Blame zlib-src/inffast.c

Packit d03632
/* inffast.c -- fast decoding
Packit d03632
 * Copyright (C) 1995-2017 Mark Adler
Packit d03632
 * For conditions of distribution and use, see copyright notice in zlib.h
Packit d03632
 */
Packit d03632
Packit d03632
#include "zutil.h"
Packit d03632
#include "inftrees.h"
Packit d03632
#include "inflate.h"
Packit d03632
#include "inffast.h"
Packit d03632
Packit d03632
#ifdef ASMINF
Packit d03632
#  pragma message("Assembler code may have bugs -- use at your own risk")
Packit d03632
#else
Packit d03632
Packit d03632
/*
Packit d03632
   Decode literal, length, and distance codes and write out the resulting
Packit d03632
   literal and match bytes until either not enough input or output is
Packit d03632
   available, an end-of-block is encountered, or a data error is encountered.
Packit d03632
   When large enough input and output buffers are supplied to inflate(), for
Packit d03632
   example, a 16K input buffer and a 64K output buffer, more than 95% of the
Packit d03632
   inflate execution time is spent in this routine.
Packit d03632
Packit d03632
   Entry assumptions:
Packit d03632
Packit d03632
        state->mode == LEN
Packit d03632
        strm->avail_in >= 6
Packit d03632
        strm->avail_out >= 258
Packit d03632
        start >= strm->avail_out
Packit d03632
        state->bits < 8
Packit d03632
Packit d03632
   On return, state->mode is one of:
Packit d03632
Packit d03632
        LEN -- ran out of enough output space or enough available input
Packit d03632
        TYPE -- reached end of block code, inflate() to interpret next block
Packit d03632
        BAD -- error in block data
Packit d03632
Packit d03632
   Notes:
Packit d03632
Packit d03632
    - The maximum input bits used by a length/distance pair is 15 bits for the
Packit d03632
      length code, 5 bits for the length extra, 15 bits for the distance code,
Packit d03632
      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
Packit d03632
      Therefore if strm->avail_in >= 6, then there is enough input to avoid
Packit d03632
      checking for available input while decoding.
Packit d03632
Packit d03632
    - The maximum bytes that a single length/distance pair can output is 258
Packit d03632
      bytes, which is the maximum length that can be coded.  inflate_fast()
Packit d03632
      requires strm->avail_out >= 258 for each loop to avoid checking for
Packit d03632
      output space.
Packit d03632
 */
Packit d03632
void ZLIB_INTERNAL inflate_fast(
Packit d03632
    z_streamp strm,
Packit d03632
    unsigned start)
