1*84d9c625SLionel Sambuc /* $NetBSD: gzio.c,v 1.4 2013/11/07 17:26:13 christos Exp $ */
244bedb31SLionel Sambuc
344bedb31SLionel Sambuc /* gzio.c -- IO on .gz files
444bedb31SLionel Sambuc * Copyright (C) 1995-2005 Jean-loup Gailly.
544bedb31SLionel Sambuc * For conditions of distribution and use, see copyright notice in zlib.h
644bedb31SLionel Sambuc *
744bedb31SLionel Sambuc * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
844bedb31SLionel Sambuc */
944bedb31SLionel Sambuc
1044bedb31SLionel Sambuc /* @(#) Id */
1144bedb31SLionel Sambuc
1244bedb31SLionel Sambuc #include <stdio.h>
1344bedb31SLionel Sambuc
1444bedb31SLionel Sambuc #include "zutil.h"
1544bedb31SLionel Sambuc
1644bedb31SLionel Sambuc #ifdef NO_DEFLATE /* for compatibility with old definition */
1744bedb31SLionel Sambuc # define NO_GZCOMPRESS
1844bedb31SLionel Sambuc #endif
1944bedb31SLionel Sambuc
2044bedb31SLionel Sambuc #ifndef NO_DUMMY_DECL
2144bedb31SLionel Sambuc struct internal_state {int dummy;}; /* for buggy compilers */
2244bedb31SLionel Sambuc #endif
2344bedb31SLionel Sambuc
2444bedb31SLionel Sambuc #ifndef Z_BUFSIZE
2544bedb31SLionel Sambuc # ifdef MAXSEG_64K
2644bedb31SLionel Sambuc # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
2744bedb31SLionel Sambuc # else
2844bedb31SLionel Sambuc # define Z_BUFSIZE 16384
2944bedb31SLionel Sambuc # endif
3044bedb31SLionel Sambuc #endif
3144bedb31SLionel Sambuc #ifndef Z_PRINTF_BUFSIZE
3244bedb31SLionel Sambuc # define Z_PRINTF_BUFSIZE 4096
3344bedb31SLionel Sambuc #endif
3444bedb31SLionel Sambuc
3544bedb31SLionel Sambuc #ifdef __MVS__
3644bedb31SLionel Sambuc # pragma map (fdopen , "\174\174FDOPEN")
3744bedb31SLionel Sambuc FILE *fdopen(int, const char *);
3844bedb31SLionel Sambuc #endif
3944bedb31SLionel Sambuc
4044bedb31SLionel Sambuc #ifndef STDC
4144bedb31SLionel Sambuc extern voidp malloc OF((uInt size));
4244bedb31SLionel Sambuc extern void free OF((voidpf ptr));
4344bedb31SLionel Sambuc #endif
4444bedb31SLionel Sambuc
4544bedb31SLionel Sambuc #define ALLOC(size) malloc(size)
4644bedb31SLionel Sambuc #define TRYFREE(p) {if (p) free(p);}
4744bedb31SLionel Sambuc
4844bedb31SLionel Sambuc static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
4944bedb31SLionel Sambuc
5044bedb31SLionel Sambuc /* gzip flag byte */
5144bedb31SLionel Sambuc #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
5244bedb31SLionel Sambuc #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
5344bedb31SLionel Sambuc #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
5444bedb31SLionel Sambuc #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
5544bedb31SLionel Sambuc #define COMMENT 0x10 /* bit 4 set: file comment present */
5644bedb31SLionel Sambuc #define RESERVED 0xE0 /* bits 5..7: reserved */
5744bedb31SLionel Sambuc
5844bedb31SLionel Sambuc typedef struct gz_stream {
5944bedb31SLionel Sambuc z_stream stream;
6044bedb31SLionel Sambuc int z_err; /* error code for last stream operation */
6144bedb31SLionel Sambuc int z_eof; /* set if end of input file */
6244bedb31SLionel Sambuc FILE *file; /* .gz file */
6344bedb31SLionel Sambuc Byte *inbuf; /* input buffer */
6444bedb31SLionel Sambuc Byte *outbuf; /* output buffer */
6544bedb31SLionel Sambuc uLong crc; /* crc32 of uncompressed data */
6644bedb31SLionel Sambuc char *msg; /* error message */
6744bedb31SLionel Sambuc char *path; /* path name for debugging only */
6844bedb31SLionel Sambuc int transparent; /* 1 if input file is not a .gz file */
6944bedb31SLionel Sambuc char mode; /* 'w' or 'r' */
7044bedb31SLionel Sambuc z_off_t start; /* start of compressed data in file (header skipped) */
7144bedb31SLionel Sambuc z_off_t in; /* bytes into deflate or inflate */
7244bedb31SLionel Sambuc z_off_t out; /* bytes out of deflate or inflate */
7344bedb31SLionel Sambuc int back; /* one character push-back */
7444bedb31SLionel Sambuc int last; /* true if push-back is last character */
7544bedb31SLionel Sambuc } gz_stream;
7644bedb31SLionel Sambuc
7744bedb31SLionel Sambuc
7844bedb31SLionel Sambuc local gzFile gz_open OF((const char *path, const char *mode, int fd));
7944bedb31SLionel Sambuc #ifndef NO_GZCOMPRESS
8044bedb31SLionel Sambuc local int do_flush OF((gzFile file, int flush));
8144bedb31SLionel Sambuc #endif
8244bedb31SLionel Sambuc local int get_byte OF((gz_stream *s));
8344bedb31SLionel Sambuc local void check_header OF((gz_stream *s));
8444bedb31SLionel Sambuc local int destroy OF((gz_stream *s));
8544bedb31SLionel Sambuc #ifndef NO_GZCOMPRESS
8644bedb31SLionel Sambuc local void putLong OF((FILE *file, uLong x));
8744bedb31SLionel Sambuc #endif
8844bedb31SLionel Sambuc local uLong getLong OF((gz_stream *s));
8944bedb31SLionel Sambuc
9044bedb31SLionel Sambuc /* ===========================================================================
9144bedb31SLionel Sambuc Opens a gzip (.gz) file for reading or writing. The mode parameter
9244bedb31SLionel Sambuc is as in fopen ("rb" or "wb"). The file is given either by file descriptor
9344bedb31SLionel Sambuc or path name (if fd == -1).
9444bedb31SLionel Sambuc gz_open returns NULL if the file could not be opened or if there was
9544bedb31SLionel Sambuc insufficient memory to allocate the (de)compression state; errno
9644bedb31SLionel Sambuc can be checked to distinguish the two cases (if errno is zero, the
9744bedb31SLionel Sambuc zlib error is Z_MEM_ERROR).
9844bedb31SLionel Sambuc */
gz_open(path,mode,fd)9944bedb31SLionel Sambuc local gzFile gz_open (path, mode, fd)
10044bedb31SLionel Sambuc const char *path;
10144bedb31SLionel Sambuc const char *mode;
10244bedb31SLionel Sambuc int fd;
10344bedb31SLionel Sambuc {
10444bedb31SLionel Sambuc int err;
10544bedb31SLionel Sambuc int level = Z_DEFAULT_COMPRESSION; /* compression level */
10644bedb31SLionel Sambuc int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
10744bedb31SLionel Sambuc const char *p = mode;
10844bedb31SLionel Sambuc gz_stream *s;
10944bedb31SLionel Sambuc char fmode[80]; /* copy of mode, without the compression level */
11044bedb31SLionel Sambuc char *m = fmode;
11144bedb31SLionel Sambuc
11244bedb31SLionel Sambuc if (!path || !mode) return Z_NULL;
11344bedb31SLionel Sambuc
11444bedb31SLionel Sambuc s = (gz_stream *)ALLOC(sizeof(gz_stream));
11544bedb31SLionel Sambuc if (!s) return Z_NULL;
11644bedb31SLionel Sambuc
11744bedb31SLionel Sambuc s->stream.zalloc = (alloc_func)0;
11844bedb31SLionel Sambuc s->stream.zfree = (free_func)0;
11944bedb31SLionel Sambuc s->stream.opaque = (voidpf)0;
12044bedb31SLionel Sambuc s->stream.next_in = s->inbuf = Z_NULL;
12144bedb31SLionel Sambuc s->stream.next_out = s->outbuf = Z_NULL;
12244bedb31SLionel Sambuc s->stream.avail_in = s->stream.avail_out = 0;
12344bedb31SLionel Sambuc s->file = NULL;
12444bedb31SLionel Sambuc s->z_err = Z_OK;
12544bedb31SLionel Sambuc s->z_eof = 0;
12644bedb31SLionel Sambuc s->in = 0;
12744bedb31SLionel Sambuc s->out = 0;
12844bedb31SLionel Sambuc s->back = EOF;
12944bedb31SLionel Sambuc s->crc = crc32(0L, Z_NULL, 0);
13044bedb31SLionel Sambuc s->msg = NULL;
13144bedb31SLionel Sambuc s->transparent = 0;
13244bedb31SLionel Sambuc
13344bedb31SLionel Sambuc s->path = (char*)ALLOC(strlen(path)+1);
13444bedb31SLionel Sambuc if (s->path == NULL) {
13544bedb31SLionel Sambuc return destroy(s), (gzFile)Z_NULL;
13644bedb31SLionel Sambuc }
13744bedb31SLionel Sambuc strcpy(s->path, path); /* do this early for debugging */
13844bedb31SLionel Sambuc
13944bedb31SLionel Sambuc s->mode = '\0';
14044bedb31SLionel Sambuc do {
14144bedb31SLionel Sambuc if (*p == 'r') s->mode = 'r';
14244bedb31SLionel Sambuc if (*p == 'w' || *p == 'a') s->mode = 'w';
14344bedb31SLionel Sambuc if (*p >= '0' && *p <= '9') {
14444bedb31SLionel Sambuc level = *p - '0';
14544bedb31SLionel Sambuc } else if (*p == 'f') {
14644bedb31SLionel Sambuc strategy = Z_FILTERED;
14744bedb31SLionel Sambuc } else if (*p == 'h') {
14844bedb31SLionel Sambuc strategy = Z_HUFFMAN_ONLY;
14944bedb31SLionel Sambuc } else if (*p == 'R') {
15044bedb31SLionel Sambuc strategy = Z_RLE;
15144bedb31SLionel Sambuc } else {
15244bedb31SLionel Sambuc *m++ = *p; /* copy the mode */
15344bedb31SLionel Sambuc }
15444bedb31SLionel Sambuc } while (*p++ && m != fmode + sizeof(fmode));
15544bedb31SLionel Sambuc if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
15644bedb31SLionel Sambuc
15744bedb31SLionel Sambuc if (s->mode == 'w') {
15844bedb31SLionel Sambuc #ifdef NO_GZCOMPRESS
15944bedb31SLionel Sambuc err = Z_STREAM_ERROR;
160*84d9c625SLionel Sambuc __USE(level);
161*84d9c625SLionel Sambuc __USE(strategy);
16244bedb31SLionel Sambuc #else
16344bedb31SLionel Sambuc err = deflateInit2(&(s->stream), level,
16444bedb31SLionel Sambuc Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
16544bedb31SLionel Sambuc /* windowBits is passed < 0 to suppress zlib header */
16644bedb31SLionel Sambuc
16744bedb31SLionel Sambuc s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
16844bedb31SLionel Sambuc #endif
16944bedb31SLionel Sambuc if (err != Z_OK || s->outbuf == Z_NULL) {
17044bedb31SLionel Sambuc return destroy(s), (gzFile)Z_NULL;
17144bedb31SLionel Sambuc }
17244bedb31SLionel Sambuc } else {
17344bedb31SLionel Sambuc s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
17444bedb31SLionel Sambuc
17544bedb31SLionel Sambuc err = inflateInit2(&(s->stream), -MAX_WBITS);
17644bedb31SLionel Sambuc /* windowBits is passed < 0 to tell that there is no zlib header.
17744bedb31SLionel Sambuc * Note that in this case inflate *requires* an extra "dummy" byte
17844bedb31SLionel Sambuc * after the compressed stream in order to complete decompression and
17944bedb31SLionel Sambuc * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
18044bedb31SLionel Sambuc * present after the compressed stream.
18144bedb31SLionel Sambuc */
18244bedb31SLionel Sambuc if (err != Z_OK || s->inbuf == Z_NULL) {
18344bedb31SLionel Sambuc return destroy(s), (gzFile)Z_NULL;
18444bedb31SLionel Sambuc }
18544bedb31SLionel Sambuc }
18644bedb31SLionel Sambuc s->stream.avail_out = Z_BUFSIZE;
18744bedb31SLionel Sambuc
18844bedb31SLionel Sambuc errno = 0;
18944bedb31SLionel Sambuc s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
19044bedb31SLionel Sambuc
19144bedb31SLionel Sambuc if (s->file == NULL) {
19244bedb31SLionel Sambuc return destroy(s), (gzFile)Z_NULL;
19344bedb31SLionel Sambuc }
19444bedb31SLionel Sambuc if (s->mode == 'w') {
19544bedb31SLionel Sambuc /* Write a very simple .gz header:
19644bedb31SLionel Sambuc */
19744bedb31SLionel Sambuc fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
19844bedb31SLionel Sambuc Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
19944bedb31SLionel Sambuc s->start = 10L;
20044bedb31SLionel Sambuc /* We use 10L instead of ftell(s->file) to because ftell causes an
20144bedb31SLionel Sambuc * fflush on some systems. This version of the library doesn't use
20244bedb31SLionel Sambuc * start anyway in write mode, so this initialization is not
20344bedb31SLionel Sambuc * necessary.
20444bedb31SLionel Sambuc */
20544bedb31SLionel Sambuc } else {
20644bedb31SLionel Sambuc check_header(s); /* skip the .gz header */
20744bedb31SLionel Sambuc s->start = ftell(s->file) - s->stream.avail_in;
20844bedb31SLionel Sambuc }
20944bedb31SLionel Sambuc
21044bedb31SLionel Sambuc return (gzFile)s;
21144bedb31SLionel Sambuc }
21244bedb31SLionel Sambuc
21344bedb31SLionel Sambuc /* ===========================================================================
21444bedb31SLionel Sambuc Opens a gzip (.gz) file for reading or writing.
21544bedb31SLionel Sambuc */
gzopen(path,mode)21644bedb31SLionel Sambuc gzFile ZEXPORT gzopen (path, mode)
21744bedb31SLionel Sambuc const char *path;
21844bedb31SLionel Sambuc const char *mode;
21944bedb31SLionel Sambuc {
22044bedb31SLionel Sambuc return gz_open (path, mode, -1);
22144bedb31SLionel Sambuc }
22244bedb31SLionel Sambuc
22344bedb31SLionel Sambuc /* ===========================================================================
22444bedb31SLionel Sambuc Associate a gzFile with the file descriptor fd. fd is not dup'ed here
22544bedb31SLionel Sambuc to mimic the behavio(u)r of fdopen.
22644bedb31SLionel Sambuc */
gzdopen(fd,mode)22744bedb31SLionel Sambuc gzFile ZEXPORT gzdopen (fd, mode)
22844bedb31SLionel Sambuc int fd;
22944bedb31SLionel Sambuc const char *mode;
23044bedb31SLionel Sambuc {
23144bedb31SLionel Sambuc char name[46]; /* allow for up to 128-bit integers */
23244bedb31SLionel Sambuc
23344bedb31SLionel Sambuc if (fd < 0) return (gzFile)Z_NULL;
23444bedb31SLionel Sambuc sprintf(name, "<fd:%d>", fd); /* for debugging */
23544bedb31SLionel Sambuc
23644bedb31SLionel Sambuc return gz_open (name, mode, fd);
23744bedb31SLionel Sambuc }
23844bedb31SLionel Sambuc
23944bedb31SLionel Sambuc /* ===========================================================================
24044bedb31SLionel Sambuc * Update the compression level and strategy
24144bedb31SLionel Sambuc */
gzsetparams(file,level,strategy)24244bedb31SLionel Sambuc int ZEXPORT gzsetparams (file, level, strategy)
24344bedb31SLionel Sambuc gzFile file;
24444bedb31SLionel Sambuc int level;
24544bedb31SLionel Sambuc int strategy;
24644bedb31SLionel Sambuc {
24744bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
24844bedb31SLionel Sambuc
24944bedb31SLionel Sambuc if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
25044bedb31SLionel Sambuc
25144bedb31SLionel Sambuc /* Make room to allow flushing */
25244bedb31SLionel Sambuc if (s->stream.avail_out == 0) {
25344bedb31SLionel Sambuc
25444bedb31SLionel Sambuc s->stream.next_out = s->outbuf;
25544bedb31SLionel Sambuc if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
25644bedb31SLionel Sambuc s->z_err = Z_ERRNO;
25744bedb31SLionel Sambuc }
25844bedb31SLionel Sambuc s->stream.avail_out = Z_BUFSIZE;
25944bedb31SLionel Sambuc }
26044bedb31SLionel Sambuc
26144bedb31SLionel Sambuc return deflateParams (&(s->stream), level, strategy);
26244bedb31SLionel Sambuc }
26344bedb31SLionel Sambuc
26444bedb31SLionel Sambuc /* ===========================================================================
26544bedb31SLionel Sambuc Read a byte from a gz_stream; update next_in and avail_in. Return EOF
26644bedb31SLionel Sambuc for end of file.
26744bedb31SLionel Sambuc IN assertion: the stream s has been sucessfully opened for reading.
26844bedb31SLionel Sambuc */
get_byte(s)26944bedb31SLionel Sambuc local int get_byte(s)
27044bedb31SLionel Sambuc gz_stream *s;
27144bedb31SLionel Sambuc {
27244bedb31SLionel Sambuc if (s->z_eof) return EOF;
27344bedb31SLionel Sambuc if (s->stream.avail_in == 0) {
27444bedb31SLionel Sambuc errno = 0;
27544bedb31SLionel Sambuc s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
27644bedb31SLionel Sambuc if (s->stream.avail_in == 0) {
27744bedb31SLionel Sambuc s->z_eof = 1;
27844bedb31SLionel Sambuc if (ferror(s->file)) s->z_err = Z_ERRNO;
27944bedb31SLionel Sambuc return EOF;
28044bedb31SLionel Sambuc }
28144bedb31SLionel Sambuc s->stream.next_in = s->inbuf;
28244bedb31SLionel Sambuc }
28344bedb31SLionel Sambuc s->stream.avail_in--;
28444bedb31SLionel Sambuc return *(s->stream.next_in)++;
28544bedb31SLionel Sambuc }
28644bedb31SLionel Sambuc
28744bedb31SLionel Sambuc /* ===========================================================================
28844bedb31SLionel Sambuc Check the gzip header of a gz_stream opened for reading. Set the stream
28944bedb31SLionel Sambuc mode to transparent if the gzip magic header is not present; set s->err
29044bedb31SLionel Sambuc to Z_DATA_ERROR if the magic header is present but the rest of the header
29144bedb31SLionel Sambuc is incorrect.
29244bedb31SLionel Sambuc IN assertion: the stream s has already been created sucessfully;
29344bedb31SLionel Sambuc s->stream.avail_in is zero for the first time, but may be non-zero
29444bedb31SLionel Sambuc for concatenated .gz files.
29544bedb31SLionel Sambuc */
check_header(s)29644bedb31SLionel Sambuc local void check_header(s)
29744bedb31SLionel Sambuc gz_stream *s;
29844bedb31SLionel Sambuc {
29944bedb31SLionel Sambuc int method; /* method byte */
30044bedb31SLionel Sambuc int flags; /* flags byte */
30144bedb31SLionel Sambuc uInt len;
30244bedb31SLionel Sambuc int c;
30344bedb31SLionel Sambuc
30444bedb31SLionel Sambuc /* Assure two bytes in the buffer so we can peek ahead -- handle case
30544bedb31SLionel Sambuc where first byte of header is at the end of the buffer after the last
30644bedb31SLionel Sambuc gzip segment */
30744bedb31SLionel Sambuc len = s->stream.avail_in;
30844bedb31SLionel Sambuc if (len < 2) {
30944bedb31SLionel Sambuc if (len) s->inbuf[0] = s->stream.next_in[0];
31044bedb31SLionel Sambuc errno = 0;
31144bedb31SLionel Sambuc len = (uInt)fread(s->inbuf + len, 1, (size_t)(Z_BUFSIZE >> len),
31244bedb31SLionel Sambuc s->file);
31344bedb31SLionel Sambuc if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
31444bedb31SLionel Sambuc s->stream.avail_in += len;
31544bedb31SLionel Sambuc s->stream.next_in = s->inbuf;
31644bedb31SLionel Sambuc if (s->stream.avail_in < 2) {
31744bedb31SLionel Sambuc s->transparent = s->stream.avail_in;
31844bedb31SLionel Sambuc return;
31944bedb31SLionel Sambuc }
32044bedb31SLionel Sambuc }
32144bedb31SLionel Sambuc
32244bedb31SLionel Sambuc /* Peek ahead to check the gzip magic header */
32344bedb31SLionel Sambuc if (s->stream.next_in[0] != gz_magic[0] ||
32444bedb31SLionel Sambuc s->stream.next_in[1] != gz_magic[1]) {
32544bedb31SLionel Sambuc s->transparent = 1;
32644bedb31SLionel Sambuc return;
32744bedb31SLionel Sambuc }
32844bedb31SLionel Sambuc s->stream.avail_in -= 2;
32944bedb31SLionel Sambuc s->stream.next_in += 2;
33044bedb31SLionel Sambuc
33144bedb31SLionel Sambuc /* Check the rest of the gzip header */
33244bedb31SLionel Sambuc method = get_byte(s);
33344bedb31SLionel Sambuc flags = get_byte(s);
33444bedb31SLionel Sambuc if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
33544bedb31SLionel Sambuc s->z_err = Z_DATA_ERROR;
33644bedb31SLionel Sambuc return;
33744bedb31SLionel Sambuc }
33844bedb31SLionel Sambuc
33944bedb31SLionel Sambuc /* Discard time, xflags and OS code: */
34044bedb31SLionel Sambuc for (len = 0; len < 6; len++) (void)get_byte(s);
34144bedb31SLionel Sambuc
34244bedb31SLionel Sambuc if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
34344bedb31SLionel Sambuc len = (uInt)get_byte(s);
34444bedb31SLionel Sambuc len += ((uInt)get_byte(s))<<8;
34544bedb31SLionel Sambuc /* len is garbage if EOF but the loop below will quit anyway */
34644bedb31SLionel Sambuc while (len-- != 0 && get_byte(s) != EOF) ;
34744bedb31SLionel Sambuc }
34844bedb31SLionel Sambuc if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
34944bedb31SLionel Sambuc while ((c = get_byte(s)) != 0 && c != EOF) ;
35044bedb31SLionel Sambuc }
35144bedb31SLionel Sambuc if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
35244bedb31SLionel Sambuc while ((c = get_byte(s)) != 0 && c != EOF) ;
35344bedb31SLionel Sambuc }
35444bedb31SLionel Sambuc if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
35544bedb31SLionel Sambuc for (len = 0; len < 2; len++) (void)get_byte(s);
35644bedb31SLionel Sambuc }
35744bedb31SLionel Sambuc s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
35844bedb31SLionel Sambuc }
35944bedb31SLionel Sambuc
36044bedb31SLionel Sambuc /* ===========================================================================
36144bedb31SLionel Sambuc * Cleanup then free the given gz_stream. Return a zlib error code.
36244bedb31SLionel Sambuc Try freeing in the reverse order of allocations.
36344bedb31SLionel Sambuc */
destroy(s)36444bedb31SLionel Sambuc local int destroy (s)
36544bedb31SLionel Sambuc gz_stream *s;
36644bedb31SLionel Sambuc {
36744bedb31SLionel Sambuc int err = Z_OK;
36844bedb31SLionel Sambuc
36944bedb31SLionel Sambuc if (!s) return Z_STREAM_ERROR;
37044bedb31SLionel Sambuc
37144bedb31SLionel Sambuc TRYFREE(s->msg);
37244bedb31SLionel Sambuc
37344bedb31SLionel Sambuc if (s->stream.state != NULL) {
37444bedb31SLionel Sambuc if (s->mode == 'w') {
37544bedb31SLionel Sambuc #ifdef NO_GZCOMPRESS
37644bedb31SLionel Sambuc err = Z_STREAM_ERROR;
37744bedb31SLionel Sambuc #else
37844bedb31SLionel Sambuc err = deflateEnd(&(s->stream));
37944bedb31SLionel Sambuc #endif
38044bedb31SLionel Sambuc } else if (s->mode == 'r') {
38144bedb31SLionel Sambuc err = inflateEnd(&(s->stream));
38244bedb31SLionel Sambuc }
38344bedb31SLionel Sambuc }
38444bedb31SLionel Sambuc if (s->file != NULL && fclose(s->file)) {
38544bedb31SLionel Sambuc #ifdef ESPIPE
38644bedb31SLionel Sambuc if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
38744bedb31SLionel Sambuc #endif
38844bedb31SLionel Sambuc err = Z_ERRNO;
38944bedb31SLionel Sambuc }
39044bedb31SLionel Sambuc if (s->z_err < 0) err = s->z_err;
39144bedb31SLionel Sambuc
39244bedb31SLionel Sambuc TRYFREE(s->inbuf);
39344bedb31SLionel Sambuc TRYFREE(s->outbuf);
39444bedb31SLionel Sambuc TRYFREE(s->path);
39544bedb31SLionel Sambuc TRYFREE(s);
39644bedb31SLionel Sambuc return err;
39744bedb31SLionel Sambuc }
39844bedb31SLionel Sambuc
39944bedb31SLionel Sambuc /* ===========================================================================
40044bedb31SLionel Sambuc Reads the given number of uncompressed bytes from the compressed file.
40144bedb31SLionel Sambuc gzread returns the number of bytes actually read (0 for end of file).
40244bedb31SLionel Sambuc */
gzread(file,buf,len)40344bedb31SLionel Sambuc int ZEXPORT gzread (file, buf, len)
40444bedb31SLionel Sambuc gzFile file;
40544bedb31SLionel Sambuc voidp buf;
40644bedb31SLionel Sambuc unsigned len;
40744bedb31SLionel Sambuc {
40844bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
40944bedb31SLionel Sambuc Bytef *start = (Bytef*)buf; /* starting point for crc computation */
41044bedb31SLionel Sambuc Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
41144bedb31SLionel Sambuc
41244bedb31SLionel Sambuc if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
41344bedb31SLionel Sambuc
41444bedb31SLionel Sambuc if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
41544bedb31SLionel Sambuc if (s->z_err == Z_STREAM_END) return 0; /* EOF */
41644bedb31SLionel Sambuc
41744bedb31SLionel Sambuc next_out = (Byte*)buf;
41844bedb31SLionel Sambuc s->stream.next_out = (Bytef*)buf;
41944bedb31SLionel Sambuc s->stream.avail_out = len;
42044bedb31SLionel Sambuc
42144bedb31SLionel Sambuc if (s->stream.avail_out && s->back != EOF) {
42244bedb31SLionel Sambuc *next_out++ = s->back;
42344bedb31SLionel Sambuc s->stream.next_out++;
42444bedb31SLionel Sambuc s->stream.avail_out--;
42544bedb31SLionel Sambuc s->back = EOF;
42644bedb31SLionel Sambuc s->out++;
42744bedb31SLionel Sambuc start++;
42844bedb31SLionel Sambuc if (s->last) {
42944bedb31SLionel Sambuc s->z_err = Z_STREAM_END;
43044bedb31SLionel Sambuc return 1;
43144bedb31SLionel Sambuc }
43244bedb31SLionel Sambuc }
43344bedb31SLionel Sambuc
43444bedb31SLionel Sambuc while (s->stream.avail_out != 0) {
43544bedb31SLionel Sambuc
43644bedb31SLionel Sambuc if (s->transparent) {
43744bedb31SLionel Sambuc /* Copy first the lookahead bytes: */
43844bedb31SLionel Sambuc uInt n = s->stream.avail_in;
43944bedb31SLionel Sambuc if (n > s->stream.avail_out) n = s->stream.avail_out;
44044bedb31SLionel Sambuc if (n > 0) {
44144bedb31SLionel Sambuc zmemcpy(s->stream.next_out, s->stream.next_in, n);
44244bedb31SLionel Sambuc next_out += n;
44344bedb31SLionel Sambuc s->stream.next_out = next_out;
44444bedb31SLionel Sambuc s->stream.next_in += n;
44544bedb31SLionel Sambuc s->stream.avail_out -= n;
44644bedb31SLionel Sambuc s->stream.avail_in -= n;
44744bedb31SLionel Sambuc }
44844bedb31SLionel Sambuc if (s->stream.avail_out > 0) {
44944bedb31SLionel Sambuc s->stream.avail_out -=
45044bedb31SLionel Sambuc (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
45144bedb31SLionel Sambuc }
45244bedb31SLionel Sambuc len -= s->stream.avail_out;
45344bedb31SLionel Sambuc s->in += len;
45444bedb31SLionel Sambuc s->out += len;
45544bedb31SLionel Sambuc if (len == 0) s->z_eof = 1;
45644bedb31SLionel Sambuc return (int)len;
45744bedb31SLionel Sambuc }
45844bedb31SLionel Sambuc if (s->stream.avail_in == 0 && !s->z_eof) {
45944bedb31SLionel Sambuc
46044bedb31SLionel Sambuc errno = 0;
46144bedb31SLionel Sambuc s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
46244bedb31SLionel Sambuc if (s->stream.avail_in == 0) {
46344bedb31SLionel Sambuc s->z_eof = 1;
46444bedb31SLionel Sambuc if (ferror(s->file)) {
46544bedb31SLionel Sambuc s->z_err = Z_ERRNO;
46644bedb31SLionel Sambuc break;
46744bedb31SLionel Sambuc }
46844bedb31SLionel Sambuc }
46944bedb31SLionel Sambuc s->stream.next_in = s->inbuf;
47044bedb31SLionel Sambuc }
47144bedb31SLionel Sambuc s->in += s->stream.avail_in;
47244bedb31SLionel Sambuc s->out += s->stream.avail_out;
47344bedb31SLionel Sambuc s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
47444bedb31SLionel Sambuc s->in -= s->stream.avail_in;
47544bedb31SLionel Sambuc s->out -= s->stream.avail_out;
47644bedb31SLionel Sambuc
47744bedb31SLionel Sambuc if (s->z_err == Z_STREAM_END) {
47844bedb31SLionel Sambuc /* Check CRC and original size */
47944bedb31SLionel Sambuc s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
48044bedb31SLionel Sambuc start = s->stream.next_out;
48144bedb31SLionel Sambuc
48244bedb31SLionel Sambuc if (getLong(s) != s->crc) {
48344bedb31SLionel Sambuc s->z_err = Z_DATA_ERROR;
48444bedb31SLionel Sambuc } else {
48544bedb31SLionel Sambuc (void)getLong(s);
48644bedb31SLionel Sambuc /* The uncompressed length returned by above getlong() may be
48744bedb31SLionel Sambuc * different from s->out in case of concatenated .gz files.
48844bedb31SLionel Sambuc * Check for such files:
48944bedb31SLionel Sambuc */
49044bedb31SLionel Sambuc check_header(s);
49144bedb31SLionel Sambuc if (s->z_err == Z_OK) {
49244bedb31SLionel Sambuc inflateReset(&(s->stream));
49344bedb31SLionel Sambuc s->crc = crc32(0L, Z_NULL, 0);
49444bedb31SLionel Sambuc }
49544bedb31SLionel Sambuc }
49644bedb31SLionel Sambuc }
49744bedb31SLionel Sambuc if (s->z_err != Z_OK || s->z_eof) break;
49844bedb31SLionel Sambuc }
49944bedb31SLionel Sambuc s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
50044bedb31SLionel Sambuc
50144bedb31SLionel Sambuc if (len == s->stream.avail_out &&
50244bedb31SLionel Sambuc (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
50344bedb31SLionel Sambuc return -1;
50444bedb31SLionel Sambuc return (int)(len - s->stream.avail_out);
50544bedb31SLionel Sambuc }
50644bedb31SLionel Sambuc
50744bedb31SLionel Sambuc
50844bedb31SLionel Sambuc /* ===========================================================================
50944bedb31SLionel Sambuc Reads one byte from the compressed file. gzgetc returns this byte
51044bedb31SLionel Sambuc or -1 in case of end of file or error.
51144bedb31SLionel Sambuc */
gzgetc(file)51244bedb31SLionel Sambuc int ZEXPORT gzgetc(file)
51344bedb31SLionel Sambuc gzFile file;
51444bedb31SLionel Sambuc {
51544bedb31SLionel Sambuc unsigned char c;
51644bedb31SLionel Sambuc
51744bedb31SLionel Sambuc return gzread(file, &c, 1) == 1 ? c : -1;
51844bedb31SLionel Sambuc }
51944bedb31SLionel Sambuc
52044bedb31SLionel Sambuc
52144bedb31SLionel Sambuc /* ===========================================================================
52244bedb31SLionel Sambuc Push one byte back onto the stream.
52344bedb31SLionel Sambuc */
gzungetc(c,file)52444bedb31SLionel Sambuc int ZEXPORT gzungetc(c, file)
52544bedb31SLionel Sambuc int c;
52644bedb31SLionel Sambuc gzFile file;
52744bedb31SLionel Sambuc {
52844bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
52944bedb31SLionel Sambuc
53044bedb31SLionel Sambuc if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
53144bedb31SLionel Sambuc s->back = c;
53244bedb31SLionel Sambuc s->out--;
53344bedb31SLionel Sambuc s->last = (s->z_err == Z_STREAM_END);
53444bedb31SLionel Sambuc if (s->last) s->z_err = Z_OK;
53544bedb31SLionel Sambuc s->z_eof = 0;
53644bedb31SLionel Sambuc return c;
53744bedb31SLionel Sambuc }
53844bedb31SLionel Sambuc
53944bedb31SLionel Sambuc
54044bedb31SLionel Sambuc /* ===========================================================================
54144bedb31SLionel Sambuc Reads bytes from the compressed file until len-1 characters are
54244bedb31SLionel Sambuc read, or a newline character is read and transferred to buf, or an
54344bedb31SLionel Sambuc end-of-file condition is encountered. The string is then terminated
54444bedb31SLionel Sambuc with a null character.
54544bedb31SLionel Sambuc gzgets returns buf, or Z_NULL in case of error.
54644bedb31SLionel Sambuc
54744bedb31SLionel Sambuc The current implementation is not optimized at all.
54844bedb31SLionel Sambuc */
gzgets(file,buf,len)54944bedb31SLionel Sambuc char * ZEXPORT gzgets(file, buf, len)
55044bedb31SLionel Sambuc gzFile file;
55144bedb31SLionel Sambuc char *buf;
55244bedb31SLionel Sambuc int len;
55344bedb31SLionel Sambuc {
55444bedb31SLionel Sambuc char *b = buf;
55544bedb31SLionel Sambuc if (buf == Z_NULL || len <= 0) return Z_NULL;
55644bedb31SLionel Sambuc
55744bedb31SLionel Sambuc while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
55844bedb31SLionel Sambuc *buf = '\0';
55944bedb31SLionel Sambuc return b == buf && len > 0 ? Z_NULL : b;
56044bedb31SLionel Sambuc }
56144bedb31SLionel Sambuc
56244bedb31SLionel Sambuc
56344bedb31SLionel Sambuc #ifndef NO_GZCOMPRESS
56444bedb31SLionel Sambuc /* ===========================================================================
56544bedb31SLionel Sambuc Writes the given number of uncompressed bytes into the compressed file.
56644bedb31SLionel Sambuc gzwrite returns the number of bytes actually written (0 in case of error).
56744bedb31SLionel Sambuc */
gzwrite(file,buf,len)56844bedb31SLionel Sambuc int ZEXPORT gzwrite (file, buf, len)
56944bedb31SLionel Sambuc gzFile file;
57044bedb31SLionel Sambuc voidpc buf;
57144bedb31SLionel Sambuc unsigned len;
57244bedb31SLionel Sambuc {
57344bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
57444bedb31SLionel Sambuc
57544bedb31SLionel Sambuc if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
57644bedb31SLionel Sambuc
57744bedb31SLionel Sambuc s->stream.next_in = __UNCONST(buf);
57844bedb31SLionel Sambuc s->stream.avail_in = len;
57944bedb31SLionel Sambuc
58044bedb31SLionel Sambuc while (s->stream.avail_in != 0) {
58144bedb31SLionel Sambuc
58244bedb31SLionel Sambuc if (s->stream.avail_out == 0) {
58344bedb31SLionel Sambuc
58444bedb31SLionel Sambuc s->stream.next_out = s->outbuf;
58544bedb31SLionel Sambuc if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
58644bedb31SLionel Sambuc s->z_err = Z_ERRNO;
58744bedb31SLionel Sambuc break;
58844bedb31SLionel Sambuc }
58944bedb31SLionel Sambuc s->stream.avail_out = Z_BUFSIZE;
59044bedb31SLionel Sambuc }
59144bedb31SLionel Sambuc s->in += s->stream.avail_in;
59244bedb31SLionel Sambuc s->out += s->stream.avail_out;
59344bedb31SLionel Sambuc s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
59444bedb31SLionel Sambuc s->in -= s->stream.avail_in;
59544bedb31SLionel Sambuc s->out -= s->stream.avail_out;
59644bedb31SLionel Sambuc if (s->z_err != Z_OK) break;
59744bedb31SLionel Sambuc }
59844bedb31SLionel Sambuc s->crc = crc32(s->crc, (const Bytef *)buf, len);
59944bedb31SLionel Sambuc
60044bedb31SLionel Sambuc return (int)(len - s->stream.avail_in);
60144bedb31SLionel Sambuc }
60244bedb31SLionel Sambuc
60344bedb31SLionel Sambuc
60444bedb31SLionel Sambuc /* ===========================================================================
60544bedb31SLionel Sambuc Converts, formats, and writes the args to the compressed file under
60644bedb31SLionel Sambuc control of the format string, as in fprintf. gzprintf returns the number of
60744bedb31SLionel Sambuc uncompressed bytes actually written (0 in case of error).
60844bedb31SLionel Sambuc */
60944bedb31SLionel Sambuc #ifdef STDC
61044bedb31SLionel Sambuc #include <stdarg.h>
61144bedb31SLionel Sambuc
gzprintf(gzFile file,const char * format,...)61244bedb31SLionel Sambuc int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
61344bedb31SLionel Sambuc {
61444bedb31SLionel Sambuc char buf[Z_PRINTF_BUFSIZE];
61544bedb31SLionel Sambuc va_list va;
61644bedb31SLionel Sambuc int len;
61744bedb31SLionel Sambuc
61844bedb31SLionel Sambuc buf[sizeof(buf) - 1] = 0;
61944bedb31SLionel Sambuc va_start(va, format);
62044bedb31SLionel Sambuc #ifdef NO_vsnprintf
62144bedb31SLionel Sambuc # ifdef HAS_vsprintf_void
62244bedb31SLionel Sambuc (void)vsprintf(buf, format, va);
62344bedb31SLionel Sambuc va_end(va);
62444bedb31SLionel Sambuc for (len = 0; len < sizeof(buf); len++)
62544bedb31SLionel Sambuc if (buf[len] == 0) break;
62644bedb31SLionel Sambuc # else
62744bedb31SLionel Sambuc len = vsprintf(buf, format, va);
62844bedb31SLionel Sambuc va_end(va);
62944bedb31SLionel Sambuc # endif
63044bedb31SLionel Sambuc #else
63144bedb31SLionel Sambuc # ifdef HAS_vsnprintf_void
63244bedb31SLionel Sambuc (void)vsnprintf(buf, sizeof(buf), format, va);
63344bedb31SLionel Sambuc va_end(va);
63444bedb31SLionel Sambuc len = strlen(buf);
63544bedb31SLionel Sambuc # else
63644bedb31SLionel Sambuc len = vsnprintf(buf, sizeof(buf), format, va);
63744bedb31SLionel Sambuc va_end(va);
63844bedb31SLionel Sambuc # endif
63944bedb31SLionel Sambuc #endif
64044bedb31SLionel Sambuc if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
64144bedb31SLionel Sambuc return 0;
64244bedb31SLionel Sambuc return gzwrite(file, buf, (unsigned)len);
64344bedb31SLionel Sambuc }
64444bedb31SLionel Sambuc #else /* not ANSI C */
64544bedb31SLionel Sambuc
gzprintf(file,format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)64644bedb31SLionel Sambuc int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
64744bedb31SLionel Sambuc a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
64844bedb31SLionel Sambuc gzFile file;
64944bedb31SLionel Sambuc const char *format;
65044bedb31SLionel Sambuc int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
65144bedb31SLionel Sambuc a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
65244bedb31SLionel Sambuc {
65344bedb31SLionel Sambuc char buf[Z_PRINTF_BUFSIZE];
65444bedb31SLionel Sambuc int len;
65544bedb31SLionel Sambuc
65644bedb31SLionel Sambuc buf[sizeof(buf) - 1] = 0;
65744bedb31SLionel Sambuc #ifdef NO_snprintf
65844bedb31SLionel Sambuc # ifdef HAS_sprintf_void
65944bedb31SLionel Sambuc sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
66044bedb31SLionel Sambuc a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
66144bedb31SLionel Sambuc for (len = 0; len < sizeof(buf); len++)
66244bedb31SLionel Sambuc if (buf[len] == 0) break;
66344bedb31SLionel Sambuc # else
66444bedb31SLionel Sambuc len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
66544bedb31SLionel Sambuc a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
66644bedb31SLionel Sambuc # endif
66744bedb31SLionel Sambuc #else
66844bedb31SLionel Sambuc # ifdef HAS_snprintf_void
66944bedb31SLionel Sambuc snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
67044bedb31SLionel Sambuc a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
67144bedb31SLionel Sambuc len = strlen(buf);
67244bedb31SLionel Sambuc # else
67344bedb31SLionel Sambuc len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
67444bedb31SLionel Sambuc a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
67544bedb31SLionel Sambuc # endif
67644bedb31SLionel Sambuc #endif
67744bedb31SLionel Sambuc if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
67844bedb31SLionel Sambuc return 0;
67944bedb31SLionel Sambuc return gzwrite(file, buf, len);
68044bedb31SLionel Sambuc }
68144bedb31SLionel Sambuc #endif
68244bedb31SLionel Sambuc
68344bedb31SLionel Sambuc /* ===========================================================================
68444bedb31SLionel Sambuc Writes c, converted to an unsigned char, into the compressed file.
68544bedb31SLionel Sambuc gzputc returns the value that was written, or -1 in case of error.
68644bedb31SLionel Sambuc */
gzputc(file,c)68744bedb31SLionel Sambuc int ZEXPORT gzputc(file, c)
68844bedb31SLionel Sambuc gzFile file;
68944bedb31SLionel Sambuc int c;
69044bedb31SLionel Sambuc {
69144bedb31SLionel Sambuc unsigned char cc = (unsigned char) c; /* required for big endian systems */
69244bedb31SLionel Sambuc
69344bedb31SLionel Sambuc return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
69444bedb31SLionel Sambuc }
69544bedb31SLionel Sambuc
69644bedb31SLionel Sambuc
69744bedb31SLionel Sambuc /* ===========================================================================
69844bedb31SLionel Sambuc Writes the given null-terminated string to the compressed file, excluding
69944bedb31SLionel Sambuc the terminating null character.
70044bedb31SLionel Sambuc gzputs returns the number of characters written, or -1 in case of error.
70144bedb31SLionel Sambuc */
gzputs(file,s)70244bedb31SLionel Sambuc int ZEXPORT gzputs(file, s)
70344bedb31SLionel Sambuc gzFile file;
70444bedb31SLionel Sambuc const char *s;
70544bedb31SLionel Sambuc {
70644bedb31SLionel Sambuc return gzwrite(file, __UNCONST(s), (unsigned)strlen(s));
70744bedb31SLionel Sambuc }
70844bedb31SLionel Sambuc
70944bedb31SLionel Sambuc
71044bedb31SLionel Sambuc /* ===========================================================================
71144bedb31SLionel Sambuc Flushes all pending output into the compressed file. The parameter
71244bedb31SLionel Sambuc flush is as in the deflate() function.
71344bedb31SLionel Sambuc */
do_flush(file,flush)71444bedb31SLionel Sambuc local int do_flush (file, flush)
71544bedb31SLionel Sambuc gzFile file;
71644bedb31SLionel Sambuc int flush;
71744bedb31SLionel Sambuc {
71844bedb31SLionel Sambuc uInt len;
71944bedb31SLionel Sambuc int done = 0;
72044bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
72144bedb31SLionel Sambuc
72244bedb31SLionel Sambuc if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
72344bedb31SLionel Sambuc
72444bedb31SLionel Sambuc s->stream.avail_in = 0; /* should be zero already anyway */
72544bedb31SLionel Sambuc
72644bedb31SLionel Sambuc for (;;) {
72744bedb31SLionel Sambuc len = Z_BUFSIZE - s->stream.avail_out;
72844bedb31SLionel Sambuc
72944bedb31SLionel Sambuc if (len != 0) {
73044bedb31SLionel Sambuc if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
73144bedb31SLionel Sambuc s->z_err = Z_ERRNO;
73244bedb31SLionel Sambuc return Z_ERRNO;
73344bedb31SLionel Sambuc }
73444bedb31SLionel Sambuc s->stream.next_out = s->outbuf;
73544bedb31SLionel Sambuc s->stream.avail_out = Z_BUFSIZE;
73644bedb31SLionel Sambuc }
73744bedb31SLionel Sambuc if (done) break;
73844bedb31SLionel Sambuc s->out += s->stream.avail_out;
73944bedb31SLionel Sambuc s->z_err = deflate(&(s->stream), flush);
74044bedb31SLionel Sambuc s->out -= s->stream.avail_out;
74144bedb31SLionel Sambuc
74244bedb31SLionel Sambuc /* Ignore the second of two consecutive flushes: */
74344bedb31SLionel Sambuc if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
74444bedb31SLionel Sambuc
74544bedb31SLionel Sambuc /* deflate has finished flushing only when it hasn't used up
74644bedb31SLionel Sambuc * all the available space in the output buffer:
74744bedb31SLionel Sambuc */
74844bedb31SLionel Sambuc done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
74944bedb31SLionel Sambuc
75044bedb31SLionel Sambuc if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
75144bedb31SLionel Sambuc }
75244bedb31SLionel Sambuc return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
75344bedb31SLionel Sambuc }
75444bedb31SLionel Sambuc
gzflush(file,flush)75544bedb31SLionel Sambuc int ZEXPORT gzflush (file, flush)
75644bedb31SLionel Sambuc gzFile file;
75744bedb31SLionel Sambuc int flush;
75844bedb31SLionel Sambuc {
75944bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
76044bedb31SLionel Sambuc int err = do_flush (file, flush);
76144bedb31SLionel Sambuc
76244bedb31SLionel Sambuc if (err) return err;
76344bedb31SLionel Sambuc fflush(s->file);
76444bedb31SLionel Sambuc return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
76544bedb31SLionel Sambuc }
76644bedb31SLionel Sambuc #endif /* NO_GZCOMPRESS */
76744bedb31SLionel Sambuc
76844bedb31SLionel Sambuc /* ===========================================================================
76944bedb31SLionel Sambuc Sets the starting position for the next gzread or gzwrite on the given
77044bedb31SLionel Sambuc compressed file. The offset represents a number of bytes in the
77144bedb31SLionel Sambuc gzseek returns the resulting offset location as measured in bytes from
77244bedb31SLionel Sambuc the beginning of the uncompressed stream, or -1 in case of error.
77344bedb31SLionel Sambuc SEEK_END is not implemented, returns error.
77444bedb31SLionel Sambuc In this version of the library, gzseek can be extremely slow.
77544bedb31SLionel Sambuc */
gzseek(file,offset,whence)77644bedb31SLionel Sambuc z_off_t ZEXPORT gzseek (file, offset, whence)
77744bedb31SLionel Sambuc gzFile file;
77844bedb31SLionel Sambuc z_off_t offset;
77944bedb31SLionel Sambuc int whence;
78044bedb31SLionel Sambuc {
78144bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
78244bedb31SLionel Sambuc
78344bedb31SLionel Sambuc if (s == NULL || whence == SEEK_END ||
78444bedb31SLionel Sambuc s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
78544bedb31SLionel Sambuc return -1L;
78644bedb31SLionel Sambuc }
78744bedb31SLionel Sambuc
78844bedb31SLionel Sambuc if (s->mode == 'w') {
78944bedb31SLionel Sambuc #ifdef NO_GZCOMPRESS
79044bedb31SLionel Sambuc return -1L;
79144bedb31SLionel Sambuc #else
79244bedb31SLionel Sambuc if (whence == SEEK_SET) {
79344bedb31SLionel Sambuc offset -= s->in;
79444bedb31SLionel Sambuc }
79544bedb31SLionel Sambuc if (offset < 0) return -1L;
79644bedb31SLionel Sambuc
79744bedb31SLionel Sambuc /* At this point, offset is the number of zero bytes to write. */
79844bedb31SLionel Sambuc if (s->inbuf == Z_NULL) {
79944bedb31SLionel Sambuc s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
80044bedb31SLionel Sambuc if (s->inbuf == Z_NULL) return -1L;
80144bedb31SLionel Sambuc zmemzero(s->inbuf, Z_BUFSIZE);
80244bedb31SLionel Sambuc }
80344bedb31SLionel Sambuc while (offset > 0) {
80444bedb31SLionel Sambuc uInt size = Z_BUFSIZE;
80544bedb31SLionel Sambuc if (offset < Z_BUFSIZE) size = (uInt)offset;
80644bedb31SLionel Sambuc
80744bedb31SLionel Sambuc size = gzwrite(file, s->inbuf, size);
80844bedb31SLionel Sambuc if (size == 0) return -1L;
80944bedb31SLionel Sambuc
81044bedb31SLionel Sambuc offset -= size;
81144bedb31SLionel Sambuc }
81244bedb31SLionel Sambuc return s->in;
81344bedb31SLionel Sambuc #endif
81444bedb31SLionel Sambuc }
81544bedb31SLionel Sambuc /* Rest of function is for reading only */
81644bedb31SLionel Sambuc
81744bedb31SLionel Sambuc /* compute absolute position */
81844bedb31SLionel Sambuc if (whence == SEEK_CUR) {
81944bedb31SLionel Sambuc offset += s->out;
82044bedb31SLionel Sambuc }
82144bedb31SLionel Sambuc if (offset < 0) return -1L;
82244bedb31SLionel Sambuc
82344bedb31SLionel Sambuc if (s->transparent) {
82444bedb31SLionel Sambuc /* map to fseek */
82544bedb31SLionel Sambuc s->back = EOF;
82644bedb31SLionel Sambuc s->stream.avail_in = 0;
82744bedb31SLionel Sambuc s->stream.next_in = s->inbuf;
82844bedb31SLionel Sambuc if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
82944bedb31SLionel Sambuc
83044bedb31SLionel Sambuc s->in = s->out = offset;
83144bedb31SLionel Sambuc return offset;
83244bedb31SLionel Sambuc }
83344bedb31SLionel Sambuc
83444bedb31SLionel Sambuc /* For a negative seek, rewind and use positive seek */
83544bedb31SLionel Sambuc if (offset >= s->out) {
83644bedb31SLionel Sambuc offset -= s->out;
83744bedb31SLionel Sambuc } else if (gzrewind(file) < 0) {
83844bedb31SLionel Sambuc return -1L;
83944bedb31SLionel Sambuc }
84044bedb31SLionel Sambuc /* offset is now the number of bytes to skip. */
84144bedb31SLionel Sambuc
84244bedb31SLionel Sambuc if (offset != 0 && s->outbuf == Z_NULL) {
84344bedb31SLionel Sambuc s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
84444bedb31SLionel Sambuc if (s->outbuf == Z_NULL) return -1L;
84544bedb31SLionel Sambuc }
84644bedb31SLionel Sambuc if (offset && s->back != EOF) {
84744bedb31SLionel Sambuc s->back = EOF;
84844bedb31SLionel Sambuc s->out++;
84944bedb31SLionel Sambuc offset--;
85044bedb31SLionel Sambuc if (s->last) s->z_err = Z_STREAM_END;
85144bedb31SLionel Sambuc }
85244bedb31SLionel Sambuc while (offset > 0) {
85344bedb31SLionel Sambuc int size = Z_BUFSIZE;
85444bedb31SLionel Sambuc if (offset < Z_BUFSIZE) size = (int)offset;
85544bedb31SLionel Sambuc
85644bedb31SLionel Sambuc size = gzread(file, s->outbuf, (uInt)size);
85744bedb31SLionel Sambuc if (size <= 0) return -1L;
85844bedb31SLionel Sambuc offset -= size;
85944bedb31SLionel Sambuc }
86044bedb31SLionel Sambuc return s->out;
86144bedb31SLionel Sambuc }
86244bedb31SLionel Sambuc
86344bedb31SLionel Sambuc /* ===========================================================================
86444bedb31SLionel Sambuc Rewinds input file.
86544bedb31SLionel Sambuc */
gzrewind(file)86644bedb31SLionel Sambuc int ZEXPORT gzrewind (file)
86744bedb31SLionel Sambuc gzFile file;
86844bedb31SLionel Sambuc {
86944bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
87044bedb31SLionel Sambuc
87144bedb31SLionel Sambuc if (s == NULL || s->mode != 'r') return -1;
87244bedb31SLionel Sambuc
87344bedb31SLionel Sambuc s->z_err = Z_OK;
87444bedb31SLionel Sambuc s->z_eof = 0;
87544bedb31SLionel Sambuc s->back = EOF;
87644bedb31SLionel Sambuc s->stream.avail_in = 0;
87744bedb31SLionel Sambuc s->stream.next_in = s->inbuf;
87844bedb31SLionel Sambuc s->crc = crc32(0L, Z_NULL, 0);
87944bedb31SLionel Sambuc if (!s->transparent) (void)inflateReset(&s->stream);
88044bedb31SLionel Sambuc s->in = 0;
88144bedb31SLionel Sambuc s->out = 0;
88244bedb31SLionel Sambuc return fseek(s->file, s->start, SEEK_SET);
88344bedb31SLionel Sambuc }
88444bedb31SLionel Sambuc
88544bedb31SLionel Sambuc /* ===========================================================================
88644bedb31SLionel Sambuc Returns the starting position for the next gzread or gzwrite on the
88744bedb31SLionel Sambuc given compressed file. This position represents a number of bytes in the
88844bedb31SLionel Sambuc uncompressed data stream.
88944bedb31SLionel Sambuc */
gztell(file)89044bedb31SLionel Sambuc z_off_t ZEXPORT gztell (file)
89144bedb31SLionel Sambuc gzFile file;
89244bedb31SLionel Sambuc {
89344bedb31SLionel Sambuc return gzseek(file, 0L, SEEK_CUR);
89444bedb31SLionel Sambuc }
89544bedb31SLionel Sambuc
89644bedb31SLionel Sambuc /* ===========================================================================
89744bedb31SLionel Sambuc Returns 1 when EOF has previously been detected reading the given
89844bedb31SLionel Sambuc input stream, otherwise zero.
89944bedb31SLionel Sambuc */
gzeof(file)90044bedb31SLionel Sambuc int ZEXPORT gzeof (file)
90144bedb31SLionel Sambuc gzFile file;
90244bedb31SLionel Sambuc {
90344bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
90444bedb31SLionel Sambuc
90544bedb31SLionel Sambuc /* With concatenated compressed files that can have embedded
90644bedb31SLionel Sambuc * crc trailers, z_eof is no longer the only/best indicator of EOF
90744bedb31SLionel Sambuc * on a gz_stream. Handle end-of-stream error explicitly here.
90844bedb31SLionel Sambuc */
90944bedb31SLionel Sambuc if (s == NULL || s->mode != 'r') return 0;
91044bedb31SLionel Sambuc if (s->z_eof) return 1;
91144bedb31SLionel Sambuc return s->z_err == Z_STREAM_END;
91244bedb31SLionel Sambuc }
91344bedb31SLionel Sambuc
91444bedb31SLionel Sambuc /* ===========================================================================
91544bedb31SLionel Sambuc Returns 1 if reading and doing so transparently, otherwise zero.
91644bedb31SLionel Sambuc */
gzdirect(file)91744bedb31SLionel Sambuc int ZEXPORT gzdirect (file)
91844bedb31SLionel Sambuc gzFile file;
91944bedb31SLionel Sambuc {
92044bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
92144bedb31SLionel Sambuc
92244bedb31SLionel Sambuc if (s == NULL || s->mode != 'r') return 0;
92344bedb31SLionel Sambuc return s->transparent;
92444bedb31SLionel Sambuc }
92544bedb31SLionel Sambuc
92644bedb31SLionel Sambuc #ifndef NO_GZCOMPRESS
92744bedb31SLionel Sambuc /* ===========================================================================
92844bedb31SLionel Sambuc Outputs a long in LSB order to the given file
92944bedb31SLionel Sambuc */
putLong(file,x)93044bedb31SLionel Sambuc local void putLong (file, x)
93144bedb31SLionel Sambuc FILE *file;
93244bedb31SLionel Sambuc uLong x;
93344bedb31SLionel Sambuc {
93444bedb31SLionel Sambuc int n;
93544bedb31SLionel Sambuc for (n = 0; n < 4; n++) {
93644bedb31SLionel Sambuc fputc((int)(x & 0xff), file);
93744bedb31SLionel Sambuc x >>= 8;
93844bedb31SLionel Sambuc }
93944bedb31SLionel Sambuc }
94044bedb31SLionel Sambuc #endif
94144bedb31SLionel Sambuc
94244bedb31SLionel Sambuc /* ===========================================================================
94344bedb31SLionel Sambuc Reads a long in LSB order from the given gz_stream. Sets z_err in case
94444bedb31SLionel Sambuc of error.
94544bedb31SLionel Sambuc */
getLong(s)94644bedb31SLionel Sambuc local uLong getLong (s)
94744bedb31SLionel Sambuc gz_stream *s;
94844bedb31SLionel Sambuc {
94944bedb31SLionel Sambuc uLong x = (uLong)get_byte(s);
95044bedb31SLionel Sambuc int c;
95144bedb31SLionel Sambuc
95244bedb31SLionel Sambuc x += ((uLong)get_byte(s))<<8;
95344bedb31SLionel Sambuc x += ((uLong)get_byte(s))<<16;
95444bedb31SLionel Sambuc c = get_byte(s);
95544bedb31SLionel Sambuc if (c == EOF) s->z_err = Z_DATA_ERROR;
95644bedb31SLionel Sambuc x += ((uLong)c)<<24;
95744bedb31SLionel Sambuc return x;
95844bedb31SLionel Sambuc }
95944bedb31SLionel Sambuc
96044bedb31SLionel Sambuc /* ===========================================================================
96144bedb31SLionel Sambuc Flushes all pending output if necessary, closes the compressed file
96244bedb31SLionel Sambuc and deallocates all the (de)compression state.
96344bedb31SLionel Sambuc */
gzclose(file)96444bedb31SLionel Sambuc int ZEXPORT gzclose (file)
96544bedb31SLionel Sambuc gzFile file;
96644bedb31SLionel Sambuc {
96744bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
96844bedb31SLionel Sambuc
96944bedb31SLionel Sambuc if (s == NULL) return Z_STREAM_ERROR;
97044bedb31SLionel Sambuc
97144bedb31SLionel Sambuc if (s->mode == 'w') {
97244bedb31SLionel Sambuc #ifdef NO_GZCOMPRESS
97344bedb31SLionel Sambuc return Z_STREAM_ERROR;
97444bedb31SLionel Sambuc #else
97544bedb31SLionel Sambuc if (do_flush (file, Z_FINISH) != Z_OK)
97644bedb31SLionel Sambuc return destroy((gz_stream*)file);
97744bedb31SLionel Sambuc
97844bedb31SLionel Sambuc putLong (s->file, s->crc);
97944bedb31SLionel Sambuc putLong (s->file, (uLong)(s->in & 0xffffffff));
98044bedb31SLionel Sambuc #endif
98144bedb31SLionel Sambuc }
98244bedb31SLionel Sambuc return destroy((gz_stream*)file);
98344bedb31SLionel Sambuc }
98444bedb31SLionel Sambuc
98544bedb31SLionel Sambuc #ifdef STDC
98644bedb31SLionel Sambuc # define zstrerror(errnum) strerror(errnum)
98744bedb31SLionel Sambuc #else
98844bedb31SLionel Sambuc # define zstrerror(errnum) ""
98944bedb31SLionel Sambuc #endif
99044bedb31SLionel Sambuc
99144bedb31SLionel Sambuc /* ===========================================================================
99244bedb31SLionel Sambuc Returns the error message for the last error which occurred on the
99344bedb31SLionel Sambuc given compressed file. errnum is set to zlib error number. If an
99444bedb31SLionel Sambuc error occurred in the file system and not in the compression library,
99544bedb31SLionel Sambuc errnum is set to Z_ERRNO and the application may consult errno
99644bedb31SLionel Sambuc to get the exact error code.
99744bedb31SLionel Sambuc */
gzerror(file,errnum)99844bedb31SLionel Sambuc const char * ZEXPORT gzerror (file, errnum)
99944bedb31SLionel Sambuc gzFile file;
100044bedb31SLionel Sambuc int *errnum;
100144bedb31SLionel Sambuc {
100244bedb31SLionel Sambuc const char *m;
100344bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
100444bedb31SLionel Sambuc
100544bedb31SLionel Sambuc if (s == NULL) {
100644bedb31SLionel Sambuc *errnum = Z_STREAM_ERROR;
100744bedb31SLionel Sambuc return (const char*)ERR_MSG(Z_STREAM_ERROR);
100844bedb31SLionel Sambuc }
100944bedb31SLionel Sambuc *errnum = s->z_err;
101044bedb31SLionel Sambuc if (*errnum == Z_OK) return (const char*)"";
101144bedb31SLionel Sambuc
101244bedb31SLionel Sambuc m = *errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg;
101344bedb31SLionel Sambuc
101444bedb31SLionel Sambuc if (m == NULL || *m == '\0') m = ERR_MSG(s->z_err);
101544bedb31SLionel Sambuc
101644bedb31SLionel Sambuc TRYFREE(s->msg);
101744bedb31SLionel Sambuc s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
101844bedb31SLionel Sambuc if (s->msg == Z_NULL) return ERR_MSG(Z_MEM_ERROR);
101944bedb31SLionel Sambuc strcpy(s->msg, s->path);
102044bedb31SLionel Sambuc strcat(s->msg, ": ");
102144bedb31SLionel Sambuc strcat(s->msg, m);
102244bedb31SLionel Sambuc return (const char*)s->msg;
102344bedb31SLionel Sambuc }
102444bedb31SLionel Sambuc
102544bedb31SLionel Sambuc /* ===========================================================================
102644bedb31SLionel Sambuc Clear the error and end-of-file flags, and do the same for the real file.
102744bedb31SLionel Sambuc */
gzclearerr(file)102844bedb31SLionel Sambuc void ZEXPORT gzclearerr (file)
102944bedb31SLionel Sambuc gzFile file;
103044bedb31SLionel Sambuc {
103144bedb31SLionel Sambuc gz_stream *s = (gz_stream*)file;
103244bedb31SLionel Sambuc
103344bedb31SLionel Sambuc if (s == NULL) return;
103444bedb31SLionel Sambuc if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
103544bedb31SLionel Sambuc s->z_eof = 0;
103644bedb31SLionel Sambuc clearerr(s->file);
103744bedb31SLionel Sambuc }
1038