#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"
local
void
fixedtables OF((
struct
inflate_state FAR *state));
int
ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
z_streamp strm;
int
windowBits;
unsigned
char
FAR *window;
const
char
*version;
int
stream_size;
{
struct
inflate_state FAR *state;
if
(version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
stream_size != (
int
)(
sizeof
(z_stream)))
return
Z_VERSION_ERROR;
if
(strm == Z_NULL || window == Z_NULL ||
windowBits < 8 || windowBits > 15)
return
Z_STREAM_ERROR;
strm->msg = Z_NULL;
if
(strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
return
Z_STREAM_ERROR;
#else
strm->zalloc = zcalloc;
strm->opaque = (voidpf)0;
#endif
}
if
(strm->zfree == (free_func)0)
#ifdef Z_SOLO
return
Z_STREAM_ERROR;
#else
strm->zfree = zcfree;
#endif
state = (
struct
inflate_state FAR *)ZALLOC(strm, 1,
sizeof
(
struct
inflate_state));
if
(state == Z_NULL)
return
Z_MEM_ERROR;
Tracev((stderr,
"inflate: allocated\n"
));
strm->state = (
struct
internal_state FAR *)state;
state->dmax = 32768U;
state->wbits = windowBits;
state->wsize = 1U << windowBits;
state->window = window;
state->wnext = 0;
state->whave = 0;
return
Z_OK;
}
local
void
fixedtables(state)
struct
inflate_state FAR *state;
{
#ifdef BUILDFIXED
static
int
virgin = 1;
static
code *lenfix, *distfix;
static
code fixed[544];
if
(virgin) {
unsigned sym, bits;
static
code *next;
sym = 0;
while
(sym < 144) state->lens[sym++] = 8;
while
(sym < 256) state->lens[sym++] = 9;
while
(sym < 280) state->lens[sym++] = 7;
while
(sym < 288) state->lens[sym++] = 8;
next = fixed;
lenfix = next;
bits = 9;
inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
sym = 0;
while
(sym < 32) state->lens[sym++] = 5;
distfix = next;
bits = 5;
inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
virgin = 0;
}
#else /* !BUILDFIXED */
# include "inffixed.h"
#endif /* BUILDFIXED */
state->lencode = lenfix;
state->lenbits = 9;
state->distcode = distfix;
state->distbits = 5;
}
#define LOAD() \
do
{ \
put = strm->next_out; \
left = strm->avail_out; \
next = strm->next_in; \
have = strm->avail_in; \
hold = state->hold; \
bits = state->bits; \
}
while
(0)
#define RESTORE() \
do
{ \
strm->next_out = put; \
strm->avail_out = left; \
strm->next_in = next; \
strm->avail_in = have; \
state->hold = hold; \
state->bits = bits; \
}
while
(0)
#define INITBITS() \
do
{ \
hold = 0; \
bits = 0; \
}
while
(0)
#define PULL() \
do
{ \
if
(have == 0) { \
have = in(in_desc, &next); \
if
(have == 0) { \
next = Z_NULL; \
ret = Z_BUF_ERROR; \
goto
inf_leave; \
} \
} \
}
while
(0)
#define PULLBYTE() \
do
{ \
PULL(); \
have--; \
hold += (unsigned
long
)(*next++) << bits; \
bits += 8; \
}
while
(0)
#define NEEDBITS(n) \
do
{ \
while
(bits < (unsigned)(n)) \
PULLBYTE(); \
}
while
(0)
#define BITS(n) \
((unsigned)hold & ((1U << (n)) - 1))
#define DROPBITS(n) \
do
{ \
hold >>= (n); \
bits -= (unsigned)(n); \
}
while
(0)
#define BYTEBITS() \
do
{ \
hold >>= bits & 7; \
bits -= bits & 7; \
}
while
(0)
#define ROOM() \
do
{ \
if
(left == 0) { \
put = state->window; \
left = state->wsize; \
state->whave = left; \
if
(out(out_desc, put, left)) { \
ret = Z_BUF_ERROR; \
goto
inf_leave; \
} \
} \
}
while
(0)
int
ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
z_streamp strm;
in_func in;
void
FAR *in_desc;
out_func out;
void
FAR *out_desc;
{
struct
inflate_state FAR *state;
z_const unsigned
char
FAR *next;
unsigned
char
FAR *put;
unsigned have, left;
unsigned
long
hold;
unsigned bits;
unsigned copy;
unsigned
char
FAR *from;
code here;
code last;
unsigned len;
int
ret;
static
const
unsigned
short
order[19] =
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
if
(strm == Z_NULL || strm->state == Z_NULL)
return
Z_STREAM_ERROR;
state = (
struct
inflate_state FAR *)strm->state;
strm->msg = Z_NULL;
state->mode = TYPE;
state->last = 0;
state->whave = 0;
next = strm->next_in;
have = next != Z_NULL ? strm->avail_in : 0;
hold = 0;
bits = 0;
put = state->window;
left = state->wsize;
for
(;;)
switch
(state->mode) {
case
TYPE:
if
(state->last) {
BYTEBITS();
state->mode = DONE;
break
;
}
NEEDBITS(3);
state->last = BITS(1);
DROPBITS(1);
switch
(BITS(2)) {
case
0:
Tracev((stderr,
"inflate: stored block%s\n"
,
state->last ?
" (last)"
:
""
));
state->mode = STORED;
break
;
case
1:
fixedtables(state);
Tracev((stderr,
"inflate: fixed codes block%s\n"
,
state->last ?
" (last)"
:
""
));
state->mode = LEN;
break
;
case
2:
Tracev((stderr,
"inflate: dynamic codes block%s\n"
,
state->last ?
" (last)"
:
""
));
state->mode = TABLE;
break
;
case
3:
strm->msg = (
char
*)
"invalid block type"
;
state->mode = BAD;
}
DROPBITS(2);
break
;
case
STORED:
BYTEBITS();
NEEDBITS(32);
if
((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
strm->msg = (
char
*)
"invalid stored block lengths"
;
state->mode = BAD;
break
;
}
state->length = (unsigned)hold & 0xffff;
Tracev((stderr,
"inflate: stored length %u\n"
,
state->length));
INITBITS();
while
(state->length != 0) {
copy = state->length;
PULL();
ROOM();
if
(copy > have) copy = have;
if
(copy > left) copy = left;
zmemcpy(put, next, copy);
have -= copy;
next += copy;
left -= copy;
put += copy;
state->length -= copy;
}
Tracev((stderr,
"inflate: stored end\n"
));
state->mode = TYPE;
break
;
case
TABLE:
NEEDBITS(14);
state->nlen = BITS(5) + 257;
DROPBITS(5);
state->ndist = BITS(5) + 1;
DROPBITS(5);
state->ncode = BITS(4) + 4;
DROPBITS(4);
#ifndef PKZIP_BUG_WORKAROUND
if
(state->nlen > 286 || state->ndist > 30) {
strm->msg = (
char
*)
"too many length or distance symbols"
;
state->mode = BAD;
break
;
}
#endif
Tracev((stderr,
"inflate: table sizes ok\n"
));
state->have = 0;
while
(state->have < state->ncode) {
NEEDBITS(3);
state->lens[order[state->have++]] = (unsigned
short
)BITS(3);
DROPBITS(3);
}
while
(state->have < 19)
state->lens[order[state->have++]] = 0;
state->next = state->codes;
state->lencode = (code
const
FAR *)(state->next);
state->lenbits = 7;
ret = inflate_table(CODES, state->lens, 19, &(state->next),
&(state->lenbits), state->work);
if
(ret) {
strm->msg = (
char
*)
"invalid code lengths set"
;
state->mode = BAD;
break
;
}
Tracev((stderr,
"inflate: code lengths ok\n"
));
state->have = 0;
while
(state->have < state->nlen + state->ndist) {
for
(;;) {
here = state->lencode[BITS(state->lenbits)];
if
((unsigned)(here.bits) <= bits)
break
;
PULLBYTE();
}
if
(here.val < 16) {
DROPBITS(here.bits);
state->lens[state->have++] = here.val;
}
else
{
if
(here.val == 16) {
NEEDBITS(here.bits + 2);
DROPBITS(here.bits);
if
(state->have == 0) {
strm->msg = (
char
*)
"invalid bit length repeat"
;
state->mode = BAD;
break
;
}
len = (unsigned)(state->lens[state->have - 1]);
copy = 3 + BITS(2);
DROPBITS(2);
}
else
if
(here.val == 17) {
NEEDBITS(here.bits + 3);
DROPBITS(here.bits);
len = 0;
copy = 3 + BITS(3);
DROPBITS(3);
}
else
{
NEEDBITS(here.bits + 7);
DROPBITS(here.bits);
len = 0;
copy = 11 + BITS(7);
DROPBITS(7);
}
if
(state->have + copy > state->nlen + state->ndist) {
strm->msg = (
char
*)
"invalid bit length repeat"
;
state->mode = BAD;
break
;
}
while
(copy--)
state->lens[state->have++] = (unsigned
short
)len;
}
}
if
(state->mode == BAD)
break
;
if
(state->lens[256] == 0) {
strm->msg = (
char
*)
"invalid code -- missing end-of-block"
;
state->mode = BAD;
break
;
}
state->next = state->codes;
state->lencode = (code
const
FAR *)(state->next);
state->lenbits = 9;
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
&(state->lenbits), state->work);
if
(ret) {
strm->msg = (
char
*)
"invalid literal/lengths set"
;
state->mode = BAD;
break
;
}
state->distcode = (code
const
FAR *)(state->next);
state->distbits = 6;
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
&(state->next), &(state->distbits), state->work);
if
(ret) {
strm->msg = (
char
*)
"invalid distances set"
;
state->mode = BAD;
break
;
}
Tracev((stderr,
"inflate: codes ok\n"
));
state->mode = LEN;
case
LEN:
if
(have >= 6 && left >= 258) {
RESTORE();
if
(state->whave < state->wsize)
state->whave = state->wsize - left;
inflate_fast(strm, state->wsize);
LOAD();
break
;
}
for
(;;) {
here = state->lencode[BITS(state->lenbits)];
if
((unsigned)(here.bits) <= bits)
break
;
PULLBYTE();
}
if
(here.op && (here.op & 0xf0) == 0) {
last = here;
for
(;;) {
here = state->lencode[last.val +
(BITS(last.bits + last.op) >> last.bits)];
if
((unsigned)(last.bits + here.bits) <= bits)
break
;
PULLBYTE();
}
DROPBITS(last.bits);
}
DROPBITS(here.bits);
state->length = (unsigned)here.val;
if
(here.op == 0) {
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
"inflate: literal '%c'\n"
:
"inflate: literal 0x%02x\n"
, here.val));
ROOM();
*put++ = (unsigned
char
)(state->length);
left--;
state->mode = LEN;
break
;
}
if
(here.op & 32) {
Tracevv((stderr,
"inflate: end of block\n"
));
state->mode = TYPE;
break
;
}
if
(here.op & 64) {
strm->msg = (
char
*)
"invalid literal/length code"
;
state->mode = BAD;
break
;
}
state->extra = (unsigned)(here.op) & 15;
if
(state->extra != 0) {
NEEDBITS(state->extra);
state->length += BITS(state->extra);
DROPBITS(state->extra);
}
Tracevv((stderr,
"inflate: length %u\n"
, state->length));
for
(;;) {
here = state->distcode[BITS(state->distbits)];
if
((unsigned)(here.bits) <= bits)
break
;
PULLBYTE();
}
if
((here.op & 0xf0) == 0) {
last = here;
for
(;;) {
here = state->distcode[last.val +
(BITS(last.bits + last.op) >> last.bits)];
if
((unsigned)(last.bits + here.bits) <= bits)
break
;
PULLBYTE();
}
DROPBITS(last.bits);
}
DROPBITS(here.bits);
if
(here.op & 64) {
strm->msg = (
char
*)
"invalid distance code"
;
state->mode = BAD;
break
;
}
state->offset = (unsigned)here.val;
state->extra = (unsigned)(here.op) & 15;
if
(state->extra != 0) {
NEEDBITS(state->extra);
state->offset += BITS(state->extra);
DROPBITS(state->extra);
}
if
(state->offset > state->wsize - (state->whave < state->wsize ?
left : 0)) {
strm->msg = (
char
*)
"invalid distance too far back"
;
state->mode = BAD;
break
;
}
Tracevv((stderr,
"inflate: distance %u\n"
, state->offset));
do
{
ROOM();
copy = state->wsize - state->offset;
if
(copy < left) {
from = put + copy;
copy = left - copy;
}
else
{
from = put - state->offset;
copy = left;
}
if
(copy > state->length) copy = state->length;
state->length -= copy;
left -= copy;
do
{
*put++ = *from++;
}
while
(--copy);
}
while
(state->length != 0);
break
;
case
DONE:
ret = Z_STREAM_END;
if
(left < state->wsize) {
if
(out(out_desc, state->window, state->wsize - left))
ret = Z_BUF_ERROR;
}
goto
inf_leave;
case
BAD:
ret = Z_DATA_ERROR;
goto
inf_leave;
default
:
ret = Z_STREAM_ERROR;
goto
inf_leave;
}
inf_leave:
strm->next_in = next;
strm->avail_in = have;
return
ret;
}
int
ZEXPORT inflateBackEnd(strm)
z_streamp strm;
{
if
(strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
return
Z_STREAM_ERROR;
ZFREE(strm, strm->state);
strm->state = Z_NULL;
Tracev((stderr,
"inflate: end\n"
));
return
Z_OK;
}