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