xref: /aosp_15_r20/external/zlib/gzlib.c (revision 86ee64e75fa5f8bce2c8c356138035642429cd05)
1 /* gzlib.c -- zlib functions common to reading and writing gzip files
2  * Copyright (C) 2004-2019 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(_WIN32) && !defined(__BORLANDC__)
9 #  define LSEEK _lseeki64
10 #  define OPEN  open
11 #else
12 #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
13 #  define LSEEK lseek64
14 #  define OPEN  open64
15 #else
16 #  define LSEEK lseek
17 #  define OPEN  open
18 #endif
19 #endif
20 
21 #if defined UNDER_CE
22 
23 /* Map the Windows error number in ERROR to a locale-dependent error message
24    string and return a pointer to it.  Typically, the values for ERROR come
25    from GetLastError.
26 
27    The string pointed to shall not be modified by the application, but may be
28    overwritten by a subsequent call to gz_strwinerror
29 
30    The gz_strwinerror function does not change the current setting of
31    GetLastError. */
gz_strwinerror(DWORD error)32 char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
33     static char buf[1024];
34 
35     wchar_t *msgbuf;
36     DWORD lasterr = GetLastError();
37     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
38         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
39         NULL,
40         error,
41         0, /* Default language */
42         (LPVOID)&msgbuf,
43         0,
44         NULL);
45     if (chars != 0) {
46         /* If there is an \r\n appended, zap it.  */
47         if (chars >= 2
48             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
49             chars -= 2;
50             msgbuf[chars] = 0;
51         }
52 
53         if (chars > sizeof (buf) - 1) {
54             chars = sizeof (buf) - 1;
55             msgbuf[chars] = 0;
56         }
57 
58         wcstombs(buf, msgbuf, chars + 1);
59         LocalFree(msgbuf);
60     }
61     else {
62         sprintf(buf, "unknown win32 error (%ld)", error);
63     }
64 
65     SetLastError(lasterr);
66     return buf;
67 }
68 
69 #endif /* UNDER_CE */
70 
71 /* Reset gzip file state */
gz_reset(gz_statep state)72 local void gz_reset(gz_statep state) {
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     gz_statep state;
90     z_size_t len;
91     int oflag;
92 #ifdef O_CLOEXEC
93     int cloexec = 0;
94 #endif
95 #ifdef O_EXCL
96     int exclusive = 0;
97 #endif
98 
99     /* check input */
100     if (path == NULL)
101         return NULL;
102 
103     /* allocate gzFile structure to return */
104     state = (gz_statep)malloc(sizeof(gz_state));
105     if (state == NULL)
106         return NULL;
107     state->size = 0;            /* no buffers allocated yet */
108     state->want = GZBUFSIZE;    /* requested buffer size */
109     state->msg = NULL;          /* no error message yet */
110 
111     /* interpret mode */
112     state->mode = GZ_NONE;
113     state->level = Z_DEFAULT_COMPRESSION;
114     state->strategy = Z_DEFAULT_STRATEGY;
115     state->direct = 0;
116     while (*mode) {
117         if (*mode >= '0' && *mode <= '9')
118             state->level = *mode - '0';
119         else
120             switch (*mode) {
121             case 'r':
122                 state->mode = GZ_READ;
123                 break;
124 #ifndef NO_GZCOMPRESS
125             case 'w':
126                 state->mode = GZ_WRITE;
127                 break;
128             case 'a':
129                 state->mode = GZ_APPEND;
130                 break;
131 #endif
132             case '+':       /* can't read and write at the same time */
133                 free(state);
134                 return NULL;
135             case 'b':       /* ignore -- will request binary anyway */
136                 break;
137 #ifdef O_CLOEXEC
138             case 'e':
139                 cloexec = 1;
140                 break;
141 #endif
142 #ifdef O_EXCL
143             case 'x':
144                 exclusive = 1;
145                 break;
146 #endif
147             case 'f':
148                 state->strategy = Z_FILTERED;
149                 break;
150             case 'h':
151                 state->strategy = Z_HUFFMAN_ONLY;
152                 break;
153             case 'R':
154                 state->strategy = Z_RLE;
155                 break;
156             case 'F':
157                 state->strategy = Z_FIXED;
158                 break;
159             case 'T':
160                 state->direct = 1;
161                 break;
162             default:        /* could consider as an error, but just ignore */
163                 ;
164             }
165         mode++;
166     }
167 
168     /* must provide an "r", "w", or "a" */
169     if (state->mode == GZ_NONE) {
170         free(state);
171         return NULL;
172     }
173 
174     /* can't force transparent read */
175     if (state->mode == GZ_READ) {
176         if (state->direct) {
177             free(state);
178             return NULL;
179         }
180         state->direct = 1;      /* for empty file */
181     }
182 
183     /* save the path name for error messages */
184 #ifdef WIDECHAR
185     if (fd == -2) {
186         len = wcstombs(NULL, path, 0);
187         if (len == (z_size_t)-1)
188             len = 0;
189     }
190     else
191 #endif
192         len = strlen((const char *)path);
193     state->path = (char *)malloc(len + 1);
194     if (state->path == NULL) {
195         free(state);
196         return NULL;
197     }
198 #ifdef WIDECHAR
199     if (fd == -2)
200         if (len)
201             wcstombs(state->path, path, len + 1);
202         else
203             *(state->path) = 0;
204     else
205 #endif
206 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
207         (void)snprintf(state->path, len + 1, "%s", (const char *)path);
208 #else
209         strcpy(state->path, path);
210 #endif
211 
212     /* compute the flags for open() */
213     oflag =
214 #ifdef O_LARGEFILE
215         O_LARGEFILE |
216 #endif
217 #ifdef O_BINARY
218         O_BINARY |
219 #endif
220 #ifdef O_CLOEXEC
221         (cloexec ? O_CLOEXEC : 0) |
222 #endif
223         (state->mode == GZ_READ ?
224          O_RDONLY :
225          (O_WRONLY | O_CREAT |
226 #ifdef O_EXCL
227           (exclusive ? O_EXCL : 0) |
228 #endif
229           (state->mode == GZ_WRITE ?
230            O_TRUNC :
231            O_APPEND)));
232 
233     /* open the file with the appropriate flags (or just use fd) */
234     state->fd = fd > -1 ? fd : (
235 #ifdef WIDECHAR
236         fd == -2 ? _wopen(path, oflag, 0666) :
237 #endif
238         OPEN((const char *)path, oflag, 0666));
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 #ifndef INT_MAX
570 /* portably return maximum value for an int (when limits.h presumed not
571    available) -- we need to do this to cover cases where 2's complement not
572    used, since C standard permits 1's complement and sign-bit representations,
573    otherwise we could just use ((unsigned)-1) >> 1 */
gz_intmax(void)574 unsigned ZLIB_INTERNAL gz_intmax(void) {
575     unsigned p, q;
576 
577     p = 1;
578     do {
579         q = p;
580         p <<= 1;
581         p++;
582     } while (p > q);
583     return q >> 1;
584 }
585 #endif
586