Packit d03632
{
Packit d03632
    struct inflate_state FAR *state;
Packit d03632
    z_const unsigned char FAR *in;      /* local strm->next_in */
Packit d03632
    z_const unsigned char FAR *last;    /* have enough input while in < last */
Packit d03632
    unsigned char FAR *out;     /* local strm->next_out */
Packit d03632
    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
Packit d03632
    unsigned char FAR *end;     /* while out < end, enough space available */
Packit d03632
#ifdef INFLATE_STRICT
Packit d03632
    unsigned dmax;              /* maximum distance from zlib header */
Packit d03632
#endif
Packit d03632
    unsigned wsize;             /* window size or zero if not using window */
Packit d03632
    unsigned whave;             /* valid bytes in the window */
Packit d03632
    unsigned wnext;             /* window write index */
Packit d03632
    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
Packit d03632
    unsigned long hold;         /* local strm->hold */
Packit d03632
    unsigned bits;              /* local strm->bits */
Packit d03632
    code const FAR *lcode;      /* local strm->lencode */
Packit d03632
    code const FAR *dcode;      /* local strm->distcode */
Packit d03632
    unsigned lmask;             /* mask for first level of length codes */
Packit d03632
    unsigned dmask;             /* mask for first level of distance codes */
Packit d03632
    code here;                  /* retrieved table entry */
Packit d03632
    unsigned op;                /* code bits, operation, extra bits, or */
Packit d03632
                                /*  window position, window bytes to copy */
Packit d03632
    unsigned len;               /* match length, unused bytes */
Packit d03632
    unsigned dist;              /* match distance */
Packit d03632
    unsigned char FAR *from;    /* where to copy match from */
Packit d03632
Packit d03632
    /* copy state to local variables */
Packit d03632
    state = (struct inflate_state FAR *)strm->state;
Packit d03632
    in = strm->next_in;
Packit d03632
    last = in + (strm->avail_in - 5);
Packit d03632
    out = strm->next_out;
Packit d03632
    beg = out - (start - strm->avail_out);
Packit d03632
    end = out + (strm->avail_out - 257);
Packit d03632
#ifdef INFLATE_STRICT
Packit d03632
    dmax = state->dmax;
Packit d03632
#endif
Packit d03632
    wsize = state->wsize;
Packit d03632
    whave = state->whave;
Packit d03632
    wnext = state->wnext;
Packit d03632
    window = state->window;
Packit d03632
    hold = state->hold;
Packit d03632
    bits = state->bits;
Packit d03632
    lcode = state->lencode;
Packit d03632
    dcode = state->distcode;
Packit d03632
    lmask = (1U << state->lenbits) - 1;
Packit d03632
    dmask = (1U << state->distbits) - 1;
Packit d03632
Packit d03632
    /* decode literals and length/distances until end-of-block or not enough
Packit d03632
       input data or output space */
Packit d03632
    do {
Packit d03632
        if (bits < 15) {
Packit d03632
            hold += (unsigned long)(*in++) << bits;
Packit d03632
            bits += 8;
Packit d03632
            hold += (unsigned long)(*in++) << bits;
Packit d03632
            bits += 8;
Packit d03632
        }
Packit d03632
        here = lcode[hold & lmask];
Packit d03632
      dolen:
Packit d03632
        op = (unsigned)(here.bits);
Packit d03632
        hold >>= op;
Packit d03632
        bits -= op;
Packit d03632
        op = (unsigned)(here.op);
Packit d03632
        if (op == 0) {                          /* literal */
Packit d03632
            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
Packit d03632
                    "inflate:         literal '%c'\n" :
Packit d03632
                    "inflate:         literal 0x%02x\n", here.val));
Packit d03632
            *out++ = (unsigned char)(here.val);
Packit d03632
        }
