2009-08-23 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono/afaerber.git] / support / gzio.c
blobdf346207ffa5dc4f88ca00fb4461bbc4ea1ac535
1 /* gzio.c -- IO on .gz files
2 * Copyright (C) 1995-2006 Jean-loup Gailly.
3 * For conditions of distribution and use, see copyright notice in zlib.h
5 * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
6 */
8 /* @(#) $Id$ */
10 #ifdef _LARGEFILE64_SOURCE
11 # ifndef _LARGEFILE_SOURCE
12 # define _LARGEFILE_SOURCE
13 # endif
14 # ifdef _FILE_OFFSET_BITS
15 # undef _FILE_OFFSET_BITS
16 # endif
17 #endif
19 #include "zutil.h"
20 #include <stdio.h>
22 #ifdef NO_DEFLATE /* for compatibility with old definition */
23 # define NO_GZCOMPRESS
24 #endif
26 #ifndef NO_DUMMY_DECL
27 struct internal_state {int dummy;}; /* for buggy compilers */
28 #endif
30 #ifndef Z_BUFSIZE
31 # ifdef MAXSEG_64K
32 # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
33 # else
34 # define Z_BUFSIZE 16384
35 # endif
36 #endif
37 #ifndef Z_PRINTF_BUFSIZE
38 # define Z_PRINTF_BUFSIZE 4096
39 #endif
41 #ifdef __MVS__
42 # pragma map (fdopen , "\174\174FDOPEN")
43 FILE *fdopen(int, const char *);
44 #endif
46 #ifndef STDC
47 extern voidp malloc OF((uInt size));
48 extern void free OF((voidpf ptr));
49 #endif
51 #ifdef NO_FSEEKO
52 # define FSEEK fseek
53 # define FTELL ftell
54 #else
55 # define FSEEK fseeko
56 # define FTELL ftello
57 #endif
59 #define ALLOC(size) malloc(size)
60 #define TRYFREE(p) {if (p) free(p);}
62 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
64 /* gzip flag byte */
65 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
66 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
67 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
68 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
69 #define COMMENT 0x10 /* bit 4 set: file comment present */
70 #define RESERVED 0xE0 /* bits 5..7: reserved */
72 typedef struct gz_stream {
73 z_stream stream;
74 int z_err; /* error code for last stream operation */
75 int z_eof; /* set if end of input file */
76 FILE *file; /* .gz file */
77 Byte *inbuf; /* input buffer */
78 Byte *outbuf; /* output buffer */
79 uLong crc; /* crc32 of uncompressed data */
80 char *msg; /* error message */
81 char *path; /* path name for debugging only */
82 int transparent; /* 1 if input file is not a .gz file */
83 char mode; /* 'w' or 'r' */
84 #ifdef _LARGEFILE64_SOURCE
85 off64_t start; /* start of compressed data in file (header skipped) */
86 off64_t in; /* bytes into deflate or inflate */
87 off64_t out; /* bytes out of deflate or inflate */
88 #else
89 z_off_t start; /* start of compressed data in file (header skipped) */
90 z_off_t in; /* bytes into deflate or inflate */
91 z_off_t out; /* bytes out of deflate or inflate */
92 #endif
93 int back; /* one character push-back */
94 int last; /* true if push-back is last character */
95 } gz_stream;
98 local gzFile gz_open OF((const char *path, const char *mode, int fd,
99 int use64));
100 #ifdef _LARGEFILE64_SOURCE
101 local off64_t gz_seek OF((gzFile file, off64_t offset, int whence, int use64));
102 #else
103 local z_off_t gz_seek OF((gzFile file, z_off_t offset, int whence, int use64));
104 #endif
105 local int do_flush OF((gzFile file, int flush));
106 local int get_byte OF((gz_stream *s));
107 local void check_header OF((gz_stream *s));
108 local int destroy OF((gz_stream *s));
109 local void putLong OF((FILE *file, uLong x));
110 local uLong getLong OF((gz_stream *s));
112 /* ===========================================================================
113 Opens a gzip (.gz) file for reading or writing. The mode parameter
114 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
115 or path name (if fd == -1).
116 gz_open returns NULL if the file could not be opened or if there was
117 insufficient memory to allocate the (de)compression state; errno
118 can be checked to distinguish the two cases (if errno is zero, the
119 zlib error is Z_MEM_ERROR).
121 local gzFile gz_open (path, mode, fd, use64)
122 const char *path;
123 const char *mode;
124 int fd;
125 int use64;
127 int err;
128 int level = Z_DEFAULT_COMPRESSION; /* compression level */
129 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
130 char *p = (char*)mode;
131 gz_stream *s;
132 char fmode[80]; /* copy of mode, without the compression level */
133 char *m = fmode;
135 if (!path || !mode) return Z_NULL;
137 s = (gz_stream *)ALLOC(sizeof(gz_stream));
138 if (!s) return Z_NULL;
140 s->stream.zalloc = (alloc_func)0;
141 s->stream.zfree = (free_func)0;
142 s->stream.opaque = (voidpf)0;
143 s->stream.next_in = s->inbuf = Z_NULL;
144 s->stream.next_out = s->outbuf = Z_NULL;
145 s->stream.avail_in = s->stream.avail_out = 0;
146 s->file = NULL;
147 s->z_err = Z_OK;
148 s->z_eof = 0;
149 s->in = 0;
150 s->out = 0;
151 s->back = EOF;
152 s->crc = crc32(0L, Z_NULL, 0);
153 s->msg = NULL;
154 s->transparent = 0;
156 s->path = (char*)ALLOC(strlen(path)+1);
157 if (s->path == NULL) {
158 return destroy(s), (gzFile)Z_NULL;
160 strcpy(s->path, path); /* do this early for debugging */
162 s->mode = '\0';
163 do {
164 if (*p == 'r') s->mode = 'r';
165 if (*p == 'w' || *p == 'a') s->mode = 'w';
166 if (*p >= '0' && *p <= '9') {
167 level = *p - '0';
168 } else if (*p == 'f') {
169 strategy = Z_FILTERED;
170 } else if (*p == 'h') {
171 strategy = Z_HUFFMAN_ONLY;
172 } else if (*p == 'R') {
173 strategy = Z_RLE;
174 } else {
175 *m++ = *p; /* copy the mode */
177 } while (*p++ && m != fmode + sizeof(fmode));
178 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
180 if (s->mode == 'w') {
181 #ifdef NO_GZCOMPRESS
182 err = Z_STREAM_ERROR;
183 #else
184 err = deflateInit2(&(s->stream), level,
185 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
186 /* windowBits is passed < 0 to suppress zlib header */
188 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
189 #endif
190 if (err != Z_OK || s->outbuf == Z_NULL) {
191 return destroy(s), (gzFile)Z_NULL;
193 } else {
194 s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
196 err = inflateInit2(&(s->stream), -MAX_WBITS);
197 /* windowBits is passed < 0 to tell that there is no zlib header */
198 if (err != Z_OK || s->inbuf == Z_NULL) {
199 return destroy(s), (gzFile)Z_NULL;
202 s->stream.avail_out = Z_BUFSIZE;
204 errno = 0;
205 s->file = fd < 0 ? (use64 ? F_OPEN64(path, fmode) : F_OPEN(path, fmode)) :
206 (FILE*)fdopen(fd, fmode);
208 if (s->file == NULL) {
209 return destroy(s), (gzFile)Z_NULL;
211 if (s->mode == 'w') {
212 /* Write a very simple .gz header:
214 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
215 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, level == 9 ? 2 :
216 (strategy >= Z_HUFFMAN_ONLY ||
217 (level != Z_DEFAULT_COMPRESSION && level < 2) ?
218 4 : 0) /*xflags*/, OS_CODE);
219 s->start = 10L;
220 /* We use 10L instead of ftell(s->file) to because ftell causes an
221 * fflush on some systems. This version of the library doesn't use
222 * start anyway in write mode, so this initialization is not
223 * necessary.
225 } else {
226 check_header(s); /* skip the .gz header */
227 s->start = FTELL(s->file) - s->stream.avail_in;
230 return (gzFile)s;
233 /* ===========================================================================
234 Opens a gzip (.gz) file for reading or writing.
236 gzFile ZEXPORT gzopen (path, mode)
237 const char *path;
238 const char *mode;
240 return gz_open (path, mode, -1, 0);
243 /* ===========================================================================
244 Opens a gzip (.gz) file for reading or writing for 64-bit offsets
246 gzFile ZEXPORT gzopen64 (path, mode)
247 const char *path;
248 const char *mode;
250 return gz_open (path, mode, -1, 1);
253 /* ===========================================================================
254 Associate a gzFile with the file descriptor fd. fd is not dup'ed here
255 to mimic the behavio(u)r of fdopen.
257 gzFile ZEXPORT gzdopen (fd, mode)
258 int fd;
259 const char *mode;
261 char name[46]; /* allow for up to 128-bit integers */
263 if (fd < 0) return (gzFile)Z_NULL;
264 sprintf(name, "<fd:%d>", fd); /* for debugging */
266 return gz_open (name, mode, fd, 0);
269 /* ===========================================================================
270 * Update the compression level and strategy
272 int ZEXPORT gzsetparams (file, level, strategy)
273 gzFile file;
274 int level;
275 int strategy;
277 gz_stream *s = (gz_stream*)file;
279 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
281 /* Make room to allow flushing */
282 if (s->stream.avail_out == 0) {
284 s->stream.next_out = s->outbuf;
285 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
286 s->z_err = Z_ERRNO;
288 s->stream.avail_out = Z_BUFSIZE;
291 return deflateParams (&(s->stream), level, strategy);
294 /* ===========================================================================
295 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
296 for end of file.
297 IN assertion: the stream s has been successfully opened for reading.
299 local int get_byte(s)
300 gz_stream *s;
302 if (s->z_eof) return EOF;
303 if (s->stream.avail_in == 0) {
304 errno = 0;
305 s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
306 if (s->stream.avail_in == 0) {
307 s->z_eof = 1;
308 if (ferror(s->file)) s->z_err = Z_ERRNO;
309 return EOF;
311 s->stream.next_in = s->inbuf;
313 s->stream.avail_in--;
314 return *(s->stream.next_in)++;
317 /* ===========================================================================
318 Check the gzip header of a gz_stream opened for reading. Set the stream
319 mode to transparent if the gzip magic header is not present; set s->err
320 to Z_DATA_ERROR if the magic header is present but the rest of the header
321 is incorrect.
322 IN assertion: the stream s has already been created successfully;
323 s->stream.avail_in is zero for the first time, but may be non-zero
324 for concatenated .gz files.
326 local void check_header(s)
327 gz_stream *s;
329 int method; /* method byte */
330 int flags; /* flags byte */
331 uInt len;
332 int c;
334 /* Assure two bytes in the buffer so we can peek ahead -- handle case
335 where first byte of header is at the end of the buffer after the last
336 gzip segment */
337 len = s->stream.avail_in;
338 if (len < 2) {
339 if (len) s->inbuf[0] = s->stream.next_in[0];
340 errno = 0;
341 len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
342 if (len == 0) s->z_eof = 1;
343 if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
344 s->stream.avail_in += len;
345 s->stream.next_in = s->inbuf;
346 if (s->stream.avail_in < 2) {
347 s->transparent = s->stream.avail_in;
348 return;
352 /* Peek ahead to check the gzip magic header */
353 if (s->stream.next_in[0] != gz_magic[0] ||
354 s->stream.next_in[1] != gz_magic[1]) {
355 s->transparent = 1;
356 return;
358 s->stream.avail_in -= 2;
359 s->stream.next_in += 2;
361 /* Check the rest of the gzip header */
362 method = get_byte(s);
363 flags = get_byte(s);
364 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
365 s->z_err = Z_DATA_ERROR;
366 return;
369 /* Discard time, xflags and OS code: */
370 for (len = 0; len < 6; len++) (void)get_byte(s);
372 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
373 len = (uInt)get_byte(s);
374 len += ((uInt)get_byte(s))<<8;
375 /* len is garbage if EOF but the loop below will quit anyway */
376 while (len-- != 0 && get_byte(s) != EOF) ;
378 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
379 while ((c = get_byte(s)) != 0 && c != EOF) ;
381 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
382 while ((c = get_byte(s)) != 0 && c != EOF) ;
384 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
385 for (len = 0; len < 2; len++) (void)get_byte(s);
387 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
390 /* ===========================================================================
391 * Cleanup then free the given gz_stream. Return a zlib error code.
392 Try freeing in the reverse order of allocations.
394 local int destroy (s)
395 gz_stream *s;
397 int err = Z_OK;
399 if (!s) return Z_STREAM_ERROR;
401 TRYFREE(s->msg);
403 if (s->stream.state != NULL) {
404 if (s->mode == 'w') {
405 #ifdef NO_GZCOMPRESS
406 err = Z_STREAM_ERROR;
407 #else
408 err = deflateEnd(&(s->stream));
409 #endif
410 } else if (s->mode == 'r') {
411 err = inflateEnd(&(s->stream));
414 if (s->file != NULL && fclose(s->file)) {
415 #ifdef ESPIPE
416 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
417 #endif
418 err = Z_ERRNO;
420 if (s->z_err < 0) err = s->z_err;
422 TRYFREE(s->inbuf);
423 TRYFREE(s->outbuf);
424 TRYFREE(s->path);
425 TRYFREE(s);
426 return err;
429 /* ===========================================================================
430 Reads the given number of uncompressed bytes from the compressed file.
431 gzread returns the number of bytes actually read (0 for end of file).
433 int ZEXPORT gzread (file, buf, len)
434 gzFile file;
435 voidp buf;
436 unsigned len;
438 gz_stream *s = (gz_stream*)file;
439 Bytef *start = (Bytef*)buf; /* starting point for crc computation */
440 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
442 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
444 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
445 if (s->z_err == Z_STREAM_END) return 0; /* EOF */
447 next_out = (Byte*)buf;
448 s->stream.next_out = (Bytef*)buf;
449 s->stream.avail_out = len;
451 if (s->stream.avail_out && s->back != EOF) {
452 *next_out++ = s->back;
453 s->stream.next_out++;
454 s->stream.avail_out--;
455 s->back = EOF;
456 s->out++;
457 start++;
458 if (s->last) {
459 s->z_err = Z_STREAM_END;
460 return 1;
464 while (s->stream.avail_out != 0) {
466 if (s->transparent) {
467 /* Copy first the lookahead bytes: */
468 uInt n = s->stream.avail_in;
469 if (n > s->stream.avail_out) n = s->stream.avail_out;
470 if (n > 0) {
471 zmemcpy(s->stream.next_out, s->stream.next_in, n);
472 next_out += n;
473 s->stream.next_out = next_out;
474 s->stream.next_in += n;
475 s->stream.avail_out -= n;
476 s->stream.avail_in -= n;
478 if (s->stream.avail_out > 0 && !feof(s->file)) {
479 s->stream.avail_out -=
480 (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
482 len -= s->stream.avail_out;
483 s->in += len;
484 s->out += len;
485 if (len == 0) s->z_eof = 1;
486 return (int)len;
488 if (s->stream.avail_in == 0 && !s->z_eof) {
490 errno = 0;
491 s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
492 if (s->stream.avail_in == 0) {
493 s->z_eof = 1;
494 if (ferror(s->file)) {
495 s->z_err = Z_ERRNO;
496 break;
499 s->stream.next_in = s->inbuf;
501 s->in += s->stream.avail_in;
502 s->out += s->stream.avail_out;
503 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
504 s->in -= s->stream.avail_in;
505 s->out -= s->stream.avail_out;
507 if (s->z_err == Z_STREAM_END) {
508 /* Check CRC and original size */
509 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
510 start = s->stream.next_out;
512 if (getLong(s) != s->crc) {
513 s->z_err = Z_DATA_ERROR;
514 } else {
515 (void)getLong(s);
516 /* The uncompressed length returned by above getlong() may be
517 * different from s->out in case of concatenated .gz files.
518 * Check for such files:
520 check_header(s);
521 if (s->z_err == Z_OK) {
522 inflateReset(&(s->stream));
523 s->crc = crc32(0L, Z_NULL, 0);
527 if (s->z_err != Z_OK || s->z_eof) break;
529 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
531 if (len == s->stream.avail_out &&
532 (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
533 return -1;
534 return (int)(len - s->stream.avail_out);
538 /* ===========================================================================
539 Reads one byte from the compressed file. gzgetc returns this byte
540 or -1 in case of end of file or error.
542 int ZEXPORT gzgetc(file)
543 gzFile file;
545 unsigned char c;
547 return gzread(file, &c, 1) == 1 ? c : -1;
551 /* ===========================================================================
552 Push one byte back onto the stream.
554 int ZEXPORT gzungetc(c, file)
555 int c;
556 gzFile file;
558 gz_stream *s = (gz_stream*)file;
560 if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
561 s->back = c;
562 s->out--;
563 s->last = (s->z_err == Z_STREAM_END);
564 if (s->last) s->z_err = Z_OK;
565 s->z_eof = 0;
566 return c;
570 /* ===========================================================================
571 Reads bytes from the compressed file until len-1 characters are
572 read, or a newline character is read and transferred to buf, or an
573 end-of-file condition is encountered. The string is then terminated
574 with a null character.
575 gzgets returns buf, or Z_NULL in case of error.
577 The current implementation is not optimized at all.
579 char * ZEXPORT gzgets(file, buf, len)
580 gzFile file;
581 char *buf;
582 int len;
584 char *b = buf;
585 if (buf == Z_NULL || len <= 0) return Z_NULL;
587 while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
588 *buf = '\0';
589 return b == buf && len > 0 ? Z_NULL : b;
593 #ifndef NO_GZCOMPRESS
594 /* ===========================================================================
595 Writes the given number of uncompressed bytes into the compressed file.
596 gzwrite returns the number of bytes actually written (0 in case of error).
598 int ZEXPORT gzwrite (file, buf, len)
599 gzFile file;
600 voidpc buf;
601 unsigned len;
603 gz_stream *s = (gz_stream*)file;
605 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
607 s->stream.next_in = (Bytef*)buf;
608 s->stream.avail_in = len;
610 while (s->stream.avail_in != 0) {
612 if (s->stream.avail_out == 0) {
614 s->stream.next_out = s->outbuf;
615 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
616 s->z_err = Z_ERRNO;
617 break;
619 s->stream.avail_out = Z_BUFSIZE;
621 s->in += s->stream.avail_in;
622 s->out += s->stream.avail_out;
623 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
624 s->in -= s->stream.avail_in;
625 s->out -= s->stream.avail_out;
626 if (s->z_err != Z_OK) break;
628 s->crc = crc32(s->crc, (const Bytef *)buf, len);
630 return (int)(len - s->stream.avail_in);
634 /* ===========================================================================
635 Converts, formats, and writes the args to the compressed file under
636 control of the format string, as in fprintf. gzprintf returns the number of
637 uncompressed bytes actually written (0 in case of error).
639 #ifdef STDC
640 #include <stdarg.h>
642 int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
644 char buf[Z_PRINTF_BUFSIZE];
645 va_list va;
646 int len;
648 buf[sizeof(buf) - 1] = 0;
649 va_start(va, format);
650 #ifdef NO_vsnprintf
651 # ifdef HAS_vsprintf_void
652 (void)vsprintf(buf, format, va);
653 va_end(va);
654 for (len = 0; len < sizeof(buf); len++)
655 if (buf[len] == 0) break;
656 # else
657 len = vsprintf(buf, format, va);
658 va_end(va);
659 # endif
660 #else
661 # ifdef HAS_vsnprintf_void
662 (void)vsnprintf(buf, sizeof(buf), format, va);
663 va_end(va);
664 len = strlen(buf);
665 # else
666 len = vsnprintf(buf, sizeof(buf), format, va);
667 va_end(va);
668 # endif
669 #endif
670 if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
671 return 0;
672 return gzwrite(file, buf, (unsigned)len);
674 #else /* not ANSI C */
676 int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
677 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
678 gzFile file;
679 const char *format;
680 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
681 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
683 char buf[Z_PRINTF_BUFSIZE];
684 int len;
686 buf[sizeof(buf) - 1] = 0;
687 #ifdef NO_snprintf
688 # ifdef HAS_sprintf_void
689 sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
690 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
691 for (len = 0; len < sizeof(buf); len++)
692 if (buf[len] == 0) break;
693 # else
694 len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
695 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
696 # endif
697 #else
698 # ifdef HAS_snprintf_void
699 snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
700 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
701 len = strlen(buf);
702 # else
703 len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
704 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
705 # endif
706 #endif
707 if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
708 return 0;
709 return gzwrite(file, buf, len);
711 #endif
713 /* ===========================================================================
714 Writes c, converted to an unsigned char, into the compressed file.
715 gzputc returns the value that was written, or -1 in case of error.
717 int ZEXPORT gzputc(file, c)
718 gzFile file;
719 int c;
721 unsigned char cc = (unsigned char) c; /* required for big endian systems */
723 return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
727 /* ===========================================================================
728 Writes the given null-terminated string to the compressed file, excluding
729 the terminating null character.
730 gzputs returns the number of characters written, or -1 in case of error.
732 int ZEXPORT gzputs(file, s)
733 gzFile file;
734 const char *s;
736 return gzwrite(file, (char*)s, (unsigned)strlen(s));
740 /* ===========================================================================
741 Flushes all pending output into the compressed file. The parameter
742 flush is as in the deflate() function.
744 local int do_flush (file, flush)
745 gzFile file;
746 int flush;
748 uInt len;
749 int done = 0;
750 gz_stream *s = (gz_stream*)file;
752 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
754 s->stream.avail_in = 0; /* should be zero already anyway */
756 for (;;) {
757 len = Z_BUFSIZE - s->stream.avail_out;
759 if (len != 0) {
760 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
761 s->z_err = Z_ERRNO;
762 return Z_ERRNO;
764 s->stream.next_out = s->outbuf;
765 s->stream.avail_out = Z_BUFSIZE;
767 if (done) break;
768 s->out += s->stream.avail_out;
769 s->z_err = deflate(&(s->stream), flush);
770 s->out -= s->stream.avail_out;
772 /* Ignore the second of two consecutive flushes: */
773 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
775 /* deflate has finished flushing only when it hasn't used up
776 * all the available space in the output buffer:
778 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
780 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
782 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
785 int ZEXPORT gzflush (file, flush)
786 gzFile file;
787 int flush;
789 gz_stream *s = (gz_stream*)file;
790 int err = do_flush (file, flush);
792 if (err) return err;
793 fflush(s->file);
794 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
796 #endif /* NO_GZCOMPRESS */
798 /* ===========================================================================
799 Sets the starting position for the next gzread or gzwrite on the given
800 compressed file. The offset represents a number of bytes in the
801 gzseek returns the resulting offset location as measured in bytes from
802 the beginning of the uncompressed stream, or -1 in case of error.
803 SEEK_END is not implemented, returns error.
804 In this version of the library, gzseek can be extremely slow.
806 #ifdef _LARGEFILE64_SOURCE
807 local off64_t gz_seek (file, offset, whence, use64)
808 gzFile file;
809 off64_t offset;
810 #else
811 local z_off_t gz_seek (file, offset, whence, use64)
812 gzFile file;
813 z_off_t offset;
814 #endif
815 int whence;
816 int use64;
818 gz_stream *s = (gz_stream*)file;
820 if (s == NULL || whence == SEEK_END ||
821 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
822 return -1L;
825 if (s->mode == 'w') {
826 #ifdef NO_GZCOMPRESS
827 return -1L;
828 #else
829 if (whence == SEEK_SET) {
830 offset -= s->in;
832 if (offset < 0) return -1L;
834 /* At this point, offset is the number of zero bytes to write. */
835 if (s->inbuf == Z_NULL) {
836 s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
837 if (s->inbuf == Z_NULL) return -1L;
838 zmemzero(s->inbuf, Z_BUFSIZE);
840 while (offset > 0) {
841 uInt size = Z_BUFSIZE;
842 if (offset < Z_BUFSIZE) size = (uInt)offset;
844 size = gzwrite(file, s->inbuf, size);
845 if (size == 0) return -1L;
847 offset -= size;
849 return s->in;
850 #endif
852 /* Rest of function is for reading only */
854 /* compute absolute position */
855 if (whence == SEEK_CUR) {
856 offset += s->out;
858 if (offset < 0) return -1L;
860 if (s->transparent) {
861 /* map to fseek */
862 s->back = EOF;
863 s->stream.avail_in = 0;
864 s->stream.next_in = s->inbuf;
865 #ifdef _LARGEFILE64_SOURCE
866 if ((use64 ? fseeko64(s->file, offset, SEEK_SET) :
867 FSEEK(s->file, offset, SEEK_SET)) < 0)
868 return -1L;
869 #else
870 if (FSEEK(s->file, offset, SEEK_SET) < 0) return -1L;
871 #endif
873 s->in = s->out = offset;
874 return offset;
877 /* For a negative seek, rewind and use positive seek */
878 if (offset >= s->out) {
879 offset -= s->out;
880 } else if (gzrewind(file) < 0) {
881 return -1L;
883 /* offset is now the number of bytes to skip. */
885 if (offset != 0 && s->outbuf == Z_NULL) {
886 s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
887 if (s->outbuf == Z_NULL) return -1L;
889 if (offset && s->back != EOF) {
890 s->back = EOF;
891 s->out++;
892 offset--;
893 if (s->last) s->z_err = Z_STREAM_END;
895 while (offset > 0) {
896 int size = Z_BUFSIZE;
897 if (offset < Z_BUFSIZE) size = (int)offset;
899 size = gzread(file, s->outbuf, (uInt)size);
900 if (size <= 0) return -1L;
901 offset -= size;
903 return s->out;
906 /* ===========================================================================
907 Define external functions gzseek() and gzseek64() using local gz_seek().
909 z_off_t ZEXPORT gzseek (file, offset, whence)
910 gzFile file;
911 z_off_t offset;
912 int whence;
914 return (z_off_t)gz_seek(file, offset, whence, 0);
917 #ifdef _LARGEFILE64_SOURCE
918 off64_t ZEXPORT gzseek64 (file, offset, whence)
919 gzFile file;
920 off64_t offset;
921 int whence;
923 return gz_seek(file, offset, whence, 1);
925 #else
926 z_off_t ZEXPORT gzseek64 (file, offset, whence)
927 gzFile file;
928 z_off_t offset;
929 int whence;
931 return gz_seek(file, offset, whence, 0);
933 #endif
935 /* ===========================================================================
936 Rewinds input file.
938 int ZEXPORT gzrewind (file)
939 gzFile file;
941 gz_stream *s = (gz_stream*)file;
943 if (s == NULL || s->mode != 'r') return -1;
945 s->z_err = Z_OK;
946 s->z_eof = 0;
947 s->back = EOF;
948 s->stream.avail_in = 0;
949 s->stream.next_in = s->inbuf;
950 s->crc = crc32(0L, Z_NULL, 0);
951 if (!s->transparent) (void)inflateReset(&s->stream);
952 s->in = 0;
953 s->out = 0;
954 return FSEEK(s->file, s->start, SEEK_SET);
957 /* ===========================================================================
958 Returns the starting position for the next gzread or gzwrite on the
959 given compressed file. This position represents a number of bytes in the
960 uncompressed data stream.
962 z_off_t ZEXPORT gztell (file)
963 gzFile file;
965 return gzseek(file, 0L, SEEK_CUR);
968 /* ===========================================================================
969 64-bit version
971 #ifdef _LARGEFILE64_SOURCE
972 off64_t ZEXPORT gztell64 (file)
973 #else
974 z_off_t ZEXPORT gztell64 (file)
975 #endif
976 gzFile file;
978 return gzseek64(file, 0L, SEEK_CUR);
981 /* ===========================================================================
982 Returns 1 when EOF has previously been detected reading the given
983 input stream, otherwise zero.
985 int ZEXPORT gzeof (file)
986 gzFile file;
988 gz_stream *s = (gz_stream*)file;
990 /* With concatenated compressed files that can have embedded
991 * crc trailers, z_eof is no longer the only/best indicator of EOF
992 * on a gz_stream. Handle end-of-stream error explicitly here.
994 if (s == NULL || s->mode != 'r') return 0;
995 if (s->z_eof) return 1;
996 return s->z_err == Z_STREAM_END;
999 /* ===========================================================================
1000 Returns 1 if reading and doing so transparently, otherwise zero.
1002 int ZEXPORT gzdirect (file)
1003 gzFile file;
1005 gz_stream *s = (gz_stream*)file;
1007 if (s == NULL || s->mode != 'r') return 0;
1008 return s->transparent;
1011 /* ===========================================================================
1012 Outputs a long in LSB order to the given file
1014 local void putLong (file, x)
1015 FILE *file;
1016 uLong x;
1018 int n;
1019 for (n = 0; n < 4; n++) {
1020 fputc((int)(x & 0xff), file);
1021 x >>= 8;
1025 /* ===========================================================================
1026 Reads a long in LSB order from the given gz_stream. Sets z_err in case
1027 of error.
1029 local uLong getLong (s)
1030 gz_stream *s;
1032 uLong x = (uLong)get_byte(s);
1033 int c;
1035 x += ((uLong)get_byte(s))<<8;
1036 x += ((uLong)get_byte(s))<<16;
1037 c = get_byte(s);
1038 if (c == EOF) s->z_err = Z_DATA_ERROR;
1039 x += ((uLong)c)<<24;
1040 return x;
1043 /* ===========================================================================
1044 Flushes all pending output if necessary, closes the compressed file
1045 and deallocates all the (de)compression state.
1047 int ZEXPORT gzclose (file)
1048 gzFile file;
1050 gz_stream *s = (gz_stream*)file;
1052 if (s == NULL) return Z_STREAM_ERROR;
1054 if (s->mode == 'w') {
1055 #ifdef NO_GZCOMPRESS
1056 return Z_STREAM_ERROR;
1057 #else
1058 if (do_flush (file, Z_FINISH) != Z_OK)
1059 return destroy((gz_stream*)file);
1061 putLong (s->file, s->crc);
1062 putLong (s->file, (uLong)(s->in & 0xffffffff));
1063 #endif
1065 return destroy((gz_stream*)file);
1068 #if defined(STDC) && !defined(_WIN32_WCE)
1069 # define zstrerror(errnum) strerror(errnum)
1070 #else
1071 # define zstrerror(errnum) ""
1072 #endif
1074 /* ===========================================================================
1075 Returns the error message for the last error which occurred on the
1076 given compressed file. errnum is set to zlib error number. If an
1077 error occurred in the file system and not in the compression library,
1078 errnum is set to Z_ERRNO and the application may consult errno
1079 to get the exact error code.
1081 const char * ZEXPORT gzerror (file, errnum)
1082 gzFile file;
1083 int *errnum;
1085 char *m;
1086 gz_stream *s = (gz_stream*)file;
1088 if (s == NULL) {
1089 *errnum = Z_STREAM_ERROR;
1090 return (const char*)ERR_MSG(Z_STREAM_ERROR);
1092 *errnum = s->z_err;
1093 if (*errnum == Z_OK) return (const char*)"";
1095 m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
1097 if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
1099 TRYFREE(s->msg);
1100 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
1101 if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
1102 strcpy(s->msg, s->path);
1103 strcat(s->msg, ": ");
1104 strcat(s->msg, m);
1105 return (const char*)s->msg;
1108 /* ===========================================================================
1109 Clear the error and end-of-file flags, and do the same for the real file.
1111 void ZEXPORT gzclearerr (file)
1112 gzFile file;
1114 gz_stream *s = (gz_stream*)file;
1116 if (s == NULL) return;
1117 if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
1118 s->z_eof = 0;
1119 clearerr(s->file);