inffast.c revision 347244
1203134Sthompsa/* inffast.c -- fast decoding
2203134Sthompsa * Copyright (C) 1995-2017 Mark Adler
3203134Sthompsa * For conditions of distribution and use, see copyright notice in zlib.h
4203134Sthompsa */
5203134Sthompsa
6203134Sthompsa#include "zutil.h"
7203134Sthompsa#include "inftrees.h"
8203134Sthompsa#include "inflate.h"
9203134Sthompsa#include "inffast.h"
10203134Sthompsa
11203134Sthompsa#ifdef ASMINF
12203134Sthompsa#  pragma message("Assembler code may have bugs -- use at your own risk")
13203134Sthompsa#else
14203134Sthompsa
15203134Sthompsa/*
16203134Sthompsa   Decode literal, length, and distance codes and write out the resulting
17203134Sthompsa   literal and match bytes until either not enough input or output is
18203134Sthompsa   available, an end-of-block is encountered, or a data error is encountered.
19203134Sthompsa   When large enough input and output buffers are supplied to inflate(), for
20203134Sthompsa   example, a 16K input buffer and a 64K output buffer, more than 95% of the
21203134Sthompsa   inflate execution time is spent in this routine.
22203134Sthompsa
23203134Sthompsa   Entry assumptions:
24203134Sthompsa
25259546Skevlo        state->mode == LEN
26259546Skevlo        strm->avail_in >= 6
27203134Sthompsa        strm->avail_out >= 258
28259546Skevlo        start >= strm->avail_out
29203134Sthompsa        state->bits < 8
30203134Sthompsa
31259546Skevlo   On return, state->mode is one of:
32259546Skevlo
33259546Skevlo        LEN -- ran out of enough output space or enough available input
34259546Skevlo        TYPE -- reached end of block code, inflate() to interpret next block
35259546Skevlo        BAD -- error in block data
36259546Skevlo
37259546Skevlo   Notes:
38259546Skevlo
39259546Skevlo    - The maximum input bits used by a length/distance pair is 15 bits for the
40259546Skevlo      length code, 5 bits for the length extra, 15 bits for the distance code,
41259546Skevlo      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
42259546Skevlo      Therefore if strm->avail_in >= 6, then there is enough input to avoid
43259546Skevlo      checking for available input while decoding.
44259546Skevlo
45259546Skevlo    - The maximum bytes that a single length/distance pair can output is 258
46259546Skevlo      bytes, which is the maximum length that can be coded.  inflate_fast()
47259546Skevlo      requires strm->avail_out >= 258 for each loop to avoid checking for
48259546Skevlo      output space.
49259546Skevlo */
50259546Skevlovoid ZLIB_INTERNAL inflate_fast(strm, start)
51259546Skevloz_streamp strm;
52259546Skevlounsigned start;         /* inflate()'s starting value for strm->avail_out */
53203134Sthompsa{
54203134Sthompsa    struct inflate_state FAR *state;
55259546Skevlo    z_const unsigned char FAR *in;      /* local strm->next_in */
56259546Skevlo    z_const unsigned char FAR *last;    /* have enough input while in < last */
57259546Skevlo    unsigned char FAR *out;     /* local strm->next_out */
58259546Skevlo    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
59259546Skevlo    unsigned char FAR *end;     /* while out < end, enough space available */
60259546Skevlo#ifdef INFLATE_STRICT
61259546Skevlo    unsigned dmax;              /* maximum distance from zlib header */
62259546Skevlo#endif
63259546Skevlo    unsigned wsize;             /* window size or zero if not using window */
64259546Skevlo    unsigned whave;             /* valid bytes in the window */
65259546Skevlo    unsigned wnext;             /* window write index */
66259546Skevlo    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
67259546Skevlo    unsigned long hold;         /* local strm->hold */
68259546Skevlo    unsigned bits;              /* local strm->bits */
69259546Skevlo    code const FAR *lcode;      /* local strm->lencode */
70203134Sthompsa    code const FAR *dcode;      /* local strm->distcode */
71203134Sthompsa    unsigned lmask;             /* mask for first level of length codes */
72259546Skevlo    unsigned dmask;             /* mask for first level of distance codes */
73259546Skevlo    code here;                  /* retrieved table entry */
74259546Skevlo    unsigned op;                /* code bits, operation, extra bits, or */
75259546Skevlo                                /*  window position, window bytes to copy */
76259546Skevlo    unsigned len;               /* match length, unused bytes */
77259546Skevlo    unsigned dist;              /* match distance */
78259546Skevlo    unsigned char FAR *from;    /* where to copy match from */
79259546Skevlo
80203134Sthompsa    /* copy state to local variables */
81259032Skevlo    state = (struct inflate_state FAR *)strm->state;
82259546Skevlo    in = strm->next_in;
83259032Skevlo    last = in + (strm->avail_in - 5);
84203134Sthompsa    out = strm->next_out;
85259546Skevlo    beg = out - (start - strm->avail_out);
86259546Skevlo    end = out + (strm->avail_out - 257);
87259546Skevlo#ifdef INFLATE_STRICT
88259546Skevlo    dmax = state->dmax;
89259546Skevlo#endif
90259546Skevlo    wsize = state->wsize;
91259546Skevlo    whave = state->whave;
92259546Skevlo    wnext = state->wnext;
93259546Skevlo    window = state->window;
94259546Skevlo    hold = state->hold;
95259546Skevlo    bits = state->bits;
96259546Skevlo    lcode = state->lencode;
97203134Sthompsa    dcode = state->distcode;
98203134Sthompsa    lmask = (1U << state->lenbits) - 1;
99259546Skevlo    dmask = (1U << state->distbits) - 1;
100203134Sthompsa
101203134Sthompsa    /* decode literals and length/distances until end-of-block or not enough
102259546Skevlo       input data or output space */
103259546Skevlo    do {
104259546Skevlo        if (bits < 15) {
105259546Skevlo            hold += (unsigned long)(*in++) << bits;
106259546Skevlo            bits += 8;
107259546Skevlo            hold += (unsigned long)(*in++) << bits;
108259546Skevlo            bits += 8;
109259546Skevlo        }
110259546Skevlo        here = lcode[hold & lmask];
111259546Skevlo      dolen:
112259546Skevlo        op = (unsigned)(here.bits);
113259546Skevlo        hold >>= op;
114259546Skevlo        bits -= op;
115203134Sthompsa        op = (unsigned)(here.op);
116203134Sthompsa        if (op == 0) {                          /* literal */
117259546Skevlo            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
118259546Skevlo                    "inflate:         literal '%c'\n" :
119259546Skevlo                    "inflate:         literal 0x%02x\n", here.val));
120203134Sthompsa            *out++ = (unsigned char)(here.val);
121203134Sthompsa        }
122259546Skevlo        else if (op & 16) {                     /* length base */
123259546Skevlo            len = (unsigned)(here.val);
124259546Skevlo            op &= 15;                           /* number of extra bits */
125259546Skevlo            if (op) {
126259546Skevlo                if (bits < op) {
127259546Skevlo                    hold += (unsigned long)(*in++) << bits;
128259546Skevlo                    bits += 8;
129259546Skevlo                }
130259546Skevlo                len += (unsigned)hold & ((1U << op) - 1);
131259546Skevlo                hold >>= op;
132259546Skevlo                bits -= op;
133259546Skevlo            }
134259546Skevlo            Tracevv((stderr, "inflate:         length %u\n", len));
135259546Skevlo            if (bits < 15) {
136259546Skevlo                hold += (unsigned long)(*in++) << bits;
137259546Skevlo                bits += 8;
138259546Skevlo                hold += (unsigned long)(*in++) << bits;
139259546Skevlo                bits += 8;
140259546Skevlo            }
141259546Skevlo            here = dcode[hold & dmask];
142259546Skevlo          dodist:
143259546Skevlo            op = (unsigned)(here.bits);
144259546Skevlo            hold >>= op;
145259546Skevlo            bits -= op;
146259546Skevlo            op = (unsigned)(here.op);
147259546Skevlo            if (op & 16) {                      /* distance base */
148203134Sthompsa                dist = (unsigned)(here.val);
149203134Sthompsa                op &= 15;                       /* number of extra bits */
150259546Skevlo                if (bits < op) {
151259546Skevlo                    hold += (unsigned long)(*in++) << bits;
152259546Skevlo                    bits += 8;
153259546Skevlo                    if (bits < op) {
154259546Skevlo                        hold += (unsigned long)(*in++) << bits;
155259546Skevlo                        bits += 8;
156259546Skevlo                    }
157203134Sthompsa                }
158203134Sthompsa                dist += (unsigned)hold & ((1U << op) - 1);
159259546Skevlo#ifdef INFLATE_STRICT
160259546Skevlo                if (dist > dmax) {
161259546Skevlo                    strm->msg = (char *)"invalid distance too far back";
162203134Sthompsa                    state->mode = BAD;
163203134Sthompsa                    break;
164259546Skevlo                }
165259546Skevlo#endif
166259546Skevlo                hold >>= op;
167259546Skevlo                bits -= op;
168259546Skevlo                Tracevv((stderr, "inflate:         distance %u\n", dist));
169259546Skevlo                op = (unsigned)(out - beg);     /* max distance in output */
170203134Sthompsa                if (dist > op) {                /* see if copy from window */
171203134Sthompsa                    op = dist - op;             /* distance back in window */
172259546Skevlo                    if (op > whave) {
173259546Skevlo                        if (state->sane) {
174259546Skevlo                            strm->msg =
175259546Skevlo                                (char *)"invalid distance too far back";
176259546Skevlo                            state->mode = BAD;
177259546Skevlo                            break;
178259546Skevlo                        }
179203134Sthompsa#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
180203134Sthompsa                        if (len <= op - whave) {
181259546Skevlo                            do {
182203134Sthompsa                                *out++ = 0;
183259546Skevlo                            } while (--len);
184259546Skevlo                            continue;
185203134Sthompsa                        }
186203134Sthompsa                        len -= op - whave;
187259546Skevlo                        do {
188203134Sthompsa                            *out++ = 0;
189203134Sthompsa                        } while (--op > whave);
190259546Skevlo                        if (op == 0) {
191203134Sthompsa                            from = out - dist;
192203134Sthompsa                            do {
193259546Skevlo                                *out++ = *from++;
194203134Sthompsa                            } while (--len);
195203134Sthompsa                            continue;
196259546Skevlo                        }
197203134Sthompsa#endif
198203134Sthompsa                    }
199259546Skevlo                    from = window;
200259546Skevlo                    if (wnext == 0) {           /* very common case */
201259546Skevlo                        from += wsize - op;
202259546Skevlo                        if (op < len) {         /* some from window */
203203134Sthompsa                            len -= op;
204203134Sthompsa                            do {
205259546Skevlo                                *out++ = *from++;
206259546Skevlo                            } while (--op);
207259546Skevlo                            from = out - dist;  /* rest from output */
208259546Skevlo                        }
209259546Skevlo                    }
210259546Skevlo                    else if (wnext < op) {      /* wrap around window */
211203134Sthompsa                        from += wsize + wnext - op;
212203134Sthompsa                        op -= wnext;
213203134Sthompsa                        if (op < len) {         /* some from end of window */
214259546Skevlo                            len -= op;
215259546Skevlo                            do {
216259546Skevlo                                *out++ = *from++;
217259546Skevlo                            } while (--op);
218259546Skevlo                            from = window;
219259546Skevlo                            if (wnext < len) {  /* some from start of window */
220203134Sthompsa                                op = wnext;
221203134Sthompsa                                len -= op;
222259546Skevlo                                do {
223259546Skevlo                                    *out++ = *from++;
224259546Skevlo                                } while (--op);
225259546Skevlo                                from = out - dist;      /* rest from output */
226259546Skevlo                            }
227259546Skevlo                        }
228259546Skevlo                    }
229259546Skevlo                    else {                      /* contiguous in window */
230259546Skevlo                        from += wnext - op;
231259546Skevlo                        if (op < len) {         /* some from window */
232259546Skevlo                            len -= op;
233259546Skevlo                            do {
234259546Skevlo                                *out++ = *from++;
235259546Skevlo                            } while (--op);
236259546Skevlo                            from = out - dist;  /* rest from output */
237259546Skevlo                        }
238259546Skevlo                    }
239259546Skevlo                    while (len > 2) {
240203134Sthompsa                        *out++ = *from++;
241203134Sthompsa                        *out++ = *from++;
242259546Skevlo                        *out++ = *from++;
243259546Skevlo                        len -= 3;
244259546Skevlo                    }
245259546Skevlo                    if (len) {
246259546Skevlo                        *out++ = *from++;
247259546Skevlo                        if (len > 1)
248259546Skevlo                            *out++ = *from++;
249259546Skevlo                    }
250259546Skevlo                }
251259546Skevlo                else {
252259546Skevlo                    from = out - dist;          /* copy direct from output */
253259546Skevlo                    do {                        /* minimum length is three */
254203134Sthompsa                        *out++ = *from++;
255203134Sthompsa                        *out++ = *from++;
256259546Skevlo                        *out++ = *from++;
257259546Skevlo                        len -= 3;
258259546Skevlo                    } while (len > 2);
259259546Skevlo                    if (len) {
260259546Skevlo                        *out++ = *from++;
261259546Skevlo                        if (len > 1)
262203134Sthompsa                            *out++ = *from++;
263203134Sthompsa                    }
264259546Skevlo                }
265259546Skevlo            }
266203134Sthompsa            else if ((op & 64) == 0) {          /* 2nd level distance code */
267203134Sthompsa                here = dcode[here.val + (hold & ((1U << op) - 1))];
268259546Skevlo                goto dodist;
269259546Skevlo            }
270259546Skevlo            else {
271259546Skevlo                strm->msg = (char *)"invalid distance code";
272259546Skevlo                state->mode = BAD;
273259546Skevlo                break;
274259546Skevlo            }
275259546Skevlo        }
276259546Skevlo        else if ((op & 64) == 0) {              /* 2nd level length code */
277259546Skevlo            here = lcode[here.val + (hold & ((1U << op) - 1))];
278259546Skevlo            goto dolen;
279203134Sthompsa        }
280203134Sthompsa        else if (op & 32) {                     /* end-of-block */
281259546Skevlo            Tracevv((stderr, "inflate:         end of block\n"));
282259546Skevlo            state->mode = TYPE;
283259546Skevlo            break;
284259546Skevlo        }
285203134Sthompsa        else {
286203134Sthompsa            strm->msg = (char *)"invalid literal/length code";
287259546Skevlo            state->mode = BAD;
288259546Skevlo            break;
289259546Skevlo        }
290259546Skevlo    } while (in < last && out < end);
291259546Skevlo
292259546Skevlo    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
293259546Skevlo    len = bits >> 3;
294259546Skevlo    in -= len;
295259546Skevlo    bits -= len << 3;
296259546Skevlo    hold &= (1U << bits) - 1;
297259546Skevlo
298259546Skevlo    /* update state and return */
299259546Skevlo    strm->next_in = in;
300203134Sthompsa    strm->next_out = out;
301203134Sthompsa    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
302259546Skevlo    strm->avail_out = (unsigned)(out < end ?
303259546Skevlo                                 257 + (end - out) : 257 - (out - end));
304259546Skevlo    state->hold = hold;
305259546Skevlo    state->bits = bits;
306259546Skevlo    return;
307259546Skevlo}
308259546Skevlo
309259546Skevlo/*
310259546Skevlo   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
311259546Skevlo   - Using bit fields for code structure
312259546Skevlo   - Different op definition to avoid & for extra bits (do & for table bits)
313203134Sthompsa   - Three separate decoding do-loops for direct, window, and wnext == 0
314203134Sthompsa   - Special case for distance > 1 copies to do overlapped load and store copy
315259546Skevlo   - Explicit branch predictions (based on measured branch probabilities)
316259546Skevlo   - Deferring match copy and interspersed it with decoding subsequent codes
317259546Skevlo   - Swapping literal/length else
318259546Skevlo   - Swapping window/direct else
319259546Skevlo   - Larger unrolled copy loops (three is about right)
320259546Skevlo   - Moving len -= 3 statement into middle of loop
321259546Skevlo */
322259546Skevlo
323259546Skevlo#endif /* !ASMINF */
324259546Skevlo