1205194Sdelphij/* gzread.c -- zlib functions for reading gzip files
2311285Sdelphij * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
3205194Sdelphij * For conditions of distribution and use, see copyright notice in zlib.h
4205194Sdelphij */
5205194Sdelphij
6311275Sdelphij/* $FreeBSD: stable/11/sys/contrib/zlib/gzread.c 311285 2017-01-04 16:09:08Z delphij $ */
7311275Sdelphij
8205194Sdelphij#include "gzguts.h"
9311275Sdelphij#include <unistd.h>
10205194Sdelphij
11205194Sdelphij/* Local functions */
12205194Sdelphijlocal int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
13205194Sdelphijlocal int gz_avail OF((gz_statep));
14230837Sdelphijlocal int gz_look OF((gz_statep));
15205194Sdelphijlocal int gz_decomp OF((gz_statep));
16230837Sdelphijlocal int gz_fetch OF((gz_statep));
17205194Sdelphijlocal int gz_skip OF((gz_statep, z_off64_t));
18311285Sdelphijlocal z_size_t gz_read OF((gz_statep, voidp, z_size_t));
19205194Sdelphij
20205194Sdelphij/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
21205194Sdelphij   state->fd, and update state->eof, state->err, and state->msg as appropriate.
22205194Sdelphij   This function needs to loop on read(), since read() is not guaranteed to
23205194Sdelphij   read the number of bytes requested, depending on the type of descriptor. */
24205194Sdelphijlocal int gz_load(state, buf, len, have)
25205194Sdelphij    gz_statep state;
26205194Sdelphij    unsigned char *buf;
27205194Sdelphij    unsigned len;
28205194Sdelphij    unsigned *have;
29205194Sdelphij{
30205194Sdelphij    int ret;
31311285Sdelphij    unsigned get, max = ((unsigned)-1 >> 2) + 1;
32205194Sdelphij
33205194Sdelphij    *have = 0;
34205194Sdelphij    do {
35311285Sdelphij        get = len - *have;
36311285Sdelphij        if (get > max)
37311285Sdelphij            get = max;
38311285Sdelphij        ret = read(state->fd, buf + *have, get);
39205194Sdelphij        if (ret <= 0)
40205194Sdelphij            break;
41311285Sdelphij        *have += (unsigned)ret;
42205194Sdelphij    } while (*have < len);
43205194Sdelphij    if (ret < 0) {
44205194Sdelphij        gz_error(state, Z_ERRNO, zstrerror());
45205194Sdelphij        return -1;
46205194Sdelphij    }
47205194Sdelphij    if (ret == 0)
48205194Sdelphij        state->eof = 1;
49205194Sdelphij    return 0;
50205194Sdelphij}
51205194Sdelphij
52205194Sdelphij/* Load up input buffer and set eof flag if last data loaded -- return -1 on
53205194Sdelphij   error, 0 otherwise.  Note that the eof flag is set when the end of the input
54205194Sdelphij   file is reached, even though there may be unused data in the buffer.  Once
55205194Sdelphij   that data has been used, no more attempts will be made to read the file.
56230837Sdelphij   If strm->avail_in != 0, then the current data is moved to the beginning of
57230837Sdelphij   the input buffer, and then the remainder of the buffer is loaded with the
58230837Sdelphij   available data from the input file. */
59205194Sdelphijlocal int gz_avail(state)
60205194Sdelphij    gz_statep state;
61205194Sdelphij{
62230837Sdelphij    unsigned got;
63205194Sdelphij    z_streamp strm = &(state->strm);
64205194Sdelphij
65230837Sdelphij    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
66205194Sdelphij        return -1;
67205194Sdelphij    if (state->eof == 0) {
68237248Sdelphij        if (strm->avail_in) {       /* copy what's there to the start */
69250224Sdelphij            unsigned char *p = state->in;
70250224Sdelphij            unsigned const char *q = strm->next_in;
71237248Sdelphij            unsigned n = strm->avail_in;
72237248Sdelphij            do {
73237248Sdelphij                *p++ = *q++;
74237248Sdelphij            } while (--n);
75237248Sdelphij        }
76230837Sdelphij        if (gz_load(state, state->in + strm->avail_in,
77230837Sdelphij                    state->size - strm->avail_in, &got) == -1)
78205194Sdelphij            return -1;
79230837Sdelphij        strm->avail_in += got;
80205194Sdelphij        strm->next_in = state->in;
81205194Sdelphij    }
82205194Sdelphij    return 0;
83205194Sdelphij}
84205194Sdelphij
85230837Sdelphij/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
86205194Sdelphij   If this is the first time in, allocate required memory.  state->how will be
87205194Sdelphij   left unchanged if there is no more input data available, will be set to COPY
88205194Sdelphij   if there is no gzip header and direct copying will be performed, or it will
89230837Sdelphij   be set to GZIP for decompression.  If direct copying, then leftover input
90230837Sdelphij   data from the input buffer will be copied to the output buffer.  In that
91230837Sdelphij   case, all further file reads will be directly to either the output buffer or
92230837Sdelphij   a user buffer.  If decompressing, the inflate state will be initialized.
93230837Sdelphij   gz_look() will return 0 on success or -1 on failure. */
94230837Sdelphijlocal int gz_look(state)
95205194Sdelphij    gz_statep state;
96205194Sdelphij{
97205194Sdelphij    z_streamp strm = &(state->strm);
98205194Sdelphij
99205194Sdelphij    /* allocate read buffers and inflate memory */
100205194Sdelphij    if (state->size == 0) {
101205194Sdelphij        /* allocate buffers */
102250224Sdelphij        state->in = (unsigned char *)malloc(state->want);
103250224Sdelphij        state->out = (unsigned char *)malloc(state->want << 1);
104205194Sdelphij        if (state->in == NULL || state->out == NULL) {
105311285Sdelphij            free(state->out);
106311285Sdelphij            free(state->in);
107205194Sdelphij            gz_error(state, Z_MEM_ERROR, "out of memory");
108205194Sdelphij            return -1;
109205194Sdelphij        }
110205194Sdelphij        state->size = state->want;
111205194Sdelphij
112205194Sdelphij        /* allocate inflate memory */
113205194Sdelphij        state->strm.zalloc = Z_NULL;
114205194Sdelphij        state->strm.zfree = Z_NULL;
115205194Sdelphij        state->strm.opaque = Z_NULL;
116205194Sdelphij        state->strm.avail_in = 0;
117205194Sdelphij        state->strm.next_in = Z_NULL;
118230837Sdelphij        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
119205194Sdelphij            free(state->out);
120205194Sdelphij            free(state->in);
121205194Sdelphij            state->size = 0;
122205194Sdelphij            gz_error(state, Z_MEM_ERROR, "out of memory");
123205194Sdelphij            return -1;
124205194Sdelphij        }
125205194Sdelphij    }
126205194Sdelphij
127230837Sdelphij    /* get at least the magic bytes in the input buffer */
128230837Sdelphij    if (strm->avail_in < 2) {
129205194Sdelphij        if (gz_avail(state) == -1)
130205194Sdelphij            return -1;
131205194Sdelphij        if (strm->avail_in == 0)
132205194Sdelphij            return 0;
133205194Sdelphij    }
134205194Sdelphij
135230837Sdelphij    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
136230837Sdelphij       a logical dilemma here when considering the case of a partially written
137230837Sdelphij       gzip file, to wit, if a single 31 byte is written, then we cannot tell
138230837Sdelphij       whether this is a single-byte file, or just a partially written gzip
139230837Sdelphij       file -- for here we assume that if a gzip file is being written, then
140230837Sdelphij       the header will be written in a single operation, so that reading a
141230837Sdelphij       single byte is sufficient indication that it is not a gzip file) */
142230837Sdelphij    if (strm->avail_in > 1 &&
143230837Sdelphij            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
144230837Sdelphij        inflateReset(strm);
145230837Sdelphij        state->how = GZIP;
146230837Sdelphij        state->direct = 0;
147230837Sdelphij        return 0;
148230837Sdelphij    }
149205194Sdelphij
150230837Sdelphij    /* no gzip header -- if we were decoding gzip before, then this is trailing
151230837Sdelphij       garbage.  Ignore the trailing garbage and finish. */
152230837Sdelphij    if (state->direct == 0) {
153230837Sdelphij        strm->avail_in = 0;
154230837Sdelphij        state->eof = 1;
155230837Sdelphij        state->x.have = 0;
156230837Sdelphij        return 0;
157205194Sdelphij    }
158205194Sdelphij
159230837Sdelphij    /* doing raw i/o, copy any leftover input to output -- this assumes that
160230837Sdelphij       the output buffer is larger than the input buffer, which also assures
161230837Sdelphij       space for gzungetc() */
162230837Sdelphij    state->x.next = state->out;
163205194Sdelphij    if (strm->avail_in) {
164230837Sdelphij        memcpy(state->x.next, strm->next_in, strm->avail_in);
165230837Sdelphij        state->x.have = strm->avail_in;
166205194Sdelphij        strm->avail_in = 0;
167205194Sdelphij    }
168205194Sdelphij    state->how = COPY;
169205194Sdelphij    state->direct = 1;
170205194Sdelphij    return 0;
171205194Sdelphij}
172205194Sdelphij
173205194Sdelphij/* Decompress from input to the provided next_out and avail_out in the state.
174230837Sdelphij   On return, state->x.have and state->x.next point to the just decompressed
175230837Sdelphij   data.  If the gzip stream completes, state->how is reset to LOOK to look for
176230837Sdelphij   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
177230837Sdelphij   on success, -1 on failure. */
178205194Sdelphijlocal int gz_decomp(state)
179205194Sdelphij    gz_statep state;
180205194Sdelphij{
181230837Sdelphij    int ret = Z_OK;
182205194Sdelphij    unsigned had;
183205194Sdelphij    z_streamp strm = &(state->strm);
184205194Sdelphij
185205194Sdelphij    /* fill output buffer up to end of deflate stream */
186205194Sdelphij    had = strm->avail_out;
187205194Sdelphij    do {
188205194Sdelphij        /* get more input for inflate() */
189205194Sdelphij        if (strm->avail_in == 0 && gz_avail(state) == -1)
190205194Sdelphij            return -1;
191205194Sdelphij        if (strm->avail_in == 0) {
192230837Sdelphij            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
193230837Sdelphij            break;
194205194Sdelphij        }
195205194Sdelphij
196205194Sdelphij        /* decompress and handle errors */
197205194Sdelphij        ret = inflate(strm, Z_NO_FLUSH);
198205194Sdelphij        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
199205194Sdelphij            gz_error(state, Z_STREAM_ERROR,
200230837Sdelphij                     "internal error: inflate stream corrupt");
201205194Sdelphij            return -1;
202205194Sdelphij        }
203205194Sdelphij        if (ret == Z_MEM_ERROR) {
204205194Sdelphij            gz_error(state, Z_MEM_ERROR, "out of memory");
205205194Sdelphij            return -1;
206205194Sdelphij        }
207205194Sdelphij        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
208205194Sdelphij            gz_error(state, Z_DATA_ERROR,
209230837Sdelphij                     strm->msg == NULL ? "compressed data error" : strm->msg);
210205194Sdelphij            return -1;
211205194Sdelphij        }
212205194Sdelphij    } while (strm->avail_out && ret != Z_STREAM_END);
213205194Sdelphij
214230837Sdelphij    /* update available output */
215230837Sdelphij    state->x.have = had - strm->avail_out;
216230837Sdelphij    state->x.next = strm->next_out - state->x.have;
217205194Sdelphij
218230837Sdelphij    /* if the gzip stream completed successfully, look for another */
219230837Sdelphij    if (ret == Z_STREAM_END)
220230837Sdelphij        state->how = LOOK;
221205194Sdelphij
222205194Sdelphij    /* good decompression */
223205194Sdelphij    return 0;
224205194Sdelphij}
225205194Sdelphij
226230837Sdelphij/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
227205194Sdelphij   Data is either copied from the input file or decompressed from the input
228205194Sdelphij   file depending on state->how.  If state->how is LOOK, then a gzip header is
229230837Sdelphij   looked for to determine whether to copy or decompress.  Returns -1 on error,
230230837Sdelphij   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
231230837Sdelphij   end of the input file has been reached and all data has been processed.  */
232230837Sdelphijlocal int gz_fetch(state)
233205194Sdelphij    gz_statep state;
234205194Sdelphij{
235205194Sdelphij    z_streamp strm = &(state->strm);
236205194Sdelphij
237230837Sdelphij    do {
238230837Sdelphij        switch(state->how) {
239230837Sdelphij        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
240230837Sdelphij            if (gz_look(state) == -1)
241230837Sdelphij                return -1;
242230837Sdelphij            if (state->how == LOOK)
243230837Sdelphij                return 0;
244230837Sdelphij            break;
245230837Sdelphij        case COPY:      /* -> COPY */
246230837Sdelphij            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
247230837Sdelphij                    == -1)
248230837Sdelphij                return -1;
249230837Sdelphij            state->x.next = state->out;
250205194Sdelphij            return 0;
251230837Sdelphij        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
252230837Sdelphij            strm->avail_out = state->size << 1;
253230837Sdelphij            strm->next_out = state->out;
254230837Sdelphij            if (gz_decomp(state) == -1)
255230837Sdelphij                return -1;
256230837Sdelphij        }
257230837Sdelphij    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
258205194Sdelphij    return 0;
259205194Sdelphij}
260205194Sdelphij
261205194Sdelphij/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
262205194Sdelphijlocal int gz_skip(state, len)
263205194Sdelphij    gz_statep state;
264205194Sdelphij    z_off64_t len;
265205194Sdelphij{
266205194Sdelphij    unsigned n;
267205194Sdelphij
268205194Sdelphij    /* skip over len bytes or reach end-of-file, whichever comes first */
269205194Sdelphij    while (len)
270205194Sdelphij        /* skip over whatever is in output buffer */
271230837Sdelphij        if (state->x.have) {
272230837Sdelphij            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
273230837Sdelphij                (unsigned)len : state->x.have;
274230837Sdelphij            state->x.have -= n;
275230837Sdelphij            state->x.next += n;
276230837Sdelphij            state->x.pos += n;
277205194Sdelphij            len -= n;
278205194Sdelphij        }
279205194Sdelphij
280205194Sdelphij        /* output buffer empty -- return if we're at the end of the input */
281205194Sdelphij        else if (state->eof && state->strm.avail_in == 0)
282205194Sdelphij            break;
283205194Sdelphij
284205194Sdelphij        /* need more data to skip -- load up output buffer */
285205194Sdelphij        else {
286205194Sdelphij            /* get more output, looking for header if required */
287230837Sdelphij            if (gz_fetch(state) == -1)
288205194Sdelphij                return -1;
289205194Sdelphij        }
290205194Sdelphij    return 0;
291205194Sdelphij}
292205194Sdelphij
293311285Sdelphij/* Read len bytes into buf from file, or less than len up to the end of the
294311285Sdelphij   input.  Return the number of bytes read.  If zero is returned, either the
295311285Sdelphij   end of file was reached, or there was an error.  state->err must be
296311285Sdelphij   consulted in that case to determine which. */
297311285Sdelphijlocal z_size_t gz_read(state, buf, len)
298311285Sdelphij    gz_statep state;
299205194Sdelphij    voidp buf;
300311285Sdelphij    z_size_t len;
301205194Sdelphij{
302311285Sdelphij    z_size_t got;
303311285Sdelphij    unsigned n;
304205194Sdelphij
305205194Sdelphij    /* if len is zero, avoid unnecessary operations */
306205194Sdelphij    if (len == 0)
307205194Sdelphij        return 0;
308205194Sdelphij
309205194Sdelphij    /* process a skip request */
310205194Sdelphij    if (state->seek) {
311205194Sdelphij        state->seek = 0;
312205194Sdelphij        if (gz_skip(state, state->skip) == -1)
313311285Sdelphij            return 0;
314205194Sdelphij    }
315205194Sdelphij
316205194Sdelphij    /* get len bytes to buf, or less than len if at the end */
317205194Sdelphij    got = 0;
318205194Sdelphij    do {
319311285Sdelphij        /* set n to the maximum amount of len that fits in an unsigned int */
320311285Sdelphij        n = -1;
321311285Sdelphij        if (n > len)
322311285Sdelphij            n = len;
323311285Sdelphij
324205194Sdelphij        /* first just try copying data from the output buffer */
325230837Sdelphij        if (state->x.have) {
326311285Sdelphij            if (state->x.have < n)
327311285Sdelphij                n = state->x.have;
328230837Sdelphij            memcpy(buf, state->x.next, n);
329230837Sdelphij            state->x.next += n;
330230837Sdelphij            state->x.have -= n;
331205194Sdelphij        }
332205194Sdelphij
333205194Sdelphij        /* output buffer empty -- return if we're at the end of the input */
334311285Sdelphij        else if (state->eof && state->strm.avail_in == 0) {
335230837Sdelphij            state->past = 1;        /* tried to read past end */
336205194Sdelphij            break;
337230837Sdelphij        }
338205194Sdelphij
339205194Sdelphij        /* need output data -- for small len or new stream load up our output
340205194Sdelphij           buffer */
341311285Sdelphij        else if (state->how == LOOK || n < (state->size << 1)) {
342205194Sdelphij            /* get more output, looking for header if required */
343230837Sdelphij            if (gz_fetch(state) == -1)
344311285Sdelphij                return 0;
345237248Sdelphij            continue;       /* no progress yet -- go back to copy above */
346205194Sdelphij            /* the copy above assures that we will leave with space in the
347205194Sdelphij               output buffer, allowing at least one gzungetc() to succeed */
348205194Sdelphij        }
349205194Sdelphij
350205194Sdelphij        /* large len -- read directly into user buffer */
351205194Sdelphij        else if (state->how == COPY) {      /* read directly */
352311285Sdelphij            if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
353311285Sdelphij                return 0;
354205194Sdelphij        }
355205194Sdelphij
356205194Sdelphij        /* large len -- decompress directly into user buffer */
357205194Sdelphij        else {  /* state->how == GZIP */
358311285Sdelphij            state->strm.avail_out = n;
359311285Sdelphij            state->strm.next_out = (unsigned char *)buf;
360205194Sdelphij            if (gz_decomp(state) == -1)
361311285Sdelphij                return 0;
362230837Sdelphij            n = state->x.have;
363230837Sdelphij            state->x.have = 0;
364205194Sdelphij        }
365205194Sdelphij
366205194Sdelphij        /* update progress */
367205194Sdelphij        len -= n;
368205194Sdelphij        buf = (char *)buf + n;
369205194Sdelphij        got += n;
370230837Sdelphij        state->x.pos += n;
371205194Sdelphij    } while (len);
372205194Sdelphij
373311285Sdelphij    /* return number of bytes read into user buffer */
374311285Sdelphij    return got;
375205194Sdelphij}
376205194Sdelphij
377205194Sdelphij/* -- see zlib.h -- */
378311285Sdelphijint ZEXPORT gzread(file, buf, len)
379311285Sdelphij    gzFile file;
380311285Sdelphij    voidp buf;
381311285Sdelphij    unsigned len;
382311285Sdelphij{
383311285Sdelphij    gz_statep state;
384311285Sdelphij
385311285Sdelphij    /* get internal structure */
386311285Sdelphij    if (file == NULL)
387311285Sdelphij        return -1;
388311285Sdelphij    state = (gz_statep)file;
389311285Sdelphij
390311285Sdelphij    /* check that we're reading and that there's no (serious) error */
391311285Sdelphij    if (state->mode != GZ_READ ||
392311285Sdelphij            (state->err != Z_OK && state->err != Z_BUF_ERROR))
393311285Sdelphij        return -1;
394311285Sdelphij
395311285Sdelphij    /* since an int is returned, make sure len fits in one, otherwise return
396311285Sdelphij       with an error (this avoids a flaw in the interface) */
397311285Sdelphij    if ((int)len < 0) {
398311285Sdelphij        gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
399311285Sdelphij        return -1;
400311285Sdelphij    }
401311285Sdelphij
402311285Sdelphij    /* read len or fewer bytes to buf */
403311285Sdelphij    len = gz_read(state, buf, len);
404311285Sdelphij
405311285Sdelphij    /* check for an error */
406311285Sdelphij    if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
407311285Sdelphij        return -1;
408311285Sdelphij
409311285Sdelphij    /* return the number of bytes read (this is assured to fit in an int) */
410311285Sdelphij    return (int)len;
411311285Sdelphij}
412311285Sdelphij
413311285Sdelphij/* -- see zlib.h -- */
414311285Sdelphijz_size_t ZEXPORT gzfread(buf, size, nitems, file)
415311285Sdelphij    voidp buf;
416311285Sdelphij    z_size_t size;
417311285Sdelphij    z_size_t nitems;
418311285Sdelphij    gzFile file;
419311285Sdelphij{
420311285Sdelphij    z_size_t len;
421311285Sdelphij    gz_statep state;
422311285Sdelphij
423311285Sdelphij    /* get internal structure */
424311285Sdelphij    if (file == NULL)
425311285Sdelphij        return 0;
426311285Sdelphij    state = (gz_statep)file;
427311285Sdelphij
428311285Sdelphij    /* check that we're reading and that there's no (serious) error */
429311285Sdelphij    if (state->mode != GZ_READ ||
430311285Sdelphij            (state->err != Z_OK && state->err != Z_BUF_ERROR))
431311285Sdelphij        return 0;
432311285Sdelphij
433311285Sdelphij    /* compute bytes to read -- error on overflow */
434311285Sdelphij    len = nitems * size;
435311285Sdelphij    if (size && len / size != nitems) {
436311285Sdelphij        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
437311285Sdelphij        return 0;
438311285Sdelphij    }
439311285Sdelphij
440311285Sdelphij    /* read len or fewer bytes to buf, return the number of full items read */
441311285Sdelphij    return len ? gz_read(state, buf, len) / size : 0;
442311285Sdelphij}
443311285Sdelphij
444311285Sdelphij/* -- see zlib.h -- */
445250224Sdelphij#ifdef Z_PREFIX_SET
446250224Sdelphij#  undef z_gzgetc
447250224Sdelphij#else
448250224Sdelphij#  undef gzgetc
449250224Sdelphij#endif
450237248Sdelphijint ZEXPORT gzgetc(file)
451205194Sdelphij    gzFile file;
452205194Sdelphij{
453205194Sdelphij    int ret;
454205194Sdelphij    unsigned char buf[1];
455205194Sdelphij    gz_statep state;
456205194Sdelphij
457205194Sdelphij    /* get internal structure */
458205194Sdelphij    if (file == NULL)
459205194Sdelphij        return -1;
460205194Sdelphij    state = (gz_statep)file;
461205194Sdelphij
462230837Sdelphij    /* check that we're reading and that there's no (serious) error */
463230837Sdelphij    if (state->mode != GZ_READ ||
464230837Sdelphij        (state->err != Z_OK && state->err != Z_BUF_ERROR))
465205194Sdelphij        return -1;
466205194Sdelphij
467205194Sdelphij    /* try output buffer (no need to check for skip request) */
468230837Sdelphij    if (state->x.have) {
469230837Sdelphij        state->x.have--;
470230837Sdelphij        state->x.pos++;
471230837Sdelphij        return *(state->x.next)++;
472205194Sdelphij    }
473205194Sdelphij
474311285Sdelphij    /* nothing there -- try gz_read() */
475311285Sdelphij    ret = gz_read(state, buf, 1);
476205194Sdelphij    return ret < 1 ? -1 : buf[0];
477205194Sdelphij}
478205194Sdelphij
479237248Sdelphijint ZEXPORT gzgetc_(file)
480230837SdelphijgzFile file;
481230837Sdelphij{
482237248Sdelphij    return gzgetc(file);
483237248Sdelphij}
484230837Sdelphij
485205194Sdelphij/* -- see zlib.h -- */
486205194Sdelphijint ZEXPORT gzungetc(c, file)
487205194Sdelphij    int c;
488205194Sdelphij    gzFile file;
489205194Sdelphij{
490205194Sdelphij    gz_statep state;
491205194Sdelphij
492205194Sdelphij    /* get internal structure */
493205194Sdelphij    if (file == NULL)
494205194Sdelphij        return -1;
495205194Sdelphij    state = (gz_statep)file;
496205194Sdelphij
497230837Sdelphij    /* check that we're reading and that there's no (serious) error */
498230837Sdelphij    if (state->mode != GZ_READ ||
499230837Sdelphij        (state->err != Z_OK && state->err != Z_BUF_ERROR))
500205194Sdelphij        return -1;
501205194Sdelphij
502205194Sdelphij    /* process a skip request */
503205194Sdelphij    if (state->seek) {
504205194Sdelphij        state->seek = 0;
505205194Sdelphij        if (gz_skip(state, state->skip) == -1)
506205194Sdelphij            return -1;
507205194Sdelphij    }
508205194Sdelphij
509205194Sdelphij    /* can't push EOF */
510205194Sdelphij    if (c < 0)
511205194Sdelphij        return -1;
512205194Sdelphij
513205194Sdelphij    /* if output buffer empty, put byte at end (allows more pushing) */
514230837Sdelphij    if (state->x.have == 0) {
515230837Sdelphij        state->x.have = 1;
516230837Sdelphij        state->x.next = state->out + (state->size << 1) - 1;
517311285Sdelphij        state->x.next[0] = (unsigned char)c;
518230837Sdelphij        state->x.pos--;
519230837Sdelphij        state->past = 0;
520205194Sdelphij        return c;
521205194Sdelphij    }
522205194Sdelphij
523205194Sdelphij    /* if no room, give up (must have already done a gzungetc()) */
524230837Sdelphij    if (state->x.have == (state->size << 1)) {
525230837Sdelphij        gz_error(state, Z_DATA_ERROR, "out of room to push characters");
526205194Sdelphij        return -1;
527205194Sdelphij    }
528205194Sdelphij
529205194Sdelphij    /* slide output data if needed and insert byte before existing data */
530230837Sdelphij    if (state->x.next == state->out) {
531230837Sdelphij        unsigned char *src = state->out + state->x.have;
532205194Sdelphij        unsigned char *dest = state->out + (state->size << 1);
533205194Sdelphij        while (src > state->out)
534205194Sdelphij            *--dest = *--src;
535230837Sdelphij        state->x.next = dest;
536205194Sdelphij    }
537230837Sdelphij    state->x.have++;
538230837Sdelphij    state->x.next--;
539311285Sdelphij    state->x.next[0] = (unsigned char)c;
540230837Sdelphij    state->x.pos--;
541230837Sdelphij    state->past = 0;
542205194Sdelphij    return c;
543205194Sdelphij}
544205194Sdelphij
545205194Sdelphij/* -- see zlib.h -- */
546205194Sdelphijchar * ZEXPORT gzgets(file, buf, len)
547205194Sdelphij    gzFile file;
548205194Sdelphij    char *buf;
549205194Sdelphij    int len;
550205194Sdelphij{
551205194Sdelphij    unsigned left, n;
552205194Sdelphij    char *str;
553205194Sdelphij    unsigned char *eol;
554205194Sdelphij    gz_statep state;
555205194Sdelphij
556205194Sdelphij    /* check parameters and get internal structure */
557205194Sdelphij    if (file == NULL || buf == NULL || len < 1)
558205194Sdelphij        return NULL;
559205194Sdelphij    state = (gz_statep)file;
560205194Sdelphij
561230837Sdelphij    /* check that we're reading and that there's no (serious) error */
562230837Sdelphij    if (state->mode != GZ_READ ||
563230837Sdelphij        (state->err != Z_OK && state->err != Z_BUF_ERROR))
564205194Sdelphij        return NULL;
565205194Sdelphij
566205194Sdelphij    /* process a skip request */
567205194Sdelphij    if (state->seek) {
568205194Sdelphij        state->seek = 0;
569205194Sdelphij        if (gz_skip(state, state->skip) == -1)
570205194Sdelphij            return NULL;
571205194Sdelphij    }
572205194Sdelphij
573205194Sdelphij    /* copy output bytes up to new line or len - 1, whichever comes first --
574205194Sdelphij       append a terminating zero to the string (we don't check for a zero in
575205194Sdelphij       the contents, let the user worry about that) */
576205194Sdelphij    str = buf;
577205194Sdelphij    left = (unsigned)len - 1;
578205194Sdelphij    if (left) do {
579205194Sdelphij        /* assure that something is in the output buffer */
580230837Sdelphij        if (state->x.have == 0 && gz_fetch(state) == -1)
581230837Sdelphij            return NULL;                /* error */
582230837Sdelphij        if (state->x.have == 0) {       /* end of file */
583230837Sdelphij            state->past = 1;            /* read past end */
584230837Sdelphij            break;                      /* return what we have */
585205194Sdelphij        }
586205194Sdelphij
587205194Sdelphij        /* look for end-of-line in current output buffer */
588230837Sdelphij        n = state->x.have > left ? left : state->x.have;
589250224Sdelphij        eol = (unsigned char *)memchr(state->x.next, '\n', n);
590205194Sdelphij        if (eol != NULL)
591230837Sdelphij            n = (unsigned)(eol - state->x.next) + 1;
592205194Sdelphij
593205194Sdelphij        /* copy through end-of-line, or remainder if not found */
594230837Sdelphij        memcpy(buf, state->x.next, n);
595230837Sdelphij        state->x.have -= n;
596230837Sdelphij        state->x.next += n;
597230837Sdelphij        state->x.pos += n;
598205194Sdelphij        left -= n;
599205194Sdelphij        buf += n;
600205194Sdelphij    } while (left && eol == NULL);
601205194Sdelphij
602230837Sdelphij    /* return terminated string, or if nothing, end of file */
603230837Sdelphij    if (buf == str)
604230837Sdelphij        return NULL;
605205194Sdelphij    buf[0] = 0;
606205194Sdelphij    return str;
607205194Sdelphij}
608205194Sdelphij
609205194Sdelphij/* -- see zlib.h -- */
610205194Sdelphijint ZEXPORT gzdirect(file)
611205194Sdelphij    gzFile file;
612205194Sdelphij{
613205194Sdelphij    gz_statep state;
614205194Sdelphij
615205194Sdelphij    /* get internal structure */
616205194Sdelphij    if (file == NULL)
617205194Sdelphij        return 0;
618205194Sdelphij    state = (gz_statep)file;
619205194Sdelphij
620205194Sdelphij    /* if the state is not known, but we can find out, then do so (this is
621205194Sdelphij       mainly for right after a gzopen() or gzdopen()) */
622230837Sdelphij    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
623230837Sdelphij        (void)gz_look(state);
624205194Sdelphij
625230837Sdelphij    /* return 1 if transparent, 0 if processing a gzip stream */
626205194Sdelphij    return state->direct;
627205194Sdelphij}
628205194Sdelphij
629205194Sdelphij/* -- see zlib.h -- */
630205194Sdelphijint ZEXPORT gzclose_r(file)
631205194Sdelphij    gzFile file;
632205194Sdelphij{
633230837Sdelphij    int ret, err;
634205194Sdelphij    gz_statep state;
635205194Sdelphij
636205194Sdelphij    /* get internal structure */
637205194Sdelphij    if (file == NULL)
638205194Sdelphij        return Z_STREAM_ERROR;
639205194Sdelphij    state = (gz_statep)file;
640205194Sdelphij
641205194Sdelphij    /* check that we're reading */
642205194Sdelphij    if (state->mode != GZ_READ)
643205194Sdelphij        return Z_STREAM_ERROR;
644205194Sdelphij
645205194Sdelphij    /* free memory and close file */
646205194Sdelphij    if (state->size) {
647205194Sdelphij        inflateEnd(&(state->strm));
648205194Sdelphij        free(state->out);
649205194Sdelphij        free(state->in);
650205194Sdelphij    }
651230837Sdelphij    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
652205194Sdelphij    gz_error(state, Z_OK, NULL);
653205194Sdelphij    free(state->path);
654205194Sdelphij    ret = close(state->fd);
655205194Sdelphij    free(state);
656230837Sdelphij    return ret ? Z_ERRNO : err;
657205194Sdelphij}
658