/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995 Mark Adler
+ * Copyright (C) 1995-2002 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 */
-#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;}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
/* Called with number of bytes left to write in window at least 258
(the maximum string length) and number of input bytes available
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 *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp 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 */
+ 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 in registers */
+ /* 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 */
+ 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 */
+ 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;
}
- 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);
+ 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));
- /* 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)
+ /* 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 (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);
+ /* do the copy */
+ m -= c;
+ r = q - d;
+ if (r < s->window) /* wrap if needed */
+ {
+ do {
+ r += s->end - s->window; /* force pointer in window */
+ } while (r < s->window); /* covers invalid distances */
+ e = s->end - r;
+ if (c > e)
+ {
+ c -= e; /* wrapped copy */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ else /* normal copy */
+ {
+ *q++ = *r++; c--;
+ *q++ = *r++; c--;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ }
+ else /* normal copy */
+ {
+ *q++ = *r++; c--;
+ *q++ = *r++; c--;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ break;
+ }
+ else if ((e & 64) == 0)
+ {
+ t += t->base;
+ e = (t += ((uInt)b & inflate_mask[e]))->exop;
+ }
+ else
+ {
+ z->msg = (char*)"invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
}
- else /* else offset after destination */
+ if ((e & 64) == 0)
{
- 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);
+ t += t->base;
+ if ((e = (t += ((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 */