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
5 * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
17 #include "gzio_symb.h"
21 # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
23 # define Z_BUFSIZE 16384
32 # define OS_CODE 0x03 /* assume Unix */
36 # define F_OPEN(name, mode) fopen((name), (mode))
39 #if MAX_MEM_LEVEL >= 8
40 # define DEF_MEM_LEVEL 8
42 # define DEF_MEM_LEVEL MAX_MEM_LEVEL
45 #define ALLOC(size) malloc(size)
46 #define TRYFREE(p) {if (p) free(p);}
47 #define zmemcpy memcpy
49 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
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 */
59 typedef struct gz_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 */
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));
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).
96 local gzFile gz_open (path, mode, fd)
102 int level = Z_DEFAULT_COMPRESSION; /* compression level */
103 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
104 char *p = (char*)mode;
106 char fmode[80]; /* copy of mode, without the compression level */
109 if (!path || !mode) return Z_NULL;
111 s = (gz_stream *)ALLOC(sizeof(gz_stream));
112 if (!s) return Z_NULL;
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;
126 s->crc = crc32(0L, Z_NULL, 0);
130 s->path = (char*)ALLOC(strlen(path)+1);
131 if (s->path == NULL) {
132 return destroy(s), (gzFile)Z_NULL;
134 strcpy(s->path, path); /* do this early for debugging */
138 if (*p == 'r') s->mode = 'r';
139 if (*p == 'w' || *p == 'a') s->mode = 'w';
140 if (*p >= '0' && *p <= '9') {
142 } else if (*p == 'f') {
143 strategy = Z_FILTERED;
144 } else if (*p == 'h') {
145 strategy = Z_HUFFMAN_ONLY;
146 } else if (*p == 'R') {
149 *m++ = *p; /* copy the mode */
151 } while (*p++ && m != fmode + sizeof(fmode));
152 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
154 if (s->mode == 'w') {
156 err = Z_STREAM_ERROR;
158 err = deflateInit2(&(s->stream), level,
159 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
160 /* windowBits is passed < 0 to suppress zlib header */
162 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
164 if (err != Z_OK || s->outbuf == Z_NULL) {
165 return destroy(s), (gzFile)Z_NULL;
168 s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
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.
177 if (err != Z_OK || s->inbuf == Z_NULL) {
178 return destroy(s), (gzFile)Z_NULL;
181 s->stream.avail_out = Z_BUFSIZE;
184 s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
186 if (s->file == NULL) {
187 return destroy(s), (gzFile)Z_NULL;
189 if (s->mode == 'w') {
190 /* Write a very simple .gz header:
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);
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
201 check_header(s); /* skip the .gz header */
202 s->start = ftell(s->file) - s->stream.avail_in;
208 /* ===========================================================================
209 Opens a gzip (.gz) file for reading or writing.
211 gzFile ZEXPORT gzopen (path, mode)
215 return gz_open (path, mode, -1);
218 /* ===========================================================================
219 * Update the compression level and strategy
221 int ZEXPORT gzsetparams (file, level, strategy)
226 gz_stream *s = (gz_stream*)file;
228 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
230 /* Make room to allow flushing */
231 if (s->stream.avail_out == 0) {
233 s->stream.next_out = s->outbuf;
234 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
237 s->stream.avail_out = Z_BUFSIZE;
240 return deflateParams (&(s->stream), level, strategy);
243 /* ===========================================================================
244 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
246 IN assertion: the stream s has been sucessfully opened for reading.
248 local int get_byte(s)
251 if (s->z_eof) return EOF;
252 if (s->stream.avail_in == 0) {
254 s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
255 if (s->stream.avail_in == 0) {
257 if (ferror(s->file)) s->z_err = Z_ERRNO;
260 s->stream.next_in = s->inbuf;
262 s->stream.avail_in--;
263 return *(s->stream.next_in)++;
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
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.
275 local void check_header(s)
278 int method; /* method byte */
279 int flags; /* flags byte */
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
286 len = s->stream.avail_in;
288 if (len) s->inbuf[0] = s->stream.next_in[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;
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]) {
306 s->stream.avail_in -= 2;
307 s->stream.next_in += 2;
309 /* Check the rest of the gzip header */
310 method = get_byte(s);
312 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
313 s->z_err = Z_DATA_ERROR;
317 /* Discard time, xflags and OS code: */
318 for (len = 0; len < 6; len++) (void)get_byte(s);
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) ;
326 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
327 while ((c = get_byte(s)) != 0 && c != EOF) ;
329 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
330 while ((c = get_byte(s)) != 0 && c != EOF) ;
332 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
333 for (len = 0; len < 2; len++) (void)get_byte(s);
335 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
338 /* ===========================================================================
339 * Cleanup then free the given gz_stream. Return a zlib error code.
340 Try freeing in the reverse order of allocations.
342 local int destroy (s)
347 if (!s) return Z_STREAM_ERROR;
351 if (s->stream.state != NULL) {
352 if (s->mode == 'w') {
354 err = Z_STREAM_ERROR;
356 err = deflateEnd(&(s->stream));
358 } else if (s->mode == 'r') {
359 err = inflateEnd(&(s->stream));
362 if (s->file != NULL && fclose(s->file)) {
364 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
368 if (s->z_err < 0) err = s->z_err;
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).
381 int ZEXPORT gzread (file, buf, len)
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) */
390 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
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 */
395 next_out = (Byte*)buf;
396 s->stream.next_out = (Bytef*)buf;
397 s->stream.avail_out = len;
399 if (s->stream.avail_out && s->back != EOF) {
400 *next_out++ = s->back;
401 s->stream.next_out++;
402 s->stream.avail_out--;
407 s->z_err = Z_STREAM_END;
412 while (s->stream.avail_out != 0) {
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;
419 zmemcpy(s->stream.next_out, s->stream.next_in, 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;
426 if (s->stream.avail_out > 0) {
427 s->stream.avail_out -=
428 (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
430 len -= s->stream.avail_out;
433 if (len == 0) s->z_eof = 1;
436 if (s->stream.avail_in == 0 && !s->z_eof) {
439 s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
440 if (s->stream.avail_in == 0) {
442 if (ferror(s->file)) {
447 s->stream.next_in = s->inbuf;
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;
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;
460 if (getLong(s) != s->crc) {
461 s->z_err = Z_DATA_ERROR;
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:
469 if (s->z_err == Z_OK) {
470 inflateReset(&(s->stream));
471 s->crc = crc32(0L, Z_NULL, 0);
475 if (s->z_err != Z_OK || s->z_eof) break;
477 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
479 if (len == s->stream.avail_out &&
480 (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
482 return (int)(len - s->stream.avail_out);
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).
491 int ZEXPORT gzwrite (file, buf, len)
496 gz_stream *s = (gz_stream*)file;
498 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
500 s->stream.next_in = (Bytef*)buf;
501 s->stream.avail_in = len;
503 while (s->stream.avail_in != 0) {
505 if (s->stream.avail_out == 0) {
507 s->stream.next_out = s->outbuf;
508 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
512 s->stream.avail_out = Z_BUFSIZE;
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;
521 s->crc = crc32(s->crc, (const Bytef *)buf, len);
523 return (int)(len - s->stream.avail_in);
527 /* ===========================================================================
528 Flushes all pending output into the compressed file. The parameter
529 flush is as in the deflate() function.
531 local int do_flush (file, flush)
537 gz_stream *s = (gz_stream*)file;
539 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
541 s->stream.avail_in = 0; /* should be zero already anyway */
544 len = Z_BUFSIZE - s->stream.avail_out;
547 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
551 s->stream.next_out = s->outbuf;
552 s->stream.avail_out = Z_BUFSIZE;
555 s->out += s->stream.avail_out;
556 s->z_err = deflate(&(s->stream), flush);
557 s->out -= s->stream.avail_out;
559 /* Ignore the second of two consecutive flushes: */
560 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
562 /* deflate has finished flushing only when it hasn't used up
563 * all the available space in the output buffer:
565 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
567 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
569 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
572 #endif /* NO_GZCOMPRESS */
575 /* ===========================================================================
576 Outputs a long in LSB order to the given file
578 local void putLong (file, x)
583 for (n = 0; n < 4; n++) {
584 fputc((int)(x & 0xff), file);
589 /* ===========================================================================
590 Reads a long in LSB order from the given gz_stream. Sets z_err in case
593 local uLong getLong (s)
596 uLong x = (uLong)get_byte(s);
599 x += ((uLong)get_byte(s))<<8;
600 x += ((uLong)get_byte(s))<<16;
602 if (c == EOF) s->z_err = Z_DATA_ERROR;
607 /* ===========================================================================
608 Flushes all pending output if necessary, closes the compressed file
609 and deallocates all the (de)compression state.
611 int ZEXPORT gzclose (file)
614 gz_stream *s = (gz_stream*)file;
616 if (s == NULL) return Z_STREAM_ERROR;
618 if (s->mode == 'w') {
620 return Z_STREAM_ERROR;
622 if (do_flush (file, Z_FINISH) != Z_OK)
623 return destroy((gz_stream*)file);
625 putLong (s->file, s->crc);
626 putLong (s->file, (uLong)(s->in & 0xffffffff));
629 return destroy((gz_stream*)file);