Пример #1
0
        /// <summary>Reads the custom code table, if there is one</summary>
        void ReadCodeTable()
        {
            // The length given includes the nearSize and sameSize bytes
            int compressedTableLength = IOHelper.ReadBigEndian7BitEncodedInt(delta) - 2;
            int nearSize = IOHelper.CheckedReadByte(delta);
            int sameSize = IOHelper.CheckedReadByte(delta);

            byte[] compressedTableData = IOHelper.CheckedReadBytes(delta, compressedTableLength);

            byte[] defaultTableData = CodeTable.Default.GetBytes();

            MemoryStream tableOriginal = new MemoryStream(defaultTableData, false);
            MemoryStream tableDelta    = new MemoryStream(compressedTableData, false);

            byte[]       decompressedTableData = new byte[1536];
            MemoryStream tableOutput           = new MemoryStream(decompressedTableData, true);

            Decode(tableOriginal, tableDelta, tableOutput, 0);

            if (tableOutput.Position != 1536)
            {
                throw new VcdiffFormatException("Compressed code table was incorrect size");
            }

            codeTable = new CodeTable(decompressedTableData);
            cache     = new AddressCache(nearSize, sameSize);
        }
Пример #2
0
        private void ReadHeader()
        {
            byte[] array = IOHelper.CheckedReadBytes(delta, 4);
            if (array[0] != 214 || array[1] != 195 || array[2] != 196)
            {
                throw new VcdiffFormatException("Invalid VCDIFF header in delta stream");
            }
            if (array[3] != 0)
            {
                throw new VcdiffFormatException("VcdiffDecoder can only read delta streams of version 0");
            }
            byte b = IOHelper.CheckedReadByte(delta);

            if ((b & 1) != 0)
            {
                throw new VcdiffFormatException("VcdiffDecoder does not handle delta stream using secondary compressors");
            }
            bool flag  = (b & 2) != 0;
            bool flag2 = (b & 4) != 0;

            if ((b & 0xF8) != 0)
            {
                throw new VcdiffFormatException("Invalid header indicator - bits 3-7 not all zero.");
            }
            if (flag)
            {
                ReadCodeTable();
            }
            if (flag2)
            {
                int size = IOHelper.ReadBigEndian7BitEncodedInt(delta);
                IOHelper.CheckedReadBytes(delta, size);
            }
        }
Пример #3
0
        /// <summary>Read the header, including any custom code table. The delta stream is left positioned at the start of the first window.</summary>
        void ReadHeader()
        {
            byte[] header = IOHelper.CheckedReadBytes(delta, 4);
            if (header[0] != 0xd6 ||
                header[1] != 0xc3 ||
                header[2] != 0xc4)
            {
                throw new VcdiffFormatException("Invalid VCDIFF header in delta stream");
            }
            if (header[3] != 0)
            {
                throw new VcdiffFormatException("VcdiffDecoder can only read delta streams of version 0");
            }

            // Load the header indicator
            byte headerIndicator = IOHelper.CheckedReadByte(delta);

            if ((headerIndicator & 1) != 0)
            {
                throw new VcdiffFormatException
                          ("VcdiffDecoder does not handle delta stream using secondary compressors");
            }
            bool customCodeTable   = ((headerIndicator & 2) != 0);
            bool applicationHeader = ((headerIndicator & 4) != 0);

            if ((headerIndicator & 0xf8) != 0)
            {
                throw new VcdiffFormatException("Invalid header indicator - bits 3-7 not all zero.");
            }

            // Load the custom code table, if there is one
            if (customCodeTable)
            {
                ReadCodeTable();
            }

            // Ignore the application header if we have one. This tells xdelta3 what the right filenames are.
            if (applicationHeader)
            {
                int appHeaderLength = IOHelper.ReadBigEndian7BitEncodedInt(delta);
                IOHelper.CheckedReadBytes(delta, appHeaderLength);
            }
        }
Пример #4
0
        private void ReadCodeTable()
        {
            int size     = IOHelper.ReadBigEndian7BitEncodedInt(delta) - 2;
            int nearSize = IOHelper.CheckedReadByte(delta);
            int sameSize = IOHelper.CheckedReadByte(delta);

            byte[]       buffer        = IOHelper.CheckedReadBytes(delta, size);
            byte[]       bytes         = CodeTable.Default.GetBytes();
            MemoryStream memoryStream  = new MemoryStream(bytes, writable: false);
            MemoryStream memoryStream2 = new MemoryStream(buffer, writable: false);

            byte[]       array         = new byte[1536];
            MemoryStream memoryStream3 = new MemoryStream(array, writable: true);

            Decode(memoryStream, memoryStream2, memoryStream3, 0L);
            if (memoryStream3.Position != 1536)
            {
                throw new VcdiffFormatException("Compressed code table was incorrect size");
            }
            codeTable = new CodeTable(array);
            cache     = new AddressCache(nearSize, sameSize);
        }
