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