diff options
author | Mark Adler <madler@alumni.caltech.edu> | 2011-09-09 22:52:17 -0700 |
---|---|---|
committer | Mark Adler <madler@alumni.caltech.edu> | 2011-09-09 22:52:17 -0700 |
commit | 913afb9174bb474104049906c1382dec81826424 (patch) | |
tree | 46bb8ca746088f81382b4f33970b9d43c33d9ba3 /inffast.c | |
parent | bcf78a20978d76f64b7cd46d1a4d7a79a578c77b (diff) | |
download | zlib-913afb9174bb474104049906c1382dec81826424.tar.gz |
zlib 0.79v0.79
Diffstat (limited to 'inffast.c')
-rw-r--r-- | inffast.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/inffast.c b/inffast.c new file mode 100644 index 0000000..8c3e4ce --- /dev/null +++ b/inffast.c @@ -0,0 +1,148 @@ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infutil.h" +#include "inffast.h" + +/* 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 */ +#ifdef DEBUG +# undef NEXTBYTE +# define NEXTBYTE (n--?0:fprintf(stderr,"inffast underrun\n"),*p++) +#endif +#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, *td; +struct inflate_blocks_state *s; +z_stream *z; +{ + inflate_huft *t; /* temporary pointer */ + int e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *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 */ + Byte *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks in registers */ + 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) + do { + if (e == -128) + { + z->msg = "invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + DUMPBITS(t->bits) + e = -e; + if (e & 64) /* end of block */ + { + UNGRAB + UPDATE + return Z_STREAM_END; + } + } while ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) < 0); + DUMPBITS(t->bits) + + /* process literal or length (end of block already trapped) */ + if (e & 16) /* then it's a literal */ + { + *q++ = (Byte)t->base; + m--; + } + else /* it's a length */ + { + /* get length of block to copy (already have extra bits) */ + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + if ((e = (t = td + ((uInt)b & md))->exop) < 0) + do { + if (e == -128) + { + z->msg = "invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + DUMPBITS(t->bits) + e = -e; + } while ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) < 0); + DUMPBITS(t->bits) + + /* get extra bits to add to distance base */ + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + + /* do the copy */ + m -= c; + if (q - s->window >= d) /* if offset before destination, */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + do { + *q++ = *r++; + } while (--c); + } + else /* else offset after destination */ + { + e = d - (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); + } + } + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} |