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