gzio.c 28.0 KB
Newer Older
M
Mark Adler 已提交
1
/* gzio.c -- IO on .gz files
M
Mark Adler 已提交
2
 * Copyright (C) 1995-2003 Jean-loup Gailly.
M
Mark Adler 已提交
3
 * For conditions of distribution and use, see copyright notice in zlib.h
M
Mark Adler 已提交
4 5
 *
 * Compile this file with -DNO_DEFLATE to avoid the compression code.
M
Mark Adler 已提交
6 7
 */

M
Mark Adler 已提交
8
/* @(#) $Id$ */
M
Mark Adler 已提交
9 10 11 12 13 14 15

#include <stdio.h>

#include "zutil.h"

struct internal_state {int dummy;}; /* for buggy compilers */

M
Mark Adler 已提交
16 17 18 19 20 21 22 23 24 25
#ifndef Z_BUFSIZE
#  ifdef MAXSEG_64K
#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
#  else
#    define Z_BUFSIZE 16384
#  endif
#endif
#ifndef Z_PRINTF_BUFSIZE
#  define Z_PRINTF_BUFSIZE 4096
#endif
M
Mark Adler 已提交
26

M
Mark Adler 已提交
27 28 29 30 31
#ifndef STDC
extern voidp  malloc OF((uInt size));
extern void   free   OF((voidpf ptr));
#endif

M
Mark Adler 已提交
32 33
#define ALLOC(size) malloc(size)
#define TRYFREE(p) {if (p) free(p);}
M
Mark Adler 已提交
34

M
Mark Adler 已提交
35
static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
M
Mark Adler 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

/* gzip flag byte */
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
#define COMMENT      0x10 /* bit 4 set: file comment present */
#define RESERVED     0xE0 /* bits 5..7: reserved */

typedef struct gz_stream {
    z_stream stream;
    int      z_err;   /* error code for last stream operation */
    int      z_eof;   /* set if end of input file */
    FILE     *file;   /* .gz file */
    Byte     *inbuf;  /* input buffer */
    Byte     *outbuf; /* output buffer */
    uLong    crc;     /* crc32 of uncompressed data */
    char     *msg;    /* error message */
    char     *path;   /* path name for debugging only */
    int      transparent; /* 1 if input file is not a .gz file */
    char     mode;    /* 'w' or 'r' */
M
Mark Adler 已提交
57
    long     startpos; /* start of compressed data in file (header skipped) */
M
Mark Adler 已提交
58 59 60
} gz_stream;


M
Mark Adler 已提交
61
local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
M
Mark Adler 已提交
62
local int do_flush        OF((gzFile file, int flush));
M
Mark Adler 已提交
63 64 65 66 67
local int    get_byte     OF((gz_stream *s));
local void   check_header OF((gz_stream *s));
local int    destroy      OF((gz_stream *s));
local void   putLong      OF((FILE *file, uLong x));
local uLong  getLong      OF((gz_stream *s));
M
Mark Adler 已提交
68 69 70

/* ===========================================================================
     Opens a gzip (.gz) file for reading or writing. The mode parameter
M
Mark Adler 已提交
71
   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
M
Mark Adler 已提交
72 73 74 75 76 77 78
   or path name (if fd == -1).
     gz_open return NULL if the file could not be opened or if there was
   insufficient memory to allocate the (de)compression state; errno
   can be checked to distinguish the two cases (if errno is zero, the
   zlib error is Z_MEM_ERROR).
*/
local gzFile gz_open (path, mode, fd)
M
Mark Adler 已提交
79 80
    const char *path;
    const char *mode;
