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