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. |