From: Nathan Moinvaziri Date: Mon, 7 Mar 2022 03:20:29 +0000 (-0800) Subject: Revert "Reorganize inflate window layout" X-Git-Tag: 2.1.0-beta1~315 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6c4beb611d84a79dd7c9206104d8766fec774c45;p=thirdparty%2Fzlib-ng.git Revert "Reorganize inflate window layout" This reverts commit dc3b60841dbfa9cf37be3efb4568f055b4e15580. --- diff --git a/infback.c b/infback.c index 8c43a7ce..c3f0fccc 100644 --- a/infback.c +++ b/infback.c @@ -338,6 +338,17 @@ int32_t Z_EXPORT PREFIX(inflateBack)(PREFIX3(stream) *strm, in_func in, void *in state->mode = LEN; case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= INFLATE_FAST_MIN_HAVE && + left >= INFLATE_FAST_MIN_LEFT) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + zng_inflate_fast(strm, state->wsize); + LOAD(); + break; + } + /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; diff --git a/inffast.c b/inffast.c index 1dc1f789..36923317 100644 --- a/inffast.c +++ b/inffast.c @@ -61,16 +61,22 @@ static inline uint64_t load_64_bits(const unsigned char *in, unsigned bits) { requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ -void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm) { +void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm, unsigned long start) { + /* start: inflate()'s starting value for strm->avail_out */ struct inflate_state *state; z_const unsigned char *in; /* local strm->next_in */ const unsigned char *last; /* have enough input while in < last */ unsigned char *out; /* local strm->next_out */ + unsigned char *beg; /* inflate()'s initial strm->next_out */ unsigned char *end; /* while out < end, enough space available */ + unsigned char *safe; /* can use chunkcopy provided out < safe */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char *window; /* allocated sliding window, if wsize != 0 */ /* hold is a local copy of strm->hold. By default, hold satisfies the same invariants that strm->hold does, namely that (hold >> bits) == 0. This @@ -120,17 +126,24 @@ void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm) { /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ + unsigned char *from; /* where to copy match from */ + unsigned extra_safe; /* copy chunks safely in all cases */ /* copy state to local variables */ state = (struct inflate_state *)strm->state; in = strm->next_in; last = in + (strm->avail_in - (INFLATE_FAST_MIN_HAVE - 1)); - wsize = state->wsize; - out = state->window + wsize + state->wnext; - end = state->window + (wsize * 2) - (INFLATE_FAST_MIN_LEFT - 1); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - (INFLATE_FAST_MIN_LEFT - 1)); + safe = out + strm->avail_out; #ifdef INFLATE_STRICT dmax = state->dmax; #endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; @@ -138,6 +151,11 @@ void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm) { lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; + /* Detect if out and window point to the same memory allocation. In this instance it is + necessary to use safe chunk copy functions to prevent overwriting the window. If the + window is overwritten then future matches with far distances will fail to copy correctly. */ + extra_safe = (wsize != 0 && out >= window && out + INFLATE_FAST_MIN_LEFT <= window + wsize); + /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { @@ -146,13 +164,6 @@ void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm) { in += 6; bits += 48; } - if (out >= end) { - state->wnext = (uint32_t)(out - (state->window + wsize)); - window_output_flush(strm); - out = state->window + state->wsize + state->wnext; - if (strm->avail_out == 0) - break; - } here = lcode + (hold & lmask); dolen: DROPBITS(here->bits); @@ -199,18 +210,76 @@ void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm) { #endif DROPBITS(op); Tracevv((stderr, "inflate: distance %u\n", dist)); - - if (out - dist < ((state->window + state->wsize) - state->whave)) { - if (state->sane) { - SET_BAD("invalid distance too far back"); - break; + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + SET_BAD("invalid distance too far back"); + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif } - } - - if (len > dist || dist < state->chunksize) { - out = functable.chunkmemset(out, dist, len); + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + } else if (wnext >= op) { /* contiguous in window */ + from += wnext - op; + } else { /* wrap around window */ + op -= wnext; + from += wsize - op; + if (op < len) { /* some from end of window */ + len -= op; + out = chunkcopy_safe(out, from, op, safe); + from = window; /* more from start of window */ + op = wnext; + /* This (rare) case can create a situation where + the first chunkcopy below must be checked. + */ + } + } + if (op < len) { /* still need some from output */ + len -= op; + out = chunkcopy_safe(out, from, op, safe); + out = functable.chunkunroll(out, &dist, &len); + out = chunkcopy_safe(out, out - dist, len, safe); + } else { + out = chunkcopy_safe(out, from, len, safe); + } + } else if (extra_safe) { + /* Whole reference is in range of current output. */ + if (dist >= len || dist >= state->chunksize) + out = chunkcopy_safe(out, out - dist, len, safe); + else + out = functable.chunkmemset_safe(out, dist, len, (unsigned)((safe - out) + 1)); } else { - out = functable.chunkcopy(out, out - dist, len); + /* Whole reference is in range of current output. No range checks are + necessary because we start with room for at least 258 bytes of output, + so unroll and roundoff operations can write beyond `out+len` so long + as they stay within 258 bytes of `out`. + */ + if (dist >= len || dist >= state->chunksize) + out = functable.chunkcopy(out, out - dist, len); + else + out = functable.chunkmemset(out, dist, len); } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode + here->val + BITS(op); @@ -230,7 +299,7 @@ void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm) { SET_BAD("invalid literal/length code"); break; } - } while (in < last); + } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; @@ -240,10 +309,12 @@ void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm) { /* update state and return */ strm->next_in = in; + strm->next_out = out; strm->avail_in = (unsigned)(in < last ? (INFLATE_FAST_MIN_HAVE - 1) + (last - in) : (INFLATE_FAST_MIN_HAVE - 1) - (in - last)); + strm->avail_out = (unsigned)(out < end ? (INFLATE_FAST_MIN_LEFT - 1) + (end - out) + : (INFLATE_FAST_MIN_LEFT - 1) - (out - end)); - state->wnext = (uint32_t)(out - (state->window + state->wsize)); Assert(bits <= 32, "Remaining bits greater than 32"); state->hold = (uint32_t)hold; state->bits = bits; diff --git a/inffast.h b/inffast.h index cf9a3e2d..179a65da 100644 --- a/inffast.h +++ b/inffast.h @@ -10,7 +10,7 @@ subject to change. Applications should only use zlib.h. */ -void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm); +void Z_INTERNAL zng_inflate_fast(PREFIX3(stream) *strm, unsigned long start); #define INFLATE_FAST_MIN_HAVE 8 #define INFLATE_FAST_MIN_LEFT 258 diff --git a/inflate.c b/inflate.c index 419939b1..11f7b5b0 100644 --- a/inflate.c +++ b/inflate.c @@ -15,6 +15,7 @@ /* function prototypes */ static int inflateStateCheck(PREFIX3(stream) *strm); +static int updatewindow(PREFIX3(stream) *strm, const unsigned char *end, uint32_t copy); static uint32_t syncsearch(uint32_t *have, const unsigned char *buf, uint32_t len); static int inflateStateCheck(PREFIX3(stream) *strm) { @@ -60,6 +61,7 @@ int32_t Z_EXPORT PREFIX(inflateReset)(PREFIX3(stream) *strm) { if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; + state->wsize = 0; state->whave = 0; state->wnext = 0; return PREFIX(inflateResetKeep)(strm); @@ -92,7 +94,6 @@ int32_t Z_EXPORT PREFIX(inflateReset2)(PREFIX3(stream) *strm, int32_t windowBits if (state->window != NULL && state->wbits != (unsigned)windowBits) { ZFREE_WINDOW(strm, state->window); state->window = NULL; - state->wsize = 0; } /* update state and reset the rest of it */ @@ -125,14 +126,12 @@ int32_t Z_EXPORT PREFIX(inflateInit2_)(PREFIX3(stream) *strm, int32_t windowBits strm->state = (struct internal_state *)state; state->strm = strm; state->window = NULL; - state->wsize = 0; state->mode = HEAD; /* to pass state test in inflateReset2() */ state->chunksize = functable.chunksize(); ret = PREFIX(inflateReset2)(strm, windowBits); if (ret != Z_OK) { ZFREE_STATE(strm, state); strm->state = NULL; - return ret; } return ret; } @@ -177,7 +176,7 @@ int Z_INTERNAL inflate_ensure_window(struct inflate_state *state) { /* if it hasn't been done already, allocate space for the window */ if (state->window == NULL) { unsigned wsize = 1U << state->wbits; - state->window = (unsigned char *)ZALLOC_WINDOW(state->strm, (wsize * 2) + state->chunksize, sizeof(unsigned char)); + state->window = (unsigned char *)ZALLOC_WINDOW(state->strm, wsize + state->chunksize, sizeof(unsigned char)); if (state->window == NULL) return Z_MEM_ERROR; memset(state->window + wsize, 0, state->chunksize); @@ -193,6 +192,54 @@ int Z_INTERNAL inflate_ensure_window(struct inflate_state *state) { return Z_OK; } +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +static int32_t updatewindow(PREFIX3(stream) *strm, const uint8_t *end, uint32_t copy) { + struct inflate_state *state; + uint32_t dist; + + state = (struct inflate_state *)strm->state; + + if (inflate_ensure_window(state)) return 1; + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + memcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } else { + dist = state->wsize - state->wnext; + if (dist > copy) + dist = copy; + memcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + memcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } else { + state->wnext += dist; + if (state->wnext == state->wsize) + state->wnext = 0; + if (state->whave < state->wsize) + state->whave += dist; + } + } + return 0; +} + /* Private macros for inflate() Look in inflate_p.h for macros shared with inflateBack() @@ -298,6 +345,7 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { unsigned bits; /* bits in bit buffer */ uint32_t in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ + unsigned char *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ @@ -499,9 +547,7 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } - /* compute crc32 checksum if not in raw mode */ - if ((state->wrap & 4) && state->flags) - strm->adler = state->check = functable.crc32_fold_reset(&state->crc_fold); + strm->adler = state->check = CRC32_INITIAL_VALUE; state->mode = TYPE; break; #endif @@ -524,17 +570,6 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { goto inf_leave; case TYPEDO: - /* create window if it doesn't exist */ - if (state->window == NULL) { - RESTORE(); - ret = inflate_ensure_window(state); - if (ret != Z_OK) { - ZFREE_STATE(strm, state); - strm->state = NULL; - return ret; - } - LOAD(); - } /* determine and dispatch block type */ INFLATE_TYPEDO_HOOK(strm, flush); /* hook for IBM Z DFLTCC */ if (state->last) { @@ -591,24 +626,14 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { /* copy stored block from input to output */ copy = state->length; if (copy) { - unsigned char *end = state->window + (state->wsize * 2); - int64_t diff = end - put; - copy = MIN(copy, have); - if (copy > diff) { - if (left > 0) { - RESTORE(); - window_output_flush(strm); - LOAD(); - diff = end - put; - } - copy = MIN(copy, (uint32_t)diff); - } + copy = MIN(copy, left); if (copy == 0) goto inf_leave; memcpy(put, next, copy); have -= copy; next += copy; + left -= copy; put += copy; state->length -= copy; break; @@ -744,7 +769,7 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { /* use inflate_fast() if we have enough input and output */ if (have >= INFLATE_FAST_MIN_HAVE && left >= INFLATE_FAST_MIN_LEFT) { RESTORE(); - zng_inflate_fast(strm); + zng_inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; @@ -859,74 +884,70 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; - case MATCH: { + case MATCH: /* copy match from window to output */ if (left == 0) goto inf_leave; - - unsigned char *end = state->window + (state->wsize * 2); - int64_t buf_left = end - put; - copy = state->length; - RESTORE(); - if (copy > buf_left) { - if (strm->avail_out > 0) { - /* relies on RESTORE() above with no changes to those vars */ - window_output_flush(strm); - LOAD(); - buf_left = end - put; - } - copy = MIN(copy, (uint32_t)buf_left); - } - if (copy == 0) - goto inf_leave; - if (state->offset > state->wnext + state->whave) { - if (state->sane) { - SET_BAD("invalid distance too far back"); + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + SET_BAD("invalid distance too far back"); + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + copy = MIN(copy, state->length); + copy = MIN(copy, left); + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) + state->mode = LEN; break; +#endif } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } else { + from = state->window + (state->wnext - copy); + } + copy = MIN(copy, state->length); + copy = MIN(copy, left); + + put = chunkcopy_safe(put, from, copy, put + left); + } else { + copy = MIN(state->length, left); + + put = functable.chunkmemset_safe(put, state->offset, copy, left); } - unsigned char *next_out = state->window + state->wsize + state->wnext; - if (copy <= state->offset) { - chunkcopy_safe(next_out, next_out - state->offset, copy, put + buf_left); - } else { /* copy from output */ - functable.chunkmemset_safe(next_out, state->offset, copy, (uint32_t)buf_left); - } - state->wnext += copy; + left -= copy; state->length -= copy; - LOAD(); if (state->length == 0) state->mode = LEN; break; - } + case LIT: - if (put >= state->window + (state->wsize * 2)) { - RESTORE(); - window_output_flush(strm); - LOAD(); - } if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); + left--; state->mode = LEN; break; case CHECK: - RESTORE(); - window_output_flush(strm); - LOAD(); - if (strm->avail_out == 0 && state->wnext) - goto inf_leave; if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; - - if (INFLATE_NEED_CHECKSUM(strm) && strm->total_out) { - /* compute crc32 final value if not in raw mode */ - if ((state->wrap & 4) && state->flags) - strm->adler = state->check = functable.crc32_fold_final(&state->crc_fold); - } + if (INFLATE_NEED_CHECKSUM(strm) && (state->wrap & 4) && out) + strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if ((state->wrap & 4) && ( #ifdef GUNZIP @@ -976,21 +997,26 @@ int32_t Z_EXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int32_t flush) { /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer - error. + error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); - - if (strm->avail_out && state->wnext) - window_output_flush(strm); - + if (INFLATE_NEED_UPDATEWINDOW(strm) && + (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH)))) { + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; - + if (INFLATE_NEED_CHECKSUM(strm) && (state->wrap & 4) && out) + strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) @@ -1031,10 +1057,8 @@ int32_t Z_EXPORT PREFIX(inflateGetDictionary)(PREFIX3(stream) *strm, uint8_t *di int32_t Z_EXPORT PREFIX(inflateSetDictionary)(PREFIX3(stream) *strm, const uint8_t *dictionary, uint32_t dictLength) { struct inflate_state *state; - unsigned long dictid, dict_copy, hist_copy; - const unsigned char *dict_from, *hist_from; - unsigned char *dict_to, *hist_to; - int ret; + unsigned long dictid; + int32_t ret; /* check state */ if (inflateStateCheck(strm)) @@ -1049,33 +1073,14 @@ int32_t Z_EXPORT PREFIX(inflateSetDictionary)(PREFIX3(stream) *strm, const uint8 if (dictid != state->check) return Z_DATA_ERROR; } - ret = inflate_ensure_window(state); - if (ret != Z_OK) - return Z_MEM_ERROR; - Tracec(state->wnext != 0, (stderr, "Setting dictionary with unflushed output")); - - /* copy dictionary to window and amend if necessary */ - dict_from = dictionary; - dict_copy = dictLength; - if (dict_copy > state->wsize) { - dict_copy = state->wsize; - dict_from += (dictLength - dict_copy); + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; } - dict_to = state->window + state->wsize - dict_copy; - - hist_from = state->window + state->wsize - state->whave; - hist_copy = state->wsize - dict_copy; - if (hist_copy > state->whave) - hist_copy = state->whave; - hist_to = dict_to - hist_copy; - - if (hist_copy) - memcpy(hist_to, hist_from, hist_copy); - if (dict_copy) - memcpy(dict_to, dict_from, dict_copy); - - state->whave = hist_copy + dict_copy; state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; @@ -1215,7 +1220,7 @@ int32_t Z_EXPORT PREFIX(inflateCopy)(PREFIX3(stream) *dest, PREFIX3(stream) *sou window = NULL; if (state->window != NULL) { wsize = 1U << state->wbits; - window = (unsigned char *)ZALLOC_WINDOW(state->strm, (wsize * 2) + state->chunksize, sizeof(unsigned char)); + window = (unsigned char *)ZALLOC_WINDOW(source, wsize, sizeof(unsigned char)); if (window == NULL) { ZFREE_STATE(source, copy); return Z_MEM_ERROR; @@ -1233,7 +1238,7 @@ int32_t Z_EXPORT PREFIX(inflateCopy)(PREFIX3(stream) *dest, PREFIX3(stream) *sou copy->next = copy->codes + (state->next - state->codes); if (window != NULL) { wsize = 1U << state->wbits; - memcpy(window, state->window, (wsize * 2) + state->chunksize); + memcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state *)copy; diff --git a/inflate.h b/inflate.h index 3f57e784..67041348 100644 --- a/inflate.h +++ b/inflate.h @@ -11,8 +11,6 @@ #ifndef INFLATE_H_ #define INFLATE_H_ -#include "crc32_fold.h" - /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ @@ -103,8 +101,6 @@ struct inflate_state { uint32_t wnext; /* window write index */ unsigned char *window; /* allocated sliding window, if needed */ - struct crc32_fold_s ALIGNED_(16) crc_fold; - /* bit accumulator */ uint32_t hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ diff --git a/inflate_p.h b/inflate_p.h index fd3343a9..2735c581 100644 --- a/inflate_p.h +++ b/inflate_p.h @@ -5,9 +5,6 @@ #ifndef INFLATE_P_H #define INFLATE_P_H -#include "zbuild.h" -#include "functable.h" - /* Architecture-specific hooks. */ #ifdef S390_DFLTCC_INFLATE # include "arch/s390/dfltcc_inflate.h" @@ -35,11 +32,18 @@ # define INFLATE_SYNC_POINT_HOOK(strm) do {} while (0) #endif - /* * Macros shared by inflate() and inflateBack() */ +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? PREFIX(crc32)(check, buf, len) : functable.adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) functable.adler32(check, buf, len) +#endif + /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ @@ -62,7 +66,7 @@ /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ - put = state->window + state->wsize + state->wnext; \ + put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ @@ -73,7 +77,7 @@ /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ - state->wnext = (uint32_t)(put - (state->window + state->wsize)); \ + strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = (z_const unsigned char *)next; \ strm->avail_in = have; \ @@ -123,68 +127,6 @@ strm->msg = (char *)errmsg; \ } while (0) - -static inline void inf_crc_copy(PREFIX3(stream) *strm, unsigned char *const dst, - const unsigned char *const src, size_t len) { - struct inflate_state *const state = (struct inflate_state *const)strm->state; - - if (!INFLATE_NEED_CHECKSUM(strm)) - return; - - /* compute checksum if not in raw mode */ - if (state->wrap & 4) { - /* check flags to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP - if (state->flags) - functable.crc32_fold_copy(&state->crc_fold, dst, src, len); - else -#endif - { - memcpy(dst, src, len); - strm->adler = state->check = functable.adler32(state->check, dst, len); - } - } else { - memcpy(dst, src, len); - } -} - -static inline void window_output_flush(PREFIX3(stream) *strm) { - struct inflate_state *const state = (struct inflate_state *const)strm->state; - size_t write_offset, read_offset, copy_size; - uint32_t out_bytes; - - if (state->wnext > strm->avail_out) { - out_bytes = strm->avail_out; - copy_size = state->wnext - out_bytes; - } else { - out_bytes = state->wnext; - copy_size = 0; - } - - /* Copy from pending buffer to stream output */ - inf_crc_copy(strm, strm->next_out, state->window + state->wsize, out_bytes); - - strm->avail_out -= out_bytes; - strm->next_out += out_bytes; - - /* Discard bytes in sliding window */ - if (state->whave + out_bytes > state->wsize) { - write_offset = 0; - read_offset = out_bytes; - copy_size += state->wsize; - } else { - read_offset = state->wsize - state->whave; - write_offset = read_offset - out_bytes; - copy_size += state->whave + out_bytes; - } - - memmove(state->window + write_offset, state->window + read_offset, copy_size); - - state->wnext -= out_bytes; - state->whave += out_bytes; - state->whave = MIN(state->whave, state->wsize); -} - /* Behave like chunkcopy, but avoid writing beyond of legal output. */ static inline uint8_t* chunkcopy_safe(uint8_t *out, uint8_t *from, unsigned len, uint8_t *safe) { uint32_t safelen = (uint32_t)((safe - out) + 1); diff --git a/test/infcover.c b/test/infcover.c index 0c355aa9..974185d0 100644 --- a/test/infcover.c +++ b/test/infcover.c @@ -287,10 +287,6 @@ static void inf(char *hex, char *what, unsigned step, int win, unsigned len, int mem_setup(&strm); strm.avail_in = 0; strm.next_in = NULL; - - mem_limit(&strm, 1); - ret = PREFIX(inflateInit2)(&strm, win); assert(ret == Z_MEM_ERROR); - mem_limit(&strm, 0); ret = PREFIX(inflateInit2)(&strm, win); if (ret != Z_OK) { mem_done(&strm, what); @@ -323,6 +319,10 @@ static void inf(char *hex, char *what, unsigned step, int win, unsigned len, int if (ret == Z_NEED_DICT) { ret = PREFIX(inflateSetDictionary)(&strm, in, 1); assert(ret == Z_DATA_ERROR); + mem_limit(&strm, 1); + ret = PREFIX(inflateSetDictionary)(&strm, out, 0); + assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); ((struct inflate_state *)strm.state)->mode = DICT; ret = PREFIX(inflateSetDictionary)(&strm, out, 0); assert(ret == Z_OK); @@ -416,6 +416,10 @@ static void cover_wrap(void) { strm.next_in = (void *)"\x63"; strm.avail_out = 1; strm.next_out = (void *)&ret; + mem_limit(&strm, 1); + ret = PREFIX(inflate)(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR); + ret = PREFIX(inflate)(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); memset(dict, 0, 257); ret = PREFIX(inflateSetDictionary)(&strm, dict, 257); assert(ret == Z_OK);