1381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* gzread.c -- zlib functions for reading gzip files
2381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes * Copyright (C) 2004, 2005, 2010 Mark Adler
3381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes * For conditions of distribution and use, see copyright notice in zlib.h
4381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes */
5381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
6381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#include "gzguts.h"
7381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
8381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Local functions */
9381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
10381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_avail OF((gz_statep));
11381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_next4 OF((gz_statep, unsigned long *));
12381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_head OF((gz_statep));
13381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_decomp OF((gz_statep));
14381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_make OF((gz_statep));
15381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_skip OF((gz_statep, z_off64_t));
16381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
17381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
18381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   state->fd, and update state->eof, state->err, and state->msg as appropriate.
19381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   This function needs to loop on read(), since read() is not guaranteed to
20381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   read the number of bytes requested, depending on the type of descriptor. */
21381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_load(state, buf, len, have)
22381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
23381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned char *buf;
24381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned len;
25381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned *have;
26381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
27381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    int ret;
28381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
29381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    *have = 0;
30381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    do {
31381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        ret = read(state->fd, buf + *have, len - *have);
32381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (ret <= 0)
33381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            break;
34381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        *have += ret;
35381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    } while (*have < len);
36381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (ret < 0) {
37381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        gz_error(state, Z_ERRNO, zstrerror());
38381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
39381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
40381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (ret == 0)
41381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->eof = 1;
42381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return 0;
43381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
44381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
45381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Load up input buffer and set eof flag if last data loaded -- return -1 on
46381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   error, 0 otherwise.  Note that the eof flag is set when the end of the input
47381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   file is reached, even though there may be unused data in the buffer.  Once
48381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   that data has been used, no more attempts will be made to read the file.
49381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   gz_avail() assumes that strm->avail_in == 0. */
50381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_avail(state)
51381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
52381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
53381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    z_streamp strm = &(state->strm);
54381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
55381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->err != Z_OK)
56381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
57381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->eof == 0) {
58381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_load(state, state->in, state->size,
59381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                (unsigned *)&(strm->avail_in)) == -1)
60381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
61381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        strm->next_in = state->in;
62381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
63381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return 0;
64381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
65381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
66381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Get next byte from input, or -1 if end or error. */
67381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \
68381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                (strm->avail_in == 0 ? -1 : \
69381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                 (strm->avail_in--, *(strm->next_in)++)))
70381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
71381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Get a four-byte little-endian integer and return 0 on success and the value
72381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   in *ret.  Otherwise -1 is returned and *ret is not modified. */
73381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_next4(state, ret)
74381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
75381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned long *ret;
76381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
77381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    int ch;
78381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned long val;
79381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    z_streamp strm = &(state->strm);
80381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
81381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    val = NEXT();
82381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    val += (unsigned)NEXT() << 8;
83381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    val += (unsigned long)NEXT() << 16;
84381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    ch = NEXT();
85381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (ch == -1)
86381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
87381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    val += (unsigned long)ch << 24;
88381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    *ret = val;
89381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return 0;
90381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
91381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
92381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Look for gzip header, set up for inflate or copy.  state->have must be zero.
93381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   If this is the first time in, allocate required memory.  state->how will be
94381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   left unchanged if there is no more input data available, will be set to COPY
95381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   if there is no gzip header and direct copying will be performed, or it will
96381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   be set to GZIP for decompression, and the gzip header will be skipped so
97381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   that the next available input data is the raw deflate stream.  If direct
98381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   copying, then leftover input data from the input buffer will be copied to
99381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   the output buffer.  In that case, all further file reads will be directly to
100381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   either the output buffer or a user buffer.  If decompressing, the inflate
101381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   state and the check value will be initialized.  gz_head() will return 0 on
102381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   success or -1 on failure.  Failures may include read errors or gzip header
103381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   errors.  */
104381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_head(state)
105381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
106381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
107381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    z_streamp strm = &(state->strm);
108381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    int flags;
109381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned len;
110381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
111381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* allocate read buffers and inflate memory */
112381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->size == 0) {
113381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* allocate buffers */
114381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->in = malloc(state->want);
115381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->out = malloc(state->want << 1);
116381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (state->in == NULL || state->out == NULL) {
117381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (state->out != NULL)
118381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                free(state->out);
119381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (state->in != NULL)
120381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                free(state->in);
121381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_MEM_ERROR, "out of memory");
122381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
123381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
124381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->size = state->want;
125381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
126381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* allocate inflate memory */
127381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->strm.zalloc = Z_NULL;
128381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->strm.zfree = Z_NULL;
129381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->strm.opaque = Z_NULL;
130381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->strm.avail_in = 0;
131381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->strm.next_in = Z_NULL;
132381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (inflateInit2(&(state->strm), -15) != Z_OK) {    /* raw inflate */
133381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            free(state->out);
134381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            free(state->in);
135381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->size = 0;
136381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_MEM_ERROR, "out of memory");
137381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
138381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
139381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
140381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
141381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* get some data in the input buffer */
142381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (strm->avail_in == 0) {
143381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_avail(state) == -1)
144381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
145381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (strm->avail_in == 0)
146381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return 0;
147381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
148381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
149381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* look for the gzip magic header bytes 31 and 139 */
150381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (strm->next_in[0] == 31) {
151381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        strm->avail_in--;
152381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        strm->next_in++;
153381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (strm->avail_in == 0 && gz_avail(state) == -1)
154381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
155381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (strm->avail_in && strm->next_in[0] == 139) {
156381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            /* we have a gzip header, woo hoo! */
157381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            strm->avail_in--;
158381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            strm->next_in++;
159381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
160381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            /* skip rest of header */
161381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (NEXT() != 8) {      /* compression method */
162381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                gz_error(state, Z_DATA_ERROR, "unknown compression method");
163381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                return -1;
164381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            }
165381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            flags = NEXT();
166381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (flags & 0xe0) {     /* reserved flag bits */
167381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                gz_error(state, Z_DATA_ERROR, "unknown header flags set");
168381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                return -1;
169381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            }
170381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            NEXT();                 /* modification time */
171381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            NEXT();
172381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            NEXT();
173381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            NEXT();
174381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            NEXT();                 /* extra flags */
175381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            NEXT();                 /* operating system */
176381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (flags & 4) {        /* extra field */
177381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                len = (unsigned)NEXT();
178381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                len += (unsigned)NEXT() << 8;
179381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                while (len--)
180381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                    if (NEXT() < 0)
181381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                        break;
182381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            }
183381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (flags & 8)          /* file name */
184381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                while (NEXT() > 0)
185381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                    ;
186381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (flags & 16)         /* comment */
187381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                while (NEXT() > 0)
188381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                    ;
189381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (flags & 2) {        /* header crc */
190381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                NEXT();
191381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                NEXT();
192381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            }
193381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            /* an unexpected end of file is not checked for here -- it will be
194381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes               noticed on the first request for uncompressed data */
195381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
196381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            /* set up for decompression */
197381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            inflateReset(strm);
198381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            strm->adler = crc32(0L, Z_NULL, 0);
199381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->how = GZIP;
200381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->direct = 0;
201381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return 0;
202381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
203381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        else {
204381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            /* not a gzip file -- save first byte (31) and fall to raw i/o */
205381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->out[0] = 31;
206381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->have = 1;
207381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
208381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
209381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
210381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* doing raw i/o, save start of raw data for seeking, copy any leftover
211381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes       input to output -- this assumes that the output buffer is larger than
212381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes       the input buffer, which also assures space for gzungetc() */
213381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->raw = state->pos;
214381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->next = state->out;
215381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (strm->avail_in) {
216381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        memcpy(state->next + state->have, strm->next_in, strm->avail_in);
217381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->have += strm->avail_in;
218381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        strm->avail_in = 0;
219381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
220381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->how = COPY;
221381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->direct = 1;
222381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return 0;
223381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
224381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
225381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Decompress from input to the provided next_out and avail_out in the state.
226381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   If the end of the compressed data is reached, then verify the gzip trailer
227381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   check value and length (modulo 2^32).  state->have and state->next are set
228381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   to point to the just decompressed data, and the crc is updated.  If the
229381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   trailer is verified, state->how is reset to LOOK to look for the next gzip
230381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   stream or raw data, once state->have is depleted.  Returns 0 on success, -1
231381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   on failure.  Failures may include invalid compressed data or a failed gzip
232381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   trailer verification. */
233381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_decomp(state)
234381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
235381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
236381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    int ret;
237381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned had;
238381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned long crc, len;
239381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    z_streamp strm = &(state->strm);
240381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
241381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* fill output buffer up to end of deflate stream */
242381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    had = strm->avail_out;
243381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    do {
244381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* get more input for inflate() */
245381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (strm->avail_in == 0 && gz_avail(state) == -1)
246381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
247381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (strm->avail_in == 0) {
248381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_DATA_ERROR, "unexpected end of file");
249381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
250381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
251381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
252381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* decompress and handle errors */
253381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        ret = inflate(strm, Z_NO_FLUSH);
254381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
255381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_STREAM_ERROR,
256381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                      "internal error: inflate stream corrupt");
257381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
258381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
259381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (ret == Z_MEM_ERROR) {
260381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_MEM_ERROR, "out of memory");
261381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
262381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
263381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
264381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_DATA_ERROR,
265381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                      strm->msg == NULL ? "compressed data error" : strm->msg);
266381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
267381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
268381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    } while (strm->avail_out && ret != Z_STREAM_END);
269381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
270381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* update available output and crc check value */
271381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->have = had - strm->avail_out;
272381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->next = strm->next_out - state->have;
273381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    strm->adler = crc32(strm->adler, state->next, state->have);
274381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
275381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* check gzip trailer if at end of deflate stream */
276381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (ret == Z_STREAM_END) {
277381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) {
278381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_DATA_ERROR, "unexpected end of file");
279381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
280381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
281381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (crc != strm->adler) {
282381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_DATA_ERROR, "incorrect data check");
283381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
284381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
285381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (len != (strm->total_out & 0xffffffffL)) {
286381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            gz_error(state, Z_DATA_ERROR, "incorrect length check");
287381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
288381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
289381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->how = LOOK;      /* ready for next stream, once have is 0 (leave
290381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                                   state->direct unchanged to remember how) */
291381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
292381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
293381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* good decompression */
294381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return 0;
295381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
296381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
297381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Make data and put in the output buffer.  Assumes that state->have == 0.
298381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   Data is either copied from the input file or decompressed from the input
299381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   file depending on state->how.  If state->how is LOOK, then a gzip header is
300381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   looked for (and skipped if found) to determine wither to copy or decompress.
301381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   Returns -1 on error, otherwise 0.  gz_make() will leave state->have as COPY
302381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   or GZIP unless the end of the input file has been reached and all data has
303381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes   been processed.  */
304381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_make(state)
305381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
306381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
307381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    z_streamp strm = &(state->strm);
308381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
309381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->how == LOOK) {           /* look for gzip header */
310381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_head(state) == -1)
311381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
312381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (state->have)                /* got some data from gz_head() */
313381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return 0;
314381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
315381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->how == COPY) {           /* straight copy */
316381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1)
317381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
318381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->next = state->out;
319381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
320381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    else if (state->how == GZIP) {      /* decompress */
321381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        strm->avail_out = state->size << 1;
322381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        strm->next_out = state->out;
323381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_decomp(state) == -1)
324381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
325381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
326381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return 0;
327381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
328381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
329381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
330381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal int gz_skip(state, len)
331381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
332381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    z_off64_t len;
333381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
334381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned n;
335381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
336381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* skip over len bytes or reach end-of-file, whichever comes first */
337381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    while (len)
338381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* skip over whatever is in output buffer */
339381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (state->have) {
340381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            n = GT_OFF(state->have) || (z_off64_t)state->have > len ?
341381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                (unsigned)len : state->have;
342381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->have -= n;
343381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->next += n;
344381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->pos += n;
345381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            len -= n;
346381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
347381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
348381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* output buffer empty -- return if we're at the end of the input */
349381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        else if (state->eof && state->strm.avail_in == 0)
350381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            break;
351381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
352381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* need more data to skip -- load up output buffer */
353381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        else {
354381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            /* get more output, looking for header if required */
355381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (gz_make(state) == -1)
356381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                return -1;
357381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
358381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return 0;
359381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
360381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
361381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* -- see zlib.h -- */
362381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughesint ZEXPORT gzread(file, buf, len)
363381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gzFile file;
364381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    voidp buf;
365381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned len;
366381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
367381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned got, n;
368381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
369381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    z_streamp strm;
370381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
371381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* get internal structure */
372381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (file == NULL)
373381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
374381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state = (gz_statep)file;
375381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    strm = &(state->strm);
376381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
377381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* check that we're reading and that there's no error */
378381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->mode != GZ_READ || state->err != Z_OK)
379381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
380381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
381381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* since an int is returned, make sure len fits in one, otherwise return
382381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes       with an error (this avoids the flaw in the interface) */
383381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if ((int)len < 0) {
384381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
385381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
386381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
387381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
388381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* if len is zero, avoid unnecessary operations */
389381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (len == 0)
390381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return 0;
391381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
392381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* process a skip request */
393381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->seek) {
394381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->seek = 0;
395381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_skip(state, state->skip) == -1)
396381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
397381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
398381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
399381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* get len bytes to buf, or less than len if at the end */
400381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    got = 0;
401381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    do {
402381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* first just try copying data from the output buffer */
403381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (state->have) {
404381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            n = state->have > len ? len : state->have;
405381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            memcpy(buf, state->next, n);
406381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->next += n;
407381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->have -= n;
408381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
409381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
410381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* output buffer empty -- return if we're at the end of the input */
411381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        else if (state->eof && strm->avail_in == 0)
412381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            break;
413381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
414381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* need output data -- for small len or new stream load up our output
415381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes           buffer */
416381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        else if (state->how == LOOK || len < (state->size << 1)) {
417381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            /* get more output, looking for header if required */
418381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (gz_make(state) == -1)
419381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                return -1;
420381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            continue;       /* no progress yet -- go back to memcpy() above */
421381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            /* the copy above assures that we will leave with space in the
422381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes               output buffer, allowing at least one gzungetc() to succeed */
423381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
424381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
425381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* large len -- read directly into user buffer */
426381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        else if (state->how == COPY) {      /* read directly */
427381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (gz_load(state, buf, len, &n) == -1)
428381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                return -1;
429381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
430381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
431381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* large len -- decompress directly into user buffer */
432381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        else {  /* state->how == GZIP */
433381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            strm->avail_out = len;
434381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            strm->next_out = buf;
435381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (gz_decomp(state) == -1)
436381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                return -1;
437381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            n = state->have;
438381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            state->have = 0;
439381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
440381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
441381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* update progress */
442381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        len -= n;
443381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        buf = (char *)buf + n;
444381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        got += n;
445381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->pos += n;
446381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    } while (len);
447381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
448381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* return number of bytes read into user buffer (will fit in int) */
449381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return (int)got;
450381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
451381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
452381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* -- see zlib.h -- */
453381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughesint ZEXPORT gzgetc(file)
454381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gzFile file;
455381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
456381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    int ret;
457381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned char buf[1];
458381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
459381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
460381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* get internal structure */
461381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (file == NULL)
462381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
463381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state = (gz_statep)file;
464381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
465381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* check that we're reading and that there's no error */
466381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->mode != GZ_READ || state->err != Z_OK)
467381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
468381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
469381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* try output buffer (no need to check for skip request) */
470381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->have) {
471381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->have--;
472381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->pos++;
473381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return *(state->next)++;
474381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
475381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
476381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* nothing there -- try gzread() */
477381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    ret = gzread(file, buf, 1);
478381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return ret < 1 ? -1 : buf[0];
479381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
480381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
481381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* -- see zlib.h -- */
482381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughesint ZEXPORT gzungetc(c, file)
483381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    int c;
484381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gzFile file;
485381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
486381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
487381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
488381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* get internal structure */
489381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (file == NULL)
490381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
491381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state = (gz_statep)file;
492381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
493381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* check that we're reading and that there's no error */
494381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->mode != GZ_READ || state->err != Z_OK)
495381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
496381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
497381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* process a skip request */
498381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->seek) {
499381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->seek = 0;
500381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_skip(state, state->skip) == -1)
501381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return -1;
502381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
503381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
504381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* can't push EOF */
505381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (c < 0)
506381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
507381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
508381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* if output buffer empty, put byte at end (allows more pushing) */
509381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->have == 0) {
510381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->have = 1;
511381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->next = state->out + (state->size << 1) - 1;
512381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->next[0] = c;
513381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->pos--;
514381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return c;
515381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
516381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
517381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* if no room, give up (must have already done a gzungetc()) */
518381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->have == (state->size << 1)) {
519381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        gz_error(state, Z_BUF_ERROR, "out of room to push characters");
520381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return -1;
521381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
522381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
523381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* slide output data if needed and insert byte before existing data */
524381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->next == state->out) {
525381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        unsigned char *src = state->out + state->have;
526381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        unsigned char *dest = state->out + (state->size << 1);
527381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        while (src > state->out)
528381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            *--dest = *--src;
529381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->next = dest;
530381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
531381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->have++;
532381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->next--;
533381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->next[0] = c;
534381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state->pos--;
535381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return c;
536381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
537381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
538381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* -- see zlib.h -- */
539381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheschar * ZEXPORT gzgets(file, buf, len)
540381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gzFile file;
541381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    char *buf;
542381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    int len;
543381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
544381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned left, n;
545381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    char *str;
546381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    unsigned char *eol;
547381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
548381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
549381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* check parameters and get internal structure */
550381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (file == NULL || buf == NULL || len < 1)
551381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return NULL;
552381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state = (gz_statep)file;
553381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
554381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* check that we're reading and that there's no error */
555381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->mode != GZ_READ || state->err != Z_OK)
556381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return NULL;
557381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
558381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* process a skip request */
559381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->seek) {
560381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->seek = 0;
561381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (gz_skip(state, state->skip) == -1)
562381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            return NULL;
563381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
564381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
565381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* copy output bytes up to new line or len - 1, whichever comes first --
566381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes       append a terminating zero to the string (we don't check for a zero in
567381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes       the contents, let the user worry about that) */
568381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    str = buf;
569381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    left = (unsigned)len - 1;
570381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (left) do {
571381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* assure that something is in the output buffer */
572381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (state->have == 0) {
573381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (gz_make(state) == -1)
574381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                return NULL;            /* error */
575381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            if (state->have == 0) {     /* end of file */
576381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                if (buf == str)         /* got bupkus */
577381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                    return NULL;
578381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes                break;                  /* got something -- return it */
579381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            }
580381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        }
581381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
582381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* look for end-of-line in current output buffer */
583381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        n = state->have > left ? left : state->have;
584381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        eol = memchr(state->next, '\n', n);
585381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        if (eol != NULL)
586381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes            n = (unsigned)(eol - state->next) + 1;
587381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
588381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        /* copy through end-of-line, or remainder if not found */
589381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        memcpy(buf, state->next, n);
590381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->have -= n;
591381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->next += n;
592381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        state->pos += n;
593381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        left -= n;
594381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        buf += n;
595381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    } while (left && eol == NULL);
596381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
597381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* found end-of-line or out of space -- terminate string and return it */
598381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    buf[0] = 0;
599381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return str;
600381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
601381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
602381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* -- see zlib.h -- */
603381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughesint ZEXPORT gzdirect(file)
604381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gzFile file;
605381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
606381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
607381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
608381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* get internal structure */
609381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (file == NULL)
610381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return 0;
611381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state = (gz_statep)file;
612381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
613381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* check that we're reading */
614381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->mode != GZ_READ)
615381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return 0;
616381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
617381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* if the state is not known, but we can find out, then do so (this is
618381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes       mainly for right after a gzopen() or gzdopen()) */
619381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->how == LOOK && state->have == 0)
620381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        (void)gz_head(state);
621381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
622381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* return 1 if reading direct, 0 if decompressing a gzip stream */
623381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return state->direct;
624381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
625381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
626381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* -- see zlib.h -- */
627381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughesint ZEXPORT gzclose_r(file)
628381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gzFile file;
629381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{
630381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    int ret;
631381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_statep state;
632381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
633381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* get internal structure */
634381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (file == NULL)
635381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return Z_STREAM_ERROR;
636381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    state = (gz_statep)file;
637381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
638381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* check that we're reading */
639381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->mode != GZ_READ)
640381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        return Z_STREAM_ERROR;
641381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes
642381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    /* free memory and close file */
643381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    if (state->size) {
644381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        inflateEnd(&(state->strm));
645381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        free(state->out);
646381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes        free(state->in);
647381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    }
648381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    gz_error(state, Z_OK, NULL);
649381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    free(state->path);
650381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    ret = close(state->fd);
651381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    free(state);
652381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes    return ret ? Z_ERRNO : Z_OK;
653381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes}
654