aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2024-02-04 13:10:44 -0800
committerMark Adler <madler@alumni.caltech.edu>2024-02-04 18:51:14 -0800
commit037bca67fdf3a81996aea3662521c676f653dfc6 (patch)
treecdb37024da6883eafdf3744a0172d79983bf3eaa
parent6378d33478ea2d068960aa4e68cf9f11a5ffcfbe (diff)
downloadzlib-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.
-rw-r--r--examples/zran.c46
-rw-r--r--examples/zran.h3
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.
68void deflate_index_free(struct deflate_index *index) { 68void 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.
80static struct deflate_index *add_point(struct deflate_index *index, int bits, 83static 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.