inffast.c (muscle7.61) | : | inffast.c (muscle7.62) | ||
---|---|---|---|---|
/* inffast.c -- fast decoding | /* inffast.c -- fast decoding | |||
* Copyright (C) 1995-2008, 2010, 2013 Mark Adler | * Copyright (C) 1995-2017 Mark Adler | |||
* For conditions of distribution and use, see copyright notice in zlib.h | * For conditions of distribution and use, see copyright notice in zlib.h | |||
*/ | */ | |||
#include "zutil.h" | #include "zutil.h" | |||
#include "inftrees.h" | #include "inftrees.h" | |||
#include "inflate.h" | #include "inflate.h" | |||
#include "inffast.h" | #include "inffast.h" | |||
#ifndef ASMINF | #ifdef ASMINF | |||
# pragma message("Assembler code may have bugs -- use at your own risk") | ||||
/* Allow machine dependent optimization for post-increment or pre-increment. | ||||
Based on testing to date, | ||||
Pre-increment preferred for: | ||||
- PowerPC G3 (Adler) | ||||
- MIPS R5000 (Randers-Pehrson) | ||||
Post-increment preferred for: | ||||
- none | ||||
No measurable difference: | ||||
- Pentium III (Anderson) | ||||
- M68060 (Nikl) | ||||
*/ | ||||
#ifdef POSTINC | ||||
# define OFF 0 | ||||
# define PUP(a) *(a)++ | ||||
#else | #else | |||
# define OFF 1 | ||||
# define PUP(a) *++(a) | ||||
#endif | ||||
/* | /* | |||
Decode literal, length, and distance codes and write out the resulting | Decode literal, length, and distance codes and write out the resulting | |||
literal and match bytes until either not enough input or output is | literal and match bytes until either not enough input or output is | |||
available, an end-of-block is encountered, or a data error is encountered. | available, an end-of-block is encountered, or a data error is encountered. | |||
When large enough input and output buffers are supplied to inflate(), for | When large enough input and output buffers are supplied to inflate(), for | |||
example, a 16K input buffer and a 64K output buffer, more than 95% of the | example, a 16K input buffer and a 64K output buffer, more than 95% of the | |||
inflate execution time is spent in this routine. | inflate execution time is spent in this routine. | |||
Entry assumptions: | Entry assumptions: | |||
skipping to change at line 99 | skipping to change at line 82 | |||
unsigned dmask; /* mask for first level of distance codes */ | unsigned dmask; /* mask for first level of distance codes */ | |||
code here; /* retrieved table entry */ | code here; /* retrieved table entry */ | |||
unsigned op; /* code bits, operation, extra bits, or */ | unsigned op; /* code bits, operation, extra bits, or */ | |||
/* window position, window bytes to copy */ | /* window position, window bytes to copy */ | |||
unsigned len; /* match length, unused bytes */ | unsigned len; /* match length, unused bytes */ | |||
unsigned dist; /* match distance */ | unsigned dist; /* match distance */ | |||
unsigned char FAR *from; /* where to copy match from */ | unsigned char FAR *from; /* where to copy match from */ | |||
/* copy state to local variables */ | /* copy state to local variables */ | |||
state = (struct inflate_state FAR *)strm->state; | state = (struct inflate_state FAR *)strm->state; | |||
in = strm->next_in - OFF; | in = strm->next_in; | |||
last = in + (strm->avail_in - 5); | last = in + (strm->avail_in - 5); | |||
out = strm->next_out - OFF; | out = strm->next_out; | |||
beg = out - (start - strm->avail_out); | beg = out - (start - strm->avail_out); | |||
end = out + (strm->avail_out - 257); | end = out + (strm->avail_out - 257); | |||
#ifdef INFLATE_STRICT | #ifdef INFLATE_STRICT | |||
dmax = state->dmax; | dmax = state->dmax; | |||
#endif | #endif | |||
wsize = state->wsize; | wsize = state->wsize; | |||
whave = state->whave; | whave = state->whave; | |||
wnext = state->wnext; | wnext = state->wnext; | |||
window = state->window; | window = state->window; | |||
hold = state->hold; | hold = state->hold; | |||
bits = state->bits; | bits = state->bits; | |||
lcode = state->lencode; | lcode = state->lencode; | |||
dcode = state->distcode; | dcode = state->distcode; | |||
lmask = (1U << state->lenbits) - 1; | lmask = (1U << state->lenbits) - 1; | |||
dmask = (1U << state->distbits) - 1; | dmask = (1U << state->distbits) - 1; | |||
/* decode literals and length/distances until end-of-block or not enough | /* decode literals and length/distances until end-of-block or not enough | |||
input data or output space */ | input data or output space */ | |||
do { | do { | |||
if (bits < 15) { | if (bits < 15) { | |||
hold += (unsigned long)(PUP(in)) << bits; | hold += (unsigned long)(*in++) << bits; | |||
bits += 8; | bits += 8; | |||
hold += (unsigned long)(PUP(in)) << bits; | hold += (unsigned long)(*in++) << bits; | |||
bits += 8; | bits += 8; | |||
} | } | |||
here = lcode[hold & lmask]; | here = lcode[hold & lmask]; | |||
dolen: | dolen: | |||
op = (unsigned)(here.bits); | op = (unsigned)(here.bits); | |||
hold >>= op; | hold >>= op; | |||
bits -= op; | bits -= op; | |||
op = (unsigned)(here.op); | op = (unsigned)(here.op); | |||
if (op == 0) { /* literal */ | if (op == 0) { /* literal */ | |||
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? | Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? | |||
"inflate: literal '%c'\n" : | "inflate: literal '%c'\n" : | |||
"inflate: literal 0x%02x\n", here.val)); | "inflate: literal 0x%02x\n", here.val)); | |||
PUP(out) = (unsigned char)(here.val); | *out++ = (unsigned char)(here.val); | |||
} | } | |||
else if (op & 16) { /* length base */ | else if (op & 16) { /* length base */ | |||
len = (unsigned)(here.val); | len = (unsigned)(here.val); | |||
op &= 15; /* number of extra bits */ | op &= 15; /* number of extra bits */ | |||
if (op) { | if (op) { | |||
if (bits < op) { | if (bits < op) { | |||
hold += (unsigned long)(PUP(in)) << bits; | hold += (unsigned long)(*in++) << bits; | |||
bits += 8; | bits += 8; | |||
} | } | |||
len += (unsigned)hold & ((1U << op) - 1); | len += (unsigned)hold & ((1U << op) - 1); | |||
hold >>= op; | hold >>= op; | |||
bits -= op; | bits -= op; | |||
} | } | |||
Tracevv((stderr, "inflate: length %u\n", len)); | Tracevv((stderr, "inflate: length %u\n", len)); | |||
if (bits < 15) { | if (bits < 15) { | |||
hold += (unsigned long)(PUP(in)) << bits; | hold += (unsigned long)(*in++) << bits; | |||
bits += 8; | bits += 8; | |||
hold += (unsigned long)(PUP(in)) << bits; | hold += (unsigned long)(*in++) << bits; | |||
bits += 8; | bits += 8; | |||
} | } | |||
here = dcode[hold & dmask]; | here = dcode[hold & dmask]; | |||
dodist: | dodist: | |||
op = (unsigned)(here.bits); | op = (unsigned)(here.bits); | |||
hold >>= op; | hold >>= op; | |||
bits -= op; | bits -= op; | |||
op = (unsigned)(here.op); | op = (unsigned)(here.op); | |||
if (op & 16) { /* distance base */ | if (op & 16) { /* distance base */ | |||
dist = (unsigned)(here.val); | dist = (unsigned)(here.val); | |||
op &= 15; /* number of extra bits */ | op &= 15; /* number of extra bits */ | |||
if (bits < op) { | if (bits < op) { | |||
hold += (unsigned long)(PUP(in)) << bits; | hold += (unsigned long)(*in++) << bits; | |||
bits += 8; | bits += 8; | |||
if (bits < op) { | if (bits < op) { | |||
hold += (unsigned long)(PUP(in)) << bits; | hold += (unsigned long)(*in++) << bits; | |||
bits += 8; | bits += 8; | |||
} | } | |||
} | } | |||
dist += (unsigned)hold & ((1U << op) - 1); | dist += (unsigned)hold & ((1U << op) - 1); | |||
#ifdef INFLATE_STRICT | #ifdef INFLATE_STRICT | |||
if (dist > dmax) { | if (dist > dmax) { | |||
strm->msg = (char *)"invalid distance too far back"; | strm->msg = (char *)"invalid distance too far back"; | |||
state->mode = BAD; | state->mode = BAD; | |||
break; | break; | |||
} | } | |||
skipping to change at line 199 | skipping to change at line 182 | |||
if (op > whave) { | if (op > whave) { | |||
if (state->sane) { | if (state->sane) { | |||
strm->msg = | strm->msg = | |||
(char *)"invalid distance too far back"; | (char *)"invalid distance too far back"; | |||
state->mode = BAD; | state->mode = BAD; | |||
break; | break; | |||
} | } | |||
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR | #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR | |||
if (len <= op - whave) { | if (len <= op - whave) { | |||
do { | do { | |||
PUP(out) = 0; | *out++ = 0; | |||
} while (--len); | } while (--len); | |||
continue; | continue; | |||
} | } | |||
len -= op - whave; | len -= op - whave; | |||
do { | do { | |||
PUP(out) = 0; | *out++ = 0; | |||
} while (--op > whave); | } while (--op > whave); | |||
if (op == 0) { | if (op == 0) { | |||
from = out - dist; | from = out - dist; | |||
do { | do { | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
} while (--len); | } while (--len); | |||
continue; | continue; | |||
} | } | |||
#endif | #endif | |||
} | } | |||
from = window - OFF; | from = window; | |||
if (wnext == 0) { /* very common case */ | if (wnext == 0) { /* very common case */ | |||
from += wsize - op; | from += wsize - op; | |||
if (op < len) { /* some from window */ | if (op < len) { /* some from window */ | |||
len -= op; | len -= op; | |||
do { | do { | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
} while (--op); | } while (--op); | |||
from = out - dist; /* rest from output */ | from = out - dist; /* rest from output */ | |||
} | } | |||
} | } | |||
else if (wnext < op) { /* wrap around window */ | else if (wnext < op) { /* wrap around window */ | |||
from += wsize + wnext - op; | from += wsize + wnext - op; | |||
op -= wnext; | op -= wnext; | |||
if (op < len) { /* some from end of window */ | if (op < len) { /* some from end of window */ | |||
len -= op; | len -= op; | |||
do { | do { | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
} while (--op); | } while (--op); | |||
from = window - OFF; | from = window; | |||
if (wnext < len) { /* some from start of window */ | if (wnext < len) { /* some from start of window */ | |||
op = wnext; | op = wnext; | |||
len -= op; | len -= op; | |||
do { | do { | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
} while (--op); | } while (--op); | |||
from = out - dist; /* rest from output */ | from = out - dist; /* rest from output */ | |||
} | } | |||
} | } | |||
} | } | |||
else { /* contiguous in window */ | else { /* contiguous in window */ | |||
from += wnext - op; | from += wnext - op; | |||
if (op < len) { /* some from window */ | if (op < len) { /* some from window */ | |||
len -= op; | len -= op; | |||
do { | do { | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
} while (--op); | } while (--op); | |||
from = out - dist; /* rest from output */ | from = out - dist; /* rest from output */ | |||
} | } | |||
} | } | |||
while (len > 2) { | while (len > 2) { | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
len -= 3; | len -= 3; | |||
} | } | |||
if (len) { | if (len) { | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
if (len > 1) | if (len > 1) | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
} | } | |||
} | } | |||
else { | else { | |||
from = out - dist; /* copy direct from output */ | from = out - dist; /* copy direct from output */ | |||
do { /* minimum length is three */ | do { /* minimum length is three */ | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
len -= 3; | len -= 3; | |||
} while (len > 2); | } while (len > 2); | |||
if (len) { | if (len) { | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
if (len > 1) | if (len > 1) | |||
PUP(out) = PUP(from); | *out++ = *from++; | |||
} | } | |||
} | } | |||
} | } | |||
else if ((op & 64) == 0) { /* 2nd level distance code */ | else if ((op & 64) == 0) { /* 2nd level distance code */ | |||
here = dcode[here.val + (hold & ((1U << op) - 1))]; | here = dcode[here.val + (hold & ((1U << op) - 1))]; | |||
goto dodist; | goto dodist; | |||
} | } | |||
else { | else { | |||
strm->msg = (char *)"invalid distance code"; | strm->msg = (char *)"invalid distance code"; | |||
state->mode = BAD; | state->mode = BAD; | |||
skipping to change at line 316 | skipping to change at line 299 | |||
} | } | |||
} while (in < last && out < end); | } while (in < last && out < end); | |||
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */ | /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ | |||
len = bits >> 3; | len = bits >> 3; | |||
in -= len; | in -= len; | |||
bits -= len << 3; | bits -= len << 3; | |||
hold &= (1U << bits) - 1; | hold &= (1U << bits) - 1; | |||
/* update state and return */ | /* update state and return */ | |||
strm->next_in = in + OFF; | strm->next_in = in; | |||
strm->next_out = out + OFF; | strm->next_out = out; | |||
strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); | strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); | |||
strm->avail_out = (unsigned)(out < end ? | strm->avail_out = (unsigned)(out < end ? | |||
257 + (end - out) : 257 - (out - end)); | 257 + (end - out) : 257 - (out - end)); | |||
state->hold = hold; | state->hold = hold; | |||
state->bits = bits; | state->bits = bits; | |||
return; | return; | |||
} | } | |||
/* | /* | |||
inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): | inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): | |||
End of changes. 29 change blocks. | ||||
51 lines changed or deleted | 34 lines changed or added |