Blame deps/zlib/inffast.c

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