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