Blame zlib-src/inffast.c

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