xref: /rk3399_ARM-atf/lib/zlib/inffast.c (revision 50313d071261dacc923b18c996369326101a3e8a)
1221b1638SMasahiro Yamada /* inffast.c -- fast decoding
2221b1638SMasahiro Yamada  * Copyright (C) 1995-2017 Mark Adler
3221b1638SMasahiro Yamada  * For conditions of distribution and use, see copyright notice in zlib.h
4221b1638SMasahiro Yamada  */
5221b1638SMasahiro Yamada 
6221b1638SMasahiro Yamada #include "zutil.h"
7221b1638SMasahiro Yamada #include "inftrees.h"
8221b1638SMasahiro Yamada #include "inflate.h"
9221b1638SMasahiro Yamada #include "inffast.h"
10221b1638SMasahiro Yamada 
11221b1638SMasahiro Yamada #ifdef ASMINF
12221b1638SMasahiro Yamada #  pragma message("Assembler code may have bugs -- use at your own risk")
13221b1638SMasahiro Yamada #else
14221b1638SMasahiro Yamada 
15221b1638SMasahiro Yamada /*
16221b1638SMasahiro Yamada    Decode literal, length, and distance codes and write out the resulting
17221b1638SMasahiro Yamada    literal and match bytes until either not enough input or output is
18221b1638SMasahiro Yamada    available, an end-of-block is encountered, or a data error is encountered.
19221b1638SMasahiro Yamada    When large enough input and output buffers are supplied to inflate(), for
20221b1638SMasahiro Yamada    example, a 16K input buffer and a 64K output buffer, more than 95% of the
21221b1638SMasahiro Yamada    inflate execution time is spent in this routine.
22221b1638SMasahiro Yamada 
23221b1638SMasahiro Yamada    Entry assumptions:
24221b1638SMasahiro Yamada 
25221b1638SMasahiro Yamada         state->mode == LEN
26221b1638SMasahiro Yamada         strm->avail_in >= 6
27221b1638SMasahiro Yamada         strm->avail_out >= 258
28221b1638SMasahiro Yamada         start >= strm->avail_out
29221b1638SMasahiro Yamada         state->bits < 8
30221b1638SMasahiro Yamada 
31221b1638SMasahiro Yamada    On return, state->mode is one of:
32221b1638SMasahiro Yamada 
33221b1638SMasahiro Yamada         LEN -- ran out of enough output space or enough available input
34221b1638SMasahiro Yamada         TYPE -- reached end of block code, inflate() to interpret next block
35221b1638SMasahiro Yamada         BAD -- error in block data
36221b1638SMasahiro Yamada 
37221b1638SMasahiro Yamada    Notes:
38221b1638SMasahiro Yamada 
39221b1638SMasahiro Yamada     - The maximum input bits used by a length/distance pair is 15 bits for the
40221b1638SMasahiro Yamada       length code, 5 bits for the length extra, 15 bits for the distance code,
41221b1638SMasahiro Yamada       and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
42221b1638SMasahiro Yamada       Therefore if strm->avail_in >= 6, then there is enough input to avoid
43221b1638SMasahiro Yamada       checking for available input while decoding.
44221b1638SMasahiro Yamada 
45221b1638SMasahiro Yamada     - The maximum bytes that a single length/distance pair can output is 258
46221b1638SMasahiro Yamada       bytes, which is the maximum length that can be coded.  inflate_fast()
47221b1638SMasahiro Yamada       requires strm->avail_out >= 258 for each loop to avoid checking for
48221b1638SMasahiro Yamada       output space.
49221b1638SMasahiro Yamada  */
inflate_fast(z_streamp strm,unsigned start)50fd39217aSManish Pandey void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
51221b1638SMasahiro Yamada     struct inflate_state FAR *state;
52221b1638SMasahiro Yamada     z_const unsigned char FAR *in;      /* local strm->next_in */
53221b1638SMasahiro Yamada     z_const unsigned char FAR *last;    /* have enough input while in < last */
54221b1638SMasahiro Yamada     unsigned char FAR *out;     /* local strm->next_out */
55221b1638SMasahiro Yamada     unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
56221b1638SMasahiro Yamada     unsigned char FAR *end;     /* while out < end, enough space available */
57221b1638SMasahiro Yamada #ifdef INFLATE_STRICT
58221b1638SMasahiro Yamada     unsigned dmax;              /* maximum distance from zlib header */
59221b1638SMasahiro Yamada #endif
60221b1638SMasahiro Yamada     unsigned wsize;             /* window size or zero if not using window */
61221b1638SMasahiro Yamada     unsigned whave;             /* valid bytes in the window */
62221b1638SMasahiro Yamada     unsigned wnext;             /* window write index */
63221b1638SMasahiro Yamada     unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
64221b1638SMasahiro Yamada     unsigned long hold;         /* local strm->hold */
65221b1638SMasahiro Yamada     unsigned bits;              /* local strm->bits */
66221b1638SMasahiro Yamada     code const FAR *lcode;      /* local strm->lencode */
67221b1638SMasahiro Yamada     code const FAR *dcode;      /* local strm->distcode */
68221b1638SMasahiro Yamada     unsigned lmask;             /* mask for first level of length codes */
69221b1638SMasahiro Yamada     unsigned dmask;             /* mask for first level of distance codes */
70a194255dSDaniel Boulby     code const *here;           /* retrieved table entry */
71221b1638SMasahiro Yamada     unsigned op;                /* code bits, operation, extra bits, or */
72221b1638SMasahiro Yamada                                 /*  window position, window bytes to copy */
73221b1638SMasahiro Yamada     unsigned len;               /* match length, unused bytes */
74221b1638SMasahiro Yamada     unsigned dist;              /* match distance */
75221b1638SMasahiro Yamada     unsigned char FAR *from;    /* where to copy match from */
76221b1638SMasahiro Yamada 
77221b1638SMasahiro Yamada     /* copy state to local variables */
78221b1638SMasahiro Yamada     state = (struct inflate_state FAR *)strm->state;
79221b1638SMasahiro Yamada     in = strm->next_in;
80221b1638SMasahiro Yamada     last = in + (strm->avail_in - 5);
81221b1638SMasahiro Yamada     out = strm->next_out;
82221b1638SMasahiro Yamada     beg = out - (start - strm->avail_out);
83221b1638SMasahiro Yamada     end = out + (strm->avail_out - 257);
84221b1638SMasahiro Yamada #ifdef INFLATE_STRICT
85221b1638SMasahiro Yamada     dmax = state->dmax;
86221b1638SMasahiro Yamada #endif
87221b1638SMasahiro Yamada     wsize = state->wsize;
88221b1638SMasahiro Yamada     whave = state->whave;
89221b1638SMasahiro Yamada     wnext = state->wnext;
90221b1638SMasahiro Yamada     window = state->window;
91221b1638SMasahiro Yamada     hold = state->hold;
92221b1638SMasahiro Yamada     bits = state->bits;
93221b1638SMasahiro Yamada     lcode = state->lencode;
94221b1638SMasahiro Yamada     dcode = state->distcode;
95221b1638SMasahiro Yamada     lmask = (1U << state->lenbits) - 1;
96221b1638SMasahiro Yamada     dmask = (1U << state->distbits) - 1;
97221b1638SMasahiro Yamada 
98221b1638SMasahiro Yamada     /* decode literals and length/distances until end-of-block or not enough
99221b1638SMasahiro Yamada        input data or output space */
100221b1638SMasahiro Yamada     do {
101221b1638SMasahiro Yamada         if (bits < 15) {
102221b1638SMasahiro Yamada             hold += (unsigned long)(*in++) << bits;
103221b1638SMasahiro Yamada             bits += 8;
104221b1638SMasahiro Yamada             hold += (unsigned long)(*in++) << bits;
105221b1638SMasahiro Yamada             bits += 8;
106221b1638SMasahiro Yamada         }
107a194255dSDaniel Boulby         here = lcode + (hold & lmask);
108221b1638SMasahiro Yamada       dolen:
109a194255dSDaniel Boulby         op = (unsigned)(here->bits);
110221b1638SMasahiro Yamada         hold >>= op;
111221b1638SMasahiro Yamada         bits -= op;
112a194255dSDaniel Boulby         op = (unsigned)(here->op);
113221b1638SMasahiro Yamada         if (op == 0) {                          /* literal */
114a194255dSDaniel Boulby             Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
115221b1638SMasahiro Yamada                     "inflate:         literal '%c'\n" :
116a194255dSDaniel Boulby                     "inflate:         literal 0x%02x\n", here->val));
117a194255dSDaniel Boulby             *out++ = (unsigned char)(here->val);
118221b1638SMasahiro Yamada         }
119221b1638SMasahiro Yamada         else if (op & 16) {                     /* length base */
120a194255dSDaniel Boulby             len = (unsigned)(here->val);
121221b1638SMasahiro Yamada             op &= 15;                           /* number of extra bits */
122221b1638SMasahiro Yamada             if (op) {
123221b1638SMasahiro Yamada                 if (bits < op) {
124221b1638SMasahiro Yamada                     hold += (unsigned long)(*in++) << bits;
125221b1638SMasahiro Yamada                     bits += 8;
126221b1638SMasahiro Yamada                 }
127221b1638SMasahiro Yamada                 len += (unsigned)hold & ((1U << op) - 1);
128221b1638SMasahiro Yamada                 hold >>= op;
129221b1638SMasahiro Yamada                 bits -= op;
130221b1638SMasahiro Yamada             }
131221b1638SMasahiro Yamada             Tracevv((stderr, "inflate:         length %u\n", len));
132221b1638SMasahiro Yamada             if (bits < 15) {
133221b1638SMasahiro Yamada                 hold += (unsigned long)(*in++) << bits;
134221b1638SMasahiro Yamada                 bits += 8;
135221b1638SMasahiro Yamada                 hold += (unsigned long)(*in++) << bits;
136221b1638SMasahiro Yamada                 bits += 8;
137221b1638SMasahiro Yamada             }
138a194255dSDaniel Boulby             here = dcode + (hold & dmask);
139221b1638SMasahiro Yamada           dodist:
140a194255dSDaniel Boulby             op = (unsigned)(here->bits);
141221b1638SMasahiro Yamada             hold >>= op;
142221b1638SMasahiro Yamada             bits -= op;
143a194255dSDaniel Boulby             op = (unsigned)(here->op);
144221b1638SMasahiro Yamada             if (op & 16) {                      /* distance base */
145a194255dSDaniel Boulby                 dist = (unsigned)(here->val);
146221b1638SMasahiro Yamada                 op &= 15;                       /* number of extra bits */
147221b1638SMasahiro Yamada                 if (bits < op) {
148221b1638SMasahiro Yamada                     hold += (unsigned long)(*in++) << bits;
149221b1638SMasahiro Yamada                     bits += 8;
150221b1638SMasahiro Yamada                     if (bits < op) {
151221b1638SMasahiro Yamada                         hold += (unsigned long)(*in++) << bits;
152221b1638SMasahiro Yamada                         bits += 8;
153221b1638SMasahiro Yamada                     }
154221b1638SMasahiro Yamada                 }
155221b1638SMasahiro Yamada                 dist += (unsigned)hold & ((1U << op) - 1);
156221b1638SMasahiro Yamada #ifdef INFLATE_STRICT
157221b1638SMasahiro Yamada                 if (dist > dmax) {
158*a8c877cbSChris Kay                     strm->msg = (z_const char *)"invalid distance too far back";
159221b1638SMasahiro Yamada                     state->mode = BAD;
160221b1638SMasahiro Yamada                     break;
161221b1638SMasahiro Yamada                 }
162221b1638SMasahiro Yamada #endif
163221b1638SMasahiro Yamada                 hold >>= op;
164221b1638SMasahiro Yamada                 bits -= op;
165221b1638SMasahiro Yamada                 Tracevv((stderr, "inflate:         distance %u\n", dist));
166221b1638SMasahiro Yamada                 op = (unsigned)(out - beg);     /* max distance in output */
167221b1638SMasahiro Yamada                 if (dist > op) {                /* see if copy from window */
168221b1638SMasahiro Yamada                     op = dist - op;             /* distance back in window */
169221b1638SMasahiro Yamada                     if (op > whave) {
170221b1638SMasahiro Yamada                         if (state->sane) {
171221b1638SMasahiro Yamada                             strm->msg =
172*a8c877cbSChris Kay                                 (z_const char *)"invalid distance too far back";
173221b1638SMasahiro Yamada                             state->mode = BAD;
174221b1638SMasahiro Yamada                             break;
175221b1638SMasahiro Yamada                         }
176221b1638SMasahiro Yamada #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
177221b1638SMasahiro Yamada                         if (len <= op - whave) {
178221b1638SMasahiro Yamada                             do {
179221b1638SMasahiro Yamada                                 *out++ = 0;
180221b1638SMasahiro Yamada                             } while (--len);
181221b1638SMasahiro Yamada                             continue;
182221b1638SMasahiro Yamada                         }
183221b1638SMasahiro Yamada                         len -= op - whave;
184221b1638SMasahiro Yamada                         do {
185221b1638SMasahiro Yamada                             *out++ = 0;
186221b1638SMasahiro Yamada                         } while (--op > whave);
187221b1638SMasahiro Yamada                         if (op == 0) {
188221b1638SMasahiro Yamada                             from = out - dist;
189221b1638SMasahiro Yamada                             do {
190221b1638SMasahiro Yamada                                 *out++ = *from++;
191221b1638SMasahiro Yamada                             } while (--len);
192221b1638SMasahiro Yamada                             continue;
193221b1638SMasahiro Yamada                         }
194221b1638SMasahiro Yamada #endif
195221b1638SMasahiro Yamada                     }
196221b1638SMasahiro Yamada                     from = window;
197221b1638SMasahiro Yamada                     if (wnext == 0) {           /* very common case */
198221b1638SMasahiro Yamada                         from += wsize - op;
199221b1638SMasahiro Yamada                         if (op < len) {         /* some from window */
200221b1638SMasahiro Yamada                             len -= op;
201221b1638SMasahiro Yamada                             do {
202221b1638SMasahiro Yamada                                 *out++ = *from++;
203221b1638SMasahiro Yamada                             } while (--op);
204221b1638SMasahiro Yamada                             from = out - dist;  /* rest from output */
205221b1638SMasahiro Yamada                         }
206221b1638SMasahiro Yamada                     }
207221b1638SMasahiro Yamada                     else if (wnext < op) {      /* wrap around window */
208221b1638SMasahiro Yamada                         from += wsize + wnext - op;
209221b1638SMasahiro Yamada                         op -= wnext;
210221b1638SMasahiro Yamada                         if (op < len) {         /* some from end of window */
211221b1638SMasahiro Yamada                             len -= op;
212221b1638SMasahiro Yamada                             do {
213221b1638SMasahiro Yamada                                 *out++ = *from++;
214221b1638SMasahiro Yamada                             } while (--op);
215221b1638SMasahiro Yamada                             from = window;
216221b1638SMasahiro Yamada                             if (wnext < len) {  /* some from start of window */
217221b1638SMasahiro Yamada                                 op = wnext;
218221b1638SMasahiro Yamada                                 len -= op;
219221b1638SMasahiro Yamada                                 do {
220221b1638SMasahiro Yamada                                     *out++ = *from++;
221221b1638SMasahiro Yamada                                 } while (--op);
222221b1638SMasahiro Yamada                                 from = out - dist;      /* rest from output */
223221b1638SMasahiro Yamada                             }
224221b1638SMasahiro Yamada                         }
225221b1638SMasahiro Yamada                     }
226221b1638SMasahiro Yamada                     else {                      /* contiguous in window */
227221b1638SMasahiro Yamada                         from += wnext - op;
228221b1638SMasahiro Yamada                         if (op < len) {         /* some from window */
229221b1638SMasahiro Yamada                             len -= op;
230221b1638SMasahiro Yamada                             do {
231221b1638SMasahiro Yamada                                 *out++ = *from++;
232221b1638SMasahiro Yamada                             } while (--op);
233221b1638SMasahiro Yamada                             from = out - dist;  /* rest from output */
234221b1638SMasahiro Yamada                         }
235221b1638SMasahiro Yamada                     }
236221b1638SMasahiro Yamada                     while (len > 2) {
237221b1638SMasahiro Yamada                         *out++ = *from++;
238221b1638SMasahiro Yamada                         *out++ = *from++;
239221b1638SMasahiro Yamada                         *out++ = *from++;
240221b1638SMasahiro Yamada                         len -= 3;
241221b1638SMasahiro Yamada                     }
242221b1638SMasahiro Yamada                     if (len) {
243221b1638SMasahiro Yamada                         *out++ = *from++;
244221b1638SMasahiro Yamada                         if (len > 1)
245221b1638SMasahiro Yamada                             *out++ = *from++;
246221b1638SMasahiro Yamada                     }
247221b1638SMasahiro Yamada                 }
248221b1638SMasahiro Yamada                 else {
249221b1638SMasahiro Yamada                     from = out - dist;          /* copy direct from output */
250221b1638SMasahiro Yamada                     do {                        /* minimum length is three */
251221b1638SMasahiro Yamada                         *out++ = *from++;
252221b1638SMasahiro Yamada                         *out++ = *from++;
253221b1638SMasahiro Yamada                         *out++ = *from++;
254221b1638SMasahiro Yamada                         len -= 3;
255221b1638SMasahiro Yamada                     } while (len > 2);
256221b1638SMasahiro Yamada                     if (len) {
257221b1638SMasahiro Yamada                         *out++ = *from++;
258221b1638SMasahiro Yamada                         if (len > 1)
259221b1638SMasahiro Yamada                             *out++ = *from++;
260221b1638SMasahiro Yamada                     }
261221b1638SMasahiro Yamada                 }
262221b1638SMasahiro Yamada             }
263221b1638SMasahiro Yamada             else if ((op & 64) == 0) {          /* 2nd level distance code */
264a194255dSDaniel Boulby                 here = dcode + here->val + (hold & ((1U << op) - 1));
265221b1638SMasahiro Yamada                 goto dodist;
266221b1638SMasahiro Yamada             }
267221b1638SMasahiro Yamada             else {
268*a8c877cbSChris Kay                 strm->msg = (z_const char *)"invalid distance code";
269221b1638SMasahiro Yamada                 state->mode = BAD;
270221b1638SMasahiro Yamada                 break;
271221b1638SMasahiro Yamada             }
272221b1638SMasahiro Yamada         }
273221b1638SMasahiro Yamada         else if ((op & 64) == 0) {              /* 2nd level length code */
274a194255dSDaniel Boulby             here = lcode + here->val + (hold & ((1U << op) - 1));
275221b1638SMasahiro Yamada             goto dolen;
276221b1638SMasahiro Yamada         }
277221b1638SMasahiro Yamada         else if (op & 32) {                     /* end-of-block */
278221b1638SMasahiro Yamada             Tracevv((stderr, "inflate:         end of block\n"));
279221b1638SMasahiro Yamada             state->mode = TYPE;
280221b1638SMasahiro Yamada             break;
281221b1638SMasahiro Yamada         }
282221b1638SMasahiro Yamada         else {
283*a8c877cbSChris Kay             strm->msg = (z_const char *)"invalid literal/length code";
284221b1638SMasahiro Yamada             state->mode = BAD;
285221b1638SMasahiro Yamada             break;
286221b1638SMasahiro Yamada         }
287221b1638SMasahiro Yamada     } while (in < last && out < end);
288221b1638SMasahiro Yamada 
289221b1638SMasahiro Yamada     /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
290221b1638SMasahiro Yamada     len = bits >> 3;
291221b1638SMasahiro Yamada     in -= len;
292221b1638SMasahiro Yamada     bits -= len << 3;
293221b1638SMasahiro Yamada     hold &= (1U << bits) - 1;
294221b1638SMasahiro Yamada 
295221b1638SMasahiro Yamada     /* update state and return */
296221b1638SMasahiro Yamada     strm->next_in = in;
297221b1638SMasahiro Yamada     strm->next_out = out;
298221b1638SMasahiro Yamada     strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
299221b1638SMasahiro Yamada     strm->avail_out = (unsigned)(out < end ?
300221b1638SMasahiro Yamada                                  257 + (end - out) : 257 - (out - end));
301221b1638SMasahiro Yamada     state->hold = hold;
302221b1638SMasahiro Yamada     state->bits = bits;
303221b1638SMasahiro Yamada     return;
304221b1638SMasahiro Yamada }
305221b1638SMasahiro Yamada 
306221b1638SMasahiro Yamada /*
307221b1638SMasahiro Yamada    inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
308221b1638SMasahiro Yamada    - Using bit fields for code structure
309221b1638SMasahiro Yamada    - Different op definition to avoid & for extra bits (do & for table bits)
310221b1638SMasahiro Yamada    - Three separate decoding do-loops for direct, window, and wnext == 0
311221b1638SMasahiro Yamada    - Special case for distance > 1 copies to do overlapped load and store copy
312221b1638SMasahiro Yamada    - Explicit branch predictions (based on measured branch probabilities)
313221b1638SMasahiro Yamada    - Deferring match copy and interspersed it with decoding subsequent codes
314221b1638SMasahiro Yamada    - Swapping literal/length else
315221b1638SMasahiro Yamada    - Swapping window/direct else
316221b1638SMasahiro Yamada    - Larger unrolled copy loops (three is about right)
317221b1638SMasahiro Yamada    - Moving len -= 3 statement into middle of loop
318221b1638SMasahiro Yamada  */
319221b1638SMasahiro Yamada 
320221b1638SMasahiro Yamada #endif /* !ASMINF */
321