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