Packit d03632
        else if (op & 16) {                     /* length base */
Packit d03632
            len = (unsigned)(here.val);
Packit d03632
            op &= 15;                           /* number of extra bits */
Packit d03632
            if (op) {
Packit d03632
                if (bits < op) {
Packit d03632
                    hold += (unsigned long)(*in++) << bits;
Packit d03632
                    bits += 8;
Packit d03632
                }
Packit d03632
                len += (unsigned)hold & ((1U << op) - 1);
Packit d03632
                hold >>= op;
Packit d03632
                bits -= op;
Packit d03632
            }
Packit d03632
            Tracevv((stderr, "inflate:         length %u\n", len));
Packit d03632
            if (bits < 15) {
Packit d03632
                hold += (unsigned long)(*in++) << bits;
Packit d03632
                bits += 8;
Packit d03632
                hold += (unsigned long)(*in++) << bits;
Packit d03632
                bits += 8;
Packit d03632
            }
Packit d03632
            here = dcode[hold & dmask];
Packit d03632
          dodist:
Packit d03632
            op = (unsigned)(here.bits);
Packit d03632
            hold >>= op;
Packit d03632
            bits -= op;
Packit d03632
            op = (unsigned)(here.op);
Packit d03632
            if (op & 16) {                      /* distance base */
Packit d03632
                dist = (unsigned)(here.val);
Packit d03632
                op &= 15;                       /* number of extra bits */
Packit d03632
                if (bits < op) {
Packit d03632
                    hold += (unsigned long)(*in++) << bits;
Packit d03632
                    bits += 8;
Packit d03632
                    if (bits < op) {
Packit d03632
                        hold += (unsigned long)(*in++) << bits;
Packit d03632
                        bits += 8;
Packit d03632
                    }
Packit d03632
                }
Packit d03632
                dist += (unsigned)hold & ((1U << op) - 1);
Packit d03632
#ifdef INFLATE_STRICT
Packit d03632
                if (dist > dmax) {
Packit d03632
                    strm->msg = (char *)"invalid distance too far back";
Packit d03632
                    state->mode = BAD;
Packit d03632
                    break;
Packit d03632
                }
Packit d03632
#endif
Packit d03632
                hold >>= op;
Packit d03632
                bits -= op;
Packit d03632
                Tracevv((stderr, "inflate:         distance %u\n", dist));
Packit d03632
                op = (unsigned)(out - beg);     /* max distance in output */
Packit d03632
                if (dist > op) {                /* see if copy from window */
Packit d03632
                    op = dist - op;             /* distance back in window */
Packit d03632
                    if (op > whave) {
Packit d03632
                        if (state->sane) {
Packit d03632
                            strm->msg =
Packit d03632
                                (char *)"invalid distance too far back";
Packit d03632
                            state->mode = BAD;
Packit d03632
                            break;
Packit d03632
                        }
Packit d03632
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
Packit d03632
                        if (len <= op - whave) {
Packit d03632
                            do {
Packit d03632
                                *out++ = 0;
Packit d03632
                            } while (--len);
Packit d03632
                            continue;
Packit d03632
                        }
Packit d03632
                        len -= op - whave;
Packit d03632
                        do {
Packit d03632
                            *out++ = 0;
Packit d03632
                        } while (--op > whave);
Packit d03632
                        if (op == 0) {
Packit d03632
                            from = out - dist;
Packit d03632
                            do {
Packit d03632
                                *out++ = *from++;
Packit d03632
                            } while (--len);
Packit d03632
                            continue;
Packit d03632
                        }
Packit d03632
#endif
Packit d03632
                    }
Packit d03632
                    from = window;
Packit d03632
                    if (wnext == 0) {           /* very common case */
Packit d03632
                        from += wsize - op;
Packit d03632
                        if (op < len) {         /* some from window */
Packit d03632
                            len -= op;
Packit d03632
                            do {
Packit d03632
                                *out++ = *from++;
Packit d03632
                            } while (--op);
Packit d03632
                            from = out - dist;  /* rest from output */
Packit d03632
                        }
Packit d03632
                    }
Packit d03632
                    else if (wnext < op) {      /* wrap around window */
Packit d03632
                        from += wsize + wnext - op;
Packit d03632
                        op -= wnext;
Packit d03632
                        if (op < len) {         /* some from end of window */
Packit d03632
                            len -= op;
Packit d03632
                            do {
Packit d03632
                                *out++ = *from++;
Packit d03632
                            } while (--op);
Packit d03632
                            from = window;
Packit d03632
                            if (wnext < len) {  /* some from start of window */
Packit d03632
                                op = wnext;
Packit d03632
                                len -= op;
Packit d03632
                                do {
Packit d03632
                                    *out++ = *from++;
Packit d03632
                                } while (--op);
Packit d03632
                                from = out - dist;      /* rest from output */
Packit d03632
                            }
Packit d03632
                        }
Packit d03632
                    }
Packit d03632
                    else {                      /* contiguous in window */
Packit d03632
                        from += wnext - op;
Packit d03632
                        if (op < len) {         /* some from window */
Packit d03632
                            len -= op;
Packit d03632
                            do {
Packit d03632
                                *out++ = *from++;
Packit d03632
                            } while (--op);
Packit d03632
                            from = out - dist;  /* rest from output */
Packit d03632
                        }
Packit d03632
                    }
Packit d03632
                    while (len > 2) {
Packit d03632
                        *out++ = *from++;
Packit d03632
                        *out++ = *from++;
Packit d03632
                        *out++ = *from++;
Packit d03632
                        len -= 3;
Packit d03632
                    }
Packit d03632
                    if (len) {
Packit d03632
                        *out++ = *from++;
Packit d03632
                        if (len > 1)
Packit d03632
                            *out++ = *from++;
Packit d03632
                    }
Packit d03632
                }
Packit d03632
                else {
Packit d03632
                    from = out - dist;          /* copy direct from output */
Packit d03632
                    do {                        /* minimum length is three */
Packit d03632
                        *out++ = *from++;
Packit d03632
                        *out++ = *from++;
Packit d03632
                        *out++ = *from++;
Packit d03632
                        len -= 3;
Packit d03632
                    } while (len > 2);
Packit d03632
                    if (len) {
Packit d03632
                        *out++ = *from++;
Packit d03632
                        if (len > 1)
Packit d03632
                            *out++ = *from++;
Packit d03632
                    }
Packit d03632
                }
Packit d03632
            }
Packit d03632
            else if ((op & 64) == 0) {          /* 2nd level distance code */
Packit d03632
                here = dcode[here.val + (hold & ((1U << op) - 1))];
Packit d03632
                goto dodist;
Packit d03632
            }
Packit d03632
            else {
Packit d03632
                strm->msg = (char *)"invalid distance code";
Packit d03632
                state->mode = BAD;
Packit d03632
                break;
Packit d03632
            }
Packit d03632
        }
