diff options
Diffstat (limited to 'compat/zlib/infback.c')
| -rw-r--r-- | compat/zlib/infback.c | 640 | 
1 files changed, 640 insertions, 0 deletions
| diff --git a/compat/zlib/infback.c b/compat/zlib/infback.c new file mode 100644 index 0000000..59679ec --- /dev/null +++ b/compat/zlib/infback.c @@ -0,0 +1,640 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* +   This code is largely copied from inflate.c.  Normally either infback.o or +   inflate.o would be linked into an application--not both.  The interface +   with inffast.c is retained so that optimized assembler-coded versions of +   inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* +   strm provides memory allocation functions in zalloc and zfree, or +   Z_NULL to use the library memory allocation functions. + +   windowBits is in the range 8..15, and window is a user-supplied +   window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ +    struct inflate_state FAR *state; + +    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || +        stream_size != (int)(sizeof(z_stream))) +        return Z_VERSION_ERROR; +    if (strm == Z_NULL || window == Z_NULL || +        windowBits < 8 || windowBits > 15) +        return Z_STREAM_ERROR; +    strm->msg = Z_NULL;                 /* in case we return an error */ +    if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO +        return Z_STREAM_ERROR; +#else +        strm->zalloc = zcalloc; +        strm->opaque = (voidpf)0; +#endif +    } +    if (strm->zfree == (free_func)0) +#ifdef Z_SOLO +        return Z_STREAM_ERROR; +#else +    strm->zfree = zcfree; +#endif +    state = (struct inflate_state FAR *)ZALLOC(strm, 1, +                                               sizeof(struct inflate_state)); +    if (state == Z_NULL) return Z_MEM_ERROR; +    Tracev((stderr, "inflate: allocated\n")); +    strm->state = (struct internal_state FAR *)state; +    state->dmax = 32768U; +    state->wbits = (uInt)windowBits; +    state->wsize = 1U << windowBits; +    state->window = window; +    state->wnext = 0; +    state->whave = 0; +    return Z_OK; +} + +/* +   Return state with length and distance decoding tables and index sizes set to +   fixed code decoding.  Normally this returns fixed tables from inffixed.h. +   If BUILDFIXED is defined, then instead this routine builds the tables the +   first time it's called, and returns those tables the first time and +   thereafter.  This reduces the size of the code by about 2K bytes, in +   exchange for a little execution time.  However, BUILDFIXED should not be +   used for threaded applications, since the rewriting of the tables and virgin +   may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED +    static int virgin = 1; +    static code *lenfix, *distfix; +    static code fixed[544]; + +    /* build fixed huffman tables if first call (may not be thread safe) */ +    if (virgin) { +        unsigned sym, bits; +        static code *next; + +        /* literal/length table */ +        sym = 0; +        while (sym < 144) state->lens[sym++] = 8; +        while (sym < 256) state->lens[sym++] = 9; +        while (sym < 280) state->lens[sym++] = 7; +        while (sym < 288) state->lens[sym++] = 8; +        next = fixed; +        lenfix = next; +        bits = 9; +        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + +        /* distance table */ +        sym = 0; +        while (sym < 32) state->lens[sym++] = 5; +        distfix = next; +        bits = 5; +        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + +        /* do this just once */ +        virgin = 0; +    } +#else /* !BUILDFIXED */ +#   include "inffixed.h" +#endif /* BUILDFIXED */ +    state->lencode = lenfix; +    state->lenbits = 9; +    state->distcode = distfix; +    state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ +    do { \ +        put = strm->next_out; \ +        left = strm->avail_out; \ +        next = strm->next_in; \ +        have = strm->avail_in; \ +        hold = state->hold; \ +        bits = state->bits; \ +    } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ +    do { \ +        strm->next_out = put; \ +        strm->avail_out = left; \ +        strm->next_in = next; \ +        strm->avail_in = have; \ +        state->hold = hold; \ +        state->bits = bits; \ +    } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ +    do { \ +        hold = 0; \ +        bits = 0; \ +    } while (0) + +/* Assure that some input is available.  If input is requested, but denied, +   then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ +    do { \ +        if (have == 0) { \ +            have = in(in_desc, &next); \ +            if (have == 0) { \ +                next = Z_NULL; \ +                ret = Z_BUF_ERROR; \ +                goto inf_leave; \ +            } \ +        } \ +    } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() +   with an error if there is no input available. */ +#define PULLBYTE() \ +    do { \ +        PULL(); \ +        have--; \ +        hold += (unsigned long)(*next++) << bits; \ +        bits += 8; \ +    } while (0) + +/* Assure that there are at least n bits in the bit accumulator.  If there is +   not enough available input to do that, then return from inflateBack() with +   an error. */ +#define NEEDBITS(n) \ +    do { \ +        while (bits < (unsigned)(n)) \ +            PULLBYTE(); \ +    } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ +    ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ +    do { \ +        hold >>= (n); \ +        bits -= (unsigned)(n); \ +    } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ +    do { \ +        hold >>= bits & 7; \ +        bits -= bits & 7; \ +    } while (0) + +/* Assure that some output space is available, by writing out the window +   if it's full.  If the write fails, return from inflateBack() with a +   Z_BUF_ERROR. */ +#define ROOM() \ +    do { \ +        if (left == 0) { \ +            put = state->window; \ +            left = state->wsize; \ +            state->whave = left; \ +            if (out(out_desc, put, left)) { \ +                ret = Z_BUF_ERROR; \ +                goto inf_leave; \ +            } \ +        } \ +    } while (0) + +/* +   strm provides the memory allocation functions and window buffer on input, +   and provides information on the unused input on return.  For Z_DATA_ERROR +   returns, strm will also provide an error message. + +   in() and out() are the call-back input and output functions.  When +   inflateBack() needs more input, it calls in().  When inflateBack() has +   filled the window with output, or when it completes with data in the +   window, it calls out() to write out the data.  The application must not +   change the provided input until in() is called again or inflateBack() +   returns.  The application must not change the window/output buffer until +   inflateBack() returns. + +   in() and out() are called with a descriptor parameter provided in the +   inflateBack() call.  This parameter can be a structure that provides the +   information required to do the read or write, as well as accumulated +   information on the input and output such as totals and check values. + +   in() should return zero on failure.  out() should return non-zero on +   failure.  If either in() or out() fails, than inflateBack() returns a +   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it +   was in() or out() that caused in the error.  Otherwise,  inflateBack() +   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format +   error, or Z_MEM_ERROR if it could not allocate memory for the state. +   inflateBack() can also return Z_STREAM_ERROR if the input parameters +   are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ +    struct inflate_state FAR *state; +    z_const unsigned char FAR *next;    /* next input */ +    unsigned char FAR *put;     /* next output */ +    unsigned have, left;        /* available input and output */ +    unsigned long hold;         /* bit buffer */ +    unsigned bits;              /* bits in bit buffer */ +    unsigned copy;              /* number of stored or match bytes to copy */ +    unsigned char FAR *from;    /* where to copy match bytes from */ +    code here;                  /* current decoding table entry */ +    code last;                  /* parent table entry */ +    unsigned len;               /* length to copy for repeats, bits to drop */ +    int ret;                    /* return code */ +    static const unsigned short order[19] = /* permutation of code lengths */ +        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +    /* Check that the strm exists and that the state was initialized */ +    if (strm == Z_NULL || strm->state == Z_NULL) +        return Z_STREAM_ERROR; +    state = (struct inflate_state FAR *)strm->state; + +    /* Reset the state */ +    strm->msg = Z_NULL; +    state->mode = TYPE; +    state->last = 0; +    state->whave = 0; +    next = strm->next_in; +    have = next != Z_NULL ? strm->avail_in : 0; +    hold = 0; +    bits = 0; +    put = state->window; +    left = state->wsize; + +    /* Inflate until end of block marked as last */ +    for (;;) +        switch (state->mode) { +        case TYPE: +            /* determine and dispatch block type */ +            if (state->last) { +                BYTEBITS(); +                state->mode = DONE; +                break; +            } +            NEEDBITS(3); +            state->last = BITS(1); +            DROPBITS(1); +            switch (BITS(2)) { +            case 0:                             /* stored block */ +                Tracev((stderr, "inflate:     stored block%s\n", +                        state->last ? " (last)" : "")); +                state->mode = STORED; +                break; +            case 1:                             /* fixed block */ +                fixedtables(state); +                Tracev((stderr, "inflate:     fixed codes block%s\n", +                        state->last ? " (last)" : "")); +                state->mode = LEN;              /* decode codes */ +                break; +            case 2:                             /* dynamic block */ +                Tracev((stderr, "inflate:     dynamic codes block%s\n", +                        state->last ? " (last)" : "")); +                state->mode = TABLE; +                break; +            case 3: +                strm->msg = (char *)"invalid block type"; +                state->mode = BAD; +            } +            DROPBITS(2); +            break; + +        case STORED: +            /* get and verify stored block length */ +            BYTEBITS();                         /* go to byte boundary */ +            NEEDBITS(32); +            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { +                strm->msg = (char *)"invalid stored block lengths"; +                state->mode = BAD; +                break; +            } +            state->length = (unsigned)hold & 0xffff; +            Tracev((stderr, "inflate:       stored length %u\n", +                    state->length)); +            INITBITS(); + +            /* copy stored block from input to output */ +            while (state->length != 0) { +                copy = state->length; +                PULL(); +                ROOM(); +                if (copy > have) copy = have; +                if (copy > left) copy = left; +                zmemcpy(put, next, copy); +                have -= copy; +                next += copy; +                left -= copy; +                put += copy; +                state->length -= copy; +            } +            Tracev((stderr, "inflate:       stored end\n")); +            state->mode = TYPE; +            break; + +        case TABLE: +            /* get dynamic table entries descriptor */ +            NEEDBITS(14); +            state->nlen = BITS(5) + 257; +            DROPBITS(5); +            state->ndist = BITS(5) + 1; +            DROPBITS(5); +            state->ncode = BITS(4) + 4; +            DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND +            if (state->nlen > 286 || state->ndist > 30) { +                strm->msg = (char *)"too many length or distance symbols"; +                state->mode = BAD; +                break; +            } +#endif +            Tracev((stderr, "inflate:       table sizes ok\n")); + +            /* get code length code lengths (not a typo) */ +            state->have = 0; +            while (state->have < state->ncode) { +                NEEDBITS(3); +                state->lens[order[state->have++]] = (unsigned short)BITS(3); +                DROPBITS(3); +            } +            while (state->have < 19) +                state->lens[order[state->have++]] = 0; +            state->next = state->codes; +            state->lencode = (code const FAR *)(state->next); +            state->lenbits = 7; +            ret = inflate_table(CODES, state->lens, 19, &(state->next), +                                &(state->lenbits), state->work); +            if (ret) { +                strm->msg = (char *)"invalid code lengths set"; +                state->mode = BAD; +                break; +            } +            Tracev((stderr, "inflate:       code lengths ok\n")); + +            /* get length and distance code code lengths */ +            state->have = 0; +            while (state->have < state->nlen + state->ndist) { +                for (;;) { +                    here = state->lencode[BITS(state->lenbits)]; +                    if ((unsigned)(here.bits) <= bits) break; +                    PULLBYTE(); +                } +                if (here.val < 16) { +                    DROPBITS(here.bits); +                    state->lens[state->have++] = here.val; +                } +                else { +                    if (here.val == 16) { +                        NEEDBITS(here.bits + 2); +                        DROPBITS(here.bits); +                        if (state->have == 0) { +                            strm->msg = (char *)"invalid bit length repeat"; +                            state->mode = BAD; +                            break; +                        } +                        len = (unsigned)(state->lens[state->have - 1]); +                        copy = 3 + BITS(2); +                        DROPBITS(2); +                    } +                    else if (here.val == 17) { +                        NEEDBITS(here.bits + 3); +                        DROPBITS(here.bits); +                        len = 0; +                        copy = 3 + BITS(3); +                        DROPBITS(3); +                    } +                    else { +                        NEEDBITS(here.bits + 7); +                        DROPBITS(here.bits); +                        len = 0; +                        copy = 11 + BITS(7); +                        DROPBITS(7); +                    } +                    if (state->have + copy > state->nlen + state->ndist) { +                        strm->msg = (char *)"invalid bit length repeat"; +                        state->mode = BAD; +                        break; +                    } +                    while (copy--) +                        state->lens[state->have++] = (unsigned short)len; +                } +            } + +            /* handle error breaks in while */ +            if (state->mode == BAD) break; + +            /* check for end-of-block code (better have one) */ +            if (state->lens[256] == 0) { +                strm->msg = (char *)"invalid code -- missing end-of-block"; +                state->mode = BAD; +                break; +            } + +            /* build code tables -- note: do not change the lenbits or distbits +               values here (9 and 6) without reading the comments in inftrees.h +               concerning the ENOUGH constants, which depend on those values */ +            state->next = state->codes; +            state->lencode = (code const FAR *)(state->next); +            state->lenbits = 9; +            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), +                                &(state->lenbits), state->work); +            if (ret) { +                strm->msg = (char *)"invalid literal/lengths set"; +                state->mode = BAD; +                break; +            } +            state->distcode = (code const FAR *)(state->next); +            state->distbits = 6; +            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, +                            &(state->next), &(state->distbits), state->work); +            if (ret) { +                strm->msg = (char *)"invalid distances set"; +                state->mode = BAD; +                break; +            } +            Tracev((stderr, "inflate:       codes ok\n")); +            state->mode = LEN; + +        case LEN: +            /* use inflate_fast() if we have enough input and output */ +            if (have >= 6 && left >= 258) { +                RESTORE(); +                if (state->whave < state->wsize) +                    state->whave = state->wsize - left; +                inflate_fast(strm, state->wsize); +                LOAD(); +                break; +            } + +            /* get a literal, length, or end-of-block code */ +            for (;;) { +                here = state->lencode[BITS(state->lenbits)]; +                if ((unsigned)(here.bits) <= bits) break; +                PULLBYTE(); +            } +            if (here.op && (here.op & 0xf0) == 0) { +                last = here; +                for (;;) { +                    here = state->lencode[last.val + +                            (BITS(last.bits + last.op) >> last.bits)]; +                    if ((unsigned)(last.bits + here.bits) <= bits) break; +                    PULLBYTE(); +                } +                DROPBITS(last.bits); +            } +            DROPBITS(here.bits); +            state->length = (unsigned)here.val; + +            /* process literal */ +            if (here.op == 0) { +                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? +                        "inflate:         literal '%c'\n" : +                        "inflate:         literal 0x%02x\n", here.val)); +                ROOM(); +                *put++ = (unsigned char)(state->length); +                left--; +                state->mode = LEN; +                break; +            } + +            /* process end of block */ +            if (here.op & 32) { +                Tracevv((stderr, "inflate:         end of block\n")); +                state->mode = TYPE; +                break; +            } + +            /* invalid code */ +            if (here.op & 64) { +                strm->msg = (char *)"invalid literal/length code"; +                state->mode = BAD; +                break; +            } + +            /* length code -- get extra bits, if any */ +            state->extra = (unsigned)(here.op) & 15; +            if (state->extra != 0) { +                NEEDBITS(state->extra); +                state->length += BITS(state->extra); +                DROPBITS(state->extra); +            } +            Tracevv((stderr, "inflate:         length %u\n", state->length)); + +            /* get distance code */ +            for (;;) { +                here = state->distcode[BITS(state->distbits)]; +                if ((unsigned)(here.bits) <= bits) break; +                PULLBYTE(); +            } +            if ((here.op & 0xf0) == 0) { +                last = here; +                for (;;) { +                    here = state->distcode[last.val + +                            (BITS(last.bits + last.op) >> last.bits)]; +                    if ((unsigned)(last.bits + here.bits) <= bits) break; +                    PULLBYTE(); +                } +                DROPBITS(last.bits); +            } +            DROPBITS(here.bits); +            if (here.op & 64) { +                strm->msg = (char *)"invalid distance code"; +                state->mode = BAD; +                break; +            } +            state->offset = (unsigned)here.val; + +            /* get distance extra bits, if any */ +            state->extra = (unsigned)(here.op) & 15; +            if (state->extra != 0) { +                NEEDBITS(state->extra); +                state->offset += BITS(state->extra); +                DROPBITS(state->extra); +            } +            if (state->offset > state->wsize - (state->whave < state->wsize ? +                                                left : 0)) { +                strm->msg = (char *)"invalid distance too far back"; +                state->mode = BAD; +                break; +            } +            Tracevv((stderr, "inflate:         distance %u\n", state->offset)); + +            /* copy match from window to output */ +            do { +                ROOM(); +                copy = state->wsize - state->offset; +                if (copy < left) { +                    from = put + copy; +                    copy = left - copy; +                } +                else { +                    from = put - state->offset; +                    copy = left; +                } +                if (copy > state->length) copy = state->length; +                state->length -= copy; +                left -= copy; +                do { +                    *put++ = *from++; +                } while (--copy); +            } while (state->length != 0); +            break; + +        case DONE: +            /* inflate stream terminated properly -- write leftover output */ +            ret = Z_STREAM_END; +            if (left < state->wsize) { +                if (out(out_desc, state->window, state->wsize - left)) +                    ret = Z_BUF_ERROR; +            } +            goto inf_leave; + +        case BAD: +            ret = Z_DATA_ERROR; +            goto inf_leave; + +        default:                /* can't happen, but makes compilers happy */ +            ret = Z_STREAM_ERROR; +            goto inf_leave; +        } + +    /* Return unused input */ +  inf_leave: +    strm->next_in = next; +    strm->avail_in = have; +    return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ +    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) +        return Z_STREAM_ERROR; +    ZFREE(strm, strm->state); +    strm->state = Z_NULL; +    Tracev((stderr, "inflate: end\n")); +    return Z_OK; +} | 
