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