summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2011-10-02 13:24:43 -0700
committerMark Adler <madler@alumni.caltech.edu>2011-10-02 13:34:29 -0700
commit26a99cd8957db86bdc75d9d1ebf00146cb20c87c (patch)
tree2f65d57da589c9e5475902fdf08a4aa8c4294bda
parent3c9d261809bfafc4350147ade7b74022dd144d32 (diff)
downloadzlib-26a99cd8957db86bdc75d9d1ebf00146cb20c87c.tar.gz
Add a transparent write mode to gzopen() when 'T' is in the mode.
-rw-r--r--gzguts.h2
-rw-r--r--gzlib.c13
-rw-r--r--gzread.c8
-rw-r--r--gzwrite.c72
-rw-r--r--zlib.h26
5 files changed, 82 insertions, 39 deletions
diff --git a/gzguts.h b/gzguts.h
index 8193451..4d71db0 100644
--- 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 7b31d24..e53b6ab 100644
--- 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) {
diff --git a/gzread.c b/gzread.c
index 4701f9e..521e26f 100644
--- 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;
}
diff --git a/gzwrite.c b/gzwrite.c
index 1d28807..6c991fe 100644
--- 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 8050bdd..f77b596 100644
--- 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));