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