blob: 95bdb7d9122318fc36d3bb5b67737688f0b875fd [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Sun designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Sun in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 */
24
25/*
26 * This file is available under and governed by the GNU General Public
27 * License version 2 only, as published by the Free Software Foundation.
28 * However, the following notice accompanied the original version of this
29 * file and, per its terms, should not be removed:
30 *
31 * gzio.c -- IO on .gz files
32 * Copyright (C) 1995-1998 Jean-loup Gailly.
33 * For conditions of distribution and use, see copyright notice in zlib.h
34 *
35 * Compile this file with -DNO_DEFLATE to avoid the compression code.
36 */
37
38#include <stdio.h>
39
40#include "zutil.h"
41
42struct internal_state {int dummy;}; /* for buggy compilers */
43
44#ifndef Z_BUFSIZE
45# ifdef MAXSEG_64K
46# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
47# else
48# define Z_BUFSIZE 16384
49# endif
50#endif
51#ifndef Z_PRINTF_BUFSIZE
52# define Z_PRINTF_BUFSIZE 4096
53#endif
54
55#define ALLOC(size) malloc(size)
56#define TRYFREE(p) {if (p) free(p);}
57
58static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
59
60/* gzip flag byte */
61#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
62#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
63#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
64#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
65#define COMMENT 0x10 /* bit 4 set: file comment present */
66#define RESERVED 0xE0 /* bits 5..7: reserved */
67
68typedef struct gz_stream {
69 z_stream stream;
70 int z_err; /* error code for last stream operation */
71 int z_eof; /* set if end of input file */
72 FILE *file; /* .gz file */
73 Byte *inbuf; /* input buffer */
74 Byte *outbuf; /* output buffer */
75 uLong crc; /* crc32 of uncompressed data */
76 char *msg; /* error message */
77 char *path; /* path name for debugging only */
78 int transparent; /* 1 if input file is not a .gz file */
79 char mode; /* 'w' or 'r' */
80 long startpos; /* start of compressed data in file (header skipped) */
81} gz_stream;
82
83
84local gzFile gz_open OF((const char *path, const char *mode, int fd));
85local int do_flush OF((gzFile file, int flush));
86local int get_byte OF((gz_stream *s));
87local void check_header OF((gz_stream *s));
88local int destroy OF((gz_stream *s));
89local void putLong OF((FILE *file, uLong x));
90local uLong getLong OF((gz_stream *s));
91
92/* ===========================================================================
93 Opens a gzip (.gz) file for reading or writing. The mode parameter
94 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
95 or path name (if fd == -1).
96 gz_open return NULL if the file could not be opened or if there was
97 insufficient memory to allocate the (de)compression state; errno
98 can be checked to distinguish the two cases (if errno is zero, the
99 zlib error is Z_MEM_ERROR).
100*/
101local gzFile gz_open (path, mode, fd)
102 const char *path;
103 const char *mode;
104 int fd;
105{
106 int err;
107 int level = Z_DEFAULT_COMPRESSION; /* compression level */
108 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
109 char *p = (char*)mode;
110 gz_stream *s;
111 char fmode[80]; /* copy of mode, without the compression level */
112 char *m = fmode;
113
114 if (!path || !mode) return Z_NULL;
115
116 s = (gz_stream *)ALLOC(sizeof(gz_stream));
117 if (!s) return Z_NULL;
118
119 s->stream.zalloc = (alloc_func)0;
120 s->stream.zfree = (free_func)0;
121 s->stream.opaque = (voidpf)0;
122 s->stream.next_in = s->inbuf = Z_NULL;
123 s->stream.next_out = s->outbuf = Z_NULL;
124 s->stream.avail_in = s->stream.avail_out = 0;
125 s->file = NULL;
126 s->z_err = Z_OK;
127 s->z_eof = 0;
128 s->crc = crc32(0L, Z_NULL, 0);
129 s->msg = NULL;
130 s->transparent = 0;
131
132 s->path = (char*)ALLOC(strlen(path)+1);
133 if (s->path == NULL) {
134 return destroy(s), (gzFile)Z_NULL;
135 }
136 strcpy(s->path, path); /* do this early for debugging */
137
138 s->mode = '\0';
139 do {
140 if (*p == 'r') s->mode = 'r';
141 if (*p == 'w' || *p == 'a') s->mode = 'w';
142 if (*p >= '0' && *p <= '9') {
143 level = *p - '0';
144 } else if (*p == 'f') {
145 strategy = Z_FILTERED;
146 } else if (*p == 'h') {
147 strategy = Z_HUFFMAN_ONLY;
148 } else {
149 *m++ = *p; /* copy the mode */
150 }
151 } while (*p++ && m != fmode + sizeof(fmode));
152 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
153
154 if (s->mode == 'w') {
155#ifdef NO_DEFLATE
156 err = Z_STREAM_ERROR;
157#else
158 err = deflateInit2(&(s->stream), level,
159 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
160 /* windowBits is passed < 0 to suppress zlib header */
161
162 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
163#endif
164 if (err != Z_OK || s->outbuf == Z_NULL) {
165 return destroy(s), (gzFile)Z_NULL;
166 }
167 } else {
168 s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
169
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.
176 */
177 if (err != Z_OK || s->inbuf == Z_NULL) {
178 return destroy(s), (gzFile)Z_NULL;
179 }
180 }
181 s->stream.avail_out = Z_BUFSIZE;
182
183 errno = 0;
184 s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
185
186 if (s->file == NULL) {
187 return destroy(s), (gzFile)Z_NULL;
188 }
189 if (s->mode == 'w') {
190 /* Write a very simple .gz header:
191 */
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);
194 s->startpos = 10L;
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 * startpos anyway in write mode, so this initialization is not
198 * necessary.
199 */
200 } else {
201 check_header(s); /* skip the .gz header */
202 s->startpos = (ftell(s->file) - s->stream.avail_in);
203 }
204
205 return (gzFile)s;
206}
207
208/* ===========================================================================
209 Opens a gzip (.gz) file for reading or writing.
210*/
211gzFile ZEXPORT gzopen (path, mode)
212 const char *path;
213 const char *mode;
214{
215 return gz_open (path, mode, -1);
216}
217
218/* ===========================================================================
219 Associate a gzFile with the file descriptor fd. fd is not dup'ed here
220 to mimic the behavio(u)r of fdopen.
221*/
222gzFile ZEXPORT gzdopen (fd, mode)
223 int fd;
224 const char *mode;
225{
226 char name[20];
227
228 if (fd < 0) return (gzFile)Z_NULL;
229 sprintf(name, "<fd:%d>", fd); /* for debugging */
230
231 return gz_open (name, mode, fd);
232}
233
234/* ===========================================================================
235 * Update the compression level and strategy
236 */
237int ZEXPORT gzsetparams (file, level, strategy)
238 gzFile file;
239 int level;
240 int strategy;
241{
242 gz_stream *s = (gz_stream*)file;
243
244 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
245
246 /* Make room to allow flushing */
247 if (s->stream.avail_out == 0) {
248
249 s->stream.next_out = s->outbuf;
250 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
251 s->z_err = Z_ERRNO;
252 }
253 s->stream.avail_out = Z_BUFSIZE;
254 }
255
256 return deflateParams (&(s->stream), level, strategy);
257}
258
259/* ===========================================================================
260 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
261 for end of file.
262 IN assertion: the stream s has been sucessfully opened for reading.
263*/
264local int get_byte(s)
265 gz_stream *s;
266{
267 if (s->z_eof) return EOF;
268 if (s->stream.avail_in == 0) {
269 errno = 0;
270 s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
271 if (s->stream.avail_in == 0) {
272 s->z_eof = 1;
273 if (ferror(s->file)) s->z_err = Z_ERRNO;
274 return EOF;
275 }
276 s->stream.next_in = s->inbuf;
277 }
278 s->stream.avail_in--;
279 return *(s->stream.next_in)++;
280}
281
282/* ===========================================================================
283 Check the gzip header of a gz_stream opened for reading. Set the stream
284 mode to transparent if the gzip magic header is not present; set s->err
285 to Z_DATA_ERROR if the magic header is present but the rest of the header
286 is incorrect.
287 IN assertion: the stream s has already been created sucessfully;
288 s->stream.avail_in is zero for the first time, but may be non-zero
289 for concatenated .gz files.
290*/
291local void check_header(s)
292 gz_stream *s;
293{
294 int method; /* method byte */
295 int flags; /* flags byte */
296 uInt len;
297 int c;
298
299 /* Check the gzip magic header */
300 for (len = 0; len < 2; len++) {
301 c = get_byte(s);
302 if (c != gz_magic[len]) {
303 if (len != 0) s->stream.avail_in++, s->stream.next_in--;
304 if (c != EOF) {
305 s->stream.avail_in++, s->stream.next_in--;
306 s->transparent = 1;
307 }
308 s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
309 return;
310 }
311 }
312 method = get_byte(s);
313 flags = get_byte(s);
314 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
315 s->z_err = Z_DATA_ERROR;
316 return;
317 }
318
319 /* Discard time, xflags and OS code: */
320 for (len = 0; len < 6; len++) (void)get_byte(s);
321
322 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
323 len = (uInt)get_byte(s);
324 len += ((uInt)get_byte(s))<<8;
325 /* len is garbage if EOF but the loop below will quit anyway */
326 while (len-- != 0 && get_byte(s) != EOF) ;
327 }
328 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
329 while ((c = get_byte(s)) != 0 && c != EOF) ;
330 }
331 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
332 while ((c = get_byte(s)) != 0 && c != EOF) ;
333 }
334 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
335 for (len = 0; len < 2; len++) (void)get_byte(s);
336 }
337 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
338}
339
340 /* ===========================================================================
341 * Cleanup then free the given gz_stream. Return a zlib error code.
342 Try freeing in the reverse order of allocations.
343 */
344local int destroy (s)
345 gz_stream *s;
346{
347 int err = Z_OK;
348
349 if (!s) return Z_STREAM_ERROR;
350
351 TRYFREE(s->msg);
352
353 if (s->stream.state != NULL) {
354 if (s->mode == 'w') {
355#ifdef NO_DEFLATE
356 err = Z_STREAM_ERROR;
357#else
358 err = deflateEnd(&(s->stream));
359#endif
360 } else if (s->mode == 'r') {
361 err = inflateEnd(&(s->stream));
362 }
363 }
364 if (s->file != NULL && fclose(s->file)) {
365#ifdef ESPIPE
366 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
367#endif
368 err = Z_ERRNO;
369 }
370 if (s->z_err < 0) err = s->z_err;
371
372 TRYFREE(s->inbuf);
373 TRYFREE(s->outbuf);
374 TRYFREE(s->path);
375 TRYFREE(s);
376 return err;
377}
378
379/* ===========================================================================
380 Reads the given number of uncompressed bytes from the compressed file.
381 gzread returns the number of bytes actually read (0 for end of file).
382*/
383int ZEXPORT gzread (file, buf, len)
384 gzFile file;
385 voidp buf;
386 unsigned len;
387{
388 gz_stream *s = (gz_stream*)file;
389 Bytef *start = (Bytef*)buf; /* starting point for crc computation */
390 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
391
392 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
393
394 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
395 if (s->z_err == Z_STREAM_END) return 0; /* EOF */
396
397 next_out = (Byte*)buf;
398 s->stream.next_out = (Bytef*)buf;
399 s->stream.avail_out = len;
400
401 while (s->stream.avail_out != 0) {
402
403 if (s->transparent) {
404 /* Copy first the lookahead bytes: */
405 uInt n = s->stream.avail_in;
406 if (n > s->stream.avail_out) n = s->stream.avail_out;
407 if (n > 0) {
408 zmemcpy(s->stream.next_out, s->stream.next_in, n);
409 next_out += n;
410 s->stream.next_out = next_out;
411 s->stream.next_in += n;
412 s->stream.avail_out -= n;
413 s->stream.avail_in -= n;
414 }
415 if (s->stream.avail_out > 0) {
416 s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
417 s->file);
418 }
419 len -= s->stream.avail_out;
420 s->stream.total_in += (uLong)len;
421 s->stream.total_out += (uLong)len;
422 if (len == 0) s->z_eof = 1;
423 return (int)len;
424 }
425 if (s->stream.avail_in == 0 && !s->z_eof) {
426
427 errno = 0;
428 s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
429 if (s->stream.avail_in == 0) {
430 s->z_eof = 1;
431 if (ferror(s->file)) {
432 s->z_err = Z_ERRNO;
433 break;
434 }
435 }
436 s->stream.next_in = s->inbuf;
437 }
438 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
439
440 if (s->z_err == Z_STREAM_END) {
441 /* Check CRC and original size */
442 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
443 start = s->stream.next_out;
444
445 if (getLong(s) != s->crc) {
446 s->z_err = Z_DATA_ERROR;
447 } else {
448 (void)getLong(s);
449 /* The uncompressed length returned by above getlong() may
450 * be different from s->stream.total_out) in case of
451 * concatenated .gz files. Check for such files:
452 */
453 check_header(s);
454 if (s->z_err == Z_OK) {
455 uLong total_in = s->stream.total_in;
456 uLong total_out = s->stream.total_out;
457
458 inflateReset(&(s->stream));
459 s->stream.total_in = total_in;
460 s->stream.total_out = total_out;
461 s->crc = crc32(0L, Z_NULL, 0);
462 }
463 }
464 }
465 if (s->z_err != Z_OK || s->z_eof) break;
466 }
467 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
468
469 return (int)(len - s->stream.avail_out);
470}
471
472
473/* ===========================================================================
474 Reads one byte from the compressed file. gzgetc returns this byte
475 or -1 in case of end of file or error.
476*/
477int ZEXPORT gzgetc(file)
478 gzFile file;
479{
480 unsigned char c;
481
482 return gzread(file, &c, 1) == 1 ? c : -1;
483}
484
485
486/* ===========================================================================
487 Reads bytes from the compressed file until len-1 characters are
488 read, or a newline character is read and transferred to buf, or an
489 end-of-file condition is encountered. The string is then terminated
490 with a null character.
491 gzgets returns buf, or Z_NULL in case of error.
492
493 The current implementation is not optimized at all.
494*/
495char * ZEXPORT gzgets(file, buf, len)
496 gzFile file;
497 char *buf;
498 int len;
499{
500 char *b = buf;
501 if (buf == Z_NULL || len <= 0) return Z_NULL;
502
503 while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
504 *buf = '\0';
505 return b == buf && len > 0 ? Z_NULL : b;
506}
507
508
509#ifndef NO_DEFLATE
510/* ===========================================================================
511 Writes the given number of uncompressed bytes into the compressed file.
512 gzwrite returns the number of bytes actually written (0 in case of error).
513*/
514int ZEXPORT gzwrite (file, buf, len)
515 gzFile file;
516 const voidp buf;
517 unsigned len;
518{
519 gz_stream *s = (gz_stream*)file;
520
521 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
522
523 s->stream.next_in = (Bytef*)buf;
524 s->stream.avail_in = len;
525
526 while (s->stream.avail_in != 0) {
527
528 if (s->stream.avail_out == 0) {
529
530 s->stream.next_out = s->outbuf;
531 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
532 s->z_err = Z_ERRNO;
533 break;
534 }
535 s->stream.avail_out = Z_BUFSIZE;
536 }
537 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
538 if (s->z_err != Z_OK) break;
539 }
540 s->crc = crc32(s->crc, (const Bytef *)buf, len);
541
542 return (int)(len - s->stream.avail_in);
543}
544
545/* ===========================================================================
546 Converts, formats, and writes the args to the compressed file under
547 control of the format string, as in fprintf. gzprintf returns the number of
548 uncompressed bytes actually written (0 in case of error).
549*/
550#ifdef STDC
551#include <stdarg.h>
552
553int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
554{
555 char buf[Z_PRINTF_BUFSIZE];
556 va_list va;
557 int len;
558
559 va_start(va, format);
560#ifdef HAS_vsnprintf
561 (void)vsnprintf(buf, sizeof(buf), format, va);
562#else
563 (void)vsprintf(buf, format, va);
564#endif
565 va_end(va);
566 len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
567 if (len <= 0) return 0;
568
569 return gzwrite(file, buf, (unsigned)len);
570}
571#else /* not ANSI C */
572
573int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
574 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
575 gzFile file;
576 const char *format;
577 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
578 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
579{
580 char buf[Z_PRINTF_BUFSIZE];
581 int len;
582
583#ifdef HAS_snprintf
584 snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
585 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
586#else
587 sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
588 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
589#endif
590 len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
591 if (len <= 0) return 0;
592
593 return gzwrite(file, buf, len);
594}
595#endif
596
597/* ===========================================================================
598 Writes c, converted to an unsigned char, into the compressed file.
599 gzputc returns the value that was written, or -1 in case of error.
600*/
601int ZEXPORT gzputc(file, c)
602 gzFile file;
603 int c;
604{
605 unsigned char cc = (unsigned char) c; /* required for big endian systems */
606
607 return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
608}
609
610
611/* ===========================================================================
612 Writes the given null-terminated string to the compressed file, excluding
613 the terminating null character.
614 gzputs returns the number of characters written, or -1 in case of error.
615*/
616int ZEXPORT gzputs(file, s)
617 gzFile file;
618 const char *s;
619{
620 return gzwrite(file, (char*)s, (unsigned)strlen(s));
621}
622
623
624/* ===========================================================================
625 Flushes all pending output into the compressed file. The parameter
626 flush is as in the deflate() function.
627*/
628local int do_flush (file, flush)
629 gzFile file;
630 int flush;
631{
632 uInt len;
633 int done = 0;
634 gz_stream *s = (gz_stream*)file;
635
636 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
637
638 s->stream.avail_in = 0; /* should be zero already anyway */
639
640 for (;;) {
641 len = Z_BUFSIZE - s->stream.avail_out;
642
643 if (len != 0) {
644 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
645 s->z_err = Z_ERRNO;
646 return Z_ERRNO;
647 }
648 s->stream.next_out = s->outbuf;
649 s->stream.avail_out = Z_BUFSIZE;
650 }
651 if (done) break;
652 s->z_err = deflate(&(s->stream), flush);
653
654 /* Ignore the second of two consecutive flushes: */
655 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
656
657 /* deflate has finished flushing only when it hasn't used up
658 * all the available space in the output buffer:
659 */
660 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
661
662 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
663 }
664 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
665}
666
667int ZEXPORT gzflush (file, flush)
668 gzFile file;
669 int flush;
670{
671 gz_stream *s = (gz_stream*)file;
672 int err = do_flush (file, flush);
673
674 if (err) return err;
675 fflush(s->file);
676 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
677}
678#endif /* NO_DEFLATE */
679
680/* ===========================================================================
681 Sets the starting position for the next gzread or gzwrite on the given
682 compressed file. The offset represents a number of bytes in the
683 gzseek returns the resulting offset location as measured in bytes from
684 the beginning of the uncompressed stream, or -1 in case of error.
685 SEEK_END is not implemented, returns error.
686 In this version of the library, gzseek can be extremely slow.
687*/
688z_off_t ZEXPORT gzseek (file, offset, whence)
689 gzFile file;
690 z_off_t offset;
691 int whence;
692{
693 gz_stream *s = (gz_stream*)file;
694
695 if (s == NULL || whence == SEEK_END ||
696 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
697 return -1L;
698 }
699
700 if (s->mode == 'w') {
701#ifdef NO_DEFLATE
702 return -1L;
703#else
704 if (whence == SEEK_SET) {
705 offset -= s->stream.total_in;
706 }
707 if (offset < 0) return -1L;
708
709 /* At this point, offset is the number of zero bytes to write. */
710 if (s->inbuf == Z_NULL) {
711 s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
712 zmemzero(s->inbuf, Z_BUFSIZE);
713 }
714 while (offset > 0) {
715 uInt size = Z_BUFSIZE;
716 if (offset < Z_BUFSIZE) size = (uInt)offset;
717
718 size = gzwrite(file, s->inbuf, size);
719 if (size == 0) return -1L;
720
721 offset -= size;
722 }
723 return (z_off_t)s->stream.total_in;
724#endif
725 }
726 /* Rest of function is for reading only */
727
728 /* compute absolute position */
729 if (whence == SEEK_CUR) {
730 offset += s->stream.total_out;
731 }
732 if (offset < 0) return -1L;
733
734 if (s->transparent) {
735 /* map to fseek */
736 s->stream.avail_in = 0;
737 s->stream.next_in = s->inbuf;
738 if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
739
740 s->stream.total_in = s->stream.total_out = (uLong)offset;
741 return offset;
742 }
743
744 /* For a negative seek, rewind and use positive seek */
745 if ((uLong)offset >= s->stream.total_out) {
746 offset -= s->stream.total_out;
747 } else if (gzrewind(file) < 0) {
748 return -1L;
749 }
750 /* offset is now the number of bytes to skip. */
751
752 if (offset != 0 && s->outbuf == Z_NULL) {
753 s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
754 }
755 while (offset > 0) {
756 int size = Z_BUFSIZE;
757 if (offset < Z_BUFSIZE) size = (int)offset;
758
759 size = gzread(file, s->outbuf, (uInt)size);
760 if (size <= 0) return -1L;
761 offset -= size;
762 }
763 return (z_off_t)s->stream.total_out;
764}
765
766/* ===========================================================================
767 Rewinds input file.
768*/
769int ZEXPORT gzrewind (file)
770 gzFile file;
771{
772 gz_stream *s = (gz_stream*)file;
773
774 if (s == NULL || s->mode != 'r') return -1;
775
776 s->z_err = Z_OK;
777 s->z_eof = 0;
778 s->stream.avail_in = 0;
779 s->stream.next_in = s->inbuf;
780 s->crc = crc32(0L, Z_NULL, 0);
781
782 if (s->startpos == 0) { /* not a compressed file */
783 rewind(s->file);
784 return 0;
785 }
786
787 (void) inflateReset(&s->stream);
788 return fseek(s->file, s->startpos, SEEK_SET);
789}
790
791/* ===========================================================================
792 Returns the starting position for the next gzread or gzwrite on the
793 given compressed file. This position represents a number of bytes in the
794 uncompressed data stream.
795*/
796z_off_t ZEXPORT gztell (file)
797 gzFile file;
798{
799 return gzseek(file, 0L, SEEK_CUR);
800}
801
802/* ===========================================================================
803 Returns 1 when EOF has previously been detected reading the given
804 input stream, otherwise zero.
805*/
806int ZEXPORT gzeof (file)
807 gzFile file;
808{
809 gz_stream *s = (gz_stream*)file;
810
811 return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
812}
813
814/* ===========================================================================
815 Outputs a long in LSB order to the given file
816*/
817local void putLong (file, x)
818 FILE *file;
819 uLong x;
820{
821 int n;
822 for (n = 0; n < 4; n++) {
823 fputc((int)(x & 0xff), file);
824 x >>= 8;
825 }
826}
827
828/* ===========================================================================
829 Reads a long in LSB order from the given gz_stream. Sets z_err in case
830 of error.
831*/
832local uLong getLong (s)
833 gz_stream *s;
834{
835 uLong x = (uLong)get_byte(s);
836 int c;
837
838 x += ((uLong)get_byte(s))<<8;
839 x += ((uLong)get_byte(s))<<16;
840 c = get_byte(s);
841 if (c == EOF) s->z_err = Z_DATA_ERROR;
842 x += ((uLong)c)<<24;
843 return x;
844}
845
846/* ===========================================================================
847 Flushes all pending output if necessary, closes the compressed file
848 and deallocates all the (de)compression state.
849*/
850int ZEXPORT gzclose (file)
851 gzFile file;
852{
853 int err;
854 gz_stream *s = (gz_stream*)file;
855
856 if (s == NULL) return Z_STREAM_ERROR;
857
858 if (s->mode == 'w') {
859#ifdef NO_DEFLATE
860 return Z_STREAM_ERROR;
861#else
862 err = do_flush (file, Z_FINISH);
863 if (err != Z_OK) return destroy((gz_stream*)file);
864
865 putLong (s->file, s->crc);
866 putLong (s->file, s->stream.total_in);
867#endif
868 }
869 return destroy((gz_stream*)file);
870}
871
872/* ===========================================================================
873 Returns the error message for the last error which occured on the
874 given compressed file. errnum is set to zlib error number. If an
875 error occured in the file system and not in the compression library,
876 errnum is set to Z_ERRNO and the application may consult errno
877 to get the exact error code.
878*/
879const char* ZEXPORT gzerror (file, errnum)
880 gzFile file;
881 int *errnum;
882{
883 char *m;
884 gz_stream *s = (gz_stream*)file;
885
886 if (s == NULL) {
887 *errnum = Z_STREAM_ERROR;
888 return (const char*)ERR_MSG(Z_STREAM_ERROR);
889 }
890 *errnum = s->z_err;
891 if (*errnum == Z_OK) return (const char*)"";
892
893 m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
894
895 if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
896
897 TRYFREE(s->msg);
898 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
899 strcpy(s->msg, s->path);
900 strcat(s->msg, ": ");
901 strcat(s->msg, m);
902 return (const char*)s->msg;
903}