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