Beispiel #1
0
        private void CreatePatchInternal()
        {
            Source.Position = 0;
            Target.Position = 0;
            ulong sourceSize     = (ulong)Source.Length;
            ulong targetSize     = (ulong)Target.Length;
            var   sourceChecksum = ChecksumUtils.CalculateCRC32ForEntireStream(Source);
            var   targetChecksum = ChecksumUtils.CalculateCRC32ForEntireStream(Target);

            // header
            PatchOut.WriteUInt32(0x31535042, EndianUtils.Endianness.LittleEndian);
            PatchOut.WriteUnsignedNumber(sourceSize);
            PatchOut.WriteUnsignedNumber(targetSize);
            PatchOut.WriteUnsignedNumber(0);             // metadata

            // actions
            while (Target.Position < Target.Length)
            {
                int  s;
                int  t;
                bool advancedS;
                bool advancedT;
                if (IsNextByteSameInSourceAndTarget(out s, out t, out advancedS, out advancedT))
                {
                    ulong count = 1;
                    while (IsNextByteSameInSourceAndTarget(out s, out t, out advancedS, out advancedT))
                    {
                        ++count;
                    }
                    if (advancedS)
                    {
                        Source.Position -= 1;
                    }
                    if (advancedT)
                    {
                        Target.Position -= 1;
                    }
                    PatchOut.WriteAction(HyoutaUtils.Bps.Action.SourceRead, count);
                }
                else
                {
                    if (advancedS)
                    {
                        Source.Position -= 1;
                    }
                    if (advancedT)
                    {
                        Target.Position -= 1;
                    }
                    long  p     = Target.Position;
                    ulong count = 0;
                    while (ShouldWriteNextByteFromTarget(out s, out t, out advancedS, out advancedT))
                    {
                        ++count;
                    }
                    if (advancedS)
                    {
                        Source.Position -= 1;
                    }
                    PatchOut.WriteAction(HyoutaUtils.Bps.Action.TargetRead, count);
                    Target.Position = p;
                    StreamUtils.CopyStream(Target, PatchOut, (long)count);
                }
            }

            PatchOut.WriteUInt32(sourceChecksum.Value, EndianUtils.Endianness.LittleEndian);
            PatchOut.WriteUInt32(targetChecksum.Value, EndianUtils.Endianness.LittleEndian);

            long checksumsize = PatchOut.Position;

            PatchOut.Position = 0;
            var patchChecksum = ChecksumUtils.CalculateCRC32FromCurrentPosition(PatchOut, checksumsize);

            PatchOut.WriteUInt32(patchChecksum.Value, EndianUtils.Endianness.LittleEndian);
        }