M
Mark Adler 已提交
81 82 83
    int  fd;
{
    int err;
M
Mark Adler 已提交
84
    int level = Z_DEFAULT_COMPRESSION; /* compression level */
M
Mark Adler 已提交
85
    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
M
Mark Adler 已提交
86 87 88 89 90 91
    char *p = (char*)mode;
    gz_stream *s;
    char fmode[80]; /* copy of mode, without the compression level */
    char *m = fmode;

    if (!path || !mode) return Z_NULL;
M
Mark Adler 已提交
92

M
Mark Adler 已提交
93
    s = (gz_stream *)ALLOC(sizeof(gz_stream));
M
Mark Adler 已提交
94 95 96 97
    if (!s) return Z_NULL;

    s->stream.zalloc = (alloc_func)0;
    s->stream.zfree = (free_func)0;
M
Mark Adler 已提交
98
    s->stream.opaque = (voidpf)0;
M
Mark Adler 已提交
99 100 101 102 103 104 105 106 107 108 109 110
    s->stream.next_in = s->inbuf = Z_NULL;
    s->stream.next_out = s->outbuf = Z_NULL;
    s->stream.avail_in = s->stream.avail_out = 0;
    s->file = NULL;
    s->z_err = Z_OK;
    s->z_eof = 0;
    s->crc = crc32(0L, Z_NULL, 0);
    s->msg = NULL;
    s->transparent = 0;

    s->path = (char*)ALLOC(strlen(path)+1);
    if (s->path == NULL) {
M
Mark Adler 已提交
111
        return destroy(s), (gzFile)Z_NULL;
M
Mark Adler 已提交
112 113 114 115 116
    }
    strcpy(s->path, path); /* do this early for debugging */

    s->mode = '\0';
    do {
M
Mark Adler 已提交
117
        if (*p == 'r') s->mode = 'r';
M
Mark Adler 已提交
118 119
        if (*p == 'w' || *p == 'a') s->mode = 'w';
        if (*p >= '0' && *p <= '9') {
M
Mark Adler 已提交
120 121 122 123 124 125 126 127 128 129
            level = *p - '0';
        } else if (*p == 'f') {
          strategy = Z_FILTERED;
        } else if (*p == 'h') {
          strategy = Z_HUFFMAN_ONLY;
        } else if (*p == 'R') {
          strategy = Z_RLE;
        } else {
            *m++ = *p; /* copy the mode */
        }
M
Mark Adler 已提交
130
    } while (*p++ && m != fmode + sizeof(fmode));
M
Mark Adler 已提交
131
    if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
M
Mark Adler 已提交
132

M
Mark Adler 已提交
133
    if (s->mode == 'w') {
M
Mark Adler 已提交
134 135 136
#ifdef NO_DEFLATE
        err = Z_STREAM_ERROR;
#else
M
Mark Adler 已提交
137
        err = deflateInit2(&(s->stream), level,
M
Mark Adler 已提交
138
                           Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
M
Mark Adler 已提交
139
        /* windowBits is passed < 0 to suppress zlib header */
M
Mark Adler 已提交
140

M
Mark Adler 已提交
141
        s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
M
Mark Adler 已提交
142
#endif
M
Mark Adler 已提交
143 144 145
        if (err != Z_OK || s->outbuf == Z_NULL) {
            return destroy(s), (gzFile)Z_NULL;
        }
M
Mark Adler 已提交
146
    } else {
M
Mark Adler 已提交
147
        s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
M
Mark Adler 已提交
148

M
Mark Adler 已提交
149
        err = inflateInit2(&(s->stream), -MAX_WBITS);
M
Mark Adler 已提交
150 151 152 153 154 155
        /* windowBits is passed < 0 to tell that there is no zlib header.
         * Note that in this case inflate *requires* an extra "dummy" byte
         * after the compressed stream in order to complete decompression and
         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
         * present after the compressed stream.
         */
M
Mark Adler 已提交
156 157 158
        if (err != Z_OK || s->inbuf == Z_NULL) {
            return destroy(s), (gzFile)Z_NULL;
        }
M
Mark Adler 已提交
159 160 161 162
    }
    s->stream.avail_out = Z_BUFSIZE;

    errno = 0;
M
Mark Adler 已提交
163
    s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
M
Mark Adler 已提交
164 165

    if (s->file == NULL) {
M
Mark Adler 已提交
166
        return destroy(s), (gzFile)Z_NULL;
M
Mark Adler 已提交
167 168
    }
    if (s->mode == 'w') {
M
Mark Adler 已提交
169 170
        /* Write a very simple .gz header:
         */
M
Mark Adler 已提交
171
        fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
M
Mark Adler 已提交
172
             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
M
Mark Adler 已提交
173 174
        s->startpos = 10L;
        /* We use 10L instead of ftell(s->file) to because ftell causes an
M
Mark Adler 已提交
175 176 177 178
         * fflush on some systems. This version of the library doesn't use
         * startpos anyway in write mode, so this initialization is not
         * necessary.
         */
M
Mark Adler 已提交
179
    } else {
M
Mark Adler 已提交
180 181
        check_header(s); /* skip the .gz header */
        s->startpos = (ftell(s->file) - s->stream.avail_in);
M
Mark Adler 已提交
182
    }
M
Mark Adler 已提交
183

M
Mark Adler 已提交
184 185 186 187 188 189
    return (gzFile)s;
}

/* ===========================================================================
     Opens a gzip (.gz) file for reading or writing.
*/
M
Mark Adler 已提交
190
gzFile ZEXPORT gzopen (path, mode)
M
Mark Adler 已提交
191 192
    const char *path;
    const char *mode;
M
Mark Adler 已提交
193 194 195 196 197
{
    return gz_open (path, mode, -1);
}

/* ===========================================================================
M
Mark Adler 已提交
198 199
     Associate a gzFile with the file descriptor fd. fd is not dup'ed here
   to mimic the behavio(u)r of fdopen.
M
Mark Adler 已提交
200
*/
M
Mark Adler 已提交
201
gzFile ZEXPORT gzdopen (fd, mode)
M
Mark Adler 已提交
202
    int fd;
M
Mark Adler 已提交
203
    const char *mode;
M
Mark Adler 已提交
204 205
{
    char name[20];
M
Mark Adler 已提交
206 207

    if (fd < 0) return (gzFile)Z_NULL;
M
Mark Adler 已提交
208
    sprintf(name, "<fd:%d>", fd); /* for debugging */
M
Mark Adler 已提交
209 210 211 212

    return gz_open (name, mode, fd);
}

M
Mark Adler 已提交
213 214 215
/* ===========================================================================
 * Update the compression level and strategy
 */
M
Mark Adler 已提交
216
int ZEXPORT gzsetparams (file, level, strategy)
M
Mark Adler 已提交
217 218 219 220 221 222 223 224 225 226 227
    gzFile file;
    int level;
    int strategy;
{
    gz_stream *s = (gz_stream*)file;

    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;

    /* Make room to allow flushing */
    if (s->stream.avail_out == 0) {

M
Mark Adler 已提交
228 229 230 231 232
        s->stream.next_out = s->outbuf;
        if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
            s->z_err = Z_ERRNO;
        }
        s->stream.avail_out = Z_BUFSIZE;
M
Mark Adler 已提交
233 234 235 236 237
    }

    return deflateParams (&(s->stream), level, strategy);
}

