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