Beispiel #2
0
        private void ApplyPatchToStreamInternal()
        {
            Patch.Position  = 0;
            Target.Position = 0;

            long patchSize = Patch.Length;

            if (patchSize < 12)
            {
                throw new Exception("Patch too small to be a valid patch.");
            }
            long patchFooterPosition = patchSize - 12L;

            // note: spec doesn't actually say what endian, but files in the wild suggest little
            Patch.Position = patchFooterPosition;
            uint checksumSource = Patch.ReadUInt32().FromEndian(EndianUtils.Endianness.LittleEndian);
            uint checksumTarget = Patch.ReadUInt32().FromEndian(EndianUtils.Endianness.LittleEndian);
            uint checksumPatch  = Patch.ReadUInt32().FromEndian(EndianUtils.Endianness.LittleEndian);

            Patch.Position = 0;
            uint actualChecksumPatch = ChecksumUtils.CalculateCRC32FromCurrentPosition(Patch, patchSize - 4).Value;

            if (checksumPatch != actualChecksumPatch)
            {
                throw new Exception("Patch checksum incorrect.");
            }

            Patch.Position = 0;
            uint magic = Patch.ReadUInt32().FromEndian(EndianUtils.Endianness.LittleEndian);

            if (magic != 0x31535042)
            {
                throw new Exception("Wrong patch magic.");
            }

            ulong sourceSize = Patch.ReadUnsignedNumber();

            if (sourceSize != (ulong)Source.Length)
            {
                throw new Exception(string.Format("Source size mismatch. Actual size is {0}, patch wants {1}.", Source.Length, sourceSize));
            }
            ulong targetSize   = Patch.ReadUnsignedNumber();
            ulong metadataSize = Patch.ReadUnsignedNumber();

            if (metadataSize > 0)
            {
                // skip metadata, we don't care about it
                Patch.Position = (long)(((ulong)Patch.Position) + metadataSize);
            }

            Source.Position = 0;
            uint actualChecksumSource = ChecksumUtils.CalculateCRC32FromCurrentPosition(Source, Source.Length).Value;

            if (checksumSource != actualChecksumSource)
            {
                throw new Exception("Source checksum incorrect.");
            }

            Source.Position = 0;
            Target.Position = 0;
            while (Patch.Position < patchFooterPosition)
            {
                (Action action, ulong length) = Patch.ReadAction();
                switch (action)
                {
                case Action.SourceRead: DoSourceRead(length); break;

                case Action.TargetRead: DoTargetRead(length); break;

                case Action.SourceCopy: DoSourceCopy(length); break;

                case Action.TargetCopy: DoTargetCopy(length); break;
                }
            }

            if (Patch.Position != patchFooterPosition)
            {
                throw new Exception("Malformed action stream.");
            }

            if ((ulong)Target.Position != targetSize)
            {
                throw new Exception("Target size incorrect.");
            }

            Target.Position = 0;
            uint actualChecksumTarget = ChecksumUtils.CalculateCRC32FromCurrentPosition(Target, Target.Length).Value;

            if (checksumTarget != actualChecksumTarget)
            {
                throw new Exception("Target checksum incorrect.");
            }
        }
        private void ApplyPatchToStreamInternal()
        {
            PatchOut.WriteUInt32(0x31535042, EndianUtils.Endianness.LittleEndian);

            ulong       sourceSize     = 0;
            ulong       targetSize     = 0;
            uint        sourceChecksum = 0;
            uint        targetChecksum = 0;
            List <byte> metadata       = new List <byte>();

            // header
            string l = ReadLine();

            while (l != null && !l.StartsWith("SourceRead") && !l.StartsWith("TargetRead") && !l.StartsWith("SourceCopy") && !l.StartsWith("TargetCopy"))
            {
                if (l.StartsWith("SourceSize"))
                {
                    sourceSize = HexUtils.ParseDecOrHexUInt64(l.Split(whitespace, StringSplitOptions.RemoveEmptyEntries)[1]);
                }
                else if (l.StartsWith("TargetSize"))
                {
                    targetSize = HexUtils.ParseDecOrHexUInt64(l.Split(whitespace, StringSplitOptions.RemoveEmptyEntries)[1]);
                }
                else if (l.StartsWith("SourceChecksum"))
                {
                    sourceChecksum = HexUtils.ParseDecOrHex(l.Split(whitespace, StringSplitOptions.RemoveEmptyEntries)[1]);
                }
                else if (l.StartsWith("TargetChecksum"))
                {
                    targetChecksum = HexUtils.ParseDecOrHex(l.Split(whitespace, StringSplitOptions.RemoveEmptyEntries)[1]);
                }
                else if (l.StartsWith("Metadata"))
                {
                    metadata = ParseByteArray(l.Split(whitespace, 2, StringSplitOptions.RemoveEmptyEntries)[1]);
                }

                l = ReadLine();
            }
            PatchOut.WriteUnsignedNumber(sourceSize);
            PatchOut.WriteUnsignedNumber(targetSize);
            PatchOut.WriteUnsignedNumber((ulong)metadata.Count);
            foreach (byte b in metadata)
            {
                PatchOut.WriteByte(b);
            }

            // actions
            while (l != null)
            {
                if (l.StartsWith("SourceRead"))
                {
                    var   split  = l.Split(whitespace, StringSplitOptions.RemoveEmptyEntries);
                    ulong length = HexUtils.ParseDecOrHexUInt64(split[3]);
                    PatchOut.WriteAction(HyoutaUtils.Bps.Action.SourceRead, length);
                }
                else if (l.StartsWith("TargetRead"))
                {
                    List <byte> bytes = ParseByteArray(l.Split(whitespace, 2, StringSplitOptions.RemoveEmptyEntries)[1]);
                    PatchOut.WriteAction(HyoutaUtils.Bps.Action.TargetRead, (ulong)bytes.Count);
                    foreach (byte b in bytes)
                    {
                        PatchOut.WriteByte(b);
                    }
                }
                else if (l.StartsWith("SourceCopy"))
                {
                    var   split  = l.Split(whitespace, StringSplitOptions.RemoveEmptyEntries);
                    ulong length = HexUtils.ParseDecOrHexUInt64(split[3]);
                    long  offset;
                    if (split[1].ToLowerInvariant() == "absolute")
                    {
                        long pos = HexUtils.ParseDecOrHexInt64(split[2]);
                        offset = (pos - (long)SourceRelativeOffset);
                    }
                    else if (split[1].ToLowerInvariant() == "relative")
                    {
                        offset = HexUtils.ParseDecOrHexInt64(split[2]);
                    }
                    else
                    {
                        throw new Exception("SourceCopy argument must be 'absolute' or 'relative'.");
                    }
                    AddChecked(ref SourceRelativeOffset, offset, (long)targetSize);
                    SourceRelativeOffset += length;
                    PatchOut.WriteAction(HyoutaUtils.Bps.Action.SourceCopy, length);
                    PatchOut.WriteSignedNumber(offset);
                }
                else if (l.StartsWith("TargetCopy"))
                {
                    var   split  = l.Split(whitespace, StringSplitOptions.RemoveEmptyEntries);
                    ulong length = HexUtils.ParseDecOrHexUInt64(split[3]);
                    long  offset;
                    if (split[1].ToLowerInvariant() == "absolute")
                    {
                        long pos = HexUtils.ParseDecOrHexInt64(split[2]);
                        offset = (pos - (long)TargetRelativeOffset);
                    }
                    else if (split[1].ToLowerInvariant() == "relative")
                    {
                        offset = HexUtils.ParseDecOrHexInt64(split[2]);
                    }
                    else
                    {
                        throw new Exception("TargetCopy argument must be 'absolute' or 'relative'.");
                    }
                    AddChecked(ref TargetRelativeOffset, offset, (long)targetSize);
                    TargetRelativeOffset += length;
                    PatchOut.WriteAction(HyoutaUtils.Bps.Action.TargetCopy, length);
                    PatchOut.WriteSignedNumber(offset);
                }

                l = ReadLine();
            }

            PatchOut.WriteUInt32(sourceChecksum, EndianUtils.Endianness.LittleEndian);
            PatchOut.WriteUInt32(targetChecksum, EndianUtils.Endianness.LittleEndian);

            long checksumsize = PatchOut.Position;

            PatchOut.Position = 0;
            var patchChecksum = ChecksumUtils.CalculateCRC32FromCurrentPosition(PatchOut, checksumsize);

            PatchOut.WriteUInt32(patchChecksum.Value, EndianUtils.Endianness.LittleEndian);
        }
        private void ApplyPatchToStreamInternal()
        {
            Patch.Position = 0;
            TargetPosition = 0;

            long patchSize = Patch.Length;

            if (patchSize < 12)
            {
                throw new Exception("Patch too small to be a valid patch.");
            }
            long patchFooterPosition = patchSize - 12L;

            // note: spec doesn't actually say what endian, but files in the wild suggest little
            Patch.Position = patchFooterPosition;
            uint checksumSource = Patch.ReadUInt32().FromEndian(EndianUtils.Endianness.LittleEndian);
            uint checksumTarget = Patch.ReadUInt32().FromEndian(EndianUtils.Endianness.LittleEndian);
            uint checksumPatch  = Patch.ReadUInt32().FromEndian(EndianUtils.Endianness.LittleEndian);

            Patch.Position = 0;
            uint actualChecksumPatch = ChecksumUtils.CalculateCRC32FromCurrentPosition(Patch, patchSize - 4).Value;

            if (checksumPatch != actualChecksumPatch)
            {
                throw new Exception("Patch checksum incorrect.");
            }

            Patch.Position = 0;
            uint magic = Patch.ReadUInt32().FromEndian(EndianUtils.Endianness.LittleEndian);

            if (magic != 0x31535042)
            {
                throw new Exception("Wrong patch magic.");
            }

            ulong sourceSize = Patch.ReadUnsignedNumber();

            WriteText(string.Format("SourceSize 0x{0:x}", sourceSize));
            SourceLength = (long)sourceSize;
            ulong targetSize = Patch.ReadUnsignedNumber();

            WriteText(string.Format("TargetSize 0x{0:x}", targetSize));
            TargetLength = 0;
            ulong metadataSize = Patch.ReadUnsignedNumber();

            if (metadataSize > 0)
            {
                StringBuilder sb = new StringBuilder("Metadata");
                ReadPatchBytesToStringBuilder(sb, metadataSize);
                WriteText(sb.ToString());
            }

            WriteText(string.Format("SourceChecksum 0x{0:x}", checksumSource));
            WriteText(string.Format("TargetChecksum 0x{0:x}", checksumTarget));

            SourcePosition = 0;
            uint actualChecksumSource = checksumSource;

            SourcePosition = 0;
            TargetPosition = 0;
            while (Patch.Position < patchFooterPosition)
            {
                (HyoutaUtils.Bps.Action action, ulong length) = Patch.ReadAction();
                switch (action)
                {
                case HyoutaUtils.Bps.Action.SourceRead: DoSourceRead(length); break;

                case HyoutaUtils.Bps.Action.TargetRead: DoTargetRead(length); break;

                case HyoutaUtils.Bps.Action.SourceCopy: DoSourceCopy(length); break;

                case HyoutaUtils.Bps.Action.TargetCopy: DoTargetCopy(length); break;
                }
            }

            if (Patch.Position != patchFooterPosition)
            {
                throw new Exception("Malformed action stream.");
            }

            if ((ulong)TargetPosition != targetSize)
            {
                throw new Exception("Target size incorrect.");
            }

            TargetPosition = 0;
            uint actualChecksumTarget = checksumTarget;
        }