예제 #1
0
        VCDiffResult DecodeCopy(int size, byte mode, ByteBuffer addresses)
        {
            long here    = window.SourceLength + decodedOnly;
            long decoded = addressCache.DecodeAddress(here, mode, addresses);

            switch ((VCDiffResult)decoded)
            {
            case VCDiffResult.ERRROR:
                return(VCDiffResult.ERRROR);

            case VCDiffResult.EOD:
                return(VCDiffResult.EOD);

            default:
                if (decoded < 0 || decoded > here)
                {
                    return(VCDiffResult.ERRROR);
                }
                break;
            }

            if (decoded + size <= window.SourceLength)
            {
                dict.Position = decoded;
                byte[] rbytes = dict.ReadBytes(size);
                sout.writeBytes(rbytes);
                targetData.AddRange(rbytes);
                decodedOnly += size;
                return(VCDiffResult.SUCCESS);
            }

            ///will come back to this once
            ///target data reading is implemented

            /*if(decoded < window.SourceLength)
             * {
             *   long partial = window.SourceLength - decoded;
             *   dict.Position = decoded;
             *   sout.writeBytes(dict.ReadBytes((int)partial));
             *   bytesWritten += partial;
             *   size -= (int)partial;
             * }
             *
             * decoded -= window.SourceLength;
             *
             * while(size > (bytesDecoded - decoded))
             * {
             *   long partial = bytesDecoded - decoded;
             *   target.Position = decoded;
             *   sout.writeBytes(target.ReadBytes((int)partial));
             *   decoded += partial;
             *   size -= (int)partial;
             *   bytesWritten += partial;
             * }
             *
             * target.Position = decoded;
             * sout.writeBytes(target.ReadBytes(size));*/

            return(VCDiffResult.ERRROR);
        }
예제 #2
0
        private VCDiffResult DecodeCopy(int size, byte mode, ByteBuffer addresses)
        {
            long hereAddress    = window.SourceSegmentLength + this.TotalBytesDecoded;
            long decodedAddress = addressCache.DecodeAddress(hereAddress, mode, addresses);

            switch ((VCDiffResult)decodedAddress)
            {
            case VCDiffResult.ERROR:
                return(VCDiffResult.ERROR);

            case VCDiffResult.EOD:
                return(VCDiffResult.EOD);

            default:
                if (decodedAddress < 0 || decodedAddress > hereAddress)
                {
                    return(VCDiffResult.ERROR);
                }
                break;
            }

            // Copy all data from source segment
            if (decodedAddress + size <= window.SourceSegmentLength)
            {
                source.Position = decodedAddress + window.SourceSegmentOffset;
                var rbytes = source.ReadBytes(size).Span;
                //outputStream.Write(rbytes);
                targetData.Write(rbytes);
                this.TotalBytesDecoded += size;
                return(VCDiffResult.SUCCESS);
            }

            // Copy some data from target window...
            if (decodedAddress < window.SourceSegmentLength)
            {
                // ... plus some data from source segment
                long partialCopySize = window.SourceSegmentLength - decodedAddress;
                source.Position = decodedAddress + +window.SourceSegmentOffset;
                var rbytes = source.ReadBytes((int)partialCopySize).Span;
                //outputStream.Write(rbytes);
                targetData.Write(rbytes);
                this.TotalBytesDecoded += partialCopySize;
                decodedAddress         += partialCopySize;
                size -= (int)partialCopySize;
            }

            decodedAddress -= window.SourceSegmentLength;
            bool overlap = decodedAddress + size >= this.TotalBytesDecoded;

            if (overlap)
            {
                int availableData = (int)(this.TotalBytesDecoded - decodedAddress);
                for (int i = 0; i < size; i += availableData)
                {
                    int toCopy    = (size - i < availableData) ? size - i : availableData;
                    var tbytesBuf = targetData.GetBuffer().AsSpan((int)decodedAddress + i, toCopy);
                    //outputStream.Write(tbytesBuf);
                    targetData.Write(tbytesBuf);
                    this.TotalBytesDecoded += toCopy;
                }
            }
            else
            {
                var fbytes = targetData.GetBuffer().AsSpan((int)decodedAddress, size);
                //outputStream.Write(fbytes);
                targetData.Write(fbytes);
                this.TotalBytesDecoded += size;
            }
            return(VCDiffResult.SUCCESS);
        }
