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