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