diff --git a/BurnOutSharp.Builders/N3DS.cs b/BurnOutSharp.Builders/N3DS.cs
index 526f4f97..e12d625a 100644
--- a/BurnOutSharp.Builders/N3DS.cs
+++ b/BurnOutSharp.Builders/N3DS.cs
@@ -244,6 +244,12 @@ namespace BurnOutSharp.Builders
#endregion
+ // Align to 64-byte boundary, if needed
+ while (data.Position < data.Length - 1 && data.Position % 64 != 0)
+ {
+ _ = data.ReadByteValue();
+ }
+
#region Certificate Chain
// Create the certificate chain
@@ -261,6 +267,12 @@ namespace BurnOutSharp.Builders
#endregion
+ // Align to 64-byte boundary, if needed
+ while (data.Position < data.Length - 1 && data.Position % 64 != 0)
+ {
+ _ = data.ReadByteValue();
+ }
+
#region Ticket
// Try to parse the ticket
@@ -273,6 +285,12 @@ namespace BurnOutSharp.Builders
#endregion
+ // Align to 64-byte boundary, if needed
+ while (data.Position < data.Length - 1 && data.Position % 64 != 0)
+ {
+ _ = data.ReadByteValue();
+ }
+
#region Title Metadata
// Try to parse the title metadata
@@ -285,14 +303,31 @@ namespace BurnOutSharp.Builders
#endregion
+ // Align to 64-byte boundary, if needed
+ while (data.Position < data.Length - 1 && data.Position % 64 != 0)
+ {
+ _ = data.ReadByteValue();
+ }
+
#region Content File Data
- // If we have content
- if (header.ContentSize > 0)
- cia.ContentFileData = data.ReadBytes((int)header.ContentSize);
+ // Create the partition table
+ cia.Partitions = new NCCHHeader[8];
+
+ // Iterate and build the partitions
+ for (int i = 0; i < 8; i++)
+ {
+ cia.Partitions[i] = ParseNCCHHeader(data);
+ }
#endregion
+ // Align to 64-byte boundary, if needed
+ while (data.Position < data.Length - 1 && data.Position % 64 != 0)
+ {
+ _ = data.ReadByteValue();
+ }
+
#region Meta Data
// If we have a meta data
@@ -933,8 +968,9 @@ namespace BurnOutSharp.Builders
/// Parse a Stream into a ticket
///
/// Stream to parse
+ /// Indicates if the ticket is from CDN
/// Filled ticket on success, null on error
- private static Ticket ParseTicket(Stream data)
+ private static Ticket ParseTicket(Stream data, bool fromCdn = false)
{
// TODO: Use marshalling here instead of building
Ticket ticket = new Ticket();
@@ -1011,14 +1047,19 @@ namespace BurnOutSharp.Builders
data.Seek(-8, SeekOrigin.Current);
ticket.ContentIndex = data.ReadBytes((int)ticket.ContentIndexSize);
- ticket.CertificateChain = new Certificate[2];
- for (int i = 0; i < 2; i++)
- {
- var certificate = ParseCertificate(data);
- if (certificate == null)
- return null;
- ticket.CertificateChain[i] = certificate;
+ // Certificates only exist in standalone CETK files
+ if (fromCdn)
+ {
+ ticket.CertificateChain = new Certificate[2];
+ for (int i = 0; i < 2; i++)
+ {
+ var certificate = ParseCertificate(data);
+ if (certificate == null)
+ return null;
+
+ ticket.CertificateChain[i] = certificate;
+ }
}
return ticket;
@@ -1028,8 +1069,9 @@ namespace BurnOutSharp.Builders
/// Parse a Stream into a title metadata
///
/// Stream to parse
+ /// Indicates if the ticket is from CDN
/// Filled title metadata on success, null on error
- private static TitleMetadata ParseTitleMetadata(Stream data)
+ private static TitleMetadata ParseTitleMetadata(Stream data, bool fromCdn = false)
{
// TODO: Use marshalling here instead of building
TitleMetadata titleMetadata = new TitleMetadata();
@@ -1084,7 +1126,12 @@ namespace BurnOutSharp.Builders
titleMetadata.Reserved3 = data.ReadBytes(0x31);
titleMetadata.AccessRights = data.ReadUInt32();
titleMetadata.TitleVersion = data.ReadUInt16();
- titleMetadata.ContentCount = data.ReadUInt16();
+
+ // Read the content count (big-endian)
+ byte[] contentCount = data.ReadBytes(2);
+ Array.Reverse(contentCount);
+ titleMetadata.ContentCount = BitConverter.ToUInt16(contentCount, 0);
+
titleMetadata.BootContent = data.ReadUInt16();
titleMetadata.Padding2 = data.ReadBytes(2);
titleMetadata.SHA256HashContentInfoRecords = data.ReadBytes(0x20);
@@ -1098,14 +1145,19 @@ namespace BurnOutSharp.Builders
{
titleMetadata.ContentChunkRecords[i] = ParseContentChunkRecord(data);
}
- titleMetadata.CertificateChain = new Certificate[2];
- for (int i = 0; i < 2; i++)
- {
- var certificate = ParseCertificate(data);
- if (certificate == null)
- return null;
- titleMetadata.CertificateChain[i] = certificate;
+ // Certificates only exist in standalone TMD files
+ if (fromCdn)
+ {
+ titleMetadata.CertificateChain = new Certificate[2];
+ for (int i = 0; i < 2; i++)
+ {
+ var certificate = ParseCertificate(data);
+ if (certificate == null)
+ return null;
+
+ titleMetadata.CertificateChain[i] = certificate;
+ }
}
return titleMetadata;
diff --git a/BurnOutSharp.Models/N3DS/CIA.cs b/BurnOutSharp.Models/N3DS/CIA.cs
index 484cb746..b1983e68 100644
--- a/BurnOutSharp.Models/N3DS/CIA.cs
+++ b/BurnOutSharp.Models/N3DS/CIA.cs
@@ -37,6 +37,11 @@ namespace BurnOutSharp.Models.N3DS
///
public TitleMetadata TMDFileData { get; set; }
+ ///
+ /// Content file data
+ ///
+ public NCCHHeader[] Partitions { get; set; }
+
///
/// Content file data
///
diff --git a/BurnOutSharp.Models/N3DS/TitleMetadata.cs b/BurnOutSharp.Models/N3DS/TitleMetadata.cs
index cb56cc0c..31d8956a 100644
--- a/BurnOutSharp.Models/N3DS/TitleMetadata.cs
+++ b/BurnOutSharp.Models/N3DS/TitleMetadata.cs
@@ -114,7 +114,7 @@ namespace BurnOutSharp.Models.N3DS
public ushort TitleVersion;
///
- /// Content Count
+ /// Content Count (big-endian)
///
public ushort ContentCount;
diff --git a/BurnOutSharp.Wrappers/CIA.cs b/BurnOutSharp.Wrappers/CIA.cs
index c711fe18..b278769f 100644
--- a/BurnOutSharp.Wrappers/CIA.cs
+++ b/BurnOutSharp.Wrappers/CIA.cs
@@ -224,6 +224,13 @@ namespace BurnOutSharp.Wrappers
#endregion
+ #region Partitions
+
+ ///
+ public Models.N3DS.NCCHHeader[] Partitions => _cia.Partitions;
+
+ #endregion
+
#region Meta Data
///
@@ -321,7 +328,7 @@ namespace BurnOutSharp.Wrappers
PrintCertificateChain();
PrintTicket();
PrintTitleMetadata();
- // TODO: Print the content file data
+ PrintPartitions();
PrintMetaData();
}
@@ -602,6 +609,76 @@ namespace BurnOutSharp.Wrappers
Console.WriteLine();
}
+ ///
+ /// Print NCCH partition header information
+ ///
+ private void PrintPartitions()
+ {
+ Console.WriteLine(" NCCH Partition Header Information:");
+ Console.WriteLine(" -------------------------");
+ if (Partitions == null || Partitions.Length == 0)
+ {
+ Console.WriteLine(" No NCCH partition headers");
+ }
+ else
+ {
+ for (int i = 0; i < Partitions.Length; i++)
+ {
+ var partitionHeader = Partitions[i];
+ Console.WriteLine($" NCCH Partition Header {i}");
+ if (partitionHeader.MagicID == string.Empty)
+ {
+ Console.WriteLine($" Empty partition, no data can be parsed");
+ }
+ else if (partitionHeader.MagicID != Models.N3DS.Constants.NCCHMagicNumber)
+ {
+ Console.WriteLine($" Unrecognized partition data, no data can be parsed");
+ }
+ else
+ {
+ Console.WriteLine($" RSA-2048 SHA-256 signature: {BitConverter.ToString(partitionHeader.RSA2048Signature).Replace('-', ' ')}");
+ Console.WriteLine($" Magic ID: {partitionHeader.MagicID}");
+ Console.WriteLine($" Content size in media units: {partitionHeader.ContentSizeInMediaUnits}");
+ Console.WriteLine($" Partition ID: {partitionHeader.PartitionId}");
+ Console.WriteLine($" Maker code: {partitionHeader.MakerCode}");
+ Console.WriteLine($" Version: {partitionHeader.Version}");
+ Console.WriteLine($" Verification hash: {partitionHeader.VerificationHash}");
+ Console.WriteLine($" Program ID: {BitConverter.ToString(partitionHeader.ProgramId).Replace('-', ' ')}");
+ Console.WriteLine($" Reserved 1: {BitConverter.ToString(partitionHeader.Reserved1).Replace('-', ' ')}");
+ Console.WriteLine($" Logo region SHA-256 hash: {BitConverter.ToString(partitionHeader.LogoRegionHash).Replace('-', ' ')}");
+ Console.WriteLine($" Product code: {partitionHeader.ProductCode}");
+ Console.WriteLine($" Extended header SHA-256 hash: {BitConverter.ToString(partitionHeader.ExtendedHeaderHash).Replace('-', ' ')}");
+ Console.WriteLine($" Extended header size in bytes: {partitionHeader.ExtendedHeaderSizeInBytes}");
+ Console.WriteLine($" Reserved 2: {BitConverter.ToString(partitionHeader.Reserved2).Replace('-', ' ')}");
+ Console.WriteLine(" Flags:");
+ Console.WriteLine($" Reserved 0: {partitionHeader.Flags.Reserved0}");
+ Console.WriteLine($" Reserved 1: {partitionHeader.Flags.Reserved1}");
+ Console.WriteLine($" Reserved 2: {partitionHeader.Flags.Reserved2}");
+ Console.WriteLine($" Crypto method: {partitionHeader.Flags.CryptoMethod}");
+ Console.WriteLine($" Content platform: {partitionHeader.Flags.ContentPlatform}");
+ Console.WriteLine($" Content type: {partitionHeader.Flags.MediaPlatformIndex}");
+ Console.WriteLine($" Content unit size: {partitionHeader.Flags.ContentUnitSize}");
+ Console.WriteLine($" Bitmasks: {partitionHeader.Flags.BitMasks}");
+ Console.WriteLine($" Plain region offset, in media units: {partitionHeader.PlainRegionOffsetInMediaUnits}");
+ Console.WriteLine($" Plain region size, in media units: {partitionHeader.PlainRegionSizeInMediaUnits}");
+ Console.WriteLine($" Logo region offset, in media units: {partitionHeader.LogoRegionOffsetInMediaUnits}");
+ Console.WriteLine($" Logo region size, in media units: {partitionHeader.LogoRegionSizeInMediaUnits}");
+ Console.WriteLine($" ExeFS offset, in media units: {partitionHeader.ExeFSOffsetInMediaUnits}");
+ Console.WriteLine($" ExeFS size, in media units: {partitionHeader.ExeFSSizeInMediaUnits}");
+ Console.WriteLine($" ExeFS hash region size, in media units: {partitionHeader.ExeFSHashRegionSizeInMediaUnits}");
+ Console.WriteLine($" Reserved 3: {BitConverter.ToString(partitionHeader.Reserved3).Replace('-', ' ')}");
+ Console.WriteLine($" RomFS offset, in media units: {partitionHeader.RomFSOffsetInMediaUnits}");
+ Console.WriteLine($" RomFS size, in media units: {partitionHeader.RomFSSizeInMediaUnits}");
+ Console.WriteLine($" RomFS hash region size, in media units: {partitionHeader.RomFSHashRegionSizeInMediaUnits}");
+ Console.WriteLine($" Reserved 4: {BitConverter.ToString(partitionHeader.Reserved4).Replace('-', ' ')}");
+ Console.WriteLine($" ExeFS superblock SHA-256 hash: {BitConverter.ToString(partitionHeader.ExeFSSuperblockHash).Replace('-', ' ')}");
+ Console.WriteLine($" RomFS superblock SHA-256 hash: {BitConverter.ToString(partitionHeader.RomFSSuperblockHash).Replace('-', ' ')}");
+ }
+ }
+ }
+ Console.WriteLine();
+ }
+
///
/// Print metadata information
///