diff --git a/BurnOutSharp.Builders/N3DS.cs b/BurnOutSharp.Builders/N3DS.cs
index c134c1c2..ce0188db 100644
--- a/BurnOutSharp.Builders/N3DS.cs
+++ b/BurnOutSharp.Builders/N3DS.cs
@@ -1,3 +1,4 @@
+using System;
using System.IO;
using System.Text;
using BurnOutSharp.Models.N3DS;
@@ -105,7 +106,33 @@ namespace BurnOutSharp.Builders
#endregion
- // TODO: Parse partition extended headers (decrypted only)
+ #region Extended Headers
+
+ // Create the extended header table
+ cart.NCCHExtendedHeaders = new NCCHExtendedHeader[8];
+
+ // Iterate and build the extended headers
+ for (int i = 0; i < 8; i++)
+ {
+ // If we have an encrypted or invalid partition
+ if (cart.Partitions[i].MagicID != NCCHMagicNumber)
+ continue;
+
+ // Get the extended header offset
+ long mediaUnitSize = (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
+ long offset = (cart.Header.PartitionsTable[i].Offset * mediaUnitSize) + 0x200;
+ if (offset < 0 || offset >= data.Length)
+ continue;
+
+ // Seek to the extended header
+ data.Seek(offset, SeekOrigin.Begin);
+
+ // Parse the extended header
+ cart.NCCHExtendedHeaders[i] = ParseNCCHExtendedHeader(data);
+ }
+
+ #endregion
+
// TODO: Parse ExeFS file entries (decrypted only)
// TODO: Parse ExeFS filename table (decrypted only)
@@ -349,6 +376,209 @@ namespace BurnOutSharp.Builders
return testData;
}
+ ///
+ /// Parse a Stream into an NCCH extended header
+ ///
+ /// Stream to parse
+ /// Filled NCCH extended header on success, null on error
+ private static NCCHExtendedHeader ParseNCCHExtendedHeader(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ NCCHExtendedHeader extendedHeader = new NCCHExtendedHeader();
+
+ extendedHeader.SCI = ParseSystemControlInfo(data);
+ if (extendedHeader.SCI == null)
+ return null;
+
+ extendedHeader.ACI = ParseAccessControlInfo(data);
+ if (extendedHeader.ACI == null)
+ return null;
+
+ extendedHeader.AccessDescSignature = data.ReadBytes(0x100);
+ extendedHeader.NCCHHDRPublicKey = data.ReadBytes(0x100);
+
+ extendedHeader.ACIForLimitations = ParseAccessControlInfo(data);
+ if (extendedHeader.ACI == null)
+ return null;
+
+ return extendedHeader;
+ }
+
+ ///
+ /// Parse a Stream into a system control info
+ ///
+ /// Stream to parse
+ /// Filled system control info on success, null on error
+ private static SystemControlInfo ParseSystemControlInfo(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ SystemControlInfo systemControlInfo = new SystemControlInfo();
+
+ byte[] applicationTitle = data.ReadBytes(8);
+ systemControlInfo.ApplicationTitle = Encoding.ASCII.GetString(applicationTitle).TrimEnd('\0');
+ systemControlInfo.Reserved1 = data.ReadBytes(5);
+ systemControlInfo.Flag = data.ReadByteValue();
+ systemControlInfo.RemasterVersion = data.ReadUInt16();
+ systemControlInfo.TextCodeSetInfo = ParseCodeSetInfo(data);
+ systemControlInfo.StackSize = data.ReadUInt32();
+ systemControlInfo.ReadOnlyCodeSetInfo = ParseCodeSetInfo(data);
+ systemControlInfo.Reserved2 = data.ReadBytes(4);
+ systemControlInfo.DataCodeSetInfo = ParseCodeSetInfo(data);
+ systemControlInfo.BSSSize = data.ReadUInt32();
+ systemControlInfo.DependencyModuleList = new ulong[48];
+ for (int i = 0; i < 48; i++)
+ {
+ systemControlInfo.DependencyModuleList[i] = data.ReadUInt64();
+ }
+ systemControlInfo.SystemInfo = ParseSystemInfo(data);
+
+ return systemControlInfo;
+ }
+
+ ///
+ /// Parse a Stream into a code set info
+ ///
+ /// Stream to parse
+ /// Filled code set info on success, null on error
+ private static CodeSetInfo ParseCodeSetInfo(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ CodeSetInfo codeSetInfo = new CodeSetInfo();
+
+ codeSetInfo.Address = data.ReadUInt32();
+ codeSetInfo.PhysicalRegionSizeInPages = data.ReadUInt32();
+ codeSetInfo.SizeInBytes = data.ReadUInt32();
+
+ return codeSetInfo;
+ }
+
+ ///
+ /// Parse a Stream into a system info
+ ///
+ /// Stream to parse
+ /// Filled system info on success, null on error
+ private static SystemInfo ParseSystemInfo(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ SystemInfo systemInfo = new SystemInfo();
+
+ systemInfo.SaveDataSize = data.ReadUInt64();
+ systemInfo.JumpID = data.ReadUInt64();
+ systemInfo.Reserved = data.ReadBytes(0x30);
+
+ return systemInfo;
+ }
+
+ ///
+ /// Parse a Stream into an access control info
+ ///
+ /// Stream to parse
+ /// Filled access control info on success, null on error
+ private static AccessControlInfo ParseAccessControlInfo(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ AccessControlInfo accessControlInfo = new AccessControlInfo();
+
+ accessControlInfo.ARM11LocalSystemCapabilities = ParseARM11LocalSystemCapabilities(data);
+ accessControlInfo.ARM11KernelCapabilities = ParseARM11KernelCapabilities(data);
+ accessControlInfo.ARM9AccessControl = ParseARM9AccessControl(data);
+
+ return accessControlInfo;
+ }
+
+ ///
+ /// Parse a Stream into an ARM11 local system capabilities
+ ///
+ /// Stream to parse
+ /// Filled ARM11 local system capabilities on success, null on error
+ private static ARM11LocalSystemCapabilities ParseARM11LocalSystemCapabilities(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ ARM11LocalSystemCapabilities arm11LocalSystemCapabilities = new ARM11LocalSystemCapabilities();
+
+ arm11LocalSystemCapabilities.ProgramID = data.ReadUInt64();
+ arm11LocalSystemCapabilities.CoreVersion = data.ReadUInt32();
+ arm11LocalSystemCapabilities.Flag1 = (ARM11LSCFlag1)data.ReadByteValue();
+ arm11LocalSystemCapabilities.Flag2 = (ARM11LSCFlag2)data.ReadByteValue();
+ arm11LocalSystemCapabilities.Flag0 = (ARM11LSCFlag0)data.ReadByteValue();
+ arm11LocalSystemCapabilities.Priority = data.ReadByteValue();
+ arm11LocalSystemCapabilities.ResourceLimitDescriptors = new ushort[16];
+ for (int i = 0; i < 16; i++)
+ {
+ arm11LocalSystemCapabilities.ResourceLimitDescriptors[i] = data.ReadUInt16();
+ }
+ arm11LocalSystemCapabilities.StorageInfo = ParseStorageInfo(data);
+ arm11LocalSystemCapabilities.ServiceAccessControl = new ulong[32];
+ for (int i = 0; i < 32; i++)
+ {
+ arm11LocalSystemCapabilities.ServiceAccessControl[i] = data.ReadUInt64();
+ }
+ arm11LocalSystemCapabilities.ExtendedServiceAccessControl = new ulong[2];
+ for (int i = 0; i < 2; i++)
+ {
+ arm11LocalSystemCapabilities.ExtendedServiceAccessControl[i] = data.ReadUInt64();
+ }
+ arm11LocalSystemCapabilities.Reserved = data.ReadBytes(0x0F);
+ arm11LocalSystemCapabilities.ResourceLimitCategory = (ResourceLimitCategory)data.ReadByteValue();
+
+ return arm11LocalSystemCapabilities;
+ }
+
+ ///
+ /// Parse a Stream into a storage info
+ ///
+ /// Stream to parse
+ /// Filled storage info on success, null on error
+ private static StorageInfo ParseStorageInfo(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ StorageInfo storageInfo = new StorageInfo();
+
+ storageInfo.ExtdataID = data.ReadUInt64();
+ storageInfo.SystemSavedataIDs = data.ReadBytes(8);
+ storageInfo.StorageAccessibleUniqueIDs = data.ReadBytes(8);
+ storageInfo.FileSystemAccessInfo = data.ReadBytes(7);
+ storageInfo.OtherAttributes = (StorageInfoOtherAttributes)data.ReadByteValue();
+
+ return storageInfo;
+ }
+
+ ///
+ /// Parse a Stream into an ARM11 kernel capabilities
+ ///
+ /// Stream to parse
+ /// Filled ARM11 kernel capabilities on success, null on error
+ private static ARM11KernelCapabilities ParseARM11KernelCapabilities(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ ARM11KernelCapabilities arm11KernelCapabilities = new ARM11KernelCapabilities();
+
+ arm11KernelCapabilities.Descriptors = new uint[28];
+ for (int i = 0; i < 28; i++)
+ {
+ arm11KernelCapabilities.Descriptors[i] = data.ReadUInt32();
+ }
+ arm11KernelCapabilities.Reserved = data.ReadBytes(0x10);
+
+ return arm11KernelCapabilities;
+ }
+
+ ///
+ /// Parse a Stream into an ARM11 access control
+ ///
+ /// Stream to parse
+ /// Filled ARM11 access control on success, null on error
+ private static ARM9AccessControl ParseARM9AccessControl(Stream data)
+ {
+ // TODO: Use marshalling here instead of building
+ ARM9AccessControl arm9AccessControl = new ARM9AccessControl();
+
+ arm9AccessControl.Descriptors = data.ReadBytes(15);
+ arm9AccessControl.DescriptorVersion = data.ReadByteValue();
+
+ return arm9AccessControl;
+ }
+
#endregion
}
}
diff --git a/BurnOutSharp.Models/N3DS/ARM11KernelCapabilities.cs b/BurnOutSharp.Models/N3DS/ARM11KernelCapabilities.cs
index 94d03774..78bb3814 100644
--- a/BurnOutSharp.Models/N3DS/ARM11KernelCapabilities.cs
+++ b/BurnOutSharp.Models/N3DS/ARM11KernelCapabilities.cs
@@ -33,7 +33,8 @@
/// 12 Special memory
/// 13 Process has access to CPU core 2 (New3DS only)
///
- public byte[][] Descriptors;
+ /// TODO: Make enum for flag values
+ public uint[] Descriptors;
///
/// Reserved
diff --git a/BurnOutSharp.Models/N3DS/ARM11LocalSystemCapabilities.cs b/BurnOutSharp.Models/N3DS/ARM11LocalSystemCapabilities.cs
index 0d21a859..7cda9cfd 100644
--- a/BurnOutSharp.Models/N3DS/ARM11LocalSystemCapabilities.cs
+++ b/BurnOutSharp.Models/N3DS/ARM11LocalSystemCapabilities.cs
@@ -6,7 +6,7 @@
///
/// Program ID
///
- public byte[] ProgramID;
+ public ulong ProgramID;
///
/// Core version (The Title ID low of the required FIRM)
@@ -36,7 +36,7 @@
///
/// Resource limit descriptors. The first byte here controls the maximum allowed CpuTime.
///
- public byte[][] ResourceLimitDescriptors;
+ public ushort[] ResourceLimitDescriptors;
///
/// Storage info
@@ -46,12 +46,12 @@
///
/// Service access control
///
- public byte[][] ServiceAccessControl;
+ public ulong[] ServiceAccessControl;
///
/// Extended service access control, support for this was implemented with 9.3.0-X.
///
- public byte[][] ExtendedServiceAccessControl;
+ public ulong[] ExtendedServiceAccessControl;
///
/// Reserved
diff --git a/BurnOutSharp.Models/N3DS/ARM9AccessControl.cs b/BurnOutSharp.Models/N3DS/ARM9AccessControl.cs
index 9bb45594..8cefc0ea 100644
--- a/BurnOutSharp.Models/N3DS/ARM9AccessControl.cs
+++ b/BurnOutSharp.Models/N3DS/ARM9AccessControl.cs
@@ -6,7 +6,7 @@
///
/// Descriptors
///
- public ARM9AccessControlDescriptors[] Descriptors;
+ public byte[] Descriptors;
///
/// ARM9 Descriptor Version. Originally this value had to be ≥ 2.
diff --git a/BurnOutSharp.Models/N3DS/Cart.cs b/BurnOutSharp.Models/N3DS/Cart.cs
index 98496919..57c9752f 100644
--- a/BurnOutSharp.Models/N3DS/Cart.cs
+++ b/BurnOutSharp.Models/N3DS/Cart.cs
@@ -24,5 +24,10 @@ namespace BurnOutSharp.Models.N3DS
/// NCCH partitions
///
public NCCHHeader[] Partitions { get; set; }
+
+ ///
+ /// NCCH extended headers
+ ///
+ public NCCHExtendedHeader[] NCCHExtendedHeaders { get; set; }
}
}
\ No newline at end of file
diff --git a/BurnOutSharp.Models/N3DS/CodeSetInfo.cs b/BurnOutSharp.Models/N3DS/CodeSetInfo.cs
index a76db265..4bf8d93d 100644
--- a/BurnOutSharp.Models/N3DS/CodeSetInfo.cs
+++ b/BurnOutSharp.Models/N3DS/CodeSetInfo.cs
@@ -6,7 +6,7 @@
///
/// Address
///
- public byte[] Address;
+ public uint Address;
///
/// Physical region size (in page-multiples)
diff --git a/BurnOutSharp.Models/N3DS/Enums.cs b/BurnOutSharp.Models/N3DS/Enums.cs
index 94ddb9f4..1d4f4580 100644
--- a/BurnOutSharp.Models/N3DS/Enums.cs
+++ b/BurnOutSharp.Models/N3DS/Enums.cs
@@ -2,6 +2,7 @@
namespace BurnOutSharp.Models.N3DS
{
+ // TODO: Fix this, I don't think it's correct
[Flags]
public enum ARM9AccessControlDescriptors : byte
{
@@ -14,7 +15,7 @@ namespace BurnOutSharp.Models.N3DS
CreateSeed = 0x20,
UseCardSPI = 0x40,
SDApplication = 0x80,
- MoundSdmcWriteAccess = 0xF0,
+ MountSdmcWriteAccess = 0xF0,
}
[Flags]
diff --git a/BurnOutSharp.Models/N3DS/CXIExtendedHeader.cs b/BurnOutSharp.Models/N3DS/NCCHExtendedHeader.cs
similarity index 96%
rename from BurnOutSharp.Models/N3DS/CXIExtendedHeader.cs
rename to BurnOutSharp.Models/N3DS/NCCHExtendedHeader.cs
index 93a18121..a3581bf8 100644
--- a/BurnOutSharp.Models/N3DS/CXIExtendedHeader.cs
+++ b/BurnOutSharp.Models/N3DS/NCCHExtendedHeader.cs
@@ -6,7 +6,7 @@
/// - A signed copy of NCCH HDR public key, and exheader ACI. This version of the ACI is used as limitation to the actual ACI.
///
///
- public sealed class CXIExtendedHeader
+ public sealed class NCCHExtendedHeader
{
///
/// SCI
diff --git a/BurnOutSharp.Models/N3DS/StorageInfo.cs b/BurnOutSharp.Models/N3DS/StorageInfo.cs
index d5a1158c..682b128d 100644
--- a/BurnOutSharp.Models/N3DS/StorageInfo.cs
+++ b/BurnOutSharp.Models/N3DS/StorageInfo.cs
@@ -9,7 +9,7 @@
///
/// Extdata ID
///
- public byte[] ExtdataID;
+ public ulong ExtdataID;
///
/// System savedata IDs
@@ -24,7 +24,9 @@
///
/// Filesystem access info
///
- public byte[] FilesystemAccessInfo;
+ /// TODO: Create enum for the flag values
+ /// TODO: Combine with "other attributes"
+ public byte[] FileSystemAccessInfo;
///
/// Other attributes
diff --git a/BurnOutSharp.Models/N3DS/SystemControlInfo.cs b/BurnOutSharp.Models/N3DS/SystemControlInfo.cs
index 339960cc..e2d630d9 100644
--- a/BurnOutSharp.Models/N3DS/SystemControlInfo.cs
+++ b/BurnOutSharp.Models/N3DS/SystemControlInfo.cs
@@ -6,7 +6,7 @@
///
/// Application title (default is "CtrApp")
///
- public char[] ApplicationTitle;
+ public string ApplicationTitle;
///
/// Reserved
@@ -21,12 +21,12 @@
///
/// Remaster version
///
- public byte[] RemasterVersion;
+ public ushort RemasterVersion;
///
/// Text code set info
///
- public CodeSetInfo TextCodesetInfo;
+ public CodeSetInfo TextCodeSetInfo;
///
/// Stack size
@@ -56,7 +56,7 @@
///
/// Dependency module (program ID) list
///
- public byte[][] DependencyModuleList;
+ public ulong[] DependencyModuleList;
///
/// SystemInfo
diff --git a/BurnOutSharp.Models/N3DS/SystemInfo.cs b/BurnOutSharp.Models/N3DS/SystemInfo.cs
index 8a7abae9..2001a707 100644
--- a/BurnOutSharp.Models/N3DS/SystemInfo.cs
+++ b/BurnOutSharp.Models/N3DS/SystemInfo.cs
@@ -11,7 +11,7 @@
///
/// Jump ID
///
- public byte[] JumpID;
+ public ulong JumpID;
///
/// Reserved