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