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