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