#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"
#ifndef ASMINF
void ZLIB_INTERNAL inflate_fast(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 const *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 - (INFLATE_FAST_MIN_INPUT - 1));
out = strm->next_out;
beg = out - (start - strm->avail_out);
end = out + (strm->avail_out - (INFLATE_FAST_MIN_OUTPUT - 1));
#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 = (z_const 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 =
(z_const 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 = (z_const 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 = (z_const 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 ?
(INFLATE_FAST_MIN_INPUT - 1) + (last - in) :
(INFLATE_FAST_MIN_INPUT - 1) - (in - last));
strm->avail_out = (unsigned)(out < end ?
(INFLATE_FAST_MIN_OUTPUT - 1) + (end - out) :
(INFLATE_FAST_MIN_OUTPUT - 1) - (out - end));
state->hold = hold;
state->bits = bits;
return;
}
#endif