istereo

diff libs/zlib/gzio.c @ 26:862a3329a8f0

wohooo, added a shitload of code from zlib/libpng/libjpeg. When the good lord was raining shared libraries the iphone held a fucking umbrella...
author John Tsiombikas <nuclear@mutantstargoat.com>
date Thu, 08 Sep 2011 06:28:38 +0300
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/zlib/gzio.c	Thu Sep 08 06:28:38 2011 +0300
     1.3 @@ -0,0 +1,1026 @@
     1.4 +/* gzio.c -- IO on .gz files
     1.5 + * Copyright (C) 1995-2005 Jean-loup Gailly.
     1.6 + * For conditions of distribution and use, see copyright notice in zlib.h
     1.7 + *
     1.8 + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
     1.9 + */
    1.10 +
    1.11 +/* @(#) $Id$ */
    1.12 +
    1.13 +#include <stdio.h>
    1.14 +
    1.15 +#include "zutil.h"
    1.16 +
    1.17 +#ifdef NO_DEFLATE       /* for compatibility with old definition */
    1.18 +#  define NO_GZCOMPRESS
    1.19 +#endif
    1.20 +
    1.21 +#ifndef NO_DUMMY_DECL
    1.22 +struct internal_state {int dummy;}; /* for buggy compilers */
    1.23 +#endif
    1.24 +
    1.25 +#ifndef Z_BUFSIZE
    1.26 +#  ifdef MAXSEG_64K
    1.27 +#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
    1.28 +#  else
    1.29 +#    define Z_BUFSIZE 16384
    1.30 +#  endif
    1.31 +#endif
    1.32 +#ifndef Z_PRINTF_BUFSIZE
    1.33 +#  define Z_PRINTF_BUFSIZE 4096
    1.34 +#endif
    1.35 +
    1.36 +#ifdef __MVS__
    1.37 +#  pragma map (fdopen , "\174\174FDOPEN")
    1.38 +   FILE *fdopen(int, const char *);
    1.39 +#endif
    1.40 +
    1.41 +#ifndef STDC
    1.42 +extern voidp  malloc OF((uInt size));
    1.43 +extern void   free   OF((voidpf ptr));
    1.44 +#endif
    1.45 +
    1.46 +#define ALLOC(size) malloc(size)
    1.47 +#define TRYFREE(p) {if (p) free(p);}
    1.48 +
    1.49 +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
    1.50 +
    1.51 +/* gzip flag byte */
    1.52 +#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
    1.53 +#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
    1.54 +#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
    1.55 +#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
    1.56 +#define COMMENT      0x10 /* bit 4 set: file comment present */
    1.57 +#define RESERVED     0xE0 /* bits 5..7: reserved */
    1.58 +
    1.59 +typedef struct gz_stream {
    1.60 +    z_stream stream;
    1.61 +    int      z_err;   /* error code for last stream operation */
    1.62 +    int      z_eof;   /* set if end of input file */
    1.63 +    FILE     *file;   /* .gz file */
    1.64 +    Byte     *inbuf;  /* input buffer */
    1.65 +    Byte     *outbuf; /* output buffer */
    1.66 +    uLong    crc;     /* crc32 of uncompressed data */
    1.67 +    char     *msg;    /* error message */
    1.68 +    char     *path;   /* path name for debugging only */
    1.69 +    int      transparent; /* 1 if input file is not a .gz file */
    1.70 +    char     mode;    /* 'w' or 'r' */
    1.71 +    z_off_t  start;   /* start of compressed data in file (header skipped) */
    1.72 +    z_off_t  in;      /* bytes into deflate or inflate */
    1.73 +    z_off_t  out;     /* bytes out of deflate or inflate */
    1.74 +    int      back;    /* one character push-back */
    1.75 +    int      last;    /* true if push-back is last character */
    1.76 +} gz_stream;
    1.77 +
    1.78 +
    1.79 +local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
    1.80 +local int do_flush        OF((gzFile file, int flush));
    1.81 +local int    get_byte     OF((gz_stream *s));
    1.82 +local void   check_header OF((gz_stream *s));
    1.83 +local int    destroy      OF((gz_stream *s));
    1.84 +local void   putLong      OF((FILE *file, uLong x));
    1.85 +local uLong  getLong      OF((gz_stream *s));
    1.86 +
    1.87 +/* ===========================================================================
    1.88 +     Opens a gzip (.gz) file for reading or writing. The mode parameter
    1.89 +   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
    1.90 +   or path name (if fd == -1).
    1.91 +     gz_open returns NULL if the file could not be opened or if there was
    1.92 +   insufficient memory to allocate the (de)compression state; errno
    1.93 +   can be checked to distinguish the two cases (if errno is zero, the
    1.94 +   zlib error is Z_MEM_ERROR).
    1.95 +*/
    1.96 +local gzFile gz_open (path, mode, fd)
    1.97 +    const char *path;
    1.98 +    const char *mode;
    1.99 +    int  fd;
   1.100 +{
   1.101 +    int err;
   1.102 +    int level = Z_DEFAULT_COMPRESSION; /* compression level */
   1.103 +    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
   1.104 +    char *p = (char*)mode;
   1.105 +    gz_stream *s;
   1.106 +    char fmode[80]; /* copy of mode, without the compression level */
   1.107 +    char *m = fmode;
   1.108 +
   1.109 +    if (!path || !mode) return Z_NULL;
   1.110 +
   1.111 +    s = (gz_stream *)ALLOC(sizeof(gz_stream));
   1.112 +    if (!s) return Z_NULL;
   1.113 +
   1.114 +    s->stream.zalloc = (alloc_func)0;
   1.115 +    s->stream.zfree = (free_func)0;
   1.116 +    s->stream.opaque = (voidpf)0;
   1.117 +    s->stream.next_in = s->inbuf = Z_NULL;
   1.118 +    s->stream.next_out = s->outbuf = Z_NULL;
   1.119 +    s->stream.avail_in = s->stream.avail_out = 0;
   1.120 +    s->file = NULL;
   1.121 +    s->z_err = Z_OK;
   1.122 +    s->z_eof = 0;
   1.123 +    s->in = 0;
   1.124 +    s->out = 0;
   1.125 +    s->back = EOF;
   1.126 +    s->crc = crc32(0L, Z_NULL, 0);
   1.127 +    s->msg = NULL;
   1.128 +    s->transparent = 0;
   1.129 +
   1.130 +    s->path = (char*)ALLOC(strlen(path)+1);
   1.131 +    if (s->path == NULL) {
   1.132 +        return destroy(s), (gzFile)Z_NULL;
   1.133 +    }
   1.134 +    strcpy(s->path, path); /* do this early for debugging */
   1.135 +
   1.136 +    s->mode = '\0';
   1.137 +    do {
   1.138 +        if (*p == 'r') s->mode = 'r';
   1.139 +        if (*p == 'w' || *p == 'a') s->mode = 'w';
   1.140 +        if (*p >= '0' && *p <= '9') {
   1.141 +            level = *p - '0';
   1.142 +        } else if (*p == 'f') {
   1.143 +          strategy = Z_FILTERED;
   1.144 +        } else if (*p == 'h') {
   1.145 +          strategy = Z_HUFFMAN_ONLY;
   1.146 +        } else if (*p == 'R') {
   1.147 +          strategy = Z_RLE;
   1.148 +        } else {
   1.149 +            *m++ = *p; /* copy the mode */
   1.150 +        }
   1.151 +    } while (*p++ && m != fmode + sizeof(fmode));
   1.152 +    if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
   1.153 +
   1.154 +    if (s->mode == 'w') {
   1.155 +#ifdef NO_GZCOMPRESS
   1.156 +        err = Z_STREAM_ERROR;
   1.157 +#else
   1.158 +        err = deflateInit2(&(s->stream), level,
   1.159 +                           Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
   1.160 +        /* windowBits is passed < 0 to suppress zlib header */
   1.161 +
   1.162 +        s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
   1.163 +#endif
   1.164 +        if (err != Z_OK || s->outbuf == Z_NULL) {
   1.165 +            return destroy(s), (gzFile)Z_NULL;
   1.166 +        }
   1.167 +    } else {
   1.168 +        s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
   1.169 +
   1.170 +        err = inflateInit2(&(s->stream), -MAX_WBITS);
   1.171 +        /* windowBits is passed < 0 to tell that there is no zlib header.
   1.172 +         * Note that in this case inflate *requires* an extra "dummy" byte
   1.173 +         * after the compressed stream in order to complete decompression and
   1.174 +         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
   1.175 +         * present after the compressed stream.
   1.176 +         */
   1.177 +        if (err != Z_OK || s->inbuf == Z_NULL) {
   1.178 +            return destroy(s), (gzFile)Z_NULL;
   1.179 +        }
   1.180 +    }
   1.181 +    s->stream.avail_out = Z_BUFSIZE;
   1.182 +
   1.183 +    errno = 0;
   1.184 +    s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
   1.185 +
   1.186 +    if (s->file == NULL) {
   1.187 +        return destroy(s), (gzFile)Z_NULL;
   1.188 +    }
   1.189 +    if (s->mode == 'w') {
   1.190 +        /* Write a very simple .gz header:
   1.191 +         */
   1.192 +        fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
   1.193 +             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
   1.194 +        s->start = 10L;
   1.195 +        /* We use 10L instead of ftell(s->file) to because ftell causes an
   1.196 +         * fflush on some systems. This version of the library doesn't use
   1.197 +         * start anyway in write mode, so this initialization is not
   1.198 +         * necessary.
   1.199 +         */
   1.200 +    } else {
   1.201 +        check_header(s); /* skip the .gz header */
   1.202 +        s->start = ftell(s->file) - s->stream.avail_in;
   1.203 +    }
   1.204 +
   1.205 +    return (gzFile)s;
   1.206 +}
   1.207 +
   1.208 +/* ===========================================================================
   1.209 +     Opens a gzip (.gz) file for reading or writing.
   1.210 +*/
   1.211 +gzFile ZEXPORT gzopen (path, mode)
   1.212 +    const char *path;
   1.213 +    const char *mode;
   1.214 +{
   1.215 +    return gz_open (path, mode, -1);
   1.216 +}
   1.217 +
   1.218 +/* ===========================================================================
   1.219 +     Associate a gzFile with the file descriptor fd. fd is not dup'ed here
   1.220 +   to mimic the behavio(u)r of fdopen.
   1.221 +*/
   1.222 +gzFile ZEXPORT gzdopen (fd, mode)
   1.223 +    int fd;
   1.224 +    const char *mode;
   1.225 +{
   1.226 +    char name[46];      /* allow for up to 128-bit integers */
   1.227 +
   1.228 +    if (fd < 0) return (gzFile)Z_NULL;
   1.229 +    sprintf(name, "<fd:%d>", fd); /* for debugging */
   1.230 +
   1.231 +    return gz_open (name, mode, fd);
   1.232 +}
   1.233 +
   1.234 +/* ===========================================================================
   1.235 + * Update the compression level and strategy
   1.236 + */
   1.237 +int ZEXPORT gzsetparams (file, level, strategy)
   1.238 +    gzFile file;
   1.239 +    int level;
   1.240 +    int strategy;
   1.241 +{
   1.242 +    gz_stream *s = (gz_stream*)file;
   1.243 +
   1.244 +    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
   1.245 +
   1.246 +    /* Make room to allow flushing */
   1.247 +    if (s->stream.avail_out == 0) {
   1.248 +
   1.249 +        s->stream.next_out = s->outbuf;
   1.250 +        if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
   1.251 +            s->z_err = Z_ERRNO;
   1.252 +        }
   1.253 +        s->stream.avail_out = Z_BUFSIZE;
   1.254 +    }
   1.255 +
   1.256 +    return deflateParams (&(s->stream), level, strategy);
   1.257 +}
   1.258 +
   1.259 +/* ===========================================================================
   1.260 +     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
   1.261 +   for end of file.
   1.262 +   IN assertion: the stream s has been sucessfully opened for reading.
   1.263 +*/
   1.264 +local int get_byte(s)
   1.265 +    gz_stream *s;
   1.266 +{
   1.267 +    if (s->z_eof) return EOF;
   1.268 +    if (s->stream.avail_in == 0) {
   1.269 +        errno = 0;
   1.270 +        s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
   1.271 +        if (s->stream.avail_in == 0) {
   1.272 +            s->z_eof = 1;
   1.273 +            if (ferror(s->file)) s->z_err = Z_ERRNO;
   1.274 +            return EOF;
   1.275 +        }
   1.276 +        s->stream.next_in = s->inbuf;
   1.277 +    }
   1.278 +    s->stream.avail_in--;
   1.279 +    return *(s->stream.next_in)++;
   1.280 +}
   1.281 +
   1.282 +/* ===========================================================================
   1.283 +      Check the gzip header of a gz_stream opened for reading. Set the stream
   1.284 +    mode to transparent if the gzip magic header is not present; set s->err
   1.285 +    to Z_DATA_ERROR if the magic header is present but the rest of the header
   1.286 +    is incorrect.
   1.287 +    IN assertion: the stream s has already been created sucessfully;
   1.288 +       s->stream.avail_in is zero for the first time, but may be non-zero
   1.289 +       for concatenated .gz files.
   1.290 +*/
   1.291 +local void check_header(s)
   1.292 +    gz_stream *s;
   1.293 +{
   1.294 +    int method; /* method byte */
   1.295 +    int flags;  /* flags byte */
   1.296 +    uInt len;
   1.297 +    int c;
   1.298 +
   1.299 +    /* Assure two bytes in the buffer so we can peek ahead -- handle case
   1.300 +       where first byte of header is at the end of the buffer after the last
   1.301 +       gzip segment */
   1.302 +    len = s->stream.avail_in;
   1.303 +    if (len < 2) {
   1.304 +        if (len) s->inbuf[0] = s->stream.next_in[0];
   1.305 +        errno = 0;
   1.306 +        len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
   1.307 +        if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
   1.308 +        s->stream.avail_in += len;
   1.309 +        s->stream.next_in = s->inbuf;
   1.310 +        if (s->stream.avail_in < 2) {
   1.311 +            s->transparent = s->stream.avail_in;
   1.312 +            return;
   1.313 +        }
   1.314 +    }
   1.315 +
   1.316 +    /* Peek ahead to check the gzip magic header */
   1.317 +    if (s->stream.next_in[0] != gz_magic[0] ||
   1.318 +        s->stream.next_in[1] != gz_magic[1]) {
   1.319 +        s->transparent = 1;
   1.320 +        return;
   1.321 +    }
   1.322 +    s->stream.avail_in -= 2;
   1.323 +    s->stream.next_in += 2;
   1.324 +
   1.325 +    /* Check the rest of the gzip header */
   1.326 +    method = get_byte(s);
   1.327 +    flags = get_byte(s);
   1.328 +    if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
   1.329 +        s->z_err = Z_DATA_ERROR;
   1.330 +        return;
   1.331 +    }
   1.332 +
   1.333 +    /* Discard time, xflags and OS code: */
   1.334 +    for (len = 0; len < 6; len++) (void)get_byte(s);
   1.335 +
   1.336 +    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
   1.337 +        len  =  (uInt)get_byte(s);
   1.338 +        len += ((uInt)get_byte(s))<<8;
   1.339 +        /* len is garbage if EOF but the loop below will quit anyway */
   1.340 +        while (len-- != 0 && get_byte(s) != EOF) ;
   1.341 +    }
   1.342 +    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
   1.343 +        while ((c = get_byte(s)) != 0 && c != EOF) ;
   1.344 +    }
   1.345 +    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
   1.346 +        while ((c = get_byte(s)) != 0 && c != EOF) ;
   1.347 +    }
   1.348 +    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
   1.349 +        for (len = 0; len < 2; len++) (void)get_byte(s);
   1.350 +    }
   1.351 +    s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
   1.352 +}
   1.353 +
   1.354 + /* ===========================================================================
   1.355 + * Cleanup then free the given gz_stream. Return a zlib error code.
   1.356 +   Try freeing in the reverse order of allocations.
   1.357 + */
   1.358 +local int destroy (s)
   1.359 +    gz_stream *s;
   1.360 +{
   1.361 +    int err = Z_OK;
   1.362 +
   1.363 +    if (!s) return Z_STREAM_ERROR;
   1.364 +
   1.365 +    TRYFREE(s->msg);
   1.366 +
   1.367 +    if (s->stream.state != NULL) {
   1.368 +        if (s->mode == 'w') {
   1.369 +#ifdef NO_GZCOMPRESS
   1.370 +            err = Z_STREAM_ERROR;
   1.371 +#else
   1.372 +            err = deflateEnd(&(s->stream));
   1.373 +#endif
   1.374 +        } else if (s->mode == 'r') {
   1.375 +            err = inflateEnd(&(s->stream));
   1.376 +        }
   1.377 +    }
   1.378 +    if (s->file != NULL && fclose(s->file)) {
   1.379 +#ifdef ESPIPE
   1.380 +        if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
   1.381 +#endif
   1.382 +            err = Z_ERRNO;
   1.383 +    }
   1.384 +    if (s->z_err < 0) err = s->z_err;
   1.385 +
   1.386 +    TRYFREE(s->inbuf);
   1.387 +    TRYFREE(s->outbuf);
   1.388 +    TRYFREE(s->path);
   1.389 +    TRYFREE(s);
   1.390 +    return err;
   1.391 +}
   1.392 +
   1.393 +/* ===========================================================================
   1.394 +     Reads the given number of uncompressed bytes from the compressed file.
   1.395 +   gzread returns the number of bytes actually read (0 for end of file).
   1.396 +*/
   1.397 +int ZEXPORT gzread (file, buf, len)
   1.398 +    gzFile file;
   1.399 +    voidp buf;
   1.400 +    unsigned len;
   1.401 +{
   1.402 +    gz_stream *s = (gz_stream*)file;
   1.403 +    Bytef *start = (Bytef*)buf; /* starting point for crc computation */
   1.404 +    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
   1.405 +
   1.406 +    if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
   1.407 +
   1.408 +    if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
   1.409 +    if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
   1.410 +
   1.411 +    next_out = (Byte*)buf;
   1.412 +    s->stream.next_out = (Bytef*)buf;
   1.413 +    s->stream.avail_out = len;
   1.414 +
   1.415 +    if (s->stream.avail_out && s->back != EOF) {
   1.416 +        *next_out++ = s->back;
   1.417 +        s->stream.next_out++;
   1.418 +        s->stream.avail_out--;
   1.419 +        s->back = EOF;
   1.420 +        s->out++;
   1.421 +        start++;
   1.422 +        if (s->last) {
   1.423 +            s->z_err = Z_STREAM_END;
   1.424 +            return 1;
   1.425 +        }
   1.426 +    }
   1.427 +
   1.428 +    while (s->stream.avail_out != 0) {
   1.429 +
   1.430 +        if (s->transparent) {
   1.431 +            /* Copy first the lookahead bytes: */
   1.432 +            uInt n = s->stream.avail_in;
   1.433 +            if (n > s->stream.avail_out) n = s->stream.avail_out;
   1.434 +            if (n > 0) {
   1.435 +                zmemcpy(s->stream.next_out, s->stream.next_in, n);
   1.436 +                next_out += n;
   1.437 +                s->stream.next_out = next_out;
   1.438 +                s->stream.next_in   += n;
   1.439 +                s->stream.avail_out -= n;
   1.440 +                s->stream.avail_in  -= n;
   1.441 +            }
   1.442 +            if (s->stream.avail_out > 0) {
   1.443 +                s->stream.avail_out -=
   1.444 +                    (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
   1.445 +            }
   1.446 +            len -= s->stream.avail_out;
   1.447 +            s->in  += len;
   1.448 +            s->out += len;
   1.449 +            if (len == 0) s->z_eof = 1;
   1.450 +            return (int)len;
   1.451 +        }
   1.452 +        if (s->stream.avail_in == 0 && !s->z_eof) {
   1.453 +
   1.454 +            errno = 0;
   1.455 +            s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
   1.456 +            if (s->stream.avail_in == 0) {
   1.457 +                s->z_eof = 1;
   1.458 +                if (ferror(s->file)) {
   1.459 +                    s->z_err = Z_ERRNO;
   1.460 +                    break;
   1.461 +                }
   1.462 +            }
   1.463 +            s->stream.next_in = s->inbuf;
   1.464 +        }
   1.465 +        s->in += s->stream.avail_in;
   1.466 +        s->out += s->stream.avail_out;
   1.467 +        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
   1.468 +        s->in -= s->stream.avail_in;
   1.469 +        s->out -= s->stream.avail_out;
   1.470 +
   1.471 +        if (s->z_err == Z_STREAM_END) {
   1.472 +            /* Check CRC and original size */
   1.473 +            s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
   1.474 +            start = s->stream.next_out;
   1.475 +
   1.476 +            if (getLong(s) != s->crc) {
   1.477 +                s->z_err = Z_DATA_ERROR;
   1.478 +            } else {
   1.479 +                (void)getLong(s);
   1.480 +                /* The uncompressed length returned by above getlong() may be
   1.481 +                 * different from s->out in case of concatenated .gz files.
   1.482 +                 * Check for such files:
   1.483 +                 */
   1.484 +                check_header(s);
   1.485 +                if (s->z_err == Z_OK) {
   1.486 +                    inflateReset(&(s->stream));
   1.487 +                    s->crc = crc32(0L, Z_NULL, 0);
   1.488 +                }
   1.489 +            }
   1.490 +        }
   1.491 +        if (s->z_err != Z_OK || s->z_eof) break;
   1.492 +    }
   1.493 +    s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
   1.494 +
   1.495 +    if (len == s->stream.avail_out &&
   1.496 +        (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
   1.497 +        return -1;
   1.498 +    return (int)(len - s->stream.avail_out);
   1.499 +}
   1.500 +
   1.501 +
   1.502 +/* ===========================================================================
   1.503 +      Reads one byte from the compressed file. gzgetc returns this byte
   1.504 +   or -1 in case of end of file or error.
   1.505 +*/
   1.506 +int ZEXPORT gzgetc(file)
   1.507 +    gzFile file;
   1.508 +{
   1.509 +    unsigned char c;
   1.510 +
   1.511 +    return gzread(file, &c, 1) == 1 ? c : -1;
   1.512 +}
   1.513 +
   1.514 +
   1.515 +/* ===========================================================================
   1.516 +      Push one byte back onto the stream.
   1.517 +*/
   1.518 +int ZEXPORT gzungetc(c, file)
   1.519 +    int c;
   1.520 +    gzFile file;
   1.521 +{
   1.522 +    gz_stream *s = (gz_stream*)file;
   1.523 +
   1.524 +    if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
   1.525 +    s->back = c;
   1.526 +    s->out--;
   1.527 +    s->last = (s->z_err == Z_STREAM_END);
   1.528 +    if (s->last) s->z_err = Z_OK;
   1.529 +    s->z_eof = 0;
   1.530 +    return c;
   1.531 +}
   1.532 +
   1.533 +
   1.534 +/* ===========================================================================
   1.535 +      Reads bytes from the compressed file until len-1 characters are
   1.536 +   read, or a newline character is read and transferred to buf, or an
   1.537 +   end-of-file condition is encountered.  The string is then terminated
   1.538 +   with a null character.
   1.539 +      gzgets returns buf, or Z_NULL in case of error.
   1.540 +
   1.541 +      The current implementation is not optimized at all.
   1.542 +*/
   1.543 +char * ZEXPORT gzgets(file, buf, len)
   1.544 +    gzFile file;
   1.545 +    char *buf;
   1.546 +    int len;
   1.547 +{
   1.548 +    char *b = buf;
   1.549 +    if (buf == Z_NULL || len <= 0) return Z_NULL;
   1.550 +
   1.551 +    while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
   1.552 +    *buf = '\0';
   1.553 +    return b == buf && len > 0 ? Z_NULL : b;
   1.554 +}
   1.555 +
   1.556 +
   1.557 +#ifndef NO_GZCOMPRESS
   1.558 +/* ===========================================================================
   1.559 +     Writes the given number of uncompressed bytes into the compressed file.
   1.560 +   gzwrite returns the number of bytes actually written (0 in case of error).
   1.561 +*/
   1.562 +int ZEXPORT gzwrite (file, buf, len)
   1.563 +    gzFile file;
   1.564 +    voidpc buf;
   1.565 +    unsigned len;
   1.566 +{
   1.567 +    gz_stream *s = (gz_stream*)file;
   1.568 +
   1.569 +    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
   1.570 +
   1.571 +    s->stream.next_in = (Bytef*)buf;
   1.572 +    s->stream.avail_in = len;
   1.573 +
   1.574 +    while (s->stream.avail_in != 0) {
   1.575 +
   1.576 +        if (s->stream.avail_out == 0) {
   1.577 +
   1.578 +            s->stream.next_out = s->outbuf;
   1.579 +            if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
   1.580 +                s->z_err = Z_ERRNO;
   1.581 +                break;
   1.582 +            }
   1.583 +            s->stream.avail_out = Z_BUFSIZE;
   1.584 +        }
   1.585 +        s->in += s->stream.avail_in;
   1.586 +        s->out += s->stream.avail_out;
   1.587 +        s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
   1.588 +        s->in -= s->stream.avail_in;
   1.589 +        s->out -= s->stream.avail_out;
   1.590 +        if (s->z_err != Z_OK) break;
   1.591 +    }
   1.592 +    s->crc = crc32(s->crc, (const Bytef *)buf, len);
   1.593 +
   1.594 +    return (int)(len - s->stream.avail_in);
   1.595 +}
   1.596 +
   1.597 +
   1.598 +/* ===========================================================================
   1.599 +     Converts, formats, and writes the args to the compressed file under
   1.600 +   control of the format string, as in fprintf. gzprintf returns the number of
   1.601 +   uncompressed bytes actually written (0 in case of error).
   1.602 +*/
   1.603 +#ifdef STDC
   1.604 +#include <stdarg.h>
   1.605 +
   1.606 +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
   1.607 +{
   1.608 +    char buf[Z_PRINTF_BUFSIZE];
   1.609 +    va_list va;
   1.610 +    int len;
   1.611 +
   1.612 +    buf[sizeof(buf) - 1] = 0;
   1.613 +    va_start(va, format);
   1.614 +#ifdef NO_vsnprintf
   1.615 +#  ifdef HAS_vsprintf_void
   1.616 +    (void)vsprintf(buf, format, va);
   1.617 +    va_end(va);
   1.618 +    for (len = 0; len < sizeof(buf); len++)
   1.619 +        if (buf[len] == 0) break;
   1.620 +#  else
   1.621 +    len = vsprintf(buf, format, va);
   1.622 +    va_end(va);
   1.623 +#  endif
   1.624 +#else
   1.625 +#  ifdef HAS_vsnprintf_void
   1.626 +    (void)vsnprintf(buf, sizeof(buf), format, va);
   1.627 +    va_end(va);
   1.628 +    len = strlen(buf);
   1.629 +#  else
   1.630 +    len = vsnprintf(buf, sizeof(buf), format, va);
   1.631 +    va_end(va);
   1.632 +#  endif
   1.633 +#endif
   1.634 +    if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
   1.635 +        return 0;
   1.636 +    return gzwrite(file, buf, (unsigned)len);
   1.637 +}
   1.638 +#else /* not ANSI C */
   1.639 +
   1.640 +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
   1.641 +                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
   1.642 +    gzFile file;
   1.643 +    const char *format;
   1.644 +    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
   1.645 +        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
   1.646 +{
   1.647 +    char buf[Z_PRINTF_BUFSIZE];
   1.648 +    int len;
   1.649 +
   1.650 +    buf[sizeof(buf) - 1] = 0;
   1.651 +#ifdef NO_snprintf
   1.652 +#  ifdef HAS_sprintf_void
   1.653 +    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
   1.654 +            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
   1.655 +    for (len = 0; len < sizeof(buf); len++)
   1.656 +        if (buf[len] == 0) break;
   1.657 +#  else
   1.658 +    len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
   1.659 +                a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
   1.660 +#  endif
   1.661 +#else
   1.662 +#  ifdef HAS_snprintf_void
   1.663 +    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
   1.664 +             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
   1.665 +    len = strlen(buf);
   1.666 +#  else
   1.667 +    len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
   1.668 +                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
   1.669 +#  endif
   1.670 +#endif
   1.671 +    if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
   1.672 +        return 0;
   1.673 +    return gzwrite(file, buf, len);
   1.674 +}
   1.675 +#endif
   1.676 +
   1.677 +/* ===========================================================================
   1.678 +      Writes c, converted to an unsigned char, into the compressed file.
   1.679 +   gzputc returns the value that was written, or -1 in case of error.
   1.680 +*/
   1.681 +int ZEXPORT gzputc(file, c)
   1.682 +    gzFile file;
   1.683 +    int c;
   1.684 +{
   1.685 +    unsigned char cc = (unsigned char) c; /* required for big endian systems */
   1.686 +
   1.687 +    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
   1.688 +}
   1.689 +
   1.690 +
   1.691 +/* ===========================================================================
   1.692 +      Writes the given null-terminated string to the compressed file, excluding
   1.693 +   the terminating null character.
   1.694 +      gzputs returns the number of characters written, or -1 in case of error.
   1.695 +*/
   1.696 +int ZEXPORT gzputs(file, s)
   1.697 +    gzFile file;
   1.698 +    const char *s;
   1.699 +{
   1.700 +    return gzwrite(file, (char*)s, (unsigned)strlen(s));
   1.701 +}
   1.702 +
   1.703 +
   1.704 +/* ===========================================================================
   1.705 +     Flushes all pending output into the compressed file. The parameter
   1.706 +   flush is as in the deflate() function.
   1.707 +*/
   1.708 +local int do_flush (file, flush)
   1.709 +    gzFile file;
   1.710 +    int flush;
   1.711 +{
   1.712 +    uInt len;
   1.713 +    int done = 0;
   1.714 +    gz_stream *s = (gz_stream*)file;
   1.715 +
   1.716 +    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
   1.717 +
   1.718 +    s->stream.avail_in = 0; /* should be zero already anyway */
   1.719 +
   1.720 +    for (;;) {
   1.721 +        len = Z_BUFSIZE - s->stream.avail_out;
   1.722 +
   1.723 +        if (len != 0) {
   1.724 +            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
   1.725 +                s->z_err = Z_ERRNO;
   1.726 +                return Z_ERRNO;
   1.727 +            }
   1.728 +            s->stream.next_out = s->outbuf;
   1.729 +            s->stream.avail_out = Z_BUFSIZE;
   1.730 +        }
   1.731 +        if (done) break;
   1.732 +        s->out += s->stream.avail_out;
   1.733 +        s->z_err = deflate(&(s->stream), flush);
   1.734 +        s->out -= s->stream.avail_out;
   1.735 +
   1.736 +        /* Ignore the second of two consecutive flushes: */
   1.737 +        if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
   1.738 +
   1.739 +        /* deflate has finished flushing only when it hasn't used up
   1.740 +         * all the available space in the output buffer:
   1.741 +         */
   1.742 +        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
   1.743 +
   1.744 +        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
   1.745 +    }
   1.746 +    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
   1.747 +}
   1.748 +
   1.749 +int ZEXPORT gzflush (file, flush)
   1.750 +     gzFile file;
   1.751 +     int flush;
   1.752 +{
   1.753 +    gz_stream *s = (gz_stream*)file;
   1.754 +    int err = do_flush (file, flush);
   1.755 +
   1.756 +    if (err) return err;
   1.757 +    fflush(s->file);
   1.758 +    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
   1.759 +}
   1.760 +#endif /* NO_GZCOMPRESS */
   1.761 +
   1.762 +/* ===========================================================================
   1.763 +      Sets the starting position for the next gzread or gzwrite on the given
   1.764 +   compressed file. The offset represents a number of bytes in the
   1.765 +      gzseek returns the resulting offset location as measured in bytes from
   1.766 +   the beginning of the uncompressed stream, or -1 in case of error.
   1.767 +      SEEK_END is not implemented, returns error.
   1.768 +      In this version of the library, gzseek can be extremely slow.
   1.769 +*/
   1.770 +z_off_t ZEXPORT gzseek (file, offset, whence)
   1.771 +    gzFile file;
   1.772 +    z_off_t offset;
   1.773 +    int whence;
   1.774 +{
   1.775 +    gz_stream *s = (gz_stream*)file;
   1.776 +
   1.777 +    if (s == NULL || whence == SEEK_END ||
   1.778 +        s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
   1.779 +        return -1L;
   1.780 +    }
   1.781 +
   1.782 +    if (s->mode == 'w') {
   1.783 +#ifdef NO_GZCOMPRESS
   1.784 +        return -1L;
   1.785 +#else
   1.786 +        if (whence == SEEK_SET) {
   1.787 +            offset -= s->in;
   1.788 +        }
   1.789 +        if (offset < 0) return -1L;
   1.790 +
   1.791 +        /* At this point, offset is the number of zero bytes to write. */
   1.792 +        if (s->inbuf == Z_NULL) {
   1.793 +            s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
   1.794 +            if (s->inbuf == Z_NULL) return -1L;
   1.795 +            zmemzero(s->inbuf, Z_BUFSIZE);
   1.796 +        }
   1.797 +        while (offset > 0)  {
   1.798 +            uInt size = Z_BUFSIZE;
   1.799 +            if (offset < Z_BUFSIZE) size = (uInt)offset;
   1.800 +
   1.801 +            size = gzwrite(file, s->inbuf, size);
   1.802 +            if (size == 0) return -1L;
   1.803 +
   1.804 +            offset -= size;
   1.805 +        }
   1.806 +        return s->in;
   1.807 +#endif
   1.808 +    }
   1.809 +    /* Rest of function is for reading only */
   1.810 +
   1.811 +    /* compute absolute position */
   1.812 +    if (whence == SEEK_CUR) {
   1.813 +        offset += s->out;
   1.814 +    }
   1.815 +    if (offset < 0) return -1L;
   1.816 +
   1.817 +    if (s->transparent) {
   1.818 +        /* map to fseek */
   1.819 +        s->back = EOF;
   1.820 +        s->stream.avail_in = 0;
   1.821 +        s->stream.next_in = s->inbuf;
   1.822 +        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
   1.823 +
   1.824 +        s->in = s->out = offset;
   1.825 +        return offset;
   1.826 +    }
   1.827 +
   1.828 +    /* For a negative seek, rewind and use positive seek */
   1.829 +    if (offset >= s->out) {
   1.830 +        offset -= s->out;
   1.831 +    } else if (gzrewind(file) < 0) {
   1.832 +        return -1L;
   1.833 +    }
   1.834 +    /* offset is now the number of bytes to skip. */
   1.835 +
   1.836 +    if (offset != 0 && s->outbuf == Z_NULL) {
   1.837 +        s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
   1.838 +        if (s->outbuf == Z_NULL) return -1L;
   1.839 +    }
   1.840 +    if (offset && s->back != EOF) {
   1.841 +        s->back = EOF;
   1.842 +        s->out++;
   1.843 +        offset--;
   1.844 +        if (s->last) s->z_err = Z_STREAM_END;
   1.845 +    }
   1.846 +    while (offset > 0)  {
   1.847 +        int size = Z_BUFSIZE;
   1.848 +        if (offset < Z_BUFSIZE) size = (int)offset;
   1.849 +
   1.850 +        size = gzread(file, s->outbuf, (uInt)size);
   1.851 +        if (size <= 0) return -1L;
   1.852 +        offset -= size;
   1.853 +    }
   1.854 +    return s->out;
   1.855 +}
   1.856 +
   1.857 +/* ===========================================================================
   1.858 +     Rewinds input file.
   1.859 +*/
   1.860 +int ZEXPORT gzrewind (file)
   1.861 +    gzFile file;
   1.862 +{
   1.863 +    gz_stream *s = (gz_stream*)file;
   1.864 +
   1.865 +    if (s == NULL || s->mode != 'r') return -1;
   1.866 +
   1.867 +    s->z_err = Z_OK;
   1.868 +    s->z_eof = 0;
   1.869 +    s->back = EOF;
   1.870 +    s->stream.avail_in = 0;
   1.871 +    s->stream.next_in = s->inbuf;
   1.872 +    s->crc = crc32(0L, Z_NULL, 0);
   1.873 +    if (!s->transparent) (void)inflateReset(&s->stream);
   1.874 +    s->in = 0;
   1.875 +    s->out = 0;
   1.876 +    return fseek(s->file, s->start, SEEK_SET);
   1.877 +}
   1.878 +
   1.879 +/* ===========================================================================
   1.880 +     Returns the starting position for the next gzread or gzwrite on the
   1.881 +   given compressed file. This position represents a number of bytes in the
   1.882 +   uncompressed data stream.
   1.883 +*/
   1.884 +z_off_t ZEXPORT gztell (file)
   1.885 +    gzFile file;
   1.886 +{
   1.887 +    return gzseek(file, 0L, SEEK_CUR);
   1.888 +}
   1.889 +
   1.890 +/* ===========================================================================
   1.891 +     Returns 1 when EOF has previously been detected reading the given
   1.892 +   input stream, otherwise zero.
   1.893 +*/
   1.894 +int ZEXPORT gzeof (file)
   1.895 +    gzFile file;
   1.896 +{
   1.897 +    gz_stream *s = (gz_stream*)file;
   1.898 +
   1.899 +    /* With concatenated compressed files that can have embedded
   1.900 +     * crc trailers, z_eof is no longer the only/best indicator of EOF
   1.901 +     * on a gz_stream. Handle end-of-stream error explicitly here.
   1.902 +     */
   1.903 +    if (s == NULL || s->mode != 'r') return 0;
   1.904 +    if (s->z_eof) return 1;
   1.905 +    return s->z_err == Z_STREAM_END;
   1.906 +}
   1.907 +
   1.908 +/* ===========================================================================
   1.909 +     Returns 1 if reading and doing so transparently, otherwise zero.
   1.910 +*/
   1.911 +int ZEXPORT gzdirect (file)
   1.912 +    gzFile file;
   1.913 +{
   1.914 +    gz_stream *s = (gz_stream*)file;
   1.915 +
   1.916 +    if (s == NULL || s->mode != 'r') return 0;
   1.917 +    return s->transparent;
   1.918 +}
   1.919 +
   1.920 +/* ===========================================================================
   1.921 +   Outputs a long in LSB order to the given file
   1.922 +*/
   1.923 +local void putLong (file, x)
   1.924 +    FILE *file;
   1.925 +    uLong x;
   1.926 +{
   1.927 +    int n;
   1.928 +    for (n = 0; n < 4; n++) {
   1.929 +        fputc((int)(x & 0xff), file);
   1.930 +        x >>= 8;
   1.931 +    }
   1.932 +}
   1.933 +
   1.934 +/* ===========================================================================
   1.935 +   Reads a long in LSB order from the given gz_stream. Sets z_err in case
   1.936 +   of error.
   1.937 +*/
   1.938 +local uLong getLong (s)
   1.939 +    gz_stream *s;
   1.940 +{
   1.941 +    uLong x = (uLong)get_byte(s);
   1.942 +    int c;
   1.943 +
   1.944 +    x += ((uLong)get_byte(s))<<8;
   1.945 +    x += ((uLong)get_byte(s))<<16;
   1.946 +    c = get_byte(s);
   1.947 +    if (c == EOF) s->z_err = Z_DATA_ERROR;
   1.948 +    x += ((uLong)c)<<24;
   1.949 +    return x;
   1.950 +}
   1.951 +
   1.952 +/* ===========================================================================
   1.953 +     Flushes all pending output if necessary, closes the compressed file
   1.954 +   and deallocates all the (de)compression state.
   1.955 +*/
   1.956 +int ZEXPORT gzclose (file)
   1.957 +    gzFile file;
   1.958 +{
   1.959 +    gz_stream *s = (gz_stream*)file;
   1.960 +
   1.961 +    if (s == NULL) return Z_STREAM_ERROR;
   1.962 +
   1.963 +    if (s->mode == 'w') {
   1.964 +#ifdef NO_GZCOMPRESS
   1.965 +        return Z_STREAM_ERROR;
   1.966 +#else
   1.967 +        if (do_flush (file, Z_FINISH) != Z_OK)
   1.968 +            return destroy((gz_stream*)file);
   1.969 +
   1.970 +        putLong (s->file, s->crc);
   1.971 +        putLong (s->file, (uLong)(s->in & 0xffffffff));
   1.972 +#endif
   1.973 +    }
   1.974 +    return destroy((gz_stream*)file);
   1.975 +}
   1.976 +
   1.977 +#ifdef STDC
   1.978 +#  define zstrerror(errnum) strerror(errnum)
   1.979 +#else
   1.980 +#  define zstrerror(errnum) ""
   1.981 +#endif
   1.982 +
   1.983 +/* ===========================================================================
   1.984 +     Returns the error message for the last error which occurred on the
   1.985 +   given compressed file. errnum is set to zlib error number. If an
   1.986 +   error occurred in the file system and not in the compression library,
   1.987 +   errnum is set to Z_ERRNO and the application may consult errno
   1.988 +   to get the exact error code.
   1.989 +*/
   1.990 +const char * ZEXPORT gzerror (file, errnum)
   1.991 +    gzFile file;
   1.992 +    int *errnum;
   1.993 +{
   1.994 +    char *m;
   1.995 +    gz_stream *s = (gz_stream*)file;
   1.996 +
   1.997 +    if (s == NULL) {
   1.998 +        *errnum = Z_STREAM_ERROR;
   1.999 +        return (const char*)ERR_MSG(Z_STREAM_ERROR);
  1.1000 +    }
  1.1001 +    *errnum = s->z_err;
  1.1002 +    if (*errnum == Z_OK) return (const char*)"";
  1.1003 +
  1.1004 +    m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
  1.1005 +
  1.1006 +    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
  1.1007 +
  1.1008 +    TRYFREE(s->msg);
  1.1009 +    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
  1.1010 +    if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
  1.1011 +    strcpy(s->msg, s->path);
  1.1012 +    strcat(s->msg, ": ");
  1.1013 +    strcat(s->msg, m);
  1.1014 +    return (const char*)s->msg;
  1.1015 +}
  1.1016 +
  1.1017 +/* ===========================================================================
  1.1018 +     Clear the error and end-of-file flags, and do the same for the real file.
  1.1019 +*/
  1.1020 +void ZEXPORT gzclearerr (file)
  1.1021 +    gzFile file;
  1.1022 +{
  1.1023 +    gz_stream *s = (gz_stream*)file;
  1.1024 +
  1.1025 +    if (s == NULL) return;
  1.1026 +    if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
  1.1027 +    s->z_eof = 0;
  1.1028 +    clearerr(s->file);
  1.1029 +}