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