infcodes.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* infcodes.c -- process literals and length/distance pairs
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "inftrees.h"
#include "infblock.h"
#include "infcodes.h"
#include "infutil.h"
#include "inffast.h"
/* simplify the use of the inflate_huft type with some defines */
typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
START, /* x: set up for LEN */
LENEXT, /* i: getting length extra (have base) */
DIST, /* i: get distance next */
DISTEXT, /* i: getting distance extra */
COPY, /* o: copying bytes in window, waiting for space */
LIT, /* o: got literal, waiting for output space */
WASH, /* o: got eob, possibly still output waiting */
END, /* x: got eob and all data flushed */
BADCODE} /* x: got error */
/* inflate codes private state */
struct inflate_codes_state {
/* mode */
/* mode dependent information */
union {
struct {
} code; /* if LEN or DIST, where in tree */
struct {
} copy; /* if EXT or COPY, where and how much */
} sub; /* submode */
/* mode independent information */
};
z_streamp z;
{
if ((c = (inflate_codes_statef *)
{
}
return c;
}
int inflate_codes(s, z, r)
z_streamp z;
int r;
{
uInt j; /* temporary storage */
inflate_huft *t; /* temporary pointer */
uInt e; /* extra bits or operation */
uLong b; /* bit buffer */
uInt k; /* bits in bit buffer */
Bytef *p; /* input data pointer */
uInt n; /* bytes available there */
Bytef *q; /* output window write pointer */
uInt m; /* bytes to end of window or read pointer */
Bytef *f; /* pointer to copy strings from */
/* process input and output based on current state */
/*CONSTCOND*/
while (1) switch (c->mode)
{ /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
case START: /* x: set up for LEN */
if (m >= 258 && n >= 10)
{
if (r != Z_OK)
{
break;
}
}
/*FALLTHRU*/
NEEDBITS(j)
if (e == 0) /* literal */
{
"inflate: literal '%c'\n" :
"inflate: literal 0x%02x\n", t->base));
break;
}
if (e & 16) /* length */
{
break;
}
if ((e & 64) == 0) /* next table */
{
break;
}
if (e & 32) /* end of block */
{
break;
}
r = Z_DATA_ERROR;
case LENEXT: /* i: getting length extra (have base) */
NEEDBITS(j)
DUMPBITS(j)
/*FALLTHRU*/
case DIST: /* i: get distance next */
NEEDBITS(j)
if (e & 16) /* distance */
{
break;
}
if ((e & 64) == 0) /* next table */
{
break;
}
z->msg = (char*)"invalid distance code";
r = Z_DATA_ERROR;
case DISTEXT: /* i: getting distance extra */
NEEDBITS(j)
DUMPBITS(j)
/*FALLTHRU*/
case COPY: /* o: copying bytes in window, waiting for space */
while (c->len)
{
OUTBYTE(*f++)
if (f == s->end)
f = s->window;
c->len--;
}
break;
case LIT: /* o: got literal, waiting for output space */
break;
case WASH: /* o: got eob, possibly more output */
if (k > 7) /* return unused byte, if any */
{
k -= 8;
n++;
p--; /* can always return one */
}
/*FALLTHRU*/
case END:
r = Z_STREAM_END;
case BADCODE: /* x: got error */
r = Z_DATA_ERROR;
default:
r = Z_STREAM_ERROR;
}
/*NOTREACHED*/
}
void inflate_codes_free(c, z)
z_streamp z;
{
ZFREE(z, c);
}