cc68a136 |
1 | /* gzio.c -- IO on .gz files |
2 | * Copyright (C) 1995-2005 Jean-loup Gailly. |
3 | * For conditions of distribution and use, see copyright notice in zlib.h |
4 | * |
5 | * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. |
6 | */ |
7 | |
8 | /* @(#) $Id$ */ |
9 | |
10 | #include <stdio.h> |
11 | #include <stdlib.h> |
12 | #include <string.h> |
13 | #include <errno.h> |
14 | |
15 | //#include "zutil.h" |
16 | #include <EZlib.h> |
17 | #include "gzio_symb.h" |
18 | |
19 | #ifndef Z_BUFSIZE |
20 | # ifdef MAXSEG_64K |
21 | # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ |
22 | # else |
23 | # define Z_BUFSIZE 16384 |
24 | # endif |
25 | #endif |
26 | |
27 | #ifndef local |
28 | # define local static |
29 | #endif |
30 | |
31 | #ifndef OS_CODE |
32 | # define OS_CODE 0x03 /* assume Unix */ |
33 | #endif |
34 | |
35 | #ifndef F_OPEN |
36 | # define F_OPEN(name, mode) fopen((name), (mode)) |
37 | #endif |
38 | |
39 | #if MAX_MEM_LEVEL >= 8 |
40 | # define DEF_MEM_LEVEL 8 |
41 | #else |
42 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL |
43 | #endif |
44 | |
45 | #define ALLOC(size) malloc(size) |
46 | #define TRYFREE(p) {if (p) free(p);} |
47 | #define zmemcpy memcpy |
48 | |
49 | static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ |
50 | |
51 | /* gzip flag byte */ |
52 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ |
53 | #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ |
54 | #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ |
55 | #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ |
56 | #define COMMENT 0x10 /* bit 4 set: file comment present */ |
57 | #define RESERVED 0xE0 /* bits 5..7: reserved */ |
58 | |
59 | typedef struct gz_stream { |
60 | z_stream stream; |
61 | int z_err; /* error code for last stream operation */ |
62 | int z_eof; /* set if end of input file */ |
63 | FILE *file; /* .gz file */ |
64 | Byte *inbuf; /* input buffer */ |
65 | Byte *outbuf; /* output buffer */ |
66 | uLong crc; /* crc32 of uncompressed data */ |
67 | char *msg; /* error message */ |
68 | char *path; /* path name for debugging only */ |
69 | int transparent; /* 1 if input file is not a .gz file */ |
70 | char mode; /* 'w' or 'r' */ |
71 | z_off_t start; /* start of compressed data in file (header skipped) */ |
72 | z_off_t in; /* bytes into deflate or inflate */ |
73 | z_off_t out; /* bytes out of deflate or inflate */ |
74 | int back; /* one character push-back */ |
75 | int last; /* true if push-back is last character */ |
76 | } gz_stream; |
77 | |
78 | |
79 | local gzFile gz_open OF((const char *path, const char *mode, int fd)); |
80 | local int do_flush OF((gzFile file, int flush)); |
81 | local int get_byte OF((gz_stream *s)); |
82 | local void check_header OF((gz_stream *s)); |
83 | local int destroy OF((gz_stream *s)); |
84 | local void putLong OF((FILE *file, uLong x)); |
85 | local uLong getLong OF((gz_stream *s)); |
86 | |
87 | /* =========================================================================== |
88 | Opens a gzip (.gz) file for reading or writing. The mode parameter |
89 | is as in fopen ("rb" or "wb"). The file is given either by file descriptor |
90 | or path name (if fd == -1). |
91 | gz_open returns NULL if the file could not be opened or if there was |
92 | insufficient memory to allocate the (de)compression state; errno |
93 | can be checked to distinguish the two cases (if errno is zero, the |
94 | zlib error is Z_MEM_ERROR). |
95 | */ |
96 | local gzFile gz_open (path, mode, fd) |
97 | const char *path; |
98 | const char *mode; |
99 | int fd; |
100 | { |
101 | int err; |
102 | int level = Z_DEFAULT_COMPRESSION; /* compression level */ |
103 | int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ |
104 | char *p = (char*)mode; |
105 | gz_stream *s; |
106 | char fmode[80]; /* copy of mode, without the compression level */ |
107 | char *m = fmode; |
108 | |
109 | if (!path || !mode) return Z_NULL; |
110 | |
111 | s = (gz_stream *)ALLOC(sizeof(gz_stream)); |
112 | if (!s) return Z_NULL; |
113 | |
114 | s->stream.zalloc = (alloc_func)0; |
115 | s->stream.zfree = (free_func)0; |
116 | s->stream.opaque = (voidpf)0; |
117 | s->stream.next_in = s->inbuf = Z_NULL; |
118 | s->stream.next_out = s->outbuf = Z_NULL; |
119 | s->stream.avail_in = s->stream.avail_out = 0; |
120 | s->file = NULL; |
121 | s->z_err = Z_OK; |
122 | s->z_eof = 0; |
123 | s->in = 0; |
124 | s->out = 0; |
125 | s->back = EOF; |
126 | s->crc = crc32(0L, Z_NULL, 0); |
127 | s->msg = NULL; |
128 | s->transparent = 0; |
129 | |
130 | s->path = (char*)ALLOC(strlen(path)+1); |
131 | if (s->path == NULL) { |
132 | return destroy(s), (gzFile)Z_NULL; |
133 | } |
134 | strcpy(s->path, path); /* do this early for debugging */ |
135 | |
136 | s->mode = '\0'; |
137 | do { |
138 | if (*p == 'r') s->mode = 'r'; |
139 | if (*p == 'w' || *p == 'a') s->mode = 'w'; |
140 | if (*p >= '0' && *p <= '9') { |
141 | level = *p - '0'; |
142 | } else if (*p == 'f') { |
143 | strategy = Z_FILTERED; |
144 | } else if (*p == 'h') { |
145 | strategy = Z_HUFFMAN_ONLY; |
146 | } else if (*p == 'R') { |
147 | strategy = Z_RLE; |
148 | } else { |
149 | *m++ = *p; /* copy the mode */ |
150 | } |
151 | } while (*p++ && m != fmode + sizeof(fmode)); |
152 | if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; |
153 | |
154 | if (s->mode == 'w') { |
155 | #ifdef NO_GZCOMPRESS |
156 | err = Z_STREAM_ERROR; |
157 | #else |
158 | err = deflateInit2(&(s->stream), level, |
159 | Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); |
160 | /* windowBits is passed < 0 to suppress zlib header */ |
161 | |
162 | s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); |
163 | #endif |
164 | if (err != Z_OK || s->outbuf == Z_NULL) { |
165 | return destroy(s), (gzFile)Z_NULL; |
166 | } |
167 | } else { |
168 | s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); |
169 | |
170 | err = inflateInit2(&(s->stream), -MAX_WBITS); |
171 | /* windowBits is passed < 0 to tell that there is no zlib header. |
172 | * Note that in this case inflate *requires* an extra "dummy" byte |
173 | * after the compressed stream in order to complete decompression and |
174 | * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are |
175 | * present after the compressed stream. |
176 | */ |
177 | if (err != Z_OK || s->inbuf == Z_NULL) { |
178 | return destroy(s), (gzFile)Z_NULL; |
179 | } |
180 | } |
181 | s->stream.avail_out = Z_BUFSIZE; |
182 | |
183 | errno = 0; |
184 | s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); |
185 | |
186 | if (s->file == NULL) { |
187 | return destroy(s), (gzFile)Z_NULL; |
188 | } |
189 | if (s->mode == 'w') { |
190 | /* Write a very simple .gz header: |
191 | */ |
192 | fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], |
193 | Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); |
194 | s->start = 10L; |
195 | /* We use 10L instead of ftell(s->file) to because ftell causes an |
196 | * fflush on some systems. This version of the library doesn't use |
197 | * start anyway in write mode, so this initialization is not |
198 | * necessary. |
199 | */ |
200 | } else { |
201 | check_header(s); /* skip the .gz header */ |
202 | s->start = ftell(s->file) - s->stream.avail_in; |
203 | } |
204 | |
205 | return (gzFile)s; |
206 | } |
207 | |
208 | /* =========================================================================== |
209 | Opens a gzip (.gz) file for reading or writing. |
210 | */ |
211 | gzFile ZEXPORT gzopen (path, mode) |
212 | const char *path; |
213 | const char *mode; |
214 | { |
215 | return gz_open (path, mode, -1); |
216 | } |
217 | |
218 | /* =========================================================================== |
219 | * Update the compression level and strategy |
220 | */ |
221 | int ZEXPORT gzsetparams (file, level, strategy) |
222 | gzFile file; |
223 | int level; |
224 | int strategy; |
225 | { |
226 | gz_stream *s = (gz_stream*)file; |
227 | |
228 | if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; |
229 | |
230 | /* Make room to allow flushing */ |
231 | if (s->stream.avail_out == 0) { |
232 | |
233 | s->stream.next_out = s->outbuf; |
234 | if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { |
235 | s->z_err = Z_ERRNO; |
236 | } |
237 | s->stream.avail_out = Z_BUFSIZE; |
238 | } |
239 | |
240 | return deflateParams (&(s->stream), level, strategy); |
241 | } |
242 | |
243 | /* =========================================================================== |
244 | Read a byte from a gz_stream; update next_in and avail_in. Return EOF |
245 | for end of file. |
246 | IN assertion: the stream s has been sucessfully opened for reading. |
247 | */ |
248 | local int get_byte(s) |
249 | gz_stream *s; |
250 | { |
251 | if (s->z_eof) return EOF; |
252 | if (s->stream.avail_in == 0) { |
253 | errno = 0; |
254 | s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); |
255 | if (s->stream.avail_in == 0) { |
256 | s->z_eof = 1; |
257 | if (ferror(s->file)) s->z_err = Z_ERRNO; |
258 | return EOF; |
259 | } |
260 | s->stream.next_in = s->inbuf; |
261 | } |
262 | s->stream.avail_in--; |
263 | return *(s->stream.next_in)++; |
264 | } |
265 | |
266 | /* =========================================================================== |
267 | Check the gzip header of a gz_stream opened for reading. Set the stream |
268 | mode to transparent if the gzip magic header is not present; set s->err |
269 | to Z_DATA_ERROR if the magic header is present but the rest of the header |
270 | is incorrect. |
271 | IN assertion: the stream s has already been created sucessfully; |
272 | s->stream.avail_in is zero for the first time, but may be non-zero |
273 | for concatenated .gz files. |
274 | */ |
275 | local void check_header(s) |
276 | gz_stream *s; |
277 | { |
278 | int method; /* method byte */ |
279 | int flags; /* flags byte */ |
280 | uInt len; |
281 | int c; |
282 | |
283 | /* Assure two bytes in the buffer so we can peek ahead -- handle case |
284 | where first byte of header is at the end of the buffer after the last |
285 | gzip segment */ |
286 | len = s->stream.avail_in; |
287 | if (len < 2) { |
288 | if (len) s->inbuf[0] = s->stream.next_in[0]; |
289 | errno = 0; |
290 | len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); |
291 | if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; |
292 | s->stream.avail_in += len; |
293 | s->stream.next_in = s->inbuf; |
294 | if (s->stream.avail_in < 2) { |
295 | s->transparent = s->stream.avail_in; |
296 | return; |
297 | } |
298 | } |
299 | |
300 | /* Peek ahead to check the gzip magic header */ |
301 | if (s->stream.next_in[0] != gz_magic[0] || |
302 | s->stream.next_in[1] != gz_magic[1]) { |
303 | s->transparent = 1; |
304 | return; |
305 | } |
306 | s->stream.avail_in -= 2; |
307 | s->stream.next_in += 2; |
308 | |
309 | /* Check the rest of the gzip header */ |
310 | method = get_byte(s); |
311 | flags = get_byte(s); |
312 | if (method != Z_DEFLATED || (flags & RESERVED) != 0) { |
313 | s->z_err = Z_DATA_ERROR; |
314 | return; |
315 | } |
316 | |
317 | /* Discard time, xflags and OS code: */ |
318 | for (len = 0; len < 6; len++) (void)get_byte(s); |
319 | |
320 | if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ |
321 | len = (uInt)get_byte(s); |
322 | len += ((uInt)get_byte(s))<<8; |
323 | /* len is garbage if EOF but the loop below will quit anyway */ |
324 | while (len-- != 0 && get_byte(s) != EOF) ; |
325 | } |
326 | if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ |
327 | while ((c = get_byte(s)) != 0 && c != EOF) ; |
328 | } |
329 | if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ |
330 | while ((c = get_byte(s)) != 0 && c != EOF) ; |
331 | } |
332 | if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ |
333 | for (len = 0; len < 2; len++) (void)get_byte(s); |
334 | } |
335 | s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; |
336 | } |
337 | |
338 | /* =========================================================================== |
339 | * Cleanup then free the given gz_stream. Return a zlib error code. |
340 | Try freeing in the reverse order of allocations. |
341 | */ |
342 | local int destroy (s) |
343 | gz_stream *s; |
344 | { |
345 | int err = Z_OK; |
346 | |
347 | if (!s) return Z_STREAM_ERROR; |
348 | |
349 | TRYFREE(s->msg); |
350 | |
351 | if (s->stream.state != NULL) { |
352 | if (s->mode == 'w') { |
353 | #ifdef NO_GZCOMPRESS |
354 | err = Z_STREAM_ERROR; |
355 | #else |
356 | err = deflateEnd(&(s->stream)); |
357 | #endif |
358 | } else if (s->mode == 'r') { |
359 | err = inflateEnd(&(s->stream)); |
360 | } |
361 | } |
362 | if (s->file != NULL && fclose(s->file)) { |
363 | #ifdef ESPIPE |
364 | if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ |
365 | #endif |
366 | err = Z_ERRNO; |
367 | } |
368 | if (s->z_err < 0) err = s->z_err; |
369 | |
370 | TRYFREE(s->inbuf); |
371 | TRYFREE(s->outbuf); |
372 | TRYFREE(s->path); |
373 | TRYFREE(s); |
374 | return err; |
375 | } |
376 | |
377 | /* =========================================================================== |
378 | Reads the given number of uncompressed bytes from the compressed file. |
379 | gzread returns the number of bytes actually read (0 for end of file). |
380 | */ |
381 | int ZEXPORT gzread (file, buf, len) |
382 | gzFile file; |
383 | voidp buf; |
384 | unsigned len; |
385 | { |
386 | gz_stream *s = (gz_stream*)file; |
387 | Bytef *start = (Bytef*)buf; /* starting point for crc computation */ |
388 | Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ |
389 | |
390 | if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; |
391 | |
392 | if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; |
393 | if (s->z_err == Z_STREAM_END) return 0; /* EOF */ |
394 | |
395 | next_out = (Byte*)buf; |
396 | s->stream.next_out = (Bytef*)buf; |
397 | s->stream.avail_out = len; |
398 | |
399 | if (s->stream.avail_out && s->back != EOF) { |
400 | *next_out++ = s->back; |
401 | s->stream.next_out++; |
402 | s->stream.avail_out--; |
403 | s->back = EOF; |
404 | s->out++; |
405 | start++; |
406 | if (s->last) { |
407 | s->z_err = Z_STREAM_END; |
408 | return 1; |
409 | } |
410 | } |
411 | |
412 | while (s->stream.avail_out != 0) { |
413 | |
414 | if (s->transparent) { |
415 | /* Copy first the lookahead bytes: */ |
416 | uInt n = s->stream.avail_in; |
417 | if (n > s->stream.avail_out) n = s->stream.avail_out; |
418 | if (n > 0) { |
419 | zmemcpy(s->stream.next_out, s->stream.next_in, n); |
420 | next_out += n; |
421 | s->stream.next_out = next_out; |
422 | s->stream.next_in += n; |
423 | s->stream.avail_out -= n; |
424 | s->stream.avail_in -= n; |
425 | } |
426 | if (s->stream.avail_out > 0) { |
427 | s->stream.avail_out -= |
428 | (uInt)fread(next_out, 1, s->stream.avail_out, s->file); |
429 | } |
430 | len -= s->stream.avail_out; |
431 | s->in += len; |
432 | s->out += len; |
433 | if (len == 0) s->z_eof = 1; |
434 | return (int)len; |
435 | } |
436 | if (s->stream.avail_in == 0 && !s->z_eof) { |
437 | |
438 | errno = 0; |
439 | s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); |
440 | if (s->stream.avail_in == 0) { |
441 | s->z_eof = 1; |
442 | if (ferror(s->file)) { |
443 | s->z_err = Z_ERRNO; |
444 | break; |
445 | } |
446 | } |
447 | s->stream.next_in = s->inbuf; |
448 | } |
449 | s->in += s->stream.avail_in; |
450 | s->out += s->stream.avail_out; |
451 | s->z_err = inflate(&(s->stream), Z_NO_FLUSH); |
452 | s->in -= s->stream.avail_in; |
453 | s->out -= s->stream.avail_out; |
454 | |
455 | if (s->z_err == Z_STREAM_END) { |
456 | /* Check CRC and original size */ |
457 | s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); |
458 | start = s->stream.next_out; |
459 | |
460 | if (getLong(s) != s->crc) { |
461 | s->z_err = Z_DATA_ERROR; |
462 | } else { |
463 | (void)getLong(s); |
464 | /* The uncompressed length returned by above getlong() may be |
465 | * different from s->out in case of concatenated .gz files. |
466 | * Check for such files: |
467 | */ |
468 | check_header(s); |
469 | if (s->z_err == Z_OK) { |
470 | inflateReset(&(s->stream)); |
471 | s->crc = crc32(0L, Z_NULL, 0); |
472 | } |
473 | } |
474 | } |
475 | if (s->z_err != Z_OK || s->z_eof) break; |
476 | } |
477 | s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); |
478 | |
479 | if (len == s->stream.avail_out && |
480 | (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) |
481 | return -1; |
482 | return (int)(len - s->stream.avail_out); |
483 | } |
484 | |
485 | |
486 | #ifndef NO_GZCOMPRESS |
487 | /* =========================================================================== |
488 | Writes the given number of uncompressed bytes into the compressed file. |
489 | gzwrite returns the number of bytes actually written (0 in case of error). |
490 | */ |
491 | int ZEXPORT gzwrite (file, buf, len) |
492 | gzFile file; |
493 | voidpc buf; |
494 | unsigned len; |
495 | { |
496 | gz_stream *s = (gz_stream*)file; |
497 | |
498 | if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; |
499 | |
500 | s->stream.next_in = (Bytef*)buf; |
501 | s->stream.avail_in = len; |
502 | |
503 | while (s->stream.avail_in != 0) { |
504 | |
505 | if (s->stream.avail_out == 0) { |
506 | |
507 | s->stream.next_out = s->outbuf; |
508 | if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { |
509 | s->z_err = Z_ERRNO; |
510 | break; |
511 | } |
512 | s->stream.avail_out = Z_BUFSIZE; |
513 | } |
514 | s->in += s->stream.avail_in; |
515 | s->out += s->stream.avail_out; |
516 | s->z_err = deflate(&(s->stream), Z_NO_FLUSH); |
517 | s->in -= s->stream.avail_in; |
518 | s->out -= s->stream.avail_out; |
519 | if (s->z_err != Z_OK) break; |
520 | } |
521 | s->crc = crc32(s->crc, (const Bytef *)buf, len); |
522 | |
523 | return (int)(len - s->stream.avail_in); |
524 | } |
525 | |
526 | |
527 | /* =========================================================================== |
528 | Flushes all pending output into the compressed file. The parameter |
529 | flush is as in the deflate() function. |
530 | */ |
531 | local int do_flush (file, flush) |
532 | gzFile file; |
533 | int flush; |
534 | { |
535 | uInt len; |
536 | int done = 0; |
537 | gz_stream *s = (gz_stream*)file; |
538 | |
539 | if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; |
540 | |
541 | s->stream.avail_in = 0; /* should be zero already anyway */ |
542 | |
543 | for (;;) { |
544 | len = Z_BUFSIZE - s->stream.avail_out; |
545 | |
546 | if (len != 0) { |
547 | if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { |
548 | s->z_err = Z_ERRNO; |
549 | return Z_ERRNO; |
550 | } |
551 | s->stream.next_out = s->outbuf; |
552 | s->stream.avail_out = Z_BUFSIZE; |
553 | } |
554 | if (done) break; |
555 | s->out += s->stream.avail_out; |
556 | s->z_err = deflate(&(s->stream), flush); |
557 | s->out -= s->stream.avail_out; |
558 | |
559 | /* Ignore the second of two consecutive flushes: */ |
560 | if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; |
561 | |
562 | /* deflate has finished flushing only when it hasn't used up |
563 | * all the available space in the output buffer: |
564 | */ |
565 | done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); |
566 | |
567 | if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; |
568 | } |
569 | return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; |
570 | } |
571 | |
572 | #endif /* NO_GZCOMPRESS */ |
573 | |
574 | |
575 | /* =========================================================================== |
576 | Outputs a long in LSB order to the given file |
577 | */ |
578 | local void putLong (file, x) |
579 | FILE *file; |
580 | uLong x; |
581 | { |
582 | int n; |
583 | for (n = 0; n < 4; n++) { |
584 | fputc((int)(x & 0xff), file); |
585 | x >>= 8; |
586 | } |
587 | } |
588 | |
589 | /* =========================================================================== |
590 | Reads a long in LSB order from the given gz_stream. Sets z_err in case |
591 | of error. |
592 | */ |
593 | local uLong getLong (s) |
594 | gz_stream *s; |
595 | { |
596 | uLong x = (uLong)get_byte(s); |
597 | int c; |
598 | |
599 | x += ((uLong)get_byte(s))<<8; |
600 | x += ((uLong)get_byte(s))<<16; |
601 | c = get_byte(s); |
602 | if (c == EOF) s->z_err = Z_DATA_ERROR; |
603 | x += ((uLong)c)<<24; |
604 | return x; |
605 | } |
606 | |
607 | /* =========================================================================== |
608 | Flushes all pending output if necessary, closes the compressed file |
609 | and deallocates all the (de)compression state. |
610 | */ |
611 | int ZEXPORT gzclose (file) |
612 | gzFile file; |
613 | { |
614 | gz_stream *s = (gz_stream*)file; |
615 | |
616 | if (s == NULL) return Z_STREAM_ERROR; |
617 | |
618 | if (s->mode == 'w') { |
619 | #ifdef NO_GZCOMPRESS |
620 | return Z_STREAM_ERROR; |
621 | #else |
622 | if (do_flush (file, Z_FINISH) != Z_OK) |
623 | return destroy((gz_stream*)file); |
624 | |
625 | putLong (s->file, s->crc); |
626 | putLong (s->file, (uLong)(s->in & 0xffffffff)); |
627 | #endif |
628 | } |
629 | return destroy((gz_stream*)file); |
630 | } |