M
Mark Adler 已提交
238 239 240 241 242 243 244 245 246 247
/* ===========================================================================
     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
   for end of file.
   IN assertion: the stream s has been sucessfully opened for reading.
*/
local int get_byte(s)
    gz_stream *s;
{
    if (s->z_eof) return EOF;
    if (s->stream.avail_in == 0) {
M
Mark Adler 已提交
248 249 250 251 252 253 254 255
        errno = 0;
        s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
        if (s->stream.avail_in == 0) {
            s->z_eof = 1;
            if (ferror(s->file)) s->z_err = Z_ERRNO;
            return EOF;
        }
        s->stream.next_in = s->inbuf;
M
Mark Adler 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
    }
    s->stream.avail_in--;
    return *(s->stream.next_in)++;
}

/* ===========================================================================
      Check the gzip header of a gz_stream opened for reading. Set the stream
    mode to transparent if the gzip magic header is not present; set s->err
    to Z_DATA_ERROR if the magic header is present but the rest of the header
    is incorrect.
    IN assertion: the stream s has already been created sucessfully;
       s->stream.avail_in is zero for the first time, but may be non-zero
       for concatenated .gz files.
*/
local void check_header(s)
    gz_stream *s;
{
    int method; /* method byte */
    int flags;  /* flags byte */
    uInt len;
    int c;

M
Mark Adler 已提交
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    /* Assure two bytes in the buffer so we can peek ahead -- handle case
       where first byte of header is at the end of the buffer after the last
       gzip segment */
    len = s->stream.avail_in;
    if (len < 2) {
        if (len) s->inbuf[0] = s->stream.next_in[0];
        errno = 0;
        len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
        if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
        s->stream.avail_in += len;
        s->stream.next_in = s->inbuf;
        if (s->stream.avail_in < 2) {
            s->transparent = s->stream.avail_in;
            return;
        }
M
Mark Adler 已提交
293
    }
M
Mark Adler 已提交
294 295 296

    /* Peek ahead to check the gzip magic header */
    if (s->stream.next_in[0] != gz_magic[0] ||
M
Mark Adler 已提交
297
        s->stream.next_in[1] != gz_magic[1]) {
M
Mark Adler 已提交
298 299 300 301 302 303 304
        s->transparent = 1;
        return;
    }
    s->stream.avail_in -= 2;
    s->stream.next_in += 2;

    /* Check the rest of the gzip header */
M
Mark Adler 已提交
305 306 307
    method = get_byte(s);
    flags = get_byte(s);
    if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
M
Mark Adler 已提交
308 309
        s->z_err = Z_DATA_ERROR;
        return;
M
Mark Adler 已提交
310 311 312 313 314 315
    }

    /* Discard time, xflags and OS code: */
    for (len = 0; len < 6; len++) (void)get_byte(s);

    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
M
Mark Adler 已提交
316 317 318 319
        len  =  (uInt)get_byte(s);
        len += ((uInt)get_byte(s))<<8;
        /* len is garbage if EOF but the loop below will quit anyway */
        while (len-- != 0 && get_byte(s) != EOF) ;
M
Mark Adler 已提交
320 321
    }
    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
M
Mark Adler 已提交
322
        while ((c = get_byte(s)) != 0 && c != EOF) ;
M
Mark Adler 已提交
323 324
    }
    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
M
Mark Adler 已提交
325
        while ((c = get_byte(s)) != 0 && c != EOF) ;
M
Mark Adler 已提交
326 327
    }
    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
M
Mark Adler 已提交
328
        for (len = 0; len < 2; len++) (void)get_byte(s);
M
Mark Adler 已提交
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
    }
    s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
}

 /* ===========================================================================
 * Cleanup then free the given gz_stream. Return a zlib error code.
   Try freeing in the reverse order of allocations.
 */
