/src/zlib/gzio.c
C | 1043 lines | 732 code | 133 blank | 178 comment | 306 complexity | 2ac9b4059c2786a7947700d058d0e724 MD5 | raw file
Possible License(s): WTFPL, 0BSD, LGPL-2.1, CC-BY-3.0
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/* Warning: modified for use with Clonk groups. Now writes files */
11/* with new magic. Reads files with old or new magic. Does not */
12/* accept uncompressed (transparent) files. */
13
14#include <stdio.h>
15
16#include "zutil.h"
17
18#ifdef NO_DEFLATE /* for compatibility with old definition */
19# define NO_GZCOMPRESS
20#endif
21
22#ifndef NO_DUMMY_DECL
23struct internal_state {int dummy;}; /* for buggy compilers */
24#endif
25
26#ifndef Z_BUFSIZE
27# ifdef MAXSEG_64K
28# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
29# else
30# define Z_BUFSIZE 16384
31# endif
32#endif
33#ifndef Z_PRINTF_BUFSIZE
34# define Z_PRINTF_BUFSIZE 4096
35#endif
36
37#ifdef __MVS__
38# pragma map (fdopen , "\174\174FDOPEN")
39 FILE *fdopen(int, const char *);
40#endif
41
42#ifndef STDC
43extern voidp malloc OF((uInt size));
44extern void free OF((voidpf ptr));
45#endif
46
47#define ALLOC(size) malloc(size)
48#define TRYFREE(p) {if (p) free(p);}
49
50/* gzip magic header */
51static int gz_magic_old[2] = {0x1f, 0x8b};
52static int gz_magic_new[2] = {0x1e, 0x8c};
53
54/* gzip flag byte */
55#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
56#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
57#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
58#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
59#define COMMENT 0x10 /* bit 4 set: file comment present */
60#define RESERVED 0xE0 /* bits 5..7: reserved */
61
62typedef struct gz_stream {
63 z_stream stream;
64 int z_err; /* error code for last stream operation */
65 int z_eof; /* set if end of input file */
66 FILE *file; /* .gz file */
67 Byte *inbuf; /* input buffer */
68 Byte *outbuf; /* output buffer */
69 uLong crc; /* crc32 of uncompressed data */
70 char *msg; /* error message */
71 char *path; /* path name for debugging only */
72 int transparent; /* 1 if input file is not a .gz file */
73 char mode; /* 'w' or 'r' */
74 z_off_t start; /* start of compressed data in file (header skipped) */
75 z_off_t in; /* bytes into deflate or inflate */
76 z_off_t out; /* bytes out of deflate or inflate */
77 int back; /* one character push-back */
78 int last; /* true if push-back is last character */
79} gz_stream;
80
81
82local gzFile gz_open OF((const char *path, const char *mode, int fd));
83local int do_flush OF((gzFile file, int flush));
84local int get_byte OF((gz_stream *s));
85local void check_header OF((gz_stream *s));
86local int destroy OF((gz_stream *s));
87local void putLong OF((FILE *file, uLong x));
88local uLong getLong OF((gz_stream *s));
89
90/* ===========================================================================
91 Opens a gzip (.gz) file for reading or writing. The mode parameter
92 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
93 or path name (if fd == -1).
94 gz_open returns NULL if the file could not be opened or if there was
95 insufficient memory to allocate the (de)compression state; errno
96 can be checked to distinguish the two cases (if errno is zero, the
97 zlib error is Z_MEM_ERROR).
98*/
99local gzFile gz_open (path, mode, fd)
100 const char *path;
101 const char *mode;
102 int fd;
103{
104 int err;
105 int level = Z_DEFAULT_COMPRESSION; /* compression level */
106 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
107 char *p = (char*)mode;
108 gz_stream *s;
109 char fmode[80]; /* copy of mode, without the compression level */
110 char *m = fmode;
111
112 if (!path || !mode) return Z_NULL;
113
114 s = (gz_stream *)ALLOC(sizeof(gz_stream));
115 if (!s) return Z_NULL;
116
117 s->stream.zalloc = (alloc_func)0;
118 s->stream.zfree = (free_func)0;
119 s->stream.opaque = (voidpf)0;
120 s->stream.next_in = s->inbuf = Z_NULL;
121 s->stream.next_out = s->outbuf = Z_NULL;
122 s->stream.avail_in = s->stream.avail_out = 0;
123 s->file = NULL;
124 s->z_err = Z_OK;
125 s->z_eof = 0;
126 s->in = 0;
127 s->out = 0;
128 s->back = EOF;
129 s->crc = crc32(0L, Z_NULL, 0);
130 s->msg = NULL;
131 s->transparent = 0;
132
133 s->path = (char*)ALLOC(strlen(path)+1);
134 if (s->path == NULL) {
135 return destroy(s), (gzFile)Z_NULL;
136 }
137 strcpy(s->path, path); /* do this early for debugging */
138
139 s->mode = '\0';
140 do {
141 if (*p == 'r') s->mode = 'r';
142 if (*p == 'w' || *p == 'a') s->mode = 'w';
143 if (*p >= '0' && *p <= '9') {
144 level = *p - '0';
145 } else if (*p == 'f') {
146 strategy = Z_FILTERED;
147 } else if (*p == 'h') {
148 strategy = Z_HUFFMAN_ONLY;
149 } else if (*p == 'R') {
150 strategy = Z_RLE;
151 } else {
152 *m++ = *p; /* copy the mode */
153 }
154 } while (*p++ && m != fmode + sizeof(fmode));
155 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
156
157 if (s->mode == 'w') {
158#ifdef NO_GZCOMPRESS
159 err = Z_STREAM_ERROR;
160#else
161 err = deflateInit2(&(s->stream), level,
162 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
163 /* windowBits is passed < 0 to suppress zlib header */
164
165 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
166#endif
167 if (err != Z_OK || s->outbuf == Z_NULL) {
168 return destroy(s), (gzFile)Z_NULL;
169 }
170 } else {
171 s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
172
173 err = inflateInit2(&(s->stream), -MAX_WBITS);
174 /* windowBits is passed < 0 to tell that there is no zlib header.
175 * Note that in this case inflate *requires* an extra "dummy" byte
176 * after the compressed stream in order to complete decompression and
177 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
178 * present after the compressed stream.
179 */
180 if (err != Z_OK || s->inbuf == Z_NULL) {
181 return destroy(s), (gzFile)Z_NULL;
182 }
183 }
184 s->stream.avail_out = Z_BUFSIZE;
185
186 errno = 0;
187 s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
188
189 if (s->file == NULL) {
190 return destroy(s), (gzFile)Z_NULL;
191 }
192 if (s->mode == 'w') {
193 /* Write a very simple .gz header:
194 */
195 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic_new[0], gz_magic_new[1],
196 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, 0x0b /* OSCODE */);
197 s->start = 10L;
198 /* We use 10L instead of ftell(s->file) to because ftell causes an
199 * fflush on some systems. This version of the library doesn't use
200 * start anyway in write mode, so this initialization is not
201 * necessary.
202 */
203 } else {
204 check_header(s); /* skip the .gz header */
205 s->start = ftell(s->file) - s->stream.avail_in;
206 }
207
208 /* Reject uncompressed files */
209 if (s->transparent)
210 {
211 gzclose( (gzFile)s );
212 return (gzFile)Z_NULL;
213 }
214
215 return (gzFile)s;
216}
217
218/* ===========================================================================
219 Opens a gzip (.gz) file for reading or writing.
220*/
221gzFile ZEXPORT gzopen (path, mode)
222 const char *path;
223 const char *mode;
224{
225 return gz_open (path, mode, -1);
226}
227
228/* ===========================================================================
229 Associate a gzFile with the file descriptor fd. fd is not dup'ed here
230 to mimic the behavio(u)r of fdopen.
231*/
232gzFile ZEXPORT gzdopen (fd, mode)
233 int fd;
234 const char *mode;
235{
236 char name[46]; /* allow for up to 128-bit integers */
237
238 if (fd < 0) return (gzFile)Z_NULL;
239 sprintf(name, "<fd:%d>", fd); /* for debugging */
240
241 return gz_open (name, mode, fd);
242}
243
244/* ===========================================================================
245 * Update the compression level and strategy
246 */
247int ZEXPORT gzsetparams (file, level, strategy)
248 gzFile file;
249 int level;
250 int strategy;
251{
252 gz_stream *s = (gz_stream*)file;
253
254 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
255
256 /* Make room to allow flushing */
257 if (s->stream.avail_out == 0) {
258
259 s->stream.next_out = s->outbuf;
260 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
261 s->z_err = Z_ERRNO;
262 }
263 s->stream.avail_out = Z_BUFSIZE;
264 }
265
266 return deflateParams (&(s->stream), level, strategy);
267}
268
269/* ===========================================================================
270 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
271 for end of file.
272 IN assertion: the stream s has been sucessfully opened for reading.
273*/
274local int get_byte(s)
275 gz_stream *s;
276{
277 if (s->z_eof) return EOF;
278 if (s->stream.avail_in == 0) {
279 errno = 0;
280 s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
281 if (s->stream.avail_in == 0) {
282 s->z_eof = 1;
283 if (ferror(s->file)) s->z_err = Z_ERRNO;
284 return EOF;
285 }
286 s->stream.next_in = s->inbuf;
287 }
288 s->stream.avail_in--;
289 return *(s->stream.next_in)++;
290}
291
292/* ===========================================================================
293 Check the gzip header of a gz_stream opened for reading. Set the stream
294 mode to transparent if the gzip magic header is not present; set s->err
295 to Z_DATA_ERROR if the magic header is present but the rest of the header
296 is incorrect.
297 IN assertion: the stream s has already been created sucessfully;
298 s->stream.avail_in is zero for the first time, but may be non-zero
299 for concatenated .gz files.
300*/
301local void check_header(s)
302 gz_stream *s;
303{
304 int method; /* method byte */
305 int flags; /* flags byte */
306 uInt len;
307 int c;
308
309 /* Assure two bytes in the buffer so we can peek ahead -- handle case
310 where first byte of header is at the end of the buffer after the last
311 gzip segment */
312 len = s->stream.avail_in;
313 if (len < 2) {
314 if (len) s->inbuf[0] = s->stream.next_in[0];
315 errno = 0;
316 len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
317 if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
318 s->stream.avail_in += len;
319 s->stream.next_in = s->inbuf;
320 if (s->stream.avail_in < 2) {
321 s->transparent = s->stream.avail_in;
322 return;
323 }
324 }
325
326 /* Peek ahead to check the gzip magic header */
327 if ((s->stream.next_in[0] != gz_magic_old[0] ||
328 s->stream.next_in[1] != gz_magic_old[1]) &&
329 (s->stream.next_in[0] != gz_magic_new[0] ||
330 s->stream.next_in[1] != gz_magic_new[1])) {
331 s->transparent = 1;
332 return;
333 }
334 s->stream.avail_in -= 2;
335 s->stream.next_in += 2;
336
337 /* Check the rest of the gzip header */
338 method = get_byte(s);
339 flags = get_byte(s);
340 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
341 s->z_err = Z_DATA_ERROR;
342 return;
343 }
344
345 /* Discard time, xflags and OS code: */
346 for (len = 0; len < 6; len++) (void)get_byte(s);
347
348 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
349 len = (uInt)get_byte(s);
350 len += ((uInt)get_byte(s))<<8;
351 /* len is garbage if EOF but the loop below will quit anyway */
352 while (len-- != 0 && get_byte(s) != EOF) ;
353 }
354 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
355 while ((c = get_byte(s)) != 0 && c != EOF) ;
356 }
357 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
358 while ((c = get_byte(s)) != 0 && c != EOF) ;
359 }
360 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
361 for (len = 0; len < 2; len++) (void)get_byte(s);
362 }
363 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
364}
365
366 /* ===========================================================================
367 * Cleanup then free the given gz_stream. Return a zlib error code.
368 Try freeing in the reverse order of allocations.
369 */
370local int destroy (s)
371 gz_stream *s;
372{
373 int err = Z_OK;
374
375 if (!s) return Z_STREAM_ERROR;
376
377 TRYFREE(s->msg);
378
379 if (s->stream.state != NULL) {
380 if (s->mode == 'w') {
381#ifdef NO_GZCOMPRESS
382 err = Z_STREAM_ERROR;
383#else
384 err = deflateEnd(&(s->stream));
385#endif
386 } else if (s->mode == 'r') {
387 err = inflateEnd(&(s->stream));
388 }
389 }
390 if (s->file != NULL && fclose(s->file)) {
391#ifdef ESPIPE
392 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
393#endif
394 err = Z_ERRNO;
395 }
396 if (s->z_err < 0) err = s->z_err;
397
398 TRYFREE(s->inbuf);
399 TRYFREE(s->outbuf);
400 TRYFREE(s->path);
401 TRYFREE(s);
402 return err;
403}
404
405/* ===========================================================================
406 Reads the given number of uncompressed bytes from the compressed file.
407 gzread returns the number of bytes actually read (0 for end of file).
408*/
409int ZEXPORT gzread (file, buf, len)
410 gzFile file;
411 voidp buf;
412 unsigned len;
413{
414 gz_stream *s = (gz_stream*)file;
415 Bytef *start = (Bytef*)buf; /* starting point for crc computation */
416 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
417
418 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
419
420 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
421 if (s->z_err == Z_STREAM_END) return 0; /* EOF */
422
423 next_out = (Byte*)buf;
424 s->stream.next_out = (Bytef*)buf;
425 s->stream.avail_out = len;
426
427 if (s->stream.avail_out && s->back != EOF) {
428 *next_out++ = s->back;
429 s->stream.next_out++;
430 s->stream.avail_out--;
431 s->back = EOF;
432 s->out++;
433 start++;
434 if (s->last) {
435 s->z_err = Z_STREAM_END;
436 return 1;
437 }
438 }
439
440 while (s->stream.avail_out != 0) {
441
442 if (s->transparent) {
443 /* Copy first the lookahead bytes: */
444 uInt n = s->stream.avail_in;
445 if (n > s->stream.avail_out) n = s->stream.avail_out;
446 if (n > 0) {
447 zmemcpy(s->stream.next_out, s->stream.next_in, n);
448 next_out += n;
449 s->stream.next_out = next_out;
450 s->stream.next_in += n;
451 s->stream.avail_out -= n;
452 s->stream.avail_in -= n;
453 }
454 if (s->stream.avail_out > 0) {
455 s->stream.avail_out -=
456 (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
457 }
458 len -= s->stream.avail_out;
459 s->in += len;
460 s->out += len;
461 if (len == 0) s->z_eof = 1;
462 return (int)len;
463 }
464 if (s->stream.avail_in == 0 && !s->z_eof) {
465
466 errno = 0;
467 s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
468 if (s->stream.avail_in == 0) {
469 s->z_eof = 1;
470 if (ferror(s->file)) {
471 s->z_err = Z_ERRNO;
472 break;
473 }
474 }
475 s->stream.next_in = s->inbuf;
476 }
477 s->in += s->stream.avail_in;
478 s->out += s->stream.avail_out;
479 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
480 s->in -= s->stream.avail_in;
481 s->out -= s->stream.avail_out;
482
483 if (s->z_err == Z_STREAM_END) {
484 /* Check CRC and original size */
485 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
486 start = s->stream.next_out;
487
488 if (getLong(s) != s->crc) {
489 s->z_err = Z_DATA_ERROR;
490 } else {
491 (void)getLong(s);
492 /* The uncompressed length returned by above getlong() may be
493 * different from s->out in case of concatenated .gz files.
494 * Check for such files:
495 */
496 check_header(s);
497 if (s->z_err == Z_OK) {
498 inflateReset(&(s->stream));
499 s->crc = crc32(0L, Z_NULL, 0);
500 }
501 }
502 }
503 if (s->z_err != Z_OK || s->z_eof) break;
504 }
505 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
506
507 if (len == s->stream.avail_out &&
508 (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
509 return -1;
510 return (int)(len - s->stream.avail_out);
511}
512
513
514/* ===========================================================================
515 Reads one byte from the compressed file. gzgetc returns this byte
516 or -1 in case of end of file or error.
517*/
518int ZEXPORT gzgetc(file)
519 gzFile file;
520{
521 unsigned char c;
522
523 return gzread(file, &c, 1) == 1 ? c : -1;
524}
525
526
527/* ===========================================================================
528 Push one byte back onto the stream.
529*/
530int ZEXPORT gzungetc(c, file)
531 int c;
532 gzFile file;
533{
534 gz_stream *s = (gz_stream*)file;
535
536 if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
537 s->back = c;
538 s->out--;
539 s->last = (s->z_err == Z_STREAM_END);
540 if (s->last) s->z_err = Z_OK;
541 s->z_eof = 0;
542 return c;
543}
544
545
546/* ===========================================================================
547 Reads bytes from the compressed file until len-1 characters are
548 read, or a newline character is read and transferred to buf, or an
549 end-of-file condition is encountered. The string is then terminated
550 with a null character.
551 gzgets returns buf, or Z_NULL in case of error.
552
553 The current implementation is not optimized at all.
554*/
555char * ZEXPORT gzgets(file, buf, len)
556 gzFile file;
557 char *buf;
558 int len;
559{
560 char *b = buf;
561 if (buf == Z_NULL || len <= 0) return Z_NULL;
562
563 while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
564 *buf = '\0';
565 return b == buf && len > 0 ? Z_NULL : b;
566}
567
568
569#ifndef NO_GZCOMPRESS
570/* ===========================================================================
571 Writes the given number of uncompressed bytes into the compressed file.
572 gzwrite returns the number of bytes actually written (0 in case of error).
573*/
574int ZEXPORT gzwrite (file, buf, len)
575 gzFile file;
576 voidpc buf;
577 unsigned len;
578{
579 gz_stream *s = (gz_stream*)file;
580
581 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
582
583 s->stream.next_in = (Bytef*)buf;
584 s->stream.avail_in = len;
585
586 while (s->stream.avail_in != 0) {
587
588 if (s->stream.avail_out == 0) {
589
590 s->stream.next_out = s->outbuf;
591 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
592 s->z_err = Z_ERRNO;
593 break;
594 }
595 s->stream.avail_out = Z_BUFSIZE;
596 }
597 s->in += s->stream.avail_in;
598 s->out += s->stream.avail_out;
599 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
600 s->in -= s->stream.avail_in;
601 s->out -= s->stream.avail_out;
602 if (s->z_err != Z_OK) break;
603 }
604 s->crc = crc32(s->crc, (const Bytef *)buf, len);
605
606 return (int)(len - s->stream.avail_in);
607}
608
609
610/* ===========================================================================
611 Converts, formats, and writes the args to the compressed file under
612 control of the format string, as in fprintf. gzprintf returns the number of
613 uncompressed bytes actually written (0 in case of error).
614*/
615#ifdef STDC
616#include <stdarg.h>
617
618int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
619{
620 char buf[Z_PRINTF_BUFSIZE];
621 va_list va;
622 int len;
623
624 buf[sizeof(buf) - 1] = 0;
625 va_start(va, format);
626#ifdef NO_vsnprintf
627# ifdef HAS_vsprintf_void
628 (void)vsprintf(buf, format, va);
629 va_end(va);
630 for (len = 0; len < sizeof(buf); len++)
631 if (buf[len] == 0) break;
632# else
633 len = vsprintf(buf, format, va);
634 va_end(va);
635# endif
636#else
637# ifdef HAS_vsnprintf_void
638 (void)vsnprintf(buf, sizeof(buf), format, va);
639 va_end(va);
640 len = strlen(buf);
641# else
642 len = vsnprintf(buf, sizeof(buf), format, va);
643 va_end(va);
644# endif
645#endif
646 if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
647 return 0;
648 return gzwrite(file, buf, (unsigned)len);
649}
650#else /* not ANSI C */
651
652int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
653 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
654 gzFile file;
655 const char *format;
656 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
657 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
658{
659 char buf[Z_PRINTF_BUFSIZE];
660 int len;
661
662 buf[sizeof(buf) - 1] = 0;
663#ifdef NO_snprintf
664# ifdef HAS_sprintf_void
665 sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
666 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
667 for (len = 0; len < sizeof(buf); len++)
668 if (buf[len] == 0) break;
669# else
670 len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
671 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
672# endif
673#else
674# ifdef HAS_snprintf_void
675 snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
676 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
677 len = strlen(buf);
678# else
679 len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
680 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
681# endif
682#endif
683 if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
684 return 0;
685 return gzwrite(file, buf, len);
686}
687#endif
688
689/* ===========================================================================
690 Writes c, converted to an unsigned char, into the compressed file.
691 gzputc returns the value that was written, or -1 in case of error.
692*/
693int ZEXPORT gzputc(file, c)
694 gzFile file;
695 int c;
696{
697 unsigned char cc = (unsigned char) c; /* required for big endian systems */
698
699 return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
700}
701
702
703/* ===========================================================================
704 Writes the given null-terminated string to the compressed file, excluding
705 the terminating null character.
706 gzputs returns the number of characters written, or -1 in case of error.
707*/
708int ZEXPORT gzputs(file, s)
709 gzFile file;
710 const char *s;
711{
712 return gzwrite(file, (char*)s, (unsigned)strlen(s));
713}
714
715
716/* ===========================================================================
717 Flushes all pending output into the compressed file. The parameter
718 flush is as in the deflate() function.
719*/
720local int do_flush (file, flush)
721 gzFile file;
722 int flush;
723{
724 uInt len;
725 int done = 0;
726 gz_stream *s = (gz_stream*)file;
727
728 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
729
730 s->stream.avail_in = 0; /* should be zero already anyway */
731
732 for (;;) {
733 len = Z_BUFSIZE - s->stream.avail_out;
734
735 if (len != 0) {
736 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
737 s->z_err = Z_ERRNO;
738 return Z_ERRNO;
739 }
740 s->stream.next_out = s->outbuf;
741 s->stream.avail_out = Z_BUFSIZE;
742 }
743 if (done) break;
744 s->out += s->stream.avail_out;
745 s->z_err = deflate(&(s->stream), flush);
746 s->out -= s->stream.avail_out;
747
748 /* Ignore the second of two consecutive flushes: */
749 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
750
751 /* deflate has finished flushing only when it hasn't used up
752 * all the available space in the output buffer:
753 */
754 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
755
756 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
757 }
758 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
759}
760
761int ZEXPORT gzflush (file, flush)
762 gzFile file;
763 int flush;
764{
765 gz_stream *s = (gz_stream*)file;
766 int err = do_flush (file, flush);
767
768 if (err) return err;
769 fflush(s->file);
770 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
771}
772#endif /* NO_GZCOMPRESS */
773
774/* ===========================================================================
775 Sets the starting position for the next gzread or gzwrite on the given
776 compressed file. The offset represents a number of bytes in the
777 gzseek returns the resulting offset location as measured in bytes from
778 the beginning of the uncompressed stream, or -1 in case of error.
779 SEEK_END is not implemented, returns error.
780 In this version of the library, gzseek can be extremely slow.
781*/
782z_off_t ZEXPORT gzseek (file, offset, whence)
783 gzFile file;
784 z_off_t offset;
785 int whence;
786{
787 gz_stream *s = (gz_stream*)file;
788
789 if (s == NULL || whence == SEEK_END ||
790 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
791 return -1L;
792 }
793
794 if (s->mode == 'w') {
795#ifdef NO_GZCOMPRESS
796 return -1L;
797#else
798 if (whence == SEEK_SET) {
799 offset -= s->in;
800 }
801 if (offset < 0) return -1L;
802
803 /* At this point, offset is the number of zero bytes to write. */
804 if (s->inbuf == Z_NULL) {
805 s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
806 if (s->inbuf == Z_NULL) return -1L;
807 zmemzero(s->inbuf, Z_BUFSIZE);
808 }
809 while (offset > 0) {
810 uInt size = Z_BUFSIZE;
811 if (offset < Z_BUFSIZE) size = (uInt)offset;
812
813 size = gzwrite(file, s->inbuf, size);
814 if (size == 0) return -1L;
815
816 offset -= size;
817 }
818 return s->in;
819#endif
820 }
821 /* Rest of function is for reading only */
822
823 /* compute absolute position */
824 if (whence == SEEK_CUR) {
825 offset += s->out;
826 }
827 if (offset < 0) return -1L;
828
829 if (s->transparent) {
830 /* map to fseek */
831 s->back = EOF;
832 s->stream.avail_in = 0;
833 s->stream.next_in = s->inbuf;
834 if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
835
836 s->in = s->out = offset;
837 return offset;
838 }
839
840 /* For a negative seek, rewind and use positive seek */
841 if (offset >= s->out) {
842 offset -= s->out;
843 } else if (gzrewind(file) < 0) {
844 return -1L;
845 }
846 /* offset is now the number of bytes to skip. */
847
848 if (offset != 0 && s->outbuf == Z_NULL) {
849 s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
850 if (s->outbuf == Z_NULL) return -1L;
851 }
852 if (offset && s->back != EOF) {
853 s->back = EOF;
854 s->out++;
855 offset--;
856 if (s->last) s->z_err = Z_STREAM_END;
857 }
858 while (offset > 0) {
859 int size = Z_BUFSIZE;
860 if (offset < Z_BUFSIZE) size = (int)offset;
861
862 size = gzread(file, s->outbuf, (uInt)size);
863 if (size <= 0) return -1L;
864 offset -= size;
865 }
866 return s->out;
867}
868
869/* ===========================================================================
870 Rewinds input file.
871*/
872int ZEXPORT gzrewind (file)
873 gzFile file;
874{
875 gz_stream *s = (gz_stream*)file;
876
877 if (s == NULL || s->mode != 'r') return -1;
878
879 s->z_err = Z_OK;
880 s->z_eof = 0;
881 s->back = EOF;
882 s->stream.avail_in = 0;
883 s->stream.next_in = s->inbuf;
884 s->crc = crc32(0L, Z_NULL, 0);
885 if (!s->transparent) (void)inflateReset(&s->stream);
886 s->in = 0;
887 s->out = 0;
888 return fseek(s->file, s->start, SEEK_SET);
889}
890
891/* ===========================================================================
892 Returns the starting position for the next gzread or gzwrite on the
893 given compressed file. This position represents a number of bytes in the
894 uncompressed data stream.
895*/
896z_off_t ZEXPORT gztell (file)
897 gzFile file;
898{
899 return gzseek(file, 0L, SEEK_CUR);
900}
901
902/* ===========================================================================
903 Returns 1 when EOF has previously been detected reading the given
904 input stream, otherwise zero.
905*/
906int ZEXPORT gzeof (file)
907 gzFile file;
908{
909 gz_stream *s = (gz_stream*)file;
910
911 /* With concatenated compressed files that can have embedded
912 * crc trailers, z_eof is no longer the only/best indicator of EOF
913 * on a gz_stream. Handle end-of-stream error explicitly here.
914 */
915 if (s == NULL || s->mode != 'r') return 0;
916 if (s->z_eof) return 1;
917 return s->z_err == Z_STREAM_END;
918}
919
920/* ===========================================================================
921 Returns 1 if reading and doing so transparently, otherwise zero.
922*/
923int ZEXPORT gzdirect (file)
924 gzFile file;
925{
926 gz_stream *s = (gz_stream*)file;
927
928 if (s == NULL || s->mode != 'r') return 0;
929 return s->transparent;
930}
931
932/* ===========================================================================
933 Outputs a long in LSB order to the given file
934*/
935local void putLong (file, x)
936 FILE *file;
937 uLong x;
938{
939 int n;
940 for (n = 0; n < 4; n++) {
941 fputc((int)(x & 0xff), file);
942 x >>= 8;
943 }
944}
945
946/* ===========================================================================
947 Reads a long in LSB order from the given gz_stream. Sets z_err in case
948 of error.
949*/
950local uLong getLong (s)
951 gz_stream *s;
952{
953 uLong x = (uLong)get_byte(s);
954 int c;
955
956 x += ((uLong)get_byte(s))<<8;
957 x += ((uLong)get_byte(s))<<16;
958 c = get_byte(s);
959 if (c == EOF) s->z_err = Z_DATA_ERROR;
960 x += ((uLong)c)<<24;
961 return x;
962}
963
964/* ===========================================================================
965 Flushes all pending output if necessary, closes the compressed file
966 and deallocates all the (de)compression state.
967*/
968int ZEXPORT gzclose (file)
969 gzFile file;
970{
971 gz_stream *s = (gz_stream*)file;
972
973 if (s == NULL) return Z_STREAM_ERROR;
974
975 if (s->mode == 'w') {
976#ifdef NO_GZCOMPRESS
977 return Z_STREAM_ERROR;
978#else
979 if (do_flush (file, Z_FINISH) != Z_OK)
980 return destroy((gz_stream*)file);
981
982 putLong (s->file, s->crc);
983 putLong (s->file, (uLong)(s->in & 0xffffffff));
984#endif
985 }
986 return destroy((gz_stream*)file);
987}
988
989#ifdef STDC
990# define zstrerror(errnum) strerror(errnum)
991#else
992# define zstrerror(errnum) ""
993#endif
994
995/* ===========================================================================
996 Returns the error message for the last error which occurred on the
997 given compressed file. errnum is set to zlib error number. If an
998 error occurred in the file system and not in the compression library,
999 errnum is set to Z_ERRNO and the application may consult errno
1000 to get the exact error code.
1001*/
1002#if 0
1003const char * ZEXPORT gzerror (file, errnum)
1004 gzFile file;
1005 int *errnum;
1006{
1007 char *m;
1008 gz_stream *s = (gz_stream*)file;
1009
1010 if (s == NULL) {
1011 *errnum = Z_STREAM_ERROR;
1012 return (const char*)ERR_MSG(Z_STREAM_ERROR);
1013 }
1014 *errnum = s->z_err;
1015 if (*errnum == Z_OK) return (const char*)"";
1016
1017 m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
1018
1019 if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
1020
1021 TRYFREE(s->msg);
1022 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
1023 if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
1024 strcpy(s->msg, s->path);
1025 strcat(s->msg, ": ");
1026 strcat(s->msg, m);
1027 return (const char*)s->msg;
1028}
1029#endif
1030
1031/* ===========================================================================
1032 Clear the error and end-of-file flags, and do the same for the real file.
1033*/
1034void ZEXPORT gzclearerr (file)
1035 gzFile file;
1036{
1037 gz_stream *s = (gz_stream*)file;
1038
1039 if (s == NULL) return;
1040 if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
1041 s->z_eof = 0;
1042 clearerr(s->file);
1043}