From 5e2185dffdf1a247b2d2a114d4fd6a273212c012 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 9 Jan 2023 10:53:15 -0800 Subject: [PATCH] Add CIA printing --- BurnOutSharp.Builders/N3DS.cs | 8 + BurnOutSharp.Models/N3DS/CIA.cs | 3 +- BurnOutSharp.Wrappers/CIA.cs | 629 ++++++++++++++++++++++++++++++++ 3 files changed, 639 insertions(+), 1 deletion(-) create mode 100644 BurnOutSharp.Wrappers/CIA.cs diff --git a/BurnOutSharp.Builders/N3DS.cs b/BurnOutSharp.Builders/N3DS.cs index b0a560e5..526f4f97 100644 --- a/BurnOutSharp.Builders/N3DS.cs +++ b/BurnOutSharp.Builders/N3DS.cs @@ -285,6 +285,14 @@ namespace BurnOutSharp.Builders #endregion + #region Content File Data + + // If we have content + if (header.ContentSize > 0) + cia.ContentFileData = data.ReadBytes((int)header.ContentSize); + + #endregion + #region Meta Data // If we have a meta data diff --git a/BurnOutSharp.Models/N3DS/CIA.cs b/BurnOutSharp.Models/N3DS/CIA.cs index cdef9b55..484cb746 100644 --- a/BurnOutSharp.Models/N3DS/CIA.cs +++ b/BurnOutSharp.Models/N3DS/CIA.cs @@ -40,7 +40,8 @@ namespace BurnOutSharp.Models.N3DS /// /// Content file data /// - public NCCHHeader[] Partitions { get; set; } + /// TODO: Parse the content file data + public byte[] ContentFileData { get; set; } /// /// Meta file data (Not a necessary component) diff --git a/BurnOutSharp.Wrappers/CIA.cs b/BurnOutSharp.Wrappers/CIA.cs new file mode 100644 index 00000000..c711fe18 --- /dev/null +++ b/BurnOutSharp.Wrappers/CIA.cs @@ -0,0 +1,629 @@ +using System; +using System.IO; + +namespace BurnOutSharp.Wrappers +{ + public class CIA : WrapperBase + { + #region Pass-Through Properties + + #region Header + + /// + public uint HeaderSize => _cia.Header.HeaderSize; + + /// + public ushort Type => _cia.Header.Type; + + /// + public ushort Version => _cia.Header.Version; + + /// + public uint CertificateChainSize => _cia.Header.CertificateChainSize; + + /// + public uint TicketSize => _cia.Header.TicketSize; + + /// + public uint TMDFileSize => _cia.Header.TMDFileSize; + + /// + public uint MetaSize => _cia.Header.MetaSize; + + /// + public ulong ContentSize => _cia.Header.ContentSize; + + /// + public byte[] ContentIndex => _cia.Header.ContentIndex; + + #endregion + + #region Certificate Chain + + /// + public Models.N3DS.Certificate[] CertificateChain => _cia.CertificateChain; + + #endregion + + #region Ticket + + /// + public Models.N3DS.SignatureType T_SignatureType => _cia.Ticket.SignatureType; + + /// + public ushort T_SignatureSize => _cia.Ticket.SignatureSize; + + /// + public byte T_PaddingSize => _cia.Ticket.PaddingSize; + + /// + public byte[] T_Signature => _cia.Ticket.Signature; + + /// + public byte[] T_Padding => _cia.Ticket.Padding; + + /// + public string T_Issuer => _cia.Ticket.Issuer; + + /// + public byte[] T_ECCPublicKey => _cia.Ticket.ECCPublicKey; + + /// + public byte T_Version => _cia.Ticket.Version; + + /// + public byte T_CaCrlVersion => _cia.Ticket.CaCrlVersion; + + /// + public byte T_SignerCrlVersion => _cia.Ticket.SignerCrlVersion; + + /// + public byte[] T_TitleKey => _cia.Ticket.TitleKey; + + /// + public byte T_Reserved1 => _cia.Ticket.Reserved1; + + /// + public ulong T_TicketID => _cia.Ticket.TicketID; + + /// + public uint T_ConsoleID => _cia.Ticket.ConsoleID; + + /// + public ulong T_TitleID => _cia.Ticket.TitleID; + + /// + public byte[] T_Reserved2 => _cia.Ticket.Reserved2; + + /// + public ushort T_TicketTitleVersion => _cia.Ticket.TicketTitleVersion; + + /// + public byte[] T_Reserved3 => _cia.Ticket.Reserved3; + + /// + public byte T_LicenseType => _cia.Ticket.LicenseType; + + /// + public byte T_CommonKeyYIndex => _cia.Ticket.CommonKeyYIndex; + + /// + public byte[] T_Reserved4 => _cia.Ticket.Reserved4; + + /// + public uint T_eShopAccountID => _cia.Ticket.eShopAccountID; + + /// + public byte T_Reserved5 => _cia.Ticket.Reserved5; + + /// + public byte T_Audit => _cia.Ticket.Audit; + + /// + public byte[] T_Reserved6 => _cia.Ticket.Reserved6; + + /// + public uint[] T_Limits => _cia.Ticket.Limits; + + /// + public uint T_ContentIndexSize => _cia.Ticket.ContentIndexSize; + + /// + public byte[] T_ContentIndex => _cia.Ticket.ContentIndex; + + /// + public Models.N3DS.Certificate[] T_CertificateChain => _cia.Ticket.CertificateChain; + + #endregion + + #region Title Metadata + + /// + public Models.N3DS.SignatureType TMD_SignatureType => _cia.TMDFileData.SignatureType; + + /// + public ushort TMD_SignatureSize => _cia.TMDFileData.SignatureSize; + + /// + public byte TMD_PaddingSize => _cia.TMDFileData.PaddingSize; + + /// + public byte[] TMD_Signature => _cia.TMDFileData.Signature; + + /// + public byte[] TMD_Padding1 => _cia.TMDFileData.Padding1; + + /// + public string TMD_Issuer => _cia.TMDFileData.Issuer; + + /// + public byte TMD_Version => _cia.TMDFileData.Version; + + /// + public byte TMD_CaCrlVersion => _cia.TMDFileData.CaCrlVersion; + + /// + public byte TMD_SignerCrlVersion => _cia.TMDFileData.SignerCrlVersion; + + /// + public byte TMD_Reserved1 => _cia.TMDFileData.Reserved1; + + /// + public ulong TMD_SystemVersion => _cia.TMDFileData.SystemVersion; + + /// + public ulong TMD_TitleID => _cia.TMDFileData.TitleID; + + /// + public uint TMD_TitleType => _cia.TMDFileData.TitleType; + + /// + public ushort TMD_GroupID => _cia.TMDFileData.GroupID; + + /// + public uint TMD_SaveDataSize => _cia.TMDFileData.SaveDataSize; + + /// + public uint TMD_SRLPrivateSaveDataSize => _cia.TMDFileData.SRLPrivateSaveDataSize; + + /// + public byte[] TMD_Reserved2 => _cia.TMDFileData.Reserved2; + + /// + public byte TMD_SRLFlag => _cia.TMDFileData.SRLFlag; + + /// + public byte[] TMD_Reserved3 => _cia.TMDFileData.Reserved3; + + /// + public uint TMD_AccessRights => _cia.TMDFileData.AccessRights; + + /// + public ushort TMD_TitleVersion => _cia.TMDFileData.TitleVersion; + + /// + public ushort TMD_ContentCount => _cia.TMDFileData.ContentCount; + + /// + public ushort TMD_BootContent => _cia.TMDFileData.BootContent; + + /// + public byte[] TMD_Padding2 => _cia.TMDFileData.Padding2; + + /// + public byte[] TMD_SHA256HashContentInfoRecords => _cia.TMDFileData.SHA256HashContentInfoRecords; + + /// + public Models.N3DS.ContentInfoRecord[] TMD_ContentInfoRecords => _cia.TMDFileData.ContentInfoRecords; + + /// + public Models.N3DS.ContentChunkRecord[] TMD_ContentChunkRecords => _cia.TMDFileData.ContentChunkRecords; + + /// + public Models.N3DS.Certificate[] TMD_CertificateChain => _cia.TMDFileData.CertificateChain; + + #endregion + + #region Meta Data + + /// + public byte[] MD_TitleIDDependencyList => _cia.MetaData?.TitleIDDependencyList; + + /// + public byte[] MD_Reserved1 => _cia.MetaData?.Reserved1; + + /// + public uint? MD_CoreVersion => _cia.MetaData?.CoreVersion; + + /// + public byte[] MD_Reserved2 => _cia.MetaData?.Reserved2; + + /// + public byte[] MD_IconData => _cia.MetaData?.IconData; + + #endregion + + #endregion + + #region Instance Variables + + /// + /// Internal representation of the cart + /// + private Models.N3DS.CIA _cia; + + #endregion + + #region Constructors + + /// + /// Private constructor + /// + private CIA() { } + + /// + /// Create a CIA archive from a byte array and offset + /// + /// Byte array representing the archive + /// Offset within the array to parse + /// A CIA archive wrapper on success, null on failure + public static CIA Create(byte[] data, int offset) + { + // 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 CIA archive from a Stream + /// + /// Stream representing the archive + /// A CIA archive wrapper on success, null on failure + public static CIA Create(Stream data) + { + // If the data is invalid + if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead) + return null; + + var archive = Builders.N3DS.ParseCIA(data); + if (archive == null) + return null; + + var wrapper = new CIA + { + _cia = archive, + _dataSource = DataSource.Stream, + _streamData = data, + }; + return wrapper; + } + + #endregion + + #region Printing + + /// + public override void Print() + { + Console.WriteLine("CIA Archive Information:"); + Console.WriteLine("-------------------------"); + Console.WriteLine(); + + PrintHeader(); + PrintCertificateChain(); + PrintTicket(); + PrintTitleMetadata(); + // TODO: Print the content file data + PrintMetaData(); + } + + /// + /// Print CIA header information + /// + private void PrintHeader() + { + Console.WriteLine(" CIA Header Information:"); + Console.WriteLine(" -------------------------"); + Console.WriteLine($" Header size: {HeaderSize}"); + Console.WriteLine($" Type: {Type}"); + Console.WriteLine($" Version: {Version}"); + Console.WriteLine($" Certificate chain size: {CertificateChainSize}"); + Console.WriteLine($" Ticket size: {TicketSize}"); + Console.WriteLine($" TMD file size: {TMDFileSize}"); + Console.WriteLine($" Meta size: {MetaSize}"); + Console.WriteLine($" Content size: {ContentSize}"); + Console.WriteLine($" Content index: {BitConverter.ToString(ContentIndex).Replace('-', ' ')}"); + Console.WriteLine(); + } + + /// + /// Print NCCH partition header information + /// + private void PrintCertificateChain() + { + Console.WriteLine(" Certificate Chain Information:"); + Console.WriteLine(" -------------------------"); + if (CertificateChain == null || CertificateChain.Length == 0) + { + Console.WriteLine(" No certificates, expected 3"); + } + else + { + for (int i = 0; i < CertificateChain.Length; i++) + { + var certificate = CertificateChain[i]; + + string certificateName = string.Empty; + switch (i) + { + case 0: certificateName = " (CA)"; break; + case 1: certificateName = " (Ticket)"; break; + case 2: certificateName = " (TMD)"; break; + } + + Console.WriteLine($" Certificate {i}{certificateName}"); + Console.WriteLine($" Signature type: {certificate.SignatureType}"); + Console.WriteLine($" Signature size: {certificate.SignatureSize}"); + Console.WriteLine($" Padding size: {certificate.PaddingSize}"); + Console.WriteLine($" Signature: {BitConverter.ToString(certificate.Signature).Replace('-', ' ')}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.Padding).Replace('-', ' ')}"); + Console.WriteLine($" Issuer: {certificate.Issuer ?? "[NULL]"}"); + Console.WriteLine($" Key type: {certificate.KeyType}"); + Console.WriteLine($" Name: {certificate.Name ?? "[NULL]"}"); + Console.WriteLine($" Expiration time: {certificate.ExpirationTime}"); + switch (certificate.KeyType) + { + case Models.N3DS.PublicKeyType.RSA_4096: + case Models.N3DS.PublicKeyType.RSA_2048: + Console.WriteLine($" Modulus: {BitConverter.ToString(certificate.RSAModulus).Replace('-', ' ')}"); + Console.WriteLine($" Public exponent: {certificate.RSAPublicExponent}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.RSAPadding).Replace('-', ' ')}"); + break; + case Models.N3DS.PublicKeyType.EllipticCurve: + Console.WriteLine($" Public key: {BitConverter.ToString(certificate.ECCPublicKey).Replace('-', ' ')}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.ECCPadding).Replace('-', ' ')}"); + break; + } + } + } + Console.WriteLine(); + } + + /// + /// Print ticket information + /// + private void PrintTicket() + { + Console.WriteLine(" Ticket Information:"); + Console.WriteLine(" -------------------------"); + Console.WriteLine($" Signature type: {T_SignatureType}"); + Console.WriteLine($" Signature size: {T_SignatureSize}"); + Console.WriteLine($" Padding size: {T_PaddingSize}"); + Console.WriteLine($" Signature: {BitConverter.ToString(T_Signature).Replace('-', ' ')}"); + Console.WriteLine($" Padding: {BitConverter.ToString(T_Padding).Replace('-', ' ')}"); + Console.WriteLine($" Issuer: {T_Issuer ?? "[NULL]"}"); + Console.WriteLine($" ECC public key: {BitConverter.ToString(T_ECCPublicKey).Replace('-', ' ')}"); + Console.WriteLine($" Version: {T_Version}"); + Console.WriteLine($" CaCrlVersion: {T_CaCrlVersion}"); + Console.WriteLine($" SignerCrlVersion: {T_SignerCrlVersion}"); + Console.WriteLine($" Title key: {BitConverter.ToString(T_TitleKey).Replace('-', ' ')}"); + Console.WriteLine($" Reserved 1: {T_Reserved1}"); + Console.WriteLine($" Ticket ID: {T_TicketID}"); + Console.WriteLine($" Console ID: {T_ConsoleID}"); + Console.WriteLine($" Title ID {T_TitleID}"); + Console.WriteLine($" Reserved 2: {BitConverter.ToString(T_Reserved2).Replace('-', ' ')}"); + Console.WriteLine($" Ticket title version: {T_TicketTitleVersion}"); + Console.WriteLine($" Reserved 3: {BitConverter.ToString(T_Reserved3).Replace('-', ' ')}"); + Console.WriteLine($" License type: {T_LicenseType}"); + Console.WriteLine($" Common keY index: {T_CommonKeyYIndex}"); + Console.WriteLine($" Reserved 4: {BitConverter.ToString(T_Reserved4).Replace('-', ' ')}"); + Console.WriteLine($" eShop Account ID?: {T_eShopAccountID}"); + Console.WriteLine($" Reserved 5: {T_Reserved5}"); + Console.WriteLine($" Audit: {T_Audit}"); + Console.WriteLine($" Reserved 6: {BitConverter.ToString(T_Reserved6).Replace('-', ' ')}"); + Console.WriteLine($" Limits: {string.Join(", ", T_Limits)}"); + Console.WriteLine($" Content index size: {T_ContentIndexSize}"); + Console.WriteLine($" Content index: {BitConverter.ToString(T_ContentIndex).Replace('-', ' ')}"); + Console.WriteLine(); + + Console.WriteLine(" Ticket Certificate Chain Information:"); + Console.WriteLine(" -------------------------"); + if (T_CertificateChain == null || T_CertificateChain.Length == 0) + { + Console.WriteLine(" No certificates, expected 2"); + } + else + { + for (int i = 0; i < T_CertificateChain.Length; i++) + { + var certificate = T_CertificateChain[i]; + + string certificateName = string.Empty; + switch (i) + { + case 0: certificateName = " (Ticket)"; break; + case 1: certificateName = " (CA)"; break; + } + + Console.WriteLine($" Certificate {i}{certificateName}"); + Console.WriteLine($" Signature type: {certificate.SignatureType}"); + Console.WriteLine($" Signature size: {certificate.SignatureSize}"); + Console.WriteLine($" Padding size: {certificate.PaddingSize}"); + Console.WriteLine($" Signature: {BitConverter.ToString(certificate.Signature).Replace('-', ' ')}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.Padding).Replace('-', ' ')}"); + Console.WriteLine($" Issuer: {certificate.Issuer ?? "[NULL]"}"); + Console.WriteLine($" Key type: {certificate.KeyType}"); + Console.WriteLine($" Name: {certificate.Name ?? "[NULL]"}"); + Console.WriteLine($" Expiration time: {certificate.ExpirationTime}"); + switch (certificate.KeyType) + { + case Models.N3DS.PublicKeyType.RSA_4096: + case Models.N3DS.PublicKeyType.RSA_2048: + Console.WriteLine($" Modulus: {BitConverter.ToString(certificate.RSAModulus).Replace('-', ' ')}"); + Console.WriteLine($" Public exponent: {certificate.RSAPublicExponent}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.RSAPadding).Replace('-', ' ')}"); + break; + case Models.N3DS.PublicKeyType.EllipticCurve: + Console.WriteLine($" Public key: {BitConverter.ToString(certificate.ECCPublicKey).Replace('-', ' ')}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.ECCPadding).Replace('-', ' ')}"); + break; + } + } + } + Console.WriteLine(); + } + + /// + /// Print title metadata information + /// + private void PrintTitleMetadata() + { + Console.WriteLine(" Title Metadata Information:"); + Console.WriteLine(" -------------------------"); + Console.WriteLine($" Signature type: {TMD_SignatureType}"); + Console.WriteLine($" Signature size: {TMD_SignatureSize}"); + Console.WriteLine($" Padding size: {TMD_PaddingSize}"); + Console.WriteLine($" Signature: {BitConverter.ToString(TMD_Signature).Replace('-', ' ')}"); + Console.WriteLine($" Padding 1: {BitConverter.ToString(TMD_Padding1).Replace('-', ' ')}"); + Console.WriteLine($" Issuer: {TMD_Issuer ?? "[NULL]"}"); + Console.WriteLine($" Version: {TMD_Version}"); + Console.WriteLine($" CaCrlVersion: {TMD_CaCrlVersion}"); + Console.WriteLine($" SignerCrlVersion: {TMD_SignerCrlVersion}"); + Console.WriteLine($" Reserved 1: {TMD_Reserved1}"); + Console.WriteLine($" System version: {TMD_SystemVersion}"); + Console.WriteLine($" Title ID: {TMD_TitleID}"); + Console.WriteLine($" Title type: {TMD_TitleType}"); + Console.WriteLine($" Group ID: {TMD_GroupID}"); + Console.WriteLine($" Save data size: {TMD_SaveDataSize}"); + Console.WriteLine($" SRL private save data size: {TMD_SRLPrivateSaveDataSize}"); + Console.WriteLine($" Reserved 2: {BitConverter.ToString(TMD_Reserved2).Replace('-', ' ')}"); + Console.WriteLine($" SRL flag: {TMD_SRLFlag}"); + Console.WriteLine($" Reserved 3: {BitConverter.ToString(TMD_Reserved3).Replace('-', ' ')}"); + Console.WriteLine($" Access rights: {TMD_AccessRights}"); + Console.WriteLine($" Title version: {TMD_TitleVersion}"); + Console.WriteLine($" Content count: {TMD_ContentCount}"); + Console.WriteLine($" Boot content: {TMD_BootContent}"); + Console.WriteLine($" Padding 2: {BitConverter.ToString(TMD_Padding2).Replace('-', ' ')}"); + Console.WriteLine($" SHA-256 hash of the content info records: {BitConverter.ToString(TMD_SHA256HashContentInfoRecords).Replace('-', ' ')}"); + Console.WriteLine(); + + Console.WriteLine(" Ticket Content Info Records Information:"); + Console.WriteLine(" -------------------------"); + if (TMD_ContentInfoRecords == null || TMD_ContentInfoRecords.Length == 0) + { + Console.WriteLine(" No content info records, expected 64"); + } + else + { + for (int i = 0; i < TMD_ContentInfoRecords.Length; i++) + { + var contentInfoRecord = TMD_ContentInfoRecords[i]; + Console.WriteLine($" Content Info Record {i}"); + Console.WriteLine($" Content index offset: {contentInfoRecord.ContentIndexOffset}"); + Console.WriteLine($" Content command count: {contentInfoRecord.ContentCommandCount}"); + Console.WriteLine($" SHA-256 hash of the next {contentInfoRecord.ContentCommandCount} records not hashed: {BitConverter.ToString(contentInfoRecord.UnhashedContentRecordsSHA256Hash).Replace('-', ' ')}"); + } + } + Console.WriteLine(); + + Console.WriteLine(" Ticket Content Chunk Records Information:"); + Console.WriteLine(" -------------------------"); + if (TMD_ContentChunkRecords == null || TMD_ContentChunkRecords.Length == 0) + { + Console.WriteLine($" No content chunk records, expected {TMD_ContentCount}"); + } + else + { + for (int i = 0; i < TMD_ContentChunkRecords.Length; i++) + { + var contentChunkRecord = TMD_ContentChunkRecords[i]; + Console.WriteLine($" Content Chunk Record {i}"); + Console.WriteLine($" Content ID: {contentChunkRecord.ContentId}"); + Console.WriteLine($" Content index: {contentChunkRecord.ContentIndex}"); + Console.WriteLine($" Content type: {contentChunkRecord.ContentType}"); + Console.WriteLine($" Content size: {contentChunkRecord.ContentSize}"); + Console.WriteLine($" SHA-256 hash: {BitConverter.ToString(contentChunkRecord.SHA256Hash).Replace('-', ' ')}"); + } + } + Console.WriteLine(); + + Console.WriteLine(" Ticket Certificate Chain Information:"); + Console.WriteLine(" -------------------------"); + if (TMD_CertificateChain == null || TMD_CertificateChain.Length == 0) + { + Console.WriteLine(" No certificates, expected 2"); + } + else + { + for (int i = 0; i < TMD_CertificateChain.Length; i++) + { + var certificate = TMD_CertificateChain[i]; + + string certificateName = string.Empty; + switch (i) + { + case 0: certificateName = " (TMD)"; break; + case 1: certificateName = " (CA)"; break; + } + + Console.WriteLine($" Certificate {i}{certificateName}"); + Console.WriteLine($" Signature type: {certificate.SignatureType}"); + Console.WriteLine($" Signature size: {certificate.SignatureSize}"); + Console.WriteLine($" Padding size: {certificate.PaddingSize}"); + Console.WriteLine($" Signature: {BitConverter.ToString(certificate.Signature).Replace('-', ' ')}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.Padding).Replace('-', ' ')}"); + Console.WriteLine($" Issuer: {certificate.Issuer ?? "[NULL]"}"); + Console.WriteLine($" Key type: {certificate.KeyType}"); + Console.WriteLine($" Name: {certificate.Name ?? "[NULL]"}"); + Console.WriteLine($" Expiration time: {certificate.ExpirationTime}"); + switch (certificate.KeyType) + { + case Models.N3DS.PublicKeyType.RSA_4096: + case Models.N3DS.PublicKeyType.RSA_2048: + Console.WriteLine($" Modulus: {BitConverter.ToString(certificate.RSAModulus).Replace('-', ' ')}"); + Console.WriteLine($" Public exponent: {certificate.RSAPublicExponent}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.RSAPadding).Replace('-', ' ')}"); + break; + case Models.N3DS.PublicKeyType.EllipticCurve: + Console.WriteLine($" Public key: {BitConverter.ToString(certificate.ECCPublicKey).Replace('-', ' ')}"); + Console.WriteLine($" Padding: {BitConverter.ToString(certificate.ECCPadding).Replace('-', ' ')}"); + break; + } + } + } + Console.WriteLine(); + } + + /// + /// Print metadata information + /// + private void PrintMetaData() + { + Console.WriteLine(" Meta Data Information:"); + Console.WriteLine(" -------------------------"); + if (_cia.MetaData == null || MetaSize == 0) + { + Console.WriteLine(value: " No meta file data"); + } + else + { + Console.WriteLine(value: $" Title ID dependency list: {BitConverter.ToString(MD_TitleIDDependencyList).Replace('-', ' ')}"); + Console.WriteLine($" Reserved 1: {BitConverter.ToString(MD_Reserved1).Replace('-', ' ')}"); + Console.WriteLine($" Core version: {MD_CoreVersion}"); + Console.WriteLine($" Reserved 2: {BitConverter.ToString(MD_Reserved2).Replace('-', ' ')}"); + Console.WriteLine($" Icon data: {BitConverter.ToString(MD_IconData).Replace('-', ' ')}"); + } + Console.WriteLine(); + } + + #endregion + } +} \ No newline at end of file