local int destroy (s)
    gz_stream *s;
{
    int err = Z_OK;

    if (!s) return Z_STREAM_ERROR;

    TRYFREE(s->msg);

    if (s->stream.state != NULL) {
M
Mark Adler 已提交
347
        if (s->mode == 'w') {
M
Mark Adler 已提交
348
#ifdef NO_DEFLATE
M
Mark Adler 已提交
349
            err = Z_STREAM_ERROR;
M
Mark Adler 已提交
350
#else
M
Mark Adler 已提交
351
            err = deflateEnd(&(s->stream));
M
Mark Adler 已提交
352
#endif
M
Mark Adler 已提交
353 354 355
        } else if (s->mode == 'r') {
            err = inflateEnd(&(s->stream));
        }
M
Mark Adler 已提交
356 357
    }
    if (s->file != NULL && fclose(s->file)) {
M
Mark Adler 已提交
358
#ifdef ESPIPE
M
Mark Adler 已提交
359
        if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
M
Mark Adler 已提交
360
#endif
M
Mark Adler 已提交
361
            err = Z_ERRNO;
M
Mark Adler 已提交
362 363 364 365 366 367 368 369 370 371
    }
    if (s->z_err < 0) err = s->z_err;

    TRYFREE(s->inbuf);
    TRYFREE(s->outbuf);
    TRYFREE(s->path);
    TRYFREE(s);
    return err;
}

M
Mark Adler 已提交
372 373 374 375
/* ===========================================================================
     Reads the given number of uncompressed bytes from the compressed file.
   gzread returns the number of bytes actually read (0 for end of file).
*/
M
Mark Adler 已提交
376
int ZEXPORT gzread (file, buf, len)
M
Mark Adler 已提交
377
    gzFile file;
M
Mark Adler 已提交
378
    voidp buf;
M
Mark Adler 已提交
379 380 381
    unsigned len;
{
    gz_stream *s = (gz_stream*)file;
M
Mark Adler 已提交
382
    Bytef *start = (Bytef*)buf; /* starting point for crc computation */
M
Mark Adler 已提交
383
    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
M
Mark Adler 已提交
384 385 386

    if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;

M
Mark Adler 已提交
387 388
    if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
    if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
M
Mark Adler 已提交
389

M
Mark Adler 已提交
390 391
    next_out = (Byte*)buf;
    s->stream.next_out = (Bytef*)buf;
M
Mark Adler 已提交
392 393 394 395
    s->stream.avail_out = len;

    while (s->stream.avail_out != 0) {

M
Mark Adler 已提交
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
        if (s->transparent) {
            /* Copy first the lookahead bytes: */
            uInt n = s->stream.avail_in;
            if (n > s->stream.avail_out) n = s->stream.avail_out;
            if (n > 0) {
                zmemcpy(s->stream.next_out, s->stream.next_in, n);
                next_out += n;
                s->stream.next_out = next_out;
                s->stream.next_in   += n;
                s->stream.avail_out -= n;
                s->stream.avail_in  -= n;
            }
            if (s->stream.avail_out > 0) {
                s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
                                             s->file);
            }
            len -= s->stream.avail_out;
            s->stream.total_in  += (uLong)len;
            s->stream.total_out += (uLong)len;
M
Mark Adler 已提交
415
            if (len == 0) s->z_eof = 1;
M
Mark Adler 已提交
416 417
            return (int)len;
        }
M
Mark Adler 已提交
418 419 420
        if (s->stream.avail_in == 0 && !s->z_eof) {

            errno = 0;
M
Mark Adler 已提交
421
            s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
M
Mark Adler 已提交
422 423
            if (s->stream.avail_in == 0) {
                s->z_eof = 1;
M
Mark Adler 已提交
424 425 426 427
                if (ferror(s->file)) {
                    s->z_err = Z_ERRNO;
                    break;
                }
M
Mark Adler 已提交
428 429 430 431 432
            }
            s->stream.next_in = s->inbuf;
        }
        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);

M
Mark Adler 已提交
433 434 435 436
        if (s->z_err == Z_STREAM_END) {
            /* Check CRC and original size */
            s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
            start = s->stream.next_out;
M
Mark Adler 已提交
437

M
Mark Adler 已提交
438 439 440 441
            if (getLong(s) != s->crc) {
                s->z_err = Z_DATA_ERROR;
            } else {
                (void)getLong(s);
M
Mark Adler 已提交
442 443
                /* The uncompressed length returned by above getlong() may
                 * be different from s->stream.total_out) in case of
M
Mark Adler 已提交
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
                 * concatenated .gz files. Check for such files:
                 */
                check_header(s);
                if (s->z_err == Z_OK) {
                    uLong total_in = s->stream.total_in;
                    uLong total_out = s->stream.total_out;

                    inflateReset(&(s->stream));
                    s->stream.total_in = total_in;
                    s->stream.total_out = total_out;
                    s->crc = crc32(0L, Z_NULL, 0);
                }
            }
        }
        if (s->z_err != Z_OK || s->z_eof) break;
