inffast.c 13.1 KB
Newer Older
M
Mark Adler 已提交
1
/* inffast.c -- fast decoding
M
Mark Adler 已提交
2
 * Copyright (C) 1995-2008, 2010 Mark Adler
M
Mark Adler 已提交
3
 * For conditions of distribution and use, see copyright notice in zlib.h
M
Mark Adler 已提交
4 5 6 7
 */

#include "zutil.h"
#include "inftrees.h"
M
Mark Adler 已提交
8
#include "inflate.h"
M
Mark Adler 已提交
9 10
#include "inffast.h"

M
Mark Adler 已提交
11 12
#ifndef ASMINF

M
Mark Adler 已提交
13 14 15 16 17 18 19 20 21
/* Allow machine dependent optimization for post-increment or pre-increment.
   Based on testing to date,
   Pre-increment preferred for:
   - PowerPC G3 (Adler)
   - MIPS R5000 (Randers-Pehrson)
   Post-increment preferred for:
   - none
   No measurable difference:
   - Pentium III (Anderson)
M
Mark Adler 已提交
22
   - M68060 (Nikl)
M
Mark Adler 已提交
23 24 25 26 27 28 29 30
 */
#ifdef POSTINC
#  define OFF 0
#  define PUP(a) *(a)++
#else
#  define OFF 1
#  define PUP(a) *++(a)
#endif
M
Mark Adler 已提交
31

M
Mark Adler 已提交
32 33 34 35 36 37 38
/*
   Decode literal, length, and distance codes and write out the resulting
   literal and match bytes until either not enough input or output is
   available, an end-of-block is encountered, or a data error is encountered.
   When large enough input and output buffers are supplied to inflate(), for
   example, a 16K input buffer and a 64K output buffer, more than 95% of the
   inflate execution time is spent in this routine.
M
Mark Adler 已提交
39

M
Mark Adler 已提交
40
   Entry assumptions:
M
Mark Adler 已提交
41

M
Mark Adler 已提交
42 43 44 45 46
        state->mode == LEN
        strm->avail_in >= 6
        strm->avail_out >= 258
        start >= strm->avail_out
        state->bits < 8
M
Mark Adler 已提交
47

M
Mark Adler 已提交
48
   On return, state->mode is one of:
M
Mark Adler 已提交
49

M
Mark Adler 已提交
50 51 52
        LEN -- ran out of enough output space or enough available input
        TYPE -- reached end of block code, inflate() to interpret next block
        BAD -- error in block data
M
Mark Adler 已提交
53

M
Mark Adler 已提交
54
   Notes:
M
Mark Adler 已提交
55

M
Mark Adler 已提交
56 57 58 59 60 61 62 63 64 65 66
    - The maximum input bits used by a length/distance pair is 15 bits for the
      length code, 5 bits for the length extra, 15 bits for the distance code,
      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
      Therefore if strm->avail_in >= 6, then there is enough input to avoid
      checking for available input while decoding.

    - The maximum bytes that a single length/distance pair can output is 258
      bytes, which is the maximum length that can be coded.  inflate_fast()
      requires strm->avail_out >= 258 for each loop to avoid checking for
      output space.
 */
