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