1205194Sdelphij/* gzread.c -- zlib functions for reading gzip files
2250261Sdelphij * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
3205194Sdelphij * For conditions of distribution and use, see copyright notice in zlib.h
4205194Sdelphij */
5205194Sdelphij
6206002Sdelphij/* $FreeBSD$ */
7206002Sdelphij
8205194Sdelphij#include "gzguts.h"
9205305Sdelphij#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));
14237410Sdelphijlocal int gz_look OF((gz_statep));
15205194Sdelphijlocal int gz_decomp OF((gz_statep));
16237410Sdelphijlocal int gz_fetch OF((gz_statep));
17205194Sdelphijlocal int gz_skip OF((gz_statep, z_off64_t));
18205194Sdelphij
19205194Sdelphij/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
20205194Sdelphij   state->fd, and update state->eof, state->err, and state->msg as appropriate.
21205194Sdelphij   This function needs to loop on read(), since read() is not guaranteed to
22205194Sdelphij   read the number of bytes requested, depending on the type of descriptor. */
23205194Sdelphijlocal int gz_load(state, buf, len, have)
24205194Sdelphij    gz_statep state;
25205194Sdelphij    unsigned char *buf;
26205194Sdelphij    unsigned len;
27205194Sdelphij    unsigned *have;
28205194Sdelphij{
29205194Sdelphij    int ret;
30205194Sdelphij
31205194Sdelphij    *have = 0;
32205194Sdelphij    do {
33205194Sdelphij        ret = read(state->fd, buf + *have, len - *have);
34205194Sdelphij        if (ret <= 0)
35205194Sdelphij            break;
36205194Sdelphij        *have += ret;
37205194Sdelphij    } while (*have < len);
38205194Sdelphij    if (ret < 0) {
39205194Sdelphij        gz_error(state, Z_ERRNO, zstrerror());
40205194Sdelphij        return -1;
41205194Sdelphij    }
42205194Sdelphij    if (ret == 0)
43205194Sdelphij        state->eof = 1;
44205194Sdelphij    return 0;
45205194Sdelphij}
46205194Sdelphij
47205194Sdelphij/* Load up input buffer and set eof flag if last data loaded -- return -1 on
48205194Sdelphij   error, 0 otherwise.  Note that the eof flag is set when the end of the input
49205194Sdelphij   file is reached, even though there may be unused data in the buffer.  Once
50205194Sdelphij   that data has been used, no more attempts will be made to read the file.
51237410Sdelphij   If strm->avail_in != 0, then the current data is moved to the beginning of
52237410Sdelphij   the input buffer, and then the remainder of the buffer is loaded with the
53237410Sdelphij   available data from the input file. */
54205194Sdelphijlocal int gz_avail(state)
55205194Sdelphij    gz_statep state;
56205194Sdelphij{
57237410Sdelphij    unsigned got;
58205194Sdelphij    z_streamp strm = &(state->strm);
59205194Sdelphij
60237410Sdelphij    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
61205194Sdelphij        return -1;
62205194Sdelphij    if (state->eof == 0) {
63237410Sdelphij        if (strm->avail_in) {       /* copy what's there to the start */
64250261Sdelphij            unsigned char *p = state->in;
65250261Sdelphij            unsigned const char *q = strm->next_in;
66237410Sdelphij            unsigned n = strm->avail_in;
67237410Sdelphij            do {
68237410Sdelphij                *p++ = *q++;
69237410Sdelphij            } while (--n);
70237410Sdelphij        }
71237410Sdelphij        if (gz_load(state, state->in + strm->avail_in,
72237410Sdelphij                    state->size - strm->avail_in, &got) == -1)
73205194Sdelphij            return -1;
74237410Sdelphij        strm->avail_in += got;
75205194Sdelphij        strm->next_in = state->in;
76205194Sdelphij    }
77205194Sdelphij    return 0;
78205194Sdelphij}
79205194Sdelphij
80237410Sdelphij/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
81205194Sdelphij   If this is the first time in, allocate required memory.  state->how will be
82205194Sdelphij   left unchanged if there is no more input data available, will be set to COPY
83205194Sdelphij   if there is no gzip header and direct copying will be performed, or it will
84237410Sdelphij   be set to GZIP for decompression.  If direct copying, then leftover input
85237410Sdelphij   data from the input buffer will be copied to the output buffer.  In that
86237410Sdelphij   case, all further file reads will be directly to either the output buffer or
87237410Sdelphij   a user buffer.  If decompressing, the inflate state will be initialized.
88237410Sdelphij   gz_look() will return 0 on success or -1 on failure. */
89237410Sdelphijlocal int gz_look(state)
90205194Sdelphij    gz_statep state;
91205194Sdelphij{
92205194Sdelphij    z_streamp strm = &(state->strm);
93205194Sdelphij
94205194Sdelphij    /* allocate read buffers and inflate memory */
95205194Sdelphij    if (state->size == 0) {
96205194Sdelphij        /* allocate buffers */
97250261Sdelphij        state->in = (unsigned char *)malloc(state->want);
98250261Sdelphij        state->out = (unsigned char *)malloc(state->want << 1);
99205194Sdelphij        if (state->in == NULL || state->out == NULL) {
100205194Sdelphij            if (state->out != NULL)
101205194Sdelphij                free(state->out);
102205194Sdelphij            if (state->in != NULL)
103205194Sdelphij                free(state->in);
104205194Sdelphij            gz_error(state, Z_MEM_ERROR, "out of memory");
105205194Sdelphij            return -1;
106205194Sdelphij        }
107205194Sdelphij        state->size = state->want;
108205194Sdelphij
109205194Sdelphij        /* allocate inflate memory */
110205194Sdelphij        state->strm.zalloc = Z_NULL;
111205194Sdelphij        state->strm.zfree = Z_NULL;
112205194Sdelphij        state->strm.opaque = Z_NULL;
113205194Sdelphij        state->strm.avail_in = 0;
114205194Sdelphij        state->strm.next_in = Z_NULL;
115237410Sdelphij        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
116205194Sdelphij            free(state->out);
117205194Sdelphij            free(state->in);
118205194Sdelphij            state->size = 0;
119205194Sdelphij            gz_error(state, Z_MEM_ERROR, "out of memory");
120205194Sdelphij            return -1;
121205194Sdelphij        }
122205194Sdelphij    }
123205194Sdelphij
124237410Sdelphij    /* get at least the magic bytes in the input buffer */
125237410Sdelphij    if (strm->avail_in < 2) {
126205194Sdelphij        if (gz_avail(state) == -1)
127205194Sdelphij            return -1;
128205194Sdelphij        if (strm->avail_in == 0)
129205194Sdelphij            return 0;
130205194Sdelphij    }
131205194Sdelphij
132237410Sdelphij    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
133237410Sdelphij       a logical dilemma here when considering the case of a partially written
134237410Sdelphij       gzip file, to wit, if a single 31 byte is written, then we cannot tell
135237410Sdelphij       whether this is a single-byte file, or just a partially written gzip
136237410Sdelphij       file -- for here we assume that if a gzip file is being written, then
137237410Sdelphij       the header will be written in a single operation, so that reading a
138237410Sdelphij       single byte is sufficient indication that it is not a gzip file) */
139237410Sdelphij    if (strm->avail_in > 1 &&
140237410Sdelphij            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
141237410Sdelphij        inflateReset(strm);
142237410Sdelphij        state->how = GZIP;
143237410Sdelphij        state->direct = 0;
144237410Sdelphij        return 0;
145237410Sdelphij    }
146205194Sdelphij
147237410Sdelphij    /* no gzip header -- if we were decoding gzip before, then this is trailing
148237410Sdelphij       garbage.  Ignore the trailing garbage and finish. */
149237410Sdelphij    if (state->direct == 0) {
150237410Sdelphij        strm->avail_in = 0;
151237410Sdelphij        state->eof = 1;
152237410Sdelphij        state->x.have = 0;
153237410Sdelphij        return 0;
154205194Sdelphij    }
155205194Sdelphij
156237410Sdelphij    /* doing raw i/o, copy any leftover input to output -- this assumes that
157237410Sdelphij       the output buffer is larger than the input buffer, which also assures
158237410Sdelphij       space for gzungetc() */
159237410Sdelphij    state->x.next = state->out;
160205194Sdelphij    if (strm->avail_in) {
161237410Sdelphij        memcpy(state->x.next, strm->next_in, strm->avail_in);
162237410Sdelphij        state->x.have = strm->avail_in;
163205194Sdelphij        strm->avail_in = 0;
164205194Sdelphij    }
165205194Sdelphij    state->how = COPY;
166205194Sdelphij    state->direct = 1;
167205194Sdelphij    return 0;
168205194Sdelphij}
169205194Sdelphij
170205194Sdelphij/* Decompress from input to the provided next_out and avail_out in the state.
171237410Sdelphij   On return, state->x.have and state->x.next point to the just decompressed
172237410Sdelphij   data.  If the gzip stream completes, state->how is reset to LOOK to look for
173237410Sdelphij   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
174237410Sdelphij   on success, -1 on failure. */
175205194Sdelphijlocal int gz_decomp(state)
176205194Sdelphij    gz_statep state;
177205194Sdelphij{
178237410Sdelphij    int ret = Z_OK;
179205194Sdelphij    unsigned had;
180205194Sdelphij    z_streamp strm = &(state->strm);
181205194Sdelphij
182205194Sdelphij    /* fill output buffer up to end of deflate stream */
183205194Sdelphij    had = strm->avail_out;
184205194Sdelphij    do {
185205194Sdelphij        /* get more input for inflate() */
186205194Sdelphij        if (strm->avail_in == 0 && gz_avail(state) == -1)
187205194Sdelphij            return -1;
188205194Sdelphij        if (strm->avail_in == 0) {
189237410Sdelphij            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
190237410Sdelphij            break;
191205194Sdelphij        }
192205194Sdelphij
193205194Sdelphij        /* decompress and handle errors */
194205194Sdelphij        ret = inflate(strm, Z_NO_FLUSH);
195205194Sdelphij        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
196205194Sdelphij            gz_error(state, Z_STREAM_ERROR,
197237410Sdelphij                     "internal error: inflate stream corrupt");
198205194Sdelphij            return -1;
199205194Sdelphij        }
200205194Sdelphij        if (ret == Z_MEM_ERROR) {
201205194Sdelphij            gz_error(state, Z_MEM_ERROR, "out of memory");
202205194Sdelphij            return -1;
203205194Sdelphij        }
204205194Sdelphij        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
205205194Sdelphij            gz_error(state, Z_DATA_ERROR,
206237410Sdelphij                     strm->msg == NULL ? "compressed data error" : strm->msg);
207205194Sdelphij            return -1;
208205194Sdelphij        }
209205194Sdelphij    } while (strm->avail_out && ret != Z_STREAM_END);
210205194Sdelphij
211237410Sdelphij    /* update available output */
212237410Sdelphij    state->x.have = had - strm->avail_out;
213237410Sdelphij    state->x.next = strm->next_out - state->x.have;
214205194Sdelphij
215237410Sdelphij    /* if the gzip stream completed successfully, look for another */
216237410Sdelphij    if (ret == Z_STREAM_END)
217237410Sdelphij        state->how = LOOK;
218205194Sdelphij
219205194Sdelphij    /* good decompression */
220205194Sdelphij    return 0;
221205194Sdelphij}
222205194Sdelphij
223237410Sdelphij/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
224205194Sdelphij   Data is either copied from the input file or decompressed from the input
225205194Sdelphij   file depending on state->how.  If state->how is LOOK, then a gzip header is
226237410Sdelphij   looked for to determine whether to copy or decompress.  Returns -1 on error,
227237410Sdelphij   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
228237410Sdelphij   end of the input file has been reached and all data has been processed.  */
229237410Sdelphijlocal int gz_fetch(state)
230205194Sdelphij    gz_statep state;
231205194Sdelphij{
232205194Sdelphij    z_streamp strm = &(state->strm);
233205194Sdelphij
234237410Sdelphij    do {
235237410Sdelphij        switch(state->how) {
236237410Sdelphij        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
237237410Sdelphij            if (gz_look(state) == -1)
238237410Sdelphij                return -1;
239237410Sdelphij            if (state->how == LOOK)
240237410Sdelphij                return 0;
241237410Sdelphij            break;
242237410Sdelphij        case COPY:      /* -> COPY */
243237410Sdelphij            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
244237410Sdelphij                    == -1)
245237410Sdelphij                return -1;
246237410Sdelphij            state->x.next = state->out;
247205194Sdelphij            return 0;
248237410Sdelphij        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
249237410Sdelphij            strm->avail_out = state->size << 1;
250237410Sdelphij            strm->next_out = state->out;
251237410Sdelphij            if (gz_decomp(state) == -1)
252237410Sdelphij                return -1;
253237410Sdelphij        }
254237410Sdelphij    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
255205194Sdelphij    return 0;
256205194Sdelphij}
257205194Sdelphij
258205194Sdelphij/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
259205194Sdelphijlocal int gz_skip(state, len)
260205194Sdelphij    gz_statep state;
261205194Sdelphij    z_off64_t len;
262205194Sdelphij{
263205194Sdelphij    unsigned n;
264205194Sdelphij
265205194Sdelphij    /* skip over len bytes or reach end-of-file, whichever comes first */
266205194Sdelphij    while (len)
267205194Sdelphij        /* skip over whatever is in output buffer */
268237410Sdelphij        if (state->x.have) {
269237410Sdelphij            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
270237410Sdelphij                (unsigned)len : state->x.have;
271237410Sdelphij            state->x.have -= n;
272237410Sdelphij            state->x.next += n;
273237410Sdelphij            state->x.pos += n;
274205194Sdelphij            len -= n;
275205194Sdelphij        }
276205194Sdelphij
277205194Sdelphij        /* output buffer empty -- return if we're at the end of the input */
278205194Sdelphij        else if (state->eof && state->strm.avail_in == 0)
279205194Sdelphij            break;
280205194Sdelphij
281205194Sdelphij        /* need more data to skip -- load up output buffer */
282205194Sdelphij        else {
283205194Sdelphij            /* get more output, looking for header if required */
284237410Sdelphij            if (gz_fetch(state) == -1)
285205194Sdelphij                return -1;
286205194Sdelphij        }
287205194Sdelphij    return 0;
288205194Sdelphij}
289205194Sdelphij
290205194Sdelphij/* -- see zlib.h -- */
291205194Sdelphijint ZEXPORT gzread(file, buf, len)
292205194Sdelphij    gzFile file;
293205194Sdelphij    voidp buf;
294205194Sdelphij    unsigned len;
295205194Sdelphij{
296205194Sdelphij    unsigned got, n;
297205194Sdelphij    gz_statep state;
298205194Sdelphij    z_streamp strm;
299205194Sdelphij
300205194Sdelphij    /* get internal structure */
301205194Sdelphij    if (file == NULL)
302205194Sdelphij        return -1;
303205194Sdelphij    state = (gz_statep)file;
304205194Sdelphij    strm = &(state->strm);
305205194Sdelphij
306237410Sdelphij    /* check that we're reading and that there's no (serious) error */
307237410Sdelphij    if (state->mode != GZ_READ ||
308237410Sdelphij            (state->err != Z_OK && state->err != Z_BUF_ERROR))
309205194Sdelphij        return -1;
310205194Sdelphij
311205194Sdelphij    /* since an int is returned, make sure len fits in one, otherwise return
312205194Sdelphij       with an error (this avoids the flaw in the interface) */
313205194Sdelphij    if ((int)len < 0) {
314237410Sdelphij        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
315205194Sdelphij        return -1;
316205194Sdelphij    }
317205194Sdelphij
318205194Sdelphij    /* if len is zero, avoid unnecessary operations */
319205194Sdelphij    if (len == 0)
320205194Sdelphij        return 0;
321205194Sdelphij
322205194Sdelphij    /* process a skip request */
323205194Sdelphij    if (state->seek) {
324205194Sdelphij        state->seek = 0;
325205194Sdelphij        if (gz_skip(state, state->skip) == -1)
326205194Sdelphij            return -1;
327205194Sdelphij    }
328205194Sdelphij
329205194Sdelphij    /* get len bytes to buf, or less than len if at the end */
330205194Sdelphij    got = 0;
331205194Sdelphij    do {
332205194Sdelphij        /* first just try copying data from the output buffer */
333237410Sdelphij        if (state->x.have) {
334237410Sdelphij            n = state->x.have > len ? len : state->x.have;
335237410Sdelphij            memcpy(buf, state->x.next, n);
336237410Sdelphij            state->x.next += n;
337237410Sdelphij            state->x.have -= n;
338205194Sdelphij        }
339205194Sdelphij
340205194Sdelphij        /* output buffer empty -- return if we're at the end of the input */
341237410Sdelphij        else if (state->eof && strm->avail_in == 0) {
342237410Sdelphij            state->past = 1;        /* tried to read past end */
343205194Sdelphij            break;
344237410Sdelphij        }
345205194Sdelphij
346205194Sdelphij        /* need output data -- for small len or new stream load up our output
347205194Sdelphij           buffer */
348205194Sdelphij        else if (state->how == LOOK || len < (state->size << 1)) {
349205194Sdelphij            /* get more output, looking for header if required */
350237410Sdelphij            if (gz_fetch(state) == -1)
351205194Sdelphij                return -1;
352237410Sdelphij            continue;       /* no progress yet -- go back to copy above */
353205194Sdelphij            /* the copy above assures that we will leave with space in the
354205194Sdelphij               output buffer, allowing at least one gzungetc() to succeed */
355205194Sdelphij        }
356205194Sdelphij
357205194Sdelphij        /* large len -- read directly into user buffer */
358205194Sdelphij        else if (state->how == COPY) {      /* read directly */
359250261Sdelphij            if (gz_load(state, (unsigned char *)buf, len, &n) == -1)
360205194Sdelphij                return -1;
361205194Sdelphij        }
362205194Sdelphij
363205194Sdelphij        /* large len -- decompress directly into user buffer */
364205194Sdelphij        else {  /* state->how == GZIP */
365205194Sdelphij            strm->avail_out = len;
366250261Sdelphij            strm->next_out = (unsigned char *)buf;
367205194Sdelphij            if (gz_decomp(state) == -1)
368205194Sdelphij                return -1;
369237410Sdelphij            n = state->x.have;
370237410Sdelphij            state->x.have = 0;
371205194Sdelphij        }
372205194Sdelphij
373205194Sdelphij        /* update progress */
374205194Sdelphij        len -= n;
375205194Sdelphij        buf = (char *)buf + n;
376205194Sdelphij        got += n;
377237410Sdelphij        state->x.pos += n;
378205194Sdelphij    } while (len);
379205194Sdelphij
380205194Sdelphij    /* return number of bytes read into user buffer (will fit in int) */
381205194Sdelphij    return (int)got;
382205194Sdelphij}
383205194Sdelphij
384205194Sdelphij/* -- see zlib.h -- */
385250261Sdelphij#ifdef Z_PREFIX_SET
386250261Sdelphij#  undef z_gzgetc
387250261Sdelphij#else
388250261Sdelphij#  undef gzgetc
389250261Sdelphij#endif
390205194Sdelphijint ZEXPORT gzgetc(file)
391205194Sdelphij    gzFile file;
392205194Sdelphij{
393205194Sdelphij    int ret;
394205194Sdelphij    unsigned char buf[1];
395205194Sdelphij    gz_statep state;
396205194Sdelphij
397205194Sdelphij    /* get internal structure */
398205194Sdelphij    if (file == NULL)
399205194Sdelphij        return -1;
400205194Sdelphij    state = (gz_statep)file;
401205194Sdelphij
402237410Sdelphij    /* check that we're reading and that there's no (serious) error */
403237410Sdelphij    if (state->mode != GZ_READ ||
404237410Sdelphij        (state->err != Z_OK && state->err != Z_BUF_ERROR))
405205194Sdelphij        return -1;
406205194Sdelphij
407205194Sdelphij    /* try output buffer (no need to check for skip request) */
408237410Sdelphij    if (state->x.have) {
409237410Sdelphij        state->x.have--;
410237410Sdelphij        state->x.pos++;
411237410Sdelphij        return *(state->x.next)++;
412205194Sdelphij    }
413205194Sdelphij
414205194Sdelphij    /* nothing there -- try gzread() */
415205194Sdelphij    ret = gzread(file, buf, 1);
416205194Sdelphij    return ret < 1 ? -1 : buf[0];
417205194Sdelphij}
418205194Sdelphij
419237410Sdelphijint ZEXPORT gzgetc_(file)
420237410SdelphijgzFile file;
421237410Sdelphij{
422237410Sdelphij    return gzgetc(file);
423237410Sdelphij}
424237410Sdelphij
425205194Sdelphij/* -- see zlib.h -- */
426205194Sdelphijint ZEXPORT gzungetc(c, file)
427205194Sdelphij    int c;
428205194Sdelphij    gzFile file;
429205194Sdelphij{
430205194Sdelphij    gz_statep state;
431205194Sdelphij
432205194Sdelphij    /* get internal structure */
433205194Sdelphij    if (file == NULL)
434205194Sdelphij        return -1;
435205194Sdelphij    state = (gz_statep)file;
436205194Sdelphij
437237410Sdelphij    /* check that we're reading and that there's no (serious) error */
438237410Sdelphij    if (state->mode != GZ_READ ||
439237410Sdelphij        (state->err != Z_OK && state->err != Z_BUF_ERROR))
440205194Sdelphij        return -1;
441205194Sdelphij
442205194Sdelphij    /* process a skip request */
443205194Sdelphij    if (state->seek) {
444205194Sdelphij        state->seek = 0;
445205194Sdelphij        if (gz_skip(state, state->skip) == -1)
446205194Sdelphij            return -1;
447205194Sdelphij    }
448205194Sdelphij
449205194Sdelphij    /* can't push EOF */
450205194Sdelphij    if (c < 0)
451205194Sdelphij        return -1;
452205194Sdelphij
453205194Sdelphij    /* if output buffer empty, put byte at end (allows more pushing) */
454237410Sdelphij    if (state->x.have == 0) {
455237410Sdelphij        state->x.have = 1;
456237410Sdelphij        state->x.next = state->out + (state->size << 1) - 1;
457237410Sdelphij        state->x.next[0] = c;
458237410Sdelphij        state->x.pos--;
459237410Sdelphij        state->past = 0;
460205194Sdelphij        return c;
461205194Sdelphij    }
462205194Sdelphij
463205194Sdelphij    /* if no room, give up (must have already done a gzungetc()) */
464237410Sdelphij    if (state->x.have == (state->size << 1)) {
465237410Sdelphij        gz_error(state, Z_DATA_ERROR, "out of room to push characters");
466205194Sdelphij        return -1;
467205194Sdelphij    }
468205194Sdelphij
469205194Sdelphij    /* slide output data if needed and insert byte before existing data */
470237410Sdelphij    if (state->x.next == state->out) {
471237410Sdelphij        unsigned char *src = state->out + state->x.have;
472205194Sdelphij        unsigned char *dest = state->out + (state->size << 1);
473205194Sdelphij        while (src > state->out)
474205194Sdelphij            *--dest = *--src;
475237410Sdelphij        state->x.next = dest;
476205194Sdelphij    }
477237410Sdelphij    state->x.have++;
478237410Sdelphij    state->x.next--;
479237410Sdelphij    state->x.next[0] = c;
480237410Sdelphij    state->x.pos--;
481237410Sdelphij    state->past = 0;
482205194Sdelphij    return c;
483205194Sdelphij}
484205194Sdelphij
485205194Sdelphij/* -- see zlib.h -- */
486205194Sdelphijchar * ZEXPORT gzgets(file, buf, len)
487205194Sdelphij    gzFile file;
488205194Sdelphij    char *buf;
489205194Sdelphij    int len;
490205194Sdelphij{
491205194Sdelphij    unsigned left, n;
492205194Sdelphij    char *str;
493205194Sdelphij    unsigned char *eol;
494205194Sdelphij    gz_statep state;
495205194Sdelphij
496205194Sdelphij    /* check parameters and get internal structure */
497205194Sdelphij    if (file == NULL || buf == NULL || len < 1)
498205194Sdelphij        return NULL;
499205194Sdelphij    state = (gz_statep)file;
500205194Sdelphij
501237410Sdelphij    /* check that we're reading and that there's no (serious) error */
502237410Sdelphij    if (state->mode != GZ_READ ||
503237410Sdelphij        (state->err != Z_OK && state->err != Z_BUF_ERROR))
504205194Sdelphij        return NULL;
505205194Sdelphij
506205194Sdelphij    /* process a skip request */
507205194Sdelphij    if (state->seek) {
508205194Sdelphij        state->seek = 0;
509205194Sdelphij        if (gz_skip(state, state->skip) == -1)
510205194Sdelphij            return NULL;
511205194Sdelphij    }
512205194Sdelphij
513205194Sdelphij    /* copy output bytes up to new line or len - 1, whichever comes first --
514205194Sdelphij       append a terminating zero to the string (we don't check for a zero in
515205194Sdelphij       the contents, let the user worry about that) */
516205194Sdelphij    str = buf;
517205194Sdelphij    left = (unsigned)len - 1;
518205194Sdelphij    if (left) do {
519205194Sdelphij        /* assure that something is in the output buffer */
520237410Sdelphij        if (state->x.have == 0 && gz_fetch(state) == -1)
521237410Sdelphij            return NULL;                /* error */
522237410Sdelphij        if (state->x.have == 0) {       /* end of file */
523237410Sdelphij            state->past = 1;            /* read past end */
524237410Sdelphij            break;                      /* return what we have */
525205194Sdelphij        }
526205194Sdelphij
527205194Sdelphij        /* look for end-of-line in current output buffer */
528237410Sdelphij        n = state->x.have > left ? left : state->x.have;
529250261Sdelphij        eol = (unsigned char *)memchr(state->x.next, '\n', n);
530205194Sdelphij        if (eol != NULL)
531237410Sdelphij            n = (unsigned)(eol - state->x.next) + 1;
532205194Sdelphij
533205194Sdelphij        /* copy through end-of-line, or remainder if not found */
534237410Sdelphij        memcpy(buf, state->x.next, n);
535237410Sdelphij        state->x.have -= n;
536237410Sdelphij        state->x.next += n;
537237410Sdelphij        state->x.pos += n;
538205194Sdelphij        left -= n;
539205194Sdelphij        buf += n;
540205194Sdelphij    } while (left && eol == NULL);
541205194Sdelphij
542237410Sdelphij    /* return terminated string, or if nothing, end of file */
543237410Sdelphij    if (buf == str)
544237410Sdelphij        return NULL;
545205194Sdelphij    buf[0] = 0;
546205194Sdelphij    return str;
547205194Sdelphij}
548205194Sdelphij
549205194Sdelphij/* -- see zlib.h -- */
550205194Sdelphijint ZEXPORT gzdirect(file)
551205194Sdelphij    gzFile file;
552205194Sdelphij{
553205194Sdelphij    gz_statep state;
554205194Sdelphij
555205194Sdelphij    /* get internal structure */
556205194Sdelphij    if (file == NULL)
557205194Sdelphij        return 0;
558205194Sdelphij    state = (gz_statep)file;
559205194Sdelphij
560205194Sdelphij    /* if the state is not known, but we can find out, then do so (this is
561205194Sdelphij       mainly for right after a gzopen() or gzdopen()) */
562237410Sdelphij    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
563237410Sdelphij        (void)gz_look(state);
564205194Sdelphij
565237410Sdelphij    /* return 1 if transparent, 0 if processing a gzip stream */
566205194Sdelphij    return state->direct;
567205194Sdelphij}
568205194Sdelphij
569205194Sdelphij/* -- see zlib.h -- */
570205194Sdelphijint ZEXPORT gzclose_r(file)
571205194Sdelphij    gzFile file;
572205194Sdelphij{
573237410Sdelphij    int ret, err;
574205194Sdelphij    gz_statep state;
575205194Sdelphij
576205194Sdelphij    /* get internal structure */
577205194Sdelphij    if (file == NULL)
578205194Sdelphij        return Z_STREAM_ERROR;
579205194Sdelphij    state = (gz_statep)file;
580205194Sdelphij
581205194Sdelphij    /* check that we're reading */
582205194Sdelphij    if (state->mode != GZ_READ)
583205194Sdelphij        return Z_STREAM_ERROR;
584205194Sdelphij
585205194Sdelphij    /* free memory and close file */
586205194Sdelphij    if (state->size) {
587205194Sdelphij        inflateEnd(&(state->strm));
588205194Sdelphij        free(state->out);
589205194Sdelphij        free(state->in);
590205194Sdelphij    }
591237410Sdelphij    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
592205194Sdelphij    gz_error(state, Z_OK, NULL);
593205194Sdelphij    free(state->path);
594205194Sdelphij    ret = close(state->fd);
595205194Sdelphij    free(state);
596237410Sdelphij    return ret ? Z_ERRNO : err;
597205194Sdelphij}
598