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