M
Mark Adler 已提交
67
void ZLIB_INTERNAL inflate_fast(strm, start)
M
Mark Adler 已提交
68 69 70 71 72 73 74 75 76
z_streamp strm;
unsigned start;         /* inflate()'s starting value for strm->avail_out */
{
    struct inflate_state FAR *state;
    unsigned char FAR *in;      /* local strm->next_in */
    unsigned char FAR *last;    /* while in < last, enough input available */
    unsigned char FAR *out;     /* local strm->next_out */
    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
    unsigned char FAR *end;     /* while out < end, enough space available */
M
Mark Adler 已提交
77 78 79
#ifdef INFLATE_STRICT
    unsigned dmax;              /* maximum distance from zlib header */
#endif
M
Mark Adler 已提交
80
    unsigned wsize;             /* window size or zero if not using window */
M
Mark Adler 已提交
81
    unsigned whave;             /* valid bytes in the window */
M
Mark Adler 已提交
82
    unsigned wnext;             /* window write index */
M
Mark Adler 已提交
83 84 85 86 87 88 89
    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
    unsigned long hold;         /* local strm->hold */
    unsigned bits;              /* local strm->bits */
    code const FAR *lcode;      /* local strm->lencode */
    code const FAR *dcode;      /* local strm->distcode */
    unsigned lmask;             /* mask for first level of length codes */
    unsigned dmask;             /* mask for first level of distance codes */
M
Mark Adler 已提交
90
    code here;                  /* retrieved table entry */
M
Mark Adler 已提交
91 92 93 94 95
    unsigned op;                /* code bits, operation, extra bits, or */
                                /*  window position, window bytes to copy */
    unsigned len;               /* match length, unused bytes */
    unsigned dist;              /* match distance */
    unsigned char FAR *from;    /* where to copy match from */
M
Mark Adler 已提交
96

M
Mark Adler 已提交
97 98 99 100 101 102 103
    /* copy state to local variables */
    state = (struct inflate_state FAR *)strm->state;
    in = strm->next_in - OFF;
    last = in + (strm->avail_in - 5);
    out = strm->next_out - OFF;
    beg = out - (start - strm->avail_out);
    end = out + (strm->avail_out - 257);
M
Mark Adler 已提交
104 105 106
#ifdef INFLATE_STRICT
    dmax = state->dmax;
#endif
M
Mark Adler 已提交
107
    wsize = state->wsize;
M
Mark Adler 已提交
108
    whave = state->whave;
M
Mark Adler 已提交
109
    wnext = state->wnext;
M
Mark Adler 已提交
110 111 112 113 114 115 116
    window = state->window;
    hold = state->hold;
    bits = state->bits;
    lcode = state->lencode;
    dcode = state->distcode;
    lmask = (1U << state->lenbits) - 1;
    dmask = (1U << state->distbits) - 1;
M
Mark Adler 已提交
117

M
Mark Adler 已提交
118 119 120 121 122 123 124 125 126
    /* decode literals and length/distances until end-of-block or not enough
       input data or output space */
    do {
        if (bits < 15) {
            hold += (unsigned long)(PUP(in)) << bits;
            bits += 8;
            hold += (unsigned long)(PUP(in)) << bits;
            bits += 8;
        }
M
Mark Adler 已提交
127
        here = lcode[hold & lmask];
M
Mark Adler 已提交
128
      dolen:
M
Mark Adler 已提交
129
        op = (unsigned)(here.bits);
M
Mark Adler 已提交
130 131
        hold >>= op;
        bits -= op;
M
Mark Adler 已提交
132
        op = (unsigned)(here.op);
M
Mark Adler 已提交
133
        if (op == 0) {                          /* literal */
M
Mark Adler 已提交
134
            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
M
Mark Adler 已提交
135
                    "inflate:         literal '%c'\n" :
M
Mark Adler 已提交
136 137
                    "inflate:         literal 0x%02x\n", here.val));
            PUP(out) = (unsigned char)(here.val);
M
Mark Adler 已提交
138 139
        }
        else if (op & 16) {                     /* length base */
M
Mark Adler 已提交
140
            len = (unsigned)(here.val);
M
Mark Adler 已提交
141 142 143 144 145 146
            op &= 15;                           /* number of extra bits */
            if (op) {
                if (bits < op) {
                    hold += (unsigned long)(PUP(in)) << bits;
                    bits += 8;
                }
M
Mark Adler 已提交
147
                len += (unsigned)hold & ((1U << op) - 1);
M
Mark Adler 已提交
148 149 150 151 152 153 154 155 156
                hold >>= op;
                bits -= op;
            }
            Tracevv((stderr, "inflate:         length %u\n", len));
            if (bits < 15) {
                hold += (unsigned long)(PUP(in)) << bits;
                bits += 8;
                hold += (unsigned long)(PUP(in)) << bits;
                bits += 8;
M
Mark Adler 已提交
157
            }
M
Mark Adler 已提交
158
            here = dcode[hold & dmask];
M
Mark Adler 已提交
159
          dodist:
M
Mark Adler 已提交
160
            op = (unsigned)(here.bits);
M
Mark Adler 已提交
161 162
            hold >>= op;
            bits -= op;
M
Mark Adler 已提交
163
            op = (unsigned)(here.op);
M
Mark Adler 已提交
164
            if (op & 16) {                      /* distance base */
M
Mark Adler 已提交
165
                dist = (unsigned)(here.val);
M
Mark Adler 已提交
166 167 168 169 170 171 172 173 174
                op &= 15;                       /* number of extra bits */
                if (bits < op) {
                    hold += (unsigned long)(PUP(in)) << bits;
                    bits += 8;
                    if (bits < op) {
                        hold += (unsigned long)(PUP(in)) << bits;
                        bits += 8;
                    }
                }
M
Mark Adler 已提交
175
                dist += (unsigned)hold & ((1U << op) - 1);
M
Mark Adler 已提交
176 177 178 179 180 181 182
#ifdef INFLATE_STRICT
                if (dist > dmax) {
                    strm->msg = (char *)"invalid distance too far back";
                    state->mode = BAD;
                    break;
                }
#endif
M
Mark Adler 已提交
183 184 185 186 187
                hold >>= op;
                bits -= op;
                Tracevv((stderr, "inflate:         distance %u\n", dist));
                op = (unsigned)(out - beg);     /* max distance in output */
                if (dist > op) {                /* see if copy from window */
M
Mark Adler 已提交
188 189
                    op = dist - op;             /* distance back in window */
                    if (op > whave) {
M
Mark Adler 已提交
190
                        if (state->sane) {
M
Mark Adler 已提交
191 192
                            strm->msg =
                                (char *)"invalid distance too far back";
M
Mark Adler 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
                            state->mode = BAD;
                            break;
                        }
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
                        if (len <= op - whave) {
                            do {
                                PUP(out) = 0;
                            } while (--len);
                            continue;
                        }
                        len -= op - whave;
                        do {
                            PUP(out) = 0;
                        } while (--op > whave);
                        if (op == 0) {
                            from = out - dist;
                            do {
                                PUP(out) = PUP(from);
                            } while (--len);
                            continue;
                        }
#endif
M
Mark Adler 已提交
215 216
                    }
                    from = window - OFF;
M
Mark Adler 已提交
217
                    if (wnext == 0) {           /* very common case */
M
Mark Adler 已提交
218 219 220 221 222 223 224 225 226
                        from += wsize - op;
                        if (op < len) {         /* some from window */
                            len -= op;
                            do {
                                PUP(out) = PUP(from);
                            } while (--op);
                            from = out - dist;  /* rest from output */
                        }
                    }
M
Mark Adler 已提交
227 228 229
                    else if (wnext < op) {      /* wrap around window */
                        from += wsize + wnext - op;
                        op -= wnext;
M
Mark Adler 已提交
230 231 232 233 234 235
                        if (op < len) {         /* some from end of window */
                            len -= op;
                            do {
                                PUP(out) = PUP(from);
                            } while (--op);
                            from = window - OFF;
M
Mark Adler 已提交
236 237
                            if (wnext < len) {  /* some from start of window */
                                op = wnext;
M
Mark Adler 已提交
238 239 240 241 242 243 244 245 246
                                len -= op;
                                do {
                                    PUP(out) = PUP(from);
                                } while (--op);
                                from = out - dist;      /* rest from output */
                            }
                        }
                    }
                    else {                      /* contiguous in window */
M
Mark Adler 已提交
247
                        from += wnext - op;
M
Mark Adler 已提交
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
                        if (op < len) {         /* some from window */
                            len -= op;
                            do {
                                PUP(out) = PUP(from);
                            } while (--op);
                            from = out - dist;  /* rest from output */
                        }
                    }
                    while (len > 2) {
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        len -= 3;
                    }
                    if (len) {
                        PUP(out) = PUP(from);
                        if (len > 1)
                            PUP(out) = PUP(from);
                    }
                }
                else {
                    from = out - dist;          /* copy direct from output */
                    do {                        /* minimum length is three */
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        PUP(out) = PUP(from);
                        len -= 3;
                    } while (len > 2);
                    if (len) {
                        PUP(out) = PUP(from);
                        if (len > 1)
                            PUP(out) = PUP(from);
                    }
                }
M
Mark Adler 已提交
282
            }
M
Mark Adler 已提交
283
            else if ((op & 64) == 0) {          /* 2nd level distance code */
M
Mark Adler 已提交
284
                here = dcode[here.val + (hold & ((1U << op) - 1))];
M
Mark Adler 已提交
285 286 287 288 289 290 291 292 293
                goto dodist;
            }
            else {
                strm->msg = (char *)"invalid distance code";
                state->mode = BAD;
                break;
            }
        }
        else if ((op & 64) == 0) {              /* 2nd level length code */
M
Mark Adler 已提交
294
            here = lcode[here.val + (hold & ((1U << op) - 1))];
M
Mark Adler 已提交
295 296 297 298 299
            goto dolen;
        }
        else if (op & 32) {                     /* end-of-block */
            Tracevv((stderr, "inflate:         end of block\n"));
            state->mode = TYPE;
M
Mark Adler 已提交
300
            break;
M
Mark Adler 已提交
301
        }
