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