Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
107 pj 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-24 11:13:44 pj 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
    sprintf(buf,"%s",format);
538
    va_end(va);
539
    len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
540
    if (len <= 0) return 0;
541
 
542
    return gzwrite(file, buf, (unsigned)len);
543
}
544
#else /* not ANSI C */
545
 
546
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
547
                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
548
    gzFile file;
549
    const char *format;
550
    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
551
        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
552
{
553
    char buf[Z_PRINTF_BUFSIZE];
554
    int len;
555
 
556
#ifdef HAS_snprintf
557
    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
558
             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
559
#else
560
    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
561
            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
562
#endif
563
    len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
564
    if (len <= 0) return 0;
565
 
566
    return gzwrite(file, buf, len);
567
}
568
#endif
569
 
570
/* ===========================================================================
571
      Writes c, converted to an unsigned char, into the compressed file.
572
   gzputc returns the value that was written, or -1 in case of error.
573
*/
574
int ZEXPORT gzputc(file, c)
575
    gzFile file;
576
    int c;
577
{
578
    unsigned char cc = (unsigned char) c; /* required for big endian systems */
579
 
580
    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
581
}
582
 
583
 
584
/* ===========================================================================
585
      Writes the given null-terminated string to the compressed file, excluding
586
   the terminating null character.
587
      gzputs returns the number of characters written, or -1 in case of error.
588
*/
589
int ZEXPORT gzputs(file, s)
590
    gzFile file;
591
    const char *s;
592
{
593
    return gzwrite(file, (char*)s, (unsigned)strlen(s));
594
}
595
 
596
 
597
/* ===========================================================================
598
     Flushes all pending output into the compressed file. The parameter
599
   flush is as in the deflate() function.
600
*/
601
local int do_flush (file, flush)
602
    gzFile file;
603
    int flush;
604
{
605
    uInt len;
606
    int done = 0;
607
    gz_stream *s = (gz_stream*)file;
608
 
609
    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
610
 
611
    s->stream.avail_in = 0; /* should be zero already anyway */
612
 
613
    for (;;) {
614
        len = Z_BUFSIZE - s->stream.avail_out;
615
 
616
        if (len != 0) {
617
            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
618
                s->z_err = Z_ERRNO;
619
                return Z_ERRNO;
620
            }
621
            s->stream.next_out = s->outbuf;
622
            s->stream.avail_out = Z_BUFSIZE;
623
        }
624
        if (done) break;
625
        s->z_err = deflate(&(s->stream), flush);
626
 
627
        /* Ignore the second of two consecutive flushes: */
628
        if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
629
 
630
        /* deflate has finished flushing only when it hasn't used up
631
         * all the available space in the output buffer:
632
         */
633
        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
634
 
635
        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
636
    }
637
    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
638
}
639
 
640
int ZEXPORT gzflush (file, flush)
641
     gzFile file;
642
     int flush;
643
{
644
    gz_stream *s = (gz_stream*)file;
645
    int err = do_flush (file, flush);
646
 
647
    if (err) return err;
648
    fflush(s->file);
649
    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
650
}
651
#endif /* NO_DEFLATE */
652
 
653
/* ===========================================================================
654
      Sets the starting position for the next gzread or gzwrite on the given
655
   compressed file. The offset represents a number of bytes in the
656
      gzseek returns the resulting offset location as measured in bytes from
657
   the beginning of the uncompressed stream, or -1 in case of error.
658
      SEEK_END is not implemented, returns error.
659
      In this version of the library, gzseek can be extremely slow.
660
*/
661
z_off_t ZEXPORT gzseek (file, offset, whence)
662
    gzFile file;
663
    z_off_t offset;
664
    int whence;
665
{
666
    gz_stream *s = (gz_stream*)file;
667
 
668
    if (s == NULL || whence == SEEK_END ||
669
        s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
670
        return -1L;
671
    }
672
 
673
    if (s->mode == 'w') {
674
#ifdef NO_DEFLATE
675
        return -1L;
676
#else
677
        if (whence == SEEK_SET) {
678
            offset -= s->stream.total_in;
679
        }
680
        if (offset < 0) return -1L;
681
 
682
        /* At this point, offset is the number of zero bytes to write. */
683
        if (s->inbuf == Z_NULL) {
684
            s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
685
            zmemzero(s->inbuf, Z_BUFSIZE);
686
        }
687
        while (offset > 0)  {
688
            uInt size = Z_BUFSIZE;
689
            if (offset < Z_BUFSIZE) size = (uInt)offset;
690
 
691
            size = gzwrite(file, s->inbuf, size);
692
            if (size == 0) return -1L;
693
 
694
            offset -= size;
695
        }
696
        return (z_off_t)s->stream.total_in;
697
#endif
698
    }
699
    /* Rest of function is for reading only */
700
 
701
    /* compute absolute position */
702
    if (whence == SEEK_CUR) {
703
        offset += s->stream.total_out;
704
    }
705
    if (offset < 0) return -1L;
706
 
707
    if (s->transparent) {
708
        /* map to fseek */
709
        s->stream.avail_in = 0;
710
        s->stream.next_in = s->inbuf;
711
        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
712
 
713
        s->stream.total_in = s->stream.total_out = (uLong)offset;
714
        return offset;
715
    }
716
 
717
    /* For a negative seek, rewind and use positive seek */
718
    if ((uLong)offset >= s->stream.total_out) {
719
        offset -= s->stream.total_out;
720
    } else if (gzrewind(file) < 0) {
721
        return -1L;
722
    }
723
    /* offset is now the number of bytes to skip. */
724
 
725
    if (offset != 0 && s->outbuf == Z_NULL) {
726
        s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
727
    }
728
    while (offset > 0)  {
729
        int size = Z_BUFSIZE;
730
        if (offset < Z_BUFSIZE) size = (int)offset;
731
 
732
        size = gzread(file, s->outbuf, (uInt)size);
733
        if (size <= 0) return -1L;
734
        offset -= size;
735
    }
736
    return (z_off_t)s->stream.total_out;
737
}
738
 
