Example #1
0
        private bool DecodeWindow()
        {
            // Win_Indicator
            var winIndicator = IOUtils.CheckedReadByte(delta);

            var fromSource = ((winIndicator & VCD_SOURCE) != 0);
            var fromTarget = ((winIndicator & VCD_TARGET) != 0);

            if (fromSource && fromTarget)
            {
                throw new VcdiffFormatException("Invalid window indicator : only one bit of VCD_SOURCE and VCD_TARGET must be set");
            }

            Stream sourceStream           = null;
            var    sourceStreamPostionBak = -1;

            if (fromSource)
            {
                sourceStream = origin;
            }
            else if (fromTarget)
            {
                sourceStream           = target;
                sourceStreamPostionBak = (int)target.Position;
            }

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

            if (sourceStream != null)
            {
                // Read source position and
                sourceLength = IOUtils.ReadBigEndian7BitEncodedInt(delta);
                var sourcePosition = IOUtils.ReadBigEndian7BitEncodedInt(delta);

                sourceStream.Position = sourcePosition;
                sourceData            = IOUtils.CheckedReadBytes(sourceStream, sourceLength);

                // Reposition the source stream if appropriate
                if (sourceStreamPostionBak != -1)
                {
                    sourceStream.Position = sourceStreamPostionBak;
                }
            }

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

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

            var targetData = new byte[targetLength];

            using (var targetDataStream = new MemoryStream(targetData, true))
            {
                var deltaIndicator = IOUtils.CheckedReadByte(delta);
                if (deltaIndicator != 0)
                {
                    throw new VcdiffFormatException("This implementation does not support delta stream with secondary compressors");
                }

                var addRunLength = IOUtils.ReadBigEndian7BitEncodedInt(delta);

                var instructionsLength = IOUtils.ReadBigEndian7BitEncodedInt(delta);

                var addrLength = IOUtils.ReadBigEndian7BitEncodedInt(delta);

                // ADD/RUN data section, containing all unmatched data for the ADD and RUN instructions
                var addRunData = IOUtils.CheckedReadBytes(delta, addRunLength);

                // List of instructions and their sizes section
                var instructions = IOUtils.CheckedReadBytes(delta, instructionsLength);

                // Initialize AddressCache with addresses section for COPY
                cache.Init(IOUtils.CheckedReadBytes(delta, addrLength));

                var addRunDataIndex = 0;

                var instructionStream = new MemoryStream(instructions, false);

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

                    for (var i = 0; i < 2; i++)
                    {
                        var instruction = codeTable[instructionIndex, i];

                        // 1st argument : Instruction size
                        int size = instruction.Size;
                        if (size == 0 && instruction.Inst != InstructionType.NoOp)
                        {
                            // Custom size, read from stream
                            size = IOUtils.ReadBigEndian7BitEncodedInt(instructionStream);
                        }

                        switch (instruction.Inst)
                        {
                        case InstructionType.NoOp:
                            break;

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

                        case InstructionType.Copy:
                            // 5.3 Encoding of COPY instruction addresses

                            // address of the current location in the target data
                            var here = (int)targetDataStream.Position + sourceLength;

                            // address of the COPY instruction to execute
                            var addr = cache.DecodeAddress(here, instruction.Mode);

                            if (sourceData != null && addr < sourceData.Length)
                            {
                                // Regular copy
                                targetDataStream.Write(sourceData, addr, size);
                            }
                            else
                            {
                                // Data is in target data : see Section 3. for an example of COPY overlapping

                                // Get rid of the offset
                                addr -= sourceLength;

                                // Can we just ignore overlap issues ?
                                if (addr + size < targetDataStream.Position)
                                {
                                    targetDataStream.Write(targetData, addr, size);
                                }
                                else
                                {
                                    // No, we must write byte one by one, because we copy a repeating pattern
                                    for (var j = 0; j < size; j++)
                                    {
                                        targetDataStream.WriteByte(targetData[addr++]);
                                    }
                                }
                            }
                            break;

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

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

            // Write decoded datas
            target.Write(targetData, 0, targetLength);

            return(false);
        }