private static void WriteLocaleChanges(Patch patch, IWriter writer)
        {
            if (patch.LanguageChanges.Count == 0)
                return;

            long startPos = writer.Position;
            writer.WriteInt32(AssemblyPatchBlockID.Locl);
            writer.WriteUInt32(0); // Size filled in later
            writer.WriteByte(0); // Version 0

            // Write change data for each language
            writer.WriteByte((byte)patch.LanguageChanges.Count);
            foreach (LanguageChange language in patch.LanguageChanges)
            {
                writer.WriteByte(language.LanguageIndex);

                // Write the change data for each string in the language
                writer.WriteInt32(language.LocaleChanges.Count);
                foreach (LocaleChange change in language.LocaleChanges)
                {
                    writer.WriteUInt16((ushort)change.Index);
                    writer.WriteUTF8(change.NewValue);
                }
            }

            // Fill in the block size
            long endPos = writer.Position;
            writer.SeekTo(startPos + 4);
            writer.WriteUInt32((uint)(endPos - startPos));
            writer.SeekTo(endPos);
        }
Example #2
0
        private void makePatch_Click(object sender, EventArgs e)
        {
            Patch patch = new Patch();
            patch.Name = patchName.Text;
            patch.Description = patchDescription.Text;
            patch.Author = patchAuthor.Text;

            IReader originalReader = new EndianReader(File.OpenRead(unmoddedPath.Text), Endian.BigEndian);
            IReader newReader = new EndianReader(File.OpenRead(moddedPath.Text), Endian.BigEndian);

            ThirdGenVersionInfo version = new ThirdGenVersionInfo(originalReader);
            BuildInfoLoader loader = new BuildInfoLoader(XDocument.Load(@"Formats\SupportedBuilds.xml"), @"Formats\");
            BuildInformation buildInfo = loader.LoadBuild(version.BuildString);
            ThirdGenCacheFile originalFile = new ThirdGenCacheFile(originalReader, buildInfo, version.BuildString);
            ThirdGenCacheFile newFile = new ThirdGenCacheFile(newReader, buildInfo, version.BuildString);

            MetaComparer.CompareMeta(originalFile, originalReader, newFile, newReader, patch);
            LocaleComparer.CompareLocales(originalFile, originalReader, newFile, newReader, patch);

            originalReader.Close();
            newReader.Close();

            IWriter output = new EndianWriter(File.OpenWrite(outPath.Text), Endian.BigEndian);
            AssemblyPatchWriter.WritePatch(patch, output);
            output.Close();

            MessageBox.Show("Done!");
        }
Example #3
0
        /// <summary>
        /// Compares the tag meta between two cache files and adds the results to a patch.
        /// </summary>
        /// <param name="originalFile">The unmodified cache file.</param>
        /// <param name="originalReader">A stream open on the unmodified cache file.</param>
        /// <param name="newFile">The modified cache file.</param>
        /// <param name="newReader">A stream open on the modified cache file.</param>
        /// <param name="output">The Patch to add results to.</param>
        public static void CompareMeta(ICacheFile originalFile, IReader originalReader, ICacheFile newFile, IReader newReader, Patch output)
        {
            // TODO: Handle files with expanded meta partitions
            uint address = originalFile.Info.MetaBase.AsAddress();
            uint offset = originalFile.Info.MetaBase.AsOffset();
            uint endOffset = offset + originalFile.Info.MetaSize;

            const int BufferSize = 0x1000;
            byte[] oldBuffer = new byte[BufferSize];
            byte[] newBuffer = new byte[BufferSize];

            int diffStart = 0;
            uint diffAddress = 0;
            int diffSize = 0;

            originalReader.SeekTo(offset);
            newReader.SeekTo(offset);
            while (offset < endOffset)
            {
                // Read the meta in large blocks and then compare the blocks
                originalReader.ReadBlock(oldBuffer, 0, BufferSize);
                newReader.ReadBlock(newBuffer, 0, BufferSize);
                for (int i = 0; i < oldBuffer.Length; i++)
                {
                    if (oldBuffer[i] != newBuffer[i])
                    {
                        if (diffSize == 0)
                        {
                            diffStart = i;
                            diffAddress = (uint)(address + i);
                        }
                        diffSize++;
                    }
                    else if (diffSize > 0)
                    {
                        // Copy the differing bytes to a buffer
                        byte[] diff = new byte[diffSize];
                        Array.Copy(newBuffer, diffStart, diff, 0, diffSize);

                        // Export the change data
                        MetaChange change = new MetaChange((uint)(address + i), diff);
                        output.MetaChanges.Add(change);

                        diffSize = 0;
                    }
                }

                offset += BufferSize;
                address += BufferSize;
            }
        }
        public static void WritePatch(Patch patch, IWriter writer)
        {
            writer.WriteInt32(AssemblyPatchMagic);
            writer.WriteUInt32(0); // File size filled in later
            writer.WriteByte(0); // No compression

            WriteBlocks(patch, writer);

            // Fill in the file size
            long fileSize = writer.Position;
            writer.SeekTo(4);
            writer.WriteUInt32((uint)fileSize - 8);
            writer.SeekTo(fileSize);
        }
        private static void ReadPatchInfo(IReader reader, Patch output)
        {
            byte version = reader.ReadByte();

            // Version 0 (all versions)
            output.MapID = reader.ReadInt32();
            output.MapInternalName = reader.ReadAscii();
            output.Name = reader.ReadUTF16();
            output.Description = reader.ReadUTF16();
            output.Author = reader.ReadUTF16();

            int screenshotLength = reader.ReadInt32();
            if (screenshotLength > 0)
                output.Screenshot = reader.ReadBlock(screenshotLength);
        }
Example #6
0
        /// <summary>
        /// Compares the locale data of two cache files and adds the results to a patch.
        /// </summary>
        /// <param name="originalFile">The unmodified cache file.</param>
        /// <param name="originalReader">A stream open on the unmodified cache file.</param>
        /// <param name="newFile">The modified cache file.</param>
        /// <param name="newReader">A stream open on the modified cache file.</param>
        /// <param name="output">The Patch to add results to.</param>
        public static void CompareLocales(ICacheFile originalFile, IReader originalReader, ICacheFile newFile, IReader newReader, Patch output)
        {
            if (originalFile.Languages.Count != newFile.Languages.Count)
                throw new InvalidOperationException("Cannot compare locales between cache files with different language counts.");

            // Compare each language
            for (int i = 0; i < originalFile.Languages.Count; i++)
            {
                // Compare the strings in the two language
                LanguageChange change = CompareLanguages((byte)i, originalFile.Languages[i], originalReader, newFile.Languages[i], newReader);

                // Only add the info if anything actually changed between the two languages
                if (change.LocaleChanges.Count > 0)
                    output.LanguageChanges.Add(change);
            }
        }
        private static void WriteMetaChanges(Patch patch, IWriter writer)
        {
            if (patch.MetaChanges.Count == 0)
                return;

            long startPos = writer.Position;
            writer.WriteInt32(AssemblyPatchBlockID.Meta);
            writer.WriteUInt32(0); // Size filled in later
            writer.WriteByte(0); // Version 0

            // Filter meta changes by size (as a file size optimization)
            List<MetaChange> fourByteChanges = new List<MetaChange>();
            List<MetaChange> otherChanges = new List<MetaChange>();
            foreach (MetaChange change in patch.MetaChanges)
            {
                if (change.Data.Length == 4)
                    fourByteChanges.Add(change);
                else
                    otherChanges.Add(change);
            }

            // Write 4-byte changes
            writer.WriteUInt32((uint)fourByteChanges.Count);
            foreach (MetaChange change in fourByteChanges)
            {
                writer.WriteUInt32(change.Address);
                writer.WriteBlock(change.Data);
            }

            // Write other changes
            writer.WriteUInt32((uint)otherChanges.Count);
            foreach (MetaChange change in otherChanges)
            {
                writer.WriteUInt32(change.Address);
                writer.WriteUInt32((uint)change.Data.Length);
                writer.WriteBlock(change.Data);
            }

            // Fill in the block size
            long endPos = writer.Position;
            writer.SeekTo(startPos + 4);
            writer.WriteUInt32((uint)(endPos - startPos));
            writer.SeekTo(endPos);
        }
        private static void ReadMetaChanges(IReader reader, Patch output)
        {
            byte version = reader.ReadByte();

            // Version 0 (all versions)
            uint num4ByteChanges = 0;
            for (uint i = 0; i < num4ByteChanges; i++)
            {
                uint address = reader.ReadUInt32();
                byte[] data = reader.ReadBlock(4);
                output.MetaChanges.Add(new MetaChange(address, data));
            }

            uint numChanges = 0;
            for (uint i = 0; i < numChanges; i++)
            {
                uint address = reader.ReadUInt32();
                uint dataSize = reader.ReadUInt32();
                byte[] data = reader.ReadBlock((int)dataSize);
                output.MetaChanges.Add(new MetaChange(address, data));
            }
        }
        private static Patch ReadBlocks(IReader reader, uint offset, uint endOffset)
        {
            Patch result = new Patch();
            while (offset < endOffset)
            {
                reader.SeekTo(offset);
                int blockId = reader.ReadInt32();
                uint size = reader.ReadUInt32();

                switch (blockId)
                {
                    case AssemblyPatchBlockID.Titl:
                        ReadPatchInfo(reader, result);
                        break;
                    case AssemblyPatchBlockID.Meta:
                        ReadMetaChanges(reader, result);
                        break;
                }

                // Skip to the next block
                offset += size;
            }
            return result;
        }
 private static void WriteBlocks(Patch patch, IWriter writer)
 {
     WritePatchInfo(patch, writer);
     WriteMetaChanges(patch, writer);
     WriteLocaleChanges(patch, writer);
 }
        private static void WritePatchInfo(Patch patch, IWriter writer)
        {
            long startPos = writer.Position;
            writer.WriteInt32(AssemblyPatchBlockID.Titl);
            writer.WriteUInt32(0); // Size filled in later
            writer.WriteByte(0); // Version 0

            writer.WriteInt32(patch.MapID);
            if (patch.MapInternalName != null)
                writer.WriteAscii(patch.MapInternalName);
            else
                writer.WriteByte(0);
            writer.WriteUTF16(patch.Name);
            writer.WriteUTF16(patch.Description);
            writer.WriteUTF16(patch.Author);
            if (patch.Screenshot != null)
            {
                writer.WriteInt32(patch.Screenshot.Length);
                writer.WriteBlock(patch.Screenshot);
            }
            else
            {
                writer.WriteInt32(0);
            }

            // Fill in the block size
            long endPos = writer.Position;
            writer.SeekTo(startPos + 4);
            writer.WriteUInt32((uint)(endPos - startPos));
            writer.SeekTo(endPos);
        }