• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
19 local void gz_reset OF((gz_statep));
20 local 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. */
gz_strwinerror(error)33 char 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 */
gz_reset(state)75 local 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. */
gz_open(path,fd,mode)91 local 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 -- */
gzopen(path,mode)268 gzFile 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 -- */
gzopen64(path,mode)276 gzFile 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 -- */
gzdopen(fd,mode)284 gzFile 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
gzopen_w(path,mode)305 gzFile 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 -- */
gzbuffer(file,size)314 int 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 -- */
gzrewind(file)339 int 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 -- */
gzseek64(file,offset,whence)362 z_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 -- */
gzseek(file,offset,whence)439 z_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 -- */
gztell64(file)451 z_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 -- */
gztell(file)468 z_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 -- */
gzoffset64(file)478 z_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 -- */
gzoffset(file)501 z_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 -- */
gzeof(file)511 int 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 -- */
gzerror(file,errnum)528 const 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 -- */
gzclearerr(file)549 void 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. */
gz_error(state,err,msg)575 void 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 */
gz_intmax()622 unsigned 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