]> git.lizzy.rs Git - zlib.git/commitdiff
Add a transparent write mode to gzopen() when 'T' is in the mode.
authorMark Adler <madler@alumni.caltech.edu>
Sun, 2 Oct 2011 20:24:43 +0000 (13:24 -0700)
committerMark Adler <madler@alumni.caltech.edu>
Sun, 2 Oct 2011 20:34:29 +0000 (13:34 -0700)
gzguts.h
gzlib.c
gzread.c
gzwrite.c
zlib.h

index 8193451b5193382fad1600e6dd0e78b76ee370ba..4d71db06e42567c92365f3be5693d909b0c02141 100644 (file)
--- a/gzguts.h
+++ b/gzguts.h
@@ -136,11 +136,11 @@ typedef struct {
     unsigned want;          /* requested buffer size, default is GZBUFSIZE */
     unsigned char *in;      /* input buffer */
     unsigned char *out;     /* output buffer (double-sized when reading) */
+    int direct;             /* 0 if processing gzip, 1 if transparent */
         /* just for reading */
     int eof;                /* true if end of input file reached */
     z_off64_t start;        /* where the gzip data started, for rewinding */
     int how;                /* 0: get header, 1: copy, 2: decompress */
-    int direct;             /* true if last read direct, false if gzip */
         /* just for writing */
     int level;              /* compression level */
     int strategy;           /* compression strategy */
diff --git a/gzlib.c b/gzlib.c
index 7b31d2432658a492d8c68d8189feffa2b8de20e3..e53b6abca16fd78066d1f8f2d91bed16fcf06595 100644 (file)
--- a/gzlib.c
+++ b/gzlib.c
@@ -79,7 +79,6 @@ local void gz_reset(state)
     if (state->mode == GZ_READ) {   /* for reading ... */
         state->eof = 0;             /* not at end of file */
         state->how = LOOK;          /* look for gzip header */
-        state->direct = 1;          /* default for empty file */
     }
     state->seek = 0;                /* no seek request pending */
     gz_error(state, Z_OK, NULL);    /* clear error */
@@ -111,6 +110,7 @@ local gzFile gz_open(path, fd, mode)
     state->mode = GZ_NONE;
     state->level = Z_DEFAULT_COMPRESSION;
     state->strategy = Z_DEFAULT_STRATEGY;
+    state->direct = 0;
     while (*mode) {
         if (*mode >= '0' && *mode <= '9')
             state->level = *mode - '0';
@@ -143,6 +143,8 @@ local gzFile gz_open(path, fd, mode)
                 break;
             case 'F':
                 state->strategy = Z_FIXED;
+            case 'T':
+                state->direct = 1;
             default:        /* could consider as an error, but just ignore */
                 ;
             }
@@ -155,6 +157,15 @@ local gzFile gz_open(path, fd, mode)
         return NULL;
     }
 
+    /* can't force transparent read */
+    if (state->mode == GZ_READ) {
+        if (state->direct) {
+            free(state);
+            return NULL;
+        }
+        state->direct = 1;      /* for empty file */
+    }
+
     /* save the path name for error messages */
     state->path = malloc(strlen(path) + 1);
     if (state->path == NULL) {
index 4701f9e0e115674f479733f9bcd2ab516f9ba32f..521e26fd5ec59f6e62314723f4a23c38a861f0f5 100644 (file)
--- a/gzread.c
+++ b/gzread.c
@@ -535,16 +535,12 @@ int ZEXPORT gzdirect(file)
         return 0;
     state = (gz_statep)file;
 
-    /* check that we're reading */
-    if (state->mode != GZ_READ)
-        return 0;
-
     /* if the state is not known, but we can find out, then do so (this is
        mainly for right after a gzopen() or gzdopen()) */
-    if (state->how == LOOK && state->x.have == 0)
+    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
         (void)gz_look(state);
 
-    /* return 1 if reading direct, 0 if decompressing a gzip stream */
+    /* return 1 if transparent, 0 if processing a gzip stream */
     return state->direct;
 }
 
index 1d288073d1bdce2ea71bbcbc7ed988c53d97e09a..6c991fe4605b6c2d8ecc0ddfb1b293cfc0e0a60b 100644 (file)
--- a/gzwrite.c
+++ b/gzwrite.c
@@ -18,44 +18,55 @@ local int gz_init(state)
     int ret;
     z_streamp strm = &(state->strm);
 
-    /* allocate input and output buffers */
+    /* allocate input buffer */
     state->in = malloc(state->want);
