gzio.c 29.3 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

#include <stdio.h>

#include "zutil.h"

M
Mark Adler 已提交
14
#ifndef NO_DUMMY_DECL
M
Mark Adler 已提交
15
struct internal_state {int dummy;}; /* for buggy compilers */
M
Mark Adler 已提交
16
#endif
M
Mark Adler 已提交
17

M
Mark Adler 已提交
18 19 20 21 22 23 24 25 26 27
#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 已提交
28

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

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

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

/* 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 已提交
59
    long     startpos; /* start of compressed data in file (header skipped) */
M
Mark Adler 已提交
60 61
    int      back;    /* one character push-back */
    int      last;    /* true if push-back is last character */
M
Mark Adler 已提交
62 63 64
} gz_stream;


M
Mark Adler 已提交
65
local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
M
Mark Adler 已提交
66
local int do_flush        OF((gzFile file, int flush));
M
Mark Adler 已提交
67 68 69 70 71
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 已提交
72 73 74

/* ===========================================================================
     Opens a gzip (.gz) file for reading or writing. The mode parameter
M
Mark Adler 已提交
75
   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
M
Mark Adler 已提交
76 77 78 79 80 81 82
   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 已提交
83 84
    const char *path;
    const char *mode;
M
Mark Adler 已提交
85 86 87
    int  fd;
{
    int err;
M
Mark Adler 已提交
88
    int level = Z_DEFAULT_COMPRESSION; /* compression level */
M
Mark Adler 已提交
89
    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
M
Mark Adler 已提交
90 91 92 93 94 95
    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 已提交
96

M
Mark Adler 已提交
97
    s = (gz_stream *)ALLOC(sizeof(gz_stream));
M
Mark Adler 已提交
98 99 100 101
    if (!s) return Z_NULL;

    s->stream.zalloc = (alloc_func)0;
    s->stream.zfree = (free_func)0;
M
Mark Adler 已提交
102
    s->stream.opaque = (voidpf)0;
M
Mark Adler 已提交
103 104 105 106 107 108
    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;
M
Mark Adler 已提交
109
    s->back = EOF;
M
Mark Adler 已提交
110 111 112 113 114 115
    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 已提交
116
        return destroy(s), (gzFile)Z_NULL;
M
Mark Adler 已提交
117 118 119 120 121
    }
    strcpy(s->path, path); /* do this early for debugging */

    s->mode = '\0';
    do {
M
Mark Adler 已提交
122
        if (*p == 'r') s->mode = 'r';
M
Mark Adler 已提交
123 124
        if (*p == 'w' || *p == 'a') s->mode = 'w';
        if (*p >= '0' && *p <= '9') {
M
Mark Adler 已提交
125 126 127 128 129 130 131 132 133 134
            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 已提交
135
    } while (*p++ && m != fmode + sizeof(fmode));
M
Mark Adler 已提交
136
    if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
M
Mark Adler 已提交
137

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

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

M
Mark Adler 已提交
154
        err = inflateInit2(&(s->stream), -MAX_WBITS);
M
Mark Adler 已提交
155 156 157 158 159 160
        /* 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 已提交
161 162 163
        if (err != Z_OK || s->inbuf == Z_NULL) {
            return destroy(s), (gzFile)Z_NULL;
        }
M
Mark Adler 已提交
164 165 166 167
    }
    s->stream.avail_out = Z_BUFSIZE;

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

    if (s->file == NULL) {
M
Mark Adler 已提交
171
        return destroy(s), (gzFile)Z_NULL;
M
Mark Adler 已提交
172 173
    }
    if (s->mode == 'w') {
M
Mark Adler 已提交
174 175
        /* Write a very simple .gz header:
         */
M
Mark Adler 已提交
176
        fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
M
Mark Adler 已提交
177
             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
M
Mark Adler 已提交
178 179
        s->startpos = 10L;
        /* We use 10L instead of ftell(s->file) to because ftell causes an
M
Mark Adler 已提交
180 181 182 183
         * 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 已提交
184
    } else {
M
Mark Adler 已提交
185 186
        check_header(s); /* skip the .gz header */
        s->startpos = (ftell(s->file) - s->stream.avail_in);
M
Mark Adler 已提交
187
    }
M
Mark Adler 已提交
188

M
Mark Adler 已提交
189 190 191 192 193 194
    return (gzFile)s;
}