예제 #3
0
        /// <summary>
        /// Reads and decodes a window, returning whether or not there was
        /// any more data to read.
        /// </summary>
        /// <returns>
        /// Whether or not the delta stream had reached the end of its data.
        /// </returns>
        private bool DecodeWindow()
        {
            int windowIndicator = delta.ReadByte();

            // Have we finished?
            if (windowIndicator == -1)
            {
                return(false);
            }

            // The stream to load source data from for this window, if any
            Stream sourceStream;
            // Where to reposition the source stream to after reading from it, if anywhere
            int sourceStreamPostReadSeek = -1;

            // xdelta3 uses an undocumented extra bit which indicates that there are an extra
            // 4 bytes at the end of the encoding for the window
            bool hasAdler32Checksum = ((windowIndicator & 4) == 4);

            // Get rid of the checksum bit for the rest
            windowIndicator &= 0xfb;

            // Work out what the source data is, and detect invalid window indicators
            switch (windowIndicator & 3)
            {
            // No source data used in this window
            case 0:
                sourceStream = null;
                break;

            // Source data comes from the original stream
            case 1:
                if (original == null)
                {
                    throw new VcdiffFormatException
                              ("Source stream requested by delta but not provided by caller.");
                }
                sourceStream = original;
                break;

            case 2:
                sourceStream             = output;
                sourceStreamPostReadSeek = (int)output.Position;
                break;

            case 3:
                throw new VcdiffFormatException
                          ("Invalid window indicator - bits 0 and 1 both set.");

            default:
                throw new VcdiffFormatException("Invalid window indicator - bits 3-7 not all zero.");
            }

            // Read the source data, if any
            byte[] sourceData   = null;
            int    sourceLength = 0;

            if (sourceStream != null)
            {
                sourceLength = IOHelper.ReadBigEndian7BitEncodedInt(delta);
                int sourcePosition = IOHelper.ReadBigEndian7BitEncodedInt(delta);

                sourceStream.Position = sourcePosition;

                sourceData = IOHelper.CheckedReadBytes(sourceStream, sourceLength);
                // Reposition the source stream if appropriate
                if (sourceStreamPostReadSeek != -1)
                {
                    sourceStream.Position = sourceStreamPostReadSeek;
                }
            }

            // Read how long the delta encoding is - then ignore it
            IOHelper.ReadBigEndian7BitEncodedInt(delta);

            // Read how long the target window is
            int targetLength = IOHelper.ReadBigEndian7BitEncodedInt(delta);

            byte[]       targetData       = new byte[targetLength];
            MemoryStream targetDataStream = new MemoryStream(targetData, true);

            // Read the indicator and the lengths of the different data sections
            byte deltaIndicator = IOHelper.CheckedReadByte(delta);

            if (deltaIndicator != 0)
            {
                throw new VcdiffFormatException("VcdiffDecoder is unable to handle compressed delta sections.");
            }

            int addRunDataLength   = IOHelper.ReadBigEndian7BitEncodedInt(delta);
            int instructionsLength = IOHelper.ReadBigEndian7BitEncodedInt(delta);
            int addressesLength    = IOHelper.ReadBigEndian7BitEncodedInt(delta);

            // If we've been given a checksum, we have to read it and we might as well
            // use it to check the data.
            int checksumInFile = 0;

            if (hasAdler32Checksum)
            {
                byte[] checksumBytes = IOHelper.CheckedReadBytes(delta, 4);
                checksumInFile = (checksumBytes[0] << 24) | (checksumBytes[1] << 16) | (checksumBytes[2] << 8) | checksumBytes[3];
            }

            // Read all the data for this window
            byte[] addRunData   = IOHelper.CheckedReadBytes(delta, addRunDataLength);
            byte[] instructions = IOHelper.CheckedReadBytes(delta, instructionsLength);
            byte[] addresses    = IOHelper.CheckedReadBytes(delta, addressesLength);

            int addRunDataIndex = 0;

            MemoryStream instructionStream = new MemoryStream(instructions, false);

            _cache.Reset(addresses);

            while (true)
            {
                int instructionIndex = instructionStream.ReadByte();
                if (instructionIndex == -1)
                {
                    break;
                }

                for (int i = 0; i < 2; i++)
                {
                    Instruction instruction = _codeTable[instructionIndex, i];
                    int         size        = instruction.Size;
                    if (size == 0 && instruction.Type != InstructionType.NoOp)
                    {
                        size = IOHelper.ReadBigEndian7BitEncodedInt(instructionStream);
                    }
                    switch (instruction.Type)
                    {
                    case InstructionType.NoOp:
                        break;

                    case InstructionType.Add:
                        targetDataStream.Write(addRunData, addRunDataIndex, size);
                        addRunDataIndex += size;
                        break;

                    case InstructionType.Copy:
                        int addr = _cache.DecodeAddress((int)targetDataStream.Position + sourceLength, instruction.Mode);
                        if (sourceData != null && addr < sourceData.Length)
                        {
                            targetDataStream.Write(sourceData, addr, size);
                        }
                        else                                 // Data is in target data
                        {
                            // Get rid of the offset
                            addr -= sourceLength;
                            // Can we just ignore overlap issues?
                            if (addr + size < targetDataStream.Position)
                            {
                                targetDataStream.Write(targetData, addr, size);
                            }
                            else
                            {
                                for (int j = 0; j < size; j++)
                                {
                                    targetDataStream.WriteByte(targetData[addr++]);
                                }
                            }
                        }
                        break;

                    case InstructionType.Run:
                        byte data = addRunData[addRunDataIndex++];
                        for (int j = 0; j < size; j++)
                        {
                            targetDataStream.WriteByte(data);
                        }
                        break;

                    default:
                        throw new VcdiffFormatException("Invalid instruction type found.");
                    }
                }
            }
            output.Write(targetData, 0, targetLength);

            if (hasAdler32Checksum)
            {
                int actualChecksum = Adler32.ComputeChecksum(1, targetData);
                if (actualChecksum != checksumInFile)
                {
                    throw new VcdiffFormatException("Invalid checksum after decoding window");
                }
            }
            return(true);
        }