-    state->out = malloc(state->want);
-    if (state->in == NULL || state->out == NULL) {
-        if (state->out != NULL)
-            free(state->out);
-        if (state->in != NULL)
-            free(state->in);
+    if (state->in == NULL) {
         gz_error(state, Z_MEM_ERROR, "out of memory");
         return -1;
     }
 
-    /* allocate deflate memory, set up for gzip compression */
-    strm->zalloc = Z_NULL;
-    strm->zfree = Z_NULL;
-    strm->opaque = Z_NULL;
-    ret = deflateInit2(strm, state->level, Z_DEFLATED,
-                       15 + 16, 8, state->strategy);
-    if (ret != Z_OK) {
-        free(state->in);
-        gz_error(state, Z_MEM_ERROR, "out of memory");
-        return -1;
+    /* only need output buffer and deflate state if compressing */
+    if (!state->direct) {
+        /* allocate output buffer */
+        state->out = malloc(state->want);
+        if (state->out == NULL) {
+            free(state->in);
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+
+        /* allocate deflate memory, set up for gzip compression */
+        strm->zalloc = Z_NULL;
+        strm->zfree = Z_NULL;
+        strm->opaque = Z_NULL;
+        ret = deflateInit2(strm, state->level, Z_DEFLATED,
+                           15 + 16, 8, state->strategy);
+        if (ret != Z_OK) {
+            free(state->out);
+            free(state->in);
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
     }
 
     /* mark state as initialized */
     state->size = state->want;
 
-    /* initialize write buffer */
-    strm->avail_out = state->size;
-    strm->next_out = state->out;
-    state->x.next = strm->next_out;
+    /* initialize write buffer if compressing */
+    if (!state->direct) {
+        strm->avail_out = state->size;
+        strm->next_out = state->out;
+        state->x.next = strm->next_out;
+    }
     return 0;
 }
 
 /* Compress whatever is at avail_in and next_in and write to the output file.
    Return -1 if there is an error writing to the output file, otherwise 0.
    flush is assumed to be a valid deflate() flush value.  If flush is Z_FINISH,
-   then the deflate() state is reset to start a new gzip stream. */
+   then the deflate() state is reset to start a new gzip stream.  If gz->direct
+   is true, then simply write to the output file without compressing, and
+   ignore flush. */
 local int gz_comp(state, flush)
     gz_statep state;
     int flush;
@@ -68,6 +79,17 @@ local int gz_comp(state, flush)
     if (state->size == 0 && gz_init(state) == -1)
         return -1;
 
+    /* write directly if requested */
+    if (state->direct) {
+        got = write(state->fd, strm->next_in, strm->avail_in);
+        if (got < 0 || (unsigned)got != strm->avail_in) {
+            gz_error(state, Z_ERRNO, zstrerror());
+            return -1;
+        }
+        strm->avail_in = 0;
+        return 0;
+    }
+
     /* run deflate() on provided input until it produces no more output */
     ret = Z_OK;
     do {
@@ -526,8 +548,10 @@ int ZEXPORT gzclose_w(file)
     /* flush, free memory, and close file */
     if (gz_comp(state, Z_FINISH) == -1)
         ret = state->err;
-    (void)deflateEnd(&(state->strm));
-    free(state->out);
+    if (!state->direct) {
+        (void)deflateEnd(&(state->strm));
+        free(state->out);
+    }
     free(state->in);
     gz_error(state, Z_OK, NULL);
     free(state->path);
diff --git a/zlib.h b/zlib.h
index 8050bddc176420d0f70d13c178ae1e0a589804f5..f77b5967a22dd17d855a22a6039c4392db637072 100644 (file)
--- a/zlib.h
+++ b/zlib.h
@@ -696,7 +696,7 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
    be larger than the value returned by deflateBound() if flush options other
    than Z_FINISH or Z_NO_FLUSH are used.
 */
-    
+
 ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
                                        unsigned *pending,
                                        int *bits));
@@ -706,7 +706,7 @@ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
    provided would be due to the available output space having being consumed.
    The number of bits of output not provided are between 0 and 7, where they
    await more bits to join them in order to fill out a full byte.
+
      deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
    stream state was inconsistent.
  */
@@ -1196,10 +1196,13 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
    a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
    compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
    for fixed code compression as in "wb9F".  (See the description of
-   deflateInit2 for more information about the strategy parameter.) Also "a"
-   can be used instead of "w" to request that the gzip stream that will be
-   written be appended to the file.  "+" will result in an error, since reading
-   and writing to the same gzip file is not supported.
+   deflateInit2 for more information about the strategy parameter.)  'T' will
+   request transparent writing or appending with no compression and not using
+   the gzip format.
+
+     "a" can be used instead of "w" to request that the gzip stream that will
+   be written be appended to the file.  "+" will result in an error, since
+   reading and writing to the same gzip file is not supported.
 
      These functions, as well as gzip, will read and decode a sequence of gzip
    streams in a file.  The append function of gzopen() can be used to create
@@ -1209,7 +1212,9 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
    will simply append a gzip stream to the existing file.
 
      gzopen can be used to read a file which is not in gzip format; in this
-   case gzread will directly read from the file without decompression.
+   case gzread will directly read from the file without decompression.  When
+   reading, this will be detected automatically by looking for the magic two-
+   byte gzip header.
 
      gzopen returns NULL if the file could not be opened, if there was
    insufficient memory to allocate the gzFile state, or if an invalid mode was
@@ -1440,6 +1445,13 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
    cause buffers to be allocated to allow reading the file to determine if it
    is a gzip file.  Therefore if gzbuffer() is used, it should be called before
    gzdirect().
+
+     When writing, gzdirect() returns true (1) if transparent writing was
+   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
+   gzdirect() is not needed when writing.  Transparent writing must be
+   explicitly requested, so the application already knows the answer.  When
+   linking statically, using gzdirect() will include all of the zlib code for
+   gzip file reading and decompression, which may not be desired.)
 */
 
 ZEXTERN int ZEXPORT    gzclose OF((gzFile file));