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