xref: /dragonfly/contrib/zlib-1.2/gzlib.c (revision 25a2db75)
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 */
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. */
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 */
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. */
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 = 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 -- */
262 gzFile 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 -- */
270 gzFile 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 -- */
278 gzFile 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
295 gzFile 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 -- */
304 int 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 -- */
329 int 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 -- */
352 z_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 -- */
429 z_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 -- */
441 z_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 -- */
458 z_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 -- */
468 z_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 -- */
491 z_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 -- */
501 int 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 -- */
518 const 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 -- */
538 void 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. */
564 void 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 */
608 unsigned 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