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#include "gzguts.h"
7
8#if defined(_WIN32) && !defined(__BORLANDC__)
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    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 _WIN32
192    if (fd == -2) {
193        len = wcstombs(NULL, path, 0);
194        if (len == (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 _WIN32
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        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 _WIN32
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        state->mode = GZ_WRITE;         /* simplify later checks */
253
254    /* save the current position for rewinding (only if reading) */
255    if (state->mode == GZ_READ) {
256        state->start = LSEEK(state->fd, 0, SEEK_CUR);
257        if (state->start == -1) state->start = 0;
258    }
259
260    /* initialize stream */
261    gz_reset(state);
262
263    /* return stream */
264    return (gzFile)state;
265}
266
267/* -- see zlib.h -- */
268gzFile ZEXPORT gzopen(path, mode)
269    const char *path;
270    const char *mode;
271{
272    return gz_open(path, -1, mode);
273}
274
275/* -- see zlib.h -- */
276gzFile ZEXPORT gzopen64(path, mode)
277    const char *path;
278    const char *mode;
279{
280    return gz_open(path, -1, mode);
281}
282
283/* -- see zlib.h -- */
284gzFile ZEXPORT gzdopen(fd, mode)
285    int fd;
286    const char *mode;
287{
288    char *path;         /* identifier for error messages */
289    gzFile gz;
290
291    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
292        return NULL;
293#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
294    snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
295#else
296    sprintf(path, "<fd:%d>", fd);   /* for debugging */
297#endif
298    gz = gz_open(path, fd, mode);
299    free(path);
300    return gz;
301}
302
303/* -- see zlib.h -- */
304#ifdef _WIN32
305gzFile ZEXPORT gzopen_w(path, mode)
306    const wchar_t *path;
307    const char *mode;
308{
309    return gz_open(path, -2, mode);
310}
311#endif
312
313/* -- see zlib.h -- */
314int ZEXPORT gzbuffer(file, size)
315    gzFile file;
316    unsigned size;
317{
318    gz_statep state;
319
320    /* get internal structure and check integrity */
321    if (file == NULL)
322        return -1;
323    state = (gz_statep)file;
324    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
325        return -1;
326
327    /* make sure we haven't already allocated memory */
328    if (state->size != 0)
329        return -1;
330
331    /* check and set requested size */
332    if (size < 2)
333        size = 2;               /* need two bytes to check magic header */
334    state->want = size;
335    return 0;
336}
337
338/* -- see zlib.h -- */
339int ZEXPORT gzrewind(file)
340    gzFile file;
341{
342    gz_statep state;
343
344    /* get internal structure */
345    if (file == NULL)
346        return -1;
347    state = (gz_statep)file;
348
349    /* check that we're reading and that there's no error */
350    if (state->mode != GZ_READ ||
351            (state->err != Z_OK && state->err != Z_BUF_ERROR))
352        return -1;
353
354    /* back up and start over */
355    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
356        return -1;
357    gz_reset(state);
358    return 0;
359}
360
361/* -- see zlib.h -- */
362z_off64_t ZEXPORT gzseek64(file, offset, whence)
363    gzFile file;
364    z_off64_t offset;
365    int whence;
366{
367    unsigned n;
368    z_off64_t ret;
369    gz_statep state;
370
371    /* get internal structure and check integrity */
372    if (file == NULL)
373        return -1;
374    state = (gz_statep)file;
375    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
376        return -1;
377
378    /* check that there's no error */
379    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
380        return -1;
381
382    /* can only seek from start or relative to current position */
383    if (whence != SEEK_SET && whence != SEEK_CUR)
384        return -1;
385
386    /* normalize offset to a SEEK_CUR specification */
387    if (whence == SEEK_SET)
388        offset -= state->x.pos;
389    else if (state->seek)
390        offset += state->skip;
391    state->seek = 0;
392
393    /* if within raw area while reading, just go there */
394    if (state->mode == GZ_READ && state->how == COPY &&
395            state->x.pos + offset >= 0) {
396        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
397        if (ret == -1)
398            return -1;
399        state->x.have = 0;
400        state->eof = 0;
401        state->past = 0;
402        state->seek = 0;
403        gz_error(state, Z_OK, NULL);
404        state->strm.avail_in = 0;
405        state->x.pos += offset;
406        return state->x.pos;
407    }
408
409    /* calculate skip amount, rewinding if needed for back seek when reading */
410    if (offset < 0) {
411        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
412            return -1;
413        offset += state->x.pos;
414        if (offset < 0)                     /* before start of file! */
415            return -1;
416        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
417            return -1;
418    }
419
420    /* if reading, skip what's in output buffer (one less gzgetc() check) */
421    if (state->mode == GZ_READ) {
422        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
423            (unsigned)offset : state->x.have;
424        state->x.have -= n;
425        state->x.next += n;
426        state->x.pos += n;
427        offset -= n;
428    }
429
430    /* request skip (if not zero) */
431    if (offset) {
432        state->seek = 1;
433        state->skip = offset;
434    }
435    return state->x.pos + offset;
436}
437
438/* -- see zlib.h -- */
439z_off_t ZEXPORT gzseek(file, offset, whence)
440    gzFile file;
441    z_off_t offset;
442    int whence;
443{
444    z_off64_t ret;
445
446    ret = gzseek64(file, (z_off64_t)offset, whence);
447    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
448}
449
450/* -- see zlib.h -- */
451z_off64_t ZEXPORT gztell64(file)
452    gzFile file;
453{
454    gz_statep state;
455
456    /* get internal structure and check integrity */
457    if (file == NULL)
458        return -1;
459    state = (gz_statep)file;
460    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
461        return -1;
462
463    /* return position */
464    return state->x.pos + (state->seek ? state->skip : 0);
465}
466
467/* -- see zlib.h -- */
468z_off_t ZEXPORT gztell(file)
469    gzFile file;
470{
471    z_off64_t ret;
472
473    ret = gztell64(file);
474    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
475}
476
477/* -- see zlib.h -- */
478z_off64_t ZEXPORT gzoffset64(file)
479    gzFile file;
480{
481    z_off64_t offset;
482    gz_statep state;
483
484    /* get internal structure and check integrity */
485    if (file == NULL)
486        return -1;
487    state = (gz_statep)file;
488    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
489        return -1;
490
491    /* compute and return effective offset in file */
492    offset = LSEEK(state->fd, 0, SEEK_CUR);
493    if (offset == -1)
494        return -1;
495    if (state->mode == GZ_READ)             /* reading */
496        offset -= state->strm.avail_in;     /* don't count buffered input */
497    return offset;
498}
499
500/* -- see zlib.h -- */
501z_off_t ZEXPORT gzoffset(file)
502    gzFile file;
503{
504    z_off64_t ret;
505
506    ret = gzoffset64(file);
507    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
508}
509
510/* -- see zlib.h -- */
511int ZEXPORT gzeof(file)
512    gzFile file;
513{
514    gz_statep state;
515
516    /* get internal structure and check integrity */
517    if (file == NULL)
518        return 0;
519    state = (gz_statep)file;
520    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
521        return 0;
522
523    /* return end-of-file state */
524    return state->mode == GZ_READ ? state->past : 0;
525}
526
527/* -- see zlib.h -- */
528const char * ZEXPORT gzerror(file, errnum)
529    gzFile file;
530    int *errnum;
531{
532    gz_statep state;
533
534    /* get internal structure and check integrity */
535    if (file == NULL)
536        return NULL;
537    state = (gz_statep)file;
538    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
539        return NULL;
540
541    /* return error information */
542    if (errnum != NULL)
543        *errnum = state->err;
544    return state->err == Z_MEM_ERROR ? "out of memory" :
545                                       (state->msg == NULL ? "" : state->msg);
546}
547
548/* -- see zlib.h -- */
549void ZEXPORT gzclearerr(file)
550    gzFile file;
551{
552    gz_statep state;
553
554    /* get internal structure and check integrity */
555    if (file == NULL)
556        return;
557    state = (gz_statep)file;
558    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
559        return;
560
561    /* clear error and end-of-file */
562    if (state->mode == GZ_READ) {
563        state->eof = 0;
564        state->past = 0;
565    }
566    gz_error(state, Z_OK, NULL);
567}
568
569/* Create an error message in allocated memory and set state->err and
570   state->msg accordingly.  Free any previous error message already there.  Do
571   not try to free or allocate space if the error is Z_MEM_ERROR (out of
572   memory).  Simply save the error message as a static string.  If there is an
573   allocation failure constructing the error message, then convert the error to
574   out of memory. */
575void ZLIB_INTERNAL gz_error(state, err, msg)
576    gz_statep state;
577    int err;
578    const char *msg;
579{
580    /* free previously allocated message and clear */
581    if (state->msg != NULL) {
582        if (state->err != Z_MEM_ERROR)
583            free(state->msg);
584        state->msg = NULL;
585    }
586
587    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
588    if (err != Z_OK && err != Z_BUF_ERROR)
589        state->x.have = 0;
590
591    /* set error code, and if no message, then done */
592    state->err = err;
593    if (msg == NULL)
594        return;
595
596    /* for an out of memory error, return literal string when requested */
597    if (err == Z_MEM_ERROR)
598        return;
599
600    /* construct error message with path */
601    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
602            NULL) {
603        state->err = Z_MEM_ERROR;
604        return;
605    }
606#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
607    snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
608             "%s%s%s", state->path, ": ", msg);
609#else
610    strcpy(state->msg, state->path);
611    strcat(state->msg, ": ");
612    strcat(state->msg, msg);
613#endif
614    return;
615}
616
617#ifndef INT_MAX
618/* portably return maximum value for an int (when limits.h presumed not
619   available) -- we need to do this to cover cases where 2's complement not
620   used, since C standard permits 1's complement and sign-bit representations,
621   otherwise we could just use ((unsigned)-1) >> 1 */
622unsigned ZLIB_INTERNAL gz_intmax()
623{
624    unsigned p, q;
625
626    p = 1;
627    do {
628        q = p;
629        p <<= 1;
630        p++;
631    } while (p > q);
632    return q >> 1;
633}
634#endif
635