xref: /minix3/common/dist/zlib/gzio.c (revision b1c4ba4ab66acbca4eb1bab1b49a15e96feef93e)
1 /*	$NetBSD: gzio.c,v 1.3 2011/05/19 22:23:12 tsutsui Exp $	*/
2 
3 /* gzio.c -- IO on .gz files
4  * Copyright (C) 1995-2005 Jean-loup Gailly.
5  * For conditions of distribution and use, see copyright notice in zlib.h
6  *
7  * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
8  */
9 
10 /* @(#) Id */
11 
12 #include <stdio.h>
13 
14 #include "zutil.h"
15 
16 #ifdef NO_DEFLATE       /* for compatibility with old definition */
17 #  define NO_GZCOMPRESS
18 #endif
19 
20 #ifndef NO_DUMMY_DECL
21 struct internal_state {int dummy;}; /* for buggy compilers */
22 #endif
23 
24 #ifndef Z_BUFSIZE
25 #  ifdef MAXSEG_64K
26 #    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
27 #  else
28 #    define Z_BUFSIZE 16384
29 #  endif
30 #endif
31 #ifndef Z_PRINTF_BUFSIZE
32 #  define Z_PRINTF_BUFSIZE 4096
33 #endif
34 
35 #ifdef __MVS__
36 #  pragma map (fdopen , "\174\174FDOPEN")
37    FILE *fdopen(int, const char *);
38 #endif
39 
40 #ifndef STDC
41 extern voidp  malloc OF((uInt size));
42 extern void   free   OF((voidpf ptr));
43 #endif
44 
45 #define ALLOC(size) malloc(size)
46 #define TRYFREE(p) {if (p) free(p);}
47 
48 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
49 
50 /* gzip flag byte */
51 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
52 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
53 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
54 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
55 #define COMMENT      0x10 /* bit 4 set: file comment present */
56 #define RESERVED     0xE0 /* bits 5..7: reserved */
57 
58 typedef struct gz_stream {
59     z_stream stream;
60     int      z_err;   /* error code for last stream operation */
61     int      z_eof;   /* set if end of input file */
62     FILE     *file;   /* .gz file */
63     Byte     *inbuf;  /* input buffer */
64     Byte     *outbuf; /* output buffer */
65     uLong    crc;     /* crc32 of uncompressed data */
66     char     *msg;    /* error message */
67     char     *path;   /* path name for debugging only */
68     int      transparent; /* 1 if input file is not a .gz file */
69     char     mode;    /* 'w' or 'r' */
70     z_off_t  start;   /* start of compressed data in file (header skipped) */
71     z_off_t  in;      /* bytes into deflate or inflate */
72     z_off_t  out;     /* bytes out of deflate or inflate */
73     int      back;    /* one character push-back */
74     int      last;    /* true if push-back is last character */
75 } gz_stream;
76 
77 
78 local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
79 #ifndef NO_GZCOMPRESS
80 local int do_flush        OF((gzFile file, int flush));
81 #endif
82 local int    get_byte     OF((gz_stream *s));
83 local void   check_header OF((gz_stream *s));
84 local int    destroy      OF((gz_stream *s));
85 #ifndef NO_GZCOMPRESS
86 local void   putLong      OF((FILE *file, uLong x));
87 #endif
88 local uLong  getLong      OF((gz_stream *s));
89 
90 /* ===========================================================================
91      Opens a gzip (.gz) file for reading or writing. The mode parameter
92    is as in fopen ("rb" or "wb"). The file is given either by file descriptor
93    or path name (if fd == -1).
94      gz_open returns NULL if the file could not be opened or if there was
95    insufficient memory to allocate the (de)compression state; errno
96    can be checked to distinguish the two cases (if errno is zero, the
97    zlib error is Z_MEM_ERROR).
98 */
99 local gzFile gz_open (path, mode, fd)
100     const char *path;
101     const char *mode;
102     int  fd;
103 {
104     int err;
105     int level = Z_DEFAULT_COMPRESSION; /* compression level */
106     int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
107     const char *p = mode;
108     gz_stream *s;
109     char fmode[80]; /* copy of mode, without the compression level */
110     char *m = fmode;
111 
112     if (!path || !mode) return Z_NULL;
113 
114     s = (gz_stream *)ALLOC(sizeof(gz_stream));
115     if (!s) return Z_NULL;
116 
117     s->stream.zalloc = (alloc_func)0;
118     s->stream.zfree = (free_func)0;
119     s->stream.opaque = (voidpf)0;
120     s->stream.next_in = s->inbuf = Z_NULL;
121     s->stream.next_out = s->outbuf = Z_NULL;
122     s->stream.avail_in = s->stream.avail_out = 0;
123     s->file = NULL;
124     s->z_err = Z_OK;
125     s->z_eof = 0;
126     s->in = 0;
127     s->out = 0;
128     s->back = EOF;
129     s->crc = crc32(0L, Z_NULL, 0);
130     s->msg = NULL;
131     s->transparent = 0;
132 
133     s->path = (char*)ALLOC(strlen(path)+1);
134     if (s->path == NULL) {
135         return destroy(s), (gzFile)Z_NULL;
136     }
137     strcpy(s->path, path); /* do this early for debugging */
138 
139     s->mode = '\0';
140     do {
141         if (*p == 'r') s->mode = 'r';
142         if (*p == 'w' || *p == 'a') s->mode = 'w';
143         if (*p >= '0' && *p <= '9') {
144             level = *p - '0';
145         } else if (*p == 'f') {
146           strategy = Z_FILTERED;
147         } else if (*p == 'h') {
148           strategy = Z_HUFFMAN_ONLY;
149         } else if (*p == 'R') {
150           strategy = Z_RLE;
151         } else {
152             *m++ = *p; /* copy the mode */
153         }
154     } while (*p++ && m != fmode + sizeof(fmode));
155     if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
156 
157     if (s->mode == 'w') {
158 #ifdef NO_GZCOMPRESS
159         err = Z_STREAM_ERROR;
160 #else
161         err = deflateInit2(&(s->stream), level,
162                            Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
163         /* windowBits is passed < 0 to suppress zlib header */
164 
165         s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
166 #endif
167         if (err != Z_OK || s->outbuf == Z_NULL) {
168             return destroy(s), (gzFile)Z_NULL;
169         }
170     } else {
171         s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
172 
173         err = inflateInit2(&(s->stream), -MAX_WBITS);
174         /* windowBits is passed < 0 to tell that there is no zlib header.
175          * Note that in this case inflate *requires* an extra "dummy" byte
176          * after the compressed stream in order to complete decompression and
177          * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
178          * present after the compressed stream.
179          */
180         if (err != Z_OK || s->inbuf == Z_NULL) {
181             return destroy(s), (gzFile)Z_NULL;
182         }
183     }
184     s->stream.avail_out = Z_BUFSIZE;
185 
186     errno = 0;
187     s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
188 
189     if (s->file == NULL) {
190         return destroy(s), (gzFile)Z_NULL;
191     }
192     if (s->mode == 'w') {
193         /* Write a very simple .gz header:
194          */
195         fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
196              Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
197         s->start = 10L;
198         /* We use 10L instead of ftell(s->file) to because ftell causes an
199          * fflush on some systems. This version of the library doesn't use
200          * start anyway in write mode, so this initialization is not
201          * necessary.
202          */
203     } else {
204         check_header(s); /* skip the .gz header */
205         s->start = ftell(s->file) - s->stream.avail_in;
206     }
207 
208     return (gzFile)s;
209 }
210 
211 /* ===========================================================================
212      Opens a gzip (.gz) file for reading or writing.
213 */
214 gzFile ZEXPORT gzopen (path, mode)
215     const char *path;
216     const char *mode;
217 {
218     return gz_open (path, mode, -1);
219 }
220 
221 /* ===========================================================================
222      Associate a gzFile with the file descriptor fd. fd is not dup'ed here
223    to mimic the behavio(u)r of fdopen.
224 */
225 gzFile ZEXPORT gzdopen (fd, mode)
226     int fd;
227     const char *mode;
228 {
229     char name[46];      /* allow for up to 128-bit integers */
230 
231     if (fd < 0) return (gzFile)Z_NULL;
232     sprintf(name, "<fd:%d>", fd); /* for debugging */
233 
234     return gz_open (name, mode, fd);
235 }
236 
237 /* ===========================================================================
238  * Update the compression level and strategy
239  */
240 int ZEXPORT gzsetparams (file, level, strategy)
241     gzFile file;
242     int level;
243     int strategy;
244 {
245     gz_stream *s = (gz_stream*)file;
246 
247     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
248 
249     /* Make room to allow flushing */
250     if (s->stream.avail_out == 0) {
251 
252         s->stream.next_out = s->outbuf;
253         if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
254             s->z_err = Z_ERRNO;
255         }
256         s->stream.avail_out = Z_BUFSIZE;
257     }
258 
259     return deflateParams (&(s->stream), level, strategy);
260 }
261 
262 /* ===========================================================================
263      Read a byte from a gz_stream; update next_in and avail_in. Return EOF
264    for end of file.
265    IN assertion: the stream s has been sucessfully opened for reading.
266 */
267 local int get_byte(s)
268     gz_stream *s;
269 {
270     if (s->z_eof) return EOF;
271     if (s->stream.avail_in == 0) {
272         errno = 0;
273         s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
274         if (s->stream.avail_in == 0) {
275             s->z_eof = 1;
276             if (ferror(s->file)) s->z_err = Z_ERRNO;
277             return EOF;
278         }
279         s->stream.next_in = s->inbuf;
280     }
281     s->stream.avail_in--;
282     return *(s->stream.next_in)++;
283 }
284 
285 /* ===========================================================================
286       Check the gzip header of a gz_stream opened for reading. Set the stream
287     mode to transparent if the gzip magic header is not present; set s->err
288     to Z_DATA_ERROR if the magic header is present but the rest of the header
289     is incorrect.
290     IN assertion: the stream s has already been created sucessfully;
291        s->stream.avail_in is zero for the first time, but may be non-zero
292        for concatenated .gz files.
293 */
294 local void check_header(s)
295     gz_stream *s;
296 {
297     int method; /* method byte */
298     int flags;  /* flags byte */
299     uInt len;
300     int c;
301 
302     /* Assure two bytes in the buffer so we can peek ahead -- handle case
303        where first byte of header is at the end of the buffer after the last
304        gzip segment */
305     len = s->stream.avail_in;
306     if (len < 2) {
307         if (len) s->inbuf[0] = s->stream.next_in[0];
308         errno = 0;
309         len = (uInt)fread(s->inbuf + len, 1, (size_t)(Z_BUFSIZE >> len),
310 	    s->file);
311         if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
312         s->stream.avail_in += len;
313         s->stream.next_in = s->inbuf;
314         if (s->stream.avail_in < 2) {
315             s->transparent = s->stream.avail_in;
316             return;
317         }
318     }
319 
320     /* Peek ahead to check the gzip magic header */
321     if (s->stream.next_in[0] != gz_magic[0] ||
322         s->stream.next_in[1] != gz_magic[1]) {
323         s->transparent = 1;
324         return;
325     }
326     s->stream.avail_in -= 2;
327     s->stream.next_in += 2;
328 
329     /* Check the rest of the gzip header */
330     method = get_byte(s);
331     flags = get_byte(s);
332     if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
333         s->z_err = Z_DATA_ERROR;
334         return;
335     }
336 
337     /* Discard time, xflags and OS code: */
338     for (len = 0; len < 6; len++) (void)get_byte(s);
339 
340     if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
341         len  =  (uInt)get_byte(s);
342         len += ((uInt)get_byte(s))<<8;
343         /* len is garbage if EOF but the loop below will quit anyway */
344         while (len-- != 0 && get_byte(s) != EOF) ;
345     }
346     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
347         while ((c = get_byte(s)) != 0 && c != EOF) ;
348     }
349     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
350         while ((c = get_byte(s)) != 0 && c != EOF) ;
351     }
352     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
353         for (len = 0; len < 2; len++) (void)get_byte(s);
354     }
355     s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
356 }
357 
358  /* ===========================================================================
359  * Cleanup then free the given gz_stream. Return a zlib error code.
360    Try freeing in the reverse order of allocations.
361  */
362 local int destroy (s)
363     gz_stream *s;
364 {
365     int err = Z_OK;
366 
367     if (!s) return Z_STREAM_ERROR;
368 
369     TRYFREE(s->msg);
370 
371     if (s->stream.state != NULL) {
372         if (s->mode == 'w') {
373 #ifdef NO_GZCOMPRESS
374             err = Z_STREAM_ERROR;
375 #else
376             err = deflateEnd(&(s->stream));
377 #endif
378         } else if (s->mode == 'r') {
379             err = inflateEnd(&(s->stream));
380         }
381     }
382     if (s->file != NULL && fclose(s->file)) {
383 #ifdef ESPIPE
384         if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
385 #endif
386             err = Z_ERRNO;
387     }
388     if (s->z_err < 0) err = s->z_err;
389 
390     TRYFREE(s->inbuf);
391     TRYFREE(s->outbuf);
392     TRYFREE(s->path);
393     TRYFREE(s);
394     return err;
395 }
396 
397 /* ===========================================================================
398      Reads the given number of uncompressed bytes from the compressed file.
399    gzread returns the number of bytes actually read (0 for end of file).
400 */
401 int ZEXPORT gzread (file, buf, len)
402     gzFile file;
403     voidp buf;
404     unsigned len;
405 {
406     gz_stream *s = (gz_stream*)file;
407     Bytef *start = (Bytef*)buf; /* starting point for crc computation */
408     Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
409 
410     if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
411 
412     if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
413     if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
414 
415     next_out = (Byte*)buf;
416     s->stream.next_out = (Bytef*)buf;
417     s->stream.avail_out = len;
418 
419     if (s->stream.avail_out && s->back != EOF) {
420         *next_out++ = s->back;
421         s->stream.next_out++;
422         s->stream.avail_out--;
423         s->back = EOF;
424         s->out++;
425         start++;
426         if (s->last) {
427             s->z_err = Z_STREAM_END;
428             return 1;
429         }
430     }
431 
432     while (s->stream.avail_out != 0) {
433 
434         if (s->transparent) {
435             /* Copy first the lookahead bytes: */
436             uInt n = s->stream.avail_in;
437             if (n > s->stream.avail_out) n = s->stream.avail_out;
438             if (n > 0) {
439                 zmemcpy(s->stream.next_out, s->stream.next_in, n);
440                 next_out += n;
441                 s->stream.next_out = next_out;
442                 s->stream.next_in   += n;
443                 s->stream.avail_out -= n;
444                 s->stream.avail_in  -= n;
445             }
446             if (s->stream.avail_out > 0) {
447                 s->stream.avail_out -=
448                     (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
449             }
450             len -= s->stream.avail_out;
451             s->in  += len;
452             s->out += len;
453             if (len == 0) s->z_eof = 1;
454             return (int)len;
455         }
456         if (s->stream.avail_in == 0 && !s->z_eof) {
457 
458             errno = 0;
459             s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
460             if (s->stream.avail_in == 0) {
461                 s->z_eof = 1;
462                 if (ferror(s->file)) {
463                     s->z_err = Z_ERRNO;
464                     break;
465                 }
466             }
467             s->stream.next_in = s->inbuf;
468         }
469         s->in += s->stream.avail_in;
470         s->out += s->stream.avail_out;
471         s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
472         s->in -= s->stream.avail_in;
473         s->out -= s->stream.avail_out;
474 
475         if (s->z_err == Z_STREAM_END) {
476             /* Check CRC and original size */
477             s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
478             start = s->stream.next_out;
479 
480             if (getLong(s) != s->crc) {
481                 s->z_err = Z_DATA_ERROR;
482             } else {
483                 (void)getLong(s);
484                 /* The uncompressed length returned by above getlong() may be
485                  * different from s->out in case of concatenated .gz files.
486                  * Check for such files:
487                  */
488                 check_header(s);
489                 if (s->z_err == Z_OK) {
490                     inflateReset(&(s->stream));
491                     s->crc = crc32(0L, Z_NULL, 0);
492                 }
493             }
494         }
495         if (s->z_err != Z_OK || s->z_eof) break;
496     }
497     s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
498 
499     if (len == s->stream.avail_out &&
500         (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
501         return -1;
502     return (int)(len - s->stream.avail_out);
503 }
504 
505 
506 /* ===========================================================================
507       Reads one byte from the compressed file. gzgetc returns this byte
508    or -1 in case of end of file or error.
509 */
510 int ZEXPORT gzgetc(file)
511     gzFile file;
512 {
513     unsigned char c;
514 
515     return gzread(file, &c, 1) == 1 ? c : -1;
516 }
517 
518 
519 /* ===========================================================================
520       Push one byte back onto the stream.
521 */
522 int ZEXPORT gzungetc(c, file)
523     int c;
524     gzFile file;
525 {
526     gz_stream *s = (gz_stream*)file;
527 
528     if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
529     s->back = c;
530     s->out--;
531     s->last = (s->z_err == Z_STREAM_END);
532     if (s->last) s->z_err = Z_OK;
533     s->z_eof = 0;
534     return c;
535 }
536 
537 
538 /* ===========================================================================
539       Reads bytes from the compressed file until len-1 characters are
540    read, or a newline character is read and transferred to buf, or an
541    end-of-file condition is encountered.  The string is then terminated
542    with a null character.
543       gzgets returns buf, or Z_NULL in case of error.
544 
545       The current implementation is not optimized at all.
546 */
547 char * ZEXPORT gzgets(file, buf, len)
548     gzFile file;
549     char *buf;
550     int len;
551 {
552     char *b = buf;
553     if (buf == Z_NULL || len <= 0) return Z_NULL;
554 
555     while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
556     *buf = '\0';
557     return b == buf && len > 0 ? Z_NULL : b;
558 }
559 
560 
561 #ifndef NO_GZCOMPRESS
562 /* ===========================================================================
563      Writes the given number of uncompressed bytes into the compressed file.
564    gzwrite returns the number of bytes actually written (0 in case of error).
565 */
566 int ZEXPORT gzwrite (file, buf, len)
567     gzFile file;
568     voidpc buf;
569     unsigned len;
570 {
571     gz_stream *s = (gz_stream*)file;
572 
573     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
574 
575     s->stream.next_in = __UNCONST(buf);
576     s->stream.avail_in = len;
577 
578     while (s->stream.avail_in != 0) {
579 
580         if (s->stream.avail_out == 0) {
581 
582             s->stream.next_out = s->outbuf;
583             if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
584                 s->z_err = Z_ERRNO;
585                 break;
586             }
587             s->stream.avail_out = Z_BUFSIZE;
588         }
589         s->in += s->stream.avail_in;
590         s->out += s->stream.avail_out;
591         s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
592         s->in -= s->stream.avail_in;
593         s->out -= s->stream.avail_out;
594         if (s->z_err != Z_OK) break;
595     }
596     s->crc = crc32(s->crc, (const Bytef *)buf, len);
597 
598     return (int)(len - s->stream.avail_in);
599 }
600 
601 
602 /* ===========================================================================
603      Converts, formats, and writes the args to the compressed file under
604    control of the format string, as in fprintf. gzprintf returns the number of
605    uncompressed bytes actually written (0 in case of error).
606 */
607 #ifdef STDC
608 #include <stdarg.h>
609 
610 int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
611 {
612     char buf[Z_PRINTF_BUFSIZE];
613     va_list va;
614     int len;
615 
616     buf[sizeof(buf) - 1] = 0;
617     va_start(va, format);
618 #ifdef NO_vsnprintf
619 #  ifdef HAS_vsprintf_void
620     (void)vsprintf(buf, format, va);
621     va_end(va);
622     for (len = 0; len < sizeof(buf); len++)
623         if (buf[len] == 0) break;
624 #  else
625     len = vsprintf(buf, format, va);
626     va_end(va);
627 #  endif
628 #else
629 #  ifdef HAS_vsnprintf_void
630     (void)vsnprintf(buf, sizeof(buf), format, va);
631     va_end(va);
632     len = strlen(buf);
633 #  else
634     len = vsnprintf(buf, sizeof(buf), format, va);
635     va_end(va);
636 #  endif
637 #endif
638     if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
639         return 0;
640     return gzwrite(file, buf, (unsigned)len);
641 }
642 #else /* not ANSI C */
643 
644 int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
645                        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
646     gzFile file;
647     const char *format;
648     int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
649         a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
650 {
651     char buf[Z_PRINTF_BUFSIZE];
652     int len;
653 
654     buf[sizeof(buf) - 1] = 0;
655 #ifdef NO_snprintf
656 #  ifdef HAS_sprintf_void
657     sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
658             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
659     for (len = 0; len < sizeof(buf); len++)
660         if (buf[len] == 0) break;
661 #  else
662     len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
663                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
664 #  endif
665 #else
666 #  ifdef HAS_snprintf_void
667     snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
668              a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
669     len = strlen(buf);
670 #  else
671     len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
672                  a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
673 #  endif
674 #endif
675     if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
676         return 0;
677     return gzwrite(file, buf, len);
678 }
679 #endif
680 
681 /* ===========================================================================
682       Writes c, converted to an unsigned char, into the compressed file.
683    gzputc returns the value that was written, or -1 in case of error.
684 */
685 int ZEXPORT gzputc(file, c)
686     gzFile file;
687     int c;
688 {
689     unsigned char cc = (unsigned char) c; /* required for big endian systems */
690 
691     return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
692 }
693 
694 
695 /* ===========================================================================
696       Writes the given null-terminated string to the compressed file, excluding
697    the terminating null character.
698       gzputs returns the number of characters written, or -1 in case of error.
699 */
700 int ZEXPORT gzputs(file, s)
701     gzFile file;
702     const char *s;
703 {
704     return gzwrite(file, __UNCONST(s), (unsigned)strlen(s));
705 }
706 
707 
708 /* ===========================================================================
709      Flushes all pending output into the compressed file. The parameter
710    flush is as in the deflate() function.
711 */
712 local int do_flush (file, flush)
713     gzFile file;
714     int flush;
715 {
716     uInt len;
717     int done = 0;
718     gz_stream *s = (gz_stream*)file;
719 
720     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
721 
722     s->stream.avail_in = 0; /* should be zero already anyway */
723 
724     for (;;) {
725         len = Z_BUFSIZE - s->stream.avail_out;
726 
727         if (len != 0) {
728             if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
729                 s->z_err = Z_ERRNO;
730                 return Z_ERRNO;
731             }
732             s->stream.next_out = s->outbuf;
733             s->stream.avail_out = Z_BUFSIZE;
734         }
735         if (done) break;
736         s->out += s->stream.avail_out;
737         s->z_err = deflate(&(s->stream), flush);
738         s->out -= s->stream.avail_out;
739 
740         /* Ignore the second of two consecutive flushes: */
741         if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
742 
743         /* deflate has finished flushing only when it hasn't used up
744          * all the available space in the output buffer:
745          */
746         done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
747 
748         if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
749     }
750     return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
751 }
752 
753 int ZEXPORT gzflush (file, flush)
754      gzFile file;
755      int flush;
756 {
757     gz_stream *s = (gz_stream*)file;
758     int err = do_flush (file, flush);
759 
760     if (err) return err;
761     fflush(s->file);
762     return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
763 }
764 #endif /* NO_GZCOMPRESS */
765 
766 /* ===========================================================================
767       Sets the starting position for the next gzread or gzwrite on the given
768    compressed file. The offset represents a number of bytes in the
769       gzseek returns the resulting offset location as measured in bytes from
770    the beginning of the uncompressed stream, or -1 in case of error.
771       SEEK_END is not implemented, returns error.
772       In this version of the library, gzseek can be extremely slow.
773 */
774 z_off_t ZEXPORT gzseek (file, offset, whence)
775     gzFile file;
776     z_off_t offset;
777     int whence;
778 {
779     gz_stream *s = (gz_stream*)file;
780 
781     if (s == NULL || whence == SEEK_END ||
782         s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
783         return -1L;
784     }
785 
786     if (s->mode == 'w') {
787 #ifdef NO_GZCOMPRESS
788         return -1L;
789 #else
790         if (whence == SEEK_SET) {
791             offset -= s->in;
792         }
793         if (offset < 0) return -1L;
794 
795         /* At this point, offset is the number of zero bytes to write. */
796         if (s->inbuf == Z_NULL) {
797             s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
798             if (s->inbuf == Z_NULL) return -1L;
799             zmemzero(s->inbuf, Z_BUFSIZE);
800         }
801         while (offset > 0)  {
802             uInt size = Z_BUFSIZE;
803             if (offset < Z_BUFSIZE) size = (uInt)offset;
804 
805             size = gzwrite(file, s->inbuf, size);
806             if (size == 0) return -1L;
807 
808             offset -= size;
809         }
810         return s->in;
811 #endif
812     }
813     /* Rest of function is for reading only */
814 
815     /* compute absolute position */
816     if (whence == SEEK_CUR) {
817         offset += s->out;
818     }
819     if (offset < 0) return -1L;
820 
821     if (s->transparent) {
822         /* map to fseek */
823         s->back = EOF;
824         s->stream.avail_in = 0;
825         s->stream.next_in = s->inbuf;
826         if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
827 
828         s->in = s->out = offset;
829         return offset;
830     }
831 
832     /* For a negative seek, rewind and use positive seek */
833     if (offset >= s->out) {
834         offset -= s->out;
835     } else if (gzrewind(file) < 0) {
836         return -1L;
837     }
838     /* offset is now the number of bytes to skip. */
839 
840     if (offset != 0 && s->outbuf == Z_NULL) {
841         s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
842         if (s->outbuf == Z_NULL) return -1L;
843     }
844     if (offset && s->back != EOF) {
845         s->back = EOF;
846         s->out++;
847         offset--;
848         if (s->last) s->z_err = Z_STREAM_END;
849     }
850     while (offset > 0)  {
851         int size = Z_BUFSIZE;
852         if (offset < Z_BUFSIZE) size = (int)offset;
853 
854         size = gzread(file, s->outbuf, (uInt)size);
855         if (size <= 0) return -1L;
856         offset -= size;
857     }
858     return s->out;
859 }
860 
861 /* ===========================================================================
862      Rewinds input file.
863 */
864 int ZEXPORT gzrewind (file)
865     gzFile file;
866 {
867     gz_stream *s = (gz_stream*)file;
868 
869     if (s == NULL || s->mode != 'r') return -1;
870 
871     s->z_err = Z_OK;
872     s->z_eof = 0;
873     s->back = EOF;
874     s->stream.avail_in = 0;
875     s->stream.next_in = s->inbuf;
876     s->crc = crc32(0L, Z_NULL, 0);
877     if (!s->transparent) (void)inflateReset(&s->stream);
878     s->in = 0;
879     s->out = 0;
880     return fseek(s->file, s->start, SEEK_SET);
881 }
882 
883 /* ===========================================================================
884      Returns the starting position for the next gzread or gzwrite on the
885    given compressed file. This position represents a number of bytes in the
886    uncompressed data stream.
887 */
888 z_off_t ZEXPORT gztell (file)
889     gzFile file;
890 {
891     return gzseek(file, 0L, SEEK_CUR);
892 }
893 
894 /* ===========================================================================
895      Returns 1 when EOF has previously been detected reading the given
896    input stream, otherwise zero.
897 */
898 int ZEXPORT gzeof (file)
899     gzFile file;
900 {
901     gz_stream *s = (gz_stream*)file;
902 
903     /* With concatenated compressed files that can have embedded
904      * crc trailers, z_eof is no longer the only/best indicator of EOF
905      * on a gz_stream. Handle end-of-stream error explicitly here.
906      */
907     if (s == NULL || s->mode != 'r') return 0;
908     if (s->z_eof) return 1;
909     return s->z_err == Z_STREAM_END;
910 }
911 
912 /* ===========================================================================
913      Returns 1 if reading and doing so transparently, otherwise zero.
914 */
915 int ZEXPORT gzdirect (file)
916     gzFile file;
917 {
918     gz_stream *s = (gz_stream*)file;
919 
920     if (s == NULL || s->mode != 'r') return 0;
921     return s->transparent;
922 }
923 
924 #ifndef NO_GZCOMPRESS
925 /* ===========================================================================
926    Outputs a long in LSB order to the given file
927 */
928 local void putLong (file, x)
929     FILE *file;
930     uLong x;
931 {
932     int n;
933     for (n = 0; n < 4; n++) {
934         fputc((int)(x & 0xff), file);
935         x >>= 8;
936     }
937 }
938 #endif
939 
940 /* ===========================================================================
941    Reads a long in LSB order from the given gz_stream. Sets z_err in case
942    of error.
943 */
944 local uLong getLong (s)
945     gz_stream *s;
946 {
947     uLong x = (uLong)get_byte(s);
948     int c;
949 
950     x += ((uLong)get_byte(s))<<8;
951     x += ((uLong)get_byte(s))<<16;
952     c = get_byte(s);
953     if (c == EOF) s->z_err = Z_DATA_ERROR;
954     x += ((uLong)c)<<24;
955     return x;
956 }
957 
958 /* ===========================================================================
959      Flushes all pending output if necessary, closes the compressed file
960    and deallocates all the (de)compression state.
961 */
962 int ZEXPORT gzclose (file)
963     gzFile file;
964 {
965     gz_stream *s = (gz_stream*)file;
966 
967     if (s == NULL) return Z_STREAM_ERROR;
968 
969     if (s->mode == 'w') {
970 #ifdef NO_GZCOMPRESS
971         return Z_STREAM_ERROR;
972 #else
973         if (do_flush (file, Z_FINISH) != Z_OK)
974             return destroy((gz_stream*)file);
975 
976         putLong (s->file, s->crc);
977         putLong (s->file, (uLong)(s->in & 0xffffffff));
978 #endif
979     }
980     return destroy((gz_stream*)file);
981 }
982 
983 #ifdef STDC
984 #  define zstrerror(errnum) strerror(errnum)
985 #else
986 #  define zstrerror(errnum) ""
987 #endif
988 
989 /* ===========================================================================
990      Returns the error message for the last error which occurred on the
991    given compressed file. errnum is set to zlib error number. If an
992    error occurred in the file system and not in the compression library,
993    errnum is set to Z_ERRNO and the application may consult errno
994    to get the exact error code.
995 */
996 const char * ZEXPORT gzerror (file, errnum)
997     gzFile file;
998     int *errnum;
999 {
1000     const char *m;
1001     gz_stream *s = (gz_stream*)file;
1002 
1003     if (s == NULL) {
1004         *errnum = Z_STREAM_ERROR;
1005         return (const char*)ERR_MSG(Z_STREAM_ERROR);
1006     }
1007     *errnum = s->z_err;
1008     if (*errnum == Z_OK) return (const char*)"";
1009 
1010     m = *errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg;
1011 
1012     if (m == NULL || *m == '\0') m = ERR_MSG(s->z_err);
1013 
1014     TRYFREE(s->msg);
1015     s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
1016     if (s->msg == Z_NULL) return ERR_MSG(Z_MEM_ERROR);
1017     strcpy(s->msg, s->path);
1018     strcat(s->msg, ": ");
1019     strcat(s->msg, m);
1020     return (const char*)s->msg;
1021 }
1022 
1023 /* ===========================================================================
1024      Clear the error and end-of-file flags, and do the same for the real file.
1025 */
1026 void ZEXPORT gzclearerr (file)
1027     gzFile file;
1028 {
1029     gz_stream *s = (gz_stream*)file;
1030 
1031     if (s == NULL) return;
1032     if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
1033     s->z_eof = 0;
1034     clearerr(s->file);
1035 }
1036