using System; using System.IO; using System.Text; namespace BinaryObjectScanner.Wrappers { public class Nitro : WrapperBase { #region Descriptive Properties /// public override string DescriptionString => "Nintendo DS/DSi Cart Image"; #endregion #region Pass-Through Properties #region Common Header /// #if NET48 public string GameTitle => _model.CommonHeader.GameTitle; #else public string? GameTitle => _model.CommonHeader?.GameTitle; #endif /// #if NET48 public uint GameCode => _model.CommonHeader.GameCode; #else public uint? GameCode => _model.CommonHeader?.GameCode; #endif /// #if NET48 public string MakerCode => _model.CommonHeader.MakerCode; #else public string? MakerCode => _model.CommonHeader?.MakerCode; #endif /// #if NET48 public SabreTools.Models.Nitro.Unitcode UnitCode => _model.CommonHeader.UnitCode; #else public SabreTools.Models.Nitro.Unitcode? UnitCode => _model.CommonHeader?.UnitCode; #endif /// #if NET48 public byte EncryptionSeedSelect => _model.CommonHeader.EncryptionSeedSelect; #else public byte? EncryptionSeedSelect => _model.CommonHeader?.EncryptionSeedSelect; #endif /// #if NET48 public byte DeviceCapacity => _model.CommonHeader.DeviceCapacity; #else public byte? DeviceCapacity => _model.CommonHeader?.DeviceCapacity; #endif /// #if NET48 public byte[] Reserved1 => _model.CommonHeader.Reserved1; #else public byte[]? Reserved1 => _model.CommonHeader?.Reserved1; #endif /// #if NET48 public ushort GameRevision => _model.CommonHeader.GameRevision; #else public ushort? GameRevision => _model.CommonHeader?.GameRevision; #endif /// #if NET48 public byte RomVersion => _model.CommonHeader.RomVersion; #else public byte? RomVersion => _model.CommonHeader?.RomVersion; #endif /// #if NET48 public byte InternalFlags => _model.CommonHeader.InternalFlags; #else public byte? InternalFlags => _model.CommonHeader?.InternalFlags; #endif /// #if NET48 public uint ARM9RomOffset => _model.CommonHeader.ARM9RomOffset; #else public uint? ARM9RomOffset => _model.CommonHeader?.ARM9RomOffset; #endif /// #if NET48 public uint ARM9EntryAddress => _model.CommonHeader.ARM9EntryAddress; #else public uint? ARM9EntryAddress => _model.CommonHeader?.ARM9EntryAddress; #endif /// #if NET48 public uint ARM9LoadAddress => _model.CommonHeader.ARM9LoadAddress; #else public uint? ARM9LoadAddress => _model.CommonHeader?.ARM9LoadAddress; #endif /// #if NET48 public uint ARM9Size => _model.CommonHeader.ARM9Size; #else public uint? ARM9Size => _model.CommonHeader?.ARM9Size; #endif /// #if NET48 public uint ARM7RomOffset => _model.CommonHeader.ARM7RomOffset; #else public uint? ARM7RomOffset => _model.CommonHeader?.ARM7RomOffset; #endif /// #if NET48 public uint ARM7EntryAddress => _model.CommonHeader.ARM7EntryAddress; #else public uint? ARM7EntryAddress => _model.CommonHeader?.ARM7EntryAddress; #endif /// #if NET48 public uint ARM7LoadAddress => _model.CommonHeader.ARM7LoadAddress; #else public uint? ARM7LoadAddress => _model.CommonHeader?.ARM7LoadAddress; #endif /// #if NET48 public uint ARM7Size => _model.CommonHeader.ARM7Size; #else public uint? ARM7Size => _model.CommonHeader?.ARM7Size; #endif /// #if NET48 public uint FileNameTableOffset => _model.CommonHeader.FileNameTableOffset; #else public uint? FileNameTableOffset => _model.CommonHeader?.FileNameTableOffset; #endif /// #if NET48 public uint FileNameTableLength => _model.CommonHeader.FileNameTableLength; #else public uint? FileNameTableLength => _model.CommonHeader?.FileNameTableLength; #endif /// #if NET48 public uint FileAllocationTableOffset => _model.CommonHeader.FileAllocationTableOffset; #else public uint? FileAllocationTableOffset => _model.CommonHeader?.FileAllocationTableOffset; #endif /// #if NET48 public uint FileAllocationTableLength => _model.CommonHeader.FileAllocationTableLength; #else public uint? FileAllocationTableLength => _model.CommonHeader?.FileAllocationTableLength; #endif /// #if NET48 public uint ARM9OverlayOffset => _model.CommonHeader.ARM9OverlayOffset; #else public uint? ARM9OverlayOffset => _model.CommonHeader?.ARM9OverlayOffset; #endif /// #if NET48 public uint ARM9OverlayLength => _model.CommonHeader.ARM9OverlayLength; #else public uint? ARM9OverlayLength => _model.CommonHeader?.ARM9OverlayLength; #endif /// #if NET48 public uint ARM7OverlayOffset => _model.CommonHeader.ARM7OverlayOffset; #else public uint? ARM7OverlayOffset => _model.CommonHeader?.ARM7OverlayOffset; #endif /// #if NET48 public uint ARM7OverlayLength => _model.CommonHeader.ARM7OverlayLength; #else public uint? ARM7OverlayLength => _model.CommonHeader?.ARM7OverlayLength; #endif /// #if NET48 public uint NormalCardControlRegisterSettings => _model.CommonHeader.NormalCardControlRegisterSettings; #else public uint? NormalCardControlRegisterSettings => _model.CommonHeader?.NormalCardControlRegisterSettings; #endif /// #if NET48 public uint SecureCardControlRegisterSettings => _model.CommonHeader.SecureCardControlRegisterSettings; #else public uint? SecureCardControlRegisterSettings => _model.CommonHeader?.SecureCardControlRegisterSettings; #endif /// #if NET48 public uint IconBannerOffset => _model.CommonHeader.IconBannerOffset; #else public uint? IconBannerOffset => _model.CommonHeader?.IconBannerOffset; #endif /// #if NET48 public ushort SecureAreaCRC => _model.CommonHeader.SecureAreaCRC; #else public ushort? SecureAreaCRC => _model.CommonHeader?.SecureAreaCRC; #endif /// #if NET48 public ushort SecureTransferTimeout => _model.CommonHeader.SecureTransferTimeout; #else public ushort? SecureTransferTimeout => _model.CommonHeader?.SecureTransferTimeout; #endif /// #if NET48 public uint ARM9Autoload => _model.CommonHeader.ARM9Autoload; #else public uint? ARM9Autoload => _model.CommonHeader?.ARM9Autoload; #endif /// #if NET48 public uint ARM7Autoload => _model.CommonHeader.ARM7Autoload; #else public uint? ARM7Autoload => _model.CommonHeader?.ARM7Autoload; #endif /// #if NET48 public byte[] SecureDisable => _model.CommonHeader.SecureDisable; #else public byte[]? SecureDisable => _model.CommonHeader?.SecureDisable; #endif /// #if NET48 public uint NTRRegionRomSize => _model.CommonHeader.NTRRegionRomSize; #else public uint? NTRRegionRomSize => _model.CommonHeader?.NTRRegionRomSize; #endif /// #if NET48 public uint HeaderSize => _model.CommonHeader.HeaderSize; #else public uint? HeaderSize => _model.CommonHeader?.HeaderSize; #endif /// #if NET48 public byte[] Reserved2 => _model.CommonHeader.Reserved2; #else public byte[]? Reserved2 => _model.CommonHeader?.Reserved2; #endif /// #if NET48 public byte[] NintendoLogo => _model.CommonHeader.NintendoLogo; #else public byte[]? NintendoLogo => _model.CommonHeader?.NintendoLogo; #endif /// #if NET48 public ushort NintendoLogoCRC => _model.CommonHeader.NintendoLogoCRC; #else public ushort? NintendoLogoCRC => _model.CommonHeader?.NintendoLogoCRC; #endif /// #if NET48 public ushort HeaderCRC => _model.CommonHeader.HeaderCRC; #else public ushort? HeaderCRC => _model.CommonHeader?.HeaderCRC; #endif /// #if NET48 public byte[] DebuggerReserved => _model.CommonHeader.DebuggerReserved; #else public byte[]? DebuggerReserved => _model.CommonHeader?.DebuggerReserved; #endif #endregion #region Extended DSi Header /// #if NET48 public uint[] GlobalMBK15Settings => _model.ExtendedDSiHeader?.GlobalMBK15Settings; #else public uint[]? GlobalMBK15Settings => _model.ExtendedDSiHeader?.GlobalMBK15Settings; #endif /// #if NET48 public uint[] LocalMBK68SettingsARM9 => _model.ExtendedDSiHeader?.LocalMBK68SettingsARM9; #else public uint[]? LocalMBK68SettingsARM9 => _model.ExtendedDSiHeader?.LocalMBK68SettingsARM9; #endif /// #if NET48 public uint[] LocalMBK68SettingsARM7 => _model.ExtendedDSiHeader?.LocalMBK68SettingsARM7; #else public uint[]? LocalMBK68SettingsARM7 => _model.ExtendedDSiHeader?.LocalMBK68SettingsARM7; #endif /// public uint? GlobalMBK9Setting => _model.ExtendedDSiHeader?.GlobalMBK9Setting; /// public uint? RegionFlags => _model.ExtendedDSiHeader?.RegionFlags; /// public uint? AccessControl => _model.ExtendedDSiHeader?.AccessControl; /// public uint? ARM7SCFGEXTMask => _model.ExtendedDSiHeader?.ARM7SCFGEXTMask; /// public uint? ReservedFlags => _model.ExtendedDSiHeader?.ReservedFlags; /// public uint? ARM9iRomOffset => _model.ExtendedDSiHeader?.ARM9iRomOffset; /// public uint? Reserved3 => _model.ExtendedDSiHeader?.Reserved3; /// public uint? ARM9iLoadAddress => _model.ExtendedDSiHeader?.ARM9iLoadAddress; /// public uint? ARM9iSize => _model.ExtendedDSiHeader?.ARM9iSize; /// public uint? ARM7iRomOffset => _model.ExtendedDSiHeader?.ARM7iRomOffset; /// public uint? Reserved4 => _model.ExtendedDSiHeader?.Reserved4; /// public uint? ARM7iLoadAddress => _model.ExtendedDSiHeader?.ARM7iLoadAddress; /// public uint? ARM7iSize => _model.ExtendedDSiHeader?.ARM7iSize; /// public uint? DigestNTRRegionOffset => _model.ExtendedDSiHeader?.DigestNTRRegionOffset; /// public uint? DigestNTRRegionLength => _model.ExtendedDSiHeader?.DigestNTRRegionLength; /// public uint? DigestTWLRegionOffset => _model.ExtendedDSiHeader?.DigestTWLRegionOffset; /// public uint? DigestTWLRegionLength => _model.ExtendedDSiHeader?.DigestTWLRegionLength; /// public uint? DigestSectorHashtableRegionOffset => _model.ExtendedDSiHeader?.DigestSectorHashtableRegionOffset; /// public uint? DigestSectorHashtableRegionLength => _model.ExtendedDSiHeader?.DigestSectorHashtableRegionLength; /// public uint? DigestBlockHashtableRegionOffset => _model.ExtendedDSiHeader?.DigestBlockHashtableRegionOffset; /// public uint? DigestBlockHashtableRegionLength => _model.ExtendedDSiHeader?.DigestBlockHashtableRegionLength; /// public uint? DigestSectorSize => _model.ExtendedDSiHeader?.DigestSectorSize; /// public uint? DigestBlockSectorCount => _model.ExtendedDSiHeader?.DigestBlockSectorCount; /// public uint? IconBannerSize => _model.ExtendedDSiHeader?.IconBannerSize; /// public uint? Unknown1 => _model.ExtendedDSiHeader?.Unknown1; /// public uint? ModcryptArea1Offset => _model.ExtendedDSiHeader?.ModcryptArea1Offset; /// public uint? ModcryptArea1Size => _model.ExtendedDSiHeader?.ModcryptArea1Size; /// public uint? ModcryptArea2Offset => _model.ExtendedDSiHeader?.ModcryptArea2Offset; /// public uint? ModcryptArea2Size => _model.ExtendedDSiHeader?.ModcryptArea2Size; /// #if NET48 public byte[] TitleID => _model.ExtendedDSiHeader?.TitleID; #else public byte[]? TitleID => _model.ExtendedDSiHeader?.TitleID; #endif /// public uint? DSiWarePublicSavSize => _model.ExtendedDSiHeader?.DSiWarePublicSavSize; /// public uint? DSiWarePrivateSavSize => _model.ExtendedDSiHeader?.DSiWarePrivateSavSize; /// #if NET48 public byte[] ReservedZero => _model.ExtendedDSiHeader?.ReservedZero; #else public byte[]? ReservedZero => _model.ExtendedDSiHeader?.ReservedZero; #endif /// #if NET48 public byte[] Unknown2 => _model.ExtendedDSiHeader?.Unknown2; #else public byte[]? Unknown2 => _model.ExtendedDSiHeader?.Unknown2; #endif /// #if NET48 public byte[] ARM9WithSecureAreaSHA1HMACHash => _model.ExtendedDSiHeader?.ARM9WithSecureAreaSHA1HMACHash; #else public byte[]? ARM9WithSecureAreaSHA1HMACHash => _model.ExtendedDSiHeader?.ARM9WithSecureAreaSHA1HMACHash; #endif /// #if NET48 public byte[] ARM7SHA1HMACHash => _model.ExtendedDSiHeader?.ARM7SHA1HMACHash; #else public byte[]? ARM7SHA1HMACHash => _model.ExtendedDSiHeader?.ARM7SHA1HMACHash; #endif /// #if NET48 public byte[] DigestMasterSHA1HMACHash => _model.ExtendedDSiHeader?.DigestMasterSHA1HMACHash; #else public byte[]? DigestMasterSHA1HMACHash => _model.ExtendedDSiHeader?.DigestMasterSHA1HMACHash; #endif /// #if NET48 public byte[] BannerSHA1HMACHash => _model.ExtendedDSiHeader?.BannerSHA1HMACHash; #else public byte[]? BannerSHA1HMACHash => _model.ExtendedDSiHeader?.BannerSHA1HMACHash; #endif /// #if NET48 public byte[] ARM9iDecryptedSHA1HMACHash => _model.ExtendedDSiHeader?.ARM9iDecryptedSHA1HMACHash; #else public byte[]? ARM9iDecryptedSHA1HMACHash => _model.ExtendedDSiHeader?.ARM9iDecryptedSHA1HMACHash; #endif /// #if NET48 public byte[] ARM7iDecryptedSHA1HMACHash => _model.ExtendedDSiHeader?.ARM7iDecryptedSHA1HMACHash; #else public byte[]? ARM7iDecryptedSHA1HMACHash => _model.ExtendedDSiHeader?.ARM7iDecryptedSHA1HMACHash; #endif /// #if NET48 public byte[] Reserved5 => _model.ExtendedDSiHeader?.Reserved5; #else public byte[]? Reserved5 => _model.ExtendedDSiHeader?.Reserved5; #endif /// #if NET48 public byte[] ARM9NoSecureAreaSHA1HMACHash => _model.ExtendedDSiHeader?.ARM9NoSecureAreaSHA1HMACHash; #else public byte[]? ARM9NoSecureAreaSHA1HMACHash => _model.ExtendedDSiHeader?.ARM9NoSecureAreaSHA1HMACHash; #endif /// #if NET48 public byte[] Reserved6 => _model.ExtendedDSiHeader?.Reserved6; #else public byte[]? Reserved6 => _model.ExtendedDSiHeader?.Reserved6; #endif /// #if NET48 public byte[] ReservedAndUnchecked => _model.ExtendedDSiHeader?.ReservedAndUnchecked; #else public byte[]? ReservedAndUnchecked => _model.ExtendedDSiHeader?.ReservedAndUnchecked; #endif /// #if NET48 public byte[] RSASignature => _model.ExtendedDSiHeader?.RSASignature; #else public byte[]? RSASignature => _model.ExtendedDSiHeader?.RSASignature; #endif #endregion #region Secure Area /// #if NET48 public byte[] SecureArea => _model.SecureArea; #else public byte[]? SecureArea => _model.SecureArea; #endif #endregion #region Name Table /// #if NET48 public SabreTools.Models.Nitro.FolderAllocationTableEntry[] FolderAllocationTable => _model.NameTable.FolderAllocationTable; #else public SabreTools.Models.Nitro.FolderAllocationTableEntry?[]? FolderAllocationTable => _model.NameTable?.FolderAllocationTable; #endif /// #if NET48 public SabreTools.Models.Nitro.NameListEntry[] NameList => _model.NameTable.NameList; #else public SabreTools.Models.Nitro.NameListEntry?[]? NameList => _model.NameTable?.NameList; #endif #endregion #region File Allocation Table /// #if NET48 public SabreTools.Models.Nitro.FileAllocationTableEntry[] FileAllocationTable => _model.FileAllocationTable; #else public SabreTools.Models.Nitro.FileAllocationTableEntry?[]? FileAllocationTable => _model.FileAllocationTable; #endif #endregion #endregion #region Constructors /// #if NET48 public Nitro(SabreTools.Models.Nitro.Cart model, byte[] data, int offset) #else public Nitro(SabreTools.Models.Nitro.Cart? model, byte[]? data, int offset) #endif : base(model, data, offset) { // All logic is handled by the base class } /// #if NET48 public Nitro(SabreTools.Models.Nitro.Cart model, Stream data) #else public Nitro(SabreTools.Models.Nitro.Cart? model, Stream? data) #endif : base(model, data) { // All logic is handled by the base class } /// /// Create a NDS cart image from a byte array and offset /// /// Byte array representing the archive /// Offset within the array to parse /// A NDS cart image wrapper on success, null on failure #if NET48 public static Nitro Create(byte[] data, int offset) #else public static Nitro? Create(byte[]? data, int offset) #endif { // If the data is invalid if (data == null) return null; // If the offset is out of bounds if (offset < 0 || offset >= data.Length) return null; // Create a memory stream and use that MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset); return Create(dataStream); } /// /// Create a NDS cart image from a Stream /// /// Stream representing the archive /// A NDS cart image wrapper on success, null on failure #if NET48 public static Nitro Create(Stream data) #else public static Nitro? Create(Stream? data) #endif { // If the data is invalid if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead) return null; var archive = new SabreTools.Serialization.Streams.Nitro().Deserialize(data); if (archive == null) return null; try { return new Nitro(archive, data); } catch { return null; } } #endregion #region Printing /// public override StringBuilder PrettyPrint() { StringBuilder builder = new StringBuilder(); builder.AppendLine("NDS Cart Information:"); builder.AppendLine("-------------------------"); builder.AppendLine(); PrintCommonHeader(builder); PrintExtendedDSiHeader(builder); PrintSecureArea(builder); PrintNameTable(builder); PrintFileAllocationTable(builder); return builder; } /// /// Print common header information /// /// StringBuilder to append information to private void PrintCommonHeader(StringBuilder builder) { builder.AppendLine(" Common Header Information:"); builder.AppendLine(" -------------------------"); builder.AppendLine($" Game title: {GameTitle ?? "[NULL]"}"); builder.AppendLine($" Game code: {GameCode} (0x{GameCode:X})"); builder.AppendLine($" Maker code: {MakerCode ?? "[NULL]"}"); builder.AppendLine($" Unit code: {UnitCode} (0x{UnitCode:X})"); builder.AppendLine($" Encryption seed select: {EncryptionSeedSelect} (0x{EncryptionSeedSelect:X})"); builder.AppendLine($" Device capacity: {DeviceCapacity} (0x{DeviceCapacity:X})"); builder.AppendLine($" Reserved 1: {(Reserved1 == null ? "[NULL]" : BitConverter.ToString(Reserved1).Replace('-', ' '))}"); builder.AppendLine($" Game revision: {GameRevision} (0x{GameRevision:X})"); builder.AppendLine($" Rom version: {RomVersion} (0x{RomVersion:X})"); builder.AppendLine($" ARM9 rom offset: {ARM9RomOffset} (0x{ARM9RomOffset:X})"); builder.AppendLine($" ARM9 entry address: {ARM9EntryAddress} (0x{ARM9EntryAddress:X})"); builder.AppendLine($" ARM9 load address: {ARM9LoadAddress} (0x{ARM9LoadAddress:X})"); builder.AppendLine($" ARM9 size: {ARM9Size} (0x{ARM9Size:X})"); builder.AppendLine($" ARM7 rom offset: {ARM7RomOffset} (0x{ARM7RomOffset:X})"); builder.AppendLine($" ARM7 entry address: {ARM7EntryAddress} (0x{ARM7EntryAddress:X})"); builder.AppendLine($" ARM7 load address: {ARM7LoadAddress} (0x{ARM7LoadAddress:X})"); builder.AppendLine($" ARM7 size: {ARM7Size} (0x{ARM7Size:X})"); builder.AppendLine($" File name table offset: {FileNameTableOffset} (0x{FileNameTableOffset:X})"); builder.AppendLine($" File name table length: {FileNameTableLength} (0x{FileNameTableLength:X})"); builder.AppendLine($" File allocation table offset: {FileAllocationTableOffset} (0x{FileAllocationTableOffset:X})"); builder.AppendLine($" File allocation table length: {FileAllocationTableLength} (0x{FileAllocationTableLength:X})"); builder.AppendLine($" ARM9 overlay offset: {ARM9OverlayOffset} (0x{ARM9OverlayOffset:X})"); builder.AppendLine($" ARM9 overlay length: {ARM9OverlayLength} (0x{ARM9OverlayLength:X})"); builder.AppendLine($" ARM7 overlay offset: {ARM7OverlayOffset} (0x{ARM7OverlayOffset:X})"); builder.AppendLine($" ARM7 overlay length: {ARM7OverlayLength} (0x{ARM7OverlayLength:X})"); builder.AppendLine($" Normal card control register settings: {NormalCardControlRegisterSettings} (0x{NormalCardControlRegisterSettings:X})"); builder.AppendLine($" Secure card control register settings: {SecureCardControlRegisterSettings} (0x{SecureCardControlRegisterSettings:X})"); builder.AppendLine($" Icon banner offset: {IconBannerOffset} (0x{IconBannerOffset:X})"); builder.AppendLine($" Secure area CRC: {SecureAreaCRC} (0x{SecureAreaCRC:X})"); builder.AppendLine($" Secure transfer timeout: {SecureTransferTimeout} (0x{SecureTransferTimeout:X})"); builder.AppendLine($" ARM9 autoload: {ARM9Autoload} (0x{ARM9Autoload:X})"); builder.AppendLine($" ARM7 autoload: {ARM7Autoload} (0x{ARM7Autoload:X})"); builder.AppendLine($" Secure disable: {SecureDisable} (0x{SecureDisable:X})"); builder.AppendLine($" NTR region rom size: {NTRRegionRomSize} (0x{NTRRegionRomSize:X})"); builder.AppendLine($" Header size: {HeaderSize} (0x{HeaderSize:X})"); builder.AppendLine($" Reserved 2: {(Reserved2 == null ? "[NULL]" : BitConverter.ToString(Reserved2).Replace('-', ' '))}"); builder.AppendLine($" Nintendo logo: {(NintendoLogo == null ? "[NULL]" : BitConverter.ToString(NintendoLogo).Replace('-', ' '))}"); builder.AppendLine($" Nintendo logo CRC: {NintendoLogoCRC} (0x{NintendoLogoCRC:X})"); builder.AppendLine($" Header CRC: {HeaderCRC} (0x{HeaderCRC:X})"); builder.AppendLine($" Debugger reserved: {(DebuggerReserved == null ? "[NULL]" : BitConverter.ToString(DebuggerReserved).Replace('-', ' '))}"); builder.AppendLine(); } /// /// Print extended DSi header information /// /// StringBuilder to append information to private void PrintExtendedDSiHeader(StringBuilder builder) { builder.AppendLine(" Extended DSi Header Information:"); builder.AppendLine(" -------------------------"); if (_model.ExtendedDSiHeader == null) { builder.AppendLine(" No extended DSi header"); } else { builder.AppendLine($" Global MBK1..MBK5 settings: {(GlobalMBK15Settings == null ? "[NULL]" : string.Join(", ", GlobalMBK15Settings))}"); builder.AppendLine($" Local MBK6..MBK8 settings for ARM9: {(LocalMBK68SettingsARM9 == null ? "[NULL]" : string.Join(", ", LocalMBK68SettingsARM9))}"); builder.AppendLine($" Local MBK6..MBK8 settings for ARM7: {(LocalMBK68SettingsARM7 == null ? "[NULL]" : string.Join(", ", LocalMBK68SettingsARM7))}"); builder.AppendLine($" Global MBK9 setting: {GlobalMBK9Setting} (0x{GlobalMBK9Setting:X})"); builder.AppendLine($" Region flags: {RegionFlags} (0x{RegionFlags:X})"); builder.AppendLine($" Access control: {AccessControl} (0x{AccessControl:X})"); builder.AppendLine($" ARM7 SCFG EXT mask: {ARM7SCFGEXTMask} (0x{ARM7SCFGEXTMask:X})"); builder.AppendLine($" Reserved/flags?: {ReservedFlags} (0x{ReservedFlags:X})"); builder.AppendLine($" ARM9i rom offset: {ARM9iRomOffset} (0x{ARM9iRomOffset:X})"); builder.AppendLine($" Reserved 3: {Reserved3} (0x{Reserved3:X})"); builder.AppendLine($" ARM9i load address: {ARM9iLoadAddress} (0x{ARM9iLoadAddress:X})"); builder.AppendLine($" ARM9i size: {ARM9iSize} (0x{ARM9iSize:X})"); builder.AppendLine($" ARM7i rom offset: {ARM7iRomOffset} (0x{ARM7iRomOffset:X})"); builder.AppendLine($" Reserved 4: {Reserved4} (0x{Reserved4:X})"); builder.AppendLine($" ARM7i load address: {ARM7iLoadAddress} (0x{ARM7iLoadAddress:X})"); builder.AppendLine($" ARM7i size: {ARM7iSize} (0x{ARM7iSize:X})"); builder.AppendLine($" Digest NTR region offset: {DigestNTRRegionOffset} (0x{DigestNTRRegionOffset:X})"); builder.AppendLine($" Digest NTR region length: {DigestNTRRegionLength} (0x{DigestNTRRegionLength:X})"); builder.AppendLine($" Digest TWL region offset: {DigestTWLRegionOffset} (0x{DigestTWLRegionOffset:X})"); builder.AppendLine($" Digest TWL region length: {DigestTWLRegionLength} (0x{DigestTWLRegionLength:X})"); builder.AppendLine($" Digest sector hashtable region offset: {DigestSectorHashtableRegionOffset} (0x{DigestSectorHashtableRegionOffset:X})"); builder.AppendLine($" Digest sector hashtable region length: {DigestSectorHashtableRegionLength} (0x{DigestSectorHashtableRegionLength:X})"); builder.AppendLine($" Digest block hashtable region offset: {DigestBlockHashtableRegionOffset} (0x{DigestBlockHashtableRegionOffset:X})"); builder.AppendLine($" Digest block hashtable region length: {DigestBlockHashtableRegionLength} (0x{DigestBlockHashtableRegionLength:X})"); builder.AppendLine($" Digest sector size: {DigestSectorSize} (0x{DigestSectorSize:X})"); builder.AppendLine($" Digest block sector count: {DigestBlockSectorCount} (0x{DigestBlockSectorCount:X})"); builder.AppendLine($" Icon banner size: {IconBannerSize} (0x{IconBannerSize:X})"); builder.AppendLine($" Unknown 1: {Unknown1} (0x{Unknown1:X})"); builder.AppendLine($" Modcrypt area 1 offset: {ModcryptArea1Offset} (0x{ModcryptArea1Offset:X})"); builder.AppendLine($" Modcrypt area 1 size: {ModcryptArea1Size} (0x{ModcryptArea1Size:X})"); builder.AppendLine($" Modcrypt area 2 offset: {ModcryptArea2Offset} (0x{ModcryptArea2Offset:X})"); builder.AppendLine($" Modcrypt area 2 size: {ModcryptArea2Size} (0x{ModcryptArea2Size:X})"); builder.AppendLine($" Title ID: {(TitleID == null ? "[NULL]" : BitConverter.ToString(TitleID).Replace('-', ' '))}"); builder.AppendLine($" DSiWare 'public.sav' size: {DSiWarePublicSavSize} (0x{DSiWarePublicSavSize:X})"); builder.AppendLine($" DSiWare 'private.sav' size: {DSiWarePrivateSavSize} (0x{DSiWarePrivateSavSize:X})"); builder.AppendLine($" Reserved (zero): {(ReservedZero == null ? "[NULL]" : BitConverter.ToString(ReservedZero).Replace('-', ' '))}"); builder.AppendLine($" Unknown 2: {(Unknown2 == null ? "[NULL]" : BitConverter.ToString(Unknown2).Replace('-', ' '))}"); builder.AppendLine($" ARM9 (with encrypted secure area) SHA1 HMAC hash: {(ARM9WithSecureAreaSHA1HMACHash == null ? "[NULL]" : BitConverter.ToString(ARM9WithSecureAreaSHA1HMACHash).Replace('-', ' '))}"); builder.AppendLine($" ARM7 SHA1 HMAC hash: {(ARM7SHA1HMACHash == null ? "[NULL]" : BitConverter.ToString(ARM7SHA1HMACHash).Replace('-', ' '))}"); builder.AppendLine($" Digest master SHA1 HMAC hash: {(DigestMasterSHA1HMACHash == null ? "[NULL]" : BitConverter.ToString(DigestMasterSHA1HMACHash).Replace('-', ' '))}"); builder.AppendLine($" Banner SHA1 HMAC hash: {(BannerSHA1HMACHash == null ? "[NULL]" : BitConverter.ToString(BannerSHA1HMACHash).Replace('-', ' '))}"); builder.AppendLine($" ARM9i (decrypted) SHA1 HMAC hash: {(ARM9iDecryptedSHA1HMACHash == null ? "[NULL]" : BitConverter.ToString(ARM9iDecryptedSHA1HMACHash).Replace('-', ' '))}"); builder.AppendLine($" ARM7i (decrypted) SHA1 HMAC hash: {(ARM7iDecryptedSHA1HMACHash == null ? "[NULL]" : BitConverter.ToString(ARM7iDecryptedSHA1HMACHash).Replace('-', ' '))}"); builder.AppendLine($" Reserved 5: {(Reserved5 == null ? "[NULL]" : BitConverter.ToString(Reserved5).Replace('-', ' '))}"); builder.AppendLine($" ARM9 (without secure area) SHA1 HMAC hash: {(ARM9NoSecureAreaSHA1HMACHash == null ? "[NULL]" : BitConverter.ToString(ARM9NoSecureAreaSHA1HMACHash).Replace('-', ' '))}"); builder.AppendLine($" Reserved 6: {(Reserved6 == null ? "[NULL]" : BitConverter.ToString(Reserved6).Replace('-', ' '))}"); builder.AppendLine($" Reserved and unchecked region: {(ReservedAndUnchecked == null ? "[NULL]" : BitConverter.ToString(ReservedAndUnchecked).Replace('-', ' '))}"); builder.AppendLine($" RSA signature: {(RSASignature == null ? "[NULL]" : BitConverter.ToString(RSASignature).Replace('-', ' '))}"); } builder.AppendLine(); } /// /// Print secure area information /// /// StringBuilder to append information to private void PrintSecureArea(StringBuilder builder) { builder.AppendLine(" Secure Area Information:"); builder.AppendLine(" -------------------------"); builder.AppendLine($" {(SecureArea == null ? "[NULL]" : BitConverter.ToString(SecureArea).Replace('-', ' '))}"); builder.AppendLine(); } /// /// Print name table information /// /// StringBuilder to append information to private void PrintNameTable(StringBuilder builder) { builder.AppendLine(" Name Table Information:"); builder.AppendLine(" -------------------------"); builder.AppendLine(); PrintFolderAllocationTable(builder); PrintNameList(builder); } /// /// Print folder allocation table information /// /// StringBuilder to append information to private void PrintFolderAllocationTable(StringBuilder builder) { builder.AppendLine($" Folder Allocation Table:"); builder.AppendLine(" -------------------------"); if (FolderAllocationTable == null || FolderAllocationTable.Length == 0) { builder.AppendLine(" No folder allocation table entries"); } else { for (int i = 0; i < FolderAllocationTable.Length; i++) { var entry = FolderAllocationTable[i]; builder.AppendLine($" Folder Allocation Table Entry {i}"); if (entry == null) { builder.AppendLine(" [NULL]"); continue; } builder.AppendLine($" Start offset: {entry.StartOffset} (0x{entry.StartOffset:X})"); builder.AppendLine($" First file index: {entry.FirstFileIndex} (0x{entry.FirstFileIndex:X})"); if (entry.Unknown == 0xF0) { builder.AppendLine($" Parent folder index: {entry.ParentFolderIndex} (0x{entry.ParentFolderIndex:X})"); builder.AppendLine($" Unknown: {entry.Unknown} (0x{entry.Unknown:X})"); } else { ushort totalEntries = (ushort)((entry.Unknown << 8) | entry.ParentFolderIndex); builder.AppendLine($" Total entries: {totalEntries} (0x{totalEntries:X})"); } } } builder.AppendLine(); } /// /// Print folder allocation table information /// /// StringBuilder to append information to private void PrintNameList(StringBuilder builder) { builder.AppendLine($" Name List:"); builder.AppendLine(" -------------------------"); if (NameList == null || NameList.Length == 0) { builder.AppendLine(" No name list entries"); } else { for (int i = 0; i < NameList.Length; i++) { var entry = NameList[i]; builder.AppendLine($" Name List Entry {i}"); if (entry == null) { builder.AppendLine(" [NULL]"); continue; } builder.AppendLine($" Folder: {entry.Folder} (0x{entry.Folder:X})"); builder.AppendLine($" Name: {entry.Name ?? "[NULL]"}"); if (entry.Folder) builder.AppendLine($" Index: {entry.Index} (0x{entry.Index:X})"); } } builder.AppendLine(); } /// /// Print file allocation table information /// /// StringBuilder to append information to private void PrintFileAllocationTable(StringBuilder builder) { builder.AppendLine($" File Allocation Table:"); builder.AppendLine(" -------------------------"); if (FileAllocationTable == null || FileAllocationTable.Length == 0) { builder.AppendLine(" No file allocation table entries"); } else { for (int i = 0; i < FileAllocationTable.Length; i++) { var entry = FileAllocationTable[i]; builder.AppendLine($" File Allocation Table Entry {i}"); if (entry == null) { builder.AppendLine(" [NULL]"); continue; } builder.AppendLine($" Start offset: {entry.StartOffset} (0x{entry.StartOffset:X})"); builder.AppendLine($" End offset: {entry.EndOffset} (0x{entry.EndOffset:X})"); } } builder.AppendLine(); } #if NET6_0_OR_GREATER /// public override string ExportJSON() => System.Text.Json.JsonSerializer.Serialize(_model, _jsonSerializerOptions); #endif #endregion } }