コード例 #1
0
ファイル: LZ4Engine.cs プロジェクト: standardfx/standard
        public static int DecompressGeneric(byte *src, byte *dst, int srcSize, int outputSize,
                                            EndConditionDirective endOnInput, EarlyEndDirective partialDecoding,
                                            int targetOutputSize, DictDirective dict, byte *lowPrefix, byte *dictStart, int dictSize)
        {
            byte *ip   = src;
            byte *iend = ip + srcSize;

            byte *op    = dst;
            byte *oend  = op + outputSize;
            byte *oexit = op + targetOutputSize;

            byte *dictEnd = dictStart + dictSize;

            bool safeDecode  = endOnInput == EndConditionDirective.EndOnInputSize;
            bool checkOffset = safeDecode && dictSize < 64 * KB;

            if ((partialDecoding != EarlyEndDirective.Full) && (oexit > oend - MFLimit))
            {
                oexit = oend - MFLimit;
            }
            if ((endOnInput == EndConditionDirective.EndOnInputSize) && (outputSize == 0))
            {
                return(srcSize == 1 && *ip == 0 ? 0 : -1);
            }
            if ((endOnInput != EndConditionDirective.EndOnInputSize) && (outputSize == 0))
            {
                return(*ip == 0 ? 1 : -1);
            }

            for (; ;)
            {
                int  length;
                uint token = *ip++;

                if ((ip + 14 + 2 <= iend) &&
                    (op + 14 + 18 <= oend) &&
                    (token < 15 << MLBits) &&
                    ((token & MLMask) != 15))
                {
                    int   ll       = (int)(token >> MLBits);
                    int   off      = LZ4MemoryHelper.Peek16(ip + ll);
                    byte *matchPtr = op + ll - off;
                    if (off >= 18 && matchPtr >= lowPrefix)
                    {
                        int ml = (int)((token & MLMask) + MinMatch);
                        LZ4MemoryHelper.Copy16(op, ip);
                        op += ll;
                        ip += ll + 2;
                        LZ4MemoryHelper.Copy18(op, matchPtr);
                        op += ml;
                        continue;
                    }
                }

                if ((length = (int)(token >> MLBits)) == RunMask)
                {
                    uint s;
                    do
                    {
                        s       = *ip++;
                        length += (int)s;
                    }while (
                        (endOnInput != EndConditionDirective.EndOnInputSize || ip < iend - RunMask) &&
                        (s == 255));

                    if (safeDecode && op + length < op)
                    {
                        goto _output_error;
                    }
                    if (safeDecode && ip + length < ip)
                    {
                        goto _output_error;
                    }
                }

                byte *cpy = op + length;
                if ((endOnInput == EndConditionDirective.EndOnInputSize) &&
                    ((cpy > (partialDecoding == EarlyEndDirective.Partial ? oexit : oend - MFLimit)) ||
                     (ip + length > iend - (2 + 1 + LastLiterals))) ||
                    (endOnInput != EndConditionDirective.EndOnInputSize) && (cpy > oend - WildCopyLength))
                {
                    if (partialDecoding == EarlyEndDirective.Partial)
                    {
                        if (cpy > oend)
                        {
                            goto _output_error;
                        }
                        if ((endOnInput == EndConditionDirective.EndOnInputSize) && (ip + length > iend))
                        {
                            goto _output_error;
                        }
                    }
                    else
                    {
                        if ((endOnInput != EndConditionDirective.EndOnInputSize) && (cpy != oend))
                        {
                            goto _output_error;
                        }

                        if ((endOnInput == EndConditionDirective.EndOnInputSize) &&
                            (ip + length != iend || cpy > oend))
                        {
                            goto _output_error;
                        }
                    }

                    LZ4MemoryHelper.Copy(op, ip, length);
                    ip += length;
                    op += length;
                    break;
                }

                LZ4MemoryHelper.WildCopy(op, ip, cpy);
                ip += length;
                op  = cpy;

                int offset = LZ4MemoryHelper.Peek16(ip);
                ip += 2;
                byte *match = op - offset;
                if (checkOffset && match + dictSize < lowPrefix)
                {
                    goto _output_error;
                }

                LZ4MemoryHelper.Poke32(op, (uint)offset);

                length = (int)(token & MLMask);
                if (length == MLMask)
                {
                    uint s;
                    do
                    {
                        s = *ip++;
                        if ((endOnInput == EndConditionDirective.EndOnInputSize) && (ip > iend - LastLiterals))
                        {
                            goto _output_error;
                        }

                        length += (int)s;
                    }while (s == 255);

                    if (safeDecode && (op + length < op))
                    {
                        goto _output_error;
                    }
                }

                length += MinMatch;

                if ((dict == DictDirective.UsingExtDict) && (match < lowPrefix))
                {
                    if (op + length > oend - LastLiterals)
                    {
                        goto _output_error;
                    }

                    if (length <= lowPrefix - match)
                    {
                        LZ4MemoryHelper.Move(op, dictEnd - (lowPrefix - match), length);
                        op += length;
                    }
                    else
                    {
                        int copySize = (int)(lowPrefix - match);
                        int restSize = length - copySize;
                        LZ4MemoryHelper.Copy(op, dictEnd - copySize, copySize);
                        op += copySize;
                        if (restSize > (int)(op - lowPrefix))
                        {
                            byte *endOfMatch = op + restSize;
                            byte *copyFrom   = lowPrefix;
                            while (op < endOfMatch)
                            {
                                *op++ = *copyFrom++;
                            }
                        }
                        else
                        {
                            LZ4MemoryHelper.Copy(op, lowPrefix, restSize);
                            op += restSize;
                        }
                    }

                    continue;
                }

                cpy = op + length;
                if (offset < 8)
                {
                    op[0]  = match[0];
                    op[1]  = match[1];
                    op[2]  = match[2];
                    op[3]  = match[3];
                    match += _inc32table[offset];
                    LZ4MemoryHelper.Copy(op + 4, match, 4);
                    match -= _dec64table[offset];
                }
                else
                {
                    LZ4MemoryHelper.Copy8(op, match);
                    match += 8;
                }

                op += 8;

                if (cpy > oend - 12)
                {
                    byte *oCopyLimit = oend - (WildCopyLength - 1);
                    if (cpy > oend - LastLiterals)
                    {
                        goto _output_error;
                    }

                    if (op < oCopyLimit)
                    {
                        LZ4MemoryHelper.WildCopy(op, match, oCopyLimit);
                        match += oCopyLimit - op;
                        op     = oCopyLimit;
                    }

                    while (op < cpy)
                    {
                        *op++ = *match++;
                    }
                }
                else
                {
                    LZ4MemoryHelper.Copy8(op, match);
                    if (length > 16)
                    {
                        LZ4MemoryHelper.WildCopy(op + 8, match + 8, cpy);
                    }
                }

                op = cpy; // correction
            }

            // end of decoding
            if (endOnInput == EndConditionDirective.EndOnInputSize)
            {
                return((int)(op - dst)); // Nb of output bytes decoded
            }
            return((int)(ip - src));     // Nb of input bytes read

            // Overflow error detected
_output_error:
            return((int)-(ip - src) - 1);
        }