/* ===========================================================================
     Opens a gzip (.gz) file for reading or writing.
*/
M
Mark Adler 已提交
195
gzFile ZEXPORT gzopen (path, mode)
M
Mark Adler 已提交
196 197
    const char *path;
    const char *mode;
M
Mark Adler 已提交
198 199 200 201 202
{
    return gz_open (path, mode, -1);
}

/* ===========================================================================
M
Mark Adler 已提交
203 204
     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 已提交
205
*/
M
Mark Adler 已提交
206
gzFile ZEXPORT gzdopen (fd, mode)
M
Mark Adler 已提交
207
    int fd;
M
Mark Adler 已提交
208
    const char *mode;
M
Mark Adler 已提交
209 210
{
    char name[20];
M
Mark Adler 已提交
211 212

    if (fd < 0) return (gzFile)Z_NULL;
M
Mark Adler 已提交
213
    sprintf(name, "<fd:%d>", fd); /* for debugging */
M
Mark Adler 已提交
214 215 216 217

    return gz_open (name, mode, fd);
}

M
Mark Adler 已提交
218 219 220
/* ===========================================================================
 * Update the compression level and strategy
 */
M
Mark Adler 已提交
221
int ZEXPORT gzsetparams (file, level, strategy)
M
Mark Adler 已提交
222 223 224 225 226 227 228 229 230 231 232
    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 已提交
233 234 235 236 237
        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 已提交
238 239 240 241 242
    }

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

M
Mark Adler 已提交
243 244 245 246 247 248 249 250 251 252
/* ===========================================================================
     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 已提交
253 254 255 256 257 258 259 260
        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 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
    }
    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 已提交
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
    /* 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 已提交
298
    }
M
Mark Adler 已提交
299 300 301

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

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

    /* 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 已提交
321 322 323 324
        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 已提交
325 326
    }
    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
M
Mark Adler 已提交
327
        while ((c = get_byte(s)) != 0 && c != EOF) ;
M
Mark Adler 已提交
328 329
    }
    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
M
Mark Adler 已提交
330
        while ((c = get_byte(s)) != 0 && c != EOF) ;
M
Mark Adler 已提交
331 332
    }
    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
M
Mark Adler 已提交
333
        for (len = 0; len < 2; len++) (void)get_byte(s);
M
Mark Adler 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    }
    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 已提交
352
        if (s->mode == 'w') {
M
Mark Adler 已提交
353
#ifdef NO_DEFLATE
M
Mark Adler 已提交
354
            err = Z_STREAM_ERROR;
M
Mark Adler 已提交
355
#else
M
Mark Adler 已提交
356
            err = deflateEnd(&(s->stream));
M
Mark Adler 已提交
357
#endif
M
Mark Adler 已提交
358 359 360
        } else if (s->mode == 'r') {
            err = inflateEnd(&(s->stream));
        }
M
Mark Adler 已提交
361 362
    }
    if (s->file != NULL && fclose(s->file)) {
M
Mark Adler 已提交
363
#ifdef ESPIPE
M
Mark Adler 已提交
364
        if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
M
Mark Adler 已提交
365
#endif
M
Mark Adler 已提交
366
            err = Z_ERRNO;
M
Mark Adler 已提交
367 368 369 370 371 372 373 374 375 376
    }
    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 已提交
377 378 379 380
/* ===========================================================================
     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 已提交
381
int ZEXPORT gzread (file, buf, len)
M
Mark Adler 已提交
382
    gzFile file;
M
Mark Adler 已提交
383
    voidp buf;
M
Mark Adler 已提交
384 385 386
    unsigned len;
{
    gz_stream *s = (gz_stream*)file;
M
Mark Adler 已提交
387
    Bytef *start = (Bytef*)buf; /* starting point for crc computation */
M
Mark Adler 已提交
388
    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
M
Mark Adler 已提交
389 390 391

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

M
Mark Adler 已提交
392 393
    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 已提交
394

M
Mark Adler 已提交
395 396
    next_out = (Byte*)buf;
    s->stream.next_out = (Bytef*)buf;
M
Mark Adler 已提交
397 398
    s->stream.avail_out = len;

