Annotation of sys/lib/libz/inffast.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: inffast.c,v 1.11 2005/07/20 15:56:46 millert Exp $ */
2: /* inffast.c -- fast decoding
3: * Copyright (C) 1995-2004 Mark Adler
4: * For conditions of distribution and use, see copyright notice in zlib.h
5: */
6:
7: #include "zutil.h"
8: #include "inftrees.h"
9: #include "inflate.h"
10: #include "inffast.h"
11:
12: #ifndef ASMINF
13:
14: /* Allow machine dependent optimization for post-increment or pre-increment.
15: Based on testing to date,
16: Pre-increment preferred for:
17: - PowerPC G3 (Adler)
18: - MIPS R5000 (Randers-Pehrson)
19: Post-increment preferred for:
20: - none
21: No measurable difference:
22: - Pentium III (Anderson)
23: - M68060 (Nikl)
24: */
25: #ifdef POSTINC
26: # define OFF 0
27: # define PUP(a) *(a)++
28: #else
29: # define OFF 1
30: # define PUP(a) *++(a)
31: #endif
32:
33: /*
34: Decode literal, length, and distance codes and write out the resulting
35: literal and match bytes until either not enough input or output is
36: available, an end-of-block is encountered, or a data error is encountered.
37: When large enough input and output buffers are supplied to inflate(), for
38: example, a 16K input buffer and a 64K output buffer, more than 95% of the
39: inflate execution time is spent in this routine.
40:
41: Entry assumptions:
42:
43: state->mode == LEN
44: strm->avail_in >= 6
45: strm->avail_out >= 258
46: start >= strm->avail_out
47: state->bits < 8
48:
49: On return, state->mode is one of:
50:
51: LEN -- ran out of enough output space or enough available input
52: TYPE -- reached end of block code, inflate() to interpret next block
53: BAD -- error in block data
54:
55: Notes:
56:
57: - The maximum input bits used by a length/distance pair is 15 bits for the
58: length code, 5 bits for the length extra, 15 bits for the distance code,
59: and 13 bits for the distance extra. This totals 48 bits, or six bytes.
60: Therefore if strm->avail_in >= 6, then there is enough input to avoid
61: checking for available input while decoding.
62:
63: - The maximum bytes that a single length/distance pair can output is 258
64: bytes, which is the maximum length that can be coded. inflate_fast()
65: requires strm->avail_out >= 258 for each loop to avoid checking for
66: output space.
67: */
68: void inflate_fast(strm, start)
69: z_streamp strm;
70: unsigned start; /* inflate()'s starting value for strm->avail_out */
71: {
72: struct inflate_state FAR *state;
73: unsigned char FAR *in; /* local strm->next_in */
74: unsigned char FAR *last; /* while in < last, enough input available */
75: unsigned char FAR *out; /* local strm->next_out */
76: unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
77: unsigned char FAR *end; /* while out < end, enough space available */
78: #ifdef INFLATE_STRICT
79: unsigned dmax; /* maximum distance from zlib header */
80: #endif
81: unsigned wsize; /* window size or zero if not using window */
82: unsigned whave; /* valid bytes in the window */
83: unsigned write; /* window write index */
84: unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
85: unsigned long hold; /* local strm->hold */
86: unsigned bits; /* local strm->bits */
87: code const FAR *lcode; /* local strm->lencode */
88: code const FAR *dcode; /* local strm->distcode */
89: unsigned lmask; /* mask for first level of length codes */
90: unsigned dmask; /* mask for first level of distance codes */
91: code this; /* retrieved table entry */
92: unsigned op; /* code bits, operation, extra bits, or */
93: /* window position, window bytes to copy */
94: unsigned len; /* match length, unused bytes */
95: unsigned dist; /* match distance */
96: unsigned char FAR *from; /* where to copy match from */
97:
98: /* copy state to local variables */
99: state = (struct inflate_state FAR *)strm->state;
100: in = strm->next_in - OFF;
101: last = in + (strm->avail_in - 5);
102: out = strm->next_out - OFF;
103: beg = out - (start - strm->avail_out);
104: end = out + (strm->avail_out - 257);
105: #ifdef INFLATE_STRICT
106: dmax = state->dmax;
107: #endif
108: wsize = state->wsize;
109: whave = state->whave;
110: write = state->write;
111: window = state->window;
112: hold = state->hold;
113: bits = state->bits;
114: lcode = state->lencode;
115: dcode = state->distcode;
116: lmask = (1U << state->lenbits) - 1;
117: dmask = (1U << state->distbits) - 1;
118:
119: /* decode literals and length/distances until end-of-block or not enough
120: input data or output space */
121: do {
122: if (bits < 15) {
123: hold += (unsigned long)(PUP(in)) << bits;
124: bits += 8;
125: hold += (unsigned long)(PUP(in)) << bits;
126: bits += 8;
127: }
128: this = lcode[hold & lmask];
129: dolen:
130: op = (unsigned)(this.bits);
131: hold >>= op;
132: bits -= op;
133: op = (unsigned)(this.op);
134: if (op == 0) { /* literal */
135: Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
136: "inflate: literal '%c'\n" :
137: "inflate: literal 0x%02x\n", this.val));
138: PUP(out) = (unsigned char)(this.val);
139: }
140: else if (op & 16) { /* length base */
141: len = (unsigned)(this.val);
142: op &= 15; /* number of extra bits */
143: if (op) {
144: if (bits < op) {
145: hold += (unsigned long)(PUP(in)) << bits;
146: bits += 8;
147: }
148: len += (unsigned)hold & ((1U << op) - 1);
149: hold >>= op;
150: bits -= op;
151: }
152: Tracevv((stderr, "inflate: length %u\n", len));
153: if (bits < 15) {
154: hold += (unsigned long)(PUP(in)) << bits;
155: bits += 8;
156: hold += (unsigned long)(PUP(in)) << bits;
157: bits += 8;
158: }
159: this = dcode[hold & dmask];
160: dodist:
161: op = (unsigned)(this.bits);
162: hold >>= op;
163: bits -= op;
164: op = (unsigned)(this.op);
165: if (op & 16) { /* distance base */
166: dist = (unsigned)(this.val);
167: op &= 15; /* number of extra bits */
168: if (bits < op) {
169: hold += (unsigned long)(PUP(in)) << bits;
170: bits += 8;
171: if (bits < op) {
172: hold += (unsigned long)(PUP(in)) << bits;
173: bits += 8;
174: }
175: }
176: dist += (unsigned)hold & ((1U << op) - 1);
177: #ifdef INFLATE_STRICT
178: if (dist > dmax) {
179: strm->msg = (char *)"invalid distance too far back";
180: state->mode = BAD;
181: break;
182: }
183: #endif
184: hold >>= op;
185: bits -= op;
186: Tracevv((stderr, "inflate: distance %u\n", dist));
187: op = (unsigned)(out - beg); /* max distance in output */
188: if (dist > op) { /* see if copy from window */
189: op = dist - op; /* distance back in window */
190: if (op > whave) {
191: #ifdef SMALL
192: strm->msg = "error";
193: #else
194: strm->msg = (char *)"invalid distance too far back";
195: #endif
196: state->mode = BAD;
197: break;
198: }
199: from = window - OFF;
200: if (write == 0) { /* very common case */
201: from += wsize - op;
202: if (op < len) { /* some from window */
203: len -= op;
204: do {
205: PUP(out) = PUP(from);
206: } while (--op);
207: from = out - dist; /* rest from output */
208: }
209: }
210: else if (write < op) { /* wrap around window */
211: from += wsize + write - op;
212: op -= write;
213: if (op < len) { /* some from end of window */
214: len -= op;
215: do {
216: PUP(out) = PUP(from);
217: } while (--op);
218: from = window - OFF;
219: if (write < len) { /* some from start of window */
220: op = write;
221: len -= op;
222: do {
223: PUP(out) = PUP(from);
224: } while (--op);
225: from = out - dist; /* rest from output */
226: }
227: }
228: }
229: else { /* contiguous in window */
230: from += write - op;
231: if (op < len) { /* some from window */
232: len -= op;
233: do {
234: PUP(out) = PUP(from);
235: } while (--op);
236: from = out - dist; /* rest from output */
237: }
238: }
239: while (len > 2) {
240: PUP(out) = PUP(from);
241: PUP(out) = PUP(from);
242: PUP(out) = PUP(from);
243: len -= 3;
244: }
245: if (len) {
246: PUP(out) = PUP(from);
247: if (len > 1)
248: PUP(out) = PUP(from);
249: }
250: }
251: else {
252: from = out - dist; /* copy direct from output */
253: do { /* minimum length is three */
254: PUP(out) = PUP(from);
255: PUP(out) = PUP(from);
256: PUP(out) = PUP(from);
257: len -= 3;
258: } while (len > 2);
259: if (len) {
260: PUP(out) = PUP(from);
261: if (len > 1)
262: PUP(out) = PUP(from);
263: }
264: }
265: }
266: else if ((op & 64) == 0) { /* 2nd level distance code */
267: this = dcode[this.val + (hold & ((1U << op) - 1))];
268: goto dodist;
269: }
270: else {
271: #ifdef SMALL
272: strm->msg = "error";
273: #else
274: strm->msg = (char *)"invalid distance code";
275: #endif
276: state->mode = BAD;
277: break;
278: }
279: }
280: else if ((op & 64) == 0) { /* 2nd level length code */
281: this = lcode[this.val + (hold & ((1U << op) - 1))];
282: goto dolen;
283: }
284: else if (op & 32) { /* end-of-block */
285: Tracevv((stderr, "inflate: end of block\n"));
286: state->mode = TYPE;
287: break;
288: }
289: else {
290: #ifdef SMALL
291: strm->msg = "error";
292: #else
293: strm->msg = (char *)"invalid literal/length code";
294: #endif
295: state->mode = BAD;
296: break;
297: }
298: } while (in < last && out < end);
299:
300: /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
301: len = bits >> 3;
302: in -= len;
303: bits -= len << 3;
304: hold &= (1U << bits) - 1;
305:
306: /* update state and return */
307: strm->next_in = in + OFF;
308: strm->next_out = out + OFF;
309: strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
310: strm->avail_out = (unsigned)(out < end ?
311: 257 + (end - out) : 257 - (out - end));
312: state->hold = hold;
313: state->bits = bits;
314: return;
315: }
316:
317: /*
318: inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
319: - Using bit fields for code structure
320: - Different op definition to avoid & for extra bits (do & for table bits)
321: - Three separate decoding do-loops for direct, window, and write == 0
322: - Special case for distance > 1 copies to do overlapped load and store copy
323: - Explicit branch predictions (based on measured branch probabilities)
324: - Deferring match copy and interspersed it with decoding subsequent codes
325: - Swapping literal/length else
326: - Swapping window/direct else
327: - Larger unrolled copy loops (three is about right)
328: - Moving len -= 3 statement into middle of loop
329: */
330:
331: #endif /* !ASMINF */
CVSweb