274 lines
8.9 KiB
C
274 lines
8.9 KiB
C
|
|
|||
|
|
|||
|
#include "zutil.h"
|
|||
|
#include "inftrees.h"
|
|||
|
#include "inflate.h"
|
|||
|
#include "inffast.h"
|
|||
|
|
|||
|
#ifdef ASMINF
|
|||
|
# pragma message("Assembler code may have bugs -- use at your own risk")
|
|||
|
#else
|
|||
|
|
|||
|
|
|||
|
void ZLIB_INTERNAL inflate_fast(strm, start)
|
|||
|
z_streamp strm;
|
|||
|
unsigned start;
|
|||
|
{
|
|||
|
struct inflate_state FAR *state;
|
|||
|
z_const unsigned char FAR *in;
|
|||
|
z_const unsigned char FAR *last;
|
|||
|
unsigned char FAR *out;
|
|||
|
unsigned char FAR *beg;
|
|||
|
unsigned char FAR *end;
|
|||
|
#ifdef INFLATE_STRICT
|
|||
|
unsigned dmax;
|
|||
|
#endif
|
|||
|
unsigned wsize;
|
|||
|
unsigned whave;
|
|||
|
unsigned wnext;
|
|||
|
unsigned char FAR *window;
|
|||
|
unsigned long hold;
|
|||
|
unsigned bits;
|
|||
|
code const FAR *lcode;
|
|||
|
code const FAR *dcode;
|
|||
|
unsigned lmask;
|
|||
|
unsigned dmask;
|
|||
|
code here;
|
|||
|
unsigned op;
|
|||
|
|
|||
|
unsigned len;
|
|||
|
unsigned dist;
|
|||
|
unsigned char FAR *from;
|
|||
|
|
|||
|
|
|||
|
state = (struct inflate_state FAR *)strm->state;
|
|||
|
in = strm->next_in;
|
|||
|
last = in + (strm->avail_in - 5);
|
|||
|
out = strm->next_out;
|
|||
|
beg = out - (start - strm->avail_out);
|
|||
|
end = out + (strm->avail_out - 257);
|
|||
|
#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;
|
|||
|
dcode = state->distcode;
|
|||
|
lmask = (1U << state->lenbits) - 1;
|
|||
|
dmask = (1U << state->distbits) - 1;
|
|||
|
|
|||
|
|
|||
|
do {
|
|||
|
if (bits < 15) {
|
|||
|
hold += (unsigned long)(*in++) << bits;
|
|||
|
bits += 8;
|
|||
|
hold += (unsigned long)(*in++) << bits;
|
|||
|
bits += 8;
|
|||
|
}
|
|||
|
here = lcode[hold & lmask];
|
|||
|
dolen:
|
|||
|
op = (unsigned)(here.bits);
|
|||
|
hold >>= op;
|
|||
|
bits -= op;
|
|||
|
op = (unsigned)(here.op);
|
|||
|
if (op == 0) {
|
|||
|
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
|||
|
"inflate: literal '%c'\n" :
|
|||
|
"inflate: literal 0x%02x\n", here.val));
|
|||
|
*out++ = (unsigned char)(here.val);
|
|||
|
}
|
|||
|
else if (op & 16) {
|
|||
|
len = (unsigned)(here.val);
|
|||
|
op &= 15;
|
|||
|
if (op) {
|
|||
|
if (bits < op) {
|
|||
|
hold += (unsigned long)(*in++) << bits;
|
|||
|
bits += 8;
|
|||
|
}
|
|||
|
len += (unsigned)hold & ((1U << op) - 1);
|
|||
|
hold >>= op;
|
|||
|
bits -= op;
|
|||
|
}
|
|||
|
Tracevv((stderr, "inflate: length %u\n", len));
|
|||
|
if (bits < 15) {
|
|||
|
hold += (unsigned long)(*in++) << bits;
|
|||
|
bits += 8;
|
|||
|
hold += (unsigned long)(*in++) << bits;
|
|||
|
bits += 8;
|
|||
|
}
|
|||
|
here = dcode[hold & dmask];
|
|||
|
dodist:
|
|||
|
op = (unsigned)(here.bits);
|
|||
|
hold >>= op;
|
|||
|
bits -= op;
|
|||
|
op = (unsigned)(here.op);
|
|||
|
if (op & 16) {
|
|||
|
dist = (unsigned)(here.val);
|
|||
|
op &= 15;
|
|||
|
if (bits < op) {
|
|||
|
hold += (unsigned long)(*in++) << bits;
|
|||
|
bits += 8;
|
|||
|
if (bits < op) {
|
|||
|
hold += (unsigned long)(*in++) << bits;
|
|||
|
bits += 8;
|
|||
|
}
|
|||
|
}
|
|||
|
dist += (unsigned)hold & ((1U << op) - 1);
|
|||
|
#ifdef INFLATE_STRICT
|
|||
|
if (dist > dmax) {
|
|||
|
strm->msg = (char *)"invalid distance too far back";
|
|||
|
state->mode = BAD;
|
|||
|
break;
|
|||
|
}
|
|||
|
#endif
|
|||
|
hold >>= op;
|
|||
|
bits -= op;
|
|||
|
Tracevv((stderr, "inflate: distance %u\n", dist));
|
|||
|
op = (unsigned)(out - beg);
|
|||
|
if (dist > op) {
|
|||
|
op = dist - op;
|
|||
|
if (op > whave) {
|
|||
|
if (state->sane) {
|
|||
|
strm->msg =
|
|||
|
(char *)"invalid distance too far back";
|
|||
|
state->mode = BAD;
|
|||
|
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
|
|||
|
}
|
|||
|
from = window;
|
|||
|
if (wnext == 0) {
|
|||
|
from += wsize - op;
|
|||
|
if (op < len) {
|
|||
|
len -= op;
|
|||
|
do {
|
|||
|
*out++ = *from++;
|
|||
|
} while (--op);
|
|||
|
from = out - dist;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (wnext < op) {
|
|||
|
from += wsize + wnext - op;
|
|||
|
op -= wnext;
|
|||
|
if (op < len) {
|
|||
|
len -= op;
|
|||
|
do {
|
|||
|
*out++ = *from++;
|
|||
|
} while (--op);
|
|||
|
from = window;
|
|||
|
if (wnext < len) {
|
|||
|
op = wnext;
|
|||
|
len -= op;
|
|||
|
do {
|
|||
|
*out++ = *from++;
|
|||
|
} while (--op);
|
|||
|
from = out - dist;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
from += wnext - op;
|
|||
|
if (op < len) {
|
|||
|
len -= op;
|
|||
|
do {
|
|||
|
*out++ = *from++;
|
|||
|
} while (--op);
|
|||
|
from = out - dist;
|
|||
|
}
|
|||
|
}
|
|||
|
while (len > 2) {
|
|||
|
*out++ = *from++;
|
|||
|
*out++ = *from++;
|
|||
|
*out++ = *from++;
|
|||
|
len -= 3;
|
|||
|
}
|
|||
|
if (len) {
|
|||
|
*out++ = *from++;
|
|||
|
if (len > 1)
|
|||
|
*out++ = *from++;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
from = out - dist;
|
|||
|
do {
|
|||
|
*out++ = *from++;
|
|||
|
*out++ = *from++;
|
|||
|
*out++ = *from++;
|
|||
|
len -= 3;
|
|||
|
} while (len > 2);
|
|||
|
if (len) {
|
|||
|
*out++ = *from++;
|
|||
|
if (len > 1)
|
|||
|
*out++ = *from++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else if ((op & 64) == 0) {
|
|||
|
here = dcode[here.val + (hold & ((1U << op) - 1))];
|
|||
|
goto dodist;
|
|||
|
}
|
|||
|
else {
|
|||
|
strm->msg = (char *)"invalid distance code";
|
|||
|
state->mode = BAD;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else if ((op & 64) == 0) {
|
|||
|
here = lcode[here.val + (hold & ((1U << op) - 1))];
|
|||
|
goto dolen;
|
|||
|
}
|
|||
|
else if (op & 32) {
|
|||
|
Tracevv((stderr, "inflate: end of block\n"));
|
|||
|
state->mode = TYPE;
|
|||
|
break;
|
|||
|
}
|
|||
|
else {
|
|||
|
strm->msg = (char *)"invalid literal/length code";
|
|||
|
state->mode = BAD;
|
|||
|
break;
|
|||
|
}
|
|||
|
} while (in < last && out < end);
|
|||
|
|
|||
|
|
|||
|
len = bits >> 3;
|
|||
|
in -= len;
|
|||
|
bits -= len << 3;
|
|||
|
hold &= (1U << bits) - 1;
|
|||
|
|
|||
|
|
|||
|
strm->next_in = in;
|
|||
|
strm->next_out = out;
|
|||
|
strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
|
|||
|
strm->avail_out = (unsigned)(out < end ?
|
|||
|
257 + (end - out) : 257 - (out - end));
|
|||
|
state->hold = hold;
|
|||
|
state->bits = bits;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#endif
|