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