xref: /third_party/node/deps/zlib/gzlib.c (revision 1cb0ef41)
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. */
32char 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 */
72local 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. */
88local 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 -- */
263gzFile ZEXPORT gzopen(const char *path, const char *mode) {
264    return gz_open(path, -1, mode);
265}
266
267/* -- see zlib.h -- */
268gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
269    return gz_open(path, -1, mode);
270}
271
272/* -- see zlib.h -- */
273gzFile 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
291gzFile 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 -- */
297int 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 -- */
321int 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 -- */
342z_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 -- */
415z_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 -- */
423z_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 -- */
438z_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 -- */
446z_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 -- */
467z_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 -- */
475int 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 -- */
490const 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 -- */
508void 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. */
532void 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 */
574unsigned 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