示例#1
0
        private VCDiffResult DecodeCore()
        {
            using ByteBuffer instructionBuffer = new ByteBuffer(window.InstructionsAndSizesData);
            using ByteBuffer addressBuffer     = new ByteBuffer(window.AddressesForCopyData);
            using ByteBuffer addRunBuffer      = new ByteBuffer(window.AddRunData);

            InstructionDecoder instrDecoder = new InstructionDecoder(instructionBuffer, customTable);

            VCDiffResult result = VCDiffResult.SUCCESS;

            while (this.TotalBytesDecoded < window.TargetWindowLength)
            {
                VCDiffInstructionType instruction = instrDecoder.Next(out int decodedSize, out byte mode);

                switch (instruction)
                {
                case VCDiffInstructionType.EOD:
                    targetData.SetLength(0);
                    return(VCDiffResult.EOD);

                case VCDiffInstructionType.ERROR:
                    targetData.SetLength(0);
                    return(VCDiffResult.ERROR);
                }

                switch (instruction)
                {
                case VCDiffInstructionType.ADD:
                    result = DecodeAdd(decodedSize, addRunBuffer);
                    break;

                case VCDiffInstructionType.RUN:
                    result = DecodeRun(decodedSize, addRunBuffer);
                    break;

                case VCDiffInstructionType.COPY:
                    result = DecodeCopy(decodedSize, mode, addressBuffer);
                    break;

                default:
                    targetData.SetLength(0);
                    return(VCDiffResult.ERROR);
                }
            }

            if (window.ChecksumFormat == ChecksumFormat.SDCH)
            {
                uint adler = Checksum.ComputeGoogleAdler32(targetData.GetBuffer().AsMemory(0, (int)targetData.Length));

                if (adler != window.Checksum)
                {
                    result = VCDiffResult.ERROR;
                }
            }
            else if (window.ChecksumFormat == ChecksumFormat.Xdelta3)
            {
                uint adler = Checksum.ComputeXdelta3Adler32(targetData.GetBuffer().AsMemory(0, (int)targetData.Length));

                if (adler != window.Checksum)
                {
                    result = VCDiffResult.ERROR;
                }
            }

            return(result);
        }
示例#2
0
        private VCDiffResult DecodeInterleaveCore()
        {
            VCDiffResult result = VCDiffResult.SUCCESS;
            //since interleave expected then the last point that was most likely decoded was the lengths section
            //so following is all data for the add run copy etc
            long interleaveLength = window.InstructionAndSizesLength;

            using var previous = new MemoryStream();
            int lastDecodedSize = 0;
            VCDiffInstructionType lastDecodedInstruction = VCDiffInstructionType.NOOP;

            while (interleaveLength > 0)
            {
                if (!delta.CanRead)
                {
                    continue;
                }
                //read in
                var didBreakBeforeComplete = false;

                //try to read in all interleaved bytes
                //if not then it will buffer for next time
                previous.Write(delta.ReadBytes((int)interleaveLength).Span);
                using ByteBuffer incoming = new ByteBuffer(previous.ToArray());
                previous.SetLength(0);
                long initialLength = incoming.Length;

                InstructionDecoder instrDecoder = new InstructionDecoder(incoming, customTable);

                while (incoming.CanRead && TotalBytesDecoded < window.TargetWindowLength)
                {
                    int  decodedSize = 0;
                    byte mode        = 0;
                    VCDiffInstructionType instruction = VCDiffInstructionType.NOOP;

                    if (lastDecodedSize > 0 && lastDecodedInstruction != VCDiffInstructionType.NOOP)
                    {
                        decodedSize = lastDecodedSize;
                        instruction = lastDecodedInstruction;
                    }
                    else
                    {
                        instruction = instrDecoder.Next(out decodedSize, out mode);

                        switch (instruction)
                        {
                        case VCDiffInstructionType.EOD:
                            didBreakBeforeComplete = true;
                            break;

                        case VCDiffInstructionType.ERROR:
                            targetData.SetLength(0);
                            return(VCDiffResult.ERROR);
                        }
                    }

                    //if instruction is EOD then decodedSize will be 0 as well
                    //the last part of the buffer containing the instruction will be
                    //buffered for the next loop
                    lastDecodedInstruction = instruction;
                    lastDecodedSize        = decodedSize;

                    if (didBreakBeforeComplete)
                    {
                        //we don't have all the data so store this pointer into a temporary list to resolve next loop
                        didBreakBeforeComplete = true;
                        interleaveLength      -= incoming.Position;

                        if (initialLength - incoming.Position > 0)
                        {
                            previous.Write(incoming.ReadBytes((int)(initialLength - incoming.Position)).Span);
                        }

                        break;
                    }

                    switch (instruction)
                    {
                    case VCDiffInstructionType.ADD:
                        result = DecodeAdd(decodedSize, incoming);
                        break;

                    case VCDiffInstructionType.RUN:
                        result = DecodeRun(decodedSize, incoming);
                        break;

                    case VCDiffInstructionType.COPY:
                        result = DecodeCopy(decodedSize, mode, incoming);
                        break;

                    default:
                        targetData.SetLength(0);
                        return(VCDiffResult.ERROR);
                    }

                    if (result == VCDiffResult.EOD)
                    {
                        //we don't have all the data so store this pointer into a temporary list to resolve next loop
                        didBreakBeforeComplete = true;
                        interleaveLength      -= incoming.Position;

                        if (initialLength - incoming.Position > 0)
                        {
                            previous.Write(incoming.ReadBytes((int)(initialLength - incoming.Position)).Span);
                        }

                        break;
                    }

                    //reset these as we have successfully used them
                    lastDecodedInstruction = VCDiffInstructionType.NOOP;
                    lastDecodedSize        = 0;
                }

                if (!didBreakBeforeComplete)
                {
                    interleaveLength -= initialLength;
                }
            }

            if (window.ChecksumFormat == ChecksumFormat.SDCH)
            {
                uint adler = Checksum.ComputeGoogleAdler32(targetData.GetBuffer().AsMemory(0, (int)targetData.Length));

                if (adler != window.Checksum)
                {
                    result = VCDiffResult.ERROR;
                }
            }

            return(result);
        }
