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 /* Forward declarations */
19 z_off_t gzoffset(gzFile file);
20 int gzbuffer(gzFile file, unsigned size);
21 
22 /* Local functions */
23 static void gz_reset OF((gz_statep));
24 static gzFile gz_open OF((const void *, int, const char *));
25 
26 #if defined UNDER_CE
27 
28 /* Map the Windows error number in ERROR to a locale-dependent error message
29    string and return a pointer to it.  Typically, the values for ERROR come
30    from GetLastError.
31 
32    The string pointed to shall not be modified by the application, but may be
33    overwritten by a subsequent call to gz_strwinerror
34 
35    The gz_strwinerror function does not change the current setting of
36    GetLastError. */
gz_strwinerror(error)37 char ZLIB_INTERNAL *gz_strwinerror (error)
38    DWORD error;
39 {
40    static char buf[1024];
41 
42    wchar_t *msgbuf;
43    DWORD lasterr = GetLastError();
44    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
45          | FORMAT_MESSAGE_ALLOCATE_BUFFER,
46          NULL,
47          error,
48          0, /* Default language */
49          (LPVOID)&msgbuf,
50          0,
51          NULL);
52    if (chars != 0) {
53       /* If there is an \r\n appended, zap it.  */
54       if (chars >= 2
55             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
56          chars -= 2;
57          msgbuf[chars] = 0;
58       }
59 
60       if (chars > sizeof (buf) - 1) {
61          chars = sizeof (buf) - 1;
62          msgbuf[chars] = 0;
63       }
64 
65       wcstombs(buf, msgbuf, chars + 1);
66       LocalFree(msgbuf);
67    }
68    else {
69       sprintf(buf, "unknown win32 error (%ld)", error);
70    }
71 
72    SetLastError(lasterr);
73    return buf;
74 }
75 
76 #endif /* UNDER_CE */
77 
78 /* Reset gzip file state */
gz_reset(gz_statep state)79 static void gz_reset(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. */
gz_open(const void * path,int fd,const char * mode)94 static gzFile gz_open(const void *path, int fd, 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, (const wchar_t*)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, (const wchar_t*)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    strlcpy(state->path, path, sizeof(state->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((const wchar_t*)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 
gzopen(const char * path,const char * mode)267 gzFile gzopen(const char *path, const char *mode)
268 {
269    return gz_open(path, -1, mode);
270 }
271 
gzopen64(const char * path,const char * mode)272 gzFile gzopen64(const char *path, const char *mode)
273 {
274    return gz_open(path, -1, mode);
275 }
276 
gzdopen(int fd,const char * mode)277 gzFile gzdopen(int fd, const char *mode)
278 {
279    char *path;         /* identifier for error messages */
280    gzFile gz;
281 
282    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
283       return NULL;
284 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
285    snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
286 #else
287    sprintf(path, "<fd:%d>", fd);   /* for debugging */
288 #endif
289    gz = gz_open(path, fd, mode);
290    free(path);
291    return gz;
292 }
293 
294 #ifdef _WIN32
gzopen_w(const wchar_t * path,const char * mode)295 gzFile gzopen_w(const wchar_t *path, const char *mode)
296 {
297    return gz_open(path, -2, mode);
298 }
299 #endif
300 
gzbuffer(gzFile file,unsigned size)301 int gzbuffer(gzFile file, unsigned size)
302 {
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    /* make sure we haven't already allocated memory */
313    if (state->size != 0)
314       return -1;
315 
316    /* check and set requested size */
317    if (size < 2)
318       size = 2;               /* need two bytes to check magic header */
319    state->want = size;
320    return 0;
321 }
322 
gzrewind(gzFile file)323 int gzrewind(gzFile file)
324 {
325    gz_statep state;
326 
327    /* get internal structure */
328    if (file == NULL)
329       return -1;
330    state = (gz_statep)file;
331 
332    /* check that we're reading and that there's no error */
333    if (state->mode != GZ_READ ||
334          (state->err != Z_OK && state->err != Z_BUF_ERROR))
335       return -1;
336 
337    /* back up and start over */
338    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
339       return -1;
340    gz_reset(state);
341    return 0;
342 }
343 
gzseek64(gzFile file,z_off64_t offset,int whence)344 z_off64_t gzseek64(gzFile file, z_off64_t offset, int whence)
345 {
346    unsigned n;
347    z_off64_t ret;
348    gz_statep state;
349 
350    /* get internal structure and check integrity */
351    if (file == NULL)
352       return -1;
353    state = (gz_statep)file;
354    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
355       return -1;
356 
357    /* check that there's no error */
358    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
359       return -1;
360 
361    /* can only seek from start or relative to current position */
362    if (whence != SEEK_SET && whence != SEEK_CUR)
363       return -1;
364 
365    /* normalize offset to a SEEK_CUR specification */
366    if (whence == SEEK_SET)
367       offset -= state->x.pos;
368    else if (state->seek)
369       offset += state->skip;
370    state->seek = 0;
371 
372    /* if within raw area while reading, just go there */
373    if (state->mode == GZ_READ && state->how == MODE_COPY &&
374          state->x.pos + offset >= 0) {
375       ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
376       if (ret == -1)
377          return -1;
378       state->x.have = 0;
379       state->eof = 0;
380       state->past = 0;
381       state->seek = 0;
382       gz_error(state, Z_OK, NULL);
383       state->strm.avail_in = 0;
384       state->x.pos += offset;
385       return state->x.pos;
386    }
387 
388    /* calculate skip amount, rewinding if needed for back seek when reading */
389    if (offset < 0) {
390       if (state->mode != GZ_READ)         /* writing -- can't go backwards */
391          return -1;
392       offset += state->x.pos;
393       if (offset < 0)                     /* before start of file! */
394          return -1;
395       if (gzrewind(file) == -1)           /* rewind, then skip to offset */
396          return -1;
397    }
398 
399    /* if reading, skip what's in output buffer (one less gzgetc() check) */
400    if (state->mode == GZ_READ) {
401       n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
402          (unsigned)offset : state->x.have;
403       state->x.have -= n;
404       state->x.next += n;
405       state->x.pos += n;
406       offset -= n;
407    }
408 
409    /* request skip (if not zero) */
410    if (offset) {
411       state->seek = 1;
412       state->skip = offset;
413    }
414    return state->x.pos + offset;
415 }
416 
gzseek(gzFile file,z_off_t offset,int whence)417 z_off_t gzseek(gzFile file, z_off_t offset, int whence)
418 {
419    z_off64_t ret;
420 
421    ret = gzseek64(file, (z_off64_t)offset, whence);
422    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
423 }
424 
gztell64(gzFile file)425 z_off64_t gztell64(gzFile file)
426 {
427    gz_statep state;
428 
429    /* get internal structure and check integrity */
430    if (file == NULL)
431       return -1;
432    state = (gz_statep)file;
433    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
434       return -1;
435 
436    /* return position */
437    return state->x.pos + (state->seek ? state->skip : 0);
438 }
439 
gztell(gzFile file)440 z_off_t gztell(gzFile file)
441 {
442    z_off64_t ret;
443 
444    ret = gztell64(file);
445    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
446 }
447 
gzoffset64(gzFile file)448 z_off64_t gzoffset64(gzFile file)
449 {
450    z_off64_t offset;
451    gz_statep state;
452 
453    /* get internal structure and check integrity */
454    if (file == NULL)
455       return -1;
456    state = (gz_statep)file;
457    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
458       return -1;
459 
460    /* compute and return effective offset in file */
461    offset = LSEEK(state->fd, 0, SEEK_CUR);
462    if (offset == -1)
463       return -1;
464    if (state->mode == GZ_READ)             /* reading */
465       offset -= state->strm.avail_in;     /* don't count buffered input */
466    return offset;
467 }
468 
gzoffset(gzFile file)469 z_off_t gzoffset(gzFile file)
470 {
471    z_off64_t ret = gzoffset64(file);
472    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
473 }
474 
gzeof(gzFile file)475 int gzeof(gzFile file)
476 {
477    gz_statep state;
478 
479    /* get internal structure and check integrity */
480    if (file == NULL)
481       return 0;
482    state = (gz_statep)file;
483    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
484       return 0;
485 
486    /* return end-of-file state */
487    return state->mode == GZ_READ ? state->past : 0;
488 }
489 
gzerror(gzFile file,int * errnum)490 const char * gzerror(gzFile file, int *errnum)
491 {
492    gz_statep state;
493 
494    /* get internal structure and check integrity */
495    if (file == NULL)
496       return NULL;
497    state = (gz_statep)file;
498    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
499       return NULL;
500 
501    /* return error information */
502    if (errnum != NULL)
503       *errnum = state->err;
504    return state->err == Z_MEM_ERROR ? "out of memory" :
505       (state->msg == NULL ? "" : state->msg);
506 }
507 
gzclearerr(gzFile file)508 void gzclearerr(gzFile file)
509 {
510    gz_statep state;
511 
512    /* get internal structure and check integrity */
513    if (file == NULL)
514       return;
515    state = (gz_statep)file;
516    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
517       return;
518 
519    /* clear error and end-of-file */
520    if (state->mode == GZ_READ) {
521       state->eof = 0;
522       state->past = 0;
523    }
524    gz_error(state, Z_OK, NULL);
525 }
526 
527 /* Create an error message in allocated memory and set state->err and
528    state->msg accordingly.  Free any previous error message already there.  Do
529    not try to free or allocate space if the error is Z_MEM_ERROR (out of
530    memory).  Simply save the error message as a static string.  If there is an
531    allocation failure constructing the error message, then convert the error to
532    out of memory. */
gz_error(gz_statep state,int err,const char * msg)533 void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg)
534 {
535    /* free previously allocated message and clear */
536    if (state->msg != NULL) {
537       if (state->err != Z_MEM_ERROR)
538          free(state->msg);
539       state->msg = NULL;
540    }
541 
542    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
543    if (err != Z_OK && err != Z_BUF_ERROR)
544       state->x.have = 0;
545 
546    /* set error code, and if no message, then done */
547    state->err = err;
548    if (msg == NULL)
549       return;
550 
551    /* for an out of memory error, return literal string when requested */
552    if (err == Z_MEM_ERROR)
553       return;
554 
555    /* construct error message with path */
556    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
557          NULL) {
558       state->err = Z_MEM_ERROR;
559       return;
560    }
561 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
562    snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
563          "%s%s%s", state->path, ": ", msg);
564 #else
565    strlcpy(state->msg, state->path, sizeof(state->msg));
566    strlcat(state->msg, ": ", sizeof(state->msg));
567    strlcat(state->msg, msg, sizeof(state->msg));
568 #endif
569    return;
570 }
571 
572 #ifndef INT_MAX
573 /* portably return maximum value for an int (when limits.h presumed not
574    available) -- we need to do this to cover cases where 2's complement not
575    used, since C standard permits 1's complement and sign-bit representations,
576    otherwise we could just use ((unsigned)-1) >> 1 */
gz_intmax()577 unsigned ZLIB_INTERNAL gz_intmax()
578 {
579    unsigned p, q;
580 
581    p = 1;
582    do {
583       q = p;
584       p <<= 1;
585       p++;
586    } while (p > q);
587    return q >> 1;
588 }
589 #endif
590