Subversion Repositories shark

Rev

Rev 100 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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