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