diff --git a/.vs/Toolbox/v15/.suo b/.vs/Toolbox/v15/.suo index c296d895..63a3cb2d 100644 Binary files a/.vs/Toolbox/v15/.suo and b/.vs/Toolbox/v15/.suo differ diff --git a/File_Format_Library/FileFormats/Archives/LM2/LM2_DICT.cs b/File_Format_Library/FileFormats/Archives/LM2/LM2_DICT.cs index 65ba6510..9dddf552 100644 --- a/File_Format_Library/FileFormats/Archives/LM2/LM2_DICT.cs +++ b/File_Format_Library/FileFormats/Archives/LM2/LM2_DICT.cs @@ -82,14 +82,9 @@ namespace FirstPlugin List Textures = new List(); TreeNode textureFolder = new TreeNode("Textures"); - Nodes.Add(textureFolder); for (int i = 0; i < files.Count; i++) { - Nodes.Add(files[i]); - - continue; - if (files[i].FileType == FileEntry.FileDataType.Texture) { if (files[i].Unknown3 == 1) //Info @@ -100,6 +95,8 @@ namespace FirstPlugin while (textureReader.ReadUInt32() == TexturePOWE.Identifier) { var texture = new TexturePOWE(); + texture.ImageKey = "texture"; + texture.SelectedImageKey = texture.ImageKey; texture.Index = ImageIndex; texture.Read(textureReader); texture.Text = $"Texture {ImageIndex}"; @@ -110,10 +107,15 @@ namespace FirstPlugin } else //Block { + uint Offset = 0; foreach (var tex in Textures) { if (tex.Index == ImageIndex) - tex.ImageData = files[i].FileData; + { + tex.ImageData = Utils.SubArray(files[i].FileData, Offset, tex.ImageSize); + } + + Offset += tex.ImageSize; } ImageIndex++; } @@ -121,6 +123,9 @@ namespace FirstPlugin else Nodes.Add(files[i]); } + + if (textureFolder.Nodes.Count > 0) + Nodes.Add(textureFolder); } } diff --git a/File_Format_Library/FileFormats/Archives/Sonic Racing/GameDataToc.cs b/File_Format_Library/FileFormats/Archives/Sonic Racing/GameDataToc.cs new file mode 100644 index 00000000..560135df --- /dev/null +++ b/File_Format_Library/FileFormats/Archives/Sonic Racing/GameDataToc.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox; +using System.Windows.Forms; +using Toolbox.Library; +using Toolbox.Library.IO; +using Toolbox.Library.Forms; + +namespace FirstPlugin +{ + public class GameDataToc : TreeNodeFile, IFileFormat + { + public FileType FileType { get; set; } = FileType.Archive; + + public bool CanSave { get; set; } + public string[] Description { get; set; } = new string[] { "GameDataToc" }; + public string[] Extension { get; set; } = new string[] { "*.toc" }; + public string FileName { get; set; } + public string FilePath { get; set; } + public IFileInfo IFileInfo { get; set; } + + public bool Identify(System.IO.Stream stream) + { + using (var reader = new Toolbox.Library.IO.FileReader(stream, true)) + { + return FileName == "GameData.toc"; + } + } + + public Type[] Types + { + get + { + List types = new List(); + return types.ToArray(); + } + } + + public string EncryptionKey = "b0110b704a259cd8f0da9e4480bd0b9c8c7c94c609f322288273cf85930dd64f7baf13255b075df912e81c2d8aae98fe034dee5f61c232c4b39280fe4c68c46151be7f49b7cbd4ee0922acb02aaa76bc9585dfb89c5fb90da7094289ea18c81312839b06fd267273c81babea38405276a1d35835916e7cec88f26473abb79578762e3abe0ce719309114aa40dcf8d7466e4edc1b8a887d1ed7fad0c7d418fe81660ea5b9445d2db47174cc1bfaa2c96eb84cca8e447c95ef12a76e745c7d19497d4729beaba244eb992f2e46934920caa5ad09d6950e0f9fefdac6104b5609379eff0ad4de56a941e63baf25924dcdcb5632d27b58108d5af19ea2b3946986514940bd4953396391450286ac8f47e07b95a8ab59a770ac71acbf51ba9c8f4c18fb88865f1d49577fd14da819223d4c78a49f888d78141bfa140669eda3d890e05f6d85b8058042b127e50feb1a6fdf28a309309646ff3081933d93293239de9c74c55f0589b3658bb2764833a1001ec8c6dcba7c610d15df27fd7938da58ea7c877c0fd38c267ca295b50e37560c702b1a8f0fa9227eccbbc2b0d6e704b8a1bd65a3fb42250557c8675b1f9ebd6ce056fbf0098ee03e3ba75fc29dbc9217de62b67a04f82abb8b8b2eca5ee0ee89219805281b56c0beb6db5269c45cf330cbd7e1a7579456e380e7027ef77b4fb6fd2d9df00248357e72b206ed8d6db3577a7cf81c04dbf054ffbe69b2cede6ca266172a138754b588b48ff686c728838c4c9c4342045fd74e68f28b7d0f86a5bfbee86d5122b838aeab59cddf8acc7d71416f2239d2a22db3ee83cd0396089dbae3bf9f7bf7081ec8591c159507d0a1d2b8d34f477c45dfa2341716be64ab445bef8494fb8f2aa9b5dd60d1e61a22e5b44f73dfcabf407ba0e35f1a95d69cd73e42a3e9d966bf439c3b69fb82df4929a8d65fa734dcf39c738053bb17f3296b270b3a859970083b9eb0b9732f87f96502c443327902b14827056b3711c5518d8b2ef250f4a958d61fa89ade5c2af1759a57a2403dad07c1611bfd99736ac5c86b9079b676401ea10e6dd5fbf3078e1ae6723b63f4d3908c0b9b7f679b3b25ae7e7b98ba9c127936ba9a0e86466edb580681e4f92f1b8b0c91d2ca57a65c98f03f69c8946fd93c5051cf5210aa5e7d9a13e58c464170cc6d770e3078dfde6602c7c6526f216cbb6b28db3c8a442546092342531b875c887d66f57722e7b850161483c18ac2ab6cea7fb67f05f5636a2776c0dee80913a8cec042f9d48e4db79365cf0c36f6c6446328311134b1677218549f65bcd2e7ace3a303250a66cb942dfd4d234d20ef14315ad5c460a460fa26f56efe98448b72ab374e7fc6de475b801fa3ba1f0562370894e0815f545a6c671a5b0d89fc9ec983e26aea00e1b1407e4d278de74b31d5aaae78a5edbc439011ceb2db"; + + public byte[] DecryptedTable { get; set; } + + public static byte[] EncryptOrDecryptXor(byte[] text, byte[] key) + { + byte[] xor = new byte[text.Length]; + for (int i = 0; i < text.Length; i++) + { + xor[i] = (byte)(text[i] ^ key[i % key.Length]); + } + return xor; + } + + private byte[] FromHex(string hex) + { + byte[] raw = new byte[hex.Length / 2]; + for (int i = 0; i < raw.Length; i++) + { + raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); + } + return raw; + } + + //Decryption process from https://github.com/TheFearsomeDzeraora/BFTTFutil/blob/master/Program.cs + public void Load(System.IO.Stream stream) + { + Text = FileName; + + using (var reader = new FileReader(stream)) + { + byte[] table = reader.ReadBytes((int)reader.BaseStream.Length); + DecryptedTable = FromHex(EncryptionKey); + } + } + + public static byte[] StringToByteArray(string hex) + { + + + return Enumerable.Range(0, hex.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) + .ToArray(); + } + + public override void OnClick(TreeView treeview) + { + HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor)); + if (editor == null) + { + editor = new HexEditor(); + LibraryGUI.LoadEditor(editor); + } + editor.Text = Text; + editor.Dock = DockStyle.Fill; + editor.LoadData(DecryptedTable); + } + + public void Unload() + { + + } + public byte[] Save() + { + return null; + } + } +} diff --git a/File_Format_Library/FileFormats/Archives/SP2.cs b/File_Format_Library/FileFormats/Archives/Sonic Racing/SP2.cs similarity index 100% rename from File_Format_Library/FileFormats/Archives/SP2.cs rename to File_Format_Library/FileFormats/Archives/Sonic Racing/SP2.cs diff --git a/File_Format_Library/FileFormats/Archives/SPC.cs b/File_Format_Library/FileFormats/Archives/Sonic Racing/SPC.cs similarity index 100% rename from File_Format_Library/FileFormats/Archives/SPC.cs rename to File_Format_Library/FileFormats/Archives/Sonic Racing/SPC.cs diff --git a/File_Format_Library/FileFormats/Archives/SWU.cs b/File_Format_Library/FileFormats/Archives/Sonic Racing/SWU.cs similarity index 86% rename from File_Format_Library/FileFormats/Archives/SWU.cs rename to File_Format_Library/FileFormats/Archives/Sonic Racing/SWU.cs index 7fec6f2e..becabbdb 100644 --- a/File_Format_Library/FileFormats/Archives/SWU.cs +++ b/File_Format_Library/FileFormats/Archives/Sonic Racing/SWU.cs @@ -105,11 +105,11 @@ namespace FirstPlugin case ChunkAnimInfo: if (chunk.ChunkSize > 0xB0) { - // reader.Seek(chunk.Position + 0xB0, System.IO.SeekOrigin.Begin); - // chunk.FileName = reader.ReadString(Syroot.BinaryData.BinaryStringFormat.ZeroTerminated); + reader.Seek(chunk.Position + 0xB0, System.IO.SeekOrigin.Begin); + chunk.FileName = reader.ReadString(Syroot.BinaryData.BinaryStringFormat.ZeroTerminated); } break; - /* case ChunkAnimData: + case ChunkAnimData: AnimationFile animFile = new AnimationFile(); animFile.Read(reader); chunk.ChunkData = animFile; @@ -128,7 +128,7 @@ namespace FirstPlugin MaterialFile matFile = new MaterialFile(); matFile.Read(reader); chunk.ChunkData = matFile; - break;*/ + break; } reader.Seek(chunk.Position + chunk.ChunkSize, System.IO.SeekOrigin.Begin); @@ -182,47 +182,47 @@ namespace FirstPlugin public void ReadChunk(FileReader reader) { - reader.SetByteOrder(true); + reader.SetByteOrder(true); - Console.WriteLine("TEX pos " + reader.Position); - GX2Surface = new GX2.GX2Surface(); - GX2Surface.dim = reader.ReadUInt32(); - GX2Surface.width = reader.ReadUInt32(); - GX2Surface.height = reader.ReadUInt32(); - GX2Surface.depth = reader.ReadUInt32(); - GX2Surface.numMips = reader.ReadUInt32(); - GX2Surface.format = reader.ReadUInt32(); - GX2Surface.aa = reader.ReadUInt32(); - GX2Surface.use = reader.ReadUInt32(); - GX2Surface.imageSize = reader.ReadUInt32(); - GX2Surface.imagePtr = reader.ReadUInt32(); - GX2Surface.mipSize = reader.ReadUInt32(); - GX2Surface.mipPtr = reader.ReadUInt32(); - GX2Surface.tileMode = reader.ReadUInt32(); - GX2Surface.swizzle = reader.ReadUInt32(); - GX2Surface.alignment = reader.ReadUInt32(); - GX2Surface.pitch = reader.ReadUInt32(); - GX2Surface.mipOffset = reader.ReadUInt32s(13); - GX2Surface.firstMip = reader.ReadUInt32(); - GX2Surface.imageCount = reader.ReadUInt32(); - GX2Surface.firstSlice = reader.ReadUInt32(); - GX2Surface.numSlices = reader.ReadUInt32(); - GX2Surface.compSel = reader.ReadBytes(4); - GX2Surface.texRegs = reader.ReadUInt32s(4); + Console.WriteLine("TEX pos " + reader.Position); + GX2Surface = new GX2.GX2Surface(); + GX2Surface.dim = reader.ReadUInt32(); + GX2Surface.width = reader.ReadUInt32(); + GX2Surface.height = reader.ReadUInt32(); + GX2Surface.depth = reader.ReadUInt32(); + GX2Surface.numMips = reader.ReadUInt32(); + GX2Surface.format = reader.ReadUInt32(); + GX2Surface.aa = reader.ReadUInt32(); + GX2Surface.use = reader.ReadUInt32(); + GX2Surface.imageSize = reader.ReadUInt32(); + GX2Surface.imagePtr = reader.ReadUInt32(); + GX2Surface.mipSize = reader.ReadUInt32(); + GX2Surface.mipPtr = reader.ReadUInt32(); + GX2Surface.tileMode = reader.ReadUInt32(); + GX2Surface.swizzle = reader.ReadUInt32(); + GX2Surface.alignment = reader.ReadUInt32(); + GX2Surface.pitch = reader.ReadUInt32(); + GX2Surface.mipOffset = reader.ReadUInt32s(13); + GX2Surface.firstMip = reader.ReadUInt32(); + GX2Surface.imageCount = reader.ReadUInt32(); + GX2Surface.firstSlice = reader.ReadUInt32(); + GX2Surface.numSlices = reader.ReadUInt32(); + GX2Surface.compSel = reader.ReadBytes(4); + GX2Surface.texRegs = reader.ReadUInt32s(4); - RedChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[0]); - GreenChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[1]); - BlueChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[2]); - AlphaChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[3]); + RedChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[0]); + GreenChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[1]); + BlueChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[2]); + AlphaChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[3]); - if (GX2Surface.numMips > 13) - return; + if (GX2Surface.numMips > 13) + return; - Width = GX2Surface.width; - Height = GX2Surface.height; - MipCount = GX2Surface.numMips; - ArrayCount = GX2Surface.numArray; - Format = Bfres.Structs.FTEX.ConvertFromGx2Format((Syroot.NintenTools.Bfres.GX2.GX2SurfaceFormat)GX2Surface.format); + Width = GX2Surface.width; + Height = GX2Surface.height; + MipCount = GX2Surface.numMips; + ArrayCount = GX2Surface.numArray; + Format = Bfres.Structs.FTEX.ConvertFromGx2Format((Syroot.NintenTools.Bfres.GX2.GX2SurfaceFormat)GX2Surface.format); } private STChannelType GX2ChanneToGeneric(Syroot.NintenTools.Bfres.GX2.GX2CompSel comp) diff --git a/File_Format_Library/File_Format_Library.csproj b/File_Format_Library/File_Format_Library.csproj index edcc81e4..e5368f88 100644 --- a/File_Format_Library/File_Format_Library.csproj +++ b/File_Format_Library/File_Format_Library.csproj @@ -211,9 +211,10 @@ - - - + + + + diff --git a/File_Format_Library/Main.cs b/File_Format_Library/Main.cs index 86bad240..33f066a5 100644 --- a/File_Format_Library/Main.cs +++ b/File_Format_Library/Main.cs @@ -332,6 +332,7 @@ namespace FirstPlugin Formats.Add(typeof(SP2)); Formats.Add(typeof(SWU)); Formats.Add(typeof(SPC)); + Formats.Add(typeof(GameDataToc)); Formats.Add(typeof(NUSHDB)); Formats.Add(typeof(MKGPDX_PAC)); Formats.Add(typeof(LZARC)); diff --git a/Switch_Toolbox_Library/Interfaces/IArchiveFile.cs b/Switch_Toolbox_Library/Interfaces/IArchiveFile.cs index 3eb621b0..3ea48dd7 100644 --- a/Switch_Toolbox_Library/Interfaces/IArchiveFile.cs +++ b/Switch_Toolbox_Library/Interfaces/IArchiveFile.cs @@ -35,6 +35,9 @@ namespace Toolbox.Library } public class ArchiveFileInfo : INode { + [Browsable(false)] + public string SourceFile { get; internal set; } + [Browsable(false)] public string ImageKey { get; set; } @@ -433,6 +436,9 @@ namespace Toolbox.Library if (!node.CanLoadFile) continue; + if (!((IFileFormat)archiveFile).IFileInfo.InArchive && File.Exists(((IFileFormat)archiveFile).FilePath)) + node.SourceFile = ((IFileFormat)archiveFile).FilePath; + string nodeString = node.FileName; var roots = nodeString.Split(new char[] { '/' },