PageRenderTime 94ms CodeModel.GetById 24ms app.highlight 61ms RepoModel.GetById 1ms app.codeStats 1ms

/src/FreeImage/Source/ZLib/gzio.c

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