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