inffast.c 13.8 KB
Newer Older
1 2 3 4 5
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
6
 * published by the Free Software Foundation.  Oracle designates this
7
 * particular file as subject to the "Classpath" exception as provided
8
 * by Oracle in the LICENSE file that accompanied this code.
9 10 11 12 13 14 15 16 17 18 19
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
20 21 22
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
23 24 25
 */

/* inffast.c -- fast decoding
C
coffeys 已提交
26
 * Copyright (C) 1995-2017 Mark Adler
27 28 29 30 31 32 33 34
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"

C
coffeys 已提交
35 36
#ifdef ASMINF
#  pragma message("Assembler code may have bugs -- use at your own risk")
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
#else

/*
   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.

   Entry assumptions:

        state->mode == LEN
        strm->avail_in >= 6
        strm->avail_out >= 258
        start >= strm->avail_out
        state->bits < 8

   On return, state->mode is one of:

        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

   Notes:

    - 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.
 */
74
void ZLIB_INTERNAL inflate_fast(strm, start)
75 76 77 78
z_streamp strm;
unsigned start;         /* inflate()'s starting value for strm->avail_out */
{
    struct inflate_state FAR *state;
79 80
    z_const unsigned char FAR *in;      /* local strm->next_in */
    z_const unsigned char FAR *last;    /* have enough input while in < last */
81 82 83 84 85 86 87 88
    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 */
#ifdef INFLATE_STRICT
    unsigned dmax;              /* maximum distance from zlib header */
#endif
    unsigned wsize;             /* window size or zero if not using window */
    unsigned whave;             /* valid bytes in the window */
89
    unsigned wnext;             /* window write index */
90 91 92 93 94 95 96
    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 */
97
    code here;                  /* retrieved table entry */
98 99 100 101 102 103 104 105
    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 */

    /* copy state to local variables */
    state = (struct inflate_state FAR *)strm->state;
C
coffeys 已提交
106
    in = strm->next_in;
107
    last = in + (strm->avail_in - 5);
C
coffeys 已提交
108
    out = strm->next_out;
109 110 111 112 113 114 115
    beg = out - (start - strm->avail_out);
    end = out + (strm->avail_out - 257);
#ifdef INFLATE_STRICT
    dmax = state->dmax;
#endif
    wsize = state->wsize;
    whave = state->whave;
116
    wnext = state->wnext;
117 118 119 120 121 122 123 124 125 126 127 128
    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;

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

    /* update state and return */
C
coffeys 已提交
323 324
    strm->next_in = in;
    strm->next_out = out;
325 326 327 328 329 330 331 332 333 334 335 336
    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;
}

/*
   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)
337
   - Three separate decoding do-loops for direct, window, and wnext == 0
338 339 340 341 342 343 344 345 346 347
   - 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
 */

#endif /* !ASMINF */