739
/* ===========================================================================
740
     Rewinds input file.
741
*/
742
int ZEXPORT gzrewind (file)
743
    gzFile file;
744
{
745
    gz_stream *s = (gz_stream*)file;
746
 
747
    if (s == NULL || s->mode != 'r') return -1;
748
 
749
    s->z_err = Z_OK;
750
    s->z_eof = 0;
751
    s->stream.avail_in = 0;
752
    s->stream.next_in = s->inbuf;
753
    s->crc = crc32(0L, Z_NULL, 0);
754
 
755
    if (s->startpos == 0) { /* not a compressed file */
756
        rewind(s->file);
757
        return 0;
758
    }
759
 
760
    (void) inflateReset(&s->stream);
761
    return fseek(s->file, s->startpos, SEEK_SET);
762
}
763
 
764
/* ===========================================================================
765
     Returns the starting position for the next gzread or gzwrite on the
766
   given compressed file. This position represents a number of bytes in the
767
   uncompressed data stream.
768
*/
769
z_off_t ZEXPORT gztell (file)
770
    gzFile file;
771
{
772
    return gzseek(file, 0L, SEEK_CUR);
773
}
774
 
775
/* ===========================================================================
776
     Returns 1 when EOF has previously been detected reading the given
777
   input stream, otherwise zero.
778
*/
779
int ZEXPORT gzeof (file)
780
    gzFile file;
781
{
782
    gz_stream *s = (gz_stream*)file;
783
 
784
    return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
785
}
786
 
787
/* ===========================================================================
788
   Outputs a long in LSB order to the given file
789
*/
790
local void putLong (file, x)
791
    FILE *file;
792
    uLong x;
793
{
794
    int n;
795
    for (n = 0; n < 4; n++) {
796
        fputc((int)(x & 0xff), file);
797
        x >>= 8;
798
    }
799
}
800
 
801
/* ===========================================================================
802
   Reads a long in LSB order from the given gz_stream. Sets z_err in case
803
   of error.
804
*/
805
local uLong getLong (s)
806
    gz_stream *s;
807
{
808
    uLong x = (uLong)get_byte(s);
809
    int c;
810
 
811
    x += ((uLong)get_byte(s))<<8;
812
    x += ((uLong)get_byte(s))<<16;
813
    c = get_byte(s);
814
    if (c == EOF) s->z_err = Z_DATA_ERROR;
815
    x += ((uLong)c)<<24;
816
    return x;
817
}
818
 
819
/* ===========================================================================
820
     Flushes all pending output if necessary, closes the compressed file
821
   and deallocates all the (de)compression state.
822
*/
823
int ZEXPORT gzclose (file)
824
    gzFile file;
825
{
826
    int err;
827
    gz_stream *s = (gz_stream*)file;
828
 
829
    if (s == NULL) return Z_STREAM_ERROR;
830
 
831
    if (s->mode == 'w') {
832
#ifdef NO_DEFLATE
833
        return Z_STREAM_ERROR;
834
#else
835
        err = do_flush (file, Z_FINISH);
836
        if (err != Z_OK) return destroy((gz_stream*)file);
837
 
838
        putLong (s->file, s->crc);
839
        putLong (s->file, s->stream.total_in);
840
#endif
841
    }
842
    return destroy((gz_stream*)file);
843
}
844
 
845
/* ===========================================================================
846
     Returns the error message for the last error which occured on the
847
   given compressed file. errnum is set to zlib error number. If an
848
   error occured in the file system and not in the compression library,
849
   errnum is set to Z_ERRNO and the application may consult errno
850
   to get the exact error code.
851
*/
852
const char*  ZEXPORT gzerror (file, errnum)
853
    gzFile file;
854
    int *errnum;
855
{
856
    char *m;
857
    gz_stream *s = (gz_stream*)file;
858
 
859
    if (s == NULL) {
860
        *errnum = Z_STREAM_ERROR;
861
        return (const char*)ERR_MSG(Z_STREAM_ERROR);
862
    }
863
    *errnum = s->z_err;
864
    if (*errnum == Z_OK) return (const char*)"";
865
 
866
    m =  (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
867
 
868
    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
869
 
870
    TRYFREE(s->msg);
871
    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
872
    strcpy(s->msg, s->path);
873
    strcat(s->msg, ": ");
874
    strcat(s->msg, m);
875
    return (const char*)s->msg;
876
}