M
Mark Adler 已提交
459
    }
M
Mark Adler 已提交
460 461 462
    s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));

    return (int)(len - s->stream.avail_out);
M
Mark Adler 已提交
463 464
}

M
Mark Adler 已提交
465 466 467 468 469

/* ===========================================================================
      Reads one byte from the compressed file. gzgetc returns this byte
   or -1 in case of end of file or error.
*/
M
Mark Adler 已提交
470
int ZEXPORT gzgetc(file)
M
Mark Adler 已提交
471 472
    gzFile file;
{
M
Mark Adler 已提交
473
    unsigned char c;
M
Mark Adler 已提交
474 475 476 477 478

    return gzread(file, &c, 1) == 1 ? c : -1;
}


M
Mark Adler 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
/* ===========================================================================
      Reads bytes from the compressed file until len-1 characters are
   read, or a newline character is read and transferred to buf, or an
   end-of-file condition is encountered.  The string is then terminated
   with a null character.
      gzgets returns buf, or Z_NULL in case of error.

      The current implementation is not optimized at all.
*/
char * ZEXPORT gzgets(file, buf, len)
    gzFile file;
    char *buf;
    int len;
{
    char *b = buf;
    if (buf == Z_NULL || len <= 0) return Z_NULL;

    while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
    *buf = '\0';
    return b == buf && len > 0 ? Z_NULL : b;
}


M
Mark Adler 已提交
502
#ifndef NO_DEFLATE
M
Mark Adler 已提交
503 504 505 506
/* ===========================================================================
     Writes the given number of uncompressed bytes into the compressed file.
   gzwrite returns the number of bytes actually written (0 in case of error).
*/
M
Mark Adler 已提交
507
int ZEXPORT gzwrite (file, buf, len)
M
Mark Adler 已提交
508
    gzFile file;
M
Mark Adler 已提交
509
    voidpc buf;
M
Mark Adler 已提交
510 511 512 513 514 515
    unsigned len;
{
    gz_stream *s = (gz_stream*)file;

    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;

M
Mark Adler 已提交
516
    s->stream.next_in = (Bytef*)buf;
M
Mark Adler 已提交
517 518 519 520
    s->stream.avail_in = len;

    while (s->stream.avail_in != 0) {

M
Mark Adler 已提交
521
        if (s->stream.avail_out == 0) {
M
Mark Adler 已提交
522

M
Mark Adler 已提交
523 524 525 526 527 528 529 530 531
            s->stream.next_out = s->outbuf;
            if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
                s->z_err = Z_ERRNO;
                break;
            }
            s->stream.avail_out = Z_BUFSIZE;
        }
        s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
        if (s->z_err != Z_OK) break;
M
Mark Adler 已提交
532
    }
M
Mark Adler 已提交
533
    s->crc = crc32(s->crc, (const Bytef *)buf, len);
M
Mark Adler 已提交
534

M
Mark Adler 已提交
535
    return (int)(len - s->stream.avail_in);
M
Mark Adler 已提交
536 537
}

M
Mark Adler 已提交
538 539 540 541 542 543 544 545
/* ===========================================================================
     Converts, formats, and writes the args to the compressed file under
   control of the format string, as in fprintf. gzprintf returns the number of
   uncompressed bytes actually written (0 in case of error).
*/
#ifdef STDC
#include <stdarg.h>

M
Mark Adler 已提交
546
int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
M
Mark Adler 已提交
547
{
M
Mark Adler 已提交
548
    char buf[Z_PRINTF_BUFSIZE];
M
Mark Adler 已提交
549 550 551 552
    va_list va;
    int len;

    va_start(va, format);
M
Mark Adler 已提交
553 554
#ifdef NO_vsnprintf
#  ifdef HAS_vsprintf_void
M
Mark Adler 已提交
555
    (void)vsprintf(buf, format, va);
M
Mark Adler 已提交
556
    va_end(va);
M
Mark Adler 已提交
557
    len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
M
Mark Adler 已提交
558
    if (len <= 0) return 0;
M
Mark Adler 已提交
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
#  else
    len = vsprintf(buf, format, va);
    va_end(va);
    if (len <= 0 || len >= sizeof(buf))
        return 0;
#  endif
#else
#  ifdef HAS_vsnprintf_void
    (void)vsnprintf(buf, sizeof(buf), format, va);
    va_end(va);
    len = strlen(buf);
    if (len <= 0)
        return 0;
#  else
    len = vsnprintf(buf, sizeof(buf), format, va);
    va_end(va);
    if (len <= 0 || len >= sizeof(buf))
        return 0;
#  endif
#endif
M
Mark Adler 已提交
579 580 581 582 583

    return gzwrite(file, buf, (unsigned)len);
}
#else /* not ANSI C */

M
Mark Adler 已提交
584
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
M
Mark Adler 已提交
585
                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
