private void romTree_AfterSelect(object sender, TreeViewEventArgs e) { if (e.Node.Tag is NDSFile) { if (e.Node.Tag is NDSBinary) { DataGridView grid = propertyView; NDSBinary file = e.Node.Tag as NDSBinary; grid.Rows.Clear(); string[] row = new string[] { "Name:", file.Name + file.Extension }; grid.Rows.Add(row); row = new string[] { "Path:", "Root" }; grid.Rows.Add(row); if (file.Name.Contains("9")) { if (!file.Name.Contains("i")) { row = new string[] { "File Type:", "ARM9i Binary", "ARMv5TE Compiled Binary, DSi Extended" }; } else { row = new string[] { "File Type:", "ARM7i Binary", "ARMv5TE Compiled Binary." }; } } else if (file.Name.Contains("7")) { if (!file.Name.Contains("i")) { row = new string[] { "File Type:", "ARM9 Binary", "ARMv4T Compiled Binary, DSi Extended" }; } else { row = new string[] { "File Type:", "ARM7 Binary", "ARMv4T Compiled Binary." }; } } else { row = new string[] { "File Type:", "ARM Binary", "ARM Compiled Binary" }; } grid.Rows.Add(row); row = new string[] { "Address:", file.Offset.ToString(), "Offset from beginning of ROM to start of the binary." }; grid.Rows.Add(row); row = new string[] { "Length:", file.Length.ToString(), "The length of the binary." }; grid.Rows.Add(row); row = new string[] { "RAM Address:", file.Load.ToString(), "The RAM address this binary is loaded to." }; if (!file.Name.Contains("i")) { grid.Rows.Add(row); row = new string[] { "Hook Address:", file.AutoLoad.ToString(), "The RAM auto-load hook address." }; grid.Rows.Add(row); row = new string[] { "Parameters:", file.AutoParams.ToString(), "Offset to auto-load parameter table." }; } grid.Rows.Add(row); grid.Refresh(); } else if (e.Node.Tag is NDSOverlay) { DataGridView grid = propertyView; NDSOverlay file = e.Node.Tag as NDSOverlay; grid.Rows.Clear(); string[] row = new string[] { "Name:", file.Name + file.Extension }; grid.Rows.Add(row); row = new string[] { "Path:", file.Path }; grid.Rows.Add(row); if (file.Path.Contains("9")) { row = new string[] { "File Type:", "ARM9 Binary Overlay", "ARMv5TE Compiled Binary Overlay" }; } else if (file.Path.Contains("7")) { row = new string[] { "File Type:", "ARM7 Binary Overlay", "ARMv4T Compiled Binary Overlay" }; } else { row = new string[] { "File Type:", "ARM Binary Overlay", "ARM Compiled Binary Overlay" }; } grid.Rows.Add(row); row = new string[] { "File ID:", file.ID.ToString(), "The ID of the overlay in the file allocation table." }; grid.Rows.Add(row); row = new string[] { "Overlay ID:", file.OverlayID.ToString(), "The ID of the overlay in the overlay table." }; grid.Rows.Add(row); row = new string[] { "Offset:", "0x" + file.Offset.ToString("X"), "Offset from beginning of ROM to start of the overlay." }; grid.Rows.Add(row); row = new string[] { "Size:", file.Length.ToString("N0") + " bytes", "The length of the overlay." }; grid.Rows.Add(row); row = new string[] { "RAM Size:", file.SizeRAM.ToString("N0") + " bytes", "The size of the RAM section of the overlay." }; grid.Rows.Add(row); row = new string[] { "BSS Size:", file.SizeBSS.ToString("N0") + " bytes", "The size of the BSS section of the overlay." }; grid.Rows.Add(row); row = new string[] { "Compressed:", file.Compressed.ToString(), "Flag that indicates a compressed overlay." }; grid.Rows.Add(row); if (file.Compressed) { row = new string[] { "Compressed Size:", file.CompressedSize.ToString("N0") + " bytes", "The compressed size of the overlay." }; grid.Rows.Add(row); row = new string[] { "Total Size:", (file.SizeRAM + file.SizeBSS).ToString("N0") + " bytes", "The total size of the uncompressed overlay." }; grid.Rows.Add(row); } row = new string[] { "RAM Address:", "0x" + file.AddressRAM.ToString("X"), "The overlay transfer desitation address in RAM." }; grid.Rows.Add(row); row = new string[] { "Start Address:", "0x" + file.StaticStartAddress.ToString("X"), "The static initializer start address of the overlay." }; grid.Rows.Add(row); row = new string[] { "End Address:", "0x" + file.StaticEndAddress.ToString("X"), "The static initializer end address of the overlay." }; grid.Rows.Add(row); grid.Refresh(); } else if (e.Node.Tag is NDSBanner) { DataGridView grid = propertyView; NDSBanner banner = e.Node.Tag as NDSBanner; grid.Rows.Clear(); string[] row = new string[] { }; grid.Rows.Add(row); } else { DataGridView grid = propertyView; NDSFile file = e.Node.Tag as NDSFile; grid.Rows.Clear(); string[] row = new string[] { "Name:", file.Name + file.Extension }; grid.Rows.Add(row); row = new string[] { "Path:", file.Path }; grid.Rows.Add(row); row = new string[] { "File Type:", file.Type, file.About }; grid.Rows.Add(row); row = new string[] { "Offset:", file.Offset.ToString(), "The length of the file." }; grid.Rows.Add(row); row = new string[] { "Size:", file.Length.ToString(), "Offset from beginning of ROM to start of the overlay." }; grid.Rows.Add(row); grid.Refresh(); } } }
/// <summary> /// Reads and breaks down the file tables from the specified stream.<para /> /// Currently Supports: File Name Table (FNT); File Allocation Table (FAT); Overlay Tables (OVT); NARC. /// </summary> /// <param name="stream">ROM file to read tables from.</param> /// public void ReadFileTables(Stream stream) { if (FATOffset == 0 || FATLength == 0 || FNTOffset == 0 || FNTLength == 0 || ARM9OverlayOffset == 0 || ARM9OverlayLength == 0) { return; } // We initiate a BinaryReader with using() and set it to leave the stream open after disposal. using (BinaryReader reader = new BinaryReader(stream, new UTF8Encoding(), true)) { // The File Allocation Table contain eight bytes per file entry; // a four byte file offset followed by a four byte file length. // We start by determining the file count and then dividing the // offsets and lenghts into separate indexed arrays. int file_count = Convert.ToInt32(FATLength) / 8; FileTable = new NDSFile[file_count]; reader.BaseStream.Position = FATOffset; for (int i = 0; i < file_count; i++) { FileTable[i] = new NDSFile(); FileTable[i].ID = i; FileTable[i].Offset = reader.ReadUInt32(); FileTable[i].Length = reader.ReadUInt32() - FileTable[i].Offset; } // The File Name Table contains two sections; the first is the // main directory table. It's length is eight bytes per entry. // The first four bytes represent an offset to the entry in the // second section; the sub-directory table. This is followed by // two byte index corresponding to the first file entry in the // directory. Finally we have a two byte index corresponding to // the parent directory. // The first entry in the table is slightly different though. // The last two bytes in the first entry actually denote the // number of directories in the first section. Let's read that, // then use it to iterate through the main directory table and // split the table into three seperate indexed arrays. reader.BaseStream.Position = FNTOffset + 6; int directory_count = reader.ReadUInt16(); DirectoryTable = new NDSDirectory[directory_count]; int[] entry_offset = new int[directory_count]; int[] first_file = new int[directory_count]; int[] parent_index = new int[directory_count]; reader.BaseStream.Position = FNTOffset; for (int i = 0; i < directory_count; i++) { entry_offset[i] = Convert.ToInt32(reader.ReadUInt32() + FNTOffset); first_file[i] = reader.ReadUInt16(); parent_index[i] = reader.ReadUInt16() - 61440; } // Setting up the root directory. DirectoryTable[0] = new NDSDirectory(); DirectoryTable[0].Name = "File Table"; DirectoryTable[0].Path = "File Table"; // The second section is the sub-directory table. This table is // a bit more complex. We start by iterating through the main // directory table and using the entry offset to locate its // position in the sub-directory table. int file_index = first_file[0]; for (int i = 0; i < directory_count; i++) { // Initialize the directory arrays. reader.BaseStream.Position = entry_offset[i]; NDSDirectory parent_directory = DirectoryTable[i]; parent_directory.Children = new List <NDSDirectory>(); parent_directory.Contents = new List <NDSFile>(); while (true) { // A small sanity check to make sure we havent overrun the table. if (reader.BaseStream.Position > FNTOffset + FNTLength) { break; } // The first byte in the sub-directory entry indicates how to continue. byte entry_byte = reader.ReadByte(); // 0 indicates the end of a directory. if (entry_byte == 0) { break; } // 128 is actually invalid, and shouldn't be encountered. It would // indicate a directory with no name, which isn't actually valid. else if (entry_byte == 128) { continue; } // The first bit indicates a directory entry, so anything over 128 // is a sub-directory. The other seven bits indicate the length of // the sub-directory name. We simply need to subtract 128, and the // next so many bytes are the sub-directory name. The following // two bytes are the sub-directory's ID in the main directory table. else if (entry_byte > 128) { string name = System.Text.Encoding.UTF8.GetString(reader.ReadBytes(entry_byte - 128)); NDSDirectory child_directory = new NDSDirectory(); child_directory.Name = name; child_directory.Parent = parent_directory; child_directory.Path = parent_directory.Path + "\\" + child_directory.Name; child_directory.ID = reader.ReadUInt16() - 61440; DirectoryTable[child_directory.ID] = child_directory; parent_directory.Children.Add(child_directory); } // Anything under 128 indicates a file. Same as the previous, the // other seven bits indicate the length of the file name. Unlike // sub-directories, there is no index proceeding the file name. else { string name = System.Text.Encoding.UTF8.GetString(reader.ReadBytes(entry_byte)); NDSFile file = FileTable[file_index++]; file.Name = name; file.Parent = parent_directory; file.Path = parent_directory.Path + "\\" + file.Name; parent_directory.Contents.Add(file); } } } // We run this now so that we don't mess up the memory stream. foreach (NDSFile file in FileTable) { file.GetExtension(stream); if (file.Extension == ".narc") { file.NARCTables = FileHandler.NARC(stream, file, true); } else if (file.Extension == ".arc") { file.NARCTables = FileHandler.NARC(stream, file, false); } } // Header Represented As A File Header = new NDSFile(); Header.Name = "Header"; Header.Offset = 0; Header.Length = 16384; // Header Represented As A File Banner = new NDSBanner(); Banner.Name = "Banner"; Banner.Offset = BannerOffset; Banner.Length = 9216; Banner.ReadBanner(stream); // ARM9 and ARM9 Overlay Table reading. ARM9 = new NDSBinary(); ARM9.Name = "ARM9"; ARM9.Extension = ".bin"; ARM9.Offset = ARM9Offset; ARM9.Length = ARM9Length; ARM9.Load = ARM9Load; ARM9.AutoLoad = ARM9AutoLoad; ARM9.AutoParams = ARM9AutoParam; if (ARM9iLength > 0) { ARM9i = new NDSBinary(); ARM9i.Name = "ARM9i"; ARM9i.Extension = ".bin"; ARM9i.Offset = ARM9iOffset; ARM9i.Length = ARM9iLength; } int overlay9_count = Convert.ToInt32(ARM9OverlayLength / 32); reader.BaseStream.Position = ARM9OverlayOffset; OverlayTable9 = new NDSOverlay[overlay9_count]; for (int i = 0; i < overlay9_count; i++) { NDSOverlay overlay = new NDSOverlay(); overlay.OverlayID = reader.ReadUInt32(); overlay.AddressRAM = reader.ReadUInt32(); overlay.SizeRAM = reader.ReadUInt32(); overlay.SizeBSS = reader.ReadUInt32(); overlay.StaticStartAddress = reader.ReadUInt32(); overlay.StaticEndAddress = reader.ReadUInt32(); overlay.ID = Convert.ToInt32(reader.ReadUInt32()); overlay.Offset = FileTable[overlay.ID].Offset; overlay.Length = FileTable[overlay.ID].Length; uint temp = reader.ReadUInt32(); uint flag = temp >> 24; if ((flag & 2) != 0) { overlay.Authenticated = true; } if ((flag & 1) != 0) { overlay.Compressed = true; overlay.CompressedSize = (temp << 8) >> 8; } overlay.Name = "Overlay " + overlay.OverlayID; overlay.Path = "ARM9 Overlay Table\\" + overlay.Name; overlay.Extension = ".bin"; OverlayTable9[i] = overlay; FileTable[overlay.ID] = overlay; } // ARM7 and ARM7 Overlay Table reading. if (ARM7Length > 0) { ARM7 = new NDSBinary(); ARM7.Name = "ARM7"; ARM7.Extension = ".bin"; ARM7.Offset = ARM7Offset; ARM7.Length = ARM7Length; ARM7.Load = ARM7Load; ARM7.AutoLoad = ARM7AutoLoad; ARM7.AutoParams = ARM7AutoParam; } if (ARM7iLength > 0) { ARM7i = new NDSBinary(); ARM7i.Name = "ARM7i"; ARM7i.Extension = ".bin"; ARM7i.Offset = ARM7iOffset; ARM7i.Length = ARM7Length; } int overlay7_count = Convert.ToInt32(ARM7OverlayLength / 32); OverlayTable7 = new NDSOverlay[overlay7_count]; if (overlay7_count > 0) { reader.BaseStream.Position = ARM7OverlayOffset; for (int i = 0; i < overlay7_count; i++) { NDSOverlay overlay = new NDSOverlay(); overlay.OverlayID = reader.ReadUInt32(); overlay.AddressRAM = reader.ReadUInt32(); overlay.SizeRAM = reader.ReadUInt32(); overlay.SizeBSS = reader.ReadUInt32(); overlay.StaticStartAddress = reader.ReadUInt32(); overlay.StaticEndAddress = reader.ReadUInt32(); overlay.ID = Convert.ToInt32(reader.ReadUInt32()); overlay.Offset = FileTable[overlay.ID].Offset; overlay.Length = FileTable[overlay.ID].Length; uint temp = reader.ReadUInt32(); uint flag = temp >> 24; if ((flag & 2) != 0) { overlay.Authenticated = true; } if ((flag & 1) != 0) { overlay.Compressed = true; overlay.CompressedSize = (temp << 8) >> 8; } overlay.Name = "Overlay " + overlay.OverlayID; overlay.Path = "ARM9 Overlay Table\\" + overlay.Name; overlay.Extension = ".bin"; OverlayTable7[i] = overlay; FileTable[overlay.ID] = overlay; } } } }