1 /* gzlib.c -- zlib functions common to reading and writing gzip files
2 * Copyright (C) 2004-2024 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. */
gz_strwinerror(DWORD error)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 */
gz_reset(gz_statep 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 }
76 else /* for writing ... */
77 state->reset = 0; /* no deflateReset pending */
78 state->seek = 0; /* no seek request pending */
79 gz_error(state, Z_OK, NULL); /* clear error */
80 state->x.pos = 0; /* no uncompressed data yet */
81 state->strm.avail_in = 0; /* no input data yet */
82 }
83
84 /* Open a gzip file either by name or file descriptor. */
gz_open(const void * path,int fd,const char * mode)85 local gzFile gz_open(const void *path, int fd, const char *mode) {
86 gz_statep state;
87 z_size_t len;
88 int oflag;
89 #ifdef O_CLOEXEC
90 int cloexec = 0;
91 #endif
92 #ifdef O_EXCL
93 int exclusive = 0;
94 #endif
95
96 /* check input */
97 if (path == NULL)
98 return NULL;
99
100 /* allocate gzFile structure to return */
101 state = (gz_statep)malloc(sizeof(gz_state));
102 if (state == NULL)
103 return NULL;
104 state->size = 0; /* no buffers allocated yet */
105 state->want = GZBUFSIZE; /* requested buffer size */
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 cloexec = 1;
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 'T':
157 state->direct = 1;
158 break;
159 default: /* could consider as an error, but just ignore */
160 ;
161 }
162 mode++;
163 }
164
165 /* must provide an "r", "w", or "a" */
166 if (state->mode == GZ_NONE) {
167 free(state);
168 return NULL;
169 }
170
171 /* can't force transparent read */
172 if (state->mode == GZ_READ) {
173 if (state->direct) {
174 free(state);
175 return NULL;
176 }
177 state->direct = 1; /* for empty file */
178 }
179
180 /* save the path name for error messages */
181 #ifdef WIDECHAR
182 if (fd == -2)
183 len = wcstombs(NULL, path, 0);
184 else
185 #endif
186 len = strlen((const char *)path);
187 state->path = (char *)malloc(len + 1);
188 if (state->path == NULL) {
189 free(state);
190 return NULL;
191 }
192 #ifdef WIDECHAR
193 if (fd == -2) {
194 if (len)
195 wcstombs(state->path, path, len + 1);
196 else
197 *(state->path) = 0;
198 }
199 else
200 #endif
201 {
202 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
203 (void)snprintf(state->path, len + 1, "%s", (const char *)path);
204 #else
205 strcpy(state->path, path);
206 #endif
207 }
208
209 /* compute the flags for open() */
210 oflag =
211 #ifdef O_LARGEFILE
212 O_LARGEFILE |
213 #endif
214 #ifdef O_BINARY
215 O_BINARY |
216 #endif
217 #ifdef O_CLOEXEC
218 (cloexec ? O_CLOEXEC : 0) |
219 #endif
220 (state->mode == GZ_READ ?
221 O_RDONLY :
222 (O_WRONLY | O_CREAT |
223 #ifdef O_EXCL
224 (exclusive ? O_EXCL : 0) |
225 #endif
226 (state->mode == GZ_WRITE ?
227 O_TRUNC :
228 O_APPEND)));
229
230 /* open the file with the appropriate flags (or just use fd) */
231 if (fd == -1)
232 state->fd = open((const char *)path, oflag, 0666);
233 #ifdef WIDECHAR
234 else if (fd == -2)
235 state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
236 #endif
237 else
238 state->fd = fd;
239 if (state->fd == -1) {
240 free(state->path);
241 free(state);
242 return NULL;
243 }
244 if (state->mode == GZ_APPEND) {
245 LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */
246 state->mode = GZ_WRITE; /* simplify later checks */
247 }
248
249 /* save the current position for rewinding (only if reading) */
250 if (state->mode == GZ_READ) {
251 state->start = LSEEK(state->fd, 0, SEEK_CUR);
252 if (state->start == -1) state->start = 0;
253 }
254
255 /* initialize stream */
256 gz_reset(state);
257
258 /* return stream */
259 return (gzFile)state;
260 }
261
262 /* -- see zlib.h -- */
gzopen(const char * path,const char * mode)263 gzFile ZEXPORT gzopen(const char *path, const char *mode) {
264 return gz_open(path, -1, mode);
265 }
266
267 /* -- see zlib.h -- */
gzopen64(const char * path,const char * mode)268 gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
269 return gz_open(path, -1, mode);
270 }
271
272 /* -- see zlib.h -- */
gzdopen(int fd,const char * mode)273 gzFile ZEXPORT gzdopen(int fd, const char *mode) {
274 char *path; /* identifier for error messages */
275 gzFile gz;
276
277 if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
278 return NULL;
279 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
280 (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
281 #else
282 sprintf(path, "<fd:%d>", fd); /* for debugging */
283 #endif
284 gz = gz_open(path, fd, mode);
285 free(path);
286 return gz;
287 }
288
289 /* -- see zlib.h -- */
290 #ifdef WIDECHAR
gzopen_w(const wchar_t * path,const char * mode)291 gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
292 return gz_open(path, -2, mode);
293 }
294 #endif
295
296 /* -- see zlib.h -- */
gzbuffer(gzFile file,unsigned size)297 int ZEXPORT gzbuffer(gzFile file, unsigned size) {
298 gz_statep state;
299
300 /* get internal structure and check integrity */
301 if (file == NULL)
302 return -1;
303 state = (gz_statep)file;
304 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
305 return -1;
306
307 /* make sure we haven't already allocated memory */
308 if (state->size != 0)
309 return -1;
310
311 /* check and set requested size */
312 if ((size << 1) < size)
313 return -1; /* need to be able to double it */
314 if (size < 8)
315 size = 8; /* needed to behave well with flushing */
316 state->want = size;
317 return 0;
318 }
319
320 /* -- see zlib.h -- */
gzrewind(gzFile file)321 int ZEXPORT gzrewind(gzFile file) {
322 gz_statep state;
323
324 /* get internal structure */
325 if (file == NULL)
326 return -1;
327 state = (gz_statep)file;
328
329 /* check that we're reading and that there's no error */
330 if (state->mode != GZ_READ ||
331 (state->err != Z_OK && state->err != Z_BUF_ERROR))
332 return -1;
333
334 /* back up and start over */
335 if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
336 return -1;
337 gz_reset(state);
338 return 0;
339 }
340
341 /* -- see zlib.h -- */
gzseek64(gzFile file,z_off64_t offset,int whence)342 z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
343 unsigned n;
344 z_off64_t ret;
345 gz_statep state;
346
347 /* get internal structure and check integrity */
348 if (file == NULL)
349 return -1;
350 state = (gz_statep)file;
351 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
352 return -1;
353
354 /* check that there's no error */
355 if (state->err != Z_OK && state->err != Z_BUF_ERROR)
356 return -1;
357
358 /* can only seek from start or relative to current position */
359 if (whence != SEEK_SET && whence != SEEK_CUR)
360 return -1;
361
362 /* normalize offset to a SEEK_CUR specification */
363 if (whence == SEEK_SET)
364 offset -= state->x.pos;
365 else if (state->seek)
366 offset += state->skip;
367 state->seek = 0;
368
369 /* if within raw area while reading, just go there */
370 if (state->mode == GZ_READ && state->how == COPY &&
371 state->x.pos + offset >= 0) {
372 ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
373 if (ret == -1)
374 return -1;
375 state->x.have = 0;
376 state->eof = 0;
377 state->past = 0;
378 state->seek = 0;
379 gz_error(state, Z_OK, NULL);
380 state->strm.avail_in = 0;
381 state->x.pos += offset;
382 return state->x.pos;
383 }
384
385 /* calculate skip amount, rewinding if needed for back seek when reading */
386 if (offset < 0) {
387 if (state->mode != GZ_READ) /* writing -- can't go backwards */
388 return -1;
389 offset += state->x.pos;
390 if (offset < 0) /* before start of file! */
391 return -1;
392 if (gzrewind(file) == -1) /* rewind, then skip to offset */
393 return -1;
394 }
395
396 /* if reading, skip what's in output buffer (one less gzgetc() check) */
397 if (state->mode == GZ_READ) {
398 n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
399 (unsigned)offset : state->x.have;
400 state->x.have -= n;
401 state->x.next += n;
402 state->x.pos += n;
403 offset -= n;
404 }
405
406 /* request skip (if not zero) */
407 if (offset) {
408 state->seek = 1;
409 state->skip = offset;
410 }
411 return state->x.pos + offset;
412 }
413
414 /* -- see zlib.h -- */
gzseek(gzFile file,z_off_t offset,int whence)415 z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
416 z_off64_t ret;
417
418 ret = gzseek64(file, (z_off64_t)offset, whence);
419 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
420 }
421
422 /* -- see zlib.h -- */
gztell64(gzFile file)423 z_off64_t ZEXPORT gztell64(gzFile file) {
424 gz_statep state;
425
426 /* get internal structure and check integrity */
427 if (file == NULL)
428 return -1;
429 state = (gz_statep)file;
430 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
431 return -1;
432
433 /* return position */
434 return state->x.pos + (state->seek ? state->skip : 0);
435 }
436
437 /* -- see zlib.h -- */
gztell(gzFile file)438 z_off_t ZEXPORT gztell(gzFile file) {
439 z_off64_t ret;
440
441 ret = gztell64(file);
442 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
443 }
444
445 /* -- see zlib.h -- */
gzoffset64(gzFile file)446 z_off64_t ZEXPORT gzoffset64(gzFile file) {
447 z_off64_t offset;
448 gz_statep state;
449
450 /* get internal structure and check integrity */
451 if (file == NULL)
452 return -1;
453 state = (gz_statep)file;
454 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
455 return -1;
456
457 /* compute and return effective offset in file */
458 offset = LSEEK(state->fd, 0, SEEK_CUR);
459 if (offset == -1)
460 return -1;
461 if (state->mode == GZ_READ) /* reading */
462 offset -= state->strm.avail_in; /* don't count buffered input */
463 return offset;
464 }
465
466 /* -- see zlib.h -- */
gzoffset(gzFile file)467 z_off_t ZEXPORT gzoffset(gzFile file) {
468 z_off64_t ret;
469
470 ret = gzoffset64(file);
471 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
472 }
473
474 /* -- see zlib.h -- */
gzeof(gzFile file)475 int ZEXPORT gzeof(gzFile file) {
476 gz_statep state;
477
478 /* get internal structure and check integrity */
479 if (file == NULL)
480 return 0;
481 state = (gz_statep)file;
482 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
483 return 0;
484
485 /* return end-of-file state */
486 return state->mode == GZ_READ ? state->past : 0;
487 }
488
489 /* -- see zlib.h -- */
gzerror(gzFile file,int * errnum)490 const char * ZEXPORT gzerror(gzFile file, int *errnum) {
491 gz_statep state;
492
493 /* get internal structure and check integrity */
494 if (file == NULL)
495 return NULL;
496 state = (gz_statep)file;
497 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
498 return NULL;
499
500 /* return error information */
501 if (errnum != NULL)
502 *errnum = state->err;
503 return state->err == Z_MEM_ERROR ? "out of memory" :
504 (state->msg == NULL ? "" : state->msg);
505 }
506
507 /* -- see zlib.h -- */
gzclearerr(gzFile file)508 void ZEXPORT gzclearerr(gzFile file) {
509 gz_statep state;
510
511 /* get internal structure and check integrity */
512 if (file == NULL)
513 return;
514 state = (gz_statep)file;
515 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
516 return;
517
518 /* clear error and end-of-file */
519 if (state->mode == GZ_READ) {
520 state->eof = 0;
521 state->past = 0;
522 }
523 gz_error(state, Z_OK, NULL);
524 }
525
526 /* Create an error message in allocated memory and set state->err and
527 state->msg accordingly. Free any previous error message already there. Do
528 not try to free or allocate space if the error is Z_MEM_ERROR (out of
529 memory). Simply save the error message as a static string. If there is an
530 allocation failure constructing the error message, then convert the error to
531 out of memory. */
gz_error(gz_statep state,int err,const char * msg)532 void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
533 /* free previously allocated message and clear */
534 if (state->msg != NULL) {
535 if (state->err != Z_MEM_ERROR)
536 free(state->msg);
537 state->msg = NULL;
538 }
539
540 /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
541 if (err != Z_OK && err != Z_BUF_ERROR)
542 state->x.have = 0;
543
544 /* set error code, and if no message, then done */
545 state->err = err;
546 if (msg == NULL)
547 return;
548
549 /* for an out of memory error, return literal string when requested */
550 if (err == Z_MEM_ERROR)
551 return;
552
553 /* construct error message with path */
554 if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
555 NULL) {
556 state->err = Z_MEM_ERROR;
557 return;
558 }
559 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
560 (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
561 "%s%s%s", state->path, ": ", msg);
562 #else
563 strcpy(state->msg, state->path);
564 strcat(state->msg, ": ");
565 strcat(state->msg, msg);
566 #endif
567 }
568
569 /* portably return maximum value for an int (when limits.h presumed not
570 available) -- we need to do this to cover cases where 2's complement not
571 used, since C standard permits 1's complement and sign-bit representations,
572 otherwise we could just use ((unsigned)-1) >> 1 */
gz_intmax(void)573 unsigned ZLIB_INTERNAL gz_intmax(void) {
574 #ifdef INT_MAX
575 return INT_MAX;
576 #else
577 unsigned p = 1, q;
578 do {
579 q = p;
580 p <<= 1;
581 p++;
582 } while (p > q);
583 return q >> 1;
584 #endif
585 }
586