xref: /dragonfly/contrib/zlib-1.2/gzread.c (revision e041647a)
1fe927c51SPeter Avalos /* gzread.c -- zlib functions for reading gzip files
2*e041647aSSascha Wildner  * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
3fe927c51SPeter Avalos  * For conditions of distribution and use, see copyright notice in zlib.h
4fe927c51SPeter Avalos  */
5fe927c51SPeter Avalos 
6fe927c51SPeter Avalos #include "gzguts.h"
7fe927c51SPeter Avalos 
8fe927c51SPeter Avalos /* Local functions */
9fe927c51SPeter Avalos local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
10fe927c51SPeter Avalos local int gz_avail OF((gz_statep));
11712f98b7SJohn Marino local int gz_look OF((gz_statep));
12fe927c51SPeter Avalos local int gz_decomp OF((gz_statep));
13712f98b7SJohn Marino local int gz_fetch OF((gz_statep));
14fe927c51SPeter Avalos local int gz_skip OF((gz_statep, z_off64_t));
15*e041647aSSascha Wildner local z_size_t gz_read OF((gz_statep, voidp, z_size_t));
16fe927c51SPeter Avalos 
17fe927c51SPeter Avalos /* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
18fe927c51SPeter Avalos    state->fd, and update state->eof, state->err, and state->msg as appropriate.
19fe927c51SPeter Avalos    This function needs to loop on read(), since read() is not guaranteed to
20fe927c51SPeter Avalos    read the number of bytes requested, depending on the type of descriptor. */
gz_load(state,buf,len,have)21fe927c51SPeter Avalos local int gz_load(state, buf, len, have)
22fe927c51SPeter Avalos     gz_statep state;
23fe927c51SPeter Avalos     unsigned char *buf;
24fe927c51SPeter Avalos     unsigned len;
25fe927c51SPeter Avalos     unsigned *have;
26fe927c51SPeter Avalos {
27fe927c51SPeter Avalos     int ret;
28*e041647aSSascha Wildner     unsigned get, max = ((unsigned)-1 >> 2) + 1;
29fe927c51SPeter Avalos 
30fe927c51SPeter Avalos     *have = 0;
31fe927c51SPeter Avalos     do {
32*e041647aSSascha Wildner         get = len - *have;
33*e041647aSSascha Wildner         if (get > max)
34*e041647aSSascha Wildner             get = max;
35*e041647aSSascha Wildner         ret = read(state->fd, buf + *have, get);
36fe927c51SPeter Avalos         if (ret <= 0)
37fe927c51SPeter Avalos             break;
38*e041647aSSascha Wildner         *have += (unsigned)ret;
39fe927c51SPeter Avalos     } while (*have < len);
40fe927c51SPeter Avalos     if (ret < 0) {
41fe927c51SPeter Avalos         gz_error(state, Z_ERRNO, zstrerror());
42fe927c51SPeter Avalos         return -1;
43fe927c51SPeter Avalos     }
44fe927c51SPeter Avalos     if (ret == 0)
45fe927c51SPeter Avalos         state->eof = 1;
46fe927c51SPeter Avalos     return 0;
47fe927c51SPeter Avalos }
48fe927c51SPeter Avalos 
49fe927c51SPeter Avalos /* Load up input buffer and set eof flag if last data loaded -- return -1 on
50fe927c51SPeter Avalos    error, 0 otherwise.  Note that the eof flag is set when the end of the input
51fe927c51SPeter Avalos    file is reached, even though there may be unused data in the buffer.  Once
52fe927c51SPeter Avalos    that data has been used, no more attempts will be made to read the file.
53712f98b7SJohn Marino    If strm->avail_in != 0, then the current data is moved to the beginning of
54712f98b7SJohn Marino    the input buffer, and then the remainder of the buffer is loaded with the
55712f98b7SJohn Marino    available data from the input file. */
gz_avail(state)56fe927c51SPeter Avalos local int gz_avail(state)
57fe927c51SPeter Avalos     gz_statep state;
58fe927c51SPeter Avalos {
59712f98b7SJohn Marino     unsigned got;
60fe927c51SPeter Avalos     z_streamp strm = &(state->strm);
61fe927c51SPeter Avalos 
62712f98b7SJohn Marino     if (state->err != Z_OK && state->err != Z_BUF_ERROR)
63fe927c51SPeter Avalos         return -1;
64fe927c51SPeter Avalos     if (state->eof == 0) {
65712f98b7SJohn Marino         if (strm->avail_in) {       /* copy what's there to the start */
6653ddf67cSJohn Marino             unsigned char *p = state->in;
6753ddf67cSJohn Marino             unsigned const char *q = strm->next_in;
68712f98b7SJohn Marino             unsigned n = strm->avail_in;
69712f98b7SJohn Marino             do {
70712f98b7SJohn Marino                 *p++ = *q++;
71712f98b7SJohn Marino             } while (--n);
72712f98b7SJohn Marino         }
73712f98b7SJohn Marino         if (gz_load(state, state->in + strm->avail_in,
74712f98b7SJohn Marino                     state->size - strm->avail_in, &got) == -1)
75fe927c51SPeter Avalos             return -1;
76712f98b7SJohn Marino         strm->avail_in += got;
77fe927c51SPeter Avalos         strm->next_in = state->in;
78fe927c51SPeter Avalos     }
79fe927c51SPeter Avalos     return 0;
80fe927c51SPeter Avalos }
81fe927c51SPeter Avalos 
82712f98b7SJohn Marino /* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
83fe927c51SPeter Avalos    If this is the first time in, allocate required memory.  state->how will be
84fe927c51SPeter Avalos    left unchanged if there is no more input data available, will be set to COPY
85fe927c51SPeter Avalos    if there is no gzip header and direct copying will be performed, or it will
86712f98b7SJohn Marino    be set to GZIP for decompression.  If direct copying, then leftover input
87712f98b7SJohn Marino    data from the input buffer will be copied to the output buffer.  In that
88712f98b7SJohn Marino    case, all further file reads will be directly to either the output buffer or
89712f98b7SJohn Marino    a user buffer.  If decompressing, the inflate state will be initialized.
90712f98b7SJohn Marino    gz_look() will return 0 on success or -1 on failure. */
gz_look(state)91712f98b7SJohn Marino local int gz_look(state)
92fe927c51SPeter Avalos     gz_statep state;
93fe927c51SPeter Avalos {
94fe927c51SPeter Avalos     z_streamp strm = &(state->strm);
95fe927c51SPeter Avalos 
96fe927c51SPeter Avalos     /* allocate read buffers and inflate memory */
97fe927c51SPeter Avalos     if (state->size == 0) {
98fe927c51SPeter Avalos         /* allocate buffers */
9953ddf67cSJohn Marino         state->in = (unsigned char *)malloc(state->want);
10053ddf67cSJohn Marino         state->out = (unsigned char *)malloc(state->want << 1);
101fe927c51SPeter Avalos         if (state->in == NULL || state->out == NULL) {
102fe927c51SPeter Avalos             free(state->out);
103fe927c51SPeter Avalos             free(state->in);
104fe927c51SPeter Avalos             gz_error(state, Z_MEM_ERROR, "out of memory");
105fe927c51SPeter Avalos             return -1;
106fe927c51SPeter Avalos         }
107fe927c51SPeter Avalos         state->size = state->want;
108fe927c51SPeter Avalos 
109fe927c51SPeter Avalos         /* allocate inflate memory */
110fe927c51SPeter Avalos         state->strm.zalloc = Z_NULL;
111fe927c51SPeter Avalos         state->strm.zfree = Z_NULL;
112fe927c51SPeter Avalos         state->strm.opaque = Z_NULL;
113fe927c51SPeter Avalos         state->strm.avail_in = 0;
114fe927c51SPeter Avalos         state->strm.next_in = Z_NULL;
115712f98b7SJohn Marino         if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
116fe927c51SPeter Avalos             free(state->out);
117fe927c51SPeter Avalos             free(state->in);
118fe927c51SPeter Avalos             state->size = 0;
119fe927c51SPeter Avalos             gz_error(state, Z_MEM_ERROR, "out of memory");
120fe927c51SPeter Avalos             return -1;
121fe927c51SPeter Avalos         }
122fe927c51SPeter Avalos     }
123fe927c51SPeter Avalos 
124712f98b7SJohn Marino     /* get at least the magic bytes in the input buffer */
125712f98b7SJohn Marino     if (strm->avail_in < 2) {
126fe927c51SPeter Avalos         if (gz_avail(state) == -1)
127fe927c51SPeter Avalos             return -1;
128fe927c51SPeter Avalos         if (strm->avail_in == 0)
129fe927c51SPeter Avalos             return 0;
130fe927c51SPeter Avalos     }
131fe927c51SPeter Avalos 
132712f98b7SJohn Marino     /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
133712f98b7SJohn Marino        a logical dilemma here when considering the case of a partially written
134712f98b7SJohn Marino        gzip file, to wit, if a single 31 byte is written, then we cannot tell
135712f98b7SJohn Marino        whether this is a single-byte file, or just a partially written gzip
136712f98b7SJohn Marino        file -- for here we assume that if a gzip file is being written, then
137712f98b7SJohn Marino        the header will be written in a single operation, so that reading a
138712f98b7SJohn Marino        single byte is sufficient indication that it is not a gzip file) */
139712f98b7SJohn Marino     if (strm->avail_in > 1 &&
140712f98b7SJohn Marino             strm->next_in[0] == 31 && strm->next_in[1] == 139) {
141fe927c51SPeter Avalos         inflateReset(strm);
142fe927c51SPeter Avalos         state->how = GZIP;
143fe927c51SPeter Avalos         state->direct = 0;
144fe927c51SPeter Avalos         return 0;
145fe927c51SPeter Avalos     }
146712f98b7SJohn Marino 
147712f98b7SJohn Marino     /* no gzip header -- if we were decoding gzip before, then this is trailing
148712f98b7SJohn Marino        garbage.  Ignore the trailing garbage and finish. */
149712f98b7SJohn Marino     if (state->direct == 0) {
150712f98b7SJohn Marino         strm->avail_in = 0;
151712f98b7SJohn Marino         state->eof = 1;
152712f98b7SJohn Marino         state->x.have = 0;
153712f98b7SJohn Marino         return 0;
154fe927c51SPeter Avalos     }
155fe927c51SPeter Avalos 
156712f98b7SJohn Marino     /* doing raw i/o, copy any leftover input to output -- this assumes that
157712f98b7SJohn Marino        the output buffer is larger than the input buffer, which also assures
158712f98b7SJohn Marino        space for gzungetc() */
159712f98b7SJohn Marino     state->x.next = state->out;
160fe927c51SPeter Avalos     if (strm->avail_in) {
161712f98b7SJohn Marino         memcpy(state->x.next, strm->next_in, strm->avail_in);
162712f98b7SJohn Marino         state->x.have = strm->avail_in;
163fe927c51SPeter Avalos         strm->avail_in = 0;
164fe927c51SPeter Avalos     }
165fe927c51SPeter Avalos     state->how = COPY;
166fe927c51SPeter Avalos     state->direct = 1;
167fe927c51SPeter Avalos     return 0;
168fe927c51SPeter Avalos }
169fe927c51SPeter Avalos 
170fe927c51SPeter Avalos /* Decompress from input to the provided next_out and avail_out in the state.
171712f98b7SJohn Marino    On return, state->x.have and state->x.next point to the just decompressed
172712f98b7SJohn Marino    data.  If the gzip stream completes, state->how is reset to LOOK to look for
173712f98b7SJohn Marino    the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
174712f98b7SJohn Marino    on success, -1 on failure. */
gz_decomp(state)175fe927c51SPeter Avalos local int gz_decomp(state)
176fe927c51SPeter Avalos     gz_statep state;
177fe927c51SPeter Avalos {
178712f98b7SJohn Marino     int ret = Z_OK;
179fe927c51SPeter Avalos     unsigned had;
180fe927c51SPeter Avalos     z_streamp strm = &(state->strm);
181fe927c51SPeter Avalos 
182fe927c51SPeter Avalos     /* fill output buffer up to end of deflate stream */
183fe927c51SPeter Avalos     had = strm->avail_out;
184fe927c51SPeter Avalos     do {
185fe927c51SPeter Avalos         /* get more input for inflate() */
186fe927c51SPeter Avalos         if (strm->avail_in == 0 && gz_avail(state) == -1)
187fe927c51SPeter Avalos             return -1;
188fe927c51SPeter Avalos         if (strm->avail_in == 0) {
189712f98b7SJohn Marino             gz_error(state, Z_BUF_ERROR, "unexpected end of file");
190712f98b7SJohn Marino             break;
191fe927c51SPeter Avalos         }
192fe927c51SPeter Avalos 
193fe927c51SPeter Avalos         /* decompress and handle errors */
194fe927c51SPeter Avalos         ret = inflate(strm, Z_NO_FLUSH);
195fe927c51SPeter Avalos         if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
196fe927c51SPeter Avalos             gz_error(state, Z_STREAM_ERROR,
197fe927c51SPeter Avalos                      "internal error: inflate stream corrupt");
198fe927c51SPeter Avalos             return -1;
199fe927c51SPeter Avalos         }
200fe927c51SPeter Avalos         if (ret == Z_MEM_ERROR) {
201fe927c51SPeter Avalos             gz_error(state, Z_MEM_ERROR, "out of memory");
202fe927c51SPeter Avalos             return -1;
203fe927c51SPeter Avalos         }
204fe927c51SPeter Avalos         if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
205fe927c51SPeter Avalos             gz_error(state, Z_DATA_ERROR,
206fe927c51SPeter Avalos                      strm->msg == NULL ? "compressed data error" : strm->msg);
207fe927c51SPeter Avalos             return -1;
208fe927c51SPeter Avalos         }
209fe927c51SPeter Avalos     } while (strm->avail_out && ret != Z_STREAM_END);
210fe927c51SPeter Avalos 
211712f98b7SJohn Marino     /* update available output */
212712f98b7SJohn Marino     state->x.have = had - strm->avail_out;
213712f98b7SJohn Marino     state->x.next = strm->next_out - state->x.have;
214fe927c51SPeter Avalos 
215712f98b7SJohn Marino     /* if the gzip stream completed successfully, look for another */
216712f98b7SJohn Marino     if (ret == Z_STREAM_END)
217712f98b7SJohn Marino         state->how = LOOK;
218fe927c51SPeter Avalos 
219fe927c51SPeter Avalos     /* good decompression */
220fe927c51SPeter Avalos     return 0;
221fe927c51SPeter Avalos }
222fe927c51SPeter Avalos 
223712f98b7SJohn Marino /* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
224fe927c51SPeter Avalos    Data is either copied from the input file or decompressed from the input
225fe927c51SPeter Avalos    file depending on state->how.  If state->how is LOOK, then a gzip header is
226712f98b7SJohn Marino    looked for to determine whether to copy or decompress.  Returns -1 on error,
227712f98b7SJohn Marino    otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
228712f98b7SJohn Marino    end of the input file has been reached and all data has been processed.  */
gz_fetch(state)229712f98b7SJohn Marino local int gz_fetch(state)
230fe927c51SPeter Avalos     gz_statep state;
231fe927c51SPeter Avalos {
232fe927c51SPeter Avalos     z_streamp strm = &(state->strm);
233fe927c51SPeter Avalos 
234712f98b7SJohn Marino     do {
235712f98b7SJohn Marino         switch(state->how) {
236712f98b7SJohn Marino         case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
237712f98b7SJohn Marino             if (gz_look(state) == -1)
238fe927c51SPeter Avalos                 return -1;
239712f98b7SJohn Marino             if (state->how == LOOK)
240fe927c51SPeter Avalos                 return 0;
241712f98b7SJohn Marino             break;
242712f98b7SJohn Marino         case COPY:      /* -> COPY */
243712f98b7SJohn Marino             if (gz_load(state, state->out, state->size << 1, &(state->x.have))
244712f98b7SJohn Marino                     == -1)
245fe927c51SPeter Avalos                 return -1;
246712f98b7SJohn Marino             state->x.next = state->out;
247712f98b7SJohn Marino             return 0;
248712f98b7SJohn Marino         case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
249fe927c51SPeter Avalos             strm->avail_out = state->size << 1;
250fe927c51SPeter Avalos             strm->next_out = state->out;
251fe927c51SPeter Avalos             if (gz_decomp(state) == -1)
252fe927c51SPeter Avalos                 return -1;
253fe927c51SPeter Avalos         }
254712f98b7SJohn Marino     } while (state->x.have == 0 && (!state->eof || strm->avail_in));
255fe927c51SPeter Avalos     return 0;
256fe927c51SPeter Avalos }
257fe927c51SPeter Avalos 
258fe927c51SPeter Avalos /* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
gz_skip(state,len)259fe927c51SPeter Avalos local int gz_skip(state, len)
260fe927c51SPeter Avalos     gz_statep state;
261fe927c51SPeter Avalos     z_off64_t len;
262fe927c51SPeter Avalos {
263fe927c51SPeter Avalos     unsigned n;
264fe927c51SPeter Avalos 
265fe927c51SPeter Avalos     /* skip over len bytes or reach end-of-file, whichever comes first */
266fe927c51SPeter Avalos     while (len)
267fe927c51SPeter Avalos         /* skip over whatever is in output buffer */
268712f98b7SJohn Marino         if (state->x.have) {
269712f98b7SJohn Marino             n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
270712f98b7SJohn Marino                 (unsigned)len : state->x.have;
271712f98b7SJohn Marino             state->x.have -= n;
272712f98b7SJohn Marino             state->x.next += n;
273712f98b7SJohn Marino             state->x.pos += n;
274fe927c51SPeter Avalos             len -= n;
275fe927c51SPeter Avalos         }
276fe927c51SPeter Avalos 
277fe927c51SPeter Avalos         /* output buffer empty -- return if we're at the end of the input */
278fe927c51SPeter Avalos         else if (state->eof && state->strm.avail_in == 0)
279fe927c51SPeter Avalos             break;
280fe927c51SPeter Avalos 
281fe927c51SPeter Avalos         /* need more data to skip -- load up output buffer */
282fe927c51SPeter Avalos         else {
283fe927c51SPeter Avalos             /* get more output, looking for header if required */
284712f98b7SJohn Marino             if (gz_fetch(state) == -1)
285fe927c51SPeter Avalos                 return -1;
286fe927c51SPeter Avalos         }
287fe927c51SPeter Avalos     return 0;
288fe927c51SPeter Avalos }
289fe927c51SPeter Avalos 
290*e041647aSSascha Wildner /* Read len bytes into buf from file, or less than len up to the end of the
291*e041647aSSascha Wildner    input.  Return the number of bytes read.  If zero is returned, either the
292*e041647aSSascha Wildner    end of file was reached, or there was an error.  state->err must be
293*e041647aSSascha Wildner    consulted in that case to determine which. */
gz_read(state,buf,len)294*e041647aSSascha Wildner local z_size_t gz_read(state, buf, len)
295fe927c51SPeter Avalos     gz_statep state;
296*e041647aSSascha Wildner     voidp buf;
297*e041647aSSascha Wildner     z_size_t len;
298*e041647aSSascha Wildner {
299*e041647aSSascha Wildner     z_size_t got;
300*e041647aSSascha Wildner     unsigned n;
301fe927c51SPeter Avalos 
302fe927c51SPeter Avalos     /* if len is zero, avoid unnecessary operations */
303fe927c51SPeter Avalos     if (len == 0)
304fe927c51SPeter Avalos         return 0;
305fe927c51SPeter Avalos 
306fe927c51SPeter Avalos     /* process a skip request */
307fe927c51SPeter Avalos     if (state->seek) {
308fe927c51SPeter Avalos         state->seek = 0;
309fe927c51SPeter Avalos         if (gz_skip(state, state->skip) == -1)
310*e041647aSSascha Wildner             return 0;
311fe927c51SPeter Avalos     }
312fe927c51SPeter Avalos 
313fe927c51SPeter Avalos     /* get len bytes to buf, or less than len if at the end */
314fe927c51SPeter Avalos     got = 0;
315fe927c51SPeter Avalos     do {
316*e041647aSSascha Wildner         /* set n to the maximum amount of len that fits in an unsigned int */
317*e041647aSSascha Wildner         n = -1;
318*e041647aSSascha Wildner         if (n > len)
319*e041647aSSascha Wildner             n = len;
320*e041647aSSascha Wildner 
321fe927c51SPeter Avalos         /* first just try copying data from the output buffer */
322712f98b7SJohn Marino         if (state->x.have) {
323*e041647aSSascha Wildner             if (state->x.have < n)
324*e041647aSSascha Wildner                 n = state->x.have;
325712f98b7SJohn Marino             memcpy(buf, state->x.next, n);
326712f98b7SJohn Marino             state->x.next += n;
327712f98b7SJohn Marino             state->x.have -= n;
328fe927c51SPeter Avalos         }
329fe927c51SPeter Avalos 
330fe927c51SPeter Avalos         /* output buffer empty -- return if we're at the end of the input */
331*e041647aSSascha Wildner         else if (state->eof && state->strm.avail_in == 0) {
332712f98b7SJohn Marino             state->past = 1;        /* tried to read past end */
333fe927c51SPeter Avalos             break;
334712f98b7SJohn Marino         }
335fe927c51SPeter Avalos 
336fe927c51SPeter Avalos         /* need output data -- for small len or new stream load up our output
337fe927c51SPeter Avalos            buffer */
338*e041647aSSascha Wildner         else if (state->how == LOOK || n < (state->size << 1)) {
339fe927c51SPeter Avalos             /* get more output, looking for header if required */
340712f98b7SJohn Marino             if (gz_fetch(state) == -1)
341*e041647aSSascha Wildner                 return 0;
342712f98b7SJohn Marino             continue;       /* no progress yet -- go back to copy above */
343fe927c51SPeter Avalos             /* the copy above assures that we will leave with space in the
344fe927c51SPeter Avalos                output buffer, allowing at least one gzungetc() to succeed */
345fe927c51SPeter Avalos         }
346fe927c51SPeter Avalos 
347fe927c51SPeter Avalos         /* large len -- read directly into user buffer */
348fe927c51SPeter Avalos         else if (state->how == COPY) {      /* read directly */
349*e041647aSSascha Wildner             if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
350*e041647aSSascha Wildner                 return 0;
351fe927c51SPeter Avalos         }
352fe927c51SPeter Avalos 
353fe927c51SPeter Avalos         /* large len -- decompress directly into user buffer */
354fe927c51SPeter Avalos         else {  /* state->how == GZIP */
355*e041647aSSascha Wildner             state->strm.avail_out = n;
356*e041647aSSascha Wildner             state->strm.next_out = (unsigned char *)buf;
357fe927c51SPeter Avalos             if (gz_decomp(state) == -1)
358*e041647aSSascha Wildner                 return 0;
359712f98b7SJohn Marino             n = state->x.have;
360712f98b7SJohn Marino             state->x.have = 0;
361fe927c51SPeter Avalos         }
362fe927c51SPeter Avalos 
363fe927c51SPeter Avalos         /* update progress */
364fe927c51SPeter Avalos         len -= n;
365fe927c51SPeter Avalos         buf = (char *)buf + n;
366fe927c51SPeter Avalos         got += n;
367712f98b7SJohn Marino         state->x.pos += n;
368fe927c51SPeter Avalos     } while (len);
369fe927c51SPeter Avalos 
370*e041647aSSascha Wildner     /* return number of bytes read into user buffer */
371*e041647aSSascha Wildner     return got;
372*e041647aSSascha Wildner }
373*e041647aSSascha Wildner 
374*e041647aSSascha Wildner /* -- see zlib.h -- */
gzread(file,buf,len)375*e041647aSSascha Wildner int ZEXPORT gzread(file, buf, len)
376*e041647aSSascha Wildner     gzFile file;
377*e041647aSSascha Wildner     voidp buf;
378*e041647aSSascha Wildner     unsigned len;
379*e041647aSSascha Wildner {
380*e041647aSSascha Wildner     gz_statep state;
381*e041647aSSascha Wildner 
382*e041647aSSascha Wildner     /* get internal structure */
383*e041647aSSascha Wildner     if (file == NULL)
384*e041647aSSascha Wildner         return -1;
385*e041647aSSascha Wildner     state = (gz_statep)file;
386*e041647aSSascha Wildner 
387*e041647aSSascha Wildner     /* check that we're reading and that there's no (serious) error */
388*e041647aSSascha Wildner     if (state->mode != GZ_READ ||
389*e041647aSSascha Wildner             (state->err != Z_OK && state->err != Z_BUF_ERROR))
390*e041647aSSascha Wildner         return -1;
391*e041647aSSascha Wildner 
392*e041647aSSascha Wildner     /* since an int is returned, make sure len fits in one, otherwise return
393*e041647aSSascha Wildner        with an error (this avoids a flaw in the interface) */
394*e041647aSSascha Wildner     if ((int)len < 0) {
395*e041647aSSascha Wildner         gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
396*e041647aSSascha Wildner         return -1;
397*e041647aSSascha Wildner     }
398*e041647aSSascha Wildner 
399*e041647aSSascha Wildner     /* read len or fewer bytes to buf */
400*e041647aSSascha Wildner     len = gz_read(state, buf, len);
401*e041647aSSascha Wildner 
402*e041647aSSascha Wildner     /* check for an error */
403*e041647aSSascha Wildner     if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
404*e041647aSSascha Wildner         return -1;
405*e041647aSSascha Wildner 
406*e041647aSSascha Wildner     /* return the number of bytes read (this is assured to fit in an int) */
407*e041647aSSascha Wildner     return (int)len;
408*e041647aSSascha Wildner }
409*e041647aSSascha Wildner 
410*e041647aSSascha Wildner /* -- see zlib.h -- */
gzfread(buf,size,nitems,file)411*e041647aSSascha Wildner z_size_t ZEXPORT gzfread(buf, size, nitems, file)
412*e041647aSSascha Wildner     voidp buf;
413*e041647aSSascha Wildner     z_size_t size;
414*e041647aSSascha Wildner     z_size_t nitems;
415*e041647aSSascha Wildner     gzFile file;
416*e041647aSSascha Wildner {
417*e041647aSSascha Wildner     z_size_t len;
418*e041647aSSascha Wildner     gz_statep state;
419*e041647aSSascha Wildner 
420*e041647aSSascha Wildner     /* get internal structure */
421*e041647aSSascha Wildner     if (file == NULL)
422*e041647aSSascha Wildner         return 0;
423*e041647aSSascha Wildner     state = (gz_statep)file;
424*e041647aSSascha Wildner 
425*e041647aSSascha Wildner     /* check that we're reading and that there's no (serious) error */
426*e041647aSSascha Wildner     if (state->mode != GZ_READ ||
427*e041647aSSascha Wildner             (state->err != Z_OK && state->err != Z_BUF_ERROR))
428*e041647aSSascha Wildner         return 0;
429*e041647aSSascha Wildner 
430*e041647aSSascha Wildner     /* compute bytes to read -- error on overflow */
431*e041647aSSascha Wildner     len = nitems * size;
432*e041647aSSascha Wildner     if (size && len / size != nitems) {
433*e041647aSSascha Wildner         gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
434*e041647aSSascha Wildner         return 0;
435*e041647aSSascha Wildner     }
436*e041647aSSascha Wildner 
437*e041647aSSascha Wildner     /* read len or fewer bytes to buf, return the number of full items read */
438*e041647aSSascha Wildner     return len ? gz_read(state, buf, len) / size : 0;
439fe927c51SPeter Avalos }
440fe927c51SPeter Avalos 
441fe927c51SPeter Avalos /* -- see zlib.h -- */
44253ddf67cSJohn Marino #ifdef Z_PREFIX_SET
44353ddf67cSJohn Marino #  undef z_gzgetc
44453ddf67cSJohn Marino #else
445712f98b7SJohn Marino #  undef gzgetc
44653ddf67cSJohn Marino #endif
gzgetc(file)447fe927c51SPeter Avalos int ZEXPORT gzgetc(file)
448fe927c51SPeter Avalos     gzFile file;
449fe927c51SPeter Avalos {
450fe927c51SPeter Avalos     int ret;
451fe927c51SPeter Avalos     unsigned char buf[1];
452fe927c51SPeter Avalos     gz_statep state;
453fe927c51SPeter Avalos 
454fe927c51SPeter Avalos     /* get internal structure */
455fe927c51SPeter Avalos     if (file == NULL)
456fe927c51SPeter Avalos         return -1;
457fe927c51SPeter Avalos     state = (gz_statep)file;
458fe927c51SPeter Avalos 
459712f98b7SJohn Marino     /* check that we're reading and that there's no (serious) error */
460712f98b7SJohn Marino     if (state->mode != GZ_READ ||
461712f98b7SJohn Marino         (state->err != Z_OK && state->err != Z_BUF_ERROR))
462fe927c51SPeter Avalos         return -1;
463fe927c51SPeter Avalos 
464fe927c51SPeter Avalos     /* try output buffer (no need to check for skip request) */
465712f98b7SJohn Marino     if (state->x.have) {
466712f98b7SJohn Marino         state->x.have--;
467712f98b7SJohn Marino         state->x.pos++;
468712f98b7SJohn Marino         return *(state->x.next)++;
469fe927c51SPeter Avalos     }
470fe927c51SPeter Avalos 
471*e041647aSSascha Wildner     /* nothing there -- try gz_read() */
472*e041647aSSascha Wildner     ret = gz_read(state, buf, 1);
473fe927c51SPeter Avalos     return ret < 1 ? -1 : buf[0];
474fe927c51SPeter Avalos }
475fe927c51SPeter Avalos 
gzgetc_(file)476712f98b7SJohn Marino int ZEXPORT gzgetc_(file)
477712f98b7SJohn Marino gzFile file;
478712f98b7SJohn Marino {
479712f98b7SJohn Marino     return gzgetc(file);
480712f98b7SJohn Marino }
481712f98b7SJohn Marino 
482fe927c51SPeter Avalos /* -- see zlib.h -- */
gzungetc(c,file)483fe927c51SPeter Avalos int ZEXPORT gzungetc(c, file)
484fe927c51SPeter Avalos     int c;
485fe927c51SPeter Avalos     gzFile file;
486fe927c51SPeter Avalos {
487fe927c51SPeter Avalos     gz_statep state;
488fe927c51SPeter Avalos 
489fe927c51SPeter Avalos     /* get internal structure */
490fe927c51SPeter Avalos     if (file == NULL)
491fe927c51SPeter Avalos         return -1;
492fe927c51SPeter Avalos     state = (gz_statep)file;
493fe927c51SPeter Avalos 
494712f98b7SJohn Marino     /* check that we're reading and that there's no (serious) error */
495712f98b7SJohn Marino     if (state->mode != GZ_READ ||
496712f98b7SJohn Marino         (state->err != Z_OK && state->err != Z_BUF_ERROR))
497fe927c51SPeter Avalos         return -1;
498fe927c51SPeter Avalos 
499fe927c51SPeter Avalos     /* process a skip request */
500fe927c51SPeter Avalos     if (state->seek) {
501fe927c51SPeter Avalos         state->seek = 0;
502fe927c51SPeter Avalos         if (gz_skip(state, state->skip) == -1)
503fe927c51SPeter Avalos             return -1;
504fe927c51SPeter Avalos     }
505fe927c51SPeter Avalos 
506fe927c51SPeter Avalos     /* can't push EOF */
507fe927c51SPeter Avalos     if (c < 0)
508fe927c51SPeter Avalos         return -1;
509fe927c51SPeter Avalos 
510fe927c51SPeter Avalos     /* if output buffer empty, put byte at end (allows more pushing) */
511712f98b7SJohn Marino     if (state->x.have == 0) {
512712f98b7SJohn Marino         state->x.have = 1;
513712f98b7SJohn Marino         state->x.next = state->out + (state->size << 1) - 1;
514*e041647aSSascha Wildner         state->x.next[0] = (unsigned char)c;
515712f98b7SJohn Marino         state->x.pos--;
516712f98b7SJohn Marino         state->past = 0;
517fe927c51SPeter Avalos         return c;
518fe927c51SPeter Avalos     }
519fe927c51SPeter Avalos 
520fe927c51SPeter Avalos     /* if no room, give up (must have already done a gzungetc()) */
521712f98b7SJohn Marino     if (state->x.have == (state->size << 1)) {
522712f98b7SJohn Marino         gz_error(state, Z_DATA_ERROR, "out of room to push characters");
523fe927c51SPeter Avalos         return -1;
524fe927c51SPeter Avalos     }
525fe927c51SPeter Avalos 
526fe927c51SPeter Avalos     /* slide output data if needed and insert byte before existing data */
527712f98b7SJohn Marino     if (state->x.next == state->out) {
528712f98b7SJohn Marino         unsigned char *src = state->out + state->x.have;
529fe927c51SPeter Avalos         unsigned char *dest = state->out + (state->size << 1);
530fe927c51SPeter Avalos         while (src > state->out)
531fe927c51SPeter Avalos             *--dest = *--src;
532712f98b7SJohn Marino         state->x.next = dest;
533fe927c51SPeter Avalos     }
534712f98b7SJohn Marino     state->x.have++;
535712f98b7SJohn Marino     state->x.next--;
536*e041647aSSascha Wildner     state->x.next[0] = (unsigned char)c;
537712f98b7SJohn Marino     state->x.pos--;
538712f98b7SJohn Marino     state->past = 0;
539fe927c51SPeter Avalos     return c;
540fe927c51SPeter Avalos }
541fe927c51SPeter Avalos 
542fe927c51SPeter Avalos /* -- see zlib.h -- */
gzgets(file,buf,len)543fe927c51SPeter Avalos char * ZEXPORT gzgets(file, buf, len)
544fe927c51SPeter Avalos     gzFile file;
545fe927c51SPeter Avalos     char *buf;
546fe927c51SPeter Avalos     int len;
547fe927c51SPeter Avalos {
548fe927c51SPeter Avalos     unsigned left, n;
549fe927c51SPeter Avalos     char *str;
550fe927c51SPeter Avalos     unsigned char *eol;
551fe927c51SPeter Avalos     gz_statep state;
552fe927c51SPeter Avalos 
553fe927c51SPeter Avalos     /* check parameters and get internal structure */
554fe927c51SPeter Avalos     if (file == NULL || buf == NULL || len < 1)
555fe927c51SPeter Avalos         return NULL;
556fe927c51SPeter Avalos     state = (gz_statep)file;
557fe927c51SPeter Avalos 
558712f98b7SJohn Marino     /* check that we're reading and that there's no (serious) error */
559712f98b7SJohn Marino     if (state->mode != GZ_READ ||
560712f98b7SJohn Marino         (state->err != Z_OK && state->err != Z_BUF_ERROR))
561fe927c51SPeter Avalos         return NULL;
562fe927c51SPeter Avalos 
563fe927c51SPeter Avalos     /* process a skip request */
564fe927c51SPeter Avalos     if (state->seek) {
565fe927c51SPeter Avalos         state->seek = 0;
566fe927c51SPeter Avalos         if (gz_skip(state, state->skip) == -1)
567fe927c51SPeter Avalos             return NULL;
568fe927c51SPeter Avalos     }
569fe927c51SPeter Avalos 
570fe927c51SPeter Avalos     /* copy output bytes up to new line or len - 1, whichever comes first --
571fe927c51SPeter Avalos        append a terminating zero to the string (we don't check for a zero in
572fe927c51SPeter Avalos        the contents, let the user worry about that) */
573fe927c51SPeter Avalos     str = buf;
574fe927c51SPeter Avalos     left = (unsigned)len - 1;
575fe927c51SPeter Avalos     if (left) do {
576fe927c51SPeter Avalos         /* assure that something is in the output buffer */
577712f98b7SJohn Marino         if (state->x.have == 0 && gz_fetch(state) == -1)
578fe927c51SPeter Avalos             return NULL;                /* error */
579712f98b7SJohn Marino         if (state->x.have == 0) {       /* end of file */
580712f98b7SJohn Marino             state->past = 1;            /* read past end */
581712f98b7SJohn Marino             break;                      /* return what we have */
582fe927c51SPeter Avalos         }
583fe927c51SPeter Avalos 
584fe927c51SPeter Avalos         /* look for end-of-line in current output buffer */
585712f98b7SJohn Marino         n = state->x.have > left ? left : state->x.have;
58653ddf67cSJohn Marino         eol = (unsigned char *)memchr(state->x.next, '\n', n);
587fe927c51SPeter Avalos         if (eol != NULL)
588712f98b7SJohn Marino             n = (unsigned)(eol - state->x.next) + 1;
589fe927c51SPeter Avalos 
590fe927c51SPeter Avalos         /* copy through end-of-line, or remainder if not found */
591712f98b7SJohn Marino         memcpy(buf, state->x.next, n);
592712f98b7SJohn Marino         state->x.have -= n;
593712f98b7SJohn Marino         state->x.next += n;
594712f98b7SJohn Marino         state->x.pos += n;
595fe927c51SPeter Avalos         left -= n;
596fe927c51SPeter Avalos         buf += n;
597fe927c51SPeter Avalos     } while (left && eol == NULL);
598fe927c51SPeter Avalos 
599712f98b7SJohn Marino     /* return terminated string, or if nothing, end of file */
600712f98b7SJohn Marino     if (buf == str)
601712f98b7SJohn Marino         return NULL;
602fe927c51SPeter Avalos     buf[0] = 0;
603fe927c51SPeter Avalos     return str;
604fe927c51SPeter Avalos }
605fe927c51SPeter Avalos 
606fe927c51SPeter Avalos /* -- see zlib.h -- */
gzdirect(file)607fe927c51SPeter Avalos int ZEXPORT gzdirect(file)
608fe927c51SPeter Avalos     gzFile file;
609fe927c51SPeter Avalos {
610fe927c51SPeter Avalos     gz_statep state;
611fe927c51SPeter Avalos 
612fe927c51SPeter Avalos     /* get internal structure */
613fe927c51SPeter Avalos     if (file == NULL)
614fe927c51SPeter Avalos         return 0;
615fe927c51SPeter Avalos     state = (gz_statep)file;
616fe927c51SPeter Avalos 
617fe927c51SPeter Avalos     /* if the state is not known, but we can find out, then do so (this is
618fe927c51SPeter Avalos        mainly for right after a gzopen() or gzdopen()) */
619712f98b7SJohn Marino     if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
620712f98b7SJohn Marino         (void)gz_look(state);
621fe927c51SPeter Avalos 
622712f98b7SJohn Marino     /* return 1 if transparent, 0 if processing a gzip stream */
623fe927c51SPeter Avalos     return state->direct;
624fe927c51SPeter Avalos }
625fe927c51SPeter Avalos 
626fe927c51SPeter Avalos /* -- see zlib.h -- */
gzclose_r(file)627fe927c51SPeter Avalos int ZEXPORT gzclose_r(file)
628fe927c51SPeter Avalos     gzFile file;
629fe927c51SPeter Avalos {
630712f98b7SJohn Marino     int ret, err;
631fe927c51SPeter Avalos     gz_statep state;
632fe927c51SPeter Avalos 
633fe927c51SPeter Avalos     /* get internal structure */
634fe927c51SPeter Avalos     if (file == NULL)
635fe927c51SPeter Avalos         return Z_STREAM_ERROR;
636fe927c51SPeter Avalos     state = (gz_statep)file;
637fe927c51SPeter Avalos 
638fe927c51SPeter Avalos     /* check that we're reading */
639fe927c51SPeter Avalos     if (state->mode != GZ_READ)
640fe927c51SPeter Avalos         return Z_STREAM_ERROR;
641fe927c51SPeter Avalos 
642fe927c51SPeter Avalos     /* free memory and close file */
643fe927c51SPeter Avalos     if (state->size) {
644fe927c51SPeter Avalos         inflateEnd(&(state->strm));
645fe927c51SPeter Avalos         free(state->out);
646fe927c51SPeter Avalos         free(state->in);
647fe927c51SPeter Avalos     }
648712f98b7SJohn Marino     err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
649fe927c51SPeter Avalos     gz_error(state, Z_OK, NULL);
650fe927c51SPeter Avalos     free(state->path);
651fe927c51SPeter Avalos     ret = close(state->fd);
652fe927c51SPeter Avalos     free(state);
653712f98b7SJohn Marino     return ret ? Z_ERRNO : err;
654fe927c51SPeter Avalos }
655