mirror of https://github.com/madler/zlib.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
5.5 KiB
168 lines
5.5 KiB
/* inffast.c -- process literals and length/distance pairs fast |
|
* 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" |
|
|
|
struct inflate_codes_state {int dummy;}; /* for buggy compilers */ |
|
|
|
/* simplify the use of the inflate_huft type with some defines */ |
|
#define base more.Base |
|
#define next more.Next |
|
#define exop word.what.Exop |
|
#define bits word.what.Bits |
|
|
|
/* macros for bit input with no checking and for returning unused bytes */ |
|
#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}} |
|
#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;} |
|
|
|
/* Called with number of bytes left to write in window at least 258 |
|
(the maximum string length) and number of input bytes available |
|
at least ten. The ten bytes are six bytes for the longest length/ |
|
distance pair plus four bytes for overloading the bit buffer. */ |
|
|
|
int inflate_fast(bl, bd, tl, td, s, z) |
|
uInt bl, bd; |
|
inflate_huft *tl; |
|
inflate_huft *td; /* need separate declaration for Borland C++ */ |
|
inflate_blocks_statef *s; |
|
z_streamp z; |
|
{ |
|
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 */ |
|
uInt ml; /* mask for literal/length tree */ |
|
uInt md; /* mask for distance tree */ |
|
uInt c; /* bytes to copy */ |
|
uInt d; /* distance back to copy from */ |
|
Bytef *r; /* copy source pointer */ |
|
|
|
/* load input, output, bit values */ |
|
LOAD |
|
|
|
/* initialize masks */ |
|
ml = inflate_mask[bl]; |
|
md = inflate_mask[bd]; |
|
|
|
/* do until not enough input or output space for fast loop */ |
|
do { /* assume called with m >= 258 && n >= 10 */ |
|
/* get literal/length code */ |
|
GRABBITS(20) /* max bits for literal/length code */ |
|
if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) |
|
{ |
|
DUMPBITS(t->bits) |
|
Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? |
|
"inflate: * literal '%c'\n" : |
|
"inflate: * literal 0x%02x\n", t->base)); |
|
*q++ = (Byte)t->base; |
|
m--; |
|
continue; |
|
} |
|
do { |
|
DUMPBITS(t->bits) |
|
if (e & 16) |
|
{ |
|
/* get extra bits for length */ |
|
e &= 15; |
|
c = t->base + ((uInt)b & inflate_mask[e]); |
|
DUMPBITS(e) |
|
Tracevv((stderr, "inflate: * length %u\n", c)); |
|
|
|
/* decode distance base of block to copy */ |
|
GRABBITS(15); /* max bits for distance code */ |
|
e = (t = td + ((uInt)b & md))->exop; |
|
do { |
|
DUMPBITS(t->bits) |
|
if (e & 16) |
|
{ |
|
/* get extra bits to add to distance base */ |
|
e &= 15; |
|
GRABBITS(e) /* get extra bits (up to 13) */ |
|
d = t->base + ((uInt)b & inflate_mask[e]); |
|
DUMPBITS(e) |
|
Tracevv((stderr, "inflate: * distance %u\n", d)); |
|
|
|
/* do the copy */ |
|
m -= c; |
|
if ((uInt)(q - s->window) >= d) /* offset before dest */ |
|
{ /* just copy */ |
|
r = q - d; |
|
*q++ = *r++; c--; /* minimum count is three, */ |
|
*q++ = *r++; c--; /* so unroll loop a little */ |
|
} |
|
else /* else offset after destination */ |
|
{ |
|
e = d - (uInt)(q - s->window); /* bytes from offset to end */ |
|
r = s->end - e; /* pointer to offset */ |
|
if (c > e) /* if source crosses, */ |
|
{ |
|
c -= e; /* copy to end of window */ |
|
do { |
|
*q++ = *r++; |
|
} while (--e); |
|
r = s->window; /* copy rest from start of window */ |
|
} |
|
} |
|
do { /* copy all or what's left */ |
|
*q++ = *r++; |
|
} while (--c); |
|
break; |
|
} |
|
else if ((e & 64) == 0) |
|
e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; |
|
else |
|
{ |
|
z->msg = (char*)"invalid distance code"; |
|
UNGRAB |
|
UPDATE |
|
return Z_DATA_ERROR; |
|
} |
|
} while (1); |
|
break; |
|
} |
|
if ((e & 64) == 0) |
|
{ |
|
if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) |
|
{ |
|
DUMPBITS(t->bits) |
|
Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? |
|
"inflate: * literal '%c'\n" : |
|
"inflate: * literal 0x%02x\n", t->base)); |
|
*q++ = (Byte)t->base; |
|
m--; |
|
break; |
|
} |
|
} |
|
else if (e & 32) |
|
{ |
|
Tracevv((stderr, "inflate: * end of block\n")); |
|
UNGRAB |
|
UPDATE |
|
return Z_STREAM_END; |
|
} |
|
else |
|
{ |
|
z->msg = (char*)"invalid literal/length code"; |
|
UNGRAB |
|
UPDATE |
|
return Z_DATA_ERROR; |
|
} |
|
} while (1); |
|
} while (m >= 258 && n >= 10); |
|
|
|
/* not enough input or output--restore pointers and return */ |
|
UNGRAB |
|
UPDATE |
|
return Z_OK; |
|
}
|
|
|