diff options
| author | Mark Adler <madler@alumni.caltech.edu> | 2024-02-04 13:10:44 -0800 |
|---|---|---|
| committer | Mark Adler <madler@alumni.caltech.edu> | 2024-02-04 18:51:14 -0800 |
| commit | 037bca67fdf3a81996aea3662521c676f653dfc6 (patch) | |
| tree | cdb37024da6883eafdf3744a0172d79983bf3eaa /examples | |
| parent | 6378d33478ea2d068960aa4e68cf9f11a5ffcfbe (diff) | |
| download | zlib-037bca67fdf3a81996aea3662521c676f653dfc6.tar.gz zlib-037bca67fdf3a81996aea3662521c676f653dfc6.tar.bz2 zlib-037bca67fdf3a81996aea3662521c676f653dfc6.zip | |
Allocate the dictionaries in examples/zran.c.
This reduces the memory needed for dictionaries, and avoids the
need to reallocate the index at the end to return unused memory.
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/zran.c | 46 | ||||
| -rw-r--r-- | examples/zran.h | 3 |
2 files changed, 27 insertions, 22 deletions
diff --git a/examples/zran.c b/examples/zran.c index f79e518..8f4023f 100644 --- a/examples/zran.c +++ b/examples/zran.c | |||
| @@ -67,6 +67,9 @@ | |||
| 67 | // See comments in zran.h. | 67 | // See comments in zran.h. |
| 68 | void deflate_index_free(struct deflate_index *index) { | 68 | void deflate_index_free(struct deflate_index *index) { |
| 69 | if (index != NULL) { | 69 | if (index != NULL) { |
| 70 | size_t i = index->have; | ||
| 71 | while (i) | ||
| 72 | free(index->list[--i].window); | ||
| 70 | free(index->list); | 73 | free(index->list); |
| 71 | inflateEnd(&index->strm); | 74 | inflateEnd(&index->strm); |
| 72 | free(index); | 75 | free(index); |
| @@ -77,8 +80,8 @@ void deflate_index_free(struct deflate_index *index) { | |||
| 77 | // list and return NULL. index->mode is temporarily the allocated number of | 80 | // list and return NULL. index->mode is temporarily the allocated number of |
| 78 | // access points, until it is time for deflate_index_build() to return. Then | 81 | // access points, until it is time for deflate_index_build() to return. Then |
| 79 | // index->mode is set to the mode of inflation. | 82 | // index->mode is set to the mode of inflation. |
| 80 | static struct deflate_index *add_point(struct deflate_index *index, int bits, | 83 | static struct deflate_index *add_point(struct deflate_index *index, off_t in, |
| 81 | off_t in, off_t out, unsigned left, | 84 | off_t out, off_t beg, |
| 82 | unsigned char *window) { | 85 | unsigned char *window) { |
| 83 | if (index->have == index->mode) { | 86 | if (index->have == index->mode) { |
| 84 | // The list is full. Make it bigger. | 87 | // The list is full. Make it bigger. |
| @@ -100,11 +103,18 @@ static struct deflate_index *add_point(struct deflate_index *index, int bits, | |||
| 100 | } | 103 | } |
| 101 | next->out = out; | 104 | next->out = out; |
| 102 | next->in = in; | 105 | next->in = in; |
| 103 | next->bits = bits; | 106 | next->bits = index->strm.data_type & 7; |
| 104 | if (left) | 107 | next->dict = out - beg > WINSIZE ? WINSIZE : (unsigned)(out - beg); |
| 105 | memcpy(next->window, window + WINSIZE - left, left); | 108 | next->window = malloc(next->dict); |
| 106 | if (left < WINSIZE) | 109 | if (next->window == NULL) { |
| 107 | memcpy(next->window + left, window, WINSIZE - left); | 110 | deflate_index_free(index); |
| 111 | return NULL; | ||
| 112 | } | ||
| 113 | unsigned recent = WINSIZE - index->strm.avail_out; | ||
| 114 | unsigned copy = recent > next->dict ? next->dict : recent; | ||
| 115 | memcpy(next->window + next->dict - copy, window + recent - copy, copy); | ||
| 116 | copy = next->dict - copy; | ||
| 117 | memcpy(next->window, window + WINSIZE - copy, copy); | ||
| 108 | 118 | ||
| 109 | // Return the index, which may have been newly allocated or destroyed. | 119 | // Return the index, which may have been newly allocated or destroyed. |
| 110 | return index; | 120 | return index; |
| @@ -137,6 +147,7 @@ int deflate_index_build(FILE *in, off_t span, struct deflate_index **built) { | |||
| 137 | unsigned char win[WINSIZE] = {0}; // output sliding window | 147 | unsigned char win[WINSIZE] = {0}; // output sliding window |
| 138 | off_t totin = 0; // total bytes read from input | 148 | off_t totin = 0; // total bytes read from input |
| 139 | off_t totout = 0; // total bytes uncompressed | 149 | off_t totout = 0; // total bytes uncompressed |
| 150 | off_t beg = 0; // starting offset of last history reset | ||
| 140 | int mode = 0; // mode: RAW, ZLIB, or GZIP (0 => not set yet) | 151 | int mode = 0; // mode: RAW, ZLIB, or GZIP (0 => not set yet) |
| 141 | 152 | ||
| 142 | // Decompress from in, generating access points along the way. | 153 | // Decompress from in, generating access points along the way. |
| @@ -198,9 +209,8 @@ int deflate_index_build(FILE *in, off_t span, struct deflate_index **built) { | |||
| 198 | // very start for the first access point, or there has been span or | 209 | // very start for the first access point, or there has been span or |
| 199 | // more uncompressed bytes since the last access point, so we want | 210 | // more uncompressed bytes since the last access point, so we want |
| 200 | // to add an access point here. | 211 | // to add an access point here. |
| 201 | index = add_point(index, index->strm.data_type & 7, | 212 | index = add_point(index, totin - index->strm.avail_in, totout, beg, |
| 202 | totin - index->strm.avail_in, | 213 | win); |
| 203 | totout, index->strm.avail_out, win); | ||
| 204 | if (index == NULL) { | 214 | if (index == NULL) { |
| 205 | ret = Z_MEM_ERROR; | 215 | ret = Z_MEM_ERROR; |
| 206 | break; | 216 | break; |
| @@ -209,11 +219,13 @@ int deflate_index_build(FILE *in, off_t span, struct deflate_index **built) { | |||
| 209 | } | 219 | } |
| 210 | 220 | ||
| 211 | if (ret == Z_STREAM_END && mode == GZIP && | 221 | if (ret == Z_STREAM_END && mode == GZIP && |
| 212 | (index->strm.avail_in || ungetc(getc(in), in) != EOF)) | 222 | (index->strm.avail_in || ungetc(getc(in), in) != EOF)) { |
| 213 | // There is more input after the end of a gzip member. Reset the | 223 | // There is more input after the end of a gzip member. Reset the |
| 214 | // inflate state to read another gzip member. On success, this will | 224 | // inflate state to read another gzip member. On success, this will |
| 215 | // set ret to Z_OK to continue decompressing. | 225 | // set ret to Z_OK to continue decompressing. |
| 216 | ret = inflateReset2(&index->strm, GZIP); | 226 | ret = inflateReset2(&index->strm, GZIP); |
| 227 | beg = totout; // reset history | ||
| 228 | } | ||
| 217 | 229 | ||
| 218 | // Keep going until Z_STREAM_END or error. If the compressed data ends | 230 | // Keep going until Z_STREAM_END or error. If the compressed data ends |
| 219 | // prematurely without a file read error, Z_BUF_ERROR is returned. | 231 | // prematurely without a file read error, Z_BUF_ERROR is returned. |
| @@ -226,17 +238,9 @@ int deflate_index_build(FILE *in, off_t span, struct deflate_index **built) { | |||
| 226 | return ret == Z_NEED_DICT ? Z_DATA_ERROR : ret; | 238 | return ret == Z_NEED_DICT ? Z_DATA_ERROR : ret; |
| 227 | } | 239 | } |
| 228 | 240 | ||
| 229 | // Shrink the index to only the occupied access points and return it. | 241 | // Return the index. |
| 230 | index->mode = mode; | 242 | index->mode = mode; |
| 231 | index->length = totout; | 243 | index->length = totout; |
| 232 | point_t *list = realloc(index->list, sizeof(point_t) * index->have); | ||
| 233 | if (list == NULL) { | ||
| 234 | // Seems like a realloc() to make something smaller should always work, | ||
| 235 | // but just in case. | ||
| 236 | deflate_index_free(index); | ||
| 237 | return Z_MEM_ERROR; | ||
| 238 | } | ||
| 239 | index->list = list; | ||
| 240 | *built = index; | 244 | *built = index; |
| 241 | return index->have; | 245 | return index->have; |
| 242 | } | 246 | } |
| @@ -366,7 +370,7 @@ ptrdiff_t deflate_index_extract(FILE *in, struct deflate_index *index, | |||
| 366 | return ret; | 370 | return ret; |
| 367 | if (point->bits) | 371 | if (point->bits) |
| 368 | INFLATEPRIME(&index->strm, point->bits, ch >> (8 - point->bits)); | 372 | INFLATEPRIME(&index->strm, point->bits, ch >> (8 - point->bits)); |
| 369 | inflateSetDictionary(&index->strm, point->window, WINSIZE); | 373 | inflateSetDictionary(&index->strm, point->window, point->dict); |
| 370 | 374 | ||
| 371 | // Skip uncompressed bytes until offset reached, then satisfy request. | 375 | // Skip uncompressed bytes until offset reached, then satisfy request. |
| 372 | unsigned char input[CHUNK]; | 376 | unsigned char input[CHUNK]; |
diff --git a/examples/zran.h b/examples/zran.h index 23fbd1f..de0646b 100644 --- a/examples/zran.h +++ b/examples/zran.h | |||
| @@ -11,7 +11,8 @@ typedef struct point { | |||
| 11 | off_t out; // offset in uncompressed data | 11 | off_t out; // offset in uncompressed data |
| 12 | off_t in; // offset in compressed file of first full byte | 12 | off_t in; // offset in compressed file of first full byte |
| 13 | int bits; // 0, or number of bits (1-7) from byte at in-1 | 13 | int bits; // 0, or number of bits (1-7) from byte at in-1 |
| 14 | unsigned char window[32768]; // preceding 32K of uncompressed data | 14 | unsigned dict; // number of bytes in window to use as a dictionary |
| 15 | unsigned char *window; // preceding 32K (or less) of uncompressed data | ||
| 15 | } point_t; | 16 | } point_t; |
| 16 | 17 | ||
| 17 | // Access point list. | 18 | // Access point list. |
