xref: /rk3399_ARM-atf/lib/zlib/inffast.c (revision a194255d75ed9e2ef56bd6e14349a3e7d86af934)
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  */
50221b1638SMasahiro Yamada void ZLIB_INTERNAL inflate_fast(strm, start)
51221b1638SMasahiro Yamada z_streamp strm;
52221b1638SMasahiro Yamada unsigned start;         /* inflate()'s starting value for strm->avail_out */
53221b1638SMasahiro Yamada {
54221b1638SMasahiro Yamada     struct inflate_state FAR *state;
55221b1638SMasahiro Yamada     z_const unsigned char FAR *in;      /* local strm->next_in */
56221b1638SMasahiro Yamada     z_const unsigned char FAR *last;    /* have enough input while in < last */
57221b1638SMasahiro Yamada     unsigned char FAR *out;     /* local strm->next_out */
58221b1638SMasahiro Yamada     unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
59221b1638SMasahiro Yamada     unsigned char FAR *end;     /* while out < end, enough space available */
60221b1638SMasahiro Yamada #ifdef INFLATE_STRICT
61221b1638SMasahiro Yamada     unsigned dmax;              /* maximum distance from zlib header */
62221b1638SMasahiro Yamada #endif
63221b1638SMasahiro Yamada     unsigned wsize;             /* window size or zero if not using window */
64221b1638SMasahiro Yamada     unsigned whave;             /* valid bytes in the window */
65221b1638SMasahiro Yamada     unsigned wnext;             /* window write index */
66221b1638SMasahiro Yamada     unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
67221b1638SMasahiro Yamada     unsigned long hold;         /* local strm->hold */
68221b1638SMasahiro Yamada     unsigned bits;              /* local strm->bits */
69221b1638SMasahiro Yamada     code const FAR *lcode;      /* local strm->lencode */
70221b1638SMasahiro Yamada     code const FAR *dcode;      /* local strm->distcode */
71221b1638SMasahiro Yamada     unsigned lmask;             /* mask for first level of length codes */
72221b1638SMasahiro Yamada     unsigned dmask;             /* mask for first level of distance codes */
73*a194255dSDaniel Boulby     code const *here;           /* retrieved table entry */
74221b1638SMasahiro Yamada     unsigned op;                /* code bits, operation, extra bits, or */
75221b1638SMasahiro Yamada                                 /*  window position, window bytes to copy */
76221b1638SMasahiro Yamada     unsigned len;               /* match length, unused bytes */
77221b1638SMasahiro Yamada     unsigned dist;              /* match distance */
78221b1638SMasahiro Yamada     unsigned char FAR *from;    /* where to copy match from */
79221b1638SMasahiro Yamada 
80221b1638SMasahiro Yamada     /* copy state to local variables */
81221b1638SMasahiro Yamada     state = (struct inflate_state FAR *)strm->state;
82221b1638SMasahiro Yamada     in = strm->next_in;
83221b1638SMasahiro Yamada     last = in + (strm->avail_in - 5);
84221b1638SMasahiro Yamada     out = strm->next_out;
85221b1638SMasahiro Yamada     beg = out - (start - strm->avail_out);
86221b1638SMasahiro Yamada     end = out + (strm->avail_out - 257);
87221b1638SMasahiro Yamada #ifdef INFLATE_STRICT
88221b1638SMasahiro Yamada     dmax = state->dmax;
89221b1638SMasahiro Yamada #endif
90221b1638SMasahiro Yamada     wsize = state->wsize;
91221b1638SMasahiro Yamada     whave = state->whave;
92221b1638SMasahiro Yamada     wnext = state->wnext;
93221b1638SMasahiro Yamada     window = state->window;
94221b1638SMasahiro Yamada     hold = state->hold;
95221b1638SMasahiro Yamada     bits = state->bits;
96221b1638SMasahiro Yamada     lcode = state->lencode;
97221b1638SMasahiro Yamada     dcode = state->distcode;
98221b1638SMasahiro Yamada     lmask = (1U << state->lenbits) - 1;
99221b1638SMasahiro Yamada     dmask = (1U << state->distbits) - 1;
100221b1638SMasahiro Yamada 
101221b1638SMasahiro Yamada     /* decode literals and length/distances until end-of-block or not enough
102221b1638SMasahiro Yamada        input data or output space */
103221b1638SMasahiro Yamada     do {
104221b1638SMasahiro Yamada         if (bits < 15) {
105221b1638SMasahiro Yamada             hold += (unsigned long)(*in++) << bits;
106221b1638SMasahiro Yamada             bits += 8;
107221b1638SMasahiro Yamada             hold += (unsigned long)(*in++) << bits;
108221b1638SMasahiro Yamada             bits += 8;
109221b1638SMasahiro Yamada         }
110*a194255dSDaniel Boulby         here = lcode + (hold & lmask);
111221b1638SMasahiro Yamada       dolen:
112*a194255dSDaniel Boulby         op = (unsigned)(here->bits);
113221b1638SMasahiro Yamada         hold >>= op;
114221b1638SMasahiro Yamada         bits -= op;
115*a194255dSDaniel Boulby         op = (unsigned)(here->op);
116221b1638SMasahiro Yamada         if (op == 0) {                          /* literal */
117*a194255dSDaniel Boulby             Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
118221b1638SMasahiro Yamada                     "inflate:         literal '%c'\n" :
119*a194255dSDaniel Boulby                     "inflate:         literal 0x%02x\n", here->val));
120*a194255dSDaniel Boulby             *out++ = (unsigned char)(here->val);
121221b1638SMasahiro Yamada         }
122221b1638SMasahiro Yamada         else if (op & 16) {                     /* length base */
123*a194255dSDaniel Boulby             len = (unsigned)(here->val);
124221b1638SMasahiro Yamada             op &= 15;                           /* number of extra bits */
125221b1638SMasahiro Yamada             if (op) {
126221b1638SMasahiro Yamada                 if (bits < op) {
127221b1638SMasahiro Yamada                     hold += (unsigned long)(*in++) << bits;
128221b1638SMasahiro Yamada                     bits += 8;
129221b1638SMasahiro Yamada                 }
130221b1638SMasahiro Yamada                 len += (unsigned)hold & ((1U << op) - 1);
131221b1638SMasahiro Yamada                 hold >>= op;
132221b1638SMasahiro Yamada                 bits -= op;
133221b1638SMasahiro Yamada             }
134221b1638SMasahiro Yamada             Tracevv((stderr, "inflate:         length %u\n", len));
135221b1638SMasahiro Yamada             if (bits < 15) {
136221b1638SMasahiro Yamada                 hold += (unsigned long)(*in++) << bits;
137221b1638SMasahiro Yamada                 bits += 8;
138221b1638SMasahiro Yamada                 hold += (unsigned long)(*in++) << bits;
139221b1638SMasahiro Yamada                 bits += 8;
140221b1638SMasahiro Yamada             }
141*a194255dSDaniel Boulby             here = dcode + (hold & dmask);
142221b1638SMasahiro Yamada           dodist:
143*a194255dSDaniel Boulby             op = (unsigned)(here->bits);
144221b1638SMasahiro Yamada             hold >>= op;
145221b1638SMasahiro Yamada             bits -= op;
146*a194255dSDaniel Boulby             op = (unsigned)(here->op);
147221b1638SMasahiro Yamada             if (op & 16) {                      /* distance base */
148*a194255dSDaniel Boulby                 dist = (unsigned)(here->val);
149221b1638SMasahiro Yamada                 op &= 15;                       /* number of extra bits */
150221b1638SMasahiro Yamada                 if (bits < op) {
151221b1638SMasahiro Yamada                     hold += (unsigned long)(*in++) << bits;
152221b1638SMasahiro Yamada                     bits += 8;
153221b1638SMasahiro Yamada                     if (bits < op) {
154221b1638SMasahiro Yamada                         hold += (unsigned long)(*in++) << bits;
155221b1638SMasahiro Yamada                         bits += 8;
156221b1638SMasahiro Yamada                     }
157221b1638SMasahiro Yamada                 }
158221b1638SMasahiro Yamada                 dist += (unsigned)hold & ((1U << op) - 1);
159221b1638SMasahiro Yamada #ifdef INFLATE_STRICT
160221b1638SMasahiro Yamada                 if (dist > dmax) {
161221b1638SMasahiro Yamada                     strm->msg = (char *)"invalid distance too far back";
162221b1638SMasahiro Yamada                     state->mode = BAD;
163221b1638SMasahiro Yamada                     break;
164221b1638SMasahiro Yamada                 }
165221b1638SMasahiro Yamada #endif
166221b1638SMasahiro Yamada                 hold >>= op;
167221b1638SMasahiro Yamada                 bits -= op;
168221b1638SMasahiro Yamada                 Tracevv((stderr, "inflate:         distance %u\n", dist));
169221b1638SMasahiro Yamada                 op = (unsigned)(out - beg);     /* max distance in output */
170221b1638SMasahiro Yamada                 if (dist > op) {                /* see if copy from window */
171221b1638SMasahiro Yamada                     op = dist - op;             /* distance back in window */
172221b1638SMasahiro Yamada                     if (op > whave) {
173221b1638SMasahiro Yamada                         if (state->sane) {
174221b1638SMasahiro Yamada                             strm->msg =
175221b1638SMasahiro Yamada                                 (char *)"invalid distance too far back";
176221b1638SMasahiro Yamada                             state->mode = BAD;
177221b1638SMasahiro Yamada                             break;
178221b1638SMasahiro Yamada                         }
179221b1638SMasahiro Yamada #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
180221b1638SMasahiro Yamada                         if (len <= op - whave) {
181221b1638SMasahiro Yamada                             do {
182221b1638SMasahiro Yamada                                 *out++ = 0;
183221b1638SMasahiro Yamada                             } while (--len);
184221b1638SMasahiro Yamada                             continue;
185221b1638SMasahiro Yamada                         }
186221b1638SMasahiro Yamada                         len -= op - whave;
187221b1638SMasahiro Yamada                         do {
188221b1638SMasahiro Yamada                             *out++ = 0;
189221b1638SMasahiro Yamada                         } while (--op > whave);
190221b1638SMasahiro Yamada                         if (op == 0) {
191221b1638SMasahiro Yamada                             from = out - dist;
192221b1638SMasahiro Yamada                             do {
193221b1638SMasahiro Yamada                                 *out++ = *from++;
194221b1638SMasahiro Yamada                             } while (--len);
195221b1638SMasahiro Yamada                             continue;
196221b1638SMasahiro Yamada                         }
197221b1638SMasahiro Yamada #endif
198221b1638SMasahiro Yamada                     }
199221b1638SMasahiro Yamada                     from = window;
200221b1638SMasahiro Yamada                     if (wnext == 0) {           /* very common case */
201221b1638SMasahiro Yamada                         from += wsize - op;
202221b1638SMasahiro Yamada                         if (op < len) {         /* some from window */
203221b1638SMasahiro Yamada                             len -= op;
204221b1638SMasahiro Yamada                             do {
205221b1638SMasahiro Yamada                                 *out++ = *from++;
206221b1638SMasahiro Yamada                             } while (--op);
207221b1638SMasahiro Yamada                             from = out - dist;  /* rest from output */
208221b1638SMasahiro Yamada                         }
209221b1638SMasahiro Yamada                     }
210221b1638SMasahiro Yamada                     else if (wnext < op) {      /* wrap around window */
211221b1638SMasahiro Yamada                         from += wsize + wnext - op;
212221b1638SMasahiro Yamada                         op -= wnext;
213221b1638SMasahiro Yamada                         if (op < len) {         /* some from end of window */
214221b1638SMasahiro Yamada                             len -= op;
215221b1638SMasahiro Yamada                             do {
216221b1638SMasahiro Yamada                                 *out++ = *from++;
217221b1638SMasahiro Yamada                             } while (--op);
218221b1638SMasahiro Yamada                             from = window;
219221b1638SMasahiro Yamada                             if (wnext < len) {  /* some from start of window */
220221b1638SMasahiro Yamada                                 op = wnext;
221221b1638SMasahiro Yamada                                 len -= op;
222221b1638SMasahiro Yamada                                 do {
223221b1638SMasahiro Yamada                                     *out++ = *from++;
224221b1638SMasahiro Yamada                                 } while (--op);
225221b1638SMasahiro Yamada                                 from = out - dist;      /* rest from output */
226221b1638SMasahiro Yamada                             }
227221b1638SMasahiro Yamada                         }
228221b1638SMasahiro Yamada                     }
229221b1638SMasahiro Yamada                     else {                      /* contiguous in window */
230221b1638SMasahiro Yamada                         from += wnext - op;
231221b1638SMasahiro Yamada                         if (op < len) {         /* some from window */
232221b1638SMasahiro Yamada                             len -= op;
233221b1638SMasahiro Yamada                             do {
234221b1638SMasahiro Yamada                                 *out++ = *from++;
235221b1638SMasahiro Yamada                             } while (--op);
236221b1638SMasahiro Yamada                             from = out - dist;  /* rest from output */
237221b1638SMasahiro Yamada                         }
238221b1638SMasahiro Yamada                     }
239221b1638SMasahiro Yamada                     while (len > 2) {
240221b1638SMasahiro Yamada                         *out++ = *from++;
241221b1638SMasahiro Yamada                         *out++ = *from++;
242221b1638SMasahiro Yamada                         *out++ = *from++;
243221b1638SMasahiro Yamada                         len -= 3;
244221b1638SMasahiro Yamada                     }
245221b1638SMasahiro Yamada                     if (len) {
246221b1638SMasahiro Yamada                         *out++ = *from++;
247221b1638SMasahiro Yamada                         if (len > 1)
248221b1638SMasahiro Yamada                             *out++ = *from++;
249221b1638SMasahiro Yamada                     }
250221b1638SMasahiro Yamada                 }
251221b1638SMasahiro Yamada                 else {
252221b1638SMasahiro Yamada                     from = out - dist;          /* copy direct from output */
253221b1638SMasahiro Yamada                     do {                        /* minimum length is three */
254221b1638SMasahiro Yamada                         *out++ = *from++;
255221b1638SMasahiro Yamada                         *out++ = *from++;
256221b1638SMasahiro Yamada                         *out++ = *from++;
257221b1638SMasahiro Yamada                         len -= 3;
258221b1638SMasahiro Yamada                     } while (len > 2);
259221b1638SMasahiro Yamada                     if (len) {
260221b1638SMasahiro Yamada                         *out++ = *from++;
261221b1638SMasahiro Yamada                         if (len > 1)
262221b1638SMasahiro Yamada                             *out++ = *from++;
263221b1638SMasahiro Yamada                     }
264221b1638SMasahiro Yamada                 }
265221b1638SMasahiro Yamada             }
266221b1638SMasahiro Yamada             else if ((op & 64) == 0) {          /* 2nd level distance code */
267*a194255dSDaniel Boulby                 here = dcode + here->val + (hold & ((1U << op) - 1));
268221b1638SMasahiro Yamada                 goto dodist;
269221b1638SMasahiro Yamada             }
270221b1638SMasahiro Yamada             else {
271221b1638SMasahiro Yamada                 strm->msg = (char *)"invalid distance code";
272221b1638SMasahiro Yamada                 state->mode = BAD;
273221b1638SMasahiro Yamada                 break;
274221b1638SMasahiro Yamada             }
275221b1638SMasahiro Yamada         }
276221b1638SMasahiro Yamada         else if ((op & 64) == 0) {              /* 2nd level length code */
277*a194255dSDaniel Boulby             here = lcode + here->val + (hold & ((1U << op) - 1));
278221b1638SMasahiro Yamada             goto dolen;
279221b1638SMasahiro Yamada         }
280221b1638SMasahiro Yamada         else if (op & 32) {                     /* end-of-block */
281221b1638SMasahiro Yamada             Tracevv((stderr, "inflate:         end of block\n"));
282221b1638SMasahiro Yamada             state->mode = TYPE;
283221b1638SMasahiro Yamada             break;
284221b1638SMasahiro Yamada         }
285221b1638SMasahiro Yamada         else {
286221b1638SMasahiro Yamada             strm->msg = (char *)"invalid literal/length code";
287221b1638SMasahiro Yamada             state->mode = BAD;
288221b1638SMasahiro Yamada             break;
289221b1638SMasahiro Yamada         }
290221b1638SMasahiro Yamada     } while (in < last && out < end);
291221b1638SMasahiro Yamada 
292221b1638SMasahiro Yamada     /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
293221b1638SMasahiro Yamada     len = bits >> 3;
294221b1638SMasahiro Yamada     in -= len;
295221b1638SMasahiro Yamada     bits -= len << 3;
296221b1638SMasahiro Yamada     hold &= (1U << bits) - 1;
297221b1638SMasahiro Yamada 
298221b1638SMasahiro Yamada     /* update state and return */
299221b1638SMasahiro Yamada     strm->next_in = in;
300221b1638SMasahiro Yamada     strm->next_out = out;
301221b1638SMasahiro Yamada     strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
302221b1638SMasahiro Yamada     strm->avail_out = (unsigned)(out < end ?
303221b1638SMasahiro Yamada                                  257 + (end - out) : 257 - (out - end));
304221b1638SMasahiro Yamada     state->hold = hold;
305221b1638SMasahiro Yamada     state->bits = bits;
306221b1638SMasahiro Yamada     return;
307221b1638SMasahiro Yamada }
308221b1638SMasahiro Yamada 
309221b1638SMasahiro Yamada /*
310221b1638SMasahiro Yamada    inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
311221b1638SMasahiro Yamada    - Using bit fields for code structure
312221b1638SMasahiro Yamada    - Different op definition to avoid & for extra bits (do & for table bits)
313221b1638SMasahiro Yamada    - Three separate decoding do-loops for direct, window, and wnext == 0
314221b1638SMasahiro Yamada    - Special case for distance > 1 copies to do overlapped load and store copy
315221b1638SMasahiro Yamada    - Explicit branch predictions (based on measured branch probabilities)
316221b1638SMasahiro Yamada    - Deferring match copy and interspersed it with decoding subsequent codes
317221b1638SMasahiro Yamada    - Swapping literal/length else
318221b1638SMasahiro Yamada    - Swapping window/direct else
319221b1638SMasahiro Yamada    - Larger unrolled copy loops (three is about right)
320221b1638SMasahiro Yamada    - Moving len -= 3 statement into middle of loop
321221b1638SMasahiro Yamada  */
322221b1638SMasahiro Yamada 
323221b1638SMasahiro Yamada #endif /* !ASMINF */
324