1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* gzread.c -- zlib functions for reading gzip files
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov * For conditions of distribution and use, see copyright notice in zlib.h
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov */
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "gzguts.h"
7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Local functions */
9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_avail OF((gz_statep));
11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_look OF((gz_statep));
12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_decomp OF((gz_statep));
13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_fetch OF((gz_statep));
14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_skip OF((gz_statep, z_off64_t));
15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   state->fd, and update state->eof, state->err, and state->msg as appropriate.
18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   This function needs to loop on read(), since read() is not guaranteed to
19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   read the number of bytes requested, depending on the type of descriptor. */
20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_load(
21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state,
22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned char *buf,
23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned len,
24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned *have)
25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int ret;
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *have = 0;
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    do {
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ret = read(state->fd, buf + *have, len - *have);
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (ret <= 0)
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        *have += ret;
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } while (*have < len);
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (ret < 0) {
36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gz_error(state, Z_ERRNO, zstrerror());
37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (ret == 0)
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->eof = 1;
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Load up input buffer and set eof flag if last data loaded -- return -1 on
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   error, 0 otherwise.  Note that the eof flag is set when the end of the input
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   file is reached, even though there may be unused data in the buffer.  Once
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   that data has been used, no more attempts will be made to read the file.
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   If strm->avail_in != 0, then the current data is moved to the beginning of
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   the input buffer, and then the remainder of the buffer is loaded with the
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   available data from the input file. */
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_avail(
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state)
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned got;
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    z_streamp strm = &(state->strm);
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->eof == 0) {
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (strm->avail_in) {       /* copy what's there to the start */
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            unsigned char *p = state->in;
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            unsigned const char *q = strm->next_in;
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            unsigned n = strm->avail_in;
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            do {
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                *p++ = *q++;
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            } while (--n);
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (gz_load(state, state->in + strm->avail_in,
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    state->size - strm->avail_in, &got) == -1)
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        strm->avail_in += got;
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        strm->next_in = state->in;
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   If this is the first time in, allocate required memory.  state->how will be
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   left unchanged if there is no more input data available, will be set to COPY
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   if there is no gzip header and direct copying will be performed, or it will
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   be set to GZIP for decompression.  If direct copying, then leftover input
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   data from the input buffer will be copied to the output buffer.  In that
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   case, all further file reads will be directly to either the output buffer or
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   a user buffer.  If decompressing, the inflate state will be initialized.
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   gz_look() will return 0 on success or -1 on failure. */
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_look(
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state)
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    z_streamp strm = &(state->strm);
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* allocate read buffers and inflate memory */
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->size == 0) {
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* allocate buffers */
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->in = (unsigned char *)malloc(state->want);
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->out = (unsigned char *)malloc(state->want << 1);
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (state->in == NULL || state->out == NULL) {
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (state->out != NULL)
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                free(state->out);
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (state->in != NULL)
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                free(state->in);
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            gz_error(state, Z_MEM_ERROR, "out of memory");
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->size = state->want;
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* allocate inflate memory */
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->strm.zalloc = Z_NULL;
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->strm.zfree = Z_NULL;
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->strm.opaque = Z_NULL;
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->strm.avail_in = 0;
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->strm.next_in = Z_NULL;
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            free(state->out);
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            free(state->in);
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->size = 0;
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            gz_error(state, Z_MEM_ERROR, "out of memory");
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* get at least the magic bytes in the input buffer */
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (strm->avail_in < 2) {
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (gz_avail(state) == -1)
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (strm->avail_in == 0)
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return 0;
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       a logical dilemma here when considering the case of a partially written
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       gzip file, to wit, if a single 31 byte is written, then we cannot tell
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       whether this is a single-byte file, or just a partially written gzip
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       file -- for here we assume that if a gzip file is being written, then
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       the header will be written in a single operation, so that reading a
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       single byte is sufficient indication that it is not a gzip file) */
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (strm->avail_in > 1 &&
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        inflateReset(strm);
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->how = GZIP;
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->direct = 0;
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return 0;
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* no gzip header -- if we were decoding gzip before, then this is trailing
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       garbage.  Ignore the trailing garbage and finish. */
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->direct == 0) {
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        strm->avail_in = 0;
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->eof = 1;
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.have = 0;
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return 0;
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* doing raw i/o, copy any leftover input to output -- this assumes that
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       the output buffer is larger than the input buffer, which also assures
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       space for gzungetc() */
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->x.next = state->out;
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (strm->avail_in) {
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        memcpy(state->x.next, strm->next_in, strm->avail_in);
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.have = strm->avail_in;
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        strm->avail_in = 0;
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->how = COPY;
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->direct = 1;
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Decompress from input to the provided next_out and avail_out in the state.
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   On return, state->x.have and state->x.next point to the just decompressed
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   data.  If the gzip stream completes, state->how is reset to LOOK to look for
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   on success, -1 on failure. */
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_decomp(
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state)
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int ret = Z_OK;
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned had;
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    z_streamp strm = &(state->strm);
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* fill output buffer up to end of deflate stream */
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    had = strm->avail_out;
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    do {
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* get more input for inflate() */
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (strm->avail_in == 0 && gz_avail(state) == -1)
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (strm->avail_in == 0) {
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* decompress and handle errors */
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ret = inflate(strm, Z_NO_FLUSH);
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            gz_error(state, Z_STREAM_ERROR,
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     "internal error: inflate stream corrupt");
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (ret == Z_MEM_ERROR) {
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            gz_error(state, Z_MEM_ERROR, "out of memory");
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            gz_error(state, Z_DATA_ERROR,
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     strm->msg == NULL ? "compressed data error" : strm->msg);
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } while (strm->avail_out && ret != Z_STREAM_END);
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* update available output */
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->x.have = had - strm->avail_out;
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->x.next = strm->next_out - state->x.have;
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* if the gzip stream completed successfully, look for another */
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (ret == Z_STREAM_END)
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->how = LOOK;
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* good decompression */
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   Data is either copied from the input file or decompressed from the input
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   file depending on state->how.  If state->how is LOOK, then a gzip header is
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   looked for to determine whether to copy or decompress.  Returns -1 on error,
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   end of the input file has been reached and all data has been processed.  */
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_fetch(
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state)
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    z_streamp strm = &(state->strm);
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    do {
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        switch(state->how) {
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (gz_look(state) == -1)
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -1;
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (state->how == LOOK)
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return 0;
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case COPY:      /* -> COPY */
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    == -1)
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -1;
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->x.next = state->out;
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return 0;
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            strm->avail_out = state->size << 1;
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            strm->next_out = state->out;
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (gz_decomp(state) == -1)
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -1;
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovlocal int gz_skip(
257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state,
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    z_off64_t len)
259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned n;
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* skip over len bytes or reach end-of-file, whichever comes first */
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while (len)
264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* skip over whatever is in output buffer */
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (state->x.have) {
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                (unsigned)len : state->x.have;
268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->x.have -= n;
269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->x.next += n;
270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->x.pos += n;
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            len -= n;
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* output buffer empty -- return if we're at the end of the input */
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else if (state->eof && state->strm.avail_in == 0)
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* need more data to skip -- load up output buffer */
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* get more output, looking for header if required */
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (gz_fetch(state) == -1)
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -1;
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* -- see zlib.h -- */
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint ZEXPORT gzread(
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gzFile file,
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    voidp buf,
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned len)
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned got, n;
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state;
295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    z_streamp strm;
296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* get internal structure */
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (file == NULL)
299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state = (gz_statep)file;
301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    strm = &(state->strm);
302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check that we're reading and that there's no (serious) error */
304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->mode != GZ_READ ||
305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            (state->err != Z_OK && state->err != Z_BUF_ERROR))
306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* since an int is returned, make sure len fits in one, otherwise return
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       with an error (this avoids the flaw in the interface) */
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ((int)len < 0) {
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* if len is zero, avoid unnecessary operations */
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (len == 0)
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return 0;
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* process a skip request */
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->seek) {
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->seek = 0;
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (gz_skip(state, state->skip) == -1)
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* get len bytes to buf, or less than len if at the end */
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    got = 0;
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    do {
329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* first just try copying data from the output buffer */
330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (state->x.have) {
331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            n = state->x.have > len ? len : state->x.have;
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            memcpy(buf, state->x.next, n);
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->x.next += n;
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->x.have -= n;
335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* output buffer empty -- return if we're at the end of the input */
338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else if (state->eof && strm->avail_in == 0) {
339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->past = 1;        /* tried to read past end */
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* need output data -- for small len or new stream load up our output
344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           buffer */
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else if (state->how == LOOK || len < (state->size << 1)) {
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* get more output, looking for header if required */
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (gz_fetch(state) == -1)
348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -1;
349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            continue;       /* no progress yet -- go back to copy above */
350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* the copy above assures that we will leave with space in the
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               output buffer, allowing at least one gzungetc() to succeed */
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* large len -- read directly into user buffer */
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else if (state->how == COPY) {      /* read directly */
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (gz_load(state, (unsigned char *)buf, len, &n) == -1)
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -1;
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* large len -- decompress directly into user buffer */
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {  /* state->how == GZIP */
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            strm->avail_out = len;
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            strm->next_out = (unsigned char *)buf;
364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (gz_decomp(state) == -1)
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -1;
366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            n = state->x.have;
367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->x.have = 0;
368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* update progress */
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        len -= n;
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        buf = (char *)buf + n;
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        got += n;
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.pos += n;
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } while (len);
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* return number of bytes read into user buffer (will fit in int) */
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return (int)got;
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* -- see zlib.h -- */
382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef Z_PREFIX_SET
383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#  undef z_gzgetc
384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else
385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#  undef gzgetc
386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint ZEXPORT gzgetc(
388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gzFile file)
389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int ret;
391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned char buf[1];
392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state;
393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* get internal structure */
395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (file == NULL)
396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state = (gz_statep)file;
398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check that we're reading and that there's no (serious) error */
400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->mode != GZ_READ ||
401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        (state->err != Z_OK && state->err != Z_BUF_ERROR))
402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* try output buffer (no need to check for skip request) */
405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->x.have) {
406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.have--;
407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.pos++;
408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return *(state->x.next)++;
409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* nothing there -- try gzread() */
412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ret = gzread(file, buf, 1);
413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return ret < 1 ? -1 : buf[0];
414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint ZEXPORT gzgetc_(
417ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovgzFile file)
418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gzgetc(file);
420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* -- see zlib.h -- */
423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint ZEXPORT gzungetc(
424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int c,
425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gzFile file)
426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state;
428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* get internal structure */
430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (file == NULL)
431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state = (gz_statep)file;
433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check that we're reading and that there's no (serious) error */
435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->mode != GZ_READ ||
436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        (state->err != Z_OK && state->err != Z_BUF_ERROR))
437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* process a skip request */
440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->seek) {
441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->seek = 0;
442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (gz_skip(state, state->skip) == -1)
443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* can't push EOF */
447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (c < 0)
448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* if output buffer empty, put byte at end (allows more pushing) */
451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->x.have == 0) {
452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.have = 1;
453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.next = state->out + (state->size << 1) - 1;
454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.next[0] = c;
455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.pos--;
456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->past = 0;
457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return c;
458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* if no room, give up (must have already done a gzungetc()) */
461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->x.have == (state->size << 1)) {
462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gz_error(state, Z_DATA_ERROR, "out of room to push characters");
463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return -1;
464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* slide output data if needed and insert byte before existing data */
467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->x.next == state->out) {
468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        unsigned char *src = state->out + state->x.have;
469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        unsigned char *dest = state->out + (state->size << 1);
470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        while (src > state->out)
471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            *--dest = *--src;
472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.next = dest;
473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->x.have++;
475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->x.next--;
476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->x.next[0] = c;
477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->x.pos--;
478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state->past = 0;
479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return c;
480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* -- see zlib.h -- */
483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovchar * ZEXPORT gzgets(
484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gzFile file,
485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char *buf,
486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int len)
487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned left, n;
489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char *str;
490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned char *eol;
491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state;
492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check parameters and get internal structure */
494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (file == NULL || buf == NULL || len < 1)
495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state = (gz_statep)file;
497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check that we're reading and that there's no (serious) error */
499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->mode != GZ_READ ||
500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        (state->err != Z_OK && state->err != Z_BUF_ERROR))
501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* process a skip request */
504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->seek) {
505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->seek = 0;
506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (gz_skip(state, state->skip) == -1)
507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return NULL;
508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* copy output bytes up to new line or len - 1, whichever comes first --
511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       append a terminating zero to the string (we don't check for a zero in
512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       the contents, let the user worry about that) */
513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    str = buf;
514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    left = (unsigned)len - 1;
515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (left) do {
516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* assure that something is in the output buffer */
517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (state->x.have == 0 && gz_fetch(state) == -1)
518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return NULL;                /* error */
519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (state->x.have == 0) {       /* end of file */
520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            state->past = 1;            /* read past end */
521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;                      /* return what we have */
522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* look for end-of-line in current output buffer */
525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        n = state->x.have > left ? left : state->x.have;
526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        eol = (unsigned char *)memchr(state->x.next, '\n', n);
527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (eol != NULL)
528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            n = (unsigned)(eol - state->x.next) + 1;
529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* copy through end-of-line, or remainder if not found */
531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        memcpy(buf, state->x.next, n);
532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.have -= n;
533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.next += n;
534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        state->x.pos += n;
535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        left -= n;
536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        buf += n;
537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } while (left && eol == NULL);
538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* return terminated string, or if nothing, end of file */
540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (buf == str)
541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    buf[0] = 0;
543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return str;
544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* -- see zlib.h -- */
547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint ZEXPORT gzdirect(
548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gzFile file)
549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state;
551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* get internal structure */
553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (file == NULL)
554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return 0;
555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state = (gz_statep)file;
556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* if the state is not known, but we can find out, then do so (this is
558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       mainly for right after a gzopen() or gzdopen()) */
559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        (void)gz_look(state);
561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* return 1 if transparent, 0 if processing a gzip stream */
563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return state->direct;
564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* -- see zlib.h -- */
567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint ZEXPORT gzclose_r(
568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gzFile file)
569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int ret, err;
571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_statep state;
572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* get internal structure */
574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (file == NULL)
575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return Z_STREAM_ERROR;
576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    state = (gz_statep)file;
577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check that we're reading */
579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->mode != GZ_READ)
580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return Z_STREAM_ERROR;
581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* free memory and close file */
583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (state->size) {
584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        inflateEnd(&(state->strm));
585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        free(state->out);
586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        free(state->in);
587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gz_error(state, Z_OK, NULL);
590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    free(state->path);
591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ret = close(state->fd);
592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    free(state);
593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return ret ? Z_ERRNO : err;
594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
595