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