PageRenderTime 49ms CodeModel.GetById 14ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/zlib/gzio.c

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