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