M
Mark Adler 已提交
302 303 304 305 306 307 308 309 310 311 312 313
        else {
            strm->msg = (char *)"invalid literal/length code";
            state->mode = BAD;
            break;
        }
    } while (in < last && out < end);

    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
    len = bits >> 3;
    in -= len;
    bits -= len << 3;
    hold &= (1U << bits) - 1;
M
Mark Adler 已提交
314

M
Mark Adler 已提交
315 316 317 318 319 320 321 322 323
    /* update state and return */
    strm->next_in = in + OFF;
    strm->next_out = out + OFF;
    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
    strm->avail_out = (unsigned)(out < end ?
                                 257 + (end - out) : 257 - (out - end));
    state->hold = hold;
    state->bits = bits;
    return;
M
Mark Adler 已提交
324
}
M
Mark Adler 已提交
325 326 327 328 329

/*
   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
   - Using bit fields for code structure
   - Different op definition to avoid & for extra bits (do & for table bits)
M
Mark Adler 已提交
330
   - Three separate decoding do-loops for direct, window, and wnext == 0
M
Mark Adler 已提交
331 332 333 334 335 336 337 338
   - Special case for distance > 1 copies to do overlapped load and store copy
   - Explicit branch predictions (based on measured branch probabilities)
   - Deferring match copy and interspersed it with decoding subsequent codes
   - Swapping literal/length else
   - Swapping window/direct else
   - Larger unrolled copy loops (three is about right)
   - Moving len -= 3 statement into middle of loop
 */
M
Mark Adler 已提交
339 340

#endif /* !ASMINF */