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