]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/zlib/gzlib.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / zlib / gzlib.c
1 /* gzlib.c -- zlib functions common to reading and writing gzip files
2  * Copyright (C) 2004-2017 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__) && !defined(__MINGW32__)
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     z_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 = (gz_statep)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                 break;
169             case 'T':
170                 state->direct = 1;
171                 break;
172             default:        /* could consider as an error, but just ignore */
173                 ;
174             }
175         mode++;
176     }
177
178     /* must provide an "r", "w", or "a" */
179     if (state->mode == GZ_NONE) {
180         free(state);
181         return NULL;
182     }
183
184     /* can't force transparent read */
185     if (state->mode == GZ_READ) {
186         if (state->direct) {
187             free(state);
188             return NULL;
189         }
190         state->direct = 1;      /* for empty file */
191     }
192
193     /* save the path name for error messages */
194 #ifdef WIDECHAR
195     if (fd == -2) {
196         len = wcstombs(NULL, path, 0);
197         if (len == (z_size_t)-1)
198             len = 0;
199     }
200     else
201 #endif
202         len = strlen((const char *)path);
203     state->path = (char *)malloc(len + 1);
204     if (state->path == NULL) {
205         free(state);
206         return NULL;
207     }
208 #ifdef WIDECHAR
209     if (fd == -2)
210         if (len)
211             wcstombs(state->path, path, len + 1);
212         else
213             *(state->path) = 0;
214     else
215 #endif
216 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
217         (void)snprintf(state->path, len + 1, "%s", (const char *)path);
218 #else
219         strcpy(state->path, path);
220 #endif
221
222     /* compute the flags for open() */
223     oflag =
224 #ifdef O_LARGEFILE
225         O_LARGEFILE |
226 #endif
227 #ifdef O_BINARY
228         O_BINARY |
229 #endif
230 #ifdef O_CLOEXEC
231         (cloexec ? O_CLOEXEC : 0) |
232 #endif
233         (state->mode == GZ_READ ?
234          O_RDONLY :
235          (O_WRONLY | O_CREAT |
236 #ifdef O_EXCL
237           (exclusive ? O_EXCL : 0) |
238 #endif
239           (state->mode == GZ_WRITE ?
240            O_TRUNC :
241            O_APPEND)));
242
243     /* open the file with the appropriate flags (or just use fd) */
244     state->fd = fd > -1 ? fd : (
245 #ifdef WIDECHAR
246         fd == -2 ? _wopen(path, oflag, 0666) :
247 #endif
248         open((const char *)path, oflag, 0666));
249     if (state->fd == -1) {
250         free(state->path);
251         free(state);
252         return NULL;
253     }
254     if (state->mode == GZ_APPEND) {
255         LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
256         state->mode = GZ_WRITE;         /* simplify later checks */
257     }
258
259     /* save the current position for rewinding (only if reading) */
260     if (state->mode == GZ_READ) {
261         state->start = LSEEK(state->fd, 0, SEEK_CUR);
262         if (state->start == -1) state->start = 0;
263     }
264
265     /* initialize stream */
266     gz_reset(state);
267
268     /* return stream */
269     return (gzFile)state;
270 }
271
272 /* -- see zlib.h -- */
273 gzFile ZEXPORT gzopen(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 gzopen64(path, mode)
282     const char *path;
283     const char *mode;
284 {
285     return gz_open(path, -1, mode);
286 }
287
288 /* -- see zlib.h -- */
289 gzFile ZEXPORT gzdopen(fd, mode)
290     int fd;
291     const char *mode;
292 {
293     char *path;         /* identifier for error messages */
294     gzFile gz;
295
296     if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
297         return NULL;
298 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
299     (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
300 #else
301     sprintf(path, "<fd:%d>", fd);   /* for debugging */
302 #endif
303     gz = gz_open(path, fd, mode);
304     free(path);
305     return gz;
306 }
307
308 /* -- see zlib.h -- */
309 #ifdef WIDECHAR
310 gzFile ZEXPORT gzopen_w(path, mode)
311     const wchar_t *path;
312     const char *mode;
313 {
314     return gz_open(path, -2, mode);
315 }
316 #endif
317
318 /* -- see zlib.h -- */
319 int ZEXPORT gzbuffer(file, size)
320     gzFile file;
321     unsigned size;
322 {
323     gz_statep state;
324
325     /* get internal structure and check integrity */
326     if (file == NULL)
327         return -1;
328     state = (gz_statep)file;
329     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
330         return -1;
331
332     /* make sure we haven't already allocated memory */
333     if (state->size != 0)
334         return -1;
335
336     /* check and set requested size */
337     if ((size << 1) < size)
338         return -1;              /* need to be able to double it */
339     if (size < 2)
340         size = 2;               /* need two bytes to check magic header */
341     state->want = size;
342     return 0;
343 }
344
345 /* -- see zlib.h -- */
346 int ZEXPORT gzrewind(file)
347     gzFile file;
348 {
349     gz_statep state;
350
351     /* get internal structure */
352     if (file == NULL)
353         return -1;
354     state = (gz_statep)file;
355
356     /* check that we're reading and that there's no error */
357     if (state->mode != GZ_READ ||
358             (state->err != Z_OK && state->err != Z_BUF_ERROR))
359         return -1;
360
361     /* back up and start over */
362     if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
363         return -1;
364     gz_reset(state);
365     return 0;
366 }
367
368 /* -- see zlib.h -- */
369 z_off64_t ZEXPORT gzseek64(file, offset, whence)
370     gzFile file;
371     z_off64_t offset;
372     int whence;
373 {
374     unsigned n;
375     z_off64_t ret;
376     gz_statep state;
377
378     /* get internal structure and check integrity */
379     if (file == NULL)
380         return -1;
381     state = (gz_statep)file;
382     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
383         return -1;
384
385     /* check that there's no error */
386     if (state->err != Z_OK && state->err != Z_BUF_ERROR)
387         return -1;
388
389     /* can only seek from start or relative to current position */
390     if (whence != SEEK_SET && whence != SEEK_CUR)
391         return -1;
392
393     /* normalize offset to a SEEK_CUR specification */
394     if (whence == SEEK_SET)
395         offset -= state->x.pos;
396     else if (state->seek)
397         offset += state->skip;
398     state->seek = 0;
399
400     /* if within raw area while reading, just go there */
401     if (state->mode == GZ_READ && state->how == COPY &&
402             state->x.pos + offset >= 0) {
403         ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
404         if (ret == -1)
405             return -1;
406         state->x.have = 0;
407         state->eof = 0;
408         state->past = 0;
409         state->seek = 0;
410         gz_error(state, Z_OK, NULL);
411         state->strm.avail_in = 0;
412         state->x.pos += offset;
413         return state->x.pos;
414     }
415
416     /* calculate skip amount, rewinding if needed for back seek when reading */
417     if (offset < 0) {
418         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
419             return -1;
420         offset += state->x.pos;
421         if (offset < 0)                     /* before start of file! */
422             return -1;
423         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
424             return -1;
425     }
426
427     /* if reading, skip what's in output buffer (one less gzgetc() check) */
428     if (state->mode == GZ_READ) {
429         n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
430             (unsigned)offset : state->x.have;
431         state->x.have -= n;
432         state->x.next += n;
433         state->x.pos += n;
434         offset -= n;
435     }
436
437     /* request skip (if not zero) */
438     if (offset) {
439         state->seek = 1;
440         state->skip = offset;
441     }
442     return state->x.pos + offset;
443 }
444
445 /* -- see zlib.h -- */
446 z_off_t ZEXPORT gzseek(file, offset, whence)
447     gzFile file;
448     z_off_t offset;
449     int whence;
450 {
451     z_off64_t ret;
452
453     ret = gzseek64(file, (z_off64_t)offset, whence);
454     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
455 }
456
457 /* -- see zlib.h -- */
458 z_off64_t ZEXPORT gztell64(file)
459     gzFile file;
460 {
461     gz_statep state;
462
463     /* get internal structure and check integrity */
464     if (file == NULL)
465         return -1;
466     state = (gz_statep)file;
467     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
468         return -1;
469
470     /* return position */
471     return state->x.pos + (state->seek ? state->skip : 0);
472 }
473
474 /* -- see zlib.h -- */
475 z_off_t ZEXPORT gztell(file)
476     gzFile file;
477 {
478     z_off64_t ret;
479
480     ret = gztell64(file);
481     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
482 }
483
484 /* -- see zlib.h -- */
485 z_off64_t ZEXPORT gzoffset64(file)
486     gzFile file;
487 {
488     z_off64_t offset;
489     gz_statep state;
490
491     /* get internal structure and check integrity */
492     if (file == NULL)
493         return -1;
494     state = (gz_statep)file;
495     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
496         return -1;
497
498     /* compute and return effective offset in file */
499     offset = LSEEK(state->fd, 0, SEEK_CUR);
500     if (offset == -1)
501         return -1;
502     if (state->mode == GZ_READ)             /* reading */
503         offset -= state->strm.avail_in;     /* don't count buffered input */
504     return offset;
505 }
506
507 /* -- see zlib.h -- */
508 z_off_t ZEXPORT gzoffset(file)
509     gzFile file;
510 {
511     z_off64_t ret;
512
513     ret = gzoffset64(file);
514     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
515 }
516
517 /* -- see zlib.h -- */
518 int ZEXPORT gzeof(file)
519     gzFile file;
520 {
521     gz_statep state;
522
523     /* get internal structure and check integrity */
524     if (file == NULL)
525         return 0;
526     state = (gz_statep)file;
527     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
528         return 0;
529
530     /* return end-of-file state */
531     return state->mode == GZ_READ ? state->past : 0;
532 }
533
534 /* -- see zlib.h -- */
535 const char * ZEXPORT gzerror(file, errnum)
536     gzFile file;
537     int *errnum;
538 {
539     gz_statep state;
540
541     /* get internal structure and check integrity */
542     if (file == NULL)
543         return NULL;
544     state = (gz_statep)file;
545     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
546         return NULL;
547
548     /* return error information */
549     if (errnum != NULL)
550         *errnum = state->err;
551     return state->err == Z_MEM_ERROR ? "out of memory" :
552                                        (state->msg == NULL ? "" : state->msg);
553 }
554
555 /* -- see zlib.h -- */
556 void ZEXPORT gzclearerr(file)
557     gzFile file;
558 {
559     gz_statep state;
560
561     /* get internal structure and check integrity */
562     if (file == NULL)
563         return;
564     state = (gz_statep)file;
565     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
566         return;
567
568     /* clear error and end-of-file */
569     if (state->mode == GZ_READ) {
570         state->eof = 0;
571         state->past = 0;
572     }
573     gz_error(state, Z_OK, NULL);
574 }
575
576 /* Create an error message in allocated memory and set state->err and
577    state->msg accordingly.  Free any previous error message already there.  Do
578    not try to free or allocate space if the error is Z_MEM_ERROR (out of
579    memory).  Simply save the error message as a static string.  If there is an
580    allocation failure constructing the error message, then convert the error to
581    out of memory. */
582 void ZLIB_INTERNAL gz_error(state, err, msg)
583     gz_statep state;
584     int err;
585     const char *msg;
586 {
587     /* free previously allocated message and clear */
588     if (state->msg != NULL) {
589         if (state->err != Z_MEM_ERROR)
590             free(state->msg);
591         state->msg = NULL;
592     }
593
594     /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
595     if (err != Z_OK && err != Z_BUF_ERROR)
596         state->x.have = 0;
597
598     /* set error code, and if no message, then done */
599     state->err = err;
600     if (msg == NULL)
601         return;
602
603     /* for an out of memory error, return literal string when requested */
604     if (err == Z_MEM_ERROR)
605         return;
606
607     /* construct error message with path */
608     if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
609             NULL) {
610         state->err = Z_MEM_ERROR;
611         return;
612     }
613 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
614     (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
615                    "%s%s%s", state->path, ": ", msg);
616 #else
617     strcpy(state->msg, state->path);
618     strcat(state->msg, ": ");
619     strcat(state->msg, msg);
620 #endif
621 }
622
623 #ifndef INT_MAX
624 /* portably return maximum value for an int (when limits.h presumed not
625    available) -- we need to do this to cover cases where 2's complement not
626    used, since C standard permits 1's complement and sign-bit representations,
627    otherwise we could just use ((unsigned)-1) >> 1 */
628 unsigned ZLIB_INTERNAL gz_intmax()
629 {
630     unsigned p, q;
631
632     p = 1;
633     do {
634         q = p;
635         p <<= 1;
636         p++;
637     } while (p > q);
638     return q >> 1;
639 }
640 #endif