gzlib.c revision 237248
1/* gzlib.c -- zlib functions common to reading and writing gzip files
2 * Copyright (C) 2004, 2010, 2011, 2012 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 = 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            case 'T':
166                state->direct = 1;
167            default:        /* could consider as an error, but just ignore */
168                ;
169            }
170        mode++;
171    }
172
173    /* must provide an "r", "w", or "a" */
174    if (state->mode == GZ_NONE) {
175        free(state);
176        return NULL;
177    }
178
179    /* can't force transparent read */
180    if (state->mode == GZ_READ) {
181        if (state->direct) {
182            free(state);
183            return NULL;
184        }
185        state->direct = 1;      /* for empty file */
186    }
187
188    /* save the path name for error messages */
189#ifdef _WIN32
190    if (fd == -2) {
191        len = wcstombs(NULL, path, 0);
192        if (len == (size_t)-1)
193            len = 0;
194    }
195    else
196#endif
197        len = strlen(path);
198    state->path = malloc(len + 1);
199    if (state->path == NULL) {
200        free(state);
201        return NULL;
202    }
203#ifdef _WIN32
204    if (fd == -2)
205        if (len)
206            wcstombs(state->path, path, len + 1);
207        else
208            *(state->path) = 0;
209    else
210#endif
211        strcpy(state->path, path);
212
213    /* compute the flags for open() */
214    oflag =
215#ifdef O_LARGEFILE
216        O_LARGEFILE |
217#endif
218#ifdef O_BINARY
219        O_BINARY |
220#endif
221#ifdef O_CLOEXEC
222        (cloexec ? O_CLOEXEC : 0) |
223#endif
224        (state->mode == GZ_READ ?
225         O_RDONLY :
226         (O_WRONLY | O_CREAT |
227#ifdef O_EXCL
228          (exclusive ? O_EXCL : 0) |
229#endif
230          (state->mode == GZ_WRITE ?
231           O_TRUNC :
232           O_APPEND)));
233
234    /* open the file with the appropriate flags (or just use fd) */
235    state->fd = fd > -1 ? fd : (
236#ifdef _WIN32
237        fd == -2 ? _wopen(path, oflag, 0666) :
238#endif
239        open(path, oflag, 0666));
240    if (state->fd == -1) {
241        free(state->path);
242        free(state);
243        return NULL;
244    }
245    if (state->mode == GZ_APPEND)
246        state->mode = GZ_WRITE;         /* simplify later checks */
247
248    /* save the current position for rewinding (only if reading) */
249    if (state->mode == GZ_READ) {
250        state->start = LSEEK(state->fd, 0, SEEK_CUR);
251        if (state->start == -1) state->start = 0;
252    }
253
254    /* initialize stream */
255    gz_reset(state);
256
257    /* return stream */
258    return (gzFile)state;
259}
260
261/* -- see zlib.h -- */
262gzFile ZEXPORT gzopen(path, mode)
263    const char *path;
264    const char *mode;
265{
266    return gz_open(path, -1, mode);
267}
268
269/* -- see zlib.h -- */
270gzFile ZEXPORT gzopen64(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 gzdopen(fd, mode)
279    int fd;
280    const char *mode;
281{
282    char *path;         /* identifier for error messages */
283    gzFile gz;
284
285    if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)
286        return NULL;
287    sprintf(path, "<fd:%d>", fd);   /* for debugging */
288    gz = gz_open(path, fd, mode);
289    free(path);
290    return gz;
291}
292
293/* -- see zlib.h -- */
294#ifdef _WIN32
295gzFile ZEXPORT gzopen_w(path, mode)
296    const wchar_t *path;
297    const char *mode;
298{
299    return gz_open(path, -2, mode);
300}
301#endif
302
303/* -- see zlib.h -- */
304int ZEXPORT gzbuffer(file, size)
305    gzFile file;
306    unsigned size;
307{
308    gz_statep state;
309
310    /* get internal structure and check integrity */
311    if (file == NULL)
312        return -1;
313    state = (gz_statep)file;
314    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
315        return -1;
316
317    /* make sure we haven't already allocated memory */
318    if (state->size != 0)
319        return -1;
320
321    /* check and set requested size */
322    if (size < 2)
323        size = 2;               /* need two bytes to check magic header */
324    state->want = size;
325    return 0;
326}
327
328/* -- see zlib.h -- */
329int ZEXPORT gzrewind(file)
330    gzFile file;
331{
332    gz_statep state;
333
334    /* get internal structure */
335    if (file == NULL)
336        return -1;
337    state = (gz_statep)file;
338
339    /* check that we're reading and that there's no error */
340    if (state->mode != GZ_READ ||
341            (state->err != Z_OK && state->err != Z_BUF_ERROR))
342        return -1;
343
344    /* back up and start over */
345    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
346        return -1;
347    gz_reset(state);
348    return 0;
349}
350
351/* -- see zlib.h -- */
352z_off64_t ZEXPORT gzseek64(file, offset, whence)
353    gzFile file;
354    z_off64_t offset;
355    int whence;
356{
357    unsigned n;
358    z_off64_t ret;
359    gz_statep state;
360
361    /* get internal structure and check integrity */
362    if (file == NULL)
363        return -1;
364    state = (gz_statep)file;
365    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
366        return -1;
367
368    /* check that there's no error */
369    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
370        return -1;
371
372    /* can only seek from start or relative to current position */
373    if (whence != SEEK_SET && whence != SEEK_CUR)
374        return -1;
375
376    /* normalize offset to a SEEK_CUR specification */
377    if (whence == SEEK_SET)
378        offset -= state->x.pos;
379    else if (state->seek)
380        offset += state->skip;
381    state->seek = 0;
382
383    /* if within raw area while reading, just go there */
384    if (state->mode == GZ_READ && state->how == COPY &&
385            state->x.pos + offset >= 0) {
386        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
387        if (ret == -1)
388            return -1;
389        state->x.have = 0;
390        state->eof = 0;
391        state->past = 0;
392        state->seek = 0;
393        gz_error(state, Z_OK, NULL);
394        state->strm.avail_in = 0;
395        state->x.pos += offset;
396        return state->x.pos;
397    }
398
399    /* calculate skip amount, rewinding if needed for back seek when reading */
400    if (offset < 0) {
401        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
402            return -1;
403        offset += state->x.pos;
404        if (offset < 0)                     /* before start of file! */
405            return -1;
406        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
407            return -1;
408    }
409
410    /* if reading, skip what's in output buffer (one less gzgetc() check) */
411    if (state->mode == GZ_READ) {
412        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
413            (unsigned)offset : state->x.have;
414        state->x.have -= n;
415        state->x.next += n;
416        state->x.pos += n;
417        offset -= n;
418    }
419
420    /* request skip (if not zero) */
421    if (offset) {
422        state->seek = 1;
423        state->skip = offset;
424    }
425    return state->x.pos + offset;
426}
427
428/* -- see zlib.h -- */
429z_off_t ZEXPORT gzseek(file, offset, whence)
430    gzFile file;
431    z_off_t offset;
432    int whence;
433{
434    z_off64_t ret;
435
436    ret = gzseek64(file, (z_off64_t)offset, whence);
437    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
438}
439
440/* -- see zlib.h -- */
441z_off64_t ZEXPORT gztell64(file)
442    gzFile file;
443{
444    gz_statep state;
445
446    /* get internal structure and check integrity */
447    if (file == NULL)
448        return -1;
449    state = (gz_statep)file;
450    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
451        return -1;
452
453    /* return position */
454    return state->x.pos + (state->seek ? state->skip : 0);
455}
456
457/* -- see zlib.h -- */
458z_off_t ZEXPORT gztell(file)
459    gzFile file;
460{
461    z_off64_t ret;
462
463    ret = gztell64(file);
464    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
465}
466
467/* -- see zlib.h -- */
468z_off64_t ZEXPORT gzoffset64(file)
469    gzFile file;
470{
471    z_off64_t offset;
472    gz_statep state;
473
474    /* get internal structure and check integrity */
475    if (file == NULL)
476        return -1;
477    state = (gz_statep)file;
478    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
479        return -1;
480
481    /* compute and return effective offset in file */
482    offset = LSEEK(state->fd, 0, SEEK_CUR);
483    if (offset == -1)
484        return -1;
485    if (state->mode == GZ_READ)             /* reading */
486        offset -= state->strm.avail_in;     /* don't count buffered input */
487    return offset;
488}
489
490/* -- see zlib.h -- */
491z_off_t ZEXPORT gzoffset(file)
492    gzFile file;
493{
494    z_off64_t ret;
495
496    ret = gzoffset64(file);
497    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
498}
499
500/* -- see zlib.h -- */
501int ZEXPORT gzeof(file)
502    gzFile file;
503{
504    gz_statep state;
505
506    /* get internal structure and check integrity */
507    if (file == NULL)
508        return 0;
509    state = (gz_statep)file;
510    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
511        return 0;
512
513    /* return end-of-file state */
514    return state->mode == GZ_READ ? state->past : 0;
515}
516
517/* -- see zlib.h -- */
518const char * ZEXPORT gzerror(file, errnum)
519    gzFile file;
520    int *errnum;
521{
522    gz_statep state;
523
524    /* get internal structure and check integrity */
525    if (file == NULL)
526        return NULL;
527    state = (gz_statep)file;
528    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
529        return NULL;
530
531    /* return error information */
532    if (errnum != NULL)
533        *errnum = state->err;
534    return state->msg == NULL ? "" : state->msg;
535}
536
537/* -- see zlib.h -- */
538void ZEXPORT gzclearerr(file)
539    gzFile file;
540{
541    gz_statep state;
542
543    /* get internal structure and check integrity */
544    if (file == NULL)
545        return;
546    state = (gz_statep)file;
547    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
548        return;
549
550    /* clear error and end-of-file */
551    if (state->mode == GZ_READ) {
552        state->eof = 0;
553        state->past = 0;
554    }
555    gz_error(state, Z_OK, NULL);
556}
557
558/* Create an error message in allocated memory and set state->err and
559   state->msg accordingly.  Free any previous error message already there.  Do
560   not try to free or allocate space if the error is Z_MEM_ERROR (out of
561   memory).  Simply save the error message as a static string.  If there is an
562   allocation failure constructing the error message, then convert the error to
563   out of memory. */
564void ZLIB_INTERNAL gz_error(state, err, msg)
565    gz_statep state;
566    int err;
567    const char *msg;
568{
569    /* free previously allocated message and clear */
570    if (state->msg != NULL) {
571        if (state->err != Z_MEM_ERROR)
572            free(state->msg);
573        state->msg = NULL;
574    }
575
576    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
577    if (err != Z_OK && err != Z_BUF_ERROR)
578        state->x.have = 0;
579
580    /* set error code, and if no message, then done */
581    state->err = err;
582    if (msg == NULL)
583        return;
584
585    /* for an out of memory error, save as static string */
586    if (err == Z_MEM_ERROR) {
587        state->msg = (char *)msg;
588        return;
589    }
590
591    /* construct error message with path */
592    if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
593        state->err = Z_MEM_ERROR;
594        state->msg = (char *)"out of memory";
595        return;
596    }
597    strcpy(state->msg, state->path);
598    strcat(state->msg, ": ");
599    strcat(state->msg, msg);
600    return;
601}
602
603#ifndef INT_MAX
604/* portably return maximum value for an int (when limits.h presumed not
605   available) -- we need to do this to cover cases where 2's complement not
606   used, since C standard permits 1's complement and sign-bit representations,
607   otherwise we could just use ((unsigned)-1) >> 1 */
608unsigned ZLIB_INTERNAL gz_intmax()
609{
610    unsigned p, q;
611
612    p = 1;
613    do {
614        q = p;
615        p <<= 1;
616        p++;
617    } while (p > q);
618    return q >> 1;
619}
620#endif
621