diff --git a/pk3DS/ExeFS.cs b/pk3DS/ExeFS.cs index 63677e2..dcb7094 100644 --- a/pk3DS/ExeFS.cs +++ b/pk3DS/ExeFS.cs @@ -6,8 +6,31 @@ namespace pk3DS { - public class ExeFSTool + public class ExeFS //A lot of this is lifted directly from pk3DS. { + public byte[] Data; + public byte[] SuperBlockHash; + + // Return an object with data stored in a byte array + public ExeFS(string EXEFS_PATH) + { + var files = (new DirectoryInfo(EXEFS_PATH)).GetFiles().Select(f => f.FullName).ToArray(); + setData(files); + getSuperBlockHash(); + } + public ExeFS(string[] files) + { + getData(files); + getSuperBlockHash(); + } + + public void getSuperBlockHash() + { + SHA256Managed sha = new SHA256Managed(); + SuperBlockHash = sha.ComputeHash(Data, 0, 0x200); + } + + // Overall R/W files (wrapped) internal static bool get(string inFile, string outPath) { try @@ -64,9 +87,9 @@ internal static bool set(string[] files, string outFile) using (MemoryStream newFile = new MemoryStream()) { new MemoryStream(headerData).CopyTo(newFile); - foreach (string t in files) + foreach (string s in files) { - using (MemoryStream loadFile = new MemoryStream(File.ReadAllBytes(t))) + using (MemoryStream loadFile = new MemoryStream(File.ReadAllBytes(s))) loadFile.CopyTo(newFile); new MemoryStream(new byte[0x200 - newFile.Length % 0x200]).CopyTo(newFile); } @@ -77,5 +100,86 @@ internal static bool set(string[] files, string outFile) } catch { return false; } } + + public void setData(string[] files) + { + // Set up the Header + byte[] headerData = new byte[0x200]; + uint offset = 0; + SHA256 sha = SHA256.Create(); + + // Get the Header + for (int i = 0; i < files.Length; i++) + { + // Do the Top (File Info) + string fileName = Path.GetFileNameWithoutExtension(files[i]); + byte[] nameData = Encoding.ASCII.GetBytes(fileName); Array.Resize(ref nameData, 0x8); + Array.Copy(nameData, 0, headerData, i * 0x10, 0x8); + + FileInfo fi = new FileInfo(files[i]); + uint size = (uint)fi.Length; + Array.Copy(BitConverter.GetBytes(offset), 0, headerData, 0x8 + i * 0x10, 0x4); + Array.Copy(BitConverter.GetBytes(size), 0, headerData, 0xC + i * 0x10, 0x4); + offset += (0x200 - size % 0x200) + size; + + // Do the Bottom (Hashes) + byte[] hash = sha.ComputeHash(File.ReadAllBytes(files[i])); + Array.Copy(hash, 0, headerData, 0x200 - 0x20 * (i + 1), 0x20); + } + + // Set in the Data + using (MemoryStream newFile = new MemoryStream()) + { + new MemoryStream(headerData).CopyTo(newFile); + foreach (string s in files) + { + using (MemoryStream loadFile = new MemoryStream(File.ReadAllBytes(s))) + loadFile.CopyTo(newFile); + new MemoryStream(new byte[0x200 - newFile.Length % 0x200]).CopyTo(newFile); + } + + Data = newFile.ToArray(); + } + } + public void getData(string[] files) + { + // Set up the Header + byte[] headerData = new byte[0x200]; + uint offset = 0; + SHA256 sha = SHA256.Create(); + + // Get the Header + for (int i = 0; i < files.Length; i++) + { + // Do the Top (File Info) + string fileName = Path.GetFileNameWithoutExtension(files[i]); + byte[] nameData = Encoding.ASCII.GetBytes(fileName); Array.Resize(ref nameData, 0x8); + Array.Copy(nameData, 0, headerData, i * 0x10, 0x8); + + FileInfo fi = new FileInfo(files[i]); + uint size = (uint)fi.Length; + Array.Copy(BitConverter.GetBytes(offset), 0, headerData, 0x8 + i * 0x10, 0x4); + Array.Copy(BitConverter.GetBytes(size), 0, headerData, 0xC + i * 0x10, 0x4); + offset += (0x200 - size % 0x200) + size; + + // Do the Bottom (Hashes) + byte[] hash = sha.ComputeHash(File.ReadAllBytes(files[i])); + Array.Copy(hash, 0, headerData, 0x200 - 0x20 * (i + 1), 0x20); + } + + // Set in the Data + using (MemoryStream newFile = new MemoryStream()) + { + new MemoryStream(headerData).CopyTo(newFile); + foreach (string s in files) + { + using (MemoryStream loadFile = new MemoryStream(File.ReadAllBytes(s))) + loadFile.CopyTo(newFile); + new MemoryStream(new byte[0x200 - newFile.Length % 0x200]).CopyTo(newFile); + } + + Data = newFile.ToArray(); + } + } } } diff --git a/pk3DS/Main.cs b/pk3DS/Main.cs index d223fd9..f991d81 100644 --- a/pk3DS/Main.cs +++ b/pk3DS/Main.cs @@ -58,8 +58,8 @@ public Main() skipBoth = (filename.IndexOf("3DSkip", StringComparison.Ordinal) >= 0); } public static bool oras; - public static string RomFS; - public static string ExeFS; + public static string RomFSPath; + public static string ExeFSPath; public volatile int threads; private static string[] allGARCs = { "gametext", "storytext", "personal", "trpoke", "trdata", "evolution", "megaevo", "levelup", "eggmove", "item", "move", "maisonpkS", "maisontrS", "maisonpkN", "maisontrN" }; private bool skipBoth; @@ -67,7 +67,7 @@ public Main() // Main Form Methods private void L_About_Click(object sender, EventArgs e) { - if (ModifierKeys == Keys.Control && RomFS != null) + if (ModifierKeys == Keys.Control && RomFSPath != null) { string s = "Game Type: " + ((oras) ? "ORAS" : "XY") + Environment.NewLine; s = allGARCs.Aggregate(s, (current, t) => current + String.Format(Environment.NewLine + "{0} - {1}", t, getGARCFileName(t))); @@ -96,7 +96,7 @@ private void L_About_Click(object sender, EventArgs e) } private void L_Game_Click(object sender, EventArgs e) { - if (!GB_RomFS.Enabled || RomFS == null || ModifierKeys != Keys.Control) return; + if (!GB_RomFS.Enabled || RomFSPath == null || ModifierKeys != Keys.Control) return; if (DialogResult.Yes == Util.Prompt(MessageBoxButtons.YesNo, "Restore Original Files?")) restoreGARCs(oras, allGARCs); } @@ -116,11 +116,11 @@ private void changeLanguage(object sender, EventArgs e) while (threads > 0) Thread.Sleep(50); // Gather the Text Language Strings updateStatus(String.Format("GARC Get: {0} @ {1}... ", "gametext", getGARCFileName("gametext"))); - threadGet(RomFS + getGARCFileName("gametext"), "gametext", true, true); + threadGet(RomFSPath + getGARCFileName("gametext"), "gametext", true, true); while (threads > 0) Thread.Sleep(50); if (Directory.Exists("personal")) return; updateStatus(String.Format("GARC Get: {0} @ {1}... ", "personal", getGARCFileName("personal"))); - threadGet(RomFS + getGARCFileName("personal"), "personal", true, true); + threadGet(RomFSPath + getGARCFileName("personal"), "personal", true, true); }).Start(); } private void formClosing(object sender, FormClosingEventArgs e) @@ -135,13 +135,13 @@ private void formClosing(object sender, FormClosingEventArgs e) // Set the GameText back as other forms may have edited it. updateStatus(String.Format("GARC Get: {0} @ {1}... ", "gametext", getGARCFileName("gametext"))); - threadSet(RomFS + getGARCFileName("gametext"), "gametext", false); + threadSet(RomFSPath + getGARCFileName("gametext"), "gametext", false); while (threads > 0) Thread.Sleep(100); Thread.Sleep(200); // Small gap between beeps for faster computers. updateStatus(String.Format("GARC Get: {0} @ {1}... ", "personal", getGARCFileName("personal"))); - threadSet(RomFS + getGARCFileName("personal"), "personal", false); + threadSet(RomFSPath + getGARCFileName("personal"), "personal", false); while (threads > 0) Thread.Sleep(100); if (Directory.Exists("gametext")) Directory.Delete("gametext", true); @@ -165,7 +165,7 @@ private void openQuick(string path) else { // Check for ROMFS/EXEFS - RomFS = ExeFS = null; // Reset + RomFSPath = ExeFSPath = null; // Reset string[] folders = Directory.GetDirectories(path); int count = folders.Length; if (count != 2 && count != 1) return; // Only want exefs & romfs (can have exheader there too, it's not a folder) @@ -176,21 +176,21 @@ private void openQuick(string path) if (new FileInfo(folders[count - 1]).Name.ToLower().Contains("rom") && Directory.Exists(folders[count - 1])) checkIfRomFS(folders[count - 1]); - GB_RomFS.Enabled = (RomFS != null); - GB_ExeFS.Enabled = (RomFS != null && ExeFS != null); + GB_RomFS.Enabled = (RomFSPath != null); + GB_ExeFS.Enabled = (RomFSPath != null && ExeFSPath != null); B_MoveTutor.Enabled = oras; // Default false unless loaded - if (RomFS != null) + if (RomFSPath != null) { if (L_Game.Text == "Game Loaded: ORAS" || L_Game.Text == "Game Loaded: XY") { Directory.Delete("personal", true); } // Force reloading of personal data if the game is switched. L_Game.Text = (oras) ? "Game Loaded: ORAS" : "Game Loaded: XY"; TB_Path.Text = path; } - else if (ExeFS != null) + else if (ExeFSPath != null) { L_Game.Text = "ExeFS loaded - no RomFS"; TB_Path.Text = path; } else { L_Game.Text = "No Game Loaded"; TB_Path.Text = ""; } - if (RomFS != null) + if (RomFSPath != null) { // Trigger Data Loading if (RTB_Status.Text.Length > 0) RTB_Status.Clear(); @@ -222,13 +222,13 @@ private bool checkIfRomFS(string path) DialogResult dr = Util.Prompt(MessageBoxButtons.YesNoCancel, "Loading Override Options:", "Yes - OR/AS" + Environment.NewLine + "No - X/Y" + Environment.NewLine + "Cancel - Abort", "Path:" + Environment.NewLine + path); if (dr == DialogResult.Yes) { oras = true; } else if (dr == DialogResult.No) { oras = false; } - else { RomFS = null; oras = false; return false; } + else { RomFSPath = null; oras = false; return false; } } - RomFS = path; + RomFSPath = path; backupGARCs(false, allGARCs); return true; } - RomFS = null; + RomFSPath = null; oras = false; return false; } @@ -242,7 +242,7 @@ private bool checkIfExeFS(string path) if (fi.Length % 0x200 != 0 && (Util.Prompt(MessageBoxButtons.YesNo, "Detected Compressed code.bin.", "Decompress? File will be replaced.") == DialogResult.Yes)) new Thread(() => { threads++; new BLZCoder(new[] { "-d", files[0] }, pBar1); threads--; Util.Alert("Decompressed!"); }).Start(); - ExeFS = path; + ExeFSPath = path; return true; } private void tabMain_DragEnter(object sender, DragEventArgs e) @@ -260,7 +260,7 @@ private void tabMain_DragDrop(object sender, DragEventArgs e) private void rebuildRomFS(object sender, EventArgs e) { if (threads > 0) { Util.Alert("Please wait for all operations to finish first."); return; } - if (RomFS == null) return; + if (RomFSPath == null) return; if (Util.Prompt(MessageBoxButtons.YesNo, "Rebuild RomFS?") != DialogResult.Yes) return; SaveFileDialog sfd = new SaveFileDialog {FileName = "romfs.bin", Filter = "Binary File|*.*"}; @@ -271,7 +271,7 @@ private void rebuildRomFS(object sender, EventArgs e) updateStatus(Environment.NewLine + "Building RomFS binary. Please wait until the program finishes."); threads++; - RomFSTool.BuildRomFS(sfd.FileName, RomFS, RTB_Status, pBar1); + RomFSTool.BuildRomFS(sfd.FileName, RomFSPath, RTB_Status, pBar1); threads--; updateStatus("RomFS binary saved." + Environment.NewLine); @@ -457,7 +457,7 @@ private void fileGet(string[] files, bool skipDecompression = true, bool skipGet { string GARC = getGARCFileName(toEdit); updateStatus(String.Format("GARC Get: {0} @ {1}... ", toEdit, GARC)); - threadGet(RomFS + GARC, toEdit, true, skipDecompression); + threadGet(RomFSPath + GARC, toEdit, true, skipDecompression); while (threads > 0) Thread.Sleep(50); } } @@ -468,7 +468,7 @@ private void fileSet(IEnumerable files, bool keep = false) { string GARC = getGARCFileName(toEdit); updateStatus(String.Format("GARC Set: {0} @ {1}... ", toEdit, GARC)); - threadSet(RomFS + GARC, toEdit); + threadSet(RomFSPath + GARC, toEdit); while (threads > 0) Thread.Sleep(50); if (!keep && Directory.Exists(toEdit)) Directory.Delete(toEdit, true); } @@ -477,10 +477,10 @@ private void fileSet(IEnumerable files, bool keep = false) // ExeFS Subform Items private void rebuildExeFS(object sender, EventArgs e) { - if (ExeFS == null) return; + if (ExeFSPath == null) return; if (Util.Prompt(MessageBoxButtons.YesNo, "Rebuild ExeFS?") != DialogResult.Yes) return; - string[] files = Directory.GetFiles(ExeFS); + string[] files = Directory.GetFiles(ExeFSPath); int file = 0; if (files[1].Contains("code")) file = 1; SaveFileDialog sfd = new SaveFileDialog {FileName = "exefs.bin", Filter = "Binary File|*.*"}; if (sfd.ShowDialog() == DialogResult.OK) @@ -490,7 +490,7 @@ private void rebuildExeFS(object sender, EventArgs e) threads++; new BLZCoder(new[] { "-en", files[file] }, pBar1); Util.Alert("Compressed!"); - ExeFSTool.set(Directory.GetFiles(ExeFS), sfd.FileName); + ExeFS.set(Directory.GetFiles(ExeFSPath), sfd.FileName); threads--; }).Start(); } @@ -498,28 +498,28 @@ private void rebuildExeFS(object sender, EventArgs e) private void B_Pickup_Click(object sender, EventArgs e) { if (threads > 0) { Util.Alert("Please wait for all operations to finish first."); return; } - if (ExeFS != null) new Pickup().Show(); + if (ExeFSPath != null) new Pickup().Show(); } private void B_TMHM_Click(object sender, EventArgs e) { if (threads > 0) { Util.Alert("Please wait for all operations to finish first."); return; } - if (ExeFS != null) new TMHM().Show(); + if (ExeFSPath != null) new TMHM().Show(); } private void B_Mart_Click(object sender, EventArgs e) { if (threads > 0) { Util.Alert("Please wait for all operations to finish first."); return; } - if (ExeFS != null) new Mart().Show(); + if (ExeFSPath != null) new Mart().Show(); } private void B_MoveTutor_Click(object sender, EventArgs e) { if (threads > 0) { Util.Alert("Please wait for all operations to finish first."); return; } if (!oras) { Util.Alert("No Tutors for X/Y."); return; } // Already disabled button... - if (ExeFS != null) new Tutors().Show(); + if (ExeFSPath != null) new Tutors().Show(); } private void B_OPower_Click(object sender, EventArgs e) { if (threads > 0) { Util.Alert("Please wait for all operations to finish first."); return; } - if (ExeFS != null) new OPower().Show(); + if (ExeFSPath != null) new OPower().Show(); } // Extra Tools @@ -616,7 +616,7 @@ public void backupGARCs(bool overwrite, params string[] g) string GARC = getGARCFileName(s); string dest = "backup" + Path.DirectorySeparatorChar + s + String.Format(" ({0})", GARC.Replace(Path.DirectorySeparatorChar.ToString(), "")); if (overwrite || !File.Exists(dest)) - File.Copy(RomFS + GARC, dest); + File.Copy(RomFSPath + GARC, dest); } } public void restoreGARCs(bool oras_define, params string[] g) @@ -624,7 +624,7 @@ public void restoreGARCs(bool oras_define, params string[] g) oras = oras_define; foreach (string s in g) { - string dest = RomFS + getGARCFileName(s); + string dest = RomFSPath + getGARCFileName(s); string src = "backup" + Path.DirectorySeparatorChar + s + String.Format(" ({0})", getGARCFileName(s).Replace(Path.DirectorySeparatorChar.ToString(), "")); File.Copy(src, dest, true); if (s == "personal" || s == "gametext") diff --git a/pk3DS/Subforms/EggMove.cs b/pk3DS/Subforms/EggMove.cs index e0d3d25..e065144 100644 --- a/pk3DS/Subforms/EggMove.cs +++ b/pk3DS/Subforms/EggMove.cs @@ -108,7 +108,7 @@ private void B_RandAll_Click(object sender, EventArgs e) ushort[] HMs = { 15, 19, 57, 70, 127, 249, 291 }; ushort[] TMs = { }; - if (CHK_HMs.Checked && Main.ExeFS != null) + if (CHK_HMs.Checked && Main.ExeFSPath != null) TMHM.getTMHMList(Main.oras, ref TMs, ref HMs); int[] banned = new int[HMs.Length]; diff --git a/pk3DS/Subforms/LevelUp.cs b/pk3DS/Subforms/LevelUp.cs index a4eac9a..ef9f5bd 100644 --- a/pk3DS/Subforms/LevelUp.cs +++ b/pk3DS/Subforms/LevelUp.cs @@ -150,7 +150,7 @@ private void B_RandAll_Click(object sender, EventArgs e) ushort[] HMs = { 15, 19, 57, 70, 127, 249, 291 }; ushort[] TMs = {}; - if (CHK_HMs.Checked && Main.ExeFS != null) + if (CHK_HMs.Checked && Main.ExeFSPath != null) TMHM.getTMHMList(Main.oras, ref TMs, ref HMs); int[] banned = new int[HMs.Length]; diff --git a/pk3DS/Subforms/Mart.cs b/pk3DS/Subforms/Mart.cs index 9cd4e4f..8b52d1c 100644 --- a/pk3DS/Subforms/Mart.cs +++ b/pk3DS/Subforms/Mart.cs @@ -9,8 +9,8 @@ public partial class Mart : Form public Mart() { InitializeComponent(); - if (Main.ExeFS == null) { Util.Alert("No exeFS code to load."); Close(); } - string[] files = Directory.GetFiles(Main.ExeFS); + if (Main.ExeFSPath == null) { Util.Alert("No exeFS code to load."); Close(); } + string[] files = Directory.GetFiles(Main.ExeFSPath); if (!File.Exists(files[0]) || !Path.GetFileNameWithoutExtension(files[0]).Contains("code")) { Util.Alert("No .code.bin detected."); Close(); } data = File.ReadAllBytes(files[0]); if (data.Length % 0x200 != 0) { Util.Alert(".code.bin not decompressed. Aborting."); Close(); } diff --git a/pk3DS/Subforms/OPower.cs b/pk3DS/Subforms/OPower.cs index 5988168..c7c92a6 100644 --- a/pk3DS/Subforms/OPower.cs +++ b/pk3DS/Subforms/OPower.cs @@ -10,8 +10,8 @@ public partial class OPower : Form public OPower() { InitializeComponent(); - if (Main.ExeFS == null) { Util.Alert("No exeFS code to load."); Close(); } - string[] files = Directory.GetFiles(Main.ExeFS); + if (Main.ExeFSPath == null) { Util.Alert("No exeFS code to load."); Close(); } + string[] files = Directory.GetFiles(Main.ExeFSPath); if (!File.Exists(files[0]) || !Path.GetFileNameWithoutExtension(files[0]).Contains("code")) { Util.Alert("No .code.bin detected."); Close(); } codebin = files[0]; exefsData = File.ReadAllBytes(codebin); diff --git a/pk3DS/Subforms/Pickup.cs b/pk3DS/Subforms/Pickup.cs index de22c7c..09d2399 100644 --- a/pk3DS/Subforms/Pickup.cs +++ b/pk3DS/Subforms/Pickup.cs @@ -10,8 +10,8 @@ public partial class Pickup : Form public Pickup() { InitializeComponent(); - if (Main.ExeFS == null) { Util.Alert("No exeFS code to load."); Close(); } - string[] files = Directory.GetFiles(Main.ExeFS); + if (Main.ExeFSPath == null) { Util.Alert("No exeFS code to load."); Close(); } + string[] files = Directory.GetFiles(Main.ExeFSPath); if (!File.Exists(files[0]) || !Path.GetFileNameWithoutExtension(files[0]).Contains("code")) { Util.Alert("No .code.bin detected."); Close(); } data = File.ReadAllBytes(files[0]); if (data.Length % 0x200 != 0) { Util.Alert(".code.bin not decompressed. Aborting."); Close(); } diff --git a/pk3DS/Subforms/TMHM.cs b/pk3DS/Subforms/TMHM.cs index 5cf83bc..6cdaba7 100644 --- a/pk3DS/Subforms/TMHM.cs +++ b/pk3DS/Subforms/TMHM.cs @@ -11,8 +11,8 @@ public partial class TMHM : Form public TMHM() { InitializeComponent(); - if (Main.ExeFS == null) { Util.Alert("No exeFS code to load."); Close(); } - string[] files = Directory.GetFiles(Main.ExeFS); + if (Main.ExeFSPath == null) { Util.Alert("No exeFS code to load."); Close(); } + string[] files = Directory.GetFiles(Main.ExeFSPath); if (!File.Exists(files[0]) || !Path.GetFileNameWithoutExtension(files[0]).Contains("code")) { Util.Alert("No .code.bin detected."); Close(); } data = File.ReadAllBytes(files[0]); if (data.Length % 0x200 != 0) { Util.Alert(".code.bin not decompressed. Aborting."); Close(); } @@ -172,8 +172,8 @@ private void B_RandomTM_Click(object sender, EventArgs e) internal static void getTMHMList(bool oras, ref ushort[] TMs, ref ushort[] HMs) { - if (Main.ExeFS == null) return; - string[] files = Directory.GetFiles(Main.ExeFS); + if (Main.ExeFSPath == null) return; + string[] files = Directory.GetFiles(Main.ExeFSPath); if (!File.Exists(files[0]) || !Path.GetFileNameWithoutExtension(files[0]).Contains("code")) return; byte[] data = File.ReadAllBytes(files[0]); int dataoffset = Util.IndexOfBytes(data, new byte[] { 0xD4, 0x00, 0xAE, 0x02, 0xAF, 0x02, 0xB0, 0x02 }, 0x400000, 0) + 8; diff --git a/pk3DS/Subforms/Tutors.cs b/pk3DS/Subforms/Tutors.cs index f4bca7d..e2072d8 100644 --- a/pk3DS/Subforms/Tutors.cs +++ b/pk3DS/Subforms/Tutors.cs @@ -9,8 +9,8 @@ public partial class Tutors : Form public Tutors() { InitializeComponent(); - if (Main.ExeFS == null) { Util.Alert("No exeFS code to load."); Close(); } - string[] files = Directory.GetFiles(Main.ExeFS); + if (Main.ExeFSPath == null) { Util.Alert("No exeFS code to load."); Close(); } + string[] files = Directory.GetFiles(Main.ExeFSPath); if (!File.Exists(files[0]) || !Path.GetFileNameWithoutExtension(files[0]).Contains("code")) { Util.Alert("No .code.bin detected."); Close(); } data = File.ReadAllBytes(files[0]); if (data.Length % 0x200 != 0) { Util.Alert(".code.bin not decompressed. Aborting."); Close(); }