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