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