コード例 #1
0
        public static bool Patch(Stream input, Stream delta, Stream output)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (delta == null)
            {
                throw new ArgumentNullException("delta");
            }

            if (output == null)
            {
                throw new ArgumentNullException("output");
            }

            const Endian endian = Endian.Big;

            var work       = new byte[0x10000];
            var inputBytes = new byte[0x10000];
            var deltaBytes = new byte[0x10000];

            while (delta.Position < delta.Length)
            {
                var rawFlags = delta.ReadValueU32(endian);
                var count    = (int)(rawFlags & 0xFFFFFFF);
                var type     = (PatchType)(rawFlags >> 28);

                switch (type)
                {
                case PatchType.Copy:
                {
                    for (int i = 0; i < count; i++)
                    {
                        var inputRead = CompressionHelper.DecompressBlock(input, inputBytes, work);
                        output.Write(inputBytes, 0, inputRead);
                    }
                    break;
                }

                case PatchType.CompressedChange:
                {
                    var inputRead = CompressionHelper.DecompressBlock(input, inputBytes, work);
                    int o         = 0;
                    for (int i = 0; i < count; i++)
                    {
                        var inputOffset     = delta.ReadValueU16(endian);
                        var inputSkipLength = delta.ReadValueU16(endian);
                        var inputCopyLength = inputOffset - o;
                        if (o + inputCopyLength > inputRead)
                        {
                            throw new EndOfStreamException();
                        }
                        output.Write(inputBytes, o, inputCopyLength);
                        var deltaRead = CompressionHelper.DecompressBlock(delta, deltaBytes, work);
                        output.Write(deltaBytes, 0, deltaRead);
                        o = inputOffset + inputSkipLength;
                    }
                    output.Write(inputBytes, o, inputRead - o);
                    break;
                }

                case PatchType.UncompressedChange:
                {
                    var inputRead    = CompressionHelper.DecompressBlock(input, inputBytes, work);
                    var totalSize    = 1 + delta.ReadValueU16(endian);
                    var basePosition = output.Position;
                    using (var temp = delta.ReadToMemoryStream(count))
                    {
                        temp.Position = 0;
                        int o = 0;
                        while (temp.Position < temp.Length)
                        {
                            var inputOffset     = temp.ReadValueU16(endian);
                            var inputSkipLength = temp.ReadValueU8();
                            var deltaCopyLength = temp.ReadValueU8();

                            var inputCopyLength = inputOffset - o;
                            if (o + inputCopyLength > inputRead)
                            {
                                throw new EndOfStreamException();
                            }
                            output.Write(inputBytes, o, inputCopyLength);

                            if (deltaCopyLength > 0)
                            {
                                var deltaRead = temp.Read(deltaBytes, 0, deltaCopyLength);
                                if (deltaRead != deltaCopyLength)
                                {
                                    throw new EndOfStreamException();
                                }
                                output.Write(deltaBytes, 0, deltaCopyLength);
                            }

                            o = inputOffset + inputSkipLength;
                        }
                        output.Write(inputBytes, o, inputRead - o);
                    }
                    if ((output.Position - basePosition) != totalSize)
                    {
                        throw new InvalidOperationException();
                    }
                    break;
                }

                case PatchType.Add:
                {
                    for (int i = 0; i < count; i++)
                    {
                        var deltaRead = CompressionHelper.DecompressBlock(delta, deltaBytes, work);
                        output.Write(deltaBytes, 0, deltaRead);
                    }
                    break;
                }

                case PatchType.Remove:
                {
                    for (int i = 0; i < count; i++)
                    {
                        CompressionHelper.SkipBlock(input);
                    }
                    break;
                }

                default:
                {
                    throw new NotImplementedException();
                }
                }
            }

            if (delta.Position != delta.Length)
            {
                throw new InvalidOperationException();
            }

            return(true);
        }