xref: /openbsd-src/sys/lib/libz/inffast.c (revision fb9b015228f7ecb1179e6f095135f306e545d46d)
1a79de952Smillert /* inffast.c -- fast decoding
236f395ceStb  * Copyright (C) 1995-2017 Mark Adler
335534e26Sdownsj  * For conditions of distribution and use, see copyright notice in zlib.h
435534e26Sdownsj  */
535534e26Sdownsj 
635534e26Sdownsj #include "zutil.h"
735534e26Sdownsj #include "inftrees.h"
8a79de952Smillert #include "inflate.h"
935534e26Sdownsj #include "inffast.h"
1035534e26Sdownsj 
1136f395ceStb #ifdef ASMINF
1236f395ceStb #  pragma message("Assembler code may have bugs -- use at your own risk")
1386c6ced8Sderaadt #else
1435534e26Sdownsj 
15a79de952Smillert /*
16a79de952Smillert    Decode literal, length, and distance codes and write out the resulting
17a79de952Smillert    literal and match bytes until either not enough input or output is
18a79de952Smillert    available, an end-of-block is encountered, or a data error is encountered.
19a79de952Smillert    When large enough input and output buffers are supplied to inflate(), for
20a79de952Smillert    example, a 16K input buffer and a 64K output buffer, more than 95% of the
21a79de952Smillert    inflate execution time is spent in this routine.
22a79de952Smillert 
23a79de952Smillert    Entry assumptions:
24a79de952Smillert 
25a79de952Smillert         state->mode == LEN
26a79de952Smillert         strm->avail_in >= 6
27a79de952Smillert         strm->avail_out >= 258
28a79de952Smillert         start >= strm->avail_out
29a79de952Smillert         state->bits < 8
30a79de952Smillert 
31a79de952Smillert    On return, state->mode is one of:
32a79de952Smillert 
33a79de952Smillert         LEN -- ran out of enough output space or enough available input
34a79de952Smillert         TYPE -- reached end of block code, inflate() to interpret next block
35a79de952Smillert         BAD -- error in block data
36a79de952Smillert 
37a79de952Smillert    Notes:
38a79de952Smillert 
39a79de952Smillert     - The maximum input bits used by a length/distance pair is 15 bits for the
40a79de952Smillert       length code, 5 bits for the length extra, 15 bits for the distance code,
41a79de952Smillert       and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
42a79de952Smillert       Therefore if strm->avail_in >= 6, then there is enough input to avoid
43a79de952Smillert       checking for available input while decoding.
44a79de952Smillert 
45a79de952Smillert     - The maximum bytes that a single length/distance pair can output is 258
46a79de952Smillert       bytes, which is the maximum length that can be coded.  inflate_fast()
47a79de952Smillert       requires strm->avail_out >= 258 for each loop to avoid checking for
48a79de952Smillert       output space.
49a79de952Smillert  */
inflate_fast(z_streamp strm,unsigned start)50cfac609cStb void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
51a79de952Smillert     struct inflate_state FAR *state;
52efa1b761Sjca     z_const unsigned char FAR *in;      /* local strm->next_in */
5336f395ceStb     z_const unsigned char FAR *last;    /* have enough input while in < last */
54a79de952Smillert     unsigned char FAR *out;     /* local strm->next_out */
55a79de952Smillert     unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
56a79de952Smillert     unsigned char FAR *end;     /* while out < end, enough space available */
57d76b9bfaSmillert #ifdef INFLATE_STRICT
58d76b9bfaSmillert     unsigned dmax;              /* maximum distance from zlib header */
59d76b9bfaSmillert #endif
60a79de952Smillert     unsigned wsize;             /* window size or zero if not using window */
61a79de952Smillert     unsigned whave;             /* valid bytes in the window */
6236f395ceStb     unsigned wnext;             /* window write index */
63a79de952Smillert     unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
64a79de952Smillert     unsigned long hold;         /* local strm->hold */
65a79de952Smillert     unsigned bits;              /* local strm->bits */
66a79de952Smillert     code const FAR *lcode;      /* local strm->lencode */
67a79de952Smillert     code const FAR *dcode;      /* local strm->distcode */
68a79de952Smillert     unsigned lmask;             /* mask for first level of length codes */
69a79de952Smillert     unsigned dmask;             /* mask for first level of distance codes */
70a6530658Stb     code const *here;           /* retrieved table entry */
71a79de952Smillert     unsigned op;                /* code bits, operation, extra bits, or */
72a79de952Smillert                                 /*  window position, window bytes to copy */
73a79de952Smillert     unsigned len;               /* match length, unused bytes */
74a79de952Smillert     unsigned dist;              /* match distance */
75a79de952Smillert     unsigned char FAR *from;    /* where to copy match from */
76a79de952Smillert 
77a79de952Smillert     /* copy state to local variables */
78a79de952Smillert     state = (struct inflate_state FAR *)strm->state;
7936f395ceStb     in = strm->next_in;
80a79de952Smillert     last = in + (strm->avail_in - 5);
8136f395ceStb     out = strm->next_out;
82a79de952Smillert     beg = out - (start - strm->avail_out);
83a79de952Smillert     end = out + (strm->avail_out - 257);
84d76b9bfaSmillert #ifdef INFLATE_STRICT
85d76b9bfaSmillert     dmax = state->dmax;
86d76b9bfaSmillert #endif
87a79de952Smillert     wsize = state->wsize;
88a79de952Smillert     whave = state->whave;
8936f395ceStb     wnext = state->wnext;
90a79de952Smillert     window = state->window;
91a79de952Smillert     hold = state->hold;
92a79de952Smillert     bits = state->bits;
93a79de952Smillert     lcode = state->lencode;
94a79de952Smillert     dcode = state->distcode;
95a79de952Smillert     lmask = (1U << state->lenbits) - 1;
96a79de952Smillert     dmask = (1U << state->distbits) - 1;
97a79de952Smillert 
98a79de952Smillert     /* decode literals and length/distances until end-of-block or not enough
99a79de952Smillert        input data or output space */
100a79de952Smillert     do {
101a79de952Smillert         if (bits < 15) {
10236f395ceStb             hold += (unsigned long)(*in++) << bits;
103a79de952Smillert             bits += 8;
10436f395ceStb             hold += (unsigned long)(*in++) << bits;
105a79de952Smillert             bits += 8;
10635534e26Sdownsj         }
107a6530658Stb         here = lcode + (hold & lmask);
108a79de952Smillert       dolen:
109a6530658Stb         op = (unsigned)(here->bits);
110a79de952Smillert         hold >>= op;
111a79de952Smillert         bits -= op;
112a6530658Stb         op = (unsigned)(here->op);
113a79de952Smillert         if (op == 0) {                          /* literal */
114a6530658Stb             Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
115a79de952Smillert                     "inflate:         literal '%c'\n" :
116a6530658Stb                     "inflate:         literal 0x%02x\n", here->val));
117a6530658Stb             *out++ = (unsigned char)(here->val);
118a79de952Smillert         }
119a79de952Smillert         else if (op & 16) {                     /* length base */
120a6530658Stb             len = (unsigned)(here->val);
121a79de952Smillert             op &= 15;                           /* number of extra bits */
122a79de952Smillert             if (op) {
123a79de952Smillert                 if (bits < op) {
12436f395ceStb                     hold += (unsigned long)(*in++) << bits;
125a79de952Smillert                     bits += 8;
126a79de952Smillert                 }
127a79de952Smillert                 len += (unsigned)hold & ((1U << op) - 1);
128a79de952Smillert                 hold >>= op;
129a79de952Smillert                 bits -= op;
130a79de952Smillert             }
131a79de952Smillert             Tracevv((stderr, "inflate:         length %u\n", len));
132a79de952Smillert             if (bits < 15) {
13336f395ceStb                 hold += (unsigned long)(*in++) << bits;
134a79de952Smillert                 bits += 8;
13536f395ceStb                 hold += (unsigned long)(*in++) << bits;
136a79de952Smillert                 bits += 8;
137a79de952Smillert             }
138a6530658Stb             here = dcode + (hold & dmask);
139a79de952Smillert           dodist:
140a6530658Stb             op = (unsigned)(here->bits);
141a79de952Smillert             hold >>= op;
142a79de952Smillert             bits -= op;
143a6530658Stb             op = (unsigned)(here->op);
144a79de952Smillert             if (op & 16) {                      /* distance base */
145a6530658Stb                 dist = (unsigned)(here->val);
146a79de952Smillert                 op &= 15;                       /* number of extra bits */
147a79de952Smillert                 if (bits < op) {
14836f395ceStb                     hold += (unsigned long)(*in++) << bits;
149a79de952Smillert                     bits += 8;
150a79de952Smillert                     if (bits < op) {
15136f395ceStb                         hold += (unsigned long)(*in++) << bits;
152a79de952Smillert                         bits += 8;
153a79de952Smillert                     }
154a79de952Smillert                 }
155a79de952Smillert                 dist += (unsigned)hold & ((1U << op) - 1);
156d76b9bfaSmillert #ifdef INFLATE_STRICT
157d76b9bfaSmillert                 if (dist > dmax) {
158*fb9b0152Stb                     strm->msg = (z_const char *)"invalid distance too far back";
159d76b9bfaSmillert                     state->mode = BAD;
160d76b9bfaSmillert                     break;
161d76b9bfaSmillert                 }
162d76b9bfaSmillert #endif
163a79de952Smillert                 hold >>= op;
164a79de952Smillert                 bits -= op;
165a79de952Smillert                 Tracevv((stderr, "inflate:         distance %u\n", dist));
166a79de952Smillert                 op = (unsigned)(out - beg);     /* max distance in output */
167a79de952Smillert                 if (dist > op) {                /* see if copy from window */
168a79de952Smillert                     op = dist - op;             /* distance back in window */
169a79de952Smillert                     if (op > whave) {
17036f395ceStb                         if (state->sane) {
1710ede0c43Smillert #ifdef SMALL
172*fb9b0152Stb                             strm->msg = (z_const char *)"error";
1730ede0c43Smillert #else
17436f395ceStb                             strm->msg =
175*fb9b0152Stb                                 (z_const char *)"invalid distance too far back";
1760ede0c43Smillert #endif
177a79de952Smillert                             state->mode = BAD;
178a79de952Smillert                             break;
179a79de952Smillert                         }
18036f395ceStb #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
18136f395ceStb                         if (len <= op - whave) {
18236f395ceStb                             do {
18336f395ceStb                                 *out++ = 0;
18436f395ceStb                             } while (--len);
18536f395ceStb                             continue;
18636f395ceStb                         }
18736f395ceStb                         len -= op - whave;
18836f395ceStb                         do {
18936f395ceStb                             *out++ = 0;
19036f395ceStb                         } while (--op > whave);
19136f395ceStb                         if (op == 0) {
19236f395ceStb                             from = out - dist;
19336f395ceStb                             do {
19436f395ceStb                                 *out++ = *from++;
19536f395ceStb                             } while (--len);
19636f395ceStb                             continue;
19736f395ceStb                         }
19836f395ceStb #endif
19936f395ceStb                     }
20036f395ceStb                     from = window;
20136f395ceStb                     if (wnext == 0) {           /* very common case */
202a79de952Smillert                         from += wsize - op;
203a79de952Smillert                         if (op < len) {         /* some from window */
204a79de952Smillert                             len -= op;
205a79de952Smillert                             do {
20636f395ceStb                                 *out++ = *from++;
207a79de952Smillert                             } while (--op);
208a79de952Smillert                             from = out - dist;  /* rest from output */
209a79de952Smillert                         }
210a79de952Smillert                     }
21136f395ceStb                     else if (wnext < op) {      /* wrap around window */
21236f395ceStb                         from += wsize + wnext - op;
21336f395ceStb                         op -= wnext;
214a79de952Smillert                         if (op < len) {         /* some from end of window */
215a79de952Smillert                             len -= op;
216a79de952Smillert                             do {
21736f395ceStb                                 *out++ = *from++;
218a79de952Smillert                             } while (--op);
21936f395ceStb                             from = window;
22036f395ceStb                             if (wnext < len) {  /* some from start of window */
22136f395ceStb                                 op = wnext;
222a79de952Smillert                                 len -= op;
223a79de952Smillert                                 do {
22436f395ceStb                                     *out++ = *from++;
225a79de952Smillert                                 } while (--op);
226a79de952Smillert                                 from = out - dist;      /* rest from output */
227a79de952Smillert                             }
228a79de952Smillert                         }
229a79de952Smillert                     }
230a79de952Smillert                     else {                      /* contiguous in window */
23136f395ceStb                         from += wnext - op;
232a79de952Smillert                         if (op < len) {         /* some from window */
233a79de952Smillert                             len -= op;
234a79de952Smillert                             do {
23536f395ceStb                                 *out++ = *from++;
236a79de952Smillert                             } while (--op);
237a79de952Smillert                             from = out - dist;  /* rest from output */
238a79de952Smillert                         }
239a79de952Smillert                     }
240a79de952Smillert                     while (len > 2) {
24136f395ceStb                         *out++ = *from++;
24236f395ceStb                         *out++ = *from++;
24336f395ceStb                         *out++ = *from++;
244a79de952Smillert                         len -= 3;
245a79de952Smillert                     }
246a79de952Smillert                     if (len) {
24736f395ceStb                         *out++ = *from++;
248a79de952Smillert                         if (len > 1)
24936f395ceStb                             *out++ = *from++;
250a79de952Smillert                     }
251a79de952Smillert                 }
252a79de952Smillert                 else {
253a79de952Smillert                     from = out - dist;          /* copy direct from output */
254a79de952Smillert                     do {                        /* minimum length is three */
25536f395ceStb                         *out++ = *from++;
25636f395ceStb                         *out++ = *from++;
25736f395ceStb                         *out++ = *from++;
258a79de952Smillert                         len -= 3;
259a79de952Smillert                     } while (len > 2);
260a79de952Smillert                     if (len) {
26136f395ceStb                         *out++ = *from++;
262a79de952Smillert                         if (len > 1)
26336f395ceStb                             *out++ = *from++;
264a79de952Smillert                     }
265a79de952Smillert                 }
266a79de952Smillert             }
267a79de952Smillert             else if ((op & 64) == 0) {          /* 2nd level distance code */
268a6530658Stb                 here = dcode + here->val + (hold & ((1U << op) - 1));
269a79de952Smillert                 goto dodist;
270a79de952Smillert             }
271a79de952Smillert             else {
2720ede0c43Smillert #ifdef SMALL
273*fb9b0152Stb                 strm->msg = (z_const char *)"error";
2740ede0c43Smillert #else
275*fb9b0152Stb                 strm->msg = (z_const char *)"invalid distance code";
2760ede0c43Smillert #endif
277a79de952Smillert                 state->mode = BAD;
278a79de952Smillert                 break;
279a79de952Smillert             }
280a79de952Smillert         }
281a79de952Smillert         else if ((op & 64) == 0) {              /* 2nd level length code */
282a6530658Stb             here = lcode + here->val + (hold & ((1U << op) - 1));
283a79de952Smillert             goto dolen;
284a79de952Smillert         }
285a79de952Smillert         else if (op & 32) {                     /* end-of-block */
286a79de952Smillert             Tracevv((stderr, "inflate:         end of block\n"));
287a79de952Smillert             state->mode = TYPE;
288a79de952Smillert             break;
289a79de952Smillert         }
290a79de952Smillert         else {
2910ede0c43Smillert #ifdef SMALL
292*fb9b0152Stb             strm->msg = (z_const char *)"error";
2930ede0c43Smillert #else
294*fb9b0152Stb             strm->msg = (z_const char *)"invalid literal/length code";
2950ede0c43Smillert #endif
296a79de952Smillert             state->mode = BAD;
297a79de952Smillert             break;
298a79de952Smillert         }
299a79de952Smillert     } while (in < last && out < end);
300a79de952Smillert 
301a79de952Smillert     /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
302a79de952Smillert     len = bits >> 3;
303a79de952Smillert     in -= len;
304a79de952Smillert     bits -= len << 3;
305a79de952Smillert     hold &= (1U << bits) - 1;
306a79de952Smillert 
307a79de952Smillert     /* update state and return */
30836f395ceStb     strm->next_in = in;
30936f395ceStb     strm->next_out = out;
310a79de952Smillert     strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
311a79de952Smillert     strm->avail_out = (unsigned)(out < end ?
312a79de952Smillert                                  257 + (end - out) : 257 - (out - end));
313a79de952Smillert     state->hold = hold;
314a79de952Smillert     state->bits = bits;
315a79de952Smillert     return;
316a79de952Smillert }
317a79de952Smillert 
318a79de952Smillert /*
319a79de952Smillert    inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
320a79de952Smillert    - Using bit fields for code structure
321a79de952Smillert    - Different op definition to avoid & for extra bits (do & for table bits)
32236f395ceStb    - Three separate decoding do-loops for direct, window, and wnext == 0
323a79de952Smillert    - Special case for distance > 1 copies to do overlapped load and store copy
324a79de952Smillert    - Explicit branch predictions (based on measured branch probabilities)
325a79de952Smillert    - Deferring match copy and interspersed it with decoding subsequent codes
326a79de952Smillert    - Swapping literal/length else
327a79de952Smillert    - Swapping window/direct else
328a79de952Smillert    - Larger unrolled copy loops (three is about right)
329a79de952Smillert    - Moving len -= 3 statement into middle of loop
330a79de952Smillert  */
331a79de952Smillert 
332a79de952Smillert #endif /* !ASMINF */
333