Packit d03632
        else if ((op & 64) == 0) {              /* 2nd level length code */
Packit d03632
            here = lcode[here.val + (hold & ((1U << op) - 1))];
Packit d03632
            goto dolen;
Packit d03632
        }
Packit d03632
        else if (op & 32) {                     /* end-of-block */
Packit d03632
            Tracevv((stderr, "inflate:         end of block\n"));
Packit d03632
            state->mode = TYPE;
Packit d03632
            break;
Packit d03632
        }
Packit d03632
        else {
Packit d03632
            strm->msg = (char *)"invalid literal/length code";
Packit d03632
            state->mode = BAD;
Packit d03632
            break;
Packit d03632
        }
Packit d03632
    } while (in < last && out < end);
Packit d03632
Packit d03632
    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
Packit d03632
    len = bits >> 3;
Packit d03632
    in -= len;
Packit d03632
    bits -= len << 3;
Packit d03632
    hold &= (1U << bits) - 1;
Packit d03632
Packit d03632
    /* update state and return */
Packit d03632
    strm->next_in = in;
Packit d03632
    strm->next_out = out;
Packit d03632
    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
Packit d03632
    strm->avail_out = (unsigned)(out < end ?
Packit d03632
                                 257 + (end - out) : 257 - (out - end));
Packit d03632
    state->hold = hold;
Packit d03632
    state->bits = bits;
Packit d03632
    return;
Packit d03632
}
Packit d03632
Packit d03632
/*
Packit d03632
   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
Packit d03632
   - Using bit fields for code structure
Packit d03632
   - Different op definition to avoid & for extra bits (do & for table bits)
Packit d03632
   - Three separate decoding do-loops for direct, window, and wnext == 0
Packit d03632
   - Special case for distance > 1 copies to do overlapped load and store copy
Packit d03632
   - Explicit branch predictions (based on measured branch probabilities)
Packit d03632
   - Deferring match copy and interspersed it with decoding subsequent codes
Packit d03632
   - Swapping literal/length else
Packit d03632
   - Swapping window/direct else
Packit d03632
   - Larger unrolled copy loops (three is about right)
Packit d03632
   - Moving len -= 3 statement into middle of loop
Packit d03632
 */
Packit d03632
Packit d03632
#endif /* !ASMINF */