144380Ssos/* gzread.c -- zlib functions for reading gzip files
2230132Suqs * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
344380Ssos * For conditions of distribution and use, see copyright notice in zlib.h
444380Ssos */
544380Ssos
644380Ssos/* $FreeBSD: stable/10/contrib/zlib/gzread.c 313796 2017-02-16 06:16:50Z delphij $ */
744380Ssos
844380Ssos#include "gzguts.h"
944380Ssos#include <unistd.h>
1044380Ssos
1144380Ssos/* Local functions */
1244380Ssoslocal int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
1344380Ssoslocal int gz_avail OF((gz_statep));
1444380Ssoslocal int gz_look OF((gz_statep));
1544380Ssoslocal int gz_decomp OF((gz_statep));
1644380Ssoslocal int gz_fetch OF((gz_statep));
1744380Ssoslocal int gz_skip OF((gz_statep, z_off64_t));
1844380Ssoslocal z_size_t gz_read OF((gz_statep, voidp, z_size_t));
1944380Ssos
2044380Ssos/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
2144380Ssos   state->fd, and update state->eof, state->err, and state->msg as appropriate.
2244380Ssos   This function needs to loop on read(), since read() is not guaranteed to
2344380Ssos   read the number of bytes requested, depending on the type of descriptor. */
2444380Ssoslocal int gz_load(state, buf, len, have)
2544380Ssos    gz_statep state;
2644380Ssos    unsigned char *buf;
27119418Sobrien    unsigned len;
28119418Sobrien    unsigned *have;
29119418Sobrien{
3044380Ssos    int ret;
3144380Ssos    unsigned get, max = ((unsigned)-1 >> 2) + 1;
3274302Ssos
3344380Ssos    *have = 0;
34144330Ssos    do {
35119404Ssos        get = len - *have;
36120966Ssos        if (get > max)
3774302Ssos            get = max;
3845798Ssos        ret = read(state->fd, buf + *have, get);
3960041Sphk        if (ret <= 0)
4044380Ssos            break;
41124534Ssos        *have += (unsigned)ret;
42124403Ssos    } while (*have < len);
43119404Ssos    if (ret < 0) {
44124534Ssos        gz_error(state, Z_ERRNO, zstrerror());
4556558Ssos        return -1;
4645798Ssos    }
4745798Ssos    if (ret == 0)
4845798Ssos        state->eof = 1;
4944380Ssos    return 0;
50210471Smav}
51144330Ssos
5244380Ssos/* Load up input buffer and set eof flag if last data loaded -- return -1 on
53200171Smav   error, 0 otherwise.  Note that the eof flag is set when the end of the input
54200171Smav   file is reached, even though there may be unused data in the buffer.  Once
55200171Smav   that data has been used, no more attempts will be made to read the file.
56200171Smav   If strm->avail_in != 0, then the current data is moved to the beginning of
57200171Smav   the input buffer, and then the remainder of the buffer is loaded with the
58200171Smav   available data from the input file. */
5944380Ssoslocal int gz_avail(state)
60200171Smav    gz_statep state;
61200171Smav{
62249203Smarius    unsigned got;
63249203Smarius    z_streamp strm = &(state->strm);
64249203Smarius
65249203Smarius    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
66249203Smarius        return -1;
67249203Smarius    if (state->eof == 0) {
68200171Smav        if (strm->avail_in) {       /* copy what's there to the start */
69249203Smarius            unsigned char *p = state->in;
70214016Smav            unsigned const char *q = strm->next_in;
71249203Smarius            unsigned n = strm->avail_in;
72249203Smarius            do {
7344380Ssos                *p++ = *q++;
74122484Ssos            } while (--n);
75151897Srwatson        }
76146266Ssos        if (gz_load(state, state->in + strm->avail_in,
77122484Ssos                    state->size - strm->avail_in, &got) == -1)
78178278Ssos            return -1;
79181753Sphilip        strm->avail_in += got;
80122484Ssos        strm->next_in = state->in;
8174450Ssos    }
82227309Sed    return 0;
83181753Sphilip}
84181753Sphilip
85209872Smav/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
86181753Sphilip   If this is the first time in, allocate required memory.  state->how will be
87226179Srodrigc   left unchanged if there is no more input data available, will be set to COPY
8874450Ssos   if there is no gzip header and direct copying will be performed, or it will
89119404Ssos   be set to GZIP for decompression.  If direct copying, then leftover input
90119404Ssos   data from the input buffer will be copied to the output buffer.  In that
91119404Ssos   case, all further file reads will be directly to either the output buffer or
9266070Ssos   a user buffer.  If decompressing, the inflate state will be initialized.
9357325Ssos   gz_look() will return 0 on success or -1 on failure. */
9444380Ssoslocal int gz_look(state)
95256326Sgrehan    gz_statep state;
96133556Ssos{
97133556Ssos    z_streamp strm = &(state->strm);
98133556Ssos
99133556Ssos    /* allocate read buffers and inflate memory */
100133556Ssos    if (state->size == 0) {
101144330Ssos        /* allocate buffers */
102133556Ssos        state->in = (unsigned char *)malloc(state->want);
103200171Smav        state->out = (unsigned char *)malloc(state->want << 1);
104209664Smav        if (state->in == NULL || state->out == NULL) {
105209664Smav            free(state->out);
106209664Smav            free(state->in);
107133556Ssos            gz_error(state, Z_MEM_ERROR, "out of memory");
108144330Ssos            return -1;
109144330Ssos        }
110144330Ssos        state->size = state->want;
111133556Ssos
11257325Ssos        /* allocate inflate memory */
113119404Ssos        state->strm.zalloc = Z_NULL;
114135819Ssos        state->strm.zfree = Z_NULL;
115135819Ssos        state->strm.opaque = Z_NULL;
116135819Ssos        state->strm.avail_in = 0;
117188903Smav        state->strm.next_in = Z_NULL;
118200171Smav        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
119241144Smav            free(state->out);
120241144Smav            free(state->in);
121241144Smav            state->size = 0;
122241144Smav            gz_error(state, Z_MEM_ERROR, "out of memory");
123241144Smav            return -1;
124241144Smav        }
125241144Smav    }
126241144Smav
127241144Smav    /* get at least the magic bytes in the input buffer */
128200171Smav    if (strm->avail_in < 2) {
129209664Smav        if (gz_avail(state) == -1)
130209664Smav            return -1;
131209664Smav        if (strm->avail_in == 0)
132209664Smav            return 0;
133209664Smav    }
134209664Smav
135209664Smav    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
136209664Smav       a logical dilemma here when considering the case of a partially written
137209664Smav       gzip file, to wit, if a single 31 byte is written, then we cannot tell
138209664Smav       whether this is a single-byte file, or just a partially written gzip
139209664Smav       file -- for here we assume that if a gzip file is being written, then
140200171Smav       the header will be written in a single operation, so that reading a
141200171Smav       single byte is sufficient indication that it is not a gzip file) */
142200171Smav    if (strm->avail_in > 1 &&
143200171Smav            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
144215468Smav        inflateReset(strm);
145200171Smav        state->how = GZIP;
146249199Smarius        state->direct = 0;
147249199Smarius        return 0;
148249199Smarius    }
149249199Smarius
150249199Smarius    /* no gzip header -- if we were decoding gzip before, then this is trailing
151249199Smarius       garbage.  Ignore the trailing garbage and finish. */
152249199Smarius    if (state->direct == 0) {
153249199Smarius        strm->avail_in = 0;
154249199Smarius        state->eof = 1;
155200171Smav        state->x.have = 0;
156220917Smav        return 0;
157112791Ssos    }
158179717Ssos
159179717Ssos    /* doing raw i/o, copy any leftover input to output -- this assumes that
160179717Ssos       the output buffer is larger than the input buffer, which also assures
161179717Ssos       space for gzungetc() */
162144330Ssos    state->x.next = state->out;
16372106Ssos    if (strm->avail_in) {
164127135Snjl        memcpy(state->x.next, strm->next_in, strm->avail_in);
165127135Snjl        state->x.have = strm->avail_in;
16690215Ssos        strm->avail_in = 0;
167144330Ssos    }
16857325Ssos    state->how = COPY;
16956255Ssos    state->direct = 1;
170166901Spiso    return 0;
171188731Smav}
172209944Smav
173144330Ssos/* Decompress from input to the provided next_out and avail_out in the state.
174209944Smav   On return, state->x.have and state->x.next point to the just decompressed
17591593Ssos   data.  If the gzip stream completes, state->how is reset to LOOK to look for
17657325Ssos   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
177220917Smav   on success, -1 on failure. */
178220917Smavlocal int gz_decomp(state)
179209944Smav    gz_statep state;
180200171Smav{
181200171Smav    int ret = Z_OK;
182200171Smav    unsigned had;
183200171Smav    z_streamp strm = &(state->strm);
184200171Smav
185200171Smav    /* fill output buffer up to end of deflate stream */
186200171Smav    had = strm->avail_out;
187200171Smav    do {
188200171Smav        /* get more input for inflate() */
189200171Smav        if (strm->avail_in == 0 && gz_avail(state) == -1)
190200171Smav            return -1;
191200171Smav        if (strm->avail_in == 0) {
192209944Smav            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
193200171Smav            break;
194209944Smav        }
195200171Smav
196200171Smav        /* decompress and handle errors */
197200171Smav        ret = inflate(strm, Z_NO_FLUSH);
198200171Smav        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
199200171Smav            gz_error(state, Z_STREAM_ERROR,
200200171Smav                     "internal error: inflate stream corrupt");
201200171Smav            return -1;
202200171Smav        }
203200171Smav        if (ret == Z_MEM_ERROR) {
204200171Smav            gz_error(state, Z_MEM_ERROR, "out of memory");
205200171Smav            return -1;
206200171Smav        }
207200171Smav        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
208200171Smav            gz_error(state, Z_DATA_ERROR,
209200171Smav                     strm->msg == NULL ? "compressed data error" : strm->msg);
210200171Smav            return -1;
211200171Smav        }
212200171Smav    } while (strm->avail_out && ret != Z_STREAM_END);
213200171Smav
214209944Smav    /* update available output */
215200171Smav    state->x.have = had - strm->avail_out;
216209944Smav    state->x.next = strm->next_out - state->x.have;
217200171Smav
218214016Smav    /* if the gzip stream completed successfully, look for another */
219214016Smav    if (ret == Z_STREAM_END)
220200171Smav        state->how = LOOK;
22144380Ssos
22244380Ssos    /* good decompression */
22373897Ssos    return 0;
22457325Ssos}
22556255Ssos
226144330Ssos/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
227129493Sdes   Data is either copied from the input file or decompressed from the input
228150129Ssos   file depending on state->how.  If state->how is LOOK, then a gzip header is
229144330Ssos   looked for to determine whether to copy or decompress.  Returns -1 on error,
23057325Ssos   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
23156255Ssos   end of the input file has been reached and all data has been processed.  */
232156003Ssoslocal int gz_fetch(state)
233156003Ssos    gz_statep state;
234156003Ssos{
235156003Ssos    z_streamp strm = &(state->strm);
236214016Smav
237214016Smav    do {
238156003Ssos        switch(state->how) {
239188903Smav        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
240132030Ssos            if (gz_look(state) == -1)
241200171Smav                return -1;
242200171Smav            if (state->how == LOOK)
243200171Smav                return 0;
244200171Smav            break;
245200171Smav        case COPY:      /* -> COPY */
246209944Smav            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
247200171Smav                    == -1)
248200171Smav                return -1;
249144330Ssos            state->x.next = state->out;
25090215Ssos            return 0;
25190215Ssos        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
25290215Ssos            strm->avail_out = state->size << 1;
253188763Smav            strm->next_out = state->out;
254188763Smav            if (gz_decomp(state) == -1)
255188763Smav                return -1;
256188763Smav        }
257188763Smav    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
258144330Ssos    return 0;
259119404Ssos}
260119404Ssos
261119404Ssos/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
262188903Smavlocal int gz_skip(state, len)
263188903Smav    gz_statep state;
264188903Smav    z_off64_t len;
265203108Smav{
266203108Smav    unsigned n;
267203108Smav
268188903Smav    /* skip over len bytes or reach end-of-file, whichever comes first */
269203108Smav    while (len)
270209944Smav        /* skip over whatever is in output buffer */
271209944Smav        if (state->x.have) {
272209944Smav            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
273209944Smav                (unsigned)len : state->x.have;
274203108Smav            state->x.have -= n;
275209944Smav            state->x.next += n;
276203108Smav            state->x.pos += n;
277203108Smav            len -= n;
278203108Smav        }
279203108Smav
280203108Smav        /* output buffer empty -- return if we're at the end of the input */
281203108Smav        else if (state->eof && state->strm.avail_in == 0)
282203108Smav            break;
283203108Smav
284209944Smav        /* need more data to skip -- load up output buffer */
285188903Smav        else {
286188903Smav            /* get more output, looking for header if required */
287119404Ssos            if (gz_fetch(state) == -1)
288144330Ssos                return -1;
289119404Ssos        }
290144330Ssos    return 0;
291150129Ssos}
292129493Sdes
293203108Smav/* Read len bytes into buf from file, or less than len up to the end of the
294200171Smav   input.  Return the number of bytes read.  If zero is returned, either the
295200171Smav   end of file was reached, or there was an error.  state->err must be
296200171Smav   consulted in that case to determine which. */
297200171Smavlocal z_size_t gz_read(state, buf, len)
298200171Smav    gz_statep state;
299200171Smav    voidp buf;
300200171Smav    z_size_t len;
301200171Smav{
302200171Smav    z_size_t got;
303200171Smav    unsigned n;
304200171Smav
305200171Smav    /* if len is zero, avoid unnecessary operations */
306200171Smav    if (len == 0)
307200171Smav        return 0;
308203108Smav
309200171Smav    /* process a skip request */
31056255Ssos    if (state->seek) {
31156255Ssos        state->seek = 0;
31273897Ssos        if (gz_skip(state, state->skip) == -1)
313114656Ssos            return 0;
314114656Ssos    }
315114656Ssos
316114656Ssos    /* get len bytes to buf, or less than len if at the end */
317145354Ssos    got = 0;
318114656Ssos    do {
319114656Ssos        /* set n to the maximum amount of len that fits in an unsigned int */
320133556Ssos        n = -1;
321220917Smav        if (n > len)
322220917Smav            n = len;
323208375Smav
324208375Smav        /* first just try copying data from the output buffer */
325208375Smav        if (state->x.have) {
326208375Smav            if (state->x.have < n)
327208375Smav                n = state->x.have;
328200171Smav            memcpy(buf, state->x.next, n);
329114656Ssos            state->x.next += n;
330114656Ssos            state->x.have -= n;
331114656Ssos        }
33257325Ssos
33357325Ssos        /* output buffer empty -- return if we're at the end of the input */
334208375Smav        else if (state->eof && state->strm.avail_in == 0) {
335107562Ssos            state->past = 1;        /* tried to read past end */
336107562Ssos            break;
337145354Ssos        }
338208375Smav
339107562Ssos        /* need output data -- for small len or new stream load up our output
340107562Ssos           buffer */
341208375Smav        else if (state->how == LOOK || n < (state->size << 1)) {
342208375Smav            /* get more output, looking for header if required */
343208375Smav            if (gz_fetch(state) == -1)
344208375Smav                return 0;
345220917Smav            continue;       /* no progress yet -- go back to copy above */
346220917Smav            /* the copy above assures that we will leave with space in the
347107562Ssos               output buffer, allowing at least one gzungetc() to succeed */
34857325Ssos        }
34957325Ssos
350188731Smav        /* large len -- read directly into user buffer */
351135819Ssos        else if (state->how == COPY) {      /* read directly */
352135819Ssos            if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
353135819Ssos                return 0;
354200171Smav        }
355200171Smav
356235333Smav        /* large len -- decompress directly into user buffer */
357200171Smav        else {  /* state->how == GZIP */
358235333Smav            state->strm.avail_out = n;
359200171Smav            state->strm.next_out = (unsigned char *)buf;
360200171Smav            if (gz_decomp(state) == -1)
361200171Smav                return 0;
362200171Smav            n = state->x.have;
363200171Smav            state->x.have = 0;
364200171Smav        }
365200171Smav
366136486Ssos        /* update progress */
367135819Ssos        len -= n;
368136486Ssos        buf = (char *)buf + n;
369154507Ssos        got += n;
370154507Ssos        state->x.pos += n;
371154507Ssos    } while (len);
372154507Ssos
373136486Ssos    /* return number of bytes read into user buffer */
374150129Ssos    return got;
375136486Ssos}
376135819Ssos
377136486Ssos/* -- see zlib.h -- */
378135819Ssosint ZEXPORT gzread(file, buf, len)
379154507Ssos    gzFile file;
380156003Ssos    voidp buf;
381150129Ssos    unsigned len;
382136486Ssos{
383136486Ssos    gz_statep state;
384136486Ssos
385144330Ssos    /* get internal structure */
386156486Ssos    if (file == NULL)
387145354Ssos        return -1;
388144330Ssos    state = (gz_statep)file;
389136486Ssos
390135819Ssos    /* check that we're reading and that there's no (serious) error */
391144330Ssos    if (state->mode != GZ_READ ||
392135819Ssos            (state->err != Z_OK && state->err != Z_BUF_ERROR))
393200171Smav        return -1;
394188731Smav
395135819Ssos    /* since an int is returned, make sure len fits in one, otherwise return
396136486Ssos       with an error (this avoids a flaw in the interface) */
397135819Ssos    if ((int)len < 0) {
398135819Ssos        gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
399214016Smav        return -1;
400214016Smav    }
401214016Smav
402214016Smav    /* read len or fewer bytes to buf */
403214016Smav    len = gz_read(state, buf, len);
404214016Smav
405214016Smav    /* check for an error */
406214016Smav    if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
407214016Smav        return -1;
408200171Smav
409200171Smav    /* return the number of bytes read (this is assured to fit in an int) */
410200171Smav    return (int)len;
411200171Smav}
412200171Smav
413200171Smav/* -- see zlib.h -- */
414200171Smavz_size_t ZEXPORT gzfread(buf, size, nitems, file)
415119404Ssos    voidp buf;
416119404Ssos    z_size_t size;
417119404Ssos    z_size_t nitems;
41874302Ssos    gzFile file;
419145713Ssos{
420144707Ssos    z_size_t len;
421145713Ssos    gz_statep state;
422145713Ssos
423144707Ssos    /* get internal structure */
424144707Ssos    if (file == NULL)
425144707Ssos        return 0;
426144707Ssos    state = (gz_statep)file;
427144707Ssos
428144707Ssos    /* check that we're reading and that there's no (serious) error */
429144707Ssos    if (state->mode != GZ_READ ||
430144707Ssos            (state->err != Z_OK && state->err != Z_BUF_ERROR))
431144707Ssos        return 0;
432144707Ssos
433144707Ssos    /* compute bytes to read -- error on overflow */
434149191Ssos    len = nitems * size;
435144330Ssos    if (size && len / size != nitems) {
43674302Ssos        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
437144330Ssos        return 0;
438144330Ssos    }
439144330Ssos
440144330Ssos    /* read len or fewer bytes to buf, return the number of full items read */
441166909Sjhb    return len ? gz_read(state, buf, len) / size : 0;
44274302Ssos}
44390215Ssos
444233282Smarius/* -- see zlib.h -- */
445249203Smarius#ifdef Z_PREFIX_SET
446249203Smarius#  undef z_gzgetc
447249203Smarius#else
448249203Smarius#  undef gzgetc
449249203Smarius#endif
450249203Smariusint ZEXPORT gzgetc(file)
451249203Smarius    gzFile file;
452249203Smarius{
453249203Smarius    int ret;
454249203Smarius    unsigned char buf[1];
455249203Smarius    gz_statep state;
456249203Smarius
457249203Smarius    /* get internal structure */
458249203Smarius    if (file == NULL)
459249203Smarius        return -1;
460249203Smarius    state = (gz_statep)file;
461249203Smarius
462249203Smarius    /* check that we're reading and that there's no (serious) error */
463249203Smarius    if (state->mode != GZ_READ ||
464249203Smarius        (state->err != Z_OK && state->err != Z_BUF_ERROR))
465249203Smarius        return -1;
466249203Smarius
467249203Smarius    /* try output buffer (no need to check for skip request) */
468249203Smarius    if (state->x.have) {
469249203Smarius        state->x.have--;
470249203Smarius        state->x.pos++;
471249203Smarius        return *(state->x.next)++;
472249203Smarius    }
473249203Smarius
474249203Smarius    /* nothing there -- try gz_read() */
475249203Smarius    ret = gz_read(state, buf, 1);
476249203Smarius    return ret < 1 ? -1 : buf[0];
477249203Smarius}
478249203Smarius
479249203Smariusint ZEXPORT gzgetc_(file)
480249203SmariusgzFile file;
481249203Smarius{
482249203Smarius    return gzgetc(file);
483249203Smarius}
484249203Smarius
485249203Smarius/* -- see zlib.h -- */
486249203Smariusint ZEXPORT gzungetc(c, file)
487249203Smarius    int c;
488249203Smarius    gzFile file;
489249203Smarius{
490249203Smarius    gz_statep state;
491249203Smarius
492249203Smarius    /* get internal structure */
493249203Smarius    if (file == NULL)
494249203Smarius        return -1;
495249203Smarius    state = (gz_statep)file;
496249203Smarius
497249203Smarius    /* check that we're reading and that there's no (serious) error */
498249203Smarius    if (state->mode != GZ_READ ||
499249203Smarius        (state->err != Z_OK && state->err != Z_BUF_ERROR))
500249203Smarius        return -1;
501249203Smarius
502249203Smarius    /* process a skip request */
503249203Smarius    if (state->seek) {
504249203Smarius        state->seek = 0;
505249203Smarius        if (gz_skip(state, state->skip) == -1)
506249203Smarius            return -1;
507249203Smarius    }
508249203Smarius
509249203Smarius    /* can't push EOF */
510249203Smarius    if (c < 0)
511249203Smarius        return -1;
512249203Smarius
513249203Smarius    /* if output buffer empty, put byte at end (allows more pushing) */
514249203Smarius    if (state->x.have == 0) {
515249203Smarius        state->x.have = 1;
516249203Smarius        state->x.next = state->out + (state->size << 1) - 1;
517249203Smarius        state->x.next[0] = (unsigned char)c;
518249203Smarius        state->x.pos--;
519249203Smarius        state->past = 0;
520249203Smarius        return c;
521249203Smarius    }
522249203Smarius
523249203Smarius    /* if no room, give up (must have already done a gzungetc()) */
524249203Smarius    if (state->x.have == (state->size << 1)) {
525249203Smarius        gz_error(state, Z_DATA_ERROR, "out of room to push characters");
526249203Smarius        return -1;
527249203Smarius    }
528249203Smarius
529249203Smarius    /* slide output data if needed and insert byte before existing data */
530249203Smarius    if (state->x.next == state->out) {
531249203Smarius        unsigned char *src = state->out + state->x.have;
532249203Smarius        unsigned char *dest = state->out + (state->size << 1);
533249203Smarius        while (src > state->out)
534249203Smarius            *--dest = *--src;
535249203Smarius        state->x.next = dest;
536249203Smarius    }
537249203Smarius    state->x.have++;
538249203Smarius    state->x.next--;
539249203Smarius    state->x.next[0] = (unsigned char)c;
540249203Smarius    state->x.pos--;
541249203Smarius    state->past = 0;
542249203Smarius    return c;
543249203Smarius}
544249203Smarius
545249203Smarius/* -- see zlib.h -- */
546249203Smariuschar * ZEXPORT gzgets(file, buf, len)
547249203Smarius    gzFile file;
548249203Smarius    char *buf;
549249203Smarius    int len;
550249203Smarius{
551249203Smarius    unsigned left, n;
552249203Smarius    char *str;
553249203Smarius    unsigned char *eol;
554249203Smarius    gz_statep state;
555249203Smarius
556249203Smarius    /* check parameters and get internal structure */
557249203Smarius    if (file == NULL || buf == NULL || len < 1)
558249203Smarius        return NULL;
55966070Ssos    state = (gz_statep)file;
56057325Ssos
56151520Ssos    /* check that we're reading and that there's no (serious) error */
562149594Ssos    if (state->mode != GZ_READ ||
56355333Ssos        (state->err != Z_OK && state->err != Z_BUF_ERROR))
56455333Ssos        return NULL;
56555333Ssos
56655333Ssos    /* process a skip request */
56755333Ssos    if (state->seek) {
568111188Ssos        state->seek = 0;
569111188Ssos        if (gz_skip(state, state->skip) == -1)
57055333Ssos            return NULL;
571111188Ssos    }
572111188Ssos
57355333Ssos    /* copy output bytes up to new line or len - 1, whichever comes first --
574111188Ssos       append a terminating zero to the string (we don't check for a zero in
57555333Ssos       the contents, let the user worry about that) */
57664307Ssos    str = buf;
57784584Ssos    left = (unsigned)len - 1;
578115135Ssos    if (left) do {
579148992Ssos        /* assure that something is in the output buffer */
580144330Ssos        if (state->x.have == 0 && gz_fetch(state) == -1)
581144330Ssos            return NULL;                /* error */
582144330Ssos        if (state->x.have == 0) {       /* end of file */
583144330Ssos            state->past = 1;            /* read past end */
584144330Ssos            break;                      /* return what we have */
58555333Ssos        }
58655333Ssos
58755333Ssos        /* look for end-of-line in current output buffer */
588249203Smarius        n = state->x.have > left ? left : state->x.have;
589209664Smav        eol = (unsigned char *)memchr(state->x.next, '\n', n);
590209664Smav        if (eol != NULL)
591209664Smav            n = (unsigned)(eol - state->x.next) + 1;
592209664Smav
593209664Smav        /* copy through end-of-line, or remainder if not found */
594209664Smav        memcpy(buf, state->x.next, n);
595209664Smav        state->x.have -= n;
596209664Smav        state->x.next += n;
597209664Smav        state->x.pos += n;
598209664Smav        left -= n;
599209664Smav        buf += n;
600209664Smav    } while (left && eol == NULL);
601209664Smav
602209664Smav    /* return terminated string, or if nothing, end of file */
603209664Smav    if (buf == str)
604209664Smav        return NULL;
605209664Smav    buf[0] = 0;
606209664Smav    return str;
607209664Smav}
608209664Smav
609209664Smav/* -- see zlib.h -- */
610209664Smavint ZEXPORT gzdirect(file)
611209664Smav    gzFile file;
612209664Smav{
613209664Smav    gz_statep state;
614209664Smav
615209664Smav    /* get internal structure */
616209664Smav    if (file == NULL)
61766070Ssos        return 0;
618200459Smarius    state = (gz_statep)file;
619183724Ssos
620200459Smarius    /* if the state is not known, but we can find out, then do so (this is
621183724Ssos       mainly for right after a gzopen() or gzdopen()) */
622200459Smarius    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
623183724Ssos        (void)gz_look(state);
624183724Ssos
625249203Smarius    /* return 1 if transparent, 0 if processing a gzip stream */
626249203Smarius    return state->direct;
627249203Smarius}
628249203Smarius
629249203Smarius/* -- see zlib.h -- */
630249203Smariusint ZEXPORT gzclose_r(file)
631249203Smarius    gzFile file;
632249203Smarius{
633249203Smarius    int ret, err;
634249203Smarius    gz_statep state;
635249203Smarius
636249203Smarius    /* get internal structure */
637249203Smarius    if (file == NULL)
638249203Smarius        return Z_STREAM_ERROR;
639249203Smarius    state = (gz_statep)file;
640249203Smarius
641249203Smarius    /* check that we're reading */
642249203Smarius    if (state->mode != GZ_READ)
643249203Smarius        return Z_STREAM_ERROR;
644249203Smarius
645249203Smarius    /* free memory and close file */
646249203Smarius    if (state->size) {
647249203Smarius        inflateEnd(&(state->strm));
648249203Smarius        free(state->out);
649249203Smarius        free(state->in);
650249203Smarius    }
651145676Ssos    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
652200171Smav    gz_error(state, Z_OK, NULL);
653200171Smav    free(state->path);
654200171Smav    ret = close(state->fd);
655200171Smav    free(state);
656145676Ssos    return ret ? Z_ERRNO : err;
657200171Smav}
658200171Smav