Пример #5
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>
        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 (whether we use it or not)
            if (hasAdler32Checksum)
            {
                IOHelper.CheckedReadBytes(delta, 4);
            }

            // 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);

            // update the adler for the current window
            adler.Update(targetData, 0, targetLength);

            return(true);
        }
Пример #6
0
        private bool DecodeWindow()
        {
            int num = delta.ReadByte();

            if (num == -1)
            {
                return(false);
            }
            int  num2 = -1;
            bool flag = (num & 4) == 4;

            num &= 0xFB;
            Stream stream;

            switch (num & 3)
            {
            case 0:
                stream = null;
                break;

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

            case 2:
                stream = output;
                num2   = (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.");
            }
            byte[] array = null;
            int    num3  = 0;

            if (stream != null)
            {
                num3 = IOHelper.ReadBigEndian7BitEncodedInt(delta);
                int num4 = IOHelper.ReadBigEndian7BitEncodedInt(delta);
                stream.Position = num4;
                array           = IOHelper.CheckedReadBytes(stream, num3);
                if (num2 != -1)
                {
                    stream.Position = num2;
                }
            }
            IOHelper.ReadBigEndian7BitEncodedInt(delta);
            int num5 = IOHelper.ReadBigEndian7BitEncodedInt(delta);

            byte[]       array2       = new byte[num5];
            MemoryStream memoryStream = new MemoryStream(array2, writable: true);

            if (IOHelper.CheckedReadByte(delta) != 0)
            {
                throw new VcdiffFormatException("VcdiffDecoder is unable to handle compressed delta sections.");
            }
            int size  = IOHelper.ReadBigEndian7BitEncodedInt(delta);
            int size2 = IOHelper.ReadBigEndian7BitEncodedInt(delta);
            int size3 = IOHelper.ReadBigEndian7BitEncodedInt(delta);

            if (flag)
            {
                IOHelper.CheckedReadBytes(delta, 4);
            }
            byte[]       array3        = IOHelper.CheckedReadBytes(delta, size);
            byte[]       buffer        = IOHelper.CheckedReadBytes(delta, size2);
            byte[]       addresses     = IOHelper.CheckedReadBytes(delta, size3);
            int          num6          = 0;
            MemoryStream memoryStream2 = new MemoryStream(buffer, writable: false);

            cache.Reset(addresses);
            while (true)
            {
                int num7 = memoryStream2.ReadByte();
                if (num7 == -1)
                {
                    break;
                }
                for (int i = 0; i < 2; i++)
                {
                    Instruction instruction = codeTable[num7, i];
                    int         num8        = instruction.Size;
                    if (num8 == 0 && instruction.Type != 0)
                    {
                        num8 = IOHelper.ReadBigEndian7BitEncodedInt(memoryStream2);
                    }
                    switch (instruction.Type)
                    {
                    case InstructionType.Add:
                        memoryStream.Write(array3, num6, num8);
                        num6 += num8;
                        break;

                    case InstructionType.Copy:
                    {
                        int num9 = cache.DecodeAddress((int)memoryStream.Position + num3, instruction.Mode);
                        if (array != null && num9 < array.Length)
                        {
                            memoryStream.Write(array, num9, num8);
                            break;
                        }
                        num9 -= num3;
                        if (num9 + num8 < memoryStream.Position)
                        {
                            memoryStream.Write(array2, num9, num8);
                            break;
                        }
                        for (int k = 0; k < num8; k++)
                        {
                            memoryStream.WriteByte(array2[num9++]);
                        }
                        break;
                    }

                    case InstructionType.Run:
                    {
                        byte value = array3[num6++];
                        for (int j = 0; j < num8; j++)
                        {
                            memoryStream.WriteByte(value);
                        }
                        break;
                    }

                    default:
                        throw new VcdiffFormatException("Invalid instruction type found.");

                    case InstructionType.NoOp:
                        break;
                    }
                }
            }
            output.Write(array2, 0, num5);
            adler.Update(array2, 0, num5);
            return(true);
        }