FORCE_INLINE int LZ4_decompress_generic()

in lib/lz4/lz4.cc [1128:1298]


FORCE_INLINE int LZ4_decompress_generic(
    const char *const source, char *const dest, int inputSize,
    int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */

    int endOnInput,              /* endOnOutputSize, endOnInputSize */
    int partialDecoding,         /* full, partial */
    int targetOutputSize,        /* only used if partialDecoding==partial */
    int dict,                    /* noDict, withPrefix64k, usingExtDict */
    const BYTE *const lowPrefix, /* == dest if dict == noDict */
    const BYTE *const dictStart, /* only if dict==usingExtDict */
    const size_t dictSize        /* note : = 0 if noDict */
) {
    /* Local Variables */
    const BYTE *ip = (const BYTE *)source;
    const BYTE *const iend = ip + inputSize;

    BYTE *op = (BYTE *)dest;
    BYTE *const oend = op + outputSize;
    BYTE *cpy;
    BYTE *oexit = op + targetOutputSize;
    const BYTE *const lowLimit = lowPrefix - dictSize;

    const BYTE *const dictEnd = (const BYTE *)dictStart + dictSize;
    const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4};
    const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};

    const int safeDecode = (endOnInput == endOnInputSize);
    const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));

    /* Special cases */
    if ((partialDecoding) && (oexit > oend - MFLIMIT))
        oexit = oend - MFLIMIT; /* targetOutputSize too high => decode everything */
    if ((endOnInput) && (unlikely(outputSize == 0)))
        return ((inputSize == 1) && (*ip == 0)) ? 0 : -1; /* Empty output buffer */
    if ((!endOnInput) && (unlikely(outputSize == 0))) return (*ip == 0 ? 1 : -1);

    /* Main Loop */
    while (1) {
        unsigned token;
        size_t length;
        const BYTE *match;

        /* get literal length */
        token = *ip++;
        if ((length = (token >> ML_BITS)) == RUN_MASK) {
            unsigned s;
            do {
                s = *ip++;
                length += s;
            } while (likely((endOnInput) ? ip < iend - RUN_MASK : 1) && (s == 255));
            if ((safeDecode) && unlikely((size_t)(op + length) < (size_t)(op)))
                goto _output_error; /* overflow detection */
            if ((safeDecode) && unlikely((size_t)(ip + length) < (size_t)(ip)))
                goto _output_error; /* overflow detection */
        }

        /* copy literals */
        cpy = op + length;
        if (((endOnInput) && ((cpy > (partialDecoding ? oexit : oend - MFLIMIT)) ||
                              (ip + length > iend - (2 + 1 + LASTLITERALS)))) ||
            ((!endOnInput) && (cpy > oend - COPYLENGTH))) {
            if (partialDecoding) {
                if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
                if ((endOnInput) && (ip + length > iend))
                    goto _output_error; /* Error : read attempt beyond end of input buffer */
            } else {
                if ((!endOnInput) && (cpy != oend))
                    goto _output_error; /* Error : block decoding must stop exactly there */
                if ((endOnInput) && ((ip + length != iend) || (cpy > oend)))
                    goto _output_error; /* Error : input must be consumed */
            }
            memcpy(op, ip, length);
            ip += length;
            op += length;
            break; /* Necessarily EOF, due to parsing restrictions */
        }
        LZ4_wildCopy(op, ip, cpy);
        ip += length;
        op = cpy;

        /* get offset */
        match = cpy - LZ4_readLE16(ip);
        ip += 2;
        if ((checkOffset) && (unlikely(match < lowLimit)))
            goto _output_error; /* Error : offset outside destination buffer */

        /* get matchlength */
        length = token & ML_MASK;
        if (length == ML_MASK) {
            unsigned s;
            do {
                if ((endOnInput) && (ip > iend - LASTLITERALS)) goto _output_error;
                s = *ip++;
                length += s;
            } while (s == 255);
            if ((safeDecode) && unlikely((size_t)(op + length) < (size_t)op))
                goto _output_error; /* overflow detection */
        }
        length += MINMATCH;

        /* check external dictionary */
        if ((dict == usingExtDict) && (match < lowPrefix)) {
            if (unlikely(op + length > oend - LASTLITERALS))
                goto _output_error; /* doesn't respect parsing restriction */

            if (length <= (size_t)(lowPrefix - match)) {
                /* match can be copied as a single segment from external dictionary */
                match = dictEnd - (lowPrefix - match);
                memmove(op, match, length);
                op += length;
            } else {
                /* match encompass external dictionary and current segment */
                size_t copySize = (size_t)(lowPrefix - match);
                memcpy(op, dictEnd - copySize, copySize);
                op += copySize;
                copySize = length - copySize;
                if (copySize > (size_t)(op - lowPrefix)) /* overlap within current segment */
                {
                    BYTE *const endOfMatch = op + copySize;
                    const BYTE *copyFrom = lowPrefix;
                    while (op < endOfMatch) *op++ = *copyFrom++;
                } else {
                    memcpy(op, lowPrefix, copySize);
                    op += copySize;
                }
            }
            continue;
        }

        /* copy repeated sequence */
        cpy = op + length;
        if (unlikely((op - match) < 8)) {
            const size_t dec64 = dec64table[op - match];
            op[0] = match[0];
            op[1] = match[1];
            op[2] = match[2];
            op[3] = match[3];
            match += dec32table[op - match];
            LZ4_copy4(op + 4, match);
            op += 8;
            match -= dec64;
        } else {
            LZ4_copy8(op, match);
            op += 8;
            match += 8;
        }

        if (unlikely(cpy > oend - 12)) {
            if (cpy > oend - LASTLITERALS)
                goto _output_error; /* Error : last LASTLITERALS bytes must be literals */
            if (op < oend - 8) {
                LZ4_wildCopy(op, match, oend - 8);
                match += (oend - 8) - op;
                op = oend - 8;
            }
            while (op < cpy) *op++ = *match++;
        } else
            LZ4_wildCopy(op, match, cpy);
        op = cpy; /* correction */
    }

    /* end of decoding */
    if (endOnInput)
        return (int)(((char *)op) - dest); /* Nb of output bytes decoded */
    else
        return (int)(((const char *)ip) - source); /* Nb of input bytes read */

/* Overflow error detected */
_output_error:
    return (int)(-(((const char *)ip) - source)) - 1;
}