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