M
Mark Adler 已提交
399 400 401 402 403 404 405 406 407 408 409 410
    if (s->stream.avail_out && s->back != EOF) {
        *next_out++ = s->back;
        s->stream.next_out++;
        s->stream.avail_out--;
        s->back = EOF;
        s->stream.total_out++;
        if (s->last) {
            s->z_err = Z_STREAM_END;
            return 1;
        }
    }

M
Mark Adler 已提交
411 412
    while (s->stream.avail_out != 0) {

M
Mark Adler 已提交
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
        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 已提交
432
            if (len == 0) s->z_eof = 1;
M
Mark Adler 已提交
433 434
            return (int)len;
        }
M
Mark Adler 已提交
435 436 437
        if (s->stream.avail_in == 0 && !s->z_eof) {

            errno = 0;
M
Mark Adler 已提交
438
            s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
M
Mark Adler 已提交
439 440
            if (s->stream.avail_in == 0) {
                s->z_eof = 1;
M
Mark Adler 已提交
441 442 443 444
                if (ferror(s->file)) {
                    s->z_err = Z_ERRNO;
                    break;
                }
M
Mark Adler 已提交
445 446 447 448 449
            }
            s->stream.next_in = s->inbuf;
        }
        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);

M
Mark Adler 已提交
450 451 452 453
        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 已提交
454

