mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-07-09 02:16:46 +00:00
Add alignment, partition parsing, fix BE
This commit is contained in:
@@ -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
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="fromCdn">Indicates if the ticket is from CDN</param>
|
||||
/// <returns>Filled ticket on success, null on error</returns>
|
||||
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
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="fromCdn">Indicates if the ticket is from CDN</param>
|
||||
/// <returns>Filled title metadata on success, null on error</returns>
|
||||
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;
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace BurnOutSharp.Models.N3DS
|
||||
/// </summary>
|
||||
public TitleMetadata TMDFileData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Content file data
|
||||
/// </summary>
|
||||
public NCCHHeader[] Partitions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Content file data
|
||||
/// </summary>
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace BurnOutSharp.Models.N3DS
|
||||
public ushort TitleVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Content Count
|
||||
/// Content Count (big-endian)
|
||||
/// </summary>
|
||||
public ushort ContentCount;
|
||||
|
||||
|
||||
@@ -224,6 +224,13 @@ namespace BurnOutSharp.Wrappers
|
||||
|
||||
#endregion
|
||||
|
||||
#region Partitions
|
||||
|
||||
/// <inheritdoc cref="Models.N3DS.CIA.Partitions"/>
|
||||
public Models.N3DS.NCCHHeader[] Partitions => _cia.Partitions;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Meta Data
|
||||
|
||||
/// <inheritdoc cref="Models.N3DS.MetaData.TitleIDDependencyList"/>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print NCCH partition header information
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print metadata information
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user