Fossil SCM

fossil-scm / compat / zlib / gzlib.c
Blame History Raw 610 lines
1
/* gzlib.c -- zlib functions common to reading and writing gzip files
2
* Copyright (C) 2004-2026 Mark Adler
3
* For conditions of distribution and use, see copyright notice in zlib.h
4
*/
5
6
#include "gzguts.h"
7
8
#if defined(__DJGPP__)
9
# define LSEEK llseek
10
#elif defined(_WIN32) && !defined(__BORLANDC__) && !defined(UNDER_CE)
11
# define LSEEK _lseeki64
12
#elif defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
13
# define LSEEK lseek64
14
#else
15
# define LSEEK lseek
16
#endif
17
18
#if defined UNDER_CE
19
20
/* Map the Windows error number in ERROR to a locale-dependent error message
21
string and return a pointer to it. Typically, the values for ERROR come
22
from GetLastError.
23
24
The string pointed to shall not be modified by the application, but may be
25
overwritten by a subsequent call to gz_strwinerror
26
27
The gz_strwinerror function does not change the current setting of
28
GetLastError. */
29
char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
30
static char buf[1024];
31
32
wchar_t *msgbuf;
33
DWORD lasterr = GetLastError();
34
DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
35
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
36
NULL,
37
error,
38
0, /* Default language */
39
(LPVOID)&msgbuf,
40
0,
41
NULL);
42
if (chars != 0) {
43
/* If there is an \r\n appended, zap it. */
44
if (chars >= 2
45
&& msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
46
chars -= 2;
47
msgbuf[chars] = 0;
48
}
49
50
if (chars > sizeof (buf) - 1) {
51
chars = sizeof (buf) - 1;
52
msgbuf[chars] = 0;
53
}
54
55
wcstombs(buf, msgbuf, chars + 1); /* assumes buf is big enough */
56
LocalFree(msgbuf);
57
}
58
else {
59
sprintf(buf, "unknown win32 error (%ld)", error);
60
}
61
62
SetLastError(lasterr);
63
return buf;
64
}
65
66
#endif /* UNDER_CE */
67
68
/* Reset gzip file state */
69
local void gz_reset(gz_statep state) {
70
state->x.have = 0; /* no output data available */
71
if (state->mode == GZ_READ) { /* for reading ... */
72
state->eof = 0; /* not at end of file */
73
state->past = 0; /* have not read past end yet */
74
state->how = LOOK; /* look for gzip header */
75
state->junk = -1; /* mark first member */
76
}
77
else /* for writing ... */
78
state->reset = 0; /* no deflateReset pending */
79
state->again = 0; /* no stalled i/o yet */
80
state->skip = 0; /* no seek request pending */
81
gz_error(state, Z_OK, NULL); /* clear error */
82
state->x.pos = 0; /* no uncompressed data yet */
83
state->strm.avail_in = 0; /* no input data yet */
84
}
85
86
/* Open a gzip file either by name or file descriptor. */
87
local gzFile gz_open(const void *path, int fd, const char *mode) {
88
gz_statep state;
89
z_size_t len;
90
int oflag = 0;
91
#ifdef O_EXCL
92
int exclusive = 0;
93
#endif
94
95
/* check input */
96
if (path == NULL || mode == NULL)
97
return NULL;
98
99
/* allocate gzFile structure to return */
100
state = (gz_statep)malloc(sizeof(gz_state));
101
if (state == NULL)
102
return NULL;
103
state->size = 0; /* no buffers allocated yet */
104
state->want = GZBUFSIZE; /* requested buffer size */
105
state->err = Z_OK; /* no error yet */
106
state->msg = NULL; /* no error message yet */
107
108
/* interpret mode */
109
state->mode = GZ_NONE;
110
state->level = Z_DEFAULT_COMPRESSION;
111
state->strategy = Z_DEFAULT_STRATEGY;
112
state->direct = 0;
113
while (*mode) {
114
if (*mode >= '0' && *mode <= '9')
115
state->level = *mode - '0';
116
else
117
switch (*mode) {
118
case 'r':
119
state->mode = GZ_READ;
120
break;
121
#ifndef NO_GZCOMPRESS
122
case 'w':
123
state->mode = GZ_WRITE;
124
break;
125
case 'a':
126
state->mode = GZ_APPEND;
127
break;
128
#endif
129
case '+': /* can't read and write at the same time */
130
free(state);
131
return NULL;
132
case 'b': /* ignore -- will request binary anyway */
133
break;
134
#ifdef O_CLOEXEC
135
case 'e':
136
oflag |= O_CLOEXEC;
137
break;
138
#endif
139
#ifdef O_EXCL
140
case 'x':
141
exclusive = 1;
142
break;
143
#endif
144
case 'f':
145
state->strategy = Z_FILTERED;
146
break;
147
case 'h':
148
state->strategy = Z_HUFFMAN_ONLY;
149
break;
150
case 'R':
151
state->strategy = Z_RLE;
152
break;
153
case 'F':
154
state->strategy = Z_FIXED;
155
break;
156
case 'G':
157
state->direct = -1;
158
break;
159
#ifdef O_NONBLOCK
160
case 'N':
161
oflag |= O_NONBLOCK;
162
break;
163
#endif
164
case 'T':
165
state->direct = 1;
166
break;
167
default: /* could consider as an error, but just ignore */
168
;
169
}
170
mode++;
171
}
172
173
/* must provide an "r", "w", or "a" */
174
if (state->mode == GZ_NONE) {
175
free(state);
176
return NULL;
177
}
178
179
/* direct is 0, 1 if "T", or -1 if "G" (last "G" or "T" wins) */
180
if (state->mode == GZ_READ) {
181
if (state->direct == 1) {
182
/* can't force a transparent read */
183
free(state);
184
return NULL;
185
}
186
if (state->direct == 0)
187
/* default when reading is auto-detect of gzip vs. transparent --
188
start with a transparent assumption in case of an empty file */
189
state->direct = 1;
190
}
191
else if (state->direct == -1) {
192
/* "G" has no meaning when writing -- disallow it */
193
free(state);
194
return NULL;
195
}
196
/* if reading, direct == 1 for auto-detect, -1 for gzip only; if writing or
197
appending, direct == 0 for gzip, 1 for transparent (copy in to out) */
198
199
/* save the path name for error messages */
200
#ifdef WIDECHAR
201
if (fd == -2)
202
len = wcstombs(NULL, path, 0);
203
else
204
#endif
205
len = strlen((const char *)path);
206
state->path = (char *)malloc(len + 1);
207
if (state->path == NULL) {
208
free(state);
209
return NULL;
210
}
211
#ifdef WIDECHAR
212
if (fd == -2) {
213
if (len)
214
wcstombs(state->path, path, len + 1);
215
else
216
*(state->path) = 0;
217
}
218
else
219
#endif
220
{
221
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
222
(void)snprintf(state->path, len + 1, "%s", (const char *)path);
223
#else
224
strcpy(state->path, path);
225
#endif
226
}
227
228
/* compute the flags for open() */
229
oflag |=
230
#ifdef O_LARGEFILE
231
O_LARGEFILE |
232
#endif
233
#ifdef O_BINARY
234
O_BINARY |
235
#endif
236
(state->mode == GZ_READ ?
237
O_RDONLY :
238
(O_WRONLY | O_CREAT |
239
#ifdef O_EXCL
240
(exclusive ? O_EXCL : 0) |
241
#endif
242
(state->mode == GZ_WRITE ?
243
O_TRUNC :
244
O_APPEND)));
245
246
/* open the file with the appropriate flags (or just use fd) */
247
if (fd == -1)
248
state->fd = open((const char *)path, oflag, 0666);
249
#ifdef WIDECHAR
250
else if (fd == -2)
251
state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
252
#endif
253
else {
254
#ifdef O_NONBLOCK
255
if (oflag & O_NONBLOCK)
256
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
257
#endif
258
#ifdef O_CLOEXEC
259
if (oflag & O_CLOEXEC)
260
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | O_CLOEXEC);
261
#endif
262
state->fd = fd;
263
}
264
if (state->fd == -1) {
265
free(state->path);
266
free(state);
267
return NULL;
268
}
269
if (state->mode == GZ_APPEND) {
270
LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */
271
state->mode = GZ_WRITE; /* simplify later checks */
272
}
273
274
/* save the current position for rewinding (only if reading) */
275
if (state->mode == GZ_READ) {
276
state->start = LSEEK(state->fd, 0, SEEK_CUR);
277
if (state->start == -1) state->start = 0;
278
}
279
280
/* initialize stream */
281
gz_reset(state);
282
283
/* return stream */
284
return (gzFile)state;
285
}
286
287
/* -- see zlib.h -- */
288
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
289
return gz_open(path, -1, mode);
290
}
291
292
/* -- see zlib.h -- */
293
gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
294
return gz_open(path, -1, mode);
295
}
296
297
/* -- see zlib.h -- */
298
gzFile ZEXPORT gzdopen(int fd, const char *mode) {
299
char *path; /* identifier for error messages */
300
gzFile gz;
301
302
if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
303
return NULL;
304
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
305
(void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
306
#else
307
sprintf(path, "<fd:%d>", fd); /* for debugging */
308
#endif
309
gz = gz_open(path, fd, mode);
310
free(path);
311
return gz;
312
}
313
314
/* -- see zlib.h -- */
315
#ifdef WIDECHAR
316
gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
317
return gz_open(path, -2, mode);
318
}
319
#endif
320
321
/* -- see zlib.h -- */
322
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
323
gz_statep state;
324
325
/* get internal structure and check integrity */
326
if (file == NULL)
327
return -1;
328
state = (gz_statep)file;
329
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
330
return -1;
331
332
/* make sure we haven't already allocated memory */
333
if (state->size != 0)
334
return -1;
335
336
/* check and set requested size */
337
if ((size << 1) < size)
338
return -1; /* need to be able to double it */
339
if (size < 8)
340
size = 8; /* needed to behave well with flushing */
341
state->want = size;
342
return 0;
343
}
344
345
/* -- see zlib.h -- */
346
int ZEXPORT gzrewind(gzFile file) {
347
gz_statep state;
348
349
/* get internal structure */
350
if (file == NULL)
351
return -1;
352
state = (gz_statep)file;
353
354
/* check that we're reading and that there's no error */
355
if (state->mode != GZ_READ ||
356
(state->err != Z_OK && state->err != Z_BUF_ERROR))
357
return -1;
358
359
/* back up and start over */
360
if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
361
return -1;
362
gz_reset(state);
363
return 0;
364
}
365
366
/* -- see zlib.h -- */
367
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
368
unsigned n;
369
z_off64_t ret;
370
gz_statep state;
371
372
/* get internal structure and check integrity */
373
if (file == NULL)
374
return -1;
375
state = (gz_statep)file;
376
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
377
return -1;
378
379
/* check that there's no error */
380
if (state->err != Z_OK && state->err != Z_BUF_ERROR)
381
return -1;
382
383
/* can only seek from start or relative to current position */
384
if (whence != SEEK_SET && whence != SEEK_CUR)
385
return -1;
386
387
/* normalize offset to a SEEK_CUR specification */
388
if (whence == SEEK_SET)
389
offset -= state->x.pos;
390
else {
391
offset += state->past ? 0 : state->skip;
392
state->skip = 0;
393
}
394
395
/* if within raw area while reading, just go there */
396
if (state->mode == GZ_READ && state->how == COPY &&
397
state->x.pos + offset >= 0) {
398
ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
399
if (ret == -1)
400
return -1;
401
state->x.have = 0;
402
state->eof = 0;
403
state->past = 0;
404
state->skip = 0;
405
gz_error(state, Z_OK, NULL);
406
state->strm.avail_in = 0;
407
state->x.pos += offset;
408
return state->x.pos;
409
}
410
411
/* calculate skip amount, rewinding if needed for back seek when reading */
412
if (offset < 0) {
413
if (state->mode != GZ_READ) /* writing -- can't go backwards */
414
return -1;
415
offset += state->x.pos;
416
if (offset < 0) /* before start of file! */
417
return -1;
418
if (gzrewind(file) == -1) /* rewind, then skip to offset */
419
return -1;
420
}
421
422
/* if reading, skip what's in output buffer (one less gzgetc() check) */
423
if (state->mode == GZ_READ) {
424
n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
425
(unsigned)offset : state->x.have;
426
state->x.have -= n;
427
state->x.next += n;
428
state->x.pos += n;
429
offset -= n;
430
}
431
432
/* request skip (if not zero) */
433
state->skip = offset;
434
return state->x.pos + offset;
435
}
436
437
/* -- see zlib.h -- */
438
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
439
z_off64_t ret;
440
441
ret = gzseek64(file, (z_off64_t)offset, whence);
442
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
443
}
444
445
/* -- see zlib.h -- */
446
z_off64_t ZEXPORT gztell64(gzFile file) {
447
gz_statep state;
448
449
/* get internal structure and check integrity */
450
if (file == NULL)
451
return -1;
452
state = (gz_statep)file;
453
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
454
return -1;
455
456
/* return position */
457
return state->x.pos + (state->past ? 0 : state->skip);
458
}
459
460
/* -- see zlib.h -- */
461
z_off_t ZEXPORT gztell(gzFile file) {
462
z_off64_t ret;
463
464
ret = gztell64(file);
465
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
466
}
467
468
/* -- see zlib.h -- */
469
z_off64_t ZEXPORT gzoffset64(gzFile file) {
470
z_off64_t offset;
471
gz_statep state;
472
473
/* get internal structure and check integrity */
474
if (file == NULL)
475
return -1;
476
state = (gz_statep)file;
477
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
478
return -1;
479
480
/* compute and return effective offset in file */
481
offset = LSEEK(state->fd, 0, SEEK_CUR);
482
if (offset == -1)
483
return -1;
484
if (state->mode == GZ_READ) /* reading */
485
offset -= state->strm.avail_in; /* don't count buffered input */
486
return offset;
487
}
488
489
/* -- see zlib.h -- */
490
z_off_t ZEXPORT gzoffset(gzFile file) {
491
z_off64_t ret;
492
493
ret = gzoffset64(file);
494
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
495
}
496
497
/* -- see zlib.h -- */
498
int ZEXPORT gzeof(gzFile file) {
499
gz_statep state;
500
501
/* get internal structure and check integrity */
502
if (file == NULL)
503
return 0;
504
state = (gz_statep)file;
505
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
506
return 0;
507
508
/* return end-of-file state */
509
return state->mode == GZ_READ ? state->past : 0;
510
}
511
512
/* -- see zlib.h -- */
513
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
514
gz_statep state;
515
516
/* get internal structure and check integrity */
517
if (file == NULL)
518
return NULL;
519
state = (gz_statep)file;
520
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
521
return NULL;
522
523
/* return error information */
524
if (errnum != NULL)
525
*errnum = state->err;
526
return state->err == Z_MEM_ERROR ? "out of memory" :
527
(state->msg == NULL ? "" : state->msg);
528
}
529
530
/* -- see zlib.h -- */
531
void ZEXPORT gzclearerr(gzFile file) {
532
gz_statep state;
533
534
/* get internal structure and check integrity */
535
if (file == NULL)
536
return;
537
state = (gz_statep)file;
538
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
539
return;
540
541
/* clear error and end-of-file */
542
if (state->mode == GZ_READ) {
543
state->eof = 0;
544
state->past = 0;
545
}
546
gz_error(state, Z_OK, NULL);
547
}
548
549
/* Create an error message in allocated memory and set state->err and
550
state->msg accordingly. Free any previous error message already there. Do
551
not try to free or allocate space if the error is Z_MEM_ERROR (out of
552
memory). Simply save the error message as a static string. If there is an
553
allocation failure constructing the error message, then convert the error to
554
out of memory. */
555
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
556
/* free previously allocated message and clear */
557
if (state->msg != NULL) {
558
if (state->err != Z_MEM_ERROR)
559
free(state->msg);
560
state->msg = NULL;
561
}
562
563
/* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
564
if (err != Z_OK && err != Z_BUF_ERROR && !state->again)
565
state->x.have = 0;
566
567
/* set error code, and if no message, then done */
568
state->err = err;
569
if (msg == NULL)
570
return;
571
572
/* for an out of memory error, return literal string when requested */
573
if (err == Z_MEM_ERROR)
574
return;
575
576
/* construct error message with path */
577
if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
578
NULL) {
579
state->err = Z_MEM_ERROR;
580
return;
581
}
582
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
583
(void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
584
"%s%s%s", state->path, ": ", msg);
585
#else
586
strcpy(state->msg, state->path);
587
strcat(state->msg, ": ");
588
strcat(state->msg, msg);
589
#endif
590
}
591
592
/* portably return maximum value for an int (when limits.h presumed not
593
available) -- we need to do this to cover cases where 2's complement not
594
used, since C standard permits 1's complement and sign-bit representations,
595
otherwise we could just use ((unsigned)-1) >> 1 */
596
unsigned ZLIB_INTERNAL gz_intmax(void) {
597
#ifdef INT_MAX
598
return INT_MAX;
599
#else
600
unsigned p = 1, q;
601
602
do {
603
q = p;
604
p <<= 1;
605
p++;
606
} while (p > q);
607
return q >> 1;
608
#endif
609
}
610

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button