diff options
| author | Mark Adler <madler@alumni.caltech.edu> | 2011-10-02 13:24:43 -0700 |
|---|---|---|
| committer | Mark Adler <madler@alumni.caltech.edu> | 2011-10-02 13:34:29 -0700 |
| commit | 26a99cd8957db86bdc75d9d1ebf00146cb20c87c (patch) | |
| tree | 2f65d57da589c9e5475902fdf08a4aa8c4294bda | |
| parent | 3c9d261809bfafc4350147ade7b74022dd144d32 (diff) | |
| download | zlib-26a99cd8957db86bdc75d9d1ebf00146cb20c87c.tar.gz zlib-26a99cd8957db86bdc75d9d1ebf00146cb20c87c.tar.bz2 zlib-26a99cd8957db86bdc75d9d1ebf00146cb20c87c.zip | |
Add a transparent write mode to gzopen() when 'T' is in the mode.
| -rw-r--r-- | gzguts.h | 2 | ||||
| -rw-r--r-- | gzlib.c | 13 | ||||
| -rw-r--r-- | gzread.c | 8 | ||||
| -rw-r--r-- | gzwrite.c | 72 | ||||
| -rw-r--r-- | zlib.h | 26 |
5 files changed, 82 insertions, 39 deletions
| @@ -136,11 +136,11 @@ typedef struct { | |||
| 136 | unsigned want; /* requested buffer size, default is GZBUFSIZE */ | 136 | unsigned want; /* requested buffer size, default is GZBUFSIZE */ |
| 137 | unsigned char *in; /* input buffer */ | 137 | unsigned char *in; /* input buffer */ |
| 138 | unsigned char *out; /* output buffer (double-sized when reading) */ | 138 | unsigned char *out; /* output buffer (double-sized when reading) */ |
| 139 | int direct; /* 0 if processing gzip, 1 if transparent */ | ||
| 139 | /* just for reading */ | 140 | /* just for reading */ |
| 140 | int eof; /* true if end of input file reached */ | 141 | int eof; /* true if end of input file reached */ |
| 141 | z_off64_t start; /* where the gzip data started, for rewinding */ | 142 | z_off64_t start; /* where the gzip data started, for rewinding */ |
| 142 | int how; /* 0: get header, 1: copy, 2: decompress */ | 143 | int how; /* 0: get header, 1: copy, 2: decompress */ |
| 143 | int direct; /* true if last read direct, false if gzip */ | ||
| 144 | /* just for writing */ | 144 | /* just for writing */ |
| 145 | int level; /* compression level */ | 145 | int level; /* compression level */ |
| 146 | int strategy; /* compression strategy */ | 146 | int strategy; /* compression strategy */ |
| @@ -79,7 +79,6 @@ local void gz_reset(state) | |||
| 79 | if (state->mode == GZ_READ) { /* for reading ... */ | 79 | if (state->mode == GZ_READ) { /* for reading ... */ |
| 80 | state->eof = 0; /* not at end of file */ | 80 | state->eof = 0; /* not at end of file */ |
| 81 | state->how = LOOK; /* look for gzip header */ | 81 | state->how = LOOK; /* look for gzip header */ |
| 82 | state->direct = 1; /* default for empty file */ | ||
| 83 | } | 82 | } |
| 84 | state->seek = 0; /* no seek request pending */ | 83 | state->seek = 0; /* no seek request pending */ |
| 85 | gz_error(state, Z_OK, NULL); /* clear error */ | 84 | gz_error(state, Z_OK, NULL); /* clear error */ |
| @@ -111,6 +110,7 @@ local gzFile gz_open(path, fd, mode) | |||
| 111 | state->mode = GZ_NONE; | 110 | state->mode = GZ_NONE; |
| 112 | state->level = Z_DEFAULT_COMPRESSION; | 111 | state->level = Z_DEFAULT_COMPRESSION; |
| 113 | state->strategy = Z_DEFAULT_STRATEGY; | 112 | state->strategy = Z_DEFAULT_STRATEGY; |
| 113 | state->direct = 0; | ||
| 114 | while (*mode) { | 114 | while (*mode) { |
| 115 | if (*mode >= '0' && *mode <= '9') | 115 | if (*mode >= '0' && *mode <= '9') |
| 116 | state->level = *mode - '0'; | 116 | state->level = *mode - '0'; |
| @@ -143,6 +143,8 @@ local gzFile gz_open(path, fd, mode) | |||
| 143 | break; | 143 | break; |
| 144 | case 'F': | 144 | case 'F': |
| 145 | state->strategy = Z_FIXED; | 145 | state->strategy = Z_FIXED; |
| 146 | case 'T': | ||
| 147 | state->direct = 1; | ||
| 146 | default: /* could consider as an error, but just ignore */ | 148 | default: /* could consider as an error, but just ignore */ |
| 147 | ; | 149 | ; |
| 148 | } | 150 | } |
| @@ -155,6 +157,15 @@ local gzFile gz_open(path, fd, mode) | |||
| 155 | return NULL; | 157 | return NULL; |
| 156 | } | 158 | } |
| 157 | 159 | ||
| 160 | /* can't force transparent read */ | ||
| 161 | if (state->mode == GZ_READ) { | ||
| 162 | if (state->direct) { | ||
| 163 | free(state); | ||
| 164 | return NULL; | ||
| 165 | } | ||
| 166 | state->direct = 1; /* for empty file */ | ||
| 167 | } | ||
| 168 | |||
| 158 | /* save the path name for error messages */ | 169 | /* save the path name for error messages */ |
| 159 | state->path = malloc(strlen(path) + 1); | 170 | state->path = malloc(strlen(path) + 1); |
| 160 | if (state->path == NULL) { | 171 | if (state->path == NULL) { |
| @@ -535,16 +535,12 @@ int ZEXPORT gzdirect(file) | |||
| 535 | return 0; | 535 | return 0; |
| 536 | state = (gz_statep)file; | 536 | state = (gz_statep)file; |
| 537 | 537 | ||
| 538 | /* check that we're reading */ | ||
| 539 | if (state->mode != GZ_READ) | ||
| 540 | return 0; | ||
| 541 | |||
| 542 | /* if the state is not known, but we can find out, then do so (this is | 538 | /* if the state is not known, but we can find out, then do so (this is |
| 543 | mainly for right after a gzopen() or gzdopen()) */ | 539 | mainly for right after a gzopen() or gzdopen()) */ |
| 544 | if (state->how == LOOK && state->x.have == 0) | 540 | if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) |
| 545 | (void)gz_look(state); | 541 | (void)gz_look(state); |
| 546 | 542 | ||
| 547 | /* return 1 if reading direct, 0 if decompressing a gzip stream */ | 543 | /* return 1 if transparent, 0 if processing a gzip stream */ |
| 548 | return state->direct; | 544 | return state->direct; |
| 549 | } | 545 | } |
| 550 | 546 | ||
| @@ -18,44 +18,55 @@ local int gz_init(state) | |||
| 18 | int ret; | 18 | int ret; |
| 19 | z_streamp strm = &(state->strm); | 19 | z_streamp strm = &(state->strm); |
| 20 | 20 | ||
| 21 | /* allocate input and output buffers */ | 21 | /* allocate input buffer */ |
| 22 | state->in = malloc(state->want); | 22 | state->in = malloc(state->want); |
| 23 | state->out = malloc(state->want); | 23 | if (state->in == NULL) { |
| 24 | if (state->in == NULL || state->out == NULL) { | ||
| 25 | if (state->out != NULL) | ||
| 26 | free(state->out); | ||
| 27 | if (state->in != NULL) | ||
| 28 | free(state->in); | ||
| 29 | gz_error(state, Z_MEM_ERROR, "out of memory"); | 24 | gz_error(state, Z_MEM_ERROR, "out of memory"); |
| 30 | return -1; | 25 | return -1; |
| 31 | } | 26 | } |
| 32 | 27 | ||
| 33 | /* allocate deflate memory, set up for gzip compression */ | 28 | /* only need output buffer and deflate state if compressing */ |
| 34 | strm->zalloc = Z_NULL; | 29 | if (!state->direct) { |
| 35 | strm->zfree = Z_NULL; | 30 | /* allocate output buffer */ |
| 36 | strm->opaque = Z_NULL; | 31 | state->out = malloc(state->want); |
| 37 | ret = deflateInit2(strm, state->level, Z_DEFLATED, | 32 | if (state->out == NULL) { |
| 38 | 15 + 16, 8, state->strategy); | 33 | free(state->in); |
| 39 | if (ret != Z_OK) { | 34 | gz_error(state, Z_MEM_ERROR, "out of memory"); |
| 40 | free(state->in); | 35 | return -1; |
| 41 | gz_error(state, Z_MEM_ERROR, "out of memory"); | 36 | } |
| 42 | return -1; | 37 | |
| 38 | /* allocate deflate memory, set up for gzip compression */ | ||
| 39 | strm->zalloc = Z_NULL; | ||
| 40 | strm->zfree = Z_NULL; | ||
| 41 | strm->opaque = Z_NULL; | ||
| 42 | ret = deflateInit2(strm, state->level, Z_DEFLATED, | ||
| 43 | 15 + 16, 8, state->strategy); | ||
| 44 | if (ret != Z_OK) { | ||
| 45 | free(state->out); | ||
| 46 | free(state->in); | ||
| 47 | gz_error(state, Z_MEM_ERROR, "out of memory"); | ||
| 48 | return -1; | ||
| 49 | } | ||
| 43 | } | 50 | } |
| 44 | 51 | ||
| 45 | /* mark state as initialized */ | 52 | /* mark state as initialized */ |
| 46 | state->size = state->want; | 53 | state->size = state->want; |
| 47 | 54 | ||
| 48 | /* initialize write buffer */ | 55 | /* initialize write buffer if compressing */ |
| 49 | strm->avail_out = state->size; | 56 | if (!state->direct) { |
| 50 | strm->next_out = state->out; | 57 | strm->avail_out = state->size; |
| 51 | state->x.next = strm->next_out; | 58 | strm->next_out = state->out; |
| 59 | state->x.next = strm->next_out; | ||
| 60 | } | ||
| 52 | return 0; | 61 | return 0; |
| 53 | } | 62 | } |
| 54 | 63 | ||
| 55 | /* Compress whatever is at avail_in and next_in and write to the output file. | 64 | /* Compress whatever is at avail_in and next_in and write to the output file. |
| 56 | Return -1 if there is an error writing to the output file, otherwise 0. | 65 | Return -1 if there is an error writing to the output file, otherwise 0. |
| 57 | flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, | 66 | flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, |
| 58 | then the deflate() state is reset to start a new gzip stream. */ | 67 | then the deflate() state is reset to start a new gzip stream. If gz->direct |
| 68 | is true, then simply write to the output file without compressing, and | ||
| 69 | ignore flush. */ | ||
| 59 | local int gz_comp(state, flush) | 70 | local int gz_comp(state, flush) |
| 60 | gz_statep state; | 71 | gz_statep state; |
| 61 | int flush; | 72 | int flush; |
| @@ -68,6 +79,17 @@ local int gz_comp(state, flush) | |||
| 68 | if (state->size == 0 && gz_init(state) == -1) | 79 | if (state->size == 0 && gz_init(state) == -1) |
| 69 | return -1; | 80 | return -1; |
| 70 | 81 | ||
| 82 | /* write directly if requested */ | ||
| 83 | if (state->direct) { | ||
| 84 | got = write(state->fd, strm->next_in, strm->avail_in); | ||
| 85 | if (got < 0 || (unsigned)got != strm->avail_in) { | ||
| 86 | gz_error(state, Z_ERRNO, zstrerror()); | ||
| 87 | return -1; | ||
| 88 | } | ||
| 89 | strm->avail_in = 0; | ||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 71 | /* run deflate() on provided input until it produces no more output */ | 93 | /* run deflate() on provided input until it produces no more output */ |
| 72 | ret = Z_OK; | 94 | ret = Z_OK; |
| 73 | do { | 95 | do { |
| @@ -526,8 +548,10 @@ int ZEXPORT gzclose_w(file) | |||
| 526 | /* flush, free memory, and close file */ | 548 | /* flush, free memory, and close file */ |
| 527 | if (gz_comp(state, Z_FINISH) == -1) | 549 | if (gz_comp(state, Z_FINISH) == -1) |
| 528 | ret = state->err; | 550 | ret = state->err; |
| 529 | (void)deflateEnd(&(state->strm)); | 551 | if (!state->direct) { |
| 530 | free(state->out); | 552 | (void)deflateEnd(&(state->strm)); |
| 553 | free(state->out); | ||
| 554 | } | ||
| 531 | free(state->in); | 555 | free(state->in); |
| 532 | gz_error(state, Z_OK, NULL); | 556 | gz_error(state, Z_OK, NULL); |
| 533 | free(state->path); | 557 | free(state->path); |
| @@ -696,7 +696,7 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, | |||
| 696 | be larger than the value returned by deflateBound() if flush options other | 696 | be larger than the value returned by deflateBound() if flush options other |
| 697 | than Z_FINISH or Z_NO_FLUSH are used. | 697 | than Z_FINISH or Z_NO_FLUSH are used. |
| 698 | */ | 698 | */ |
| 699 | 699 | ||
| 700 | ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, | 700 | ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, |
| 701 | unsigned *pending, | 701 | unsigned *pending, |
| 702 | int *bits)); | 702 | int *bits)); |
| @@ -706,7 +706,7 @@ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, | |||
| 706 | provided would be due to the available output space having being consumed. | 706 | provided would be due to the available output space having being consumed. |
| 707 | The number of bits of output not provided are between 0 and 7, where they | 707 | The number of bits of output not provided are between 0 and 7, where they |
| 708 | await more bits to join them in order to fill out a full byte. | 708 | await more bits to join them in order to fill out a full byte. |
| 709 | 709 | ||
| 710 | deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source | 710 | deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source |
| 711 | stream state was inconsistent. | 711 | stream state was inconsistent. |
| 712 | */ | 712 | */ |
| @@ -1196,10 +1196,13 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); | |||
| 1196 | a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only | 1196 | a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only |
| 1197 | compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' | 1197 | compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' |
| 1198 | for fixed code compression as in "wb9F". (See the description of | 1198 | for fixed code compression as in "wb9F". (See the description of |
| 1199 | deflateInit2 for more information about the strategy parameter.) Also "a" | 1199 | deflateInit2 for more information about the strategy parameter.) 'T' will |
| 1200 | can be used instead of "w" to request that the gzip stream that will be | 1200 | request transparent writing or appending with no compression and not using |
| 1201 | written be appended to the file. "+" will result in an error, since reading | 1201 | the gzip format. |
| 1202 | and writing to the same gzip file is not supported. | 1202 | |
| 1203 | "a" can be used instead of "w" to request that the gzip stream that will | ||
| 1204 | be written be appended to the file. "+" will result in an error, since | ||
| 1205 | reading and writing to the same gzip file is not supported. | ||
| 1203 | 1206 | ||
| 1204 | These functions, as well as gzip, will read and decode a sequence of gzip | 1207 | These functions, as well as gzip, will read and decode a sequence of gzip |
| 1205 | streams in a file. The append function of gzopen() can be used to create | 1208 | 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)); | |||
| 1209 | will simply append a gzip stream to the existing file. | 1212 | will simply append a gzip stream to the existing file. |
| 1210 | 1213 | ||
| 1211 | gzopen can be used to read a file which is not in gzip format; in this | 1214 | gzopen can be used to read a file which is not in gzip format; in this |
| 1212 | case gzread will directly read from the file without decompression. | 1215 | case gzread will directly read from the file without decompression. When |
| 1216 | reading, this will be detected automatically by looking for the magic two- | ||
| 1217 | byte gzip header. | ||
| 1213 | 1218 | ||
| 1214 | gzopen returns NULL if the file could not be opened, if there was | 1219 | gzopen returns NULL if the file could not be opened, if there was |
| 1215 | insufficient memory to allocate the gzFile state, or if an invalid mode was | 1220 | insufficient memory to allocate the gzFile state, or if an invalid mode was |
| @@ -1440,6 +1445,13 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); | |||
| 1440 | cause buffers to be allocated to allow reading the file to determine if it | 1445 | cause buffers to be allocated to allow reading the file to determine if it |
| 1441 | is a gzip file. Therefore if gzbuffer() is used, it should be called before | 1446 | is a gzip file. Therefore if gzbuffer() is used, it should be called before |
| 1442 | gzdirect(). | 1447 | gzdirect(). |
| 1448 | |||
| 1449 | When writing, gzdirect() returns true (1) if transparent writing was | ||
| 1450 | requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: | ||
| 1451 | gzdirect() is not needed when writing. Transparent writing must be | ||
| 1452 | explicitly requested, so the application already knows the answer. When | ||
| 1453 | linking statically, using gzdirect() will include all of the zlib code for | ||
| 1454 | gzip file reading and decompression, which may not be desired.) | ||
| 1443 | */ | 1455 | */ |
| 1444 | 1456 | ||
| 1445 | ZEXTERN int ZEXPORT gzclose OF((gzFile file)); | 1457 | ZEXTERN int ZEXPORT gzclose OF((gzFile file)); |
