// Create a new filesystem. public Filesystem(BinaryReader r, uint fntOff, uint fntSize, uint fatOff, uint fatSize, bool convertFiles, ConversionInfo conversionInfo) { // Read a folder. Folder ReadFolder(ushort id, Folder parent = null, string folderName = "") { // Get folder info. r.BaseStream.Position = fntOff + 8 * id; Folder ret = new Folder(); ret.Parent = parent; ret.Id = id; ret.Name = folderName; uint off = r.ReadUInt32(); ret.FirstFileId = r.ReadUInt16(); r.ReadUInt16(); // Parent ID. Root folder is total number of folders. r.BaseStream.Position = fntOff + off; // Data. byte control = r.ReadByte(); ushort currId = ret.FirstFileId; while (control != 0) { bool folder = (control & 0x80) != 0; control &= 0x7F; string name = new string(r.ReadChars(control)); if (folder) { ushort subId = (ushort)(r.ReadUInt16() & 0xFFF); long bakPos = r.BaseStream.Position; Folder newFolder = ReadFolder(subId, ret, name); r.BaseStream.Position = bakPos; ret.Folders.Add(newFolder); } else { long bakPos = r.BaseStream.Position; r.BaseStream.Position = fatOff + currId * 8; uint startOff = r.ReadUInt32(); uint endOff = r.ReadUInt32(); r.BaseStream.Position = startOff; byte[] fileData = r.ReadBytes((int)(endOff - startOff)); IFormat newData = null; if (convertFiles) { string filePath = name; Folder currFolder = ret; while (currFolder != null) { filePath = currFolder.Name + "/" + filePath; currFolder = currFolder.Parent; } if (filePath.StartsWith("/")) { filePath = filePath.Substring(1); } newData = FormatUtil.DoExtractionConversion(conversionInfo, r, startOff, filePath, fileData); } else { newData = new GenericFile() { Data = fileData }; } r.BaseStream.Position = bakPos; ret.Files.Add(new File() { Name = name, Id = currId++, Data = newData }); } control = r.ReadByte(); } // Finish. return(ret); } // Read root. var root = ReadFolder(0); Folders = root.Folders; Files = root.Files; FirstFileId = root.FirstFileId; }
// Create a new ROM. public ROM(string filePath, string conversionPath) { // Build system. if (!conversionPath.Equals("")) { Directory.CreateDirectory(conversionPath); ConversionInfo = new ConversionInfo(conversionPath); } // Read the file. using (Stream s = new FileStream(filePath, FileMode.Open)) { // Read general data. BinaryReader r = new BinaryReader(s); GameTitle = r.ReadFixedLen(0xC); GameCode = r.ReadFixedLen(0x4); MakerCode = r.ReadFixedLen(0x2); UnitCode = (UnitCode)r.ReadByte(); EncryptionSeedSelect = r.ReadByte(); DeviceCapacity = r.ReadByte(); r.ReadBytes(7); Revision = r.ReadUInt16(); Version = r.ReadByte(); Flags = r.ReadByte(); uint arm9Offset = r.ReadUInt32(); Arm9EntryAddress = r.ReadUInt32(); Arm9LoadAddress = r.ReadUInt32(); uint arm9Size = r.ReadUInt32(); uint arm7Offset = r.ReadUInt32(); Arm7EntryAddress = r.ReadUInt32(); Arm7LoadAddress = r.ReadUInt32(); uint arm7Size = r.ReadUInt32(); uint fntOffset = r.ReadUInt32(); uint fntSize = r.ReadUInt32(); uint fatOffset = r.ReadUInt32(); uint fatSize = r.ReadUInt32(); uint arm9OverlayOffset = r.ReadUInt32(); uint arm9OverlayLength = r.ReadUInt32(); uint arm7OverlayOffset = r.ReadUInt32(); uint arm7OverlayLength = r.ReadUInt32(); NormalCardControlRegisterSettings = r.ReadUInt32(); SecureCardControlRegisterSettings = r.ReadUInt32(); uint iconBannerOffset = r.ReadUInt32(); SecureAreaCRC = r.ReadUInt16(); SecureTransferTimeout = r.ReadUInt16(); Arm9Autoload = r.ReadUInt32(); Arm7Autoload = r.ReadUInt32(); SecureDisable = r.ReadUInt64(); uint romSize = r.ReadUInt32() + 0x88; HeaderSize = r.ReadUInt32(); // Read logo. r.BaseStream.Position = 0xC0; NintendoLogo = r.ReadBytes(0x9C); r.ReadUInt16(); // Nintendo logo CRC. It is literally just the CRC of the logo. r.ReadUInt16(); // Header CRC. It is the CRC of everything up to this point (0 to 0x15E). // Get banner. r.BaseStream.Position = iconBannerOffset; ushort bannerVersion = r.ReadUInt16(); r.BaseStream.Position -= 2; Banner = r.ReadBytes((int)BANNER_LENGTHS[bannerVersion]); // Code binaries. r.BaseStream.Position = arm9Offset; Arm9 = r.ReadBytes((int)arm9Size); r.BaseStream.Position = arm7Offset; Arm7 = r.ReadBytes((int)arm7Size); // Get overlays. Arm9Overlays = Overlay.LoadOverlays(r, arm9OverlayOffset, arm9OverlayLength); Arm7Overlays = Overlay.LoadOverlays(r, arm7OverlayOffset, arm7OverlayLength); for (int i = 0; i < Arm9Overlays.Count; i++) { r.BaseStream.Position = fatOffset + Arm9Overlays[i].FileId * 8; uint fileStart = r.ReadUInt32(); uint fileEnd = r.ReadUInt32(); r.BaseStream.Position = fileStart; Arm9Overlays[i].Data = r.ReadBytes((int)(fileEnd - fileStart)); } for (int i = 0; i < Arm7Overlays.Count; i++) { r.BaseStream.Position = fatOffset + Arm7Overlays[i].FileId * 8; uint fileStart = r.ReadUInt32(); uint fileEnd = r.ReadUInt32(); r.BaseStream.Position = fileStart; Arm7Overlays[i].Data = r.ReadBytes((int)(fileEnd - fileStart)); } // Read filesystem. Filesystem = new Filesystem(r, fntOffset, fntSize, fatOffset, fatSize, !conversionPath.Equals(""), ConversionInfo); // Dispose. r.Dispose(); } }