17dd7cddfSDavid du Colombier /* gzio.c -- IO on .gz files
2*593dc095SDavid du Colombier * Copyright (C) 1995-2003 Jean-loup Gailly.
37dd7cddfSDavid du Colombier * For conditions of distribution and use, see copyright notice in zlib.h
4*593dc095SDavid du Colombier *
5*593dc095SDavid du Colombier * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
67dd7cddfSDavid du Colombier */
77dd7cddfSDavid du Colombier
8*593dc095SDavid du Colombier /* @(#) $Id: gzio.c,v 1.1.1.1 2005/04/24 21:39:39 giles Exp $ */
97dd7cddfSDavid du Colombier
107dd7cddfSDavid du Colombier #include <stdio.h>
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier #include "zutil.h"
137dd7cddfSDavid du Colombier
14*593dc095SDavid du Colombier #ifdef NO_DEFLATE /* for compatiblity with old definition */
15*593dc095SDavid du Colombier # define NO_GZCOMPRESS
16*593dc095SDavid du Colombier #endif
177dd7cddfSDavid du Colombier
18*593dc095SDavid du Colombier #ifndef NO_DUMMY_DECL
19*593dc095SDavid du Colombier struct internal_state {int dummy;}; /* for buggy compilers */
20*593dc095SDavid du Colombier #endif
21*593dc095SDavid du Colombier
22*593dc095SDavid du Colombier #ifndef Z_BUFSIZE
23*593dc095SDavid du Colombier # ifdef MAXSEG_64K
24*593dc095SDavid du Colombier # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
25*593dc095SDavid du Colombier # else
26*593dc095SDavid du Colombier # define Z_BUFSIZE 16384
27*593dc095SDavid du Colombier # endif
28*593dc095SDavid du Colombier #endif
29*593dc095SDavid du Colombier #ifndef Z_PRINTF_BUFSIZE
30*593dc095SDavid du Colombier # define Z_PRINTF_BUFSIZE 4096
31*593dc095SDavid du Colombier #endif
32*593dc095SDavid du Colombier
33*593dc095SDavid du Colombier #ifdef __MVS__
34*593dc095SDavid du Colombier # pragma map (fdopen , "\174\174FDOPEN")
35*593dc095SDavid du Colombier FILE *fdopen(int, const char *);
36*593dc095SDavid du Colombier #endif
37*593dc095SDavid du Colombier
38*593dc095SDavid du Colombier #ifndef STDC
39*593dc095SDavid du Colombier extern voidp malloc OF((uInt size));
40*593dc095SDavid du Colombier extern void free OF((voidpf ptr));
41*593dc095SDavid du Colombier #endif
427dd7cddfSDavid du Colombier
437dd7cddfSDavid du Colombier #define ALLOC(size) malloc(size)
447dd7cddfSDavid du Colombier #define TRYFREE(p) {if (p) free(p);}
457dd7cddfSDavid du Colombier
46*593dc095SDavid du Colombier static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
477dd7cddfSDavid du Colombier
487dd7cddfSDavid du Colombier /* gzip flag byte */
497dd7cddfSDavid du Colombier #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
507dd7cddfSDavid du Colombier #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
517dd7cddfSDavid du Colombier #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
527dd7cddfSDavid du Colombier #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
537dd7cddfSDavid du Colombier #define COMMENT 0x10 /* bit 4 set: file comment present */
547dd7cddfSDavid du Colombier #define RESERVED 0xE0 /* bits 5..7: reserved */
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier typedef struct gz_stream {
577dd7cddfSDavid du Colombier z_stream stream;
587dd7cddfSDavid du Colombier int z_err; /* error code for last stream operation */
597dd7cddfSDavid du Colombier int z_eof; /* set if end of input file */
607dd7cddfSDavid du Colombier FILE *file; /* .gz file */
617dd7cddfSDavid du Colombier Byte *inbuf; /* input buffer */
627dd7cddfSDavid du Colombier Byte *outbuf; /* output buffer */
637dd7cddfSDavid du Colombier uLong crc; /* crc32 of uncompressed data */
647dd7cddfSDavid du Colombier char *msg; /* error message */
657dd7cddfSDavid du Colombier char *path; /* path name for debugging only */
667dd7cddfSDavid du Colombier int transparent; /* 1 if input file is not a .gz file */
677dd7cddfSDavid du Colombier char mode; /* 'w' or 'r' */
68*593dc095SDavid du Colombier z_off_t start; /* start of compressed data in file (header skipped) */
69*593dc095SDavid du Colombier z_off_t in; /* bytes into deflate or inflate */
70*593dc095SDavid du Colombier z_off_t out; /* bytes out of deflate or inflate */
71*593dc095SDavid du Colombier int back; /* one character push-back */
72*593dc095SDavid du Colombier int last; /* true if push-back is last character */
737dd7cddfSDavid du Colombier } gz_stream;
747dd7cddfSDavid du Colombier
757dd7cddfSDavid du Colombier
767dd7cddfSDavid du Colombier local gzFile gz_open OF((const char *path, const char *mode, int fd));
77*593dc095SDavid du Colombier local int do_flush OF((gzFile file, int flush));
787dd7cddfSDavid du Colombier local int get_byte OF((gz_stream *s));
797dd7cddfSDavid du Colombier local void check_header OF((gz_stream *s));
807dd7cddfSDavid du Colombier local int destroy OF((gz_stream *s));
817dd7cddfSDavid du Colombier local void putLong OF((FILE *file, uLong x));
827dd7cddfSDavid du Colombier local uLong getLong OF((gz_stream *s));
837dd7cddfSDavid du Colombier
847dd7cddfSDavid du Colombier /* ===========================================================================
857dd7cddfSDavid du Colombier Opens a gzip (.gz) file for reading or writing. The mode parameter
867dd7cddfSDavid du Colombier is as in fopen ("rb" or "wb"). The file is given either by file descriptor
877dd7cddfSDavid du Colombier or path name (if fd == -1).
88*593dc095SDavid du Colombier gz_open returns NULL if the file could not be opened or if there was
897dd7cddfSDavid du Colombier insufficient memory to allocate the (de)compression state; errno
907dd7cddfSDavid du Colombier can be checked to distinguish the two cases (if errno is zero, the
917dd7cddfSDavid du Colombier zlib error is Z_MEM_ERROR).
927dd7cddfSDavid du Colombier */
gz_open(path,mode,fd)937dd7cddfSDavid du Colombier local gzFile gz_open (path, mode, fd)
947dd7cddfSDavid du Colombier const char *path;
957dd7cddfSDavid du Colombier const char *mode;
967dd7cddfSDavid du Colombier int fd;
977dd7cddfSDavid du Colombier {
987dd7cddfSDavid du Colombier int err;
997dd7cddfSDavid du Colombier int level = Z_DEFAULT_COMPRESSION; /* compression level */
100*593dc095SDavid du Colombier int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
1017dd7cddfSDavid du Colombier char *p = (char*)mode;
1027dd7cddfSDavid du Colombier gz_stream *s;
1037dd7cddfSDavid du Colombier char fmode[80]; /* copy of mode, without the compression level */
1047dd7cddfSDavid du Colombier char *m = fmode;
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier if (!path || !mode) return Z_NULL;
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier s = (gz_stream *)ALLOC(sizeof(gz_stream));
1097dd7cddfSDavid du Colombier if (!s) return Z_NULL;
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier s->stream.zalloc = (alloc_func)0;
1127dd7cddfSDavid du Colombier s->stream.zfree = (free_func)0;
1137dd7cddfSDavid du Colombier s->stream.opaque = (voidpf)0;
1147dd7cddfSDavid du Colombier s->stream.next_in = s->inbuf = Z_NULL;
1157dd7cddfSDavid du Colombier s->stream.next_out = s->outbuf = Z_NULL;
1167dd7cddfSDavid du Colombier s->stream.avail_in = s->stream.avail_out = 0;
1177dd7cddfSDavid du Colombier s->file = NULL;
1187dd7cddfSDavid du Colombier s->z_err = Z_OK;
1197dd7cddfSDavid du Colombier s->z_eof = 0;
120*593dc095SDavid du Colombier s->in = 0;
121*593dc095SDavid du Colombier s->out = 0;
122*593dc095SDavid du Colombier s->back = EOF;
1237dd7cddfSDavid du Colombier s->crc = crc32(0L, Z_NULL, 0);
1247dd7cddfSDavid du Colombier s->msg = NULL;
1257dd7cddfSDavid du Colombier s->transparent = 0;
1267dd7cddfSDavid du Colombier
1277dd7cddfSDavid du Colombier s->path = (char*)ALLOC(strlen(path)+1);
1287dd7cddfSDavid du Colombier if (s->path == NULL) {
1297dd7cddfSDavid du Colombier return destroy(s), (gzFile)Z_NULL;
1307dd7cddfSDavid du Colombier }
1317dd7cddfSDavid du Colombier strcpy(s->path, path); /* do this early for debugging */
1327dd7cddfSDavid du Colombier
1337dd7cddfSDavid du Colombier s->mode = '\0';
1347dd7cddfSDavid du Colombier do {
1357dd7cddfSDavid du Colombier if (*p == 'r') s->mode = 'r';
1367dd7cddfSDavid du Colombier if (*p == 'w' || *p == 'a') s->mode = 'w';
1377dd7cddfSDavid du Colombier if (*p >= '0' && *p <= '9') {
1387dd7cddfSDavid du Colombier level = *p - '0';
139*593dc095SDavid du Colombier } else if (*p == 'f') {
140*593dc095SDavid du Colombier strategy = Z_FILTERED;
141*593dc095SDavid du Colombier } else if (*p == 'h') {
142*593dc095SDavid du Colombier strategy = Z_HUFFMAN_ONLY;
143*593dc095SDavid du Colombier } else if (*p == 'R') {
144*593dc095SDavid du Colombier strategy = Z_RLE;
1457dd7cddfSDavid du Colombier } else {
1467dd7cddfSDavid du Colombier *m++ = *p; /* copy the mode */
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier } while (*p++ && m != fmode + sizeof(fmode));
1497dd7cddfSDavid du Colombier if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
1507dd7cddfSDavid du Colombier
1517dd7cddfSDavid du Colombier if (s->mode == 'w') {
152*593dc095SDavid du Colombier #ifdef NO_GZCOMPRESS
153*593dc095SDavid du Colombier err = Z_STREAM_ERROR;
154*593dc095SDavid du Colombier #else
1557dd7cddfSDavid du Colombier err = deflateInit2(&(s->stream), level,
156*593dc095SDavid du Colombier Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
1577dd7cddfSDavid du Colombier /* windowBits is passed < 0 to suppress zlib header */
1587dd7cddfSDavid du Colombier
1597dd7cddfSDavid du Colombier s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
160*593dc095SDavid du Colombier #endif
1617dd7cddfSDavid du Colombier if (err != Z_OK || s->outbuf == Z_NULL) {
1627dd7cddfSDavid du Colombier return destroy(s), (gzFile)Z_NULL;
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier } else {
1657dd7cddfSDavid du Colombier s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
1667dd7cddfSDavid du Colombier
167*593dc095SDavid du Colombier err = inflateInit2(&(s->stream), -MAX_WBITS);
168*593dc095SDavid du Colombier /* windowBits is passed < 0 to tell that there is no zlib header.
169*593dc095SDavid du Colombier * Note that in this case inflate *requires* an extra "dummy" byte
170*593dc095SDavid du Colombier * after the compressed stream in order to complete decompression and
171*593dc095SDavid du Colombier * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
172*593dc095SDavid du Colombier * present after the compressed stream.
173*593dc095SDavid du Colombier */
1747dd7cddfSDavid du Colombier if (err != Z_OK || s->inbuf == Z_NULL) {
1757dd7cddfSDavid du Colombier return destroy(s), (gzFile)Z_NULL;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier }
1787dd7cddfSDavid du Colombier s->stream.avail_out = Z_BUFSIZE;
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier errno = 0;
181*593dc095SDavid du Colombier s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier if (s->file == NULL) {
1847dd7cddfSDavid du Colombier return destroy(s), (gzFile)Z_NULL;
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier if (s->mode == 'w') {
1877dd7cddfSDavid du Colombier /* Write a very simple .gz header:
1887dd7cddfSDavid du Colombier */
1897dd7cddfSDavid du Colombier fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
1907dd7cddfSDavid du Colombier Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
191*593dc095SDavid du Colombier s->start = 10L;
192*593dc095SDavid du Colombier /* We use 10L instead of ftell(s->file) to because ftell causes an
193*593dc095SDavid du Colombier * fflush on some systems. This version of the library doesn't use
194*593dc095SDavid du Colombier * start anyway in write mode, so this initialization is not
195*593dc095SDavid du Colombier * necessary.
196*593dc095SDavid du Colombier */
1977dd7cddfSDavid du Colombier } else {
1987dd7cddfSDavid du Colombier check_header(s); /* skip the .gz header */
199*593dc095SDavid du Colombier s->start = ftell(s->file) - s->stream.avail_in;
2007dd7cddfSDavid du Colombier }
201*593dc095SDavid du Colombier
2027dd7cddfSDavid du Colombier return (gzFile)s;
2037dd7cddfSDavid du Colombier }
2047dd7cddfSDavid du Colombier
2057dd7cddfSDavid du Colombier /* ===========================================================================
2067dd7cddfSDavid du Colombier Opens a gzip (.gz) file for reading or writing.
2077dd7cddfSDavid du Colombier */
gzopen(path,mode)208*593dc095SDavid du Colombier gzFile ZEXPORT gzopen (path, mode)
2097dd7cddfSDavid du Colombier const char *path;
2107dd7cddfSDavid du Colombier const char *mode;
2117dd7cddfSDavid du Colombier {
2127dd7cddfSDavid du Colombier return gz_open (path, mode, -1);
2137dd7cddfSDavid du Colombier }
2147dd7cddfSDavid du Colombier
2157dd7cddfSDavid du Colombier /* ===========================================================================
2167dd7cddfSDavid du Colombier Associate a gzFile with the file descriptor fd. fd is not dup'ed here
2177dd7cddfSDavid du Colombier to mimic the behavio(u)r of fdopen.
2187dd7cddfSDavid du Colombier */
gzdopen(fd,mode)219*593dc095SDavid du Colombier gzFile ZEXPORT gzdopen (fd, mode)
2207dd7cddfSDavid du Colombier int fd;
2217dd7cddfSDavid du Colombier const char *mode;
2227dd7cddfSDavid du Colombier {
2237dd7cddfSDavid du Colombier char name[20];
2247dd7cddfSDavid du Colombier
2257dd7cddfSDavid du Colombier if (fd < 0) return (gzFile)Z_NULL;
2267dd7cddfSDavid du Colombier sprintf(name, "<fd:%d>", fd); /* for debugging */
2277dd7cddfSDavid du Colombier
2287dd7cddfSDavid du Colombier return gz_open (name, mode, fd);
2297dd7cddfSDavid du Colombier }
2307dd7cddfSDavid du Colombier
2317dd7cddfSDavid du Colombier /* ===========================================================================
232*593dc095SDavid du Colombier * Update the compression level and strategy
233*593dc095SDavid du Colombier */
gzsetparams(file,level,strategy)234*593dc095SDavid du Colombier int ZEXPORT gzsetparams (file, level, strategy)
235*593dc095SDavid du Colombier gzFile file;
236*593dc095SDavid du Colombier int level;
237*593dc095SDavid du Colombier int strategy;
238*593dc095SDavid du Colombier {
239*593dc095SDavid du Colombier gz_stream *s = (gz_stream*)file;
240*593dc095SDavid du Colombier
241*593dc095SDavid du Colombier if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
242*593dc095SDavid du Colombier
243*593dc095SDavid du Colombier /* Make room to allow flushing */
244*593dc095SDavid du Colombier if (s->stream.avail_out == 0) {
245*593dc095SDavid du Colombier
246*593dc095SDavid du Colombier s->stream.next_out = s->outbuf;
247*593dc095SDavid du Colombier if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
248*593dc095SDavid du Colombier s->z_err = Z_ERRNO;
249*593dc095SDavid du Colombier }
250*593dc095SDavid du Colombier s->stream.avail_out = Z_BUFSIZE;
251*593dc095SDavid du Colombier }
252*593dc095SDavid du Colombier
253*593dc095SDavid du Colombier return deflateParams (&(s->stream), level, strategy);
254*593dc095SDavid du Colombier }
255*593dc095SDavid du Colombier
256*593dc095SDavid du Colombier /* ===========================================================================
2577dd7cddfSDavid du Colombier Read a byte from a gz_stream; update next_in and avail_in. Return EOF
2587dd7cddfSDavid du Colombier for end of file.
2597dd7cddfSDavid du Colombier IN assertion: the stream s has been sucessfully opened for reading.
2607dd7cddfSDavid du Colombier */
get_byte(s)2617dd7cddfSDavid du Colombier local int get_byte(s)
2627dd7cddfSDavid du Colombier gz_stream *s;
2637dd7cddfSDavid du Colombier {
2647dd7cddfSDavid du Colombier if (s->z_eof) return EOF;
2657dd7cddfSDavid du Colombier if (s->stream.avail_in == 0) {
2667dd7cddfSDavid du Colombier errno = 0;
2677dd7cddfSDavid du Colombier s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
2687dd7cddfSDavid du Colombier if (s->stream.avail_in == 0) {
2697dd7cddfSDavid du Colombier s->z_eof = 1;
2707dd7cddfSDavid du Colombier if (ferror(s->file)) s->z_err = Z_ERRNO;
2717dd7cddfSDavid du Colombier return EOF;
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier s->stream.next_in = s->inbuf;
2747dd7cddfSDavid du Colombier }
2757dd7cddfSDavid du Colombier s->stream.avail_in--;
2767dd7cddfSDavid du Colombier return *(s->stream.next_in)++;
2777dd7cddfSDavid du Colombier }
2787dd7cddfSDavid du Colombier
2797dd7cddfSDavid du Colombier /* ===========================================================================
2807dd7cddfSDavid du Colombier Check the gzip header of a gz_stream opened for reading. Set the stream
2817dd7cddfSDavid du Colombier mode to transparent if the gzip magic header is not present; set s->err
2827dd7cddfSDavid du Colombier to Z_DATA_ERROR if the magic header is present but the rest of the header
2837dd7cddfSDavid du Colombier is incorrect.
2847dd7cddfSDavid du Colombier IN assertion: the stream s has already been created sucessfully;
2857dd7cddfSDavid du Colombier s->stream.avail_in is zero for the first time, but may be non-zero
2867dd7cddfSDavid du Colombier for concatenated .gz files.
2877dd7cddfSDavid du Colombier */
check_header(s)2887dd7cddfSDavid du Colombier local void check_header(s)
2897dd7cddfSDavid du Colombier gz_stream *s;
2907dd7cddfSDavid du Colombier {
2917dd7cddfSDavid du Colombier int method; /* method byte */
2927dd7cddfSDavid du Colombier int flags; /* flags byte */
2937dd7cddfSDavid du Colombier uInt len;
2947dd7cddfSDavid du Colombier int c;
2957dd7cddfSDavid du Colombier
296*593dc095SDavid du Colombier /* Assure two bytes in the buffer so we can peek ahead -- handle case
297*593dc095SDavid du Colombier where first byte of header is at the end of the buffer after the last
298*593dc095SDavid du Colombier gzip segment */
299*593dc095SDavid du Colombier len = s->stream.avail_in;
300*593dc095SDavid du Colombier if (len < 2) {
301*593dc095SDavid du Colombier if (len) s->inbuf[0] = s->stream.next_in[0];
302*593dc095SDavid du Colombier errno = 0;
303*593dc095SDavid du Colombier len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
304*593dc095SDavid du Colombier if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
305*593dc095SDavid du Colombier s->stream.avail_in += len;
306*593dc095SDavid du Colombier s->stream.next_in = s->inbuf;
307*593dc095SDavid du Colombier if (s->stream.avail_in < 2) {
308*593dc095SDavid du Colombier s->transparent = s->stream.avail_in;
3097dd7cddfSDavid du Colombier return;
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier }
312*593dc095SDavid du Colombier
313*593dc095SDavid du Colombier /* Peek ahead to check the gzip magic header */
314*593dc095SDavid du Colombier if (s->stream.next_in[0] != gz_magic[0] ||
315*593dc095SDavid du Colombier s->stream.next_in[1] != gz_magic[1]) {
316*593dc095SDavid du Colombier s->transparent = 1;
317*593dc095SDavid du Colombier return;
318*593dc095SDavid du Colombier }
319*593dc095SDavid du Colombier s->stream.avail_in -= 2;
320*593dc095SDavid du Colombier s->stream.next_in += 2;
321*593dc095SDavid du Colombier
322*593dc095SDavid du Colombier /* Check the rest of the gzip header */
3237dd7cddfSDavid du Colombier method = get_byte(s);
3247dd7cddfSDavid du Colombier flags = get_byte(s);
3257dd7cddfSDavid du Colombier if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
3267dd7cddfSDavid du Colombier s->z_err = Z_DATA_ERROR;
3277dd7cddfSDavid du Colombier return;
3287dd7cddfSDavid du Colombier }
3297dd7cddfSDavid du Colombier
3307dd7cddfSDavid du Colombier /* Discard time, xflags and OS code: */
3317dd7cddfSDavid du Colombier for (len = 0; len < 6; len++) (void)get_byte(s);
3327dd7cddfSDavid du Colombier
3337dd7cddfSDavid du Colombier if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
3347dd7cddfSDavid du Colombier len = (uInt)get_byte(s);
3357dd7cddfSDavid du Colombier len += ((uInt)get_byte(s))<<8;
3367dd7cddfSDavid du Colombier /* len is garbage if EOF but the loop below will quit anyway */
3377dd7cddfSDavid du Colombier while (len-- != 0 && get_byte(s) != EOF) ;
3387dd7cddfSDavid du Colombier }
3397dd7cddfSDavid du Colombier if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
3407dd7cddfSDavid du Colombier while ((c = get_byte(s)) != 0 && c != EOF) ;
3417dd7cddfSDavid du Colombier }
3427dd7cddfSDavid du Colombier if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
3437dd7cddfSDavid du Colombier while ((c = get_byte(s)) != 0 && c != EOF) ;
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
3467dd7cddfSDavid du Colombier for (len = 0; len < 2; len++) (void)get_byte(s);
3477dd7cddfSDavid du Colombier }
3487dd7cddfSDavid du Colombier s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
3497dd7cddfSDavid du Colombier }
3507dd7cddfSDavid du Colombier
3517dd7cddfSDavid du Colombier /* ===========================================================================
3527dd7cddfSDavid du Colombier * Cleanup then free the given gz_stream. Return a zlib error code.
3537dd7cddfSDavid du Colombier Try freeing in the reverse order of allocations.
3547dd7cddfSDavid du Colombier */
destroy(s)3557dd7cddfSDavid du Colombier local int destroy (s)
3567dd7cddfSDavid du Colombier gz_stream *s;
3577dd7cddfSDavid du Colombier {
3587dd7cddfSDavid du Colombier int err = Z_OK;
3597dd7cddfSDavid du Colombier
3607dd7cddfSDavid du Colombier if (!s) return Z_STREAM_ERROR;
3617dd7cddfSDavid du Colombier
3627dd7cddfSDavid du Colombier TRYFREE(s->msg);
3637dd7cddfSDavid du Colombier
3647dd7cddfSDavid du Colombier if (s->stream.state != NULL) {
3657dd7cddfSDavid du Colombier if (s->mode == 'w') {
366*593dc095SDavid du Colombier #ifdef NO_GZCOMPRESS
367*593dc095SDavid du Colombier err = Z_STREAM_ERROR;
368*593dc095SDavid du Colombier #else
3697dd7cddfSDavid du Colombier err = deflateEnd(&(s->stream));
370*593dc095SDavid du Colombier #endif
3717dd7cddfSDavid du Colombier } else if (s->mode == 'r') {
3727dd7cddfSDavid du Colombier err = inflateEnd(&(s->stream));
3737dd7cddfSDavid du Colombier }
3747dd7cddfSDavid du Colombier }
3757dd7cddfSDavid du Colombier if (s->file != NULL && fclose(s->file)) {
376*593dc095SDavid du Colombier #ifdef ESPIPE
377*593dc095SDavid du Colombier if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
378*593dc095SDavid du Colombier #endif
3797dd7cddfSDavid du Colombier err = Z_ERRNO;
3807dd7cddfSDavid du Colombier }
3817dd7cddfSDavid du Colombier if (s->z_err < 0) err = s->z_err;
3827dd7cddfSDavid du Colombier
3837dd7cddfSDavid du Colombier TRYFREE(s->inbuf);
3847dd7cddfSDavid du Colombier TRYFREE(s->outbuf);
3857dd7cddfSDavid du Colombier TRYFREE(s->path);
3867dd7cddfSDavid du Colombier TRYFREE(s);
3877dd7cddfSDavid du Colombier return err;
3887dd7cddfSDavid du Colombier }
3897dd7cddfSDavid du Colombier
3907dd7cddfSDavid du Colombier /* ===========================================================================
3917dd7cddfSDavid du Colombier Reads the given number of uncompressed bytes from the compressed file.
3927dd7cddfSDavid du Colombier gzread returns the number of bytes actually read (0 for end of file).
3937dd7cddfSDavid du Colombier */
gzread(file,buf,len)394*593dc095SDavid du Colombier int ZEXPORT gzread (file, buf, len)
3957dd7cddfSDavid du Colombier gzFile file;
3967dd7cddfSDavid du Colombier voidp buf;
3977dd7cddfSDavid du Colombier unsigned len;
3987dd7cddfSDavid du Colombier {
3997dd7cddfSDavid du Colombier gz_stream *s = (gz_stream*)file;
400*593dc095SDavid du Colombier Bytef *start = (Bytef*)buf; /* starting point for crc computation */
4017dd7cddfSDavid du Colombier Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
4027dd7cddfSDavid du Colombier
4037dd7cddfSDavid du Colombier if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
4047dd7cddfSDavid du Colombier
4057dd7cddfSDavid du Colombier if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
4067dd7cddfSDavid du Colombier if (s->z_err == Z_STREAM_END) return 0; /* EOF */
4077dd7cddfSDavid du Colombier
408*593dc095SDavid du Colombier next_out = (Byte*)buf;
409*593dc095SDavid du Colombier s->stream.next_out = (Bytef*)buf;
4107dd7cddfSDavid du Colombier s->stream.avail_out = len;
4117dd7cddfSDavid du Colombier
412*593dc095SDavid du Colombier if (s->stream.avail_out && s->back != EOF) {
413*593dc095SDavid du Colombier *next_out++ = s->back;
414*593dc095SDavid du Colombier s->stream.next_out++;
415*593dc095SDavid du Colombier s->stream.avail_out--;
416*593dc095SDavid du Colombier s->back = EOF;
417*593dc095SDavid du Colombier s->out++;
418*593dc095SDavid du Colombier if (s->last) {
419*593dc095SDavid du Colombier s->z_err = Z_STREAM_END;
420*593dc095SDavid du Colombier return 1;
421*593dc095SDavid du Colombier }
422*593dc095SDavid du Colombier }
423*593dc095SDavid du Colombier
4247dd7cddfSDavid du Colombier while (s->stream.avail_out != 0) {
4257dd7cddfSDavid du Colombier
4267dd7cddfSDavid du Colombier if (s->transparent) {
4277dd7cddfSDavid du Colombier /* Copy first the lookahead bytes: */
4287dd7cddfSDavid du Colombier uInt n = s->stream.avail_in;
4297dd7cddfSDavid du Colombier if (n > s->stream.avail_out) n = s->stream.avail_out;
4307dd7cddfSDavid du Colombier if (n > 0) {
4317dd7cddfSDavid du Colombier zmemcpy(s->stream.next_out, s->stream.next_in, n);
4327dd7cddfSDavid du Colombier next_out += n;
4337dd7cddfSDavid du Colombier s->stream.next_out = next_out;
4347dd7cddfSDavid du Colombier s->stream.next_in += n;
4357dd7cddfSDavid du Colombier s->stream.avail_out -= n;
4367dd7cddfSDavid du Colombier s->stream.avail_in -= n;
4377dd7cddfSDavid du Colombier }
4387dd7cddfSDavid du Colombier if (s->stream.avail_out > 0) {
4397dd7cddfSDavid du Colombier s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
4407dd7cddfSDavid du Colombier s->file);
4417dd7cddfSDavid du Colombier }
442*593dc095SDavid du Colombier len -= s->stream.avail_out;
443*593dc095SDavid du Colombier s->in += len;
444*593dc095SDavid du Colombier s->out += len;
445*593dc095SDavid du Colombier if (len == 0) s->z_eof = 1;
446*593dc095SDavid du Colombier return (int)len;
4477dd7cddfSDavid du Colombier }
4487dd7cddfSDavid du Colombier if (s->stream.avail_in == 0 && !s->z_eof) {
4497dd7cddfSDavid du Colombier
4507dd7cddfSDavid du Colombier errno = 0;
4517dd7cddfSDavid du Colombier s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
4527dd7cddfSDavid du Colombier if (s->stream.avail_in == 0) {
4537dd7cddfSDavid du Colombier s->z_eof = 1;
4547dd7cddfSDavid du Colombier if (ferror(s->file)) {
4557dd7cddfSDavid du Colombier s->z_err = Z_ERRNO;
4567dd7cddfSDavid du Colombier break;
4577dd7cddfSDavid du Colombier }
458*593dc095SDavid du Colombier if (feof(s->file)) { /* avoid error for empty file */
459*593dc095SDavid du Colombier s->z_err = Z_STREAM_END;
460*593dc095SDavid du Colombier break;
461*593dc095SDavid du Colombier }
4627dd7cddfSDavid du Colombier }
4637dd7cddfSDavid du Colombier s->stream.next_in = s->inbuf;
4647dd7cddfSDavid du Colombier }
465*593dc095SDavid du Colombier s->in += s->stream.avail_in;
466*593dc095SDavid du Colombier s->out += s->stream.avail_out;
4677dd7cddfSDavid du Colombier s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
468*593dc095SDavid du Colombier s->in -= s->stream.avail_in;
469*593dc095SDavid du Colombier s->out -= s->stream.avail_out;
4707dd7cddfSDavid du Colombier
4717dd7cddfSDavid du Colombier if (s->z_err == Z_STREAM_END) {
4727dd7cddfSDavid du Colombier /* Check CRC and original size */
4737dd7cddfSDavid du Colombier s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
4747dd7cddfSDavid du Colombier start = s->stream.next_out;
4757dd7cddfSDavid du Colombier
476*593dc095SDavid du Colombier if (getLong(s) != s->crc) {
4777dd7cddfSDavid du Colombier s->z_err = Z_DATA_ERROR;
4787dd7cddfSDavid du Colombier } else {
479*593dc095SDavid du Colombier (void)getLong(s);
480*593dc095SDavid du Colombier /* The uncompressed length returned by above getlong() may be
481*593dc095SDavid du Colombier * different from s->out in case of concatenated .gz files.
482*593dc095SDavid du Colombier * Check for such files:
483*593dc095SDavid du Colombier */
4847dd7cddfSDavid du Colombier check_header(s);
4857dd7cddfSDavid du Colombier if (s->z_err == Z_OK) {
4867dd7cddfSDavid du Colombier inflateReset(&(s->stream));
4877dd7cddfSDavid du Colombier s->crc = crc32(0L, Z_NULL, 0);
4887dd7cddfSDavid du Colombier }
4897dd7cddfSDavid du Colombier }
4907dd7cddfSDavid du Colombier }
4917dd7cddfSDavid du Colombier if (s->z_err != Z_OK || s->z_eof) break;
4927dd7cddfSDavid du Colombier }
4937dd7cddfSDavid du Colombier s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
4947dd7cddfSDavid du Colombier
4957dd7cddfSDavid du Colombier return (int)(len - s->stream.avail_out);
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier
498*593dc095SDavid du Colombier
499*593dc095SDavid du Colombier /* ===========================================================================
500*593dc095SDavid du Colombier Reads one byte from the compressed file. gzgetc returns this byte
501*593dc095SDavid du Colombier or -1 in case of end of file or error.
502*593dc095SDavid du Colombier */
gzgetc(file)503*593dc095SDavid du Colombier int ZEXPORT gzgetc(file)
504*593dc095SDavid du Colombier gzFile file;
505*593dc095SDavid du Colombier {
506*593dc095SDavid du Colombier unsigned char c;
507*593dc095SDavid du Colombier
508*593dc095SDavid du Colombier return gzread(file, &c, 1) == 1 ? c : -1;
509*593dc095SDavid du Colombier }
510*593dc095SDavid du Colombier
511*593dc095SDavid du Colombier
512*593dc095SDavid du Colombier /* ===========================================================================
513*593dc095SDavid du Colombier Push one byte back onto the stream.
514*593dc095SDavid du Colombier */
gzungetc(c,file)515*593dc095SDavid du Colombier int ZEXPORT gzungetc(c, file)
516*593dc095SDavid du Colombier int c;
517*593dc095SDavid du Colombier gzFile file;
518*593dc095SDavid du Colombier {
519*593dc095SDavid du Colombier gz_stream *s = (gz_stream*)file;
520*593dc095SDavid du Colombier
521*593dc095SDavid du Colombier if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
522*593dc095SDavid du Colombier s->back = c;
523*593dc095SDavid du Colombier s->out--;
524*593dc095SDavid du Colombier s->last = (s->z_err == Z_STREAM_END);
525*593dc095SDavid du Colombier if (s->last) s->z_err = Z_OK;
526*593dc095SDavid du Colombier s->z_eof = 0;
527*593dc095SDavid du Colombier return c;
528*593dc095SDavid du Colombier }
529*593dc095SDavid du Colombier
530*593dc095SDavid du Colombier
531*593dc095SDavid du Colombier /* ===========================================================================
532*593dc095SDavid du Colombier Reads bytes from the compressed file until len-1 characters are
533*593dc095SDavid du Colombier read, or a newline character is read and transferred to buf, or an
534*593dc095SDavid du Colombier end-of-file condition is encountered. The string is then terminated
535*593dc095SDavid du Colombier with a null character.
536*593dc095SDavid du Colombier gzgets returns buf, or Z_NULL in case of error.
537*593dc095SDavid du Colombier
538*593dc095SDavid du Colombier The current implementation is not optimized at all.
539*593dc095SDavid du Colombier */
gzgets(file,buf,len)540*593dc095SDavid du Colombier char * ZEXPORT gzgets(file, buf, len)
541*593dc095SDavid du Colombier gzFile file;
542*593dc095SDavid du Colombier char *buf;
543*593dc095SDavid du Colombier int len;
544*593dc095SDavid du Colombier {
545*593dc095SDavid du Colombier char *b = buf;
546*593dc095SDavid du Colombier if (buf == Z_NULL || len <= 0) return Z_NULL;
547*593dc095SDavid du Colombier
548*593dc095SDavid du Colombier while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
549*593dc095SDavid du Colombier *buf = '\0';
550*593dc095SDavid du Colombier return b == buf && len > 0 ? Z_NULL : b;
551*593dc095SDavid du Colombier }
552*593dc095SDavid du Colombier
553*593dc095SDavid du Colombier
554*593dc095SDavid du Colombier #ifndef NO_GZCOMPRESS
5557dd7cddfSDavid du Colombier /* ===========================================================================
5567dd7cddfSDavid du Colombier Writes the given number of uncompressed bytes into the compressed file.
5577dd7cddfSDavid du Colombier gzwrite returns the number of bytes actually written (0 in case of error).
5587dd7cddfSDavid du Colombier */
gzwrite(file,buf,len)559*593dc095SDavid du Colombier int ZEXPORT gzwrite (file, buf, len)
5607dd7cddfSDavid du Colombier gzFile file;
561*593dc095SDavid du Colombier voidpc buf;
5627dd7cddfSDavid du Colombier unsigned len;
5637dd7cddfSDavid du Colombier {
5647dd7cddfSDavid du Colombier gz_stream *s = (gz_stream*)file;
5657dd7cddfSDavid du Colombier
5667dd7cddfSDavid du Colombier if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
5677dd7cddfSDavid du Colombier
568*593dc095SDavid du Colombier s->stream.next_in = (Bytef*)buf;
5697dd7cddfSDavid du Colombier s->stream.avail_in = len;
5707dd7cddfSDavid du Colombier
5717dd7cddfSDavid du Colombier while (s->stream.avail_in != 0) {
5727dd7cddfSDavid du Colombier
5737dd7cddfSDavid du Colombier if (s->stream.avail_out == 0) {
5747dd7cddfSDavid du Colombier
5757dd7cddfSDavid du Colombier s->stream.next_out = s->outbuf;
5767dd7cddfSDavid du Colombier if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
5777dd7cddfSDavid du Colombier s->z_err = Z_ERRNO;
5787dd7cddfSDavid du Colombier break;
5797dd7cddfSDavid du Colombier }
5807dd7cddfSDavid du Colombier s->stream.avail_out = Z_BUFSIZE;
5817dd7cddfSDavid du Colombier }
582*593dc095SDavid du Colombier s->in += s->stream.avail_in;
583*593dc095SDavid du Colombier s->out += s->stream.avail_out;
5847dd7cddfSDavid du Colombier s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
585*593dc095SDavid du Colombier s->in -= s->stream.avail_in;
586*593dc095SDavid du Colombier s->out -= s->stream.avail_out;
5877dd7cddfSDavid du Colombier if (s->z_err != Z_OK) break;
5887dd7cddfSDavid du Colombier }
589*593dc095SDavid du Colombier s->crc = crc32(s->crc, (const Bytef *)buf, len);
5907dd7cddfSDavid du Colombier
5917dd7cddfSDavid du Colombier return (int)(len - s->stream.avail_in);
5927dd7cddfSDavid du Colombier }
5937dd7cddfSDavid du Colombier
594*593dc095SDavid du Colombier
595*593dc095SDavid du Colombier /* ===========================================================================
596*593dc095SDavid du Colombier Converts, formats, and writes the args to the compressed file under
597*593dc095SDavid du Colombier control of the format string, as in fprintf. gzprintf returns the number of
598*593dc095SDavid du Colombier uncompressed bytes actually written (0 in case of error).
599*593dc095SDavid du Colombier */
600*593dc095SDavid du Colombier #ifdef STDC
601*593dc095SDavid du Colombier #include <stdarg.h>
602*593dc095SDavid du Colombier
gzprintf(gzFile file,const char * format,...)603*593dc095SDavid du Colombier int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
604*593dc095SDavid du Colombier {
605*593dc095SDavid du Colombier char buf[Z_PRINTF_BUFSIZE];
606*593dc095SDavid du Colombier va_list va;
607*593dc095SDavid du Colombier int len;
608*593dc095SDavid du Colombier
609*593dc095SDavid du Colombier buf[sizeof(buf) - 1] = 0;
610*593dc095SDavid du Colombier va_start(va, format);
611*593dc095SDavid du Colombier #ifdef NO_vsnprintf
612*593dc095SDavid du Colombier # ifdef HAS_vsprintf_void
613*593dc095SDavid du Colombier (void)vsprintf(buf, format, va);
614*593dc095SDavid du Colombier va_end(va);
615*593dc095SDavid du Colombier for (len = 0; len < sizeof(buf); len++)
616*593dc095SDavid du Colombier if (buf[len] == 0) break;
617*593dc095SDavid du Colombier # else
618*593dc095SDavid du Colombier len = vsprintf(buf, format, va);
619*593dc095SDavid du Colombier va_end(va);
620*593dc095SDavid du Colombier # endif
621*593dc095SDavid du Colombier #else
622*593dc095SDavid du Colombier # ifdef HAS_vsnprintf_void
623*593dc095SDavid du Colombier (void)vsnprintf(buf, sizeof(buf), format, va);
624*593dc095SDavid du Colombier va_end(va);
625*593dc095SDavid du Colombier len = strlen(buf);
626*593dc095SDavid du Colombier # else
627*593dc095SDavid du Colombier len = vsnprintf(buf, sizeof(buf), format, va);
628*593dc095SDavid du Colombier va_end(va);
629*593dc095SDavid du Colombier # endif
630*593dc095SDavid du Colombier #endif
631*593dc095SDavid du Colombier if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
632*593dc095SDavid du Colombier return 0;
633*593dc095SDavid du Colombier return gzwrite(file, buf, (unsigned)len);
634*593dc095SDavid du Colombier }
635*593dc095SDavid du Colombier #else /* not ANSI C */
636*593dc095SDavid du Colombier
gzprintf(file,format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)637*593dc095SDavid du Colombier int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
638*593dc095SDavid du Colombier a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
639*593dc095SDavid du Colombier gzFile file;
640*593dc095SDavid du Colombier const char *format;
641*593dc095SDavid du Colombier int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
642*593dc095SDavid du Colombier a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
643*593dc095SDavid du Colombier {
644*593dc095SDavid du Colombier char buf[Z_PRINTF_BUFSIZE];
645*593dc095SDavid du Colombier int len;
646*593dc095SDavid du Colombier
647*593dc095SDavid du Colombier buf[sizeof(buf) - 1] = 0;
648*593dc095SDavid du Colombier #ifdef NO_snprintf
649*593dc095SDavid du Colombier # ifdef HAS_sprintf_void
650*593dc095SDavid du Colombier sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
651*593dc095SDavid du Colombier a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
652*593dc095SDavid du Colombier for (len = 0; len < sizeof(buf); len++)
653*593dc095SDavid du Colombier if (buf[len] == 0) break;
654*593dc095SDavid du Colombier # else
655*593dc095SDavid du Colombier len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
656*593dc095SDavid du Colombier a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
657*593dc095SDavid du Colombier # endif
658*593dc095SDavid du Colombier #else
659*593dc095SDavid du Colombier # ifdef HAS_snprintf_void
660*593dc095SDavid du Colombier snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
661*593dc095SDavid du Colombier a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
662*593dc095SDavid du Colombier len = strlen(buf);
663*593dc095SDavid du Colombier # else
664*593dc095SDavid du Colombier len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
665*593dc095SDavid du Colombier a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
666*593dc095SDavid du Colombier # endif
667*593dc095SDavid du Colombier #endif
668*593dc095SDavid du Colombier if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
669*593dc095SDavid du Colombier return 0;
670*593dc095SDavid du Colombier return gzwrite(file, buf, len);
671*593dc095SDavid du Colombier }
672*593dc095SDavid du Colombier #endif
673*593dc095SDavid du Colombier
674*593dc095SDavid du Colombier /* ===========================================================================
675*593dc095SDavid du Colombier Writes c, converted to an unsigned char, into the compressed file.
676*593dc095SDavid du Colombier gzputc returns the value that was written, or -1 in case of error.
677*593dc095SDavid du Colombier */
gzputc(file,c)678*593dc095SDavid du Colombier int ZEXPORT gzputc(file, c)
679*593dc095SDavid du Colombier gzFile file;
680*593dc095SDavid du Colombier int c;
681*593dc095SDavid du Colombier {
682*593dc095SDavid du Colombier unsigned char cc = (unsigned char) c; /* required for big endian systems */
683*593dc095SDavid du Colombier
684*593dc095SDavid du Colombier return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
685*593dc095SDavid du Colombier }
686*593dc095SDavid du Colombier
687*593dc095SDavid du Colombier
688*593dc095SDavid du Colombier /* ===========================================================================
689*593dc095SDavid du Colombier Writes the given null-terminated string to the compressed file, excluding
690*593dc095SDavid du Colombier the terminating null character.
691*593dc095SDavid du Colombier gzputs returns the number of characters written, or -1 in case of error.
692*593dc095SDavid du Colombier */
gzputs(file,s)693*593dc095SDavid du Colombier int ZEXPORT gzputs(file, s)
694*593dc095SDavid du Colombier gzFile file;
695*593dc095SDavid du Colombier const char *s;
696*593dc095SDavid du Colombier {
697*593dc095SDavid du Colombier return gzwrite(file, (char*)s, (unsigned)strlen(s));
698*593dc095SDavid du Colombier }
699*593dc095SDavid du Colombier
700*593dc095SDavid du Colombier
7017dd7cddfSDavid du Colombier /* ===========================================================================
7027dd7cddfSDavid du Colombier Flushes all pending output into the compressed file. The parameter
7037dd7cddfSDavid du Colombier flush is as in the deflate() function.
7047dd7cddfSDavid du Colombier */
do_flush(file,flush)705*593dc095SDavid du Colombier local int do_flush (file, flush)
7067dd7cddfSDavid du Colombier gzFile file;
7077dd7cddfSDavid du Colombier int flush;
7087dd7cddfSDavid du Colombier {
7097dd7cddfSDavid du Colombier uInt len;
7107dd7cddfSDavid du Colombier int done = 0;
7117dd7cddfSDavid du Colombier gz_stream *s = (gz_stream*)file;
7127dd7cddfSDavid du Colombier
7137dd7cddfSDavid du Colombier if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
7147dd7cddfSDavid du Colombier
7157dd7cddfSDavid du Colombier s->stream.avail_in = 0; /* should be zero already anyway */
7167dd7cddfSDavid du Colombier
7177dd7cddfSDavid du Colombier for (;;) {
7187dd7cddfSDavid du Colombier len = Z_BUFSIZE - s->stream.avail_out;
7197dd7cddfSDavid du Colombier
7207dd7cddfSDavid du Colombier if (len != 0) {
7217dd7cddfSDavid du Colombier if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
7227dd7cddfSDavid du Colombier s->z_err = Z_ERRNO;
7237dd7cddfSDavid du Colombier return Z_ERRNO;
7247dd7cddfSDavid du Colombier }
7257dd7cddfSDavid du Colombier s->stream.next_out = s->outbuf;
7267dd7cddfSDavid du Colombier s->stream.avail_out = Z_BUFSIZE;
7277dd7cddfSDavid du Colombier }
7287dd7cddfSDavid du Colombier if (done) break;
729*593dc095SDavid du Colombier s->out += s->stream.avail_out;
7307dd7cddfSDavid du Colombier s->z_err = deflate(&(s->stream), flush);
731*593dc095SDavid du Colombier s->out -= s->stream.avail_out;
732*593dc095SDavid du Colombier
733*593dc095SDavid du Colombier /* Ignore the second of two consecutive flushes: */
734*593dc095SDavid du Colombier if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
7357dd7cddfSDavid du Colombier
7367dd7cddfSDavid du Colombier /* deflate has finished flushing only when it hasn't used up
7377dd7cddfSDavid du Colombier * all the available space in the output buffer:
7387dd7cddfSDavid du Colombier */
7397dd7cddfSDavid du Colombier done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
7407dd7cddfSDavid du Colombier
7417dd7cddfSDavid du Colombier if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
7427dd7cddfSDavid du Colombier }
743*593dc095SDavid du Colombier return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
744*593dc095SDavid du Colombier }
745*593dc095SDavid du Colombier
gzflush(file,flush)746*593dc095SDavid du Colombier int ZEXPORT gzflush (file, flush)
747*593dc095SDavid du Colombier gzFile file;
748*593dc095SDavid du Colombier int flush;
749*593dc095SDavid du Colombier {
750*593dc095SDavid du Colombier gz_stream *s = (gz_stream*)file;
751*593dc095SDavid du Colombier int err = do_flush (file, flush);
752*593dc095SDavid du Colombier
753*593dc095SDavid du Colombier if (err) return err;
7547dd7cddfSDavid du Colombier fflush(s->file);
7557dd7cddfSDavid du Colombier return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
7567dd7cddfSDavid du Colombier }
757*593dc095SDavid du Colombier #endif /* NO_GZCOMPRESS */
758*593dc095SDavid du Colombier
759*593dc095SDavid du Colombier /* ===========================================================================
760*593dc095SDavid du Colombier Sets the starting position for the next gzread or gzwrite on the given
761*593dc095SDavid du Colombier compressed file. The offset represents a number of bytes in the
762*593dc095SDavid du Colombier gzseek returns the resulting offset location as measured in bytes from
763*593dc095SDavid du Colombier the beginning of the uncompressed stream, or -1 in case of error.
764*593dc095SDavid du Colombier SEEK_END is not implemented, returns error.
765*593dc095SDavid du Colombier In this version of the library, gzseek can be extremely slow.
766*593dc095SDavid du Colombier */
gzseek(file,offset,whence)767*593dc095SDavid du Colombier z_off_t ZEXPORT gzseek (file, offset, whence)
768*593dc095SDavid du Colombier gzFile file;
769*593dc095SDavid du Colombier z_off_t offset;
770*593dc095SDavid du Colombier int whence;
771*593dc095SDavid du Colombier {
772*593dc095SDavid du Colombier gz_stream *s = (gz_stream*)file;
773*593dc095SDavid du Colombier
774*593dc095SDavid du Colombier if (s == NULL || whence == SEEK_END ||
775*593dc095SDavid du Colombier s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
776*593dc095SDavid du Colombier return -1L;
777*593dc095SDavid du Colombier }
778*593dc095SDavid du Colombier
779*593dc095SDavid du Colombier if (s->mode == 'w') {
780*593dc095SDavid du Colombier #ifdef NO_GZCOMPRESS
781*593dc095SDavid du Colombier return -1L;
782*593dc095SDavid du Colombier #else
783*593dc095SDavid du Colombier if (whence == SEEK_SET) {
784*593dc095SDavid du Colombier offset -= s->in;
785*593dc095SDavid du Colombier }
786*593dc095SDavid du Colombier if (offset < 0) return -1L;
787*593dc095SDavid du Colombier
788*593dc095SDavid du Colombier /* At this point, offset is the number of zero bytes to write. */
789*593dc095SDavid du Colombier if (s->inbuf == Z_NULL) {
790*593dc095SDavid du Colombier s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
791*593dc095SDavid du Colombier if (s->inbuf == Z_NULL) return -1L;
792*593dc095SDavid du Colombier zmemzero(s->inbuf, Z_BUFSIZE);
793*593dc095SDavid du Colombier }
794*593dc095SDavid du Colombier while (offset > 0) {
795*593dc095SDavid du Colombier uInt size = Z_BUFSIZE;
796*593dc095SDavid du Colombier if (offset < Z_BUFSIZE) size = (uInt)offset;
797*593dc095SDavid du Colombier
798*593dc095SDavid du Colombier size = gzwrite(file, s->inbuf, size);
799*593dc095SDavid du Colombier if (size == 0) return -1L;
800*593dc095SDavid du Colombier
801*593dc095SDavid du Colombier offset -= size;
802*593dc095SDavid du Colombier }
803*593dc095SDavid du Colombier return s->in;
804*593dc095SDavid du Colombier #endif
805*593dc095SDavid du Colombier }
806*593dc095SDavid du Colombier /* Rest of function is for reading only */
807*593dc095SDavid du Colombier
808*593dc095SDavid du Colombier /* compute absolute position */
809*593dc095SDavid du Colombier if (whence == SEEK_CUR) {
810*593dc095SDavid du Colombier offset += s->out;
811*593dc095SDavid du Colombier }
812*593dc095SDavid du Colombier if (offset < 0) return -1L;
813*593dc095SDavid du Colombier
814*593dc095SDavid du Colombier if (s->transparent) {
815*593dc095SDavid du Colombier /* map to fseek */
816*593dc095SDavid du Colombier s->back = EOF;
817*593dc095SDavid du Colombier s->stream.avail_in = 0;
818*593dc095SDavid du Colombier s->stream.next_in = s->inbuf;
819*593dc095SDavid du Colombier if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
820*593dc095SDavid du Colombier
821*593dc095SDavid du Colombier s->in = s->out = offset;
822*593dc095SDavid du Colombier return offset;
823*593dc095SDavid du Colombier }
824*593dc095SDavid du Colombier
825*593dc095SDavid du Colombier /* For a negative seek, rewind and use positive seek */
826*593dc095SDavid du Colombier if (offset >= s->out) {
827*593dc095SDavid du Colombier offset -= s->out;
828*593dc095SDavid du Colombier } else if (gzrewind(file) < 0) {
829*593dc095SDavid du Colombier return -1L;
830*593dc095SDavid du Colombier }
831*593dc095SDavid du Colombier /* offset is now the number of bytes to skip. */
832*593dc095SDavid du Colombier
833*593dc095SDavid du Colombier if (offset != 0 && s->outbuf == Z_NULL) {
834*593dc095SDavid du Colombier s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
835*593dc095SDavid du Colombier if (s->outbuf == Z_NULL) return -1L;
836*593dc095SDavid du Colombier }
837*593dc095SDavid du Colombier if (offset && s->back != EOF) {
838*593dc095SDavid du Colombier s->back = EOF;
839*593dc095SDavid du Colombier s->out++;
840*593dc095SDavid du Colombier offset--;
841*593dc095SDavid du Colombier if (s->last) s->z_err = Z_STREAM_END;
842*593dc095SDavid du Colombier }
843*593dc095SDavid du Colombier while (offset > 0) {
844*593dc095SDavid du Colombier int size = Z_BUFSIZE;
845*593dc095SDavid du Colombier if (offset < Z_BUFSIZE) size = (int)offset;
846*593dc095SDavid du Colombier
847*593dc095SDavid du Colombier size = gzread(file, s->outbuf, (uInt)size);
848*593dc095SDavid du Colombier if (size <= 0) return -1L;
849*593dc095SDavid du Colombier offset -= size;
850*593dc095SDavid du Colombier }
851*593dc095SDavid du Colombier return s->out;
852*593dc095SDavid du Colombier }
853*593dc095SDavid du Colombier
854*593dc095SDavid du Colombier /* ===========================================================================
855*593dc095SDavid du Colombier Rewinds input file.
856*593dc095SDavid du Colombier */
gzrewind(file)857*593dc095SDavid du Colombier int ZEXPORT gzrewind (file)
858*593dc095SDavid du Colombier gzFile file;
859*593dc095SDavid du Colombier {
860*593dc095SDavid du Colombier gz_stream *s = (gz_stream*)file;
861*593dc095SDavid du Colombier
862*593dc095SDavid du Colombier if (s == NULL || s->mode != 'r') return -1;
863*593dc095SDavid du Colombier
864*593dc095SDavid du Colombier s->z_err = Z_OK;
865*593dc095SDavid du Colombier s->z_eof = 0;
866*593dc095SDavid du Colombier s->back = EOF;
867*593dc095SDavid du Colombier s->stream.avail_in = 0;
868*593dc095SDavid du Colombier s->stream.next_in = s->inbuf;
869*593dc095SDavid du Colombier s->crc = crc32(0L, Z_NULL, 0);
870*593dc095SDavid du Colombier if (!s->transparent) (void)inflateReset(&s->stream);
871*593dc095SDavid du Colombier s->in = 0;
872*593dc095SDavid du Colombier s->out = 0;
873*593dc095SDavid du Colombier return fseek(s->file, s->start, SEEK_SET);
874*593dc095SDavid du Colombier }
875*593dc095SDavid du Colombier
876*593dc095SDavid du Colombier /* ===========================================================================
877*593dc095SDavid du Colombier Returns the starting position for the next gzread or gzwrite on the
878*593dc095SDavid du Colombier given compressed file. This position represents a number of bytes in the
879*593dc095SDavid du Colombier uncompressed data stream.
880*593dc095SDavid du Colombier */
gztell(file)881*593dc095SDavid du Colombier z_off_t ZEXPORT gztell (file)
882*593dc095SDavid du Colombier gzFile file;
883*593dc095SDavid du Colombier {
884*593dc095SDavid du Colombier return gzseek(file, 0L, SEEK_CUR);
885*593dc095SDavid du Colombier }
886*593dc095SDavid du Colombier
887*593dc095SDavid du Colombier /* ===========================================================================
888*593dc095SDavid du Colombier Returns 1 when EOF has previously been detected reading the given
889*593dc095SDavid du Colombier input stream, otherwise zero.
890*593dc095SDavid du Colombier */
gzeof(file)891*593dc095SDavid du Colombier int ZEXPORT gzeof (file)
892*593dc095SDavid du Colombier gzFile file;
893*593dc095SDavid du Colombier {
894*593dc095SDavid du Colombier gz_stream *s = (gz_stream*)file;
895*593dc095SDavid du Colombier
896*593dc095SDavid du Colombier /* With concatenated compressed files that can have embedded
897*593dc095SDavid du Colombier * crc trailers, z_eof is no longer the only/best indicator of EOF
898*593dc095SDavid du Colombier * on a gz_stream. Handle end-of-stream error explicitly here.
899*593dc095SDavid du Colombier */
900*593dc095SDavid du Colombier if (s == NULL || s->mode != 'r') return 0;
901*593dc095SDavid du Colombier if (s->z_eof) return 1;
902*593dc095SDavid du Colombier return s->z_err == Z_STREAM_END;
903*593dc095SDavid du Colombier }
9047dd7cddfSDavid du Colombier
9057dd7cddfSDavid du Colombier /* ===========================================================================
9067dd7cddfSDavid du Colombier Outputs a long in LSB order to the given file
9077dd7cddfSDavid du Colombier */
putLong(file,x)9087dd7cddfSDavid du Colombier local void putLong (file, x)
9097dd7cddfSDavid du Colombier FILE *file;
9107dd7cddfSDavid du Colombier uLong x;
9117dd7cddfSDavid du Colombier {
9127dd7cddfSDavid du Colombier int n;
9137dd7cddfSDavid du Colombier for (n = 0; n < 4; n++) {
9147dd7cddfSDavid du Colombier fputc((int)(x & 0xff), file);
9157dd7cddfSDavid du Colombier x >>= 8;
9167dd7cddfSDavid du Colombier }
9177dd7cddfSDavid du Colombier }
9187dd7cddfSDavid du Colombier
9197dd7cddfSDavid du Colombier /* ===========================================================================
920*593dc095SDavid du Colombier Reads a long in LSB order from the given gz_stream. Sets z_err in case
921*593dc095SDavid du Colombier of error.
9227dd7cddfSDavid du Colombier */
getLong(s)9237dd7cddfSDavid du Colombier local uLong getLong (s)
9247dd7cddfSDavid du Colombier gz_stream *s;
9257dd7cddfSDavid du Colombier {
9267dd7cddfSDavid du Colombier uLong x = (uLong)get_byte(s);
9277dd7cddfSDavid du Colombier int c;
9287dd7cddfSDavid du Colombier
9297dd7cddfSDavid du Colombier x += ((uLong)get_byte(s))<<8;
9307dd7cddfSDavid du Colombier x += ((uLong)get_byte(s))<<16;
9317dd7cddfSDavid du Colombier c = get_byte(s);
9327dd7cddfSDavid du Colombier if (c == EOF) s->z_err = Z_DATA_ERROR;
9337dd7cddfSDavid du Colombier x += ((uLong)c)<<24;
9347dd7cddfSDavid du Colombier return x;
9357dd7cddfSDavid du Colombier }
9367dd7cddfSDavid du Colombier
9377dd7cddfSDavid du Colombier /* ===========================================================================
9387dd7cddfSDavid du Colombier Flushes all pending output if necessary, closes the compressed file
9397dd7cddfSDavid du Colombier and deallocates all the (de)compression state.
9407dd7cddfSDavid du Colombier */
gzclose(file)941*593dc095SDavid du Colombier int ZEXPORT gzclose (file)
9427dd7cddfSDavid du Colombier gzFile file;
9437dd7cddfSDavid du Colombier {
9447dd7cddfSDavid du Colombier int err;
9457dd7cddfSDavid du Colombier gz_stream *s = (gz_stream*)file;
9467dd7cddfSDavid du Colombier
9477dd7cddfSDavid du Colombier if (s == NULL) return Z_STREAM_ERROR;
9487dd7cddfSDavid du Colombier
9497dd7cddfSDavid du Colombier if (s->mode == 'w') {
950*593dc095SDavid du Colombier #ifdef NO_GZCOMPRESS
951*593dc095SDavid du Colombier return Z_STREAM_ERROR;
952*593dc095SDavid du Colombier #else
953*593dc095SDavid du Colombier err = do_flush (file, Z_FINISH);
954*593dc095SDavid du Colombier if (err != Z_OK) return destroy((gz_stream*)file);
9557dd7cddfSDavid du Colombier
9567dd7cddfSDavid du Colombier putLong (s->file, s->crc);
957*593dc095SDavid du Colombier putLong (s->file, (uLong)(s->in & 0xffffffff));
958*593dc095SDavid du Colombier #endif
9597dd7cddfSDavid du Colombier }
960*593dc095SDavid du Colombier return destroy((gz_stream*)file);
9617dd7cddfSDavid du Colombier }
9627dd7cddfSDavid du Colombier
9637dd7cddfSDavid du Colombier /* ===========================================================================
9647dd7cddfSDavid du Colombier Returns the error message for the last error which occured on the
9657dd7cddfSDavid du Colombier given compressed file. errnum is set to zlib error number. If an
9667dd7cddfSDavid du Colombier error occured in the file system and not in the compression library,
9677dd7cddfSDavid du Colombier errnum is set to Z_ERRNO and the application may consult errno
9687dd7cddfSDavid du Colombier to get the exact error code.
9697dd7cddfSDavid du Colombier */
gzerror(file,errnum)970*593dc095SDavid du Colombier const char * ZEXPORT gzerror (file, errnum)
9717dd7cddfSDavid du Colombier gzFile file;
9727dd7cddfSDavid du Colombier int *errnum;
9737dd7cddfSDavid du Colombier {
9747dd7cddfSDavid du Colombier char *m;
9757dd7cddfSDavid du Colombier gz_stream *s = (gz_stream*)file;
9767dd7cddfSDavid du Colombier
9777dd7cddfSDavid du Colombier if (s == NULL) {
9787dd7cddfSDavid du Colombier *errnum = Z_STREAM_ERROR;
9797dd7cddfSDavid du Colombier return (const char*)ERR_MSG(Z_STREAM_ERROR);
9807dd7cddfSDavid du Colombier }
9817dd7cddfSDavid du Colombier *errnum = s->z_err;
9827dd7cddfSDavid du Colombier if (*errnum == Z_OK) return (const char*)"";
9837dd7cddfSDavid du Colombier
9847dd7cddfSDavid du Colombier m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
9857dd7cddfSDavid du Colombier
9867dd7cddfSDavid du Colombier if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
9877dd7cddfSDavid du Colombier
9887dd7cddfSDavid du Colombier TRYFREE(s->msg);
9897dd7cddfSDavid du Colombier s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
990*593dc095SDavid du Colombier if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
9917dd7cddfSDavid du Colombier strcpy(s->msg, s->path);
9927dd7cddfSDavid du Colombier strcat(s->msg, ": ");
9937dd7cddfSDavid du Colombier strcat(s->msg, m);
9947dd7cddfSDavid du Colombier return (const char*)s->msg;
9957dd7cddfSDavid du Colombier }
996*593dc095SDavid du Colombier
997*593dc095SDavid du Colombier /* ===========================================================================
998*593dc095SDavid du Colombier Clear the error and end-of-file flags, and do the same for the real file.
999*593dc095SDavid du Colombier */
gzclearerr(file)1000*593dc095SDavid du Colombier void ZEXPORT gzclearerr (file)
1001*593dc095SDavid du Colombier gzFile file;
1002*593dc095SDavid du Colombier {
1003*593dc095SDavid du Colombier gz_stream *s = (gz_stream*)file;
1004*593dc095SDavid du Colombier
1005*593dc095SDavid du Colombier if (s == NULL) return;
1006*593dc095SDavid du Colombier if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
1007*593dc095SDavid du Colombier s->z_eof = 0;
1008*593dc095SDavid du Colombier clearerr(s->file);
1009*593dc095SDavid du Colombier }
1010