1/* gzlib.c -- zlib functions common to reading and writing gzip files
2 * Copyright (C) 2004, 2010, 2011 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 char *, 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 char *path;
93    int fd;
94    const char *mode;
95{
96    gz_statep state;
97
98    /* check input */
99    if (path == NULL)
100        return NULL;
101
102    /* allocate gzFile structure to return */
103    state = malloc(sizeof(gz_state));
104    if (state == NULL)
105        return NULL;
106    state->size = 0;            /* no buffers allocated yet */
107    state->want = GZBUFSIZE;    /* requested buffer size */
108    state->msg = NULL;          /* no error message yet */
109
110    /* interpret mode */
111    state->mode = GZ_NONE;
112    state->level = Z_DEFAULT_COMPRESSION;
113    state->strategy = Z_DEFAULT_STRATEGY;
114    state->direct = 0;
115    while (*mode) {
116        if (*mode >= '0' && *mode <= '9')
117            state->level = *mode - '0';
118        else
119            switch (*mode) {
120            case 'r':
121                state->mode = GZ_READ;
122                break;
123#ifndef NO_GZCOMPRESS
124            case 'w':
125                state->mode = GZ_WRITE;
126                break;
127            case 'a':
128                state->mode = GZ_APPEND;
129                break;
130#endif
131            case '+':       /* can't read and write at the same time */
132                free(state);
133                return NULL;
134            case 'b':       /* ignore -- will request binary anyway */
135                break;
136            case 'f':
137                state->strategy = Z_FILTERED;
138                break;
139            case 'h':
140                state->strategy = Z_HUFFMAN_ONLY;
141                break;
142            case 'R':
143                state->strategy = Z_RLE;
144                break;
145            case 'F':
146                state->strategy = Z_FIXED;
147            case 'T':
148                state->direct = 1;
149            default:        /* could consider as an error, but just ignore */
150                ;
151            }
152        mode++;
153    }
154
155    /* must provide an "r", "w", or "a" */
156    if (state->mode == GZ_NONE) {
157        free(state);
158        return NULL;
159    }
160
161    /* can't force transparent read */
162    if (state->mode == GZ_READ) {
163        if (state->direct) {
164            free(state);
165            return NULL;
166        }
167        state->direct = 1;      /* for empty file */
168    }
169
170    /* save the path name for error messages */
171    state->path = malloc(strlen(path) + 1);
172    if (state->path == NULL) {
173        free(state);
174        return NULL;
175    }
176    strcpy(state->path, path);
177
178    /* open the file with the appropriate mode (or just use fd) */
179    state->fd = fd != -1 ? fd :
180        open(path,
181#ifdef O_LARGEFILE
182            O_LARGEFILE |
183#endif
184#ifdef O_BINARY
185            O_BINARY |
186#endif
187            (state->mode == GZ_READ ?
188                O_RDONLY :
189                (O_WRONLY | O_CREAT | (
190                    state->mode == GZ_WRITE ?
191                        O_TRUNC :
192                        O_APPEND))),
193            0666);
194    if (state->fd == -1) {
195        free(state->path);
196        free(state);
197        return NULL;
198    }
199    if (state->mode == GZ_APPEND)
200        state->mode = GZ_WRITE;         /* simplify later checks */
201
202    /* save the current position for rewinding (only if reading) */
203    if (state->mode == GZ_READ) {
204        state->start = LSEEK(state->fd, 0, SEEK_CUR);
205        if (state->start == -1) state->start = 0;
206    }
207
208    /* initialize stream */
209    gz_reset(state);
210
211    /* return stream */
212    return (gzFile)state;
213}
214
215/* -- see zlib.h -- */
216gzFile ZEXPORT gzopen(path, mode)
217    const char *path;
218    const char *mode;
219{
220    return gz_open(path, -1, mode);
221}
222
223/* -- see zlib.h -- */
224gzFile ZEXPORT gzopen64(path, mode)
225    const char *path;
226    const char *mode;
227{
228    return gz_open(path, -1, mode);
229}
230
231/* -- see zlib.h -- */
232gzFile ZEXPORT gzdopen(fd, mode)
233    int fd;
234    const char *mode;
235{
236    char *path;         /* identifier for error messages */
237    gzFile gz;
238
239    if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)
240        return NULL;
241    sprintf(path, "<fd:%d>", fd);   /* for debugging */
242    gz = gz_open(path, fd, mode);
243    free(path);
244    return gz;
245}
246
247/* -- see zlib.h -- */
248int ZEXPORT gzbuffer(file, size)
249    gzFile file;
250    unsigned size;
251{
252    gz_statep state;
253
254    /* get internal structure and check integrity */
255    if (file == NULL)
256        return -1;
257    state = (gz_statep)file;
258    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
259        return -1;
260
261    /* make sure we haven't already allocated memory */
262    if (state->size != 0)
263        return -1;
264
265    /* check and set requested size */
266    if (size < 2)
267        size = 2;               /* need two bytes to check magic header */
268    state->want = size;
269    return 0;
270}
271
272/* -- see zlib.h -- */
273int ZEXPORT gzrewind(file)
274    gzFile file;
275{
276    gz_statep state;
277
278    /* get internal structure */
279    if (file == NULL)
280        return -1;
281    state = (gz_statep)file;
282
283    /* check that we're reading and that there's no error */
284    if (state->mode != GZ_READ ||
285            (state->err != Z_OK && state->err != Z_BUF_ERROR))
286        return -1;
287
288    /* back up and start over */
289    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
290        return -1;
291    gz_reset(state);
292    return 0;
293}
294
295/* -- see zlib.h -- */
296z_off64_t ZEXPORT gzseek64(file, offset, whence)
297    gzFile file;
298    z_off64_t offset;
299    int whence;
300{
301    unsigned n;
302    z_off64_t ret;
303    gz_statep state;
304
305    /* get internal structure and check integrity */
306    if (file == NULL)
307        return -1;
308    state = (gz_statep)file;
309    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
310        return -1;
311
312    /* check that there's no error */
313    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
314        return -1;
315
316    /* can only seek from start or relative to current position */
317    if (whence != SEEK_SET && whence != SEEK_CUR)
318        return -1;
319
320    /* normalize offset to a SEEK_CUR specification */
321    if (whence == SEEK_SET)
322        offset -= state->x.pos;
323    else if (state->seek)
324        offset += state->skip;
325    state->seek = 0;
326
327    /* if within raw area while reading, just go there */
328    if (state->mode == GZ_READ && state->how == COPY &&
329            state->x.pos + offset >= 0) {
330        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
331        if (ret == -1)
332            return -1;
333        state->x.have = 0;
334        state->eof = 0;
335        state->past = 0;
336        state->seek = 0;
337        gz_error(state, Z_OK, NULL);
338        state->strm.avail_in = 0;
339        state->x.pos += offset;
340        return state->x.pos;
341    }
342
343    /* calculate skip amount, rewinding if needed for back seek when reading */
344    if (offset < 0) {
345        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
346            return -1;
347        offset += state->x.pos;
348        if (offset < 0)                     /* before start of file! */
349            return -1;
350        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
351            return -1;
352    }
353
354    /* if reading, skip what's in output buffer (one less gzgetc() check) */
355    if (state->mode == GZ_READ) {
356        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
357            (unsigned)offset : state->x.have;
358        state->x.have -= n;
359        state->x.next += n;
360        state->x.pos += n;
361        offset -= n;
362    }
363
364    /* request skip (if not zero) */
365    if (offset) {
366        state->seek = 1;
367        state->skip = offset;
368    }
369    return state->x.pos + offset;
370}
371
372/* -- see zlib.h -- */
373z_off_t ZEXPORT gzseek(file, offset, whence)
374    gzFile file;
375    z_off_t offset;
376    int whence;
377{
378    z_off64_t ret;
379
380    ret = gzseek64(file, (z_off64_t)offset, whence);
381    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
382}
383
384/* -- see zlib.h -- */
385z_off64_t ZEXPORT gztell64(file)
386    gzFile file;
387{
388    gz_statep state;
389
390    /* get internal structure and check integrity */
391    if (file == NULL)
392        return -1;
393    state = (gz_statep)file;
394    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
395        return -1;
396
397    /* return position */
398    return state->x.pos + (state->seek ? state->skip : 0);
399}
400
401/* -- see zlib.h -- */
402z_off_t ZEXPORT gztell(file)
403    gzFile file;
404{
405    z_off64_t ret;
406
407    ret = gztell64(file);
408    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
409}
410
411/* -- see zlib.h -- */
412z_off64_t ZEXPORT gzoffset64(file)
413    gzFile file;
414{
415    z_off64_t offset;
416    gz_statep state;
417
418    /* get internal structure and check integrity */
419    if (file == NULL)
420        return -1;
421    state = (gz_statep)file;
422    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
423        return -1;
424
425    /* compute and return effective offset in file */
426    offset = LSEEK(state->fd, 0, SEEK_CUR);
427    if (offset == -1)
428        return -1;
429    if (state->mode == GZ_READ)             /* reading */
430        offset -= state->strm.avail_in;     /* don't count buffered input */
431    return offset;
432}
433
434/* -- see zlib.h -- */
435z_off_t ZEXPORT gzoffset(file)
436    gzFile file;
437{
438    z_off64_t ret;
439
440    ret = gzoffset64(file);
441    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
442}
443
444/* -- see zlib.h -- */
445int ZEXPORT gzeof(file)
446    gzFile file;
447{
448    gz_statep state;
449
450    /* get internal structure and check integrity */
451    if (file == NULL)
452        return 0;
453    state = (gz_statep)file;
454    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
455        return 0;
456
457    /* return end-of-file state */
458    return state->mode == GZ_READ ? state->past : 0;
459}
460
461/* -- see zlib.h -- */
462const char * ZEXPORT gzerror(file, errnum)
463    gzFile file;
464    int *errnum;
465{
466    gz_statep state;
467
468    /* get internal structure and check integrity */
469    if (file == NULL)
470        return NULL;
471    state = (gz_statep)file;
472    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
473        return NULL;
474
475    /* return error information */
476    if (errnum != NULL)
477        *errnum = state->err;
478    return state->msg == NULL ? "" : state->msg;
479}
480
481/* -- see zlib.h -- */
482void ZEXPORT gzclearerr(file)
483    gzFile file;
484{
485    gz_statep state;
486
487    /* get internal structure and check integrity */
488    if (file == NULL)
489        return;
490    state = (gz_statep)file;
491    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
492        return;
493
494    /* clear error and end-of-file */
495    if (state->mode == GZ_READ) {
496        state->eof = 0;
497        state->past = 0;
498    }
499    gz_error(state, Z_OK, NULL);
500}
501
502/* Create an error message in allocated memory and set state->err and
503   state->msg accordingly.  Free any previous error message already there.  Do
504   not try to free or allocate space if the error is Z_MEM_ERROR (out of
505   memory).  Simply save the error message as a static string.  If there is an
506   allocation failure constructing the error message, then convert the error to
507   out of memory. */
508void ZLIB_INTERNAL gz_error(state, err, msg)
509    gz_statep state;
510    int err;
511    const char *msg;
512{
513    /* free previously allocated message and clear */
514    if (state->msg != NULL) {
515        if (state->err != Z_MEM_ERROR)
516            free(state->msg);
517        state->msg = NULL;
518    }
519
520    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
521    if (err != Z_OK && err != Z_BUF_ERROR)
522        state->x.have = 0;
523
524    /* set error code, and if no message, then done */
525    state->err = err;
526    if (msg == NULL)
527        return;
528
529    /* for an out of memory error, save as static string */
530    if (err == Z_MEM_ERROR) {
531        state->msg = (char *)msg;
532        return;
533    }
534
535    /* construct error message with path */
536    if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
537        state->err = Z_MEM_ERROR;
538        state->msg = (char *)"out of memory";
539        return;
540    }
541    strcpy(state->msg, state->path);
542    strcat(state->msg, ": ");
543    strcat(state->msg, msg);
544    return;
545}
546
547#ifndef INT_MAX
548/* portably return maximum value for an int (when limits.h presumed not
549   available) -- we need to do this to cover cases where 2's complement not
550   used, since C standard permits 1's complement and sign-bit representations,
551   otherwise we could just use ((unsigned)-1) >> 1 */
552unsigned ZLIB_INTERNAL gz_intmax()
553{
554    unsigned p, q;
555
556    p = 1;
557    do {
558        q = p;
559        p <<= 1;
560        p++;
561    } while (p > q);
562    return q >> 1;
563}
564#endif
565