Back to index

lightning-sunbird  0.9+nobinonly
gzio.c
Go to the documentation of this file.
00001 /* gzio.c -- IO on .gz files
00002  * Copyright (C) 1995-2005 Jean-loup Gailly.
00003  * For conditions of distribution and use, see copyright notice in zlib.h
00004  *
00005  * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
00006  */
00007 
00008 /* @(#) $Id: gzio.c,v 1.5 2005/07/20 20:32:42 wtchang%redhat.com Exp $ */
00009 
00010 #include <stdio.h>
00011 
00012 #include "zutil.h"
00013 
00014 #ifdef NO_DEFLATE       /* for compatibility with old definition */
00015 #  define NO_GZCOMPRESS
00016 #endif
00017 
00018 #ifndef NO_DUMMY_DECL
00019 struct internal_state {int dummy;}; /* for buggy compilers */
00020 #endif
00021 
00022 #ifndef Z_BUFSIZE
00023 #  ifdef MAXSEG_64K
00024 #    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
00025 #  else
00026 #    define Z_BUFSIZE 16384
00027 #  endif
00028 #endif
00029 #ifndef Z_PRINTF_BUFSIZE
00030 #  define Z_PRINTF_BUFSIZE 4096
00031 #endif
00032 
00033 #ifdef __MVS__
00034 #  pragma map (fdopen , "\174\174FDOPEN")
00035    FILE *fdopen(int, const char *);
00036 #endif
00037 
00038 #ifndef STDC
00039 extern voidp  malloc OF((uInt size));
00040 extern void   free   OF((voidpf ptr));
00041 #endif
00042 
00043 #define ALLOC(size) malloc(size)
00044 #define TRYFREE(p) {if (p) free(p);}
00045 
00046 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
00047 
00048 /* gzip flag byte */
00049 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
00050 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
00051 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
00052 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
00053 #define COMMENT      0x10 /* bit 4 set: file comment present */
00054 #define RESERVED     0xE0 /* bits 5..7: reserved */
00055 
00056 typedef struct gz_stream {
00057     z_stream stream;
00058     int      z_err;   /* error code for last stream operation */
00059     int      z_eof;   /* set if end of input file */
00060     FILE     *file;   /* .gz file */
00061     Byte     *inbuf;  /* input buffer */
00062     Byte     *outbuf; /* output buffer */
00063     uLong    crc;     /* crc32 of uncompressed data */
00064     char     *msg;    /* error message */
00065     char     *path;   /* path name for debugging only */
00066     int      transparent; /* 1 if input file is not a .gz file */
00067     char     mode;    /* 'w' or 'r' */
00068     z_off_t  start;   /* start of compressed data in file (header skipped) */
00069     z_off_t  in;      /* bytes into deflate or inflate */
00070     z_off_t  out;     /* bytes out of deflate or inflate */
00071     int      back;    /* one character push-back */
00072     int      last;    /* true if push-back is last character */
00073 } gz_stream;
00074 
00075 
00076 local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
00077 local int do_flush        OF((gzFile file, int flush));
00078 local int    get_byte     OF((gz_stream *s));
00079 local void   check_header OF((gz_stream *s));
00080 local int    destroy      OF((gz_stream *s));
00081 local void   putLong      OF((FILE *file, uLong x));
00082 local uLong  getLong      OF((gz_stream *s));
00083 
00084 /* ===========================================================================
00085      Opens a gzip (.gz) file for reading or writing. The mode parameter
00086    is as in fopen ("rb" or "wb"). The file is given either by file descriptor
00087    or path name (if fd == -1).
00088      gz_open returns NULL if the file could not be opened or if there was
00089    insufficient memory to allocate the (de)compression state; errno
00090    can be checked to distinguish the two cases (if errno is zero, the
00091    zlib error is Z_MEM_ERROR).
00092 */
00093 local gzFile gz_open (path, mode, fd)
00094     const char *path;
00095     const char *mode;
00096     int  fd;
00097 {
00098     int err;
00099     int level = Z_DEFAULT_COMPRESSION; /* compression level */
00100     int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
00101     char *p = (char*)mode;
00102     gz_stream *s;
00103     char fmode[80]; /* copy of mode, without the compression level */
00104     char *m = fmode;
00105 
00106     if (!path || !mode) return Z_NULL;
00107 
00108     s = (gz_stream *)ALLOC(sizeof(gz_stream));
00109     if (!s) return Z_NULL;
00110 
00111     s->stream.zalloc = (alloc_func)0;
00112     s->stream.zfree = (free_func)0;
00113     s->stream.opaque = (voidpf)0;
00114     s->stream.next_in = s->inbuf = Z_NULL;
00115     s->stream.next_out = s->outbuf = Z_NULL;
00116     s->stream.avail_in = s->stream.avail_out = 0;
00117     s->file = NULL;
00118     s->z_err = Z_OK;
00119     s->z_eof = 0;
00120     s->in = 0;
00121     s->out = 0;
00122     s->back = EOF;
00123     s->crc = crc32(0L, Z_NULL, 0);
00124     s->msg = NULL;
00125     s->transparent = 0;
00126 
00127     s->path = (char*)ALLOC(strlen(path)+1);
00128     if (s->path == NULL) {
00129         return destroy(s), (gzFile)Z_NULL;
00130     }
00131     strcpy(s->path, path); /* do this early for debugging */
00132 
00133     s->mode = '\0';
00134     do {
00135         if (*p == 'r') s->mode = 'r';
00136         if (*p == 'w' || *p == 'a') s->mode = 'w';
00137         if (*p >= '0' && *p <= '9') {
00138             level = *p - '0';
00139         } else if (*p == 'f') {
00140           strategy = Z_FILTERED;
00141         } else if (*p == 'h') {
00142           strategy = Z_HUFFMAN_ONLY;
00143         } else if (*p == 'R') {
00144           strategy = Z_RLE;
00145         } else {
00146             *m++ = *p; /* copy the mode */
00147         }
00148     } while (*p++ && m != fmode + sizeof(fmode));
00149     if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
00150 
00151     if (s->mode == 'w') {
00152 #ifdef NO_GZCOMPRESS
00153         err = Z_STREAM_ERROR;
00154 #else
00155         err = deflateInit2(&(s->stream), level,
00156                            Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
00157         /* windowBits is passed < 0 to suppress zlib header */
00158 
00159         s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
00160 #endif
00161         if (err != Z_OK || s->outbuf == Z_NULL) {
00162             return destroy(s), (gzFile)Z_NULL;
00163         }
00164     } else {
00165         s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
00166 
00167         err = inflateInit2(&(s->stream), -MAX_WBITS);
00168         /* windowBits is passed < 0 to tell that there is no zlib header.
00169          * Note that in this case inflate *requires* an extra "dummy" byte
00170          * after the compressed stream in order to complete decompression and
00171          * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
00172          * present after the compressed stream.
00173          */
00174         if (err != Z_OK || s->inbuf == Z_NULL) {
00175             return destroy(s), (gzFile)Z_NULL;
00176         }
00177     }
00178     s->stream.avail_out = Z_BUFSIZE;
00179 
00180     errno = 0;
00181     s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
00182 
00183     if (s->file == NULL) {
00184         return destroy(s), (gzFile)Z_NULL;
00185     }
00186     if (s->mode == 'w') {
00187         /* Write a very simple .gz header:
00188          */
00189         fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
00190              Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
00191         s->start = 10L;
00192         /* We use 10L instead of ftell(s->file) to because ftell causes an
00193          * fflush on some systems. This version of the library doesn't use
00194          * start anyway in write mode, so this initialization is not
00195          * necessary.
00196          */
00197     } else {
00198         check_header(s); /* skip the .gz header */
00199         s->start = ftell(s->file) - s->stream.avail_in;
00200     }
00201 
00202     return (gzFile)s;
00203 }
00204 
00205 /* ===========================================================================
00206      Opens a gzip (.gz) file for reading or writing.
00207 */
00208 gzFile ZEXPORT gzopen (path, mode)
00209     const char *path;
00210     const char *mode;
00211 {
00212     return gz_open (path, mode, -1);
00213 }
00214 
00215 /* ===========================================================================
00216      Associate a gzFile with the file descriptor fd. fd is not dup'ed here
00217    to mimic the behavio(u)r of fdopen.
00218 */
00219 gzFile ZEXPORT gzdopen (fd, mode)
00220     int fd;
00221     const char *mode;
00222 {
00223     char name[46];      /* allow for up to 128-bit integers */
00224 
00225     if (fd < 0) return (gzFile)Z_NULL;
00226     sprintf(name, "<fd:%d>", fd); /* for debugging */
00227 
00228     return gz_open (name, mode, fd);
00229 }
00230 
00231 /* ===========================================================================
00232  * Update the compression level and strategy
00233  */
00234 int ZEXPORT gzsetparams (file, level, strategy)
00235     gzFile file;
00236     int level;
00237     int strategy;
00238 {
00239     gz_stream *s = (gz_stream*)file;
00240 
00241     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
00242 
00243     /* Make room to allow flushing */
00244     if (s->stream.avail_out == 0) {
00245 
00246         s->stream.next_out = s->outbuf;
00247         if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
00248             s->z_err = Z_ERRNO;
00249         }
00250         s->stream.avail_out = Z_BUFSIZE;
00251     }
00252 
00253     return deflateParams (&(s->stream), level, strategy);
00254 }
00255 
00256 /* ===========================================================================
00257      Read a byte from a gz_stream; update next_in and avail_in. Return EOF
00258    for end of file.
00259    IN assertion: the stream s has been sucessfully opened for reading.
00260 */
00261 local int get_byte(s)
00262     gz_stream *s;
00263 {
00264     if (s->z_eof) return EOF;
00265     if (s->stream.avail_in == 0) {
00266         errno = 0;
00267         s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
00268         if (s->stream.avail_in == 0) {
00269             s->z_eof = 1;
00270             if (ferror(s->file)) s->z_err = Z_ERRNO;
00271             return EOF;
00272         }
00273         s->stream.next_in = s->inbuf;
00274     }
00275     s->stream.avail_in--;
00276     return *(s->stream.next_in)++;
00277 }
00278 
00279 /* ===========================================================================
00280       Check the gzip header of a gz_stream opened for reading. Set the stream
00281     mode to transparent if the gzip magic header is not present; set s->err
00282     to Z_DATA_ERROR if the magic header is present but the rest of the header
00283     is incorrect.
00284     IN assertion: the stream s has already been created sucessfully;
00285        s->stream.avail_in is zero for the first time, but may be non-zero
00286        for concatenated .gz files.
00287 */
00288 local void check_header(s)
00289     gz_stream *s;
00290 {
00291     int method; /* method byte */
00292     int flags;  /* flags byte */
00293     uInt len;
00294     int c;
00295 
00296     /* Assure two bytes in the buffer so we can peek ahead -- handle case
00297        where first byte of header is at the end of the buffer after the last
00298        gzip segment */
00299     len = s->stream.avail_in;
00300     if (len < 2) {
00301         if (len) s->inbuf[0] = s->stream.next_in[0];
00302         errno = 0;
00303         len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
00304         if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
00305         s->stream.avail_in += len;
00306         s->stream.next_in = s->inbuf;
00307         if (s->stream.avail_in < 2) {
00308             s->transparent = s->stream.avail_in;
00309             return;
00310         }
00311     }
00312 
00313     /* Peek ahead to check the gzip magic header */
00314     if (s->stream.next_in[0] != gz_magic[0] ||
00315         s->stream.next_in[1] != gz_magic[1]) {
00316         s->transparent = 1;
00317         return;
00318     }
00319     s->stream.avail_in -= 2;
00320     s->stream.next_in += 2;
00321 
00322     /* Check the rest of the gzip header */
00323     method = get_byte(s);
00324     flags = get_byte(s);
00325     if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
00326         s->z_err = Z_DATA_ERROR;
00327         return;
00328     }
00329 
00330     /* Discard time, xflags and OS code: */
00331     for (len = 0; len < 6; len++) (void)get_byte(s);
00332 
00333     if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
00334         len  =  (uInt)get_byte(s);
00335         len += ((uInt)get_byte(s))<<8;
00336         /* len is garbage if EOF but the loop below will quit anyway */
00337         while (len-- != 0 && get_byte(s) != EOF) ;
00338     }
00339     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
00340         while ((c = get_byte(s)) != 0 && c != EOF) ;
00341     }
00342     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
00343         while ((c = get_byte(s)) != 0 && c != EOF) ;
00344     }
00345     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
00346         for (len = 0; len < 2; len++) (void)get_byte(s);
00347     }
00348     s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
00349 }
00350 
00351  /* ===========================================================================
00352  * Cleanup then free the given gz_stream. Return a zlib error code.
00353    Try freeing in the reverse order of allocations.
00354  */
00355 local int destroy (s)
00356     gz_stream *s;
00357 {
00358     int err = Z_OK;
00359 
00360     if (!s) return Z_STREAM_ERROR;
00361 
00362     TRYFREE(s->msg);
00363 
00364     if (s->stream.state != NULL) {
00365         if (s->mode == 'w') {
00366 #ifdef NO_GZCOMPRESS
00367             err = Z_STREAM_ERROR;
00368 #else
00369             err = deflateEnd(&(s->stream));
00370 #endif
00371         } else if (s->mode == 'r') {
00372             err = inflateEnd(&(s->stream));
00373         }
00374     }
00375     if (s->file != NULL && fclose(s->file)) {
00376 #ifdef ESPIPE
00377         if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
00378 #endif
00379             err = Z_ERRNO;
00380     }
00381     if (s->z_err < 0) err = s->z_err;
00382 
00383     TRYFREE(s->inbuf);
00384     TRYFREE(s->outbuf);
00385     TRYFREE(s->path);
00386     TRYFREE(s);
00387     return err;
00388 }
00389 
00390 /* ===========================================================================
00391      Reads the given number of uncompressed bytes from the compressed file.
00392    gzread returns the number of bytes actually read (0 for end of file).
00393 */
00394 int ZEXPORT gzread (file, buf, len)
00395     gzFile file;
00396     voidp buf;
00397     unsigned len;
00398 {
00399     gz_stream *s = (gz_stream*)file;
00400     Bytef *start = (Bytef*)buf; /* starting point for crc computation */
00401     Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
00402 
00403     if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
00404 
00405     if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
00406     if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
00407 
00408     next_out = (Byte*)buf;
00409     s->stream.next_out = (Bytef*)buf;
00410     s->stream.avail_out = len;
00411 
00412     if (s->stream.avail_out && s->back != EOF) {
00413         *next_out++ = s->back;
00414         s->stream.next_out++;
00415         s->stream.avail_out--;
00416         s->back = EOF;
00417         s->out++;
00418         start++;
00419         if (s->last) {
00420             s->z_err = Z_STREAM_END;
00421             return 1;
00422         }
00423     }
00424 
00425     while (s->stream.avail_out != 0) {
00426 
00427         if (s->transparent) {
00428             /* Copy first the lookahead bytes: */
00429             uInt n = s->stream.avail_in;
00430             if (n > s->stream.avail_out) n = s->stream.avail_out;
00431             if (n > 0) {
00432                 zmemcpy(s->stream.next_out, s->stream.next_in, n);
00433                 next_out += n;
00434                 s->stream.next_out = next_out;
00435                 s->stream.next_in   += n;
00436                 s->stream.avail_out -= n;
00437                 s->stream.avail_in  -= n;
00438             }
00439             if (s->stream.avail_out > 0) {
00440                 s->stream.avail_out -=
00441                     (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
00442             }
00443             len -= s->stream.avail_out;
00444             s->in  += len;
00445             s->out += len;
00446             if (len == 0) s->z_eof = 1;
00447             return (int)len;
00448         }
00449         if (s->stream.avail_in == 0 && !s->z_eof) {
00450 
00451             errno = 0;
00452             s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
00453             if (s->stream.avail_in == 0) {
00454                 s->z_eof = 1;
00455                 if (ferror(s->file)) {
00456                     s->z_err = Z_ERRNO;
00457                     break;
00458                 }
00459             }
00460             s->stream.next_in = s->inbuf;
00461         }
00462         s->in += s->stream.avail_in;
00463         s->out += s->stream.avail_out;
00464         s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
00465         s->in -= s->stream.avail_in;
00466         s->out -= s->stream.avail_out;
00467 
00468         if (s->z_err == Z_STREAM_END) {
00469             /* Check CRC and original size */
00470             s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
00471             start = s->stream.next_out;
00472 
00473             if (getLong(s) != s->crc) {
00474                 s->z_err = Z_DATA_ERROR;
00475             } else {
00476                 (void)getLong(s);
00477                 /* The uncompressed length returned by above getlong() may be
00478                  * different from s->out in case of concatenated .gz files.
00479                  * Check for such files:
00480                  */
00481                 check_header(s);
00482                 if (s->z_err == Z_OK) {
00483                     inflateReset(&(s->stream));
00484                     s->crc = crc32(0L, Z_NULL, 0);
00485                 }
00486             }
00487         }
00488         if (s->z_err != Z_OK || s->z_eof) break;
00489     }
00490     s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
00491 
00492     if (len == s->stream.avail_out &&
00493         (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
00494         return -1;
00495     return (int)(len - s->stream.avail_out);
00496 }
00497 
00498 
00499 /* ===========================================================================
00500       Reads one byte from the compressed file. gzgetc returns this byte
00501    or -1 in case of end of file or error.
00502 */
00503 int ZEXPORT gzgetc(file)
00504     gzFile file;
00505 {
00506     unsigned char c;
00507 
00508     return gzread(file, &c, 1) == 1 ? c : -1;
00509 }
00510 
00511 
00512 /* ===========================================================================
00513       Push one byte back onto the stream.
00514 */
00515 int ZEXPORT gzungetc(c, file)
00516     int c;
00517     gzFile file;
00518 {
00519     gz_stream *s = (gz_stream*)file;
00520 
00521     if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
00522     s->back = c;
00523     s->out--;
00524     s->last = (s->z_err == Z_STREAM_END);
00525     if (s->last) s->z_err = Z_OK;
00526     s->z_eof = 0;
00527     return c;
00528 }
00529 
00530 
00531 /* ===========================================================================
00532       Reads bytes from the compressed file until len-1 characters are
00533    read, or a newline character is read and transferred to buf, or an
00534    end-of-file condition is encountered.  The string is then terminated
00535    with a null character.
00536       gzgets returns buf, or Z_NULL in case of error.
00537 
00538       The current implementation is not optimized at all.
00539 */
00540 char * ZEXPORT gzgets(file, buf, len)
00541     gzFile file;
00542     char *buf;
00543     int len;
00544 {
00545     char *b = buf;
00546     if (buf == Z_NULL || len <= 0) return Z_NULL;
00547 
00548     while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
00549     *buf = '\0';
00550     return b == buf && len > 0 ? Z_NULL : b;
00551 }
00552 
00553 
00554 #ifndef NO_GZCOMPRESS
00555 /* ===========================================================================
00556      Writes the given number of uncompressed bytes into the compressed file.
00557    gzwrite returns the number of bytes actually written (0 in case of error).
00558 */
00559 int ZEXPORT gzwrite (file, buf, len)
00560     gzFile file;
00561     voidpc buf;
00562     unsigned len;
00563 {
00564     gz_stream *s = (gz_stream*)file;
00565 
00566     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
00567 
00568     s->stream.next_in = (Bytef*)buf;
00569     s->stream.avail_in = len;
00570 
00571     while (s->stream.avail_in != 0) {
00572 
00573         if (s->stream.avail_out == 0) {
00574 
00575             s->stream.next_out = s->outbuf;
00576             if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
00577                 s->z_err = Z_ERRNO;
00578                 break;
00579             }
00580             s->stream.avail_out = Z_BUFSIZE;
00581         }
00582         s->in += s->stream.avail_in;
00583         s->out += s->stream.avail_out;
00584         s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
00585         s->in -= s->stream.avail_in;
00586         s->out -= s->stream.avail_out;
00587         if (s->z_err != Z_OK) break;
00588     }
00589     s->crc = crc32(s->crc, (const Bytef *)buf, len);
00590 
00591     return (int)(len - s->stream.avail_in);
00592 }
00593 
00594 
00595 /* ===========================================================================
00596      Converts, formats, and writes the args to the compressed file under
00597    control of the format string, as in fprintf. gzprintf returns the number of
00598    uncompressed bytes actually written (0 in case of error).
00599 */
00600 #ifdef STDC
00601 #include <stdarg.h>
00602 
00603 int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
00604 {
00605     char buf[Z_PRINTF_BUFSIZE];
00606     va_list va;
00607     int len;
00608 
00609     buf[sizeof(buf) - 1] = 0;
00610     va_start(va, format);
00611 #ifdef NO_vsnprintf
00612 #  ifdef HAS_vsprintf_void
00613     (void)vsprintf(buf, format, va);
00614     va_end(va);
00615     for (len = 0; len < sizeof(buf); len++)
00616         if (buf[len] == 0) break;
00617 #  else
00618     len = vsprintf(buf, format, va);
00619     va_end(va);
00620 #  endif
00621 #else
00622 #  ifdef HAS_vsnprintf_void
00623     (void)vsnprintf(buf, sizeof(buf), format, va);
00624     va_end(va);
00625     len = strlen(buf);
00626 #  else
00627     len = vsnprintf(buf, sizeof(buf), format, va);
00628     va_end(va);
00629 #  endif
00630 #endif
00631     if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
00632         return 0;
00633     return gzwrite(file, buf, (unsigned)len);
00634 }
00635 #else /* not ANSI C */
00636 
00637 int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
00638                        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
00639     gzFile file;
00640     const char *format;
00641     int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
00642         a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
00643 {
00644     char buf[Z_PRINTF_BUFSIZE];
00645     int len;
00646 
00647     buf[sizeof(buf) - 1] = 0;
00648 #ifdef NO_snprintf
00649 #  ifdef HAS_sprintf_void
00650     sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
00651             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
00652     for (len = 0; len < sizeof(buf); len++)
00653         if (buf[len] == 0) break;
00654 #  else
00655     len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
00656                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
00657 #  endif
00658 #else
00659 #  ifdef HAS_snprintf_void
00660     snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
00661              a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
00662     len = strlen(buf);
00663 #  else
00664     len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
00665                  a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
00666 #  endif
00667 #endif
00668     if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
00669         return 0;
00670     return gzwrite(file, buf, len);
00671 }
00672 #endif
00673 
00674 /* ===========================================================================
00675       Writes c, converted to an unsigned char, into the compressed file.
00676    gzputc returns the value that was written, or -1 in case of error.
00677 */
00678 int ZEXPORT gzputc(file, c)
00679     gzFile file;
00680     int c;
00681 {
00682     unsigned char cc = (unsigned char) c; /* required for big endian systems */
00683 
00684     return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
00685 }
00686 
00687 
00688 /* ===========================================================================
00689       Writes the given null-terminated string to the compressed file, excluding
00690    the terminating null character.
00691       gzputs returns the number of characters written, or -1 in case of error.
00692 */
00693 int ZEXPORT gzputs(file, s)
00694     gzFile file;
00695     const char *s;
00696 {
00697     return gzwrite(file, (char*)s, (unsigned)strlen(s));
00698 }
00699 
00700 
00701 /* ===========================================================================
00702      Flushes all pending output into the compressed file. The parameter
00703    flush is as in the deflate() function.
00704 */
00705 local int do_flush (file, flush)
00706     gzFile file;
00707     int flush;
00708 {
00709     uInt len;
00710     int done = 0;
00711     gz_stream *s = (gz_stream*)file;
00712 
00713     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
00714 
00715     s->stream.avail_in = 0; /* should be zero already anyway */
00716 
00717     for (;;) {
00718         len = Z_BUFSIZE - s->stream.avail_out;
00719 
00720         if (len != 0) {
00721             if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
00722                 s->z_err = Z_ERRNO;
00723                 return Z_ERRNO;
00724             }
00725             s->stream.next_out = s->outbuf;
00726             s->stream.avail_out = Z_BUFSIZE;
00727         }
00728         if (done) break;
00729         s->out += s->stream.avail_out;
00730         s->z_err = deflate(&(s->stream), flush);
00731         s->out -= s->stream.avail_out;
00732 
00733         /* Ignore the second of two consecutive flushes: */
00734         if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
00735 
00736         /* deflate has finished flushing only when it hasn't used up
00737          * all the available space in the output buffer:
00738          */
00739         done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
00740 
00741         if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
00742     }
00743     return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
00744 }
00745 
00746 int ZEXPORT gzflush (file, flush)
00747      gzFile file;
00748      int flush;
00749 {
00750     gz_stream *s = (gz_stream*)file;
00751     int err = do_flush (file, flush);
00752 
00753     if (err) return err;
00754     fflush(s->file);
00755     return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
00756 }
00757 #endif /* NO_GZCOMPRESS */
00758 
00759 /* ===========================================================================
00760       Sets the starting position for the next gzread or gzwrite on the given
00761    compressed file. The offset represents a number of bytes in the
00762       gzseek returns the resulting offset location as measured in bytes from
00763    the beginning of the uncompressed stream, or -1 in case of error.
00764       SEEK_END is not implemented, returns error.
00765       In this version of the library, gzseek can be extremely slow.
00766 */
00767 z_off_t ZEXPORT gzseek (file, offset, whence)
00768     gzFile file;
00769     z_off_t offset;
00770     int whence;
00771 {
00772     gz_stream *s = (gz_stream*)file;
00773 
00774     if (s == NULL || whence == SEEK_END ||
00775         s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
00776         return -1L;
00777     }
00778 
00779     if (s->mode == 'w') {
00780 #ifdef NO_GZCOMPRESS
00781         return -1L;
00782 #else
00783         if (whence == SEEK_SET) {
00784             offset -= s->in;
00785         }
00786         if (offset < 0) return -1L;
00787 
00788         /* At this point, offset is the number of zero bytes to write. */
00789         if (s->inbuf == Z_NULL) {
00790             s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
00791             if (s->inbuf == Z_NULL) return -1L;
00792             zmemzero(s->inbuf, Z_BUFSIZE);
00793         }
00794         while (offset > 0)  {
00795             uInt size = Z_BUFSIZE;
00796             if (offset < Z_BUFSIZE) size = (uInt)offset;
00797 
00798             size = gzwrite(file, s->inbuf, size);
00799             if (size == 0) return -1L;
00800 
00801             offset -= size;
00802         }
00803         return s->in;
00804 #endif
00805     }
00806     /* Rest of function is for reading only */
00807 
00808     /* compute absolute position */
00809     if (whence == SEEK_CUR) {
00810         offset += s->out;
00811     }
00812     if (offset < 0) return -1L;
00813 
00814     if (s->transparent) {
00815         /* map to fseek */
00816         s->back = EOF;
00817         s->stream.avail_in = 0;
00818         s->stream.next_in = s->inbuf;
00819         if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
00820 
00821         s->in = s->out = offset;
00822         return offset;
00823     }
00824 
00825     /* For a negative seek, rewind and use positive seek */
00826     if (offset >= s->out) {
00827         offset -= s->out;
00828     } else if (gzrewind(file) < 0) {
00829         return -1L;
00830     }
00831     /* offset is now the number of bytes to skip. */
00832 
00833     if (offset != 0 && s->outbuf == Z_NULL) {
00834         s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
00835         if (s->outbuf == Z_NULL) return -1L;
00836     }
00837     if (offset && s->back != EOF) {
00838         s->back = EOF;
00839         s->out++;
00840         offset--;
00841         if (s->last) s->z_err = Z_STREAM_END;
00842     }
00843     while (offset > 0)  {
00844         int size = Z_BUFSIZE;
00845         if (offset < Z_BUFSIZE) size = (int)offset;
00846 
00847         size = gzread(file, s->outbuf, (uInt)size);
00848         if (size <= 0) return -1L;
00849         offset -= size;
00850     }
00851     return s->out;
00852 }
00853 
00854 /* ===========================================================================
00855      Rewinds input file.
00856 */
00857 int ZEXPORT gzrewind (file)
00858     gzFile file;
00859 {
00860     gz_stream *s = (gz_stream*)file;
00861 
00862     if (s == NULL || s->mode != 'r') return -1;
00863 
00864     s->z_err = Z_OK;
00865     s->z_eof = 0;
00866     s->back = EOF;
00867     s->stream.avail_in = 0;
00868     s->stream.next_in = s->inbuf;
00869     s->crc = crc32(0L, Z_NULL, 0);
00870     if (!s->transparent) (void)inflateReset(&s->stream);
00871     s->in = 0;
00872     s->out = 0;
00873     return fseek(s->file, s->start, SEEK_SET);
00874 }
00875 
00876 /* ===========================================================================
00877      Returns the starting position for the next gzread or gzwrite on the
00878    given compressed file. This position represents a number of bytes in the
00879    uncompressed data stream.
00880 */
00881 z_off_t ZEXPORT gztell (file)
00882     gzFile file;
00883 {
00884     return gzseek(file, 0L, SEEK_CUR);
00885 }
00886 
00887 /* ===========================================================================
00888      Returns 1 when EOF has previously been detected reading the given
00889    input stream, otherwise zero.
00890 */
00891 int ZEXPORT gzeof (file)
00892     gzFile file;
00893 {
00894     gz_stream *s = (gz_stream*)file;
00895 
00896     /* With concatenated compressed files that can have embedded
00897      * crc trailers, z_eof is no longer the only/best indicator of EOF
00898      * on a gz_stream. Handle end-of-stream error explicitly here.
00899      */
00900     if (s == NULL || s->mode != 'r') return 0;
00901     if (s->z_eof) return 1;
00902     return s->z_err == Z_STREAM_END;
00903 }
00904 
00905 /* ===========================================================================
00906      Returns 1 if reading and doing so transparently, otherwise zero.
00907 */
00908 int ZEXPORT gzdirect (file)
00909     gzFile file;
00910 {
00911     gz_stream *s = (gz_stream*)file;
00912 
00913     if (s == NULL || s->mode != 'r') return 0;
00914     return s->transparent;
00915 }
00916 
00917 /* ===========================================================================
00918    Outputs a long in LSB order to the given file
00919 */
00920 local void putLong (file, x)
00921     FILE *file;
00922     uLong x;
00923 {
00924     int n;
00925     for (n = 0; n < 4; n++) {
00926         fputc((int)(x & 0xff), file);
00927         x >>= 8;
00928     }
00929 }
00930 
00931 /* ===========================================================================
00932    Reads a long in LSB order from the given gz_stream. Sets z_err in case
00933    of error.
00934 */
00935 local uLong getLong (s)
00936     gz_stream *s;
00937 {
00938     uLong x = (uLong)get_byte(s);
00939     int c;
00940 
00941     x += ((uLong)get_byte(s))<<8;
00942     x += ((uLong)get_byte(s))<<16;
00943     c = get_byte(s);
00944     if (c == EOF) s->z_err = Z_DATA_ERROR;
00945     x += ((uLong)c)<<24;
00946     return x;
00947 }
00948 
00949 /* ===========================================================================
00950      Flushes all pending output if necessary, closes the compressed file
00951    and deallocates all the (de)compression state.
00952 */
00953 int ZEXPORT gzclose (file)
00954     gzFile file;
00955 {
00956     gz_stream *s = (gz_stream*)file;
00957 
00958     if (s == NULL) return Z_STREAM_ERROR;
00959 
00960     if (s->mode == 'w') {
00961 #ifdef NO_GZCOMPRESS
00962         return Z_STREAM_ERROR;
00963 #else
00964         if (do_flush (file, Z_FINISH) != Z_OK)
00965             return destroy((gz_stream*)file);
00966 
00967         putLong (s->file, s->crc);
00968         putLong (s->file, (uLong)(s->in & 0xffffffff));
00969 #endif
00970     }
00971     return destroy((gz_stream*)file);
00972 }
00973 
00974 #ifdef STDC
00975 #  define zstrerror(errnum) strerror(errnum)
00976 #else
00977 #  define zstrerror(errnum) ""
00978 #endif
00979 
00980 /* ===========================================================================
00981      Returns the error message for the last error which occurred on the
00982    given compressed file. errnum is set to zlib error number. If an
00983    error occurred in the file system and not in the compression library,
00984    errnum is set to Z_ERRNO and the application may consult errno
00985    to get the exact error code.
00986 */
00987 const char * ZEXPORT gzerror (file, errnum)
00988     gzFile file;
00989     int *errnum;
00990 {
00991     char *m;
00992     gz_stream *s = (gz_stream*)file;
00993 
00994     if (s == NULL) {
00995         *errnum = Z_STREAM_ERROR;
00996         return (const char*)ERR_MSG(Z_STREAM_ERROR);
00997     }
00998     *errnum = s->z_err;
00999     if (*errnum == Z_OK) return (const char*)"";
01000 
01001     m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
01002 
01003     if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
01004 
01005     TRYFREE(s->msg);
01006     s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
01007     if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
01008     strcpy(s->msg, s->path);
01009     strcat(s->msg, ": ");
01010     strcat(s->msg, m);
01011     return (const char*)s->msg;
01012 }
01013 
01014 /* ===========================================================================
01015      Clear the error and end-of-file flags, and do the same for the real file.
01016 */
01017 void ZEXPORT gzclearerr (file)
01018     gzFile file;
01019 {
01020     gz_stream *s = (gz_stream*)file;
01021 
01022     if (s == NULL) return;
01023     if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
01024     s->z_eof = 0;
01025     clearerr(s->file);
01026 }