xref: /openbsd-src/gnu/usr.bin/perl/cpan/Compress-Raw-Zlib/zlib-src/inffast.c (revision 5486feefcc8cb79b19e014ab332cc5dfd05b3b33)
1b39c5158Smillert /* inffast.c -- fast decoding
25759b3d2Safresh1  * Copyright (C) 1995-2017 Mark Adler
3b39c5158Smillert  * For conditions of distribution and use, see copyright notice in zlib.h
4b39c5158Smillert  */
5b39c5158Smillert 
6b39c5158Smillert #include "zutil.h"
7b39c5158Smillert #include "inftrees.h"
8b39c5158Smillert #include "inflate.h"
9b39c5158Smillert #include "inffast.h"
10b39c5158Smillert 
115759b3d2Safresh1 #ifdef ASMINF
125759b3d2Safresh1 #  pragma message("Assembler code may have bugs -- use at your own risk")
13b39c5158Smillert #else
14b39c5158Smillert 
15b39c5158Smillert /*
16b39c5158Smillert    Decode literal, length, and distance codes and write out the resulting
17b39c5158Smillert    literal and match bytes until either not enough input or output is
18b39c5158Smillert    available, an end-of-block is encountered, or a data error is encountered.
19b39c5158Smillert    When large enough input and output buffers are supplied to inflate(), for
20b39c5158Smillert    example, a 16K input buffer and a 64K output buffer, more than 95% of the
21b39c5158Smillert    inflate execution time is spent in this routine.
22b39c5158Smillert 
23b39c5158Smillert    Entry assumptions:
24b39c5158Smillert 
25b39c5158Smillert         state->mode == LEN
26b39c5158Smillert         strm->avail_in >= 6
27b39c5158Smillert         strm->avail_out >= 258
28b39c5158Smillert         start >= strm->avail_out
29b39c5158Smillert         state->bits < 8
30b39c5158Smillert 
31b39c5158Smillert    On return, state->mode is one of:
32b39c5158Smillert 
33b39c5158Smillert         LEN -- ran out of enough output space or enough available input
34b39c5158Smillert         TYPE -- reached end of block code, inflate() to interpret next block
35b39c5158Smillert         BAD -- error in block data
36b39c5158Smillert 
37b39c5158Smillert    Notes:
38b39c5158Smillert 
39b39c5158Smillert     - The maximum input bits used by a length/distance pair is 15 bits for the
40b39c5158Smillert       length code, 5 bits for the length extra, 15 bits for the distance code,
41b39c5158Smillert       and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
42b39c5158Smillert       Therefore if strm->avail_in >= 6, then there is enough input to avoid
43b39c5158Smillert       checking for available input while decoding.
44b39c5158Smillert 
45b39c5158Smillert     - The maximum bytes that a single length/distance pair can output is 258
46b39c5158Smillert       bytes, which is the maximum length that can be coded.  inflate_fast()
47b39c5158Smillert       requires strm->avail_out >= 258 for each loop to avoid checking for
48b39c5158Smillert       output space.
49b39c5158Smillert  */
50*5486feefSafresh1 void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
51b39c5158Smillert     struct inflate_state FAR *state;
526fb12b70Safresh1     z_const unsigned char FAR *in;      /* local strm->next_in */
536fb12b70Safresh1     z_const unsigned char FAR *last;    /* have enough input while in < last */
54b39c5158Smillert     unsigned char FAR *out;     /* local strm->next_out */
55b39c5158Smillert     unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
56b39c5158Smillert     unsigned char FAR *end;     /* while out < end, enough space available */
57b39c5158Smillert #ifdef INFLATE_STRICT
58b39c5158Smillert     unsigned dmax;              /* maximum distance from zlib header */
59b39c5158Smillert #endif
60b39c5158Smillert     unsigned wsize;             /* window size or zero if not using window */
61b39c5158Smillert     unsigned whave;             /* valid bytes in the window */
62898184e3Ssthen     unsigned wnext;             /* window write index */
63b39c5158Smillert     unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
64b39c5158Smillert     unsigned long hold;         /* local strm->hold */
65b39c5158Smillert     unsigned bits;              /* local strm->bits */
66b39c5158Smillert     code const FAR *lcode;      /* local strm->lencode */
67b39c5158Smillert     code const FAR *dcode;      /* local strm->distcode */
68b39c5158Smillert     unsigned lmask;             /* mask for first level of length codes */
69b39c5158Smillert     unsigned dmask;             /* mask for first level of distance codes */
70256a93a4Safresh1     code const *here;           /* retrieved table entry */
71b39c5158Smillert     unsigned op;                /* code bits, operation, extra bits, or */
72b39c5158Smillert                                 /*  window position, window bytes to copy */
73b39c5158Smillert     unsigned len;               /* match length, unused bytes */
74b39c5158Smillert     unsigned dist;              /* match distance */
75b39c5158Smillert     unsigned char FAR *from;    /* where to copy match from */
76b39c5158Smillert 
77b39c5158Smillert     /* copy state to local variables */
78b39c5158Smillert     state = (struct inflate_state FAR *)strm->state;
795759b3d2Safresh1     in = strm->next_in;
80b39c5158Smillert     last = in + (strm->avail_in - 5);
815759b3d2Safresh1     out = strm->next_out;
82b39c5158Smillert     beg = out - (start - strm->avail_out);
83b39c5158Smillert     end = out + (strm->avail_out - 257);
84b39c5158Smillert #ifdef INFLATE_STRICT
85b39c5158Smillert     dmax = state->dmax;
86b39c5158Smillert #endif
87b39c5158Smillert     wsize = state->wsize;
88b39c5158Smillert     whave = state->whave;
89898184e3Ssthen     wnext = state->wnext;
90b39c5158Smillert     window = state->window;
91b39c5158Smillert     hold = state->hold;
92b39c5158Smillert     bits = state->bits;
93b39c5158Smillert     lcode = state->lencode;
94b39c5158Smillert     dcode = state->distcode;
95b39c5158Smillert     lmask = (1U << state->lenbits) - 1;
96b39c5158Smillert     dmask = (1U << state->distbits) - 1;
97b39c5158Smillert 
98b39c5158Smillert     /* decode literals and length/distances until end-of-block or not enough
99b39c5158Smillert        input data or output space */
100b39c5158Smillert     do {
101b39c5158Smillert         if (bits < 15) {
1025759b3d2Safresh1             hold += (unsigned long)(*in++) << bits;
103b39c5158Smillert             bits += 8;
1045759b3d2Safresh1             hold += (unsigned long)(*in++) << bits;
105b39c5158Smillert             bits += 8;
106b39c5158Smillert         }
107256a93a4Safresh1         here = lcode + (hold & lmask);
108b39c5158Smillert       dolen:
109256a93a4Safresh1         op = (unsigned)(here->bits);
110b39c5158Smillert         hold >>= op;
111b39c5158Smillert         bits -= op;
112256a93a4Safresh1         op = (unsigned)(here->op);
113b39c5158Smillert         if (op == 0) {                          /* literal */
114256a93a4Safresh1             Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
115b39c5158Smillert                     "inflate:         literal '%c'\n" :
116256a93a4Safresh1                     "inflate:         literal 0x%02x\n", here->val));
117256a93a4Safresh1             *out++ = (unsigned char)(here->val);
118b39c5158Smillert         }
119b39c5158Smillert         else if (op & 16) {                     /* length base */
120256a93a4Safresh1             len = (unsigned)(here->val);
121b39c5158Smillert             op &= 15;                           /* number of extra bits */
122b39c5158Smillert             if (op) {
123b39c5158Smillert                 if (bits < op) {
1245759b3d2Safresh1                     hold += (unsigned long)(*in++) << bits;
125b39c5158Smillert                     bits += 8;
126b39c5158Smillert                 }
127b39c5158Smillert                 len += (unsigned)hold & ((1U << op) - 1);
128b39c5158Smillert                 hold >>= op;
129b39c5158Smillert                 bits -= op;
130b39c5158Smillert             }
131b39c5158Smillert             Tracevv((stderr, "inflate:         length %u\n", len));
132b39c5158Smillert             if (bits < 15) {
1335759b3d2Safresh1                 hold += (unsigned long)(*in++) << bits;
134b39c5158Smillert                 bits += 8;
1355759b3d2Safresh1                 hold += (unsigned long)(*in++) << bits;
136b39c5158Smillert                 bits += 8;
137b39c5158Smillert             }
138256a93a4Safresh1             here = dcode + (hold & dmask);
139b39c5158Smillert           dodist:
140256a93a4Safresh1             op = (unsigned)(here->bits);
141b39c5158Smillert             hold >>= op;
142b39c5158Smillert             bits -= op;
143256a93a4Safresh1             op = (unsigned)(here->op);
144b39c5158Smillert             if (op & 16) {                      /* distance base */
145256a93a4Safresh1                 dist = (unsigned)(here->val);
146b39c5158Smillert                 op &= 15;                       /* number of extra bits */
147b39c5158Smillert                 if (bits < op) {
1485759b3d2Safresh1                     hold += (unsigned long)(*in++) << bits;
149b39c5158Smillert                     bits += 8;
150b39c5158Smillert                     if (bits < op) {
1515759b3d2Safresh1                         hold += (unsigned long)(*in++) << bits;
152b39c5158Smillert                         bits += 8;
153b39c5158Smillert                     }
154b39c5158Smillert                 }
155b39c5158Smillert                 dist += (unsigned)hold & ((1U << op) - 1);
156b39c5158Smillert #ifdef INFLATE_STRICT
157b39c5158Smillert                 if (dist > dmax) {
158b39c5158Smillert                     strm->msg = (char *)"invalid distance too far back";
159b39c5158Smillert                     state->mode = BAD;
160b39c5158Smillert                     break;
161b39c5158Smillert                 }
162b39c5158Smillert #endif
163b39c5158Smillert                 hold >>= op;
164b39c5158Smillert                 bits -= op;
165b39c5158Smillert                 Tracevv((stderr, "inflate:         distance %u\n", dist));
166b39c5158Smillert                 op = (unsigned)(out - beg);     /* max distance in output */
167b39c5158Smillert                 if (dist > op) {                /* see if copy from window */
168b39c5158Smillert                     op = dist - op;             /* distance back in window */
169b39c5158Smillert                     if (op > whave) {
170898184e3Ssthen                         if (state->sane) {
171898184e3Ssthen                             strm->msg =
172898184e3Ssthen                                 (char *)"invalid distance too far back";
173b39c5158Smillert                             state->mode = BAD;
174b39c5158Smillert                             break;
175b39c5158Smillert                         }
176898184e3Ssthen #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
177898184e3Ssthen                         if (len <= op - whave) {
178898184e3Ssthen                             do {
1795759b3d2Safresh1                                 *out++ = 0;
180898184e3Ssthen                             } while (--len);
181898184e3Ssthen                             continue;
182898184e3Ssthen                         }
183898184e3Ssthen                         len -= op - whave;
184898184e3Ssthen                         do {
1855759b3d2Safresh1                             *out++ = 0;
186898184e3Ssthen                         } while (--op > whave);
187898184e3Ssthen                         if (op == 0) {
188898184e3Ssthen                             from = out - dist;
189898184e3Ssthen                             do {
1905759b3d2Safresh1                                 *out++ = *from++;
191898184e3Ssthen                             } while (--len);
192898184e3Ssthen                             continue;
193898184e3Ssthen                         }
194898184e3Ssthen #endif
195898184e3Ssthen                     }
1965759b3d2Safresh1                     from = window;
197898184e3Ssthen                     if (wnext == 0) {           /* very common case */
198b39c5158Smillert                         from += wsize - op;
199b39c5158Smillert                         if (op < len) {         /* some from window */
200b39c5158Smillert                             len -= op;
201b39c5158Smillert                             do {
2025759b3d2Safresh1                                 *out++ = *from++;
203b39c5158Smillert                             } while (--op);
204b39c5158Smillert                             from = out - dist;  /* rest from output */
205b39c5158Smillert                         }
206b39c5158Smillert                     }
207898184e3Ssthen                     else if (wnext < op) {      /* wrap around window */
208898184e3Ssthen                         from += wsize + wnext - op;
209898184e3Ssthen                         op -= wnext;
210b39c5158Smillert                         if (op < len) {         /* some from end of window */
211b39c5158Smillert                             len -= op;
212b39c5158Smillert                             do {
2135759b3d2Safresh1                                 *out++ = *from++;
214b39c5158Smillert                             } while (--op);
2155759b3d2Safresh1                             from = window;
216898184e3Ssthen                             if (wnext < len) {  /* some from start of window */
217898184e3Ssthen                                 op = wnext;
218b39c5158Smillert                                 len -= op;
219b39c5158Smillert                                 do {
2205759b3d2Safresh1                                     *out++ = *from++;
221b39c5158Smillert                                 } while (--op);
222b39c5158Smillert                                 from = out - dist;      /* rest from output */
223b39c5158Smillert                             }
224b39c5158Smillert                         }
225b39c5158Smillert                     }
226b39c5158Smillert                     else {                      /* contiguous in window */
227898184e3Ssthen                         from += wnext - op;
228b39c5158Smillert                         if (op < len) {         /* some from window */
229b39c5158Smillert                             len -= op;
230b39c5158Smillert                             do {
2315759b3d2Safresh1                                 *out++ = *from++;
232b39c5158Smillert                             } while (--op);
233b39c5158Smillert                             from = out - dist;  /* rest from output */
234b39c5158Smillert                         }
235b39c5158Smillert                     }
236b39c5158Smillert                     while (len > 2) {
2375759b3d2Safresh1                         *out++ = *from++;
2385759b3d2Safresh1                         *out++ = *from++;
2395759b3d2Safresh1                         *out++ = *from++;
240b39c5158Smillert                         len -= 3;
241b39c5158Smillert                     }
242b39c5158Smillert                     if (len) {
2435759b3d2Safresh1                         *out++ = *from++;
244b39c5158Smillert                         if (len > 1)
2455759b3d2Safresh1                             *out++ = *from++;
246b39c5158Smillert                     }
247b39c5158Smillert                 }
248b39c5158Smillert                 else {
249b39c5158Smillert                     from = out - dist;          /* copy direct from output */
250b39c5158Smillert                     do {                        /* minimum length is three */
2515759b3d2Safresh1                         *out++ = *from++;
2525759b3d2Safresh1                         *out++ = *from++;
2535759b3d2Safresh1                         *out++ = *from++;
254b39c5158Smillert                         len -= 3;
255b39c5158Smillert                     } while (len > 2);
256b39c5158Smillert                     if (len) {
2575759b3d2Safresh1                         *out++ = *from++;
258b39c5158Smillert                         if (len > 1)
2595759b3d2Safresh1                             *out++ = *from++;
260b39c5158Smillert                     }
261b39c5158Smillert                 }
262b39c5158Smillert             }
263b39c5158Smillert             else if ((op & 64) == 0) {          /* 2nd level distance code */
264256a93a4Safresh1                 here = dcode + here->val + (hold & ((1U << op) - 1));
265b39c5158Smillert                 goto dodist;
266b39c5158Smillert             }
267b39c5158Smillert             else {
268b39c5158Smillert                 strm->msg = (char *)"invalid distance code";
269b39c5158Smillert                 state->mode = BAD;
270b39c5158Smillert                 break;
271b39c5158Smillert             }
272b39c5158Smillert         }
273b39c5158Smillert         else if ((op & 64) == 0) {              /* 2nd level length code */
274256a93a4Safresh1             here = lcode + here->val + (hold & ((1U << op) - 1));
275b39c5158Smillert             goto dolen;
276b39c5158Smillert         }
277b39c5158Smillert         else if (op & 32) {                     /* end-of-block */
278b39c5158Smillert             Tracevv((stderr, "inflate:         end of block\n"));
279b39c5158Smillert             state->mode = TYPE;
280b39c5158Smillert             break;
281b39c5158Smillert         }
282b39c5158Smillert         else {
283b39c5158Smillert             strm->msg = (char *)"invalid literal/length code";
284b39c5158Smillert             state->mode = BAD;
285b39c5158Smillert             break;
286b39c5158Smillert         }
287b39c5158Smillert     } while (in < last && out < end);
288b39c5158Smillert 
289b39c5158Smillert     /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
290b39c5158Smillert     len = bits >> 3;
291b39c5158Smillert     in -= len;
292b39c5158Smillert     bits -= len << 3;
293b39c5158Smillert     hold &= (1U << bits) - 1;
294b39c5158Smillert 
295b39c5158Smillert     /* update state and return */
2965759b3d2Safresh1     strm->next_in = in;
2975759b3d2Safresh1     strm->next_out = out;
298b39c5158Smillert     strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
299b39c5158Smillert     strm->avail_out = (unsigned)(out < end ?
300b39c5158Smillert                                  257 + (end - out) : 257 - (out - end));
301b39c5158Smillert     state->hold = hold;
302b39c5158Smillert     state->bits = bits;
303b39c5158Smillert     return;
304b39c5158Smillert }
305b39c5158Smillert 
306b39c5158Smillert /*
307b39c5158Smillert    inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
308b39c5158Smillert    - Using bit fields for code structure
309b39c5158Smillert    - Different op definition to avoid & for extra bits (do & for table bits)
310898184e3Ssthen    - Three separate decoding do-loops for direct, window, and wnext == 0
311b39c5158Smillert    - Special case for distance > 1 copies to do overlapped load and store copy
312b39c5158Smillert    - Explicit branch predictions (based on measured branch probabilities)
313b39c5158Smillert    - Deferring match copy and interspersed it with decoding subsequent codes
314b39c5158Smillert    - Swapping literal/length else
315b39c5158Smillert    - Swapping window/direct else
316b39c5158Smillert    - Larger unrolled copy loops (three is about right)
317b39c5158Smillert    - Moving len -= 3 statement into middle of loop
318b39c5158Smillert  */
319b39c5158Smillert 
320b39c5158Smillert #endif /* !ASMINF */
321