Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

gzio.c

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

Generated on Sat Oct 13 16:08:37 2001 for XMILL by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001