M
Mark Adler 已提交
455 456 457 458
            if (getLong(s) != s->crc) {
                s->z_err = Z_DATA_ERROR;
            } else {
                (void)getLong(s);
M
Mark Adler 已提交
459 460
                /* The uncompressed length returned by above getlong() may
                 * be different from s->stream.total_out) in case of
M
Mark Adler 已提交
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
                 * 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 已提交
476
    }
M
Mark Adler 已提交
477 478 479
    s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));

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

M
Mark Adler 已提交
482 483 484 485 486

/* ===========================================================================
      Reads one byte from the compressed file. gzgetc returns this byte
   or -1 in case of end of file or error.
*/
M
Mark Adler 已提交
487
int ZEXPORT gzgetc(file)
M
Mark Adler 已提交
488 489
    gzFile file;
{
M
Mark Adler 已提交
490
    unsigned char c;
M
Mark Adler 已提交
491 492 493 494 495

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


M
Mark Adler 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
/* ===========================================================================
      Push one byte back onto the stream.
*/
int ZEXPORT gzungetc(c, file)
    int c;
    gzFile file;
{
    gz_stream *s = (gz_stream*)file;

    if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
    s->back = c;
    s->stream.total_out--;
    s->last = (s->z_err == Z_STREAM_END);
    if (s->z_eof) s->z_eof = 0;
    return c;
}


M
Mark Adler 已提交
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
/* ===========================================================================
      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 已提交
537
#ifndef NO_DEFLATE
M
Mark Adler 已提交
538 539 540 541
/* ===========================================================================
     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 已提交
542
int ZEXPORT gzwrite (file, buf, len)
M
Mark Adler 已提交
543
    gzFile file;
M
Mark Adler 已提交
544
    voidpc buf;
M
Mark Adler 已提交
545 546 547 548 549 550
    unsigned len;
{
    gz_stream *s = (gz_stream*)file;

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

M
Mark Adler 已提交
551
    s->stream.next_in = (Bytef*)buf;
M
Mark Adler 已提交
552 553 554 555
    s->stream.avail_in = len;

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

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

M
Mark Adler 已提交
558 559 560 561 562 563 564 565 566
            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 已提交
567
    }
M
Mark Adler 已提交
568
    s->crc = crc32(s->crc, (const Bytef *)buf, len);
M
Mark Adler 已提交
569

M
Mark Adler 已提交
570
    return (int)(len - s->stream.avail_in);
M
Mark Adler 已提交
571 572
}

M
Mark Adler 已提交
573

M
Mark Adler 已提交
574 575 576 577 578 579 580 581
/* ===========================================================================
     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 已提交
582
int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
M
Mark Adler 已提交
583
{
M
Mark Adler 已提交
584
    char buf[Z_PRINTF_BUFSIZE];
M
Mark Adler 已提交
585 586 587
    va_list va;
    int len;

M
Mark Adler 已提交
588
    buf[sizeof(buf) - 1] = 0;
M
Mark Adler 已提交
589
    va_start(va, format);
M
Mark Adler 已提交
590 591
#ifdef NO_vsnprintf
#  ifdef HAS_vsprintf_void
M
Mark Adler 已提交
592
    (void)vsprintf(buf, format, va);
M
Mark Adler 已提交
593
    va_end(va);
M
Mark Adler 已提交
594 595
    for (len = 0; len < sizeof(buf); len++)
        if (buf[len] == 0) break;
M
Mark Adler 已提交
596 597 598 599 600 601 602 603 604 605 606 607 608 609
#  else
    len = vsprintf(buf, format, va);
    va_end(va);
#  endif
#else
#  ifdef HAS_vsnprintf_void
    (void)vsnprintf(buf, sizeof(buf), format, va);
    va_end(va);
    len = strlen(buf);
#  else
    len = vsnprintf(buf, sizeof(buf), format, va);
    va_end(va);
#  endif
#endif
M
Mark Adler 已提交
610 611
    if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
        return 0;
M
Mark Adler 已提交
612 613 614 615
    return gzwrite(file, buf, (unsigned)len);
}
#else /* not ANSI C */

M
Mark Adler 已提交
616
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
M
Mark Adler 已提交
617
                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
M
Mark Adler 已提交
618 619 620
    gzFile file;
    const char *format;
    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
M
Mark Adler 已提交
621
        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
M
Mark Adler 已提交
622
{
M
Mark Adler 已提交
623
    char buf[Z_PRINTF_BUFSIZE];
M
Mark Adler 已提交
624 625
    int len;

M
Mark Adler 已提交
626
    buf[sizeof(buf) - 1] = 0;
M
Mark Adler 已提交
627 628
#ifdef NO_snprintf
#  ifdef HAS_sprintf_void
M
Mark Adler 已提交
629
    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
M
Mark Adler 已提交
630
            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
M
Mark Adler 已提交
631 632
    for (len = 0; len < sizeof(buf); len++)
        if (buf[len] == 0) break;
M
Mark Adler 已提交
633 634
#  else
    len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
M
Mark Adler 已提交
635
                a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
M
Mark Adler 已提交
636 637 638 639
#  endif
#else
#  ifdef HAS_snprintf_void
    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
M
Mark Adler 已提交
640
             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
M
Mark Adler 已提交
641 642 643
    len = strlen(buf);
#  else
    len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
M
Mark Adler 已提交
644
                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
M
Mark Adler 已提交
645 646
#  endif
#endif
M
Mark Adler 已提交
647 648
    if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
        return 0;
M
Mark Adler 已提交
649 650 651 652 653 654 655 656
    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 已提交
657
int ZEXPORT gzputc(file, c)
M
Mark Adler 已提交
658 659 660
    gzFile file;
    int c;
{
M
Mark Adler 已提交
661 662 663
    unsigned char cc = (unsigned char) c; /* required for big endian systems */

    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
M
Mark Adler 已提交
664 665 666
}


M
Mark Adler 已提交
667 668 669 670 671 672 673 674 675
/* ===========================================================================
      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 已提交
676
    return gzwrite(file, (char*)s, (unsigned)strlen(s));
M
Mark Adler 已提交
677 678 679
}


M
Mark Adler 已提交
680 681 682 683
/* ===========================================================================
     Flushes all pending output into the compressed file. The parameter
   flush is as in the deflate() function.
*/
M
Mark Adler 已提交
684
local int do_flush (file, flush)
M
Mark Adler 已提交
685 686 687 688 689 690 691 692 693 694 695 696
    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 已提交
697 698 699
        len = Z_BUFSIZE - s->stream.avail_out;

        if (len != 0) {
M
Mark Adler 已提交
700
            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
M
Mark Adler 已提交
701 702 703 704 705 706 707 708
                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 已提交
709

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

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

M
Mark Adler 已提交
718
        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
M
Mark Adler 已提交
719
    }
M
Mark Adler 已提交
720 721 722
    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
}

M
Mark Adler 已提交
723
int ZEXPORT gzflush (file, flush)
M
Mark Adler 已提交
724 725 726 727 728 729 730
     gzFile file;
     int flush;
{
    gz_stream *s = (gz_stream*)file;
    int err = do_flush (file, flush);

    if (err) return err;
M
Mark Adler 已提交
731
    fflush(s->file);
M
Mark Adler 已提交
732
    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
M
Mark Adler 已提交
733
}
M
Mark Adler 已提交
734 735 736 737 738 739 740 741 742 743
#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 已提交
744
z_off_t ZEXPORT gzseek (file, offset, whence)
M
Mark Adler 已提交
745 746 747 748 749 750
    gzFile file;
    z_off_t offset;
    int whence;
{
    gz_stream *s = (gz_stream*)file;

M
Mark Adler 已提交
751
    if (s == NULL || whence == SEEK_END ||
M
Mark Adler 已提交
752 753
        s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
        return -1L;
M
Mark Adler 已提交
754
    }
M
Mark Adler 已提交
755

M
Mark Adler 已提交
756 757
    if (s->mode == 'w') {
#ifdef NO_DEFLATE
M
Mark Adler 已提交
758
        return -1L;
M
Mark Adler 已提交
759
#else
M
Mark Adler 已提交
760 761 762 763 764 765 766 767
        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 已提交
768
            if (s->inbuf == Z_NULL) return -1L;
M
Mark Adler 已提交
769 770 771 772 773 774 775 776 777 778 779 780
            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 已提交
781 782 783 784 785 786
#endif
    }
    /* Rest of function is for reading only */

    /* compute absolute position */
    if (whence == SEEK_CUR) {
M
Mark Adler 已提交
787
        offset += s->stream.total_out;
M
Mark Adler 已提交
788 789 790 791
    }
    if (offset < 0) return -1L;

    if (s->transparent) {
M
Mark Adler 已提交
792
        /* map to fseek */
M
Mark Adler 已提交
793
        s->back = EOF;
M
Mark Adler 已提交
794 795
        s->stream.avail_in = 0;
        s->stream.next_in = s->inbuf;
M
Mark Adler 已提交
796 797
        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;

M
Mark Adler 已提交
798 799
        s->stream.total_in = s->stream.total_out = (uLong)offset;
        return offset;
M
Mark Adler 已提交
800 801 802 803
    }

    /* For a negative seek, rewind and use positive seek */
    if ((uLong)offset >= s->stream.total_out) {
M
Mark Adler 已提交
804
        offset -= s->stream.total_out;
M
Mark Adler 已提交
805
    } else if (gzrewind(file) < 0) {
M
Mark Adler 已提交
806
        return -1L;
M
Mark Adler 已提交
807 808 809 810
    }
    /* offset is now the number of bytes to skip. */

    if (offset != 0 && s->outbuf == Z_NULL) {
M
Mark Adler 已提交
811
        s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
M
Mark Adler 已提交
812
        if (s->outbuf == Z_NULL) return -1L;
M
Mark Adler 已提交
813
    }
M
Mark Adler 已提交
814 815 816 817 818 819
    if (offset && s->back != EOF) {
        s->back == EOF;
        s->stream.total_out++;
        offset--;
        if (s->last) s->z_err = Z_STREAM_END;
    }
M
Mark Adler 已提交
820
    while (offset > 0)  {
M
Mark Adler 已提交
821 822
        int size = Z_BUFSIZE;
        if (offset < Z_BUFSIZE) size = (int)offset;
M
Mark Adler 已提交
823

M
Mark Adler 已提交
824 825 826
        size = gzread(file, s->outbuf, (uInt)size);
        if (size <= 0) return -1L;
        offset -= size;
M
Mark Adler 已提交
827
    }
M
Mark Adler 已提交
828
    return (z_off_t)s->stream.total_out;
M
Mark Adler 已提交
829 830 831
}

/* ===========================================================================
M
Mark Adler 已提交
832
     Rewinds input file.
M
Mark Adler 已提交
833
*/
M
Mark Adler 已提交
834
int ZEXPORT gzrewind (file)
M
Mark Adler 已提交
835 836 837
    gzFile file;
{
    gz_stream *s = (gz_stream*)file;
M
Mark Adler 已提交
838

M
Mark Adler 已提交
839 840 841 842
    if (s == NULL || s->mode != 'r') return -1;

    s->z_err = Z_OK;
    s->z_eof = 0;
M
Mark Adler 已提交
843
    s->back = EOF;
M
Mark Adler 已提交
844 845
    s->stream.avail_in = 0;
    s->stream.next_in = s->inbuf;
M
Mark Adler 已提交
846
    s->crc = crc32(0L, Z_NULL, 0);
M
Mark Adler 已提交
847

M
Mark Adler 已提交
848
    if (s->startpos == 0) { /* not a compressed file */
M
Mark Adler 已提交
849
        fseek(s->file, 0L, SEEK_SET);   /* rewind() is not always available */
M
Mark Adler 已提交
850
        return 0;
M
Mark Adler 已提交
851 852 853 854 855 856 857 858 859 860 861
    }

    (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 已提交
862
z_off_t ZEXPORT gztell (file)
M
Mark Adler 已提交
863 864 865 866 867 868 869 870 871
    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 已提交
872
int ZEXPORT gzeof (file)
M
Mark Adler 已提交
873 874 875
    gzFile file;
{
    gz_stream *s = (gz_stream*)file;
M
Mark Adler 已提交
876

M
Mark Adler 已提交
877 878
    return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
}
M
Mark Adler 已提交
879 880 881 882 883 884 885 886 887 888

/* ===========================================================================
   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 已提交
889 890
        fputc((int)(x & 0xff), file);
        x >>= 8;
M
Mark Adler 已提交
891 892 893 894
    }
}

/* ===========================================================================
M
Mark Adler 已提交
895 896
   Reads a long in LSB order from the given gz_stream. Sets z_err in case
   of error.
M
Mark Adler 已提交
897
*/
M
Mark Adler 已提交
898 899
local uLong getLong (s)
    gz_stream *s;
M
Mark Adler 已提交
900
{
M
Mark Adler 已提交
901 902 903 904 905 906 907 908
    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 已提交
909 910 911 912 913 914 915
    return x;
}

/* ===========================================================================
     Flushes all pending output if necessary, closes the compressed file
   and deallocates all the (de)compression state.
*/
M
Mark Adler 已提交
916
int ZEXPORT gzclose (file)
M
Mark Adler 已提交
917 918
    gzFile file;
{
M
Mark Adler 已提交
919
    int err;
M
Mark Adler 已提交
920 921 922 923 924
    gz_stream *s = (gz_stream*)file;

    if (s == NULL) return Z_STREAM_ERROR;

    if (s->mode == 'w') {
M
Mark Adler 已提交
925
#ifdef NO_DEFLATE
M
Mark Adler 已提交
926
        return Z_STREAM_ERROR;
M
Mark Adler 已提交
927 928 929
#else
        err = do_flush (file, Z_FINISH);
        if (err != Z_OK) return destroy((gz_stream*)file);
M
Mark Adler 已提交
930

M
Mark Adler 已提交
931 932
        putLong (s->file, s->crc);
        putLong (s->file, s->stream.total_in);
M
Mark Adler 已提交
933
#endif
M
Mark Adler 已提交
934
    }
M
Mark Adler 已提交
935
    return destroy((gz_stream*)file);
M
Mark Adler 已提交
936 937 938 939 940 941 942 943 944
}

/* ===========================================================================
     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 已提交
945
const char * ZEXPORT gzerror (file, errnum)
M
Mark Adler 已提交
946 947 948 949 950 951 952
    gzFile file;
    int *errnum;
{
    char *m;
    gz_stream *s = (gz_stream*)file;

    if (s == NULL) {
M
Mark Adler 已提交
953
        *errnum = Z_STREAM_ERROR;
M
Mark Adler 已提交
954
        return (const char*)ERR_MSG(Z_STREAM_ERROR);
M
Mark Adler 已提交
955 956
    }
    *errnum = s->z_err;
M
Mark Adler 已提交
957
    if (*errnum == Z_OK) return (const char*)"";
M
Mark Adler 已提交
958

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

M
Mark Adler 已提交
961
    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
M
Mark Adler 已提交
962 963 964

    TRYFREE(s->msg);
    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
M
Mark Adler 已提交
965
    if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
M
Mark Adler 已提交
966 967 968
    strcpy(s->msg, s->path);
    strcat(s->msg, ": ");
    strcat(s->msg, m);
M
Mark Adler 已提交
969
    return (const char*)s->msg;
M
Mark Adler 已提交
970
}
M
Mark Adler 已提交
971 972 973 974 975 976 977 978 979 980 981 982 983 984

/* ===========================================================================
     Clear the error and end-of-file flags, and do the same for the real file.
*/
void ZEXPORT gzclearerr (file)
    gzFile file;
{
    gz_stream *s = (gz_stream*)file;

    if (s == NULL) return;
    if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
    s->z_eof = 0;
    clearerr(s->file);
}