Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into 4-0-abartlet
[tprouty/samba.git] / source4 / lib / zlib / gzio.c
1 /* gzio.c -- IO on .gz files
2  * Copyright (C) 1995-2005 Jean-loup Gailly.
3  * For conditions of distribution and use, see copyright notice in zlib.h
4  *
5  * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
6  */
7
8 /* @(#) $Id$ */
9
10 #include "zutil.h"
11
12 #ifdef NO_DEFLATE       /* for compatibility with old definition */
13 #  define NO_GZCOMPRESS
14 #endif
15
16 #ifndef NO_DUMMY_DECL
17 struct internal_state {int dummy;}; /* for buggy compilers */
18 #endif
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 #ifdef __MVS__
32 #  pragma map (fdopen , "\174\174FDOPEN")
33    FILE *fdopen(int, const char *);
34 #endif
35
36 #ifndef STDC
37 extern voidp  malloc OF((uInt size));
38 extern void   free   OF((voidpf ptr));
39 #endif
40
41 #define ALLOC(size) malloc(size)
42 #define TRYFREE(p) {if (p) free(p);}
43
44 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
45
46 /* gzip flag byte */
47 /*#define ASCII_FLAG   0x01 *//* bit 0 set: file probably ascii text */
48 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
49 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
50 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
51 #define COMMENT      0x10 /* bit 4 set: file comment present */
52 #define RESERVED     0xE0 /* bits 5..7: reserved */
53
54 typedef struct gz_stream {
55     z_stream stream;
56     int      z_err;   /* error code for last stream operation */
57     int      z_eof;   /* set if end of input file */
58     FILE     *file;   /* .gz file */
59     Byte     *inbuf;  /* input buffer */
60     Byte     *outbuf; /* output buffer */
61     uLong    crc;     /* crc32 of uncompressed data */
62     char     *msg;    /* error message */
63     char     *path;   /* path name for debugging only */
64     int      transparent; /* 1 if input file is not a .gz file */
65     char     mode;    /* 'w' or 'r' */
66     z_off_t  start;   /* start of compressed data in file (header skipped) */
67     z_off_t  in;      /* bytes into deflate or inflate */
68     z_off_t  out;     /* bytes out of deflate or inflate */
69     int      back;    /* one character push-back */
70     int      last;    /* true if push-back is last character */
71 } gz_stream;
72
73
74 local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
75 local int do_flush        OF((gzFile file, int flush));
76 local int    get_byte     OF((gz_stream *s));
77 local void   check_header OF((gz_stream *s));
78 local int    destroy      OF((gz_stream *s));
79 local void   putLong      OF((FILE *file, uLong x));
80 local uLong  getLong      OF((gz_stream *s));
81
82 /* ===========================================================================
83      Opens a gzip (.gz) file for reading or writing. The mode parameter
84    is as in fopen ("rb" or "wb"). The file is given either by file descriptor
85    or path name (if fd == -1).
86      gz_open returns NULL if the file could not be opened or if there was
87    insufficient memory to allocate the (de)compression state; errno
88    can be checked to distinguish the two cases (if errno is zero, the
89    zlib error is Z_MEM_ERROR).
90 */
91 local gzFile gz_open (path, mode, fd)
92     const char *path;
93     const char *mode;
94     int  fd;
95 {
96     int err;
97     int level = Z_DEFAULT_COMPRESSION; /* compression level */
98     int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
99     const char *p = mode;
100     gz_stream *s;
101     char fmode[80]; /* copy of mode, without the compression level */
102     char *m = fmode;
103
104     if (!path || !mode) return Z_NULL;
105
106     s = (gz_stream *)ALLOC(sizeof(gz_stream));
107     if (!s) return Z_NULL;
108
109     s->stream.zalloc = (alloc_func)0;
110     s->stream.zfree = (free_func)0;
111     s->stream.opaque = (voidpf)0;
112     s->stream.next_in = s->inbuf = Z_NULL;
113     s->stream.next_out = s->outbuf = Z_NULL;
114     s->stream.avail_in = s->stream.avail_out = 0;
115     s->file = NULL;
116     s->z_err = Z_OK;
117     s->z_eof = 0;
118     s->in = 0;
119     s->out = 0;
120     s->back = EOF;
121     s->crc = crc32(0L, Z_NULL, 0);
122     s->msg = NULL;
123     s->transparent = 0;
124
125     s->path = (char*)ALLOC(strlen(path)+1);
126     if (s->path == NULL) {
127         return destroy(s), (gzFile)Z_NULL;
128     }
129     strcpy(s->path, path); /* do this early for debugging */
130
131     s->mode = '\0';
132     do {
133         if (*p == 'r') s->mode = 'r';
134         if (*p == 'w' || *p == 'a') s->mode = 'w';
135         if (*p >= '0' && *p <= '9') {
136             level = *p - '0';
137         } else if (*p == 'f') {
138           strategy = Z_FILTERED;
139         } else if (*p == 'h') {
140           strategy = Z_HUFFMAN_ONLY;
141         } else if (*p == 'R') {
142           strategy = Z_RLE;
143         } else {
144             *m++ = *p; /* copy the mode */
145         }
146     } while (*p++ && m != fmode + sizeof(fmode));
147     if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
148
149     if (s->mode == 'w') {
150 #ifdef NO_GZCOMPRESS
151         err = Z_STREAM_ERROR;
152 #else
153         err = deflateInit2(&(s->stream), level,
154                            Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
155         /* windowBits is passed < 0 to suppress zlib header */
156
157         s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
158 #endif
159         if (err != Z_OK || s->outbuf == Z_NULL) {
160             return destroy(s), (gzFile)Z_NULL;
161         }
162     } else {
163         s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
164
165         err = inflateInit2(&(s->stream), -MAX_WBITS);
166         /* windowBits is passed < 0 to tell that there is no zlib header.
167          * Note that in this case inflate *requires* an extra "dummy" byte
168          * after the compressed stream in order to complete decompression and
169          * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
170          * present after the compressed stream.
171          */
172         if (err != Z_OK || s->inbuf == Z_NULL) {
173             return destroy(s), (gzFile)Z_NULL;
174         }
175     }
176     s->stream.avail_out = Z_BUFSIZE;
177
178     errno = 0;
179     s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
180
181     if (s->file == NULL) {
182         return destroy(s), (gzFile)Z_NULL;
183     }
184     if (s->mode == 'w') {
185         /* Write a very simple .gz header:
186          */
187         fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
188              Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
189         s->start = 10L;
190         /* We use 10L instead of ftell(s->file) to because ftell causes an
191          * fflush on some systems. This version of the library doesn't use
192          * start anyway in write mode, so this initialization is not
193          * necessary.
194          */
195     } else {
196         check_header(s); /* skip the .gz header */
197         s->start = ftell(s->file) - s->stream.avail_in;
198     }
199
200     return (gzFile)s;
201 }
202
203 /* ===========================================================================
204      Opens a gzip (.gz) file for reading or writing.
205 */
206 gzFile ZEXPORT gzopen (path, mode)
207     const char *path;
208     const char *mode;
209 {
210     return gz_open (path, mode, -1);
211 }
212
213 /* ===========================================================================
214      Associate a gzFile with the file descriptor fd. fd is not dup'ed here
215    to mimic the behavio(u)r of fdopen.
216 */
217 gzFile ZEXPORT gzdopen (fd, mode)
218     int fd;
219     const char *mode;
220 {
221     char name[46];      /* allow for up to 128-bit integers */
222
223     if (fd < 0) return (gzFile)Z_NULL;
224     sprintf(name, "<fd:%d>", fd); /* for debugging */
225
226     return gz_open (name, mode, fd);
227 }
228
229 /* ===========================================================================
230  * Update the compression level and strategy
231  */
232 int ZEXPORT gzsetparams (file, level, strategy)
233     gzFile file;
234     int level;
235     int strategy;
236 {
237     gz_stream *s = (gz_stream*)file;
238
239     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
240
241     /* Make room to allow flushing */
242     if (s->stream.avail_out == 0) {
243
244         s->stream.next_out = s->outbuf;
245         if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
246             s->z_err = Z_ERRNO;
247         }
248         s->stream.avail_out = Z_BUFSIZE;
249     }
250
251     return deflateParams (&(s->stream), level, strategy);
252 }
253
254 /* ===========================================================================
255      Read a byte from a gz_stream; update next_in and avail_in. Return EOF
256    for end of file.
257    IN assertion: the stream s has been sucessfully opened for reading.
258 */
259 local int get_byte(s)
260     gz_stream *s;
261 {
262     if (s->z_eof) return EOF;
263     if (s->stream.avail_in == 0) {
264         errno = 0;
265         s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
266         if (s->stream.avail_in == 0) {
267             s->z_eof = 1;
268             if (ferror(s->file)) s->z_err = Z_ERRNO;
269             return EOF;
270         }
271         s->stream.next_in = s->inbuf;
272     }
273     s->stream.avail_in--;
274     return *(s->stream.next_in)++;
275 }
276
277 /* ===========================================================================
278       Check the gzip header of a gz_stream opened for reading. Set the stream
279     mode to transparent if the gzip magic header is not present; set s->err
280     to Z_DATA_ERROR if the magic header is present but the rest of the header
281     is incorrect.
282     IN assertion: the stream s has already been created sucessfully;
283        s->stream.avail_in is zero for the first time, but may be non-zero
284        for concatenated .gz files.
285 */
286 local void check_header(s)
287     gz_stream *s;
288 {
289     int method; /* method byte */
290     int flags;  /* flags byte */
291     uInt len;
292     int c;
293
294     /* Assure two bytes in the buffer so we can peek ahead -- handle case
295        where first byte of header is at the end of the buffer after the last
296        gzip segment */
297     len = s->stream.avail_in;
298     if (len < 2) {
299         if (len) s->inbuf[0] = s->stream.next_in[0];
300         errno = 0;
301         len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
302         if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
303         s->stream.avail_in += len;
304         s->stream.next_in = s->inbuf;
305         if (s->stream.avail_in < 2) {
306             s->transparent = s->stream.avail_in;
307             return;
308         }
309     }
310
311     /* Peek ahead to check the gzip magic header */
312     if (s->stream.next_in[0] != gz_magic[0] ||
313         s->stream.next_in[1] != gz_magic[1]) {
314         s->transparent = 1;
315         return;
316     }
317     s->stream.avail_in -= 2;
318     s->stream.next_in += 2;
319
320     /* Check the rest of the gzip header */
321     method = get_byte(s);
322     flags = get_byte(s);
323     if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
324         s->z_err = Z_DATA_ERROR;
325         return;
326     }
327
328     /* Discard time, xflags and OS code: */
329     for (len = 0; len < 6; len++) (void)get_byte(s);
330
331     if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
332         len  =  (uInt)get_byte(s);
333         len += ((uInt)get_byte(s))<<8;
334         /* len is garbage if EOF but the loop below will quit anyway */
335         while (len-- != 0 && get_byte(s) != EOF) ;
336     }
337     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
338         while ((c = get_byte(s)) != 0 && c != EOF) ;
339     }
340     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
341         while ((c = get_byte(s)) != 0 && c != EOF) ;
342     }
343     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
344         for (len = 0; len < 2; len++) (void)get_byte(s);
345     }
346     s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
347 }
348
349  /* ===========================================================================
350  * Cleanup then free the given gz_stream. Return a zlib error code.
351    Try freeing in the reverse order of allocations.
352  */
353 local int destroy (s)
354     gz_stream *s;
355 {
356     int err = Z_OK;
357
358     if (!s) return Z_STREAM_ERROR;
359
360     TRYFREE(s->msg);
361
362     if (s->stream.state != NULL) {
363         if (s->mode == 'w') {
364 #ifdef NO_GZCOMPRESS
365             err = Z_STREAM_ERROR;
366 #else
367             err = deflateEnd(&(s->stream));
368 #endif
369         } else if (s->mode == 'r') {
370             err = inflateEnd(&(s->stream));
371         }
372     }
373     if (s->file != NULL && fclose(s->file)) {
374 #ifdef ESPIPE
375         if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
376 #endif
377             err = Z_ERRNO;
378     }
379     if (s->z_err < 0) err = s->z_err;
380
381     TRYFREE(s->inbuf);
382     TRYFREE(s->outbuf);
383     TRYFREE(s->path);
384     TRYFREE(s);
385     return err;
386 }
387
388 /* ===========================================================================
389      Reads the given number of uncompressed bytes from the compressed file.
390    gzread returns the number of bytes actually read (0 for end of file).
391 */
392 int ZEXPORT gzread (file, buf, len)
393     gzFile file;
394     voidp buf;
395     unsigned len;
396 {
397     gz_stream *s = (gz_stream*)file;
398     Bytef *start = (Bytef*)buf; /* starting point for crc computation */
399     Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
400
401     if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
402
403     if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
404     if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
405
406     next_out = (Byte*)buf;
407     s->stream.next_out = (Bytef*)buf;
408     s->stream.avail_out = len;
409
410     if (s->stream.avail_out && s->back != EOF) {
411         *next_out++ = s->back;
412         s->stream.next_out++;
413         s->stream.avail_out--;
414         s->back = EOF;
415         s->out++;
416         start++;
417         if (s->last) {
418             s->z_err = Z_STREAM_END;
419             return 1;
420         }
421     }
422
423     while (s->stream.avail_out != 0) {
424
425         if (s->transparent) {
426             /* Copy first the lookahead bytes: */
427             uInt n = s->stream.avail_in;
428             if (n > s->stream.avail_out) n = s->stream.avail_out;
429             if (n > 0) {
430                 zmemcpy(s->stream.next_out, s->stream.next_in, n);
431                 next_out += n;
432                 s->stream.next_out = next_out;
433                 s->stream.next_in   += n;
434                 s->stream.avail_out -= n;
435                 s->stream.avail_in  -= n;
436             }
437             if (s->stream.avail_out > 0) {
438                 s->stream.avail_out -=
439                     (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
440             }
441             len -= s->stream.avail_out;
442             s->in  += len;
443             s->out += len;
444             if (len == 0) s->z_eof = 1;
445             return (int)len;
446         }
447         if (s->stream.avail_in == 0 && !s->z_eof) {
448
449             errno = 0;
450             s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
451             if (s->stream.avail_in == 0) {
452                 s->z_eof = 1;
453                 if (ferror(s->file)) {
454                     s->z_err = Z_ERRNO;
455                     break;
456                 }
457             }
458             s->stream.next_in = s->inbuf;
459         }
460         s->in += s->stream.avail_in;
461         s->out += s->stream.avail_out;
462         s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
463         s->in -= s->stream.avail_in;
464         s->out -= s->stream.avail_out;
465
466         if (s->z_err == Z_STREAM_END) {
467             /* Check CRC and original size */
468             s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
469             start = s->stream.next_out;
470
471             if (getLong(s) != s->crc) {
472                 s->z_err = Z_DATA_ERROR;
473             } else {
474                 (void)getLong(s);
475                 /* The uncompressed length returned by above getlong() may be
476                  * different from s->out in case of concatenated .gz files.
477                  * Check for such files:
478                  */
479                 check_header(s);
480                 if (s->z_err == Z_OK) {
481                     inflateReset(&(s->stream));
482                     s->crc = crc32(0L, Z_NULL, 0);
483                 }
484             }
485         }
486         if (s->z_err != Z_OK || s->z_eof) break;
487     }
488     s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
489
490     if (len == s->stream.avail_out &&
491         (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
492         return -1;
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 = (const 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, (voidpc)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      Returns 1 if reading and doing so transparently, otherwise zero.
905 */
906 int ZEXPORT gzdirect (file)
907     gzFile file;
908 {
909     gz_stream *s = (gz_stream*)file;
910
911     if (s == NULL || s->mode != 'r') return 0;
912     return s->transparent;
913 }
914
915 /* ===========================================================================
916    Outputs a long in LSB order to the given file
917 */
918 local void putLong (file, x)
919     FILE *file;
920     uLong x;
921 {
922     int n;
923     for (n = 0; n < 4; n++) {
924         fputc((int)(x & 0xff), file);
925         x >>= 8;
926     }
927 }
928
929 /* ===========================================================================
930    Reads a long in LSB order from the given gz_stream. Sets z_err in case
931    of error.
932 */
933 local uLong getLong (s)
934     gz_stream *s;
935 {
936     uLong x = (uLong)get_byte(s);
937     int c;
938
939     x += ((uLong)get_byte(s))<<8;
940     x += ((uLong)get_byte(s))<<16;
941     c = get_byte(s);
942     if (c == EOF) s->z_err = Z_DATA_ERROR;
943     x += ((uLong)c)<<24;
944     return x;
945 }
946
947 /* ===========================================================================
948      Flushes all pending output if necessary, closes the compressed file
949    and deallocates all the (de)compression state.
950 */
951 int ZEXPORT gzclose (file)
952     gzFile file;
953 {
954     gz_stream *s = (gz_stream*)file;
955
956     if (s == NULL) return Z_STREAM_ERROR;
957
958     if (s->mode == 'w') {
959 #ifdef NO_GZCOMPRESS
960         return Z_STREAM_ERROR;
961 #else
962         if (do_flush (file, Z_FINISH) != Z_OK)
963             return destroy((gz_stream*)file);
964
965         putLong (s->file, s->crc);
966         putLong (s->file, (uLong)(s->in & 0xffffffff));
967 #endif
968     }
969     return destroy((gz_stream*)file);
970 }
971
972 #ifdef STDC
973 #  define zstrerror(errnum) strerror(errnum)
974 #else
975 #  define zstrerror(errnum) ""
976 #endif
977
978 /* ===========================================================================
979      Returns the error message for the last error which occurred on the
980    given compressed file. errnum is set to zlib error number. If an
981    error occurred in the file system and not in the compression library,
982    errnum is set to Z_ERRNO and the application may consult errno
983    to get the exact error code.
984 */
985 const char * ZEXPORT gzerror (file, errnum)
986     gzFile file;
987     int *errnum;
988 {
989     const char *m;
990     gz_stream *s = (gz_stream*)file;
991
992     if (s == NULL) {
993         *errnum = Z_STREAM_ERROR;
994         return (const char*)ERR_MSG(Z_STREAM_ERROR);
995     }
996     *errnum = s->z_err;
997     if (*errnum == Z_OK) return (const char*)"";
998
999     m = (*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
1000
1001     if (m == NULL || *m == '\0') m = ERR_MSG(s->z_err);
1002
1003     TRYFREE(s->msg);
1004     s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
1005     if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
1006     strcpy(s->msg, s->path);
1007     strcat(s->msg, ": ");
1008     strcat(s->msg, m);
1009     return (const char*)s->msg;
1010 }
1011
1012 /* ===========================================================================
1013      Clear the error and end-of-file flags, and do the same for the real file.
1014 */
1015 void ZEXPORT gzclearerr (file)
1016     gzFile file;
1017 {
1018     gz_stream *s = (gz_stream*)file;
1019
1020     if (s == NULL) return;
1021     if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
1022     s->z_eof = 0;
1023     clearerr(s->file);
1024 }