示例#3
0
        /// <summary>
        /// Encodes the data using the settings from initialization
        /// </summary>
        /// <param name="newData">the target data</param>
        /// <param name="outputStream">the out stream</param>
        public unsafe void EncodeChunk(ByteBuffer newData, Stream outputStream)
        {
            newData.Position = 0;
            ReadOnlyMemory <byte> checksumBytes = newData.ReadBytes((int)newData.Length);

            uint checksum = this.checksumFormat switch
            {
                ChecksumFormat.SDCH => Checksum.ComputeGoogleAdler32(checksumBytes),
                ChecksumFormat.Xdelta3 => Checksum.ComputeXdelta3Adler32(checksumBytes),
                ChecksumFormat.None => 0,
                _ => 0
            };

            windowEncoder = new WindowEncoder(oldData.Length, checksum, this.checksumFormat, this.interleaved);

            oldData.Position = 0;
            newData.Position = 0;

            long nextEncode       = newData.Position;
            long targetEnd        = newData.Length;
            long startOfLastBlock = targetEnd - this.dictionary.blockSize;
            long candidatePos     = nextEncode;

            ulong hash;

            //create the first hash
            hash = hasher.Hash(newData.DangerousGetBytePointerAtCurrentPositionAndIncreaseOffsetAfter(0),
                               this.dictionary.blockSize);


            byte *newDataPtr = newData.DangerousGetBytePointer();

            while (true)
            {
                //if less than block size exit and then write as an ADD
                if (newData.Length - nextEncode < this.dictionary.blockSize)
                {
                    break;
                }


                //try and encode the copy and add instructions that best match
                var bytesEncoded = EncodeCopyForBestMatch(hash, candidatePos, nextEncode, targetEnd, newDataPtr, newData);

                if (bytesEncoded > 0)
                {
                    nextEncode  += bytesEncoded;
                    candidatePos = nextEncode;

                    if (candidatePos > startOfLastBlock)
                    {
                        break;
                    }

                    newData.Position = candidatePos;
                    //cannot use rolling hash since we skipped so many
                    hash = hasher.Hash(newData.DangerousGetBytePointerAtCurrentPositionAndIncreaseOffsetAfter(this.dictionary.blockSize), this.dictionary.blockSize);
                }
                else
                {
                    if (candidatePos + 1 > startOfLastBlock)
                    {
                        break;
                    }

                    //update hash requires the first byte of the last hash as well as the byte that is first byte pos + blockSize
                    //in order to properly calculate the rolling hash
                    newData.Position = candidatePos;
                    byte peek0 = newData.ReadByte();
                    newData.Position = candidatePos + this.dictionary.blockSize;
                    byte peek1 = newData.ReadByte();
                    hash = hasher.UpdateHash(hash, peek0, peek1);
                    candidatePos++;
                }
            }

            //Add the rest of the data that was not encoded
            if (nextEncode < newData.Length)
            {
                int len = (int)(newData.Length - nextEncode);
                newData.Position = nextEncode;
                windowEncoder.Add(newData.ReadBytes(len).Span);
            }

            //output the final window
            windowEncoder.Output(outputStream);
        }