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