diff --git a/SabreTools.Serialization/Deserializers/N3DS.cs b/SabreTools.Serialization/Deserializers/N3DS.cs index f0d1a46f..ebc6b341 100644 --- a/SabreTools.Serialization/Deserializers/N3DS.cs +++ b/SabreTools.Serialization/Deserializers/N3DS.cs @@ -264,25 +264,20 @@ namespace SabreTools.Serialization.Deserializers header.WritableAddressMediaUnits = data.ReadUInt32(); header.CardInfoBitmask = data.ReadUInt32(); - header.Reserved3 = data.ReadBytes(0x108); + header.Reserved1 = data.ReadBytes(0xF8); + header.FilledSize = data.ReadUInt32(); + header.Reserved2 = data.ReadBytes(0x0C); header.TitleVersion = data.ReadUInt16(); header.CardRevision = data.ReadUInt16(); + header.Reserved3 = data.ReadBytes(0x0C); + header.CVerTitleID = data.ReadBytes(0x08); + header.CVerVersionNumber = data.ReadUInt16(); header.Reserved4 = data.ReadBytes(0xCD6); header.InitialData = ParseInitialData(data); return header; } - /// - /// Parse a Stream into a development card info header - /// - /// Stream to parse - /// Filled development card info header on success, null on error - public static DevelopmentCardInfoHeader? ParseDevelopmentCardInfoHeader(Stream data) - { - return data.ReadType(); - } - /// /// Parse a Stream into initial data /// @@ -303,6 +298,34 @@ namespace SabreTools.Serialization.Deserializers return id; } + /// + /// Parse a Stream into a development card info header + /// + /// Stream to parse + /// Filled development card info header on success, null on error + public static DevelopmentCardInfoHeader? ParseDevelopmentCardInfoHeader(Stream data) + { + // TODO: Go back to `data.ReadType();` when Models is fixed + var header = new DevelopmentCardInfoHeader(); + + header.CardDeviceReserved1 = data.ReadBytes(0x200); + header.TitleKey = data.ReadBytes(0x10); + header.CardDeviceReserved2 = data.ReadBytes(0x1BF0); + header.TestData = ParseTestData(data); + + return header; + } + + /// + /// Parse a Stream into test data + /// + /// Stream to parse + /// Filled test data on success, null on error + public static TestData? ParseTestData(Stream data) + { + return data.ReadType(); + } + /// /// Parse a Stream into an NCCH header /// diff --git a/SabreTools.Serialization/Printers/N3DS.cs b/SabreTools.Serialization/Printers/N3DS.cs index 604e74b4..7ff8bcff 100644 --- a/SabreTools.Serialization/Printers/N3DS.cs +++ b/SabreTools.Serialization/Printers/N3DS.cs @@ -44,26 +44,26 @@ namespace SabreTools.Serialization.Printers builder.AppendLine(header.PartitionsCryptType, " Partitions crypt type"); builder.AppendLine(); - builder.AppendLine(" Partition table:"); - builder.AppendLine(" -------------------------"); + builder.AppendLine(" Partition table:"); + builder.AppendLine(" -------------------------"); if (header.PartitionsTable == null || header.PartitionsTable.Length == 0) { - builder.AppendLine(" No partition table entries"); + builder.AppendLine(" No partition table entries"); } else { for (int i = 0; i < header.PartitionsTable.Length; i++) { var partitionTableEntry = header.PartitionsTable[i]; - builder.AppendLine($" Partition table entry {i}"); + builder.AppendLine($" Partition table entry {i}"); if (partitionTableEntry == null) { - builder.AppendLine(" [NULL]"); + builder.AppendLine(" [NULL]"); continue; } - builder.AppendLine(partitionTableEntry.Offset, " Offset"); - builder.AppendLine(partitionTableEntry.Length, " Length"); + builder.AppendLine(partitionTableEntry.Offset, " Offset"); + builder.AppendLine(partitionTableEntry.Length, " Length"); } } builder.AppendLine(); @@ -77,17 +77,17 @@ namespace SabreTools.Serialization.Printers builder.AppendLine(header.PartitionFlags, " Partition flags"); builder.AppendLine(); - builder.AppendLine(" Partition ID table:"); - builder.AppendLine(" -------------------------"); + builder.AppendLine(" Partition ID table:"); + builder.AppendLine(" -------------------------"); if (header.PartitionIdTable == null || header.PartitionIdTable.Length == 0) { - builder.AppendLine(" No partition ID table entries"); + builder.AppendLine(" No partition ID table entries"); } else { for (int i = 0; i < header.PartitionIdTable.Length; i++) { - builder.AppendLine(header.PartitionIdTable[i], $" Partition {i} ID"); + builder.AppendLine(header.PartitionIdTable[i], $" Partition {i} ID"); } } builder.AppendLine(); @@ -146,62 +146,6 @@ namespace SabreTools.Serialization.Printers return; } - builder.AppendLine(); - builder.AppendLine(" Initial Data:"); - builder.AppendLine(" -------------------------"); - if (header.InitialData == null) - { - builder.AppendLine(" No initial data"); - } - else - { - builder.AppendLine(header.InitialData.CardSeedKeyY, " Card seed keyY"); - builder.AppendLine(header.InitialData.EncryptedCardSeed, " Encrypted card seed"); - builder.AppendLine(header.InitialData.CardSeedAESMAC, " Card seed AES-MAC"); - builder.AppendLine(header.InitialData.CardSeedNonce, " Card seed nonce"); - builder.AppendLine(header.InitialData.Reserved, " Reserved"); - builder.AppendLine(); - - builder.AppendLine(" Backup Header:"); - builder.AppendLine(" -------------------------"); - if (header.InitialData.BackupHeader == null) - { - builder.AppendLine(" No backup header"); - } - else - { - builder.AppendLine(header.InitialData.BackupHeader.MagicID, " Magic ID"); - builder.AppendLine(header.InitialData.BackupHeader.ContentSizeInMediaUnits, " Content size in media units"); - builder.AppendLine(header.InitialData.BackupHeader.PartitionId, " Partition ID"); - builder.AppendLine(header.InitialData.BackupHeader.MakerCode, " Maker code"); - builder.AppendLine(header.InitialData.BackupHeader.Version, " Version"); - builder.AppendLine(header.InitialData.BackupHeader.VerificationHash, " Verification hash"); - builder.AppendLine(header.InitialData.BackupHeader.ProgramId, " Program ID"); - builder.AppendLine(header.InitialData.BackupHeader.Reserved1, " Reserved 1"); - builder.AppendLine(header.InitialData.BackupHeader.LogoRegionHash, " Logo region SHA-256 hash"); - builder.AppendLine(header.InitialData.BackupHeader.ProductCode, " Product code"); - builder.AppendLine(header.InitialData.BackupHeader.ExtendedHeaderHash, " Extended header SHA-256 hash"); - builder.AppendLine(header.InitialData.BackupHeader.ExtendedHeaderSizeInBytes, " Extended header size in bytes"); - builder.AppendLine(header.InitialData.BackupHeader.Reserved2, " Reserved 2"); - builder.AppendLine($" Flags: {header.InitialData.BackupHeader.Flags} (0x{header.InitialData.BackupHeader.Flags:X})"); - builder.AppendLine(header.InitialData.BackupHeader.PlainRegionOffsetInMediaUnits, " Plain region offset, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.PlainRegionSizeInMediaUnits, " Plain region size, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.LogoRegionOffsetInMediaUnits, " Logo region offset, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.LogoRegionSizeInMediaUnits, " Logo region size, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.ExeFSOffsetInMediaUnits, " ExeFS offset, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.ExeFSSizeInMediaUnits, " ExeFS size, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.ExeFSHashRegionSizeInMediaUnits, " ExeFS hash region size, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.Reserved3, " Reserved 3"); - builder.AppendLine(header.InitialData.BackupHeader.RomFSOffsetInMediaUnits, " RomFS offset, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.RomFSSizeInMediaUnits, " RomFS size, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.RomFSHashRegionSizeInMediaUnits, " RomFS hash region size, in media units"); - builder.AppendLine(header.InitialData.BackupHeader.Reserved4, " Reserved 4"); - builder.AppendLine(header.InitialData.BackupHeader.ExeFSSuperblockHash, " ExeFS superblock SHA-256 hash"); - builder.AppendLine(header.InitialData.BackupHeader.RomFSSuperblockHash, " RomFS superblock SHA-256 hash"); - } - } - builder.AppendLine(); - builder.AppendLine(header.CardDeviceReserved1, " Card device reserved 1"); builder.AppendLine(header.TitleKey, " Title key"); builder.AppendLine(header.CardDeviceReserved2, " Card device reserved 2"); diff --git a/SabreTools.Serialization/Wrappers/N3DS.cs b/SabreTools.Serialization/Wrappers/N3DS.cs index 734cb87c..bce3b6ed 100644 --- a/SabreTools.Serialization/Wrappers/N3DS.cs +++ b/SabreTools.Serialization/Wrappers/N3DS.cs @@ -13,6 +13,169 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Extension Properties + + /// + /// Backup Write Wait Time (The time to wait to write save to backup after the card is recognized (0-255 + /// seconds)). NATIVE_FIRM loads this flag from the gamecard NCSD header starting with 6.0.0-11. + /// + public byte BackupWriteWaitTime + { + get + { + if (Model.Header?.PartitionFlags == null) + return default; + + return Model.Header.PartitionFlags[(int)NCSDFlags.BackupWriteWaitTime]; + } + } + + /// + /// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (Only SDK 2.X) + /// + public MediaCardDeviceType MediaCardDevice2X + { + get + { + if (Model.Header?.PartitionFlags == null) + return default; + + return (MediaCardDeviceType)Model.Header.PartitionFlags[(int)NCSDFlags.MediaCardDevice2X]; + } + } + + /// + /// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (SDK 3.X+) + /// + public MediaCardDeviceType MediaCardDevice3X + { + get + { + if (Model.Header?.PartitionFlags == null) + return default; + + return (MediaCardDeviceType)Model.Header.PartitionFlags[(int)NCSDFlags.MediaCardDevice3X]; + } + } + + /// + /// Media Platform Index (1 = CTR) + /// + public MediaPlatformIndex MediaPlatformIndex + { + get + { + if (Model.Header?.PartitionFlags == null) + return default; + + return (MediaPlatformIndex)Model.Header.PartitionFlags[(int)NCSDFlags.MediaPlatformIndex]; + } + } + + /// + /// Media Type Index (0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device) + /// + public MediaTypeIndex MediaTypeIndex + { + get + { + if (Model.Header?.PartitionFlags == null) + return default; + + return (MediaTypeIndex)Model.Header.PartitionFlags[(int)NCSDFlags.MediaTypeIndex]; + } + } + + /// + /// Media unit size in bytes + /// + public uint MediaUnitSize + { + get + { + if (Model.Header?.PartitionFlags == null) + return default; + + return (uint)(0x200 * Math.Pow(2, Model.Header.PartitionFlags[(int)NCSDFlags.MediaUnitSize])); + } + } + + #region Partition Entries + + /// + /// Partition table entry for Executable Content (CXI) + /// + public PartitionTableEntry? ExecutableContentEntry + { + get + { + if (Model.Header?.PartitionsTable == null) + return null; + + return Model.Header.PartitionsTable[0]; + } + } + + /// + /// Partition table entry for E-Manual (CFA) + /// + public PartitionTableEntry? EManualEntry + { + get + { + if (Model.Header?.PartitionsTable == null) + return null; + + return Model.Header.PartitionsTable[1]; + } + } + + /// + /// Partition table entry for Download Play Child container (CFA) + /// + public PartitionTableEntry? DownloadPlayChildContainerEntry + { + get + { + if (Model.Header?.PartitionsTable == null) + return null; + + return Model.Header.PartitionsTable[2]; + } + } + + /// + /// Partition table entry for New3DS Update Data (CFA) + /// + public PartitionTableEntry? New3DSUpdateDataEntry + { + get + { + if (Model.Header?.PartitionsTable == null) + return null; + + return Model.Header.PartitionsTable[6]; + } + } + + /// + /// Partition table entry for Update Data (CFA) + /// + public PartitionTableEntry? UpdateDataEntry + { + get + { + if (Model.Header?.PartitionsTable == null) + return null; + + return Model.Header.PartitionsTable[7]; + } + } + + #endregion + + #endregion + #region Constructors /// @@ -77,177 +240,54 @@ namespace SabreTools.Serialization.Wrappers #endregion - // TODO: Hook these up for external use - #region Currently Unused Extensions - - #region ExeFSFileHeader + #region Data /// /// Determines if a file header represents a CODE block /// - public static bool IsCodeBinary(ExeFSFileHeader? header) + public bool IsCodeBinary(int fsIndex, int headerIndex) { - if (header == null) + if (Model.ExeFSHeaders == null) + return false; + if (fsIndex < 0 || fsIndex >= Model.ExeFSHeaders.Length) + return false; + + var fsHeader = Model.ExeFSHeaders[fsIndex]; + if (fsHeader?.FileHeaders == null) return false; - return header.FileName == ".code\0\0\0"; + if (headerIndex < 0 || headerIndex >= fsHeader.FileHeaders.Length) + return false; + + var fileHeader = fsHeader.FileHeaders[headerIndex]; + if (fileHeader == null) + return false; + + return fileHeader.FileName == ".code\0\0\0"; } - #endregion - - #region NCCHHeaderFlags - /// /// Get if the NoCrypto bit is set /// - public static bool PossiblyDecrypted(NCCHHeaderFlags flags) + public bool PossiblyDecrypted(int index) { - if (flags == null) + if (Model.Partitions == null) + return false; + + if (index < 0 || index >= Model.Partitions.Length) + return false; + + var partition = Model.Partitions[index]; + if (partition?.Flags == null) return false; #if NET20 || NET35 - return (flags.BitMasks & BitMasks.NoCrypto) != 0; + return (partition.Flags.BitMasks & BitMasks.NoCrypto) != 0; #else - return flags.BitMasks.HasFlag(BitMasks.NoCrypto); + return partition.Flags.BitMasks.HasFlag(BitMasks.NoCrypto); #endif } #endregion - - #region NCSDHeader - - /// - /// Partition table entry for Executable Content (CXI) - /// - public static PartitionTableEntry? ExecutableContent(NCSDHeader? header) - { - if (header?.PartitionsTable == null) - return null; - - return header.PartitionsTable[0]; - } - - /// - /// Partition table entry for E-Manual (CFA) - /// - public static PartitionTableEntry? EManual(NCSDHeader? header) - { - if (header?.PartitionsTable == null) - return null; - - return header.PartitionsTable[1]; - } - - /// - /// Partition table entry for Download Play Child container (CFA) - /// - public static PartitionTableEntry? DownloadPlayChildContainer(NCSDHeader? header) - { - if (header?.PartitionsTable == null) - return null; - - return header.PartitionsTable[2]; - } - - /// - /// Partition table entry for New3DS Update Data (CFA) - /// - public static PartitionTableEntry? New3DSUpdateData(NCSDHeader? header) - { - if (header?.PartitionsTable == null) - return null; - - return header.PartitionsTable[6]; - } - - /// - /// Partition table entry for Update Data (CFA) - /// - public static PartitionTableEntry? UpdateData(NCSDHeader? header) - { - if (header?.PartitionsTable == null) - return null; - - return header.PartitionsTable[7]; - } - - /// - /// Backup Write Wait Time (The time to wait to write save to backup after the card is recognized (0-255 - /// seconds)).NATIVE_FIRM loads this flag from the gamecard NCSD header starting with 6.0.0-11. - /// - public static byte BackupWriteWaitTime(NCSDHeader? header) - { - if (header?.PartitionFlags == null) - return default; - - return header.PartitionFlags[(int)NCSDFlags.BackupWriteWaitTime]; - } - - /// - /// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (SDK 3.X+) - /// - public static MediaCardDeviceType MediaCardDevice3X(NCSDHeader? header) - { - if (header?.PartitionFlags == null) - return default; - - return (MediaCardDeviceType)header.PartitionFlags[(int)NCSDFlags.MediaCardDevice3X]; - } - - /// - /// Media Platform Index (1 = CTR) - /// - public static MediaPlatformIndex MediaPlatformIndex(NCSDHeader? header) - { - if (header?.PartitionFlags == null) - return default; - - return (MediaPlatformIndex)header.PartitionFlags[(int)NCSDFlags.MediaPlatformIndex]; - } - - /// - /// Media Type Index (0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device) - /// - public static MediaTypeIndex MediaTypeIndex(NCSDHeader? header) - { - if (header?.PartitionFlags == null) - return default; - - return (MediaTypeIndex)header.PartitionFlags[(int)NCSDFlags.MediaTypeIndex]; - } - - /// - /// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6]; - /// - public static uint MediaUnitSize(Cart cart) - { - return MediaUnitSize(cart.Header); - } - - /// - /// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6]; - /// - public static uint MediaUnitSize(NCSDHeader? header) - { - if (header?.PartitionFlags == null) - return default; - - return (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize])); - } - - /// - /// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (Only SDK 2.X) - /// - public static MediaCardDeviceType MediaCardDevice2X(NCSDHeader? header) - { - if (header?.PartitionFlags == null) - return default; - - return (MediaCardDeviceType)header.PartitionFlags[(int)NCSDFlags.MediaCardDevice2X]; - } - - #endregion - - #endregion } } \ No newline at end of file