M
Mark Adler 已提交
586 587 588
    gzFile file;
    const char *format;
    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
M
Mark Adler 已提交
589
        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
M
Mark Adler 已提交
590
{
M
Mark Adler 已提交
591
    char buf[Z_PRINTF_BUFSIZE];
M
Mark Adler 已提交
592 593
    int len;

M
Mark Adler 已提交
594 595
#ifdef NO_snprintf
#  ifdef HAS_sprintf_void
M
Mark Adler 已提交
596
    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
M
Mark Adler 已提交
597
            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
M
Mark Adler 已提交
598 599
    len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
    if (len <= 0) return 0;
M
Mark Adler 已提交
600 601
#  else
    len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
M
Mark Adler 已提交
602
                a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
M
Mark Adler 已提交
603 604 605 606 607 608
    if (len <= 0 || len >= sizeof(buf))
        return 0;
#  endif
#else
#  ifdef HAS_snprintf_void
    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
M
Mark Adler 已提交
609
             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
M
Mark Adler 已提交
610 611 612 613 614
    len = strlen(buf);
    if (len <= 0)
        return 0;
#  else
    len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
M
Mark Adler 已提交
615
                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
M
Mark Adler 已提交
616 617 618 619
    if (len <= 0 || len >= sizeof(buf))
        return 0;
#  endif
#endif
M
Mark Adler 已提交
620 621 622 623 624 625 626 627 628

    return gzwrite(file, buf, len);
}
#endif

/* ===========================================================================
      Writes c, converted to an unsigned char, into the compressed file.
   gzputc returns the value that was written, or -1 in case of error.
*/
M
Mark Adler 已提交
629
int ZEXPORT gzputc(file, c)
M
Mark Adler 已提交
630 631 632
    gzFile file;
    int c;
{
M
Mark Adler 已提交
633 634 635
    unsigned char cc = (unsigned char) c; /* required for big endian systems */

    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
M
Mark Adler 已提交
636 637 638
}


M
Mark Adler 已提交
639 640 641 642 643 644 645 646 647
/* ===========================================================================
      Writes the given null-terminated string to the compressed file, excluding
   the terminating null character.
      gzputs returns the number of characters written, or -1 in case of error.
*/
int ZEXPORT gzputs(file, s)
    gzFile file;
    const char *s;
{
M
Mark Adler 已提交
648
    return gzwrite(file, (char*)s, (unsigned)strlen(s));
M
Mark Adler 已提交
649 650 651
}


M
Mark Adler 已提交
652 653 654 655
/* ===========================================================================
     Flushes all pending output into the compressed file. The parameter
   flush is as in the deflate() function.
*/
M
Mark Adler 已提交
656
local int do_flush (file, flush)
M
Mark Adler 已提交
657 658 659 660 661 662 663 664 665 666 667 668
    gzFile file;
    int flush;
{
    uInt len;
    int done = 0;
    gz_stream *s = (gz_stream*)file;

    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;

    s->stream.avail_in = 0; /* should be zero already anyway */

    for (;;) {
M
Mark Adler 已提交
669 670 671
        len = Z_BUFSIZE - s->stream.avail_out;

        if (len != 0) {
M
Mark Adler 已提交
672
            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
M
Mark Adler 已提交
673 674 675 676 677 678 679 680
                s->z_err = Z_ERRNO;
                return Z_ERRNO;
            }
            s->stream.next_out = s->outbuf;
            s->stream.avail_out = Z_BUFSIZE;
        }
        if (done) break;
        s->z_err = deflate(&(s->stream), flush);
M
Mark Adler 已提交
681

M
Mark Adler 已提交
682 683
        /* Ignore the second of two consecutive flushes: */
        if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
M
Mark Adler 已提交
684

M
Mark Adler 已提交
685
        /* deflate has finished flushing only when it hasn't used up
M
Mark Adler 已提交
686
         * all the available space in the output buffer:
M
Mark Adler 已提交
687
         */
M
Mark Adler 已提交
688
        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
M
Mark Adler 已提交
689

M
Mark Adler 已提交
690
        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
M
Mark Adler 已提交
691
    }
M
Mark Adler 已提交
692 693 694
    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
}

M
Mark Adler 已提交
695
int ZEXPORT gzflush (file, flush)
M
Mark Adler 已提交
696 697 698 699 700 701 702
     gzFile file;
     int flush;
{
    gz_stream *s = (gz_stream*)file;
    int err = do_flush (file, flush);

    if (err) return err;
M
Mark Adler 已提交
703
    fflush(s->file);
M
Mark Adler 已提交
704
    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
M
Mark Adler 已提交
705
}
M
Mark Adler 已提交
706 707 708 709 710 711 712 713 714 715
#endif /* NO_DEFLATE */

