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.
This commit is contained in:
Mark Adler 2024-02-04 13:10:44 -08:00
parent 6378d33478
commit 037bca67fd
2 changed files with 27 additions and 22 deletions

View File

@ -67,6 +67,9 @@
// See comments in zran.h.
void deflate_index_free(struct deflate_index *index) {
if (index != NULL) {
size_t i = index->have;
while (i)
free(index->list[--i].window);
free(index->list);
inflateEnd(&index->strm);
free(index);
@ -77,8 +80,8 @@ void deflate_index_free(struct deflate_index *index) {
// list and return NULL. index->mode is temporarily the allocated number of
// access points, until it is time for deflate_index_build() to return. Then
// index->mode is set to the mode of inflation.
static struct deflate_index *add_point(struct deflate_index *index, int bits,
off_t in, off_t out, unsigned left,
static struct deflate_index *add_point(struct deflate_index *index, off_t in,
off_t out, off_t beg,
unsigned char *window) {
if (index->have == index->mode) {
// The list is full. Make it bigger.
@ -100,11 +103,18 @@ static struct deflate_index *add_point(struct deflate_index *index, int bits,
}
next->out = out;
next->in = in;
next->bits = bits;
if (left)
memcpy(next->window, window + WINSIZE - left, left);
if (left < WINSIZE)
memcpy(next->window + left, window, WINSIZE - left);
next->bits = index->strm.data_type & 7;
next->dict = out - beg > WINSIZE ? WINSIZE : (unsigned)(out - beg);
next->window = malloc(next->dict);
if (next->window == NULL) {
deflate_index_free(index);
return NULL;
}
unsigned recent = WINSIZE - index->strm.avail_out;
unsigned copy = recent > next->dict ? next->dict : recent;
memcpy(next->window + next->dict - copy, window + recent - copy, copy);
copy = next->dict - copy;
memcpy(next->window, window + WINSIZE - copy, copy);
// Return the index, which may have been newly allocated or destroyed.
return index;
@ -137,6 +147,7 @@ int deflate_index_build(FILE *in, off_t span, struct deflate_index **built) {
unsigned char win[WINSIZE] = {0}; // output sliding window
off_t totin = 0; // total bytes read from input
off_t totout = 0; // total bytes uncompressed
off_t beg = 0; // starting offset of last history reset
int mode = 0; // mode: RAW, ZLIB, or GZIP (0 => not set yet)
// 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) {
// very start for the first access point, or there has been span or
// more uncompressed bytes since the last access point, so we want
// to add an access point here.
index = add_point(index, index->strm.data_type & 7,
totin - index->strm.avail_in,
totout, index->strm.avail_out, win);
index = add_point(index, totin - index->strm.avail_in, totout, beg,
win);
if (index == NULL) {
ret = Z_MEM_ERROR;
break;
@ -209,11 +219,13 @@ int deflate_index_build(FILE *in, off_t span, struct deflate_index **built) {
}
if (ret == Z_STREAM_END && mode == GZIP &&
(index->strm.avail_in || ungetc(getc(in), in) != EOF))
(index->strm.avail_in || ungetc(getc(in), in) != EOF)) {
// There is more input after the end of a gzip member. Reset the
// inflate state to read another gzip member. On success, this will
// set ret to Z_OK to continue decompressing.
ret = inflateReset2(&index->strm, GZIP);
beg = totout; // reset history
}
// Keep going until Z_STREAM_END or error. If the compressed data ends
// 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) {
return ret == Z_NEED_DICT ? Z_DATA_ERROR : ret;
}
// Shrink the index to only the occupied access points and return it.
// Return the index.
index->mode = mode;
index->length = totout;
point_t *list = realloc(index->list, sizeof(point_t) * index->have);
if (list == NULL) {
// Seems like a realloc() to make something smaller should always work,
// but just in case.
deflate_index_free(index);
return Z_MEM_ERROR;
}
index->list = list;
*built = index;
return index->have;
}
@ -366,7 +370,7 @@ ptrdiff_t deflate_index_extract(FILE *in, struct deflate_index *index,
return ret;
if (point->bits)
INFLATEPRIME(&index->strm, point->bits, ch >> (8 - point->bits));
inflateSetDictionary(&index->strm, point->window, WINSIZE);
inflateSetDictionary(&index->strm, point->window, point->dict);
// Skip uncompressed bytes until offset reached, then satisfy request.
unsigned char input[CHUNK];

View File

@ -11,7 +11,8 @@ typedef struct point {
off_t out; // offset in uncompressed data
off_t in; // offset in compressed file of first full byte
int bits; // 0, or number of bits (1-7) from byte at in-1
unsigned char window[32768]; // preceding 32K of uncompressed data
unsigned dict; // number of bytes in window to use as a dictionary
unsigned char *window; // preceding 32K (or less) of uncompressed data
} point_t;
// Access point list.