summaryrefslogtreecommitdiff
path: root/gzio.c
diff options
context:
space:
mode:
Diffstat (limited to 'gzio.c')
-rw-r--r--gzio.c347
1 files changed, 316 insertions, 31 deletions
diff --git a/gzio.c b/gzio.c
index 6c82677..0b9915c 100644
--- a/gzio.c
+++ b/gzio.c
@@ -1,9 +1,11 @@
1/* gzio.c -- IO on .gz files 1/* gzio.c -- IO on .gz files
2 * Copyright (C) 1995-1996 Jean-loup Gailly. 2 * Copyright (C) 1995-1998 Jean-loup Gailly.
3 * For conditions of distribution and use, see copyright notice in zlib.h 3 * For conditions of distribution and use, see copyright notice in zlib.h
4 *
5 * Compile this file with -DNO_DEFLATE to avoid the compression code.
4 */ 6 */
5 7
6/* $Id: gzio.c,v 1.14 1996/07/24 13:41:01 me Exp $ */ 8/* @(#) $Id$ */
7 9
8#include <stdio.h> 10#include <stdio.h>
9 11
@@ -38,10 +40,12 @@ typedef struct gz_stream {
38 char *path; /* path name for debugging only */ 40 char *path; /* path name for debugging only */
39 int transparent; /* 1 if input file is not a .gz file */ 41 int transparent; /* 1 if input file is not a .gz file */
40 char mode; /* 'w' or 'r' */ 42 char mode; /* 'w' or 'r' */
43 long startpos; /* start of compressed data in file (header skipped) */
41} gz_stream; 44} gz_stream;
42 45
43 46
44local gzFile gz_open OF((const char *path, const char *mode, int fd)); 47local gzFile gz_open OF((const char *path, const char *mode, int fd));
48local int do_flush OF((gzFile file, int flush));
45local int get_byte OF((gz_stream *s)); 49local int get_byte OF((gz_stream *s));
46local void check_header OF((gz_stream *s)); 50local void check_header OF((gz_stream *s));
47local int destroy OF((gz_stream *s)); 51local int destroy OF((gz_stream *s));
@@ -64,6 +68,7 @@ local gzFile gz_open (path, mode, fd)
64{ 68{
65 int err; 69 int err;
66 int level = Z_DEFAULT_COMPRESSION; /* compression level */ 70 int level = Z_DEFAULT_COMPRESSION; /* compression level */
71 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
67 char *p = (char*)mode; 72 char *p = (char*)mode;
68 gz_stream *s; 73 gz_stream *s;
69 char fmode[80]; /* copy of mode, without the compression level */ 74 char fmode[80]; /* copy of mode, without the compression level */
@@ -99,6 +104,10 @@ local gzFile gz_open (path, mode, fd)
99 if (*p == 'w' || *p == 'a') s->mode = 'w'; 104 if (*p == 'w' || *p == 'a') s->mode = 'w';
100 if (*p >= '0' && *p <= '9') { 105 if (*p >= '0' && *p <= '9') {
101 level = *p - '0'; 106 level = *p - '0';
107 } else if (*p == 'f') {
108 strategy = Z_FILTERED;
109 } else if (*p == 'h') {
110 strategy = Z_HUFFMAN_ONLY;
102 } else { 111 } else {
103 *m++ = *p; /* copy the mode */ 112 *m++ = *p; /* copy the mode */
104 } 113 }
@@ -106,19 +115,24 @@ local gzFile gz_open (path, mode, fd)
106 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; 115 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
107 116
108 if (s->mode == 'w') { 117 if (s->mode == 'w') {
118#ifdef NO_DEFLATE
119 err = Z_STREAM_ERROR;
120#else
109 err = deflateInit2(&(s->stream), level, 121 err = deflateInit2(&(s->stream), level,
110 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0); 122 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
111 /* windowBits is passed < 0 to suppress zlib header */ 123 /* windowBits is passed < 0 to suppress zlib header */
112 124
113 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); 125 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
114 126#endif
115 if (err != Z_OK || s->outbuf == Z_NULL) { 127 if (err != Z_OK || s->outbuf == Z_NULL) {
116 return destroy(s), (gzFile)Z_NULL; 128 return destroy(s), (gzFile)Z_NULL;
117 } 129 }
118 } else { 130 } else {
119 err = inflateInit2(&(s->stream), -MAX_WBITS);
120 s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); 131 s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
121 132
133 err = inflateInit2(&(s->stream), -MAX_WBITS);
134 /* windowBits is passed < 0 to tell that there is no zlib header */
135
122 if (err != Z_OK || s->inbuf == Z_NULL) { 136 if (err != Z_OK || s->inbuf == Z_NULL) {
123 return destroy(s), (gzFile)Z_NULL; 137 return destroy(s), (gzFile)Z_NULL;
124 } 138 }
@@ -126,7 +140,7 @@ local gzFile gz_open (path, mode, fd)
126 s->stream.avail_out = Z_BUFSIZE; 140 s->stream.avail_out = Z_BUFSIZE;
127 141
128 errno = 0; 142 errno = 0;
129 s->file = fd < 0 ? FOPEN(path, fmode) : (FILE*)fdopen(fd, fmode); 143 s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
130 144
131 if (s->file == NULL) { 145 if (s->file == NULL) {
132 return destroy(s), (gzFile)Z_NULL; 146 return destroy(s), (gzFile)Z_NULL;
@@ -136,16 +150,19 @@ local gzFile gz_open (path, mode, fd)
136 */ 150 */
137 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], 151 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
138 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); 152 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
153 s->startpos = ftell(s->file);
139 } else { 154 } else {
140 check_header(s); /* skip the .gz header */ 155 check_header(s); /* skip the .gz header */
156 s->startpos = (ftell(s->file) - s->stream.avail_in);
141 } 157 }
158
142 return (gzFile)s; 159 return (gzFile)s;
143} 160}
144 161
145/* =========================================================================== 162/* ===========================================================================
146 Opens a gzip (.gz) file for reading or writing. 163 Opens a gzip (.gz) file for reading or writing.
147*/ 164*/
148gzFile gzopen (path, mode) 165gzFile EXPORT gzopen (path, mode)
149 const char *path; 166 const char *path;
150 const char *mode; 167 const char *mode;
151{ 168{
@@ -156,7 +173,7 @@ gzFile gzopen (path, mode)
156 Associate a gzFile with the file descriptor fd. fd is not dup'ed here 173 Associate a gzFile with the file descriptor fd. fd is not dup'ed here
157 to mimic the behavio(u)r of fdopen. 174 to mimic the behavio(u)r of fdopen.
158*/ 175*/
159gzFile gzdopen (fd, mode) 176gzFile EXPORT gzdopen (fd, mode)
160 int fd; 177 int fd;
161 const char *mode; 178 const char *mode;
162{ 179{
@@ -169,6 +186,31 @@ gzFile gzdopen (fd, mode)
169} 186}
170 187
171/* =========================================================================== 188/* ===========================================================================
189 * Update the compression level and strategy
190 */
191int EXPORT gzsetparams (file, level, strategy)
192 gzFile file;
193 int level;
194 int strategy;
195{
196 gz_stream *s = (gz_stream*)file;
197
198 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
199
200 /* Make room to allow flushing */
201 if (s->stream.avail_out == 0) {
202
203 s->stream.next_out = s->outbuf;
204 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
205 s->z_err = Z_ERRNO;
206 }
207 s->stream.avail_out = Z_BUFSIZE;
208 }
209
210 return deflateParams (&(s->stream), level, strategy);
211}
212
213/* ===========================================================================
172 Read a byte from a gz_stream; update next_in and avail_in. Return EOF 214 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
173 for end of file. 215 for end of file.
174 IN assertion: the stream s has been sucessfully opened for reading. 216 IN assertion: the stream s has been sucessfully opened for reading.
@@ -212,8 +254,11 @@ local void check_header(s)
212 for (len = 0; len < 2; len++) { 254 for (len = 0; len < 2; len++) {
213 c = get_byte(s); 255 c = get_byte(s);
214 if (c != gz_magic[len]) { 256 if (c != gz_magic[len]) {
215 s->transparent = 1; 257 if (len != 0) s->stream.avail_in++, s->stream.next_in--;
216 if (c != EOF) s->stream.avail_in++, s->stream.next_in--; 258 if (c != EOF) {
259 s->stream.avail_in++, s->stream.next_in--;
260 s->transparent = 1;
261 }
217 s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; 262 s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
218 return; 263 return;
219 } 264 }
@@ -260,14 +305,21 @@ local int destroy (s)
260 TRYFREE(s->msg); 305 TRYFREE(s->msg);
261 306
262 if (s->stream.state != NULL) { 307 if (s->stream.state != NULL) {
263 if (s->mode == 'w') { 308 if (s->mode == 'w') {
264 err = deflateEnd(&(s->stream)); 309#ifdef NO_DEFLATE
265 } else if (s->mode == 'r') { 310 err = Z_STREAM_ERROR;
266 err = inflateEnd(&(s->stream)); 311#else
267 } 312 err = deflateEnd(&(s->stream));
313#endif
314 } else if (s->mode == 'r') {
315 err = inflateEnd(&(s->stream));
316 }
268 } 317 }
269 if (s->file != NULL && fclose(s->file)) { 318 if (s->file != NULL && fclose(s->file)) {
270 err = Z_ERRNO; 319#ifdef ESPIPE
320 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
321#endif
322 err = Z_ERRNO;
271 } 323 }
272 if (s->z_err < 0) err = s->z_err; 324 if (s->z_err < 0) err = s->z_err;
273 325
@@ -282,13 +334,13 @@ local int destroy (s)
282 Reads the given number of uncompressed bytes from the compressed file. 334 Reads the given number of uncompressed bytes from the compressed file.
283 gzread returns the number of bytes actually read (0 for end of file). 335 gzread returns the number of bytes actually read (0 for end of file).
284*/ 336*/
285int gzread (file, buf, len) 337int EXPORT gzread (file, buf, len)
286 gzFile file; 338 gzFile file;
287 voidp buf; 339 voidp buf;
288 unsigned len; 340 unsigned len;
289{ 341{
290 gz_stream *s = (gz_stream*)file; 342 gz_stream *s = (gz_stream*)file;
291 Bytef *start = buf; /* starting point for crc computation */ 343 Bytef *start = (Bytef*)buf; /* starting point for crc computation */
292 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ 344 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
293 345
294 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; 346 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
@@ -296,7 +348,8 @@ int gzread (file, buf, len)
296 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; 348 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
297 if (s->z_err == Z_STREAM_END) return 0; /* EOF */ 349 if (s->z_err == Z_STREAM_END) return 0; /* EOF */
298 350
299 s->stream.next_out = next_out = buf; 351 next_out = (Byte*)buf;
352 s->stream.next_out = (Bytef*)buf;
300 s->stream.avail_out = len; 353 s->stream.avail_out = len;
301 354
302 while (s->stream.avail_out != 0) { 355 while (s->stream.avail_out != 0) {
@@ -345,7 +398,12 @@ int gzread (file, buf, len)
345 /* Check for concatenated .gz files: */ 398 /* Check for concatenated .gz files: */
346 check_header(s); 399 check_header(s);
347 if (s->z_err == Z_OK) { 400 if (s->z_err == Z_OK) {
401 uLong total_in = s->stream.total_in;
402 uLong total_out = s->stream.total_out;
403
348 inflateReset(&(s->stream)); 404 inflateReset(&(s->stream));
405 s->stream.total_in = total_in;
406 s->stream.total_out = total_out;
349 s->crc = crc32(0L, Z_NULL, 0); 407 s->crc = crc32(0L, Z_NULL, 0);
350 } 408 }
351 } 409 }
@@ -357,11 +415,26 @@ int gzread (file, buf, len)
357 return (int)(len - s->stream.avail_out); 415 return (int)(len - s->stream.avail_out);
358} 416}
359 417
418
419/* ===========================================================================
420 Reads one byte from the compressed file. gzgetc returns this byte
421 or -1 in case of end of file or error.
422*/
423int EXPORT gzgetc(file)
424 gzFile file;
425{
426 int c;
427
428 return gzread(file, &c, 1) == 1 ? c : -1;
429}
430
431
432#ifndef NO_DEFLATE
360/* =========================================================================== 433/* ===========================================================================
361 Writes the given number of uncompressed bytes into the compressed file. 434 Writes the given number of uncompressed bytes into the compressed file.
362 gzwrite returns the number of bytes actually written (0 in case of error). 435 gzwrite returns the number of bytes actually written (0 in case of error).
363*/ 436*/
364int gzwrite (file, buf, len) 437int EXPORT gzwrite (file, buf, len)
365 gzFile file; 438 gzFile file;
366 const voidp buf; 439 const voidp buf;
367 unsigned len; 440 unsigned len;
@@ -370,7 +443,7 @@ int gzwrite (file, buf, len)
370 443
371 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; 444 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
372 445
373 s->stream.next_in = buf; 446 s->stream.next_in = (Bytef*)buf;
374 s->stream.avail_in = len; 447 s->stream.avail_in = len;
375 448
376 while (s->stream.avail_in != 0) { 449 while (s->stream.avail_in != 0) {
@@ -387,18 +460,79 @@ int gzwrite (file, buf, len)
387 s->z_err = deflate(&(s->stream), Z_NO_FLUSH); 460 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
388 if (s->z_err != Z_OK) break; 461 if (s->z_err != Z_OK) break;
389 } 462 }
390 s->crc = crc32(s->crc, buf, len); 463 s->crc = crc32(s->crc, (const Bytef *)buf, len);
391 464
392 return (int)(len - s->stream.avail_in); 465 return (int)(len - s->stream.avail_in);
393} 466}
394 467
395/* =========================================================================== 468/* ===========================================================================
469 Converts, formats, and writes the args to the compressed file under
470 control of the format string, as in fprintf. gzprintf returns the number of
471 uncompressed bytes actually written (0 in case of error).
472*/
473#ifdef STDC
474#include <stdarg.h>
475
476int EXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
477{
478 char buf[Z_BUFSIZE];
479 va_list va;
480 int len;
481
482 va_start(va, format);
483#ifdef HAS_vsnprintf
484 len = vsnprintf(buf, sizeof(buf), format, va);
485#else
486 len = vsprintf(buf, format, va);
487#endif
488 va_end(va);
489 if (len <= 0) return 0;
490
491 return gzwrite(file, buf, (unsigned)len);
492}
493#else /* not ANSI C */
494
495int EXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
496 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
497 gzFile file;
498 const char *format;
499 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
500 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
501{
502 char buf[Z_BUFSIZE];
503 int len;
504
505#ifdef HAS_snprintf
506 snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
507 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
508#else
509 sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
510 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
511#endif
512 len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
513 if (len <= 0) return 0;
514
515 return gzwrite(file, buf, len);
516}
517#endif
518
519/* ===========================================================================
520 Writes c, converted to an unsigned char, into the compressed file.
521 gzputc returns the value that was written, or -1 in case of error.
522*/
523int EXPORT gzputc(file, c)
524 gzFile file;
525 int c;
526{
527 return gzwrite(file, &c, 1) == 1 ? c : -1;
528}
529
530
531/* ===========================================================================
396 Flushes all pending output into the compressed file. The parameter 532 Flushes all pending output into the compressed file. The parameter
397 flush is as in the deflate() function. 533 flush is as in the deflate() function.
398 gzflush should be called only when strictly necessary because it can
399 degrade compression.
400*/ 534*/
401int gzflush (file, flush) 535local int do_flush (file, flush)
402 gzFile file; 536 gzFile file;
403 int flush; 537 int flush;
404{ 538{
@@ -424,6 +558,9 @@ int gzflush (file, flush)
424 if (done) break; 558 if (done) break;
425 s->z_err = deflate(&(s->stream), flush); 559 s->z_err = deflate(&(s->stream), flush);
426 560
561 /* Ignore the second of two consecutive flushes: */
562 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
563
427 /* deflate has finished flushing only when it hasn't used up 564 /* deflate has finished flushing only when it hasn't used up
428 * all the available space in the output buffer: 565 * all the available space in the output buffer:
429 */ 566 */
@@ -431,9 +568,154 @@ int gzflush (file, flush)
431 568
432 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; 569 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
433 } 570 }
571 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
572}
573
574int EXPORT gzflush (file, flush)
575 gzFile file;
576 int flush;
577{
578 gz_stream *s = (gz_stream*)file;
579 int err = do_flush (file, flush);
580
581 if (err) return err;
434 fflush(s->file); 582 fflush(s->file);
435 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; 583 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
436} 584}
585#endif /* NO_DEFLATE */
586
587/* ===========================================================================
588 Sets the starting position for the next gzread or gzwrite on the given
589 compressed file. The offset represents a number of bytes in the
590 gzseek returns the resulting offset location as measured in bytes from
591 the beginning of the uncompressed stream, or -1 in case of error.
592 SEEK_END is not implemented, returns error.
593 In this version of the library, gzseek can be extremely slow.
594*/
595z_off_t EXPORT gzseek (file, offset, whence)
596 gzFile file;
597 z_off_t offset;
598 int whence;
599{
600 gz_stream *s = (gz_stream*)file;
601
602 if (s == NULL || whence == SEEK_END || s->z_err == Z_ERRNO) return -1L;
603
604 s->z_err = Z_OK;
605 s->z_eof = 0;
606
607 if (s->mode == 'w') {
608#ifdef NO_DEFLATE
609 return -1L;
610#else
611 if (whence == SEEK_SET) {
612 offset -= s->stream.total_out;
613 }
614 if (offset < 0) return -1L;
615
616 /* At this point, offset is the number of zero bytes to write. */
617 if (s->inbuf == Z_NULL) {
618 s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
619 zmemzero(s->inbuf, Z_BUFSIZE);
620 }
621 while (offset > 0) {
622 uInt size = Z_BUFSIZE;
623 if (offset < Z_BUFSIZE) size = (uInt)offset;
624
625 size = gzwrite(file, s->inbuf, size);
626 if (size == 0) return -1L;
627
628 offset -= size;
629 }
630 return s->stream.total_in;
631#endif
632 }
633 /* Rest of function is for reading only */
634
635 if (s->z_err == Z_DATA_ERROR) return -1L;
636
637 /* compute absolute position */
638 if (whence == SEEK_CUR) {
639 offset += s->stream.total_out;
640 }
641 if (offset < 0) return -1L;
642
643 if (s->transparent) {
644 /* map to fseek */
645 s->stream.avail_in = 0;
646 s->stream.next_in = s->inbuf;
647 if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
648 return offset;
649 }
650
651 /* For a negative seek, rewind and use positive seek */
652 if ((uLong)offset >= s->stream.total_out) {
653 offset -= s->stream.total_out;
654 } else if (gzrewind(file) < 0) {
655 return -1L;
656 }
657 /* offset is now the number of bytes to skip. */
658
659 if (offset != 0 && s->outbuf == Z_NULL) {
660 s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
661 }
662 while (offset > 0) {
663 int size = Z_BUFSIZE;
664 if (offset < Z_BUFSIZE) size = (int)offset;
665
666 size = gzread(file, s->outbuf, (uInt)size);
667 if (size <= 0) return -1L;
668 offset -= size;
669 }
670 return s->stream.total_out;
671}
672
673/* ===========================================================================
674 Rewinds input file.
675*/
676int EXPORT gzrewind (file)
677 gzFile file;
678{
679 gz_stream *s = (gz_stream*)file;
680
681 if (s == NULL || s->mode != 'r') return -1;
682
683 s->z_err = Z_OK;
684 s->z_eof = 0;
685 s->stream.avail_in = 0;
686 s->stream.next_in = s->inbuf;
687
688 if (s->startpos == 0) { /* not a compressed file */
689 rewind(s->file);
690 return 0;
691 }
692
693 (void) inflateReset(&s->stream);
694 return fseek(s->file, s->startpos, SEEK_SET);
695}
696
697/* ===========================================================================
698 Returns the starting position for the next gzread or gzwrite on the
699 given compressed file. This position represents a number of bytes in the
700 uncompressed data stream.
701*/
702z_off_t EXPORT gztell (file)
703 gzFile file;
704{
705 return gzseek(file, 0L, SEEK_CUR);
706}
707
708/* ===========================================================================
709 Returns 1 when EOF has previously been detected reading the given
710 input stream, otherwise zero.
711*/
712int EXPORT gzeof (file)
713 gzFile file;
714{
715 gz_stream *s = (gz_stream*)file;
716
717 return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
718}
437 719
438/* =========================================================================== 720/* ===========================================================================
439 Outputs a long in LSB order to the given file 721 Outputs a long in LSB order to the given file
@@ -470,7 +752,7 @@ local uLong getLong (s)
470 Flushes all pending output if necessary, closes the compressed file 752 Flushes all pending output if necessary, closes the compressed file
471 and deallocates all the (de)compression state. 753 and deallocates all the (de)compression state.
472*/ 754*/
473int gzclose (file) 755int EXPORT gzclose (file)
474 gzFile file; 756 gzFile file;
475{ 757{
476 int err; 758 int err;
@@ -479,14 +761,17 @@ int gzclose (file)
479 if (s == NULL) return Z_STREAM_ERROR; 761 if (s == NULL) return Z_STREAM_ERROR;
480 762
481 if (s->mode == 'w') { 763 if (s->mode == 'w') {
482 err = gzflush (file, Z_FINISH); 764#ifdef NO_DEFLATE
483 if (err != Z_OK) return destroy(file); 765 return Z_STREAM_ERROR;
766#else
767 err = do_flush (file, Z_FINISH);
768 if (err != Z_OK) return destroy((gz_stream*)file);
484 769
485 putLong (s->file, s->crc); 770 putLong (s->file, s->crc);
486 putLong (s->file, s->stream.total_in); 771 putLong (s->file, s->stream.total_in);
487 772#endif
488 } 773 }
489 return destroy(file); 774 return destroy((gz_stream*)file);
490} 775}
491 776
492/* =========================================================================== 777/* ===========================================================================
@@ -496,7 +781,7 @@ int gzclose (file)
496 errnum is set to Z_ERRNO and the application may consult errno 781 errnum is set to Z_ERRNO and the application may consult errno
497 to get the exact error code. 782 to get the exact error code.
498*/ 783*/
499const char* gzerror (file, errnum) 784const char* EXPORT gzerror (file, errnum)
500 gzFile file; 785 gzFile file;
501 int *errnum; 786 int *errnum;
502{ 787{