/* ===========================================================================
      Sets the starting position for the next gzread or gzwrite on the given
   compressed file. The offset represents a number of bytes in the
      gzseek returns the resulting offset location as measured in bytes from
   the beginning of the uncompressed stream, or -1 in case of error.
      SEEK_END is not implemented, returns error.
      In this version of the library, gzseek can be extremely slow.
*/
M
Mark Adler 已提交
716
z_off_t ZEXPORT gzseek (file, offset, whence)
M
Mark Adler 已提交
717 718 719 720 721 722
    gzFile file;
    z_off_t offset;
    int whence;
{
    gz_stream *s = (gz_stream*)file;

M
Mark Adler 已提交
723
    if (s == NULL || whence == SEEK_END ||
M
Mark Adler 已提交
724 725
        s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
        return -1L;
M
Mark Adler 已提交
726
    }
M
Mark Adler 已提交
727

M
Mark Adler 已提交
728 729
    if (s->mode == 'w') {
#ifdef NO_DEFLATE
M
Mark Adler 已提交
730
        return -1L;
M
Mark Adler 已提交
731
#else
M
Mark Adler 已提交
732 733 734 735 736 737 738 739
        if (whence == SEEK_SET) {
            offset -= s->stream.total_in;
        }
        if (offset < 0) return -1L;

        /* At this point, offset is the number of zero bytes to write. */
        if (s->inbuf == Z_NULL) {
            s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
M
Mark Adler 已提交
740
            if (s->inbuf == Z_NULL) return -1L;
M
Mark Adler 已提交
741 742 743 744 745 746 747 748 749 750 751 752
            zmemzero(s->inbuf, Z_BUFSIZE);
        }
        while (offset > 0)  {
            uInt size = Z_BUFSIZE;
            if (offset < Z_BUFSIZE) size = (uInt)offset;

            size = gzwrite(file, s->inbuf, size);
            if (size == 0) return -1L;

            offset -= size;
        }
        return (z_off_t)s->stream.total_in;
M
Mark Adler 已提交
753 754 755 756 757 758
#endif
    }
    /* Rest of function is for reading only */

    /* compute absolute position */
    if (whence == SEEK_CUR) {
M
Mark Adler 已提交
759
        offset += s->stream.total_out;
M
Mark Adler 已提交
760 761 762 763
    }
    if (offset < 0) return -1L;

    if (s->transparent) {
M
Mark Adler 已提交
764 765 766
        /* map to fseek */
        s->stream.avail_in = 0;
        s->stream.next_in = s->inbuf;
M
Mark Adler 已提交
767 768
        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;

M
Mark Adler 已提交
769 770
        s->stream.total_in = s->stream.total_out = (uLong)offset;
        return offset;
M
Mark Adler 已提交
771 772 773 774
    }

    /* For a negative seek, rewind and use positive seek */
    if ((uLong)offset >= s->stream.total_out) {
M
Mark Adler 已提交
775
        offset -= s->stream.total_out;
M
Mark Adler 已提交
776
    } else if (gzrewind(file) < 0) {
M
Mark Adler 已提交
777
        return -1L;
M
Mark Adler 已提交
778 779 780 781
    }
    /* offset is now the number of bytes to skip. */

    if (offset != 0 && s->outbuf == Z_NULL) {
M
Mark Adler 已提交
782
        s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
M
Mark Adler 已提交
783
        if (s->outbuf == Z_NULL) return -1L;
M
Mark Adler 已提交
784 785
    }
    while (offset > 0)  {
M
Mark Adler 已提交
786 787
        int size = Z_BUFSIZE;
        if (offset < Z_BUFSIZE) size = (int)offset;
M
Mark Adler 已提交
788

M
Mark Adler 已提交
789 790 791
        size = gzread(file, s->outbuf, (uInt)size);
        if (size <= 0) return -1L;
        offset -= size;
M
Mark Adler 已提交
792
    }
M
Mark Adler 已提交
793
    return (z_off_t)s->stream.total_out;
M
Mark Adler 已提交
794 795 796
}

/* ===========================================================================
M
Mark Adler 已提交
797
     Rewinds input file.
M
Mark Adler 已提交
798
*/
M
Mark Adler 已提交
799
int ZEXPORT gzrewind (file)
M
Mark Adler 已提交
800 801 802
    gzFile file;
{
    gz_stream *s = (gz_stream*)file;
M
Mark Adler 已提交
803

M
Mark Adler 已提交
804 805 806 807 808 809
    if (s == NULL || s->mode != 'r') return -1;

    s->z_err = Z_OK;
    s->z_eof = 0;
    s->stream.avail_in = 0;
    s->stream.next_in = s->inbuf;
M
Mark Adler 已提交
810
    s->crc = crc32(0L, Z_NULL, 0);
M
Mark Adler 已提交
811

M
Mark Adler 已提交
812
    if (s->startpos == 0) { /* not a compressed file */
M
Mark Adler 已提交
813 814
        rewind(s->file);
        return 0;
M
Mark Adler 已提交
815 816 817 818 819 820 821 822 823 824 825
    }

    (void) inflateReset(&s->stream);
    return fseek(s->file, s->startpos, SEEK_SET);
}

