private TreeNode InitializeNode(NDSDirectory dir) { TreeNode node = new TreeNode(); node.Name = dir.Name; node.Text = dir.Name; node.Tag = dir; if (dir.Children.Count > 0) { foreach (NDSDirectory child in dir.Children) { node.Nodes.Add(InitializeNode(child)); romTree.Update(); } } if (dir.Contents.Count > 0) { foreach (NDSFile file in dir.Contents) { node.Nodes.Add(InitializeNode(file)); romTree.Update(); } } return(node); }
public NDSFile(string name, string path, string extension, uint offset, uint length, NDSDirectory parent) { Name = name; Path = path; Extension = extension; Offset = offset; Length = length; Parent = parent; }
/// <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; } } } }
public static NARC NARC(Stream stream, NDSFile narc, bool is_nitro) { NDSFile[] file_table; NDSDirectory[] directory_table; using (BinaryReader reader = new BinaryReader(stream, new UTF8Encoding(), true)) { reader.BaseStream.Position = narc.Offset; uint fnt_offset = 0; uint fnt_length = 0; uint fat_offset = 0; uint fat_length = 0; ushort file_count = 0; if (is_nitro) { // Here we read the header of the file. These are constants, // so if any of this is wrong, it's probably a malformed NARC // or not a NARC at all. if (reader.ReadUInt32() != 1129464142 || reader.ReadUInt16() != 65534 || reader.ReadUInt16() != 256 || reader.ReadUInt32() != narc.Length || reader.ReadUInt16() != 16 || reader.ReadUInt16() != 3) { return(new NARC(new NDSFile[0], new NDSDirectory[0], false)); } // FAT Signature Check if (reader.ReadUInt32() != 1178686530) { return(new NARC(new NDSFile[0], new NDSDirectory[0], false)); } fat_length = reader.ReadUInt32(); file_count = reader.ReadUInt16(); reader.BaseStream.Position += 2; // Another validity check ... if (fat_length != (file_count * 8) + 12) { return(new NARC(new NDSFile[0], new NDSDirectory[0], false)); } } else { fnt_offset = narc.Offset + reader.ReadUInt32(); fnt_length = reader.ReadUInt32(); fat_offset = narc.Offset + reader.ReadUInt32(); fat_length = reader.ReadUInt32(); file_count = Convert.ToUInt16(fat_length / 8); reader.BaseStream.Position = fat_offset; } // 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. file_table = new NDSFile[file_count]; for (int i = 0; i < file_count; i++) { file_table[i] = new NDSFile(); file_table[i].Name = "File " + i.ToString("D" + file_count.ToString().Length); file_table[i].ID = i; file_table[i].Offset = reader.ReadUInt32(); file_table[i].Length = reader.ReadUInt32() - file_table[i].Offset; } if (is_nitro) { // FNT Signature check if (reader.ReadUInt32() != 1179538498) { return(new NARC(new NDSFile[0], new NDSDirectory[0], false)); } fnt_length = reader.ReadUInt32(); fnt_offset = narc.Offset + 16 + fat_length + 8; } // 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 = fnt_offset + 6; int directory_count = reader.ReadUInt16(); reader.BaseStream.Position = fnt_offset; // Setting up the root directory. directory_table = new NDSDirectory[directory_count]; directory_table[0] = new NDSDirectory(); directory_table[0].Name = narc.Name; directory_table[0].Path = narc.Path; int[] entry_offset = new int[directory_count]; int[] first_file = new int[directory_count]; int[] parent_index = new int[directory_count]; reader.BaseStream.Position = fnt_offset; for (int i = 0; i < directory_count; i++) { entry_offset[i] = Convert.ToInt32(reader.ReadUInt32() + fnt_offset); first_file[i] = reader.ReadUInt16(); parent_index[i] = reader.ReadUInt16() - 61440; } // 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 = directory_table[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 > fnt_offset + fnt_length) { 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; directory_table[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 = file_table[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 have to jump the memory stream a ton. foreach (NDSFile file in file_table) { if (file.Parent == null) { file.Parent = directory_table[0]; file.Path = file.Parent.Path + "\\" + file.Name; file.Parent.Contents.Add(file); } file.Offset += narc.Offset + 16 + fat_length + fnt_length + 8; 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); } } } return(new NARC(file_table, directory_table, true)); }