/* ===========================================================================
     Returns the starting position for the next gzread or gzwrite on the
   given compressed file. This position represents a number of bytes in the
   uncompressed data stream.
*/
M
Mark Adler 已提交
826
z_off_t ZEXPORT gztell (file)
M
Mark Adler 已提交
827 828 829 830 831 832 833 834 835
    gzFile file;
{
    return gzseek(file, 0L, SEEK_CUR);
}

/* ===========================================================================
     Returns 1 when EOF has previously been detected reading the given
   input stream, otherwise zero.
*/
M
Mark Adler 已提交
836
int ZEXPORT gzeof (file)
M
Mark Adler 已提交
837 838 839
    gzFile file;
{
    gz_stream *s = (gz_stream*)file;
M
Mark Adler 已提交
840

M
Mark Adler 已提交
841 842
    return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
}
M
Mark Adler 已提交
843 844 845 846 847 848 849 850 851 852

/* ===========================================================================
   Outputs a long in LSB order to the given file
*/
local void putLong (file, x)
    FILE *file;
    uLong x;
{
    int n;
    for (n = 0; n < 4; n++) {
M
Mark Adler 已提交
853 854
        fputc((int)(x & 0xff), file);
        x >>= 8;
M
Mark Adler 已提交
855 856 857 858
    }
}

/* ===========================================================================
M
Mark Adler 已提交
859 860
   Reads a long in LSB order from the given gz_stream. Sets z_err in case
   of error.
M
Mark Adler 已提交
861
*/
M
Mark Adler 已提交
862 863
local uLong getLong (s)
    gz_stream *s;
M
Mark Adler 已提交
864
{
M
Mark Adler 已提交
865 866 867 868 869 870 871 872
    uLong x = (uLong)get_byte(s);
    int c;

    x += ((uLong)get_byte(s))<<8;
    x += ((uLong)get_byte(s))<<16;
    c = get_byte(s);
    if (c == EOF) s->z_err = Z_DATA_ERROR;
    x += ((uLong)c)<<24;
M
Mark Adler 已提交
873 874 875 876 877 878 879
    return x;
}

/* ===========================================================================
     Flushes all pending output if necessary, closes the compressed file
   and deallocates all the (de)compression state.
*/
M
Mark Adler 已提交
880
int ZEXPORT gzclose (file)
M
Mark Adler 已提交
881 882
    gzFile file;
{
M
Mark Adler 已提交
883
    int err;
M
Mark Adler 已提交
884 885 886 887 888
    gz_stream *s = (gz_stream*)file;

    if (s == NULL) return Z_STREAM_ERROR;

    if (s->mode == 'w') {
M
Mark Adler 已提交
889
#ifdef NO_DEFLATE
M
Mark Adler 已提交
890
        return Z_STREAM_ERROR;
M
Mark Adler 已提交
891 892 893
#else
        err = do_flush (file, Z_FINISH);
        if (err != Z_OK) return destroy((gz_stream*)file);
M
Mark Adler 已提交
894

M
Mark Adler 已提交
895 896
        putLong (s->file, s->crc);
        putLong (s->file, s->stream.total_in);
M
Mark Adler 已提交
897
#endif
M
Mark Adler 已提交
898
    }
M
Mark Adler 已提交
899
    return destroy((gz_stream*)file);
M
Mark Adler 已提交
900 901 902 903 904 905 906 907 908
}

/* ===========================================================================
     Returns the error message for the last error which occured on the
   given compressed file. errnum is set to zlib error number. If an
   error occured in the file system and not in the compression library,
   errnum is set to Z_ERRNO and the application may consult errno
   to get the exact error code.
*/
M
Mark Adler 已提交
909
const char*  ZEXPORT gzerror (file, errnum)
M
Mark Adler 已提交
910 911 912 913 914 915 916
    gzFile file;
    int *errnum;
{
    char *m;
    gz_stream *s = (gz_stream*)file;

    if (s == NULL) {
M
Mark Adler 已提交
917
        *errnum = Z_STREAM_ERROR;
M
Mark Adler 已提交
918
        return (const char*)ERR_MSG(Z_STREAM_ERROR);
M
Mark Adler 已提交
919 920
    }
    *errnum = s->z_err;
M
Mark Adler 已提交
921
    if (*errnum == Z_OK) return (const char*)"";
M
Mark Adler 已提交
922

M
Mark Adler 已提交
923
    m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
M
Mark Adler 已提交
924

M
Mark Adler 已提交
925
    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
M
Mark Adler 已提交
926 927 928

    TRYFREE(s->msg);
    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
M
Mark Adler 已提交
929
    if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
M
Mark Adler 已提交
930 931 932
    strcpy(s->msg, s->path);
    strcat(s->msg, ": ");
    strcat(s->msg, m);
M
Mark Adler 已提交
933
    return (const char*)s->msg;
M
Mark Adler 已提交
934
}