From 9bebf955991dd338702e94e8f573de4eb02e2bf1 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Tue, 23 Apr 2024 20:09:39 -0400 Subject: [PATCH] Add layouts for some N3DS models --- N3DS/ARM11KernelCapabilities.cs | 13 +++-- N3DS/ARM11LocalSystemCapabilities.cs | 41 +++++++++----- N3DS/ARM9AccessControl.cs | 11 ++-- N3DS/AccessControlInfo.cs | 11 ++-- N3DS/CIAHeader.cs | 23 ++++---- N3DS/CardInfoHeader.cs | 35 ++++++++---- N3DS/CodeSetInfo.cs | 11 ++-- N3DS/ContentChunkRecord.cs | 15 ++++-- N3DS/ContentInfoRecord.cs | 11 ++-- N3DS/DevelopmentCardInfoHeader.cs | 19 +++++-- N3DS/ExeFSFileHeader.cs | 18 +++---- N3DS/ExeFSHeader.cs | 1 + N3DS/InitialData.cs | 25 ++++++--- N3DS/MetaData.cs | 21 ++++++-- N3DS/NCCHExtendedHeader.cs | 21 +++++--- N3DS/NCCHHeader.cs | 81 +++++++++++++++++----------- N3DS/NCCHHeaderFlags.cs | 27 ++++++---- N3DS/PartitionTableEntry.cs | 9 ++-- N3DS/RomFSHeader.cs | 41 +++++++------- N3DS/StorageInfo.cs | 22 +++++--- N3DS/SystemControlInfo.cs | 35 +++++++----- N3DS/SystemInfo.cs | 13 +++-- N3DS/TestData.cs | 41 ++++++++++---- 23 files changed, 364 insertions(+), 181 deletions(-) diff --git a/N3DS/ARM11KernelCapabilities.cs b/N3DS/ARM11KernelCapabilities.cs index 75fbf92..6673a1a 100644 --- a/N3DS/ARM11KernelCapabilities.cs +++ b/N3DS/ARM11KernelCapabilities.cs @@ -1,9 +1,12 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// /// The kernel capability descriptors are passed to svcCreateProcess. /// /// + [StructLayout(LayoutKind.Sequential)] public sealed class ARM11KernelCapabilities { /// @@ -34,11 +37,15 @@ /// 13 Process has access to CPU core 2 (New3DS only) /// /// TODO: Make enum for flag values - public uint[]? Descriptors { get; set; } + /// 28 entries + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] + public uint[]? Descriptors; /// /// Reserved /// - public byte[]? Reserved { get; set; } + /// 0x10 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] + public byte[]? Reserved; } } diff --git a/N3DS/ARM11LocalSystemCapabilities.cs b/N3DS/ARM11LocalSystemCapabilities.cs index 52ff297..270f04b 100644 --- a/N3DS/ARM11LocalSystemCapabilities.cs +++ b/N3DS/ARM11LocalSystemCapabilities.cs @@ -1,66 +1,81 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class ARM11LocalSystemCapabilities { /// /// Program ID /// - public ulong ProgramID { get; set; } + public ulong ProgramID; /// /// Core version (The Title ID low of the required FIRM) /// - public uint CoreVersion { get; set; } + public uint CoreVersion; /// /// Flag1 (implemented starting from 8.0.0-18). /// - public ARM11LSCFlag1 Flag1 { get; set; } + [MarshalAs(UnmanagedType.U1)] + public ARM11LSCFlag1 Flag1; /// /// Flag2 (implemented starting from 8.0.0-18). /// - public ARM11LSCFlag2 Flag2 { get; set; } + [MarshalAs(UnmanagedType.U1)] + public ARM11LSCFlag2 Flag2; /// /// Flag0 /// - public ARM11LSCFlag0 Flag0 { get; set; } + [MarshalAs(UnmanagedType.U1)] + public ARM11LSCFlag0 Flag0; /// /// Priority /// - public byte Priority { get; set; } + public byte Priority; /// /// Resource limit descriptors. The first byte here controls the maximum allowed CpuTime. /// - public ushort[]? ResourceLimitDescriptors { get; set; } + /// 16 entries + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public ushort[]? ResourceLimitDescriptors; /// /// Storage info /// - public StorageInfo? StorageInfo { get; set; } + public StorageInfo? StorageInfo; /// /// Service access control /// - public ulong[]? ServiceAccessControl { get; set; } + /// 32 entries + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public ulong[]? ServiceAccessControl; /// /// Extended service access control, support for this was implemented with 9.3.0-X. /// - public ulong[]? ExtendedServiceAccessControl { get; set; } + /// 2 entries + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public ulong[]? ExtendedServiceAccessControl; /// /// Reserved /// - public byte[]? Reserved { get; set; } + /// 0x0F bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x0F)] + public byte[]? Reserved; /// /// Resource limit category. (0 = APPLICATION, 1 = SYS_APPLET, 2 = LIB_APPLET, 3 = OTHER (sysmodules running under the BASE memregion)) /// - public ResourceLimitCategory ResourceLimitCategory { get; set; } + [MarshalAs(UnmanagedType.U1)] + public ResourceLimitCategory ResourceLimitCategory; } } diff --git a/N3DS/ARM9AccessControl.cs b/N3DS/ARM9AccessControl.cs index c9e863d..b93533d 100644 --- a/N3DS/ARM9AccessControl.cs +++ b/N3DS/ARM9AccessControl.cs @@ -1,17 +1,22 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class ARM9AccessControl { /// /// Descriptors /// - public byte[]? Descriptors { get; set; } + /// 15 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] + public byte[]? Descriptors; /// /// ARM9 Descriptor Version. Originally this value had to be ≥ 2. /// Starting with 9.3.0-X this value has to be either value 2 or value 3. /// - public byte DescriptorVersion { get; set; } + public byte DescriptorVersion; } } diff --git a/N3DS/AccessControlInfo.cs b/N3DS/AccessControlInfo.cs index 318fbd0..ae0dd1c 100644 --- a/N3DS/AccessControlInfo.cs +++ b/N3DS/AccessControlInfo.cs @@ -1,21 +1,24 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class AccessControlInfo { /// /// ARM11 local system capabilities /// - public ARM11LocalSystemCapabilities? ARM11LocalSystemCapabilities { get; set; } + public ARM11LocalSystemCapabilities? ARM11LocalSystemCapabilities; /// /// ARM11 kernel capabilities /// - public ARM11KernelCapabilities? ARM11KernelCapabilities { get; set; } + public ARM11KernelCapabilities? ARM11KernelCapabilities; /// /// ARM9 access control /// - public ARM9AccessControl? ARM9AccessControl { get; set; } + public ARM9AccessControl? ARM9AccessControl; } } diff --git a/N3DS/CIAHeader.cs b/N3DS/CIAHeader.cs index 2bb6adf..daa4983 100644 --- a/N3DS/CIAHeader.cs +++ b/N3DS/CIAHeader.cs @@ -1,51 +1,56 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class CIAHeader { /// /// Archive header size, usually 0x2020 bytes /// - public uint HeaderSize { get; set; } + public uint HeaderSize; /// /// Type /// - public ushort Type { get; set; } + public ushort Type; /// /// Version /// - public ushort Version { get; set; } + public ushort Version; /// /// Certificate chain size /// - public uint CertificateChainSize { get; set; } + public uint CertificateChainSize; /// /// Ticket size /// - public uint TicketSize { get; set; } + public uint TicketSize; /// /// TMD file size /// - public uint TMDFileSize { get; set; } + public uint TMDFileSize; /// /// Meta size (0 if no Meta data is present) /// - public uint MetaSize { get; set; } + public uint MetaSize; /// /// Content size /// - public ulong ContentSize { get; set; } + public ulong ContentSize; /// /// Content Index /// - public byte[]? ContentIndex { get; set; } + /// 0x2000 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2000)] + public byte[]? ContentIndex; } } \ No newline at end of file diff --git a/N3DS/CardInfoHeader.cs b/N3DS/CardInfoHeader.cs index a56a523..329d677 100644 --- a/N3DS/CardInfoHeader.cs +++ b/N3DS/CardInfoHeader.cs @@ -1,61 +1,74 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class CardInfoHeader { /// /// CARD2: Writable Address In Media Units (For 'On-Chip' Savedata). CARD1: Always 0xFFFFFFFF. /// - public uint WritableAddressMediaUnits { get; set; } + public uint WritableAddressMediaUnits; /// /// Card Info Bitmask /// - public uint CardInfoBitmask { get; set; } + public uint CardInfoBitmask; /// /// Reserved /// - public byte[]? Reserved1 { get; set; } + /// 0xF8 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xF8)] + public byte[]? Reserved1; /// /// Filled size of cartridge /// - public uint FilledSize { get; set; } + public uint FilledSize; /// /// Reserved /// - public byte[]? Reserved2 { get; set; } + /// 0x0C bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x0C)] + public byte[]? Reserved2; /// /// Title version /// - public ushort TitleVersion { get; set; } + public ushort TitleVersion; /// /// Card revision /// - public ushort CardRevision { get; set; } + public ushort CardRevision; /// /// Reserved /// - public byte[]? Reserved3 { get; set; } + /// 0x0C bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x0C)] + public byte[]? Reserved3; /// /// Title ID of CVer in included update partition /// - public byte[]? CVerTitleID { get; set; } + /// 8 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[]? CVerTitleID; /// /// Version number of CVer in included update partition /// - public ushort CVerVersionNumber { get; set; } + public ushort CVerVersionNumber; /// /// Reserved /// - public byte[]? Reserved4 { get; set; } + /// 0xCD6 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xCD6)] + public byte[]? Reserved4; } } diff --git a/N3DS/CodeSetInfo.cs b/N3DS/CodeSetInfo.cs index 42028be..075291a 100644 --- a/N3DS/CodeSetInfo.cs +++ b/N3DS/CodeSetInfo.cs @@ -1,21 +1,24 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class CodeSetInfo { /// /// Address /// - public uint Address { get; set; } + public uint Address; /// /// Physical region size (in page-multiples) /// - public uint PhysicalRegionSizeInPages { get; set; } + public uint PhysicalRegionSizeInPages; /// /// Size (in bytes) /// - public uint SizeInBytes { get; set; } + public uint SizeInBytes; } } diff --git a/N3DS/ContentChunkRecord.cs b/N3DS/ContentChunkRecord.cs index cdec186..5fd8b6d 100644 --- a/N3DS/ContentChunkRecord.cs +++ b/N3DS/ContentChunkRecord.cs @@ -1,3 +1,5 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.N3DS { /// @@ -5,12 +7,13 @@ namespace SabreTools.Models.N3DS /// (Determined by "Content Count" in the TMD Header). /// /// + [StructLayout(LayoutKind.Sequential)] public sealed class ContentChunkRecord { /// /// Content id /// - public uint ContentId { get; set; } + public uint ContentId; /// /// Content index @@ -18,21 +21,23 @@ namespace SabreTools.Models.N3DS /// /// This does not apply to DLC. /// - public ContentIndex ContentIndex { get; set; } + public ContentIndex ContentIndex; /// /// Content type /// - public TMDContentType ContentType { get; set; } + public TMDContentType ContentType; /// /// Content size /// - public ulong ContentSize { get; set; } + public ulong ContentSize; /// /// SHA-256 hash /// - public byte[]? SHA256Hash { get; set; } + /// 0x20 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[]? SHA256Hash; } } \ No newline at end of file diff --git a/N3DS/ContentInfoRecord.cs b/N3DS/ContentInfoRecord.cs index 2cc2808..6f64b9f 100644 --- a/N3DS/ContentInfoRecord.cs +++ b/N3DS/ContentInfoRecord.cs @@ -1,24 +1,29 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.N3DS { /// /// There are 64 of these records, usually only the first is used. /// /// + [StructLayout(LayoutKind.Sequential)] public sealed class ContentInfoRecord { /// /// Content index offset /// - public ushort ContentIndexOffset { get; set; } + public ushort ContentIndexOffset; /// /// Content command count [k] /// - public ushort ContentCommandCount { get; set; } + public ushort ContentCommandCount; /// /// SHA-256 hash of the next k content records that have not been hashed yet /// - public byte[]? UnhashedContentRecordsSHA256Hash { get; set; } + /// 0x20 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[]? UnhashedContentRecordsSHA256Hash; } } \ No newline at end of file diff --git a/N3DS/DevelopmentCardInfoHeader.cs b/N3DS/DevelopmentCardInfoHeader.cs index e9fa121..816e522 100644 --- a/N3DS/DevelopmentCardInfoHeader.cs +++ b/N3DS/DevelopmentCardInfoHeader.cs @@ -1,31 +1,40 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class DevelopmentCardInfoHeader { /// /// InitialData /// - public InitialData? InitialData { get; set; } + public InitialData? InitialData; /// /// CardDeviceReserved1 /// - public byte[]? CardDeviceReserved1 { get; set; } + /// 0x200 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[]? CardDeviceReserved1; /// /// TitleKey /// - public byte[]? TitleKey { get; set; } + /// 0x10 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] + public byte[]? TitleKey; /// /// CardDeviceReserved2 /// - public byte[]? CardDeviceReserved2 { get; set; } + /// 0x1BF0 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1BF0)] + public byte[]? CardDeviceReserved2; /// /// TestData /// - public TestData? TestData { get; set; } + public TestData? TestData; } } diff --git a/N3DS/ExeFSFileHeader.cs b/N3DS/ExeFSFileHeader.cs index dace6be..cdf8100 100644 --- a/N3DS/ExeFSFileHeader.cs +++ b/N3DS/ExeFSFileHeader.cs @@ -1,4 +1,6 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// /// There are a maximum of 10 file headers in the ExeFS format. (This maximum @@ -8,26 +10,24 @@ /// the currently define size of 0x200 bytes.) /// /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public sealed class ExeFSFileHeader { /// /// File name /// - public string? FileName { get; set; } + /// 8 bytes + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] + public string? FileName; /// /// File offset /// - public uint FileOffset { get; set; } + public uint FileOffset; /// /// File size /// - public uint FileSize { get; set; } - - /// - /// SHA256 hash calculated over the entire file contents - /// - public byte[]? FileHash { get; set; } + public uint FileSize; } } diff --git a/N3DS/ExeFSHeader.cs b/N3DS/ExeFSHeader.cs index 742b9bd..98b3714 100644 --- a/N3DS/ExeFSHeader.cs +++ b/N3DS/ExeFSHeader.cs @@ -21,6 +21,7 @@ /// /// Reserved /// + /// 0x20 bytes public byte[]? Reserved { get; set; } /// diff --git a/N3DS/InitialData.cs b/N3DS/InitialData.cs index 8a51441..065a743 100644 --- a/N3DS/InitialData.cs +++ b/N3DS/InitialData.cs @@ -1,36 +1,49 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class InitialData { /// /// Card seed keyY (first u64 is Media ID (same as first NCCH partitionId)) /// - public byte[]? CardSeedKeyY { get; set; } + /// 0x10 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] + public byte[]? CardSeedKeyY; /// /// Encrypted card seed (AES-CCM, keyslot 0x3B for retail cards, see CTRCARD_SECSEED) /// - public byte[]? EncryptedCardSeed { get; set; } + /// 0x10 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] + public byte[]? EncryptedCardSeed; /// /// Card seed AES-MAC /// - public byte[]? CardSeedAESMAC { get; set; } + /// 0x10 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] + public byte[]? CardSeedAESMAC; /// /// Card seed nonce /// - public byte[]? CardSeedNonce { get; set; } + /// 0x0C bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x0C)] + public byte[]? CardSeedNonce; /// /// Reserved3 /// - public byte[]? Reserved { get; set; } + /// 0xC4 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xC4)] + public byte[]? Reserved; /// /// Copy of first NCCH header (excluding RSA signature) /// - public NCCHHeader? BackupHeader { get; set; } + public NCCHHeader? BackupHeader; } } diff --git a/N3DS/MetaData.cs b/N3DS/MetaData.cs index 2a9bb08..f84545e 100644 --- a/N3DS/MetaData.cs +++ b/N3DS/MetaData.cs @@ -1,32 +1,43 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class MetaData { /// /// Title ID dependency list - Taken from the application's ExHeader /// /// TODO: Determine numeric format of each entry - public byte[]? TitleIDDependencyList { get; set; } + /// 0x180 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x180)] + public byte[]? TitleIDDependencyList; /// /// Reserved /// - public byte[]? Reserved1 { get; set; } + /// 0x180 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x180)] + public byte[]? Reserved1; /// /// Core Version /// - public uint CoreVersion { get; set; } + public uint CoreVersion; /// /// Reserved /// - public byte[]? Reserved2 { get; set; } + /// 0xFC bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xFC)] + public byte[]? Reserved2; /// /// Icon Data(.ICN) - Taken from the application's ExeFS /// - public byte[]? IconData { get; set; } + /// 0x36C0 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x36C0)] + public byte[]? IconData; } } \ No newline at end of file diff --git a/N3DS/NCCHExtendedHeader.cs b/N3DS/NCCHExtendedHeader.cs index c7fd142..a9a00a7 100644 --- a/N3DS/NCCHExtendedHeader.cs +++ b/N3DS/NCCHExtendedHeader.cs @@ -1,36 +1,43 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// /// The exheader has two sections: - /// - The actual exheader data, containing System Control Info (SCI) and Access Control Info (ACI) { get; set; } + /// - The actual exheader data, containing System Control Info (SCI) and Access Control Info (ACI); /// - A signed copy of NCCH HDR public key, and exheader ACI. This version of the ACI is used as limitation to the actual ACI. /// /// + [StructLayout(LayoutKind.Sequential)] public sealed class NCCHExtendedHeader { /// /// SCI /// - public SystemControlInfo? SCI { get; set; } + public SystemControlInfo? SCI; /// /// ACI /// - public AccessControlInfo? ACI { get; set; } + public AccessControlInfo? ACI; /// /// AccessDesc signature (RSA-2048-SHA256) /// - public byte[]? AccessDescSignature { get; set; } + /// 0x100 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] + public byte[]? AccessDescSignature; /// /// NCCH HDR RSA-2048 public key /// - public byte[]? NCCHHDRPublicKey { get; set; } + /// 0x100 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] + public byte[]? NCCHHDRPublicKey; /// /// ACI (for limitation of first ACI) /// - public AccessControlInfo? ACIForLimitations { get; set; } + public AccessControlInfo? ACIForLimitations; } } diff --git a/N3DS/NCCHHeader.cs b/N3DS/NCCHHeader.cs index 0add92c..cf41fd7 100644 --- a/N3DS/NCCHHeader.cs +++ b/N3DS/NCCHHeader.cs @@ -1,37 +1,44 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public sealed class NCCHHeader { /// /// RSA-2048 signature of the NCCH header, using SHA-256. /// - public byte[]? RSA2048Signature { get; set; } + /// 0x100 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] + public byte[]? RSA2048Signature; /// /// Magic ID, always 'NCCH' /// - public string? MagicID { get; set; } + /// 4 bytes + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)] + public string? MagicID; /// /// Content size, in media units (1 media unit = 0x200 bytes) /// - public uint ContentSizeInMediaUnits { get; set; } + public uint ContentSizeInMediaUnits; /// /// Partition ID /// - public ulong PartitionId { get; set; } + public ulong PartitionId; /// /// Maker code /// - public ushort MakerCode { get; set; } + public ushort MakerCode; /// /// Version /// - public ushort Version { get; set; } + public ushort Version; /// /// When ncchflag[7] = 0x20 starting with FIRM 9.6.0-X, this is compared with the first output u32 from a @@ -39,118 +46,132 @@ /// [programID from NCCH + 0x118]. This hash is only used for verification of the content lock seed, and /// is not the actual keyY. /// - public uint VerificationHash { get; set; } + public uint VerificationHash; /// /// Program ID /// - public byte[]? ProgramId { get; set; } + /// 8 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[]? ProgramId; /// /// Reserved /// - public byte[]? Reserved1 { get; set; } + /// 0x10 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] + public byte[]? Reserved1; /// /// Logo Region SHA-256 hash. (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11) /// - public byte[]? LogoRegionHash { get; set; } + /// 0x20 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[]? LogoRegionHash; /// /// Product code /// - public string? ProductCode { get; set; } + /// 0x10 bytes + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x10)] + public string? ProductCode; /// /// Extended header SHA-256 hash (SHA256 of 2x Alignment Size, beginning at 0x0 of ExHeader) /// - public byte[]? ExtendedHeaderHash { get; set; } + /// 0x20 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[]? ExtendedHeaderHash; /// /// Extended header size, in bytes /// - public uint ExtendedHeaderSizeInBytes { get; set; } + public uint ExtendedHeaderSizeInBytes; /// /// Reserved /// - public byte[]? Reserved2 { get; set; } + public uint Reserved2; /// /// Flags /// - public NCCHHeaderFlags? Flags { get; set; } + public NCCHHeaderFlags? Flags; /// /// Plain region offset, in media units /// - public uint PlainRegionOffsetInMediaUnits { get; set; } + public uint PlainRegionOffsetInMediaUnits; /// /// Plain region size, in media units /// - public uint PlainRegionSizeInMediaUnits { get; set; } + public uint PlainRegionSizeInMediaUnits; /// /// Logo Region offset, in media units (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11) /// - public uint LogoRegionOffsetInMediaUnits { get; set; } + public uint LogoRegionOffsetInMediaUnits; /// /// Logo Region size, in media units (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11) /// - public uint LogoRegionSizeInMediaUnits { get; set; } + public uint LogoRegionSizeInMediaUnits; /// /// ExeFS offset, in media units /// - public uint ExeFSOffsetInMediaUnits { get; set; } + public uint ExeFSOffsetInMediaUnits; /// /// ExeFS size, in media units /// - public uint ExeFSSizeInMediaUnits { get; set; } + public uint ExeFSSizeInMediaUnits; /// /// ExeFS hash region size, in media units /// - public uint ExeFSHashRegionSizeInMediaUnits { get; set; } + public uint ExeFSHashRegionSizeInMediaUnits; /// /// Reserved /// - public byte[]? Reserved3 { get; set; } + public uint Reserved3; /// /// RomFS offset, in media units /// - public uint RomFSOffsetInMediaUnits { get; set; } + public uint RomFSOffsetInMediaUnits; /// /// RomFS size, in media units /// - public uint RomFSSizeInMediaUnits { get; set; } + public uint RomFSSizeInMediaUnits; /// /// RomFS hash region size, in media units /// - public uint RomFSHashRegionSizeInMediaUnits { get; set; } + public uint RomFSHashRegionSizeInMediaUnits; /// /// Reserved /// - public byte[]? Reserved4 { get; set; } + public uint Reserved4; /// /// ExeFS superblock SHA-256 hash - (SHA-256 hash, starting at 0x0 of the ExeFS over the number of /// media units specified in the ExeFS hash region size) /// - public byte[]? ExeFSSuperblockHash { get; set; } + /// 0x20 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[]? ExeFSSuperblockHash; /// /// RomFS superblock SHA-256 hash - (SHA-256 hash, starting at 0x0 of the RomFS over the number /// of media units specified in the RomFS hash region size) /// - public byte[]? RomFSSuperblockHash { get; set; } + /// 0x20 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[]? RomFSSuperblockHash; } } diff --git a/N3DS/NCCHHeaderFlags.cs b/N3DS/NCCHHeaderFlags.cs index 6d9b816..266537b 100644 --- a/N3DS/NCCHHeaderFlags.cs +++ b/N3DS/NCCHHeaderFlags.cs @@ -1,49 +1,56 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class NCCHHeaderFlags { /// /// Reserved /// - public byte Reserved0 { get; set; } + public byte Reserved0; /// /// Reserved /// - public byte Reserved1 { get; set; } + public byte Reserved1; /// /// Reserved /// - public byte Reserved2 { get; set; } + public byte Reserved2; /// /// Crypto Method: When this is non-zero, a NCCH crypto method using two keyslots is used. /// - public CryptoMethod CryptoMethod { get; set; } + [MarshalAs(UnmanagedType.U1)] + public CryptoMethod CryptoMethod; /// /// Content Platform: 1 = CTR, 2 = snake (New 3DS). /// - public ContentPlatform ContentPlatform { get; set; } + [MarshalAs(UnmanagedType.U1)] + public ContentPlatform ContentPlatform; /// /// Content Type Bit-masks: Data = 0x1, Executable = 0x2, SystemUpdate = 0x4, Manual = 0x8, /// Child = (0x4|0x8), Trial = 0x10. When 'Data' is set, but not 'Executable', NCCH is a CFA. /// Otherwise when 'Executable' is set, NCCH is a CXI. /// - public ContentType MediaPlatformIndex { get; set; } + [MarshalAs(UnmanagedType.U1)] + public ContentType MediaPlatformIndex; /// - /// Content Unit Size i.e. u32 ContentUnitSize = 0x200*2^flags[6] { get; set; } + /// Content Unit Size i.e. u32 ContentUnitSize = 0x200*2^flags[6]; /// - public byte ContentUnitSize { get; set; } + public byte ContentUnitSize; /// /// Bit-masks: FixedCryptoKey = 0x1, NoMountRomFs = 0x2, NoCrypto = 0x4, using a new keyY /// generator = 0x20(starting with FIRM 9.6.0-X). /// - public BitMasks BitMasks { get; set; } + [MarshalAs(UnmanagedType.U1)] + public BitMasks BitMasks; } } diff --git a/N3DS/PartitionTableEntry.cs b/N3DS/PartitionTableEntry.cs index 8e0ac15..17cd573 100644 --- a/N3DS/PartitionTableEntry.cs +++ b/N3DS/PartitionTableEntry.cs @@ -1,19 +1,22 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// /// Offset and Length partition table, in media units /// /// + [StructLayout(LayoutKind.Sequential)] public sealed class PartitionTableEntry { /// /// Offset /// - public uint Offset { get; set; } + public uint Offset; /// /// Length /// - public uint Length { get; set; } + public uint Length; } } diff --git a/N3DS/RomFSHeader.cs b/N3DS/RomFSHeader.cs index 01a743f..bfb7e55 100644 --- a/N3DS/RomFSHeader.cs +++ b/N3DS/RomFSHeader.cs @@ -1,4 +1,6 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// /// RomFS (or Read-Only Filesystem) is part of the NCCH format, and is @@ -6,91 +8,94 @@ /// /// /// TODO: Implement the other parts of the RomFS tree structure + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public sealed class RomFSHeader { /// /// Magic "IVFC" /// - public string? MagicString { get; set; } + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)] + public string? MagicString; /// /// Magic number 0x10000 /// - public uint MagicNumber { get; set; } + public uint MagicNumber; /// /// Master hash size /// - public uint MasterHashSize { get; set; } + public uint MasterHashSize; /// /// Level 1 logical offset /// - public ulong Level1LogicalOffset { get; set; } + public ulong Level1LogicalOffset; /// /// Level 1 hashdata size /// - public ulong Level1HashdataSize { get; set; } + public ulong Level1HashdataSize; /// /// Level 1 block size, in log2 /// - public uint Level1BlockSizeLog2 { get; set; } + public uint Level1BlockSizeLog2; /// /// Reserved /// - public byte[]? Reserved1 { get; set; } + public uint Reserved1; /// /// Level 2 logical offset /// - public ulong Level2LogicalOffset { get; set; } + public ulong Level2LogicalOffset; /// /// Level 2 hashdata size /// - public ulong Level2HashdataSize { get; set; } + public ulong Level2HashdataSize; /// /// Level 2 block size, in log2 /// - public uint Level2BlockSizeLog2 { get; set; } + public uint Level2BlockSizeLog2; /// /// Reserved /// - public byte[]? Reserved2 { get; set; } + public uint Reserved2; /// /// Level 3 logical offset /// - public ulong Level3LogicalOffset { get; set; } + public ulong Level3LogicalOffset; /// /// Level 3 hashdata size /// - public ulong Level3HashdataSize { get; set; } + public ulong Level3HashdataSize; /// /// Level 3 block size, in log2 /// - public uint Level3BlockSizeLog2 { get; set; } + public uint Level3BlockSizeLog2; /// /// Reserved /// - public byte[]? Reserved3 { get; set; } + public uint Reserved3; /// /// Reserved /// - public byte[]? Reserved4 { get; set; } + public uint Reserved4; /// /// Optional info size. /// - public uint OptionalInfoSize { get; set; } + public uint OptionalInfoSize; } } diff --git a/N3DS/StorageInfo.cs b/N3DS/StorageInfo.cs index 483ae83..0a9f752 100644 --- a/N3DS/StorageInfo.cs +++ b/N3DS/StorageInfo.cs @@ -1,36 +1,46 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// /// Used in FSReg:Register. /// /// + [StructLayout(LayoutKind.Sequential)] public sealed class StorageInfo { /// /// Extdata ID /// - public ulong ExtdataID { get; set; } + public ulong ExtdataID; /// /// System savedata IDs /// - public byte[]? SystemSavedataIDs { get; set; } + /// 8 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[]? SystemSavedataIDs; /// /// Storage accessible unique IDs /// - public byte[]? StorageAccessibleUniqueIDs { get; set; } + /// 8 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[]? StorageAccessibleUniqueIDs; /// /// Filesystem access info /// /// TODO: Create enum for the flag values /// TODO: Combine with "other attributes" - public byte[]? FileSystemAccessInfo { get; set; } + /// 7 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[]? FileSystemAccessInfo; /// /// Other attributes /// - public StorageInfoOtherAttributes OtherAttributes { get; set; } + [MarshalAs(UnmanagedType.U1)] + public StorageInfoOtherAttributes OtherAttributes; } } diff --git a/N3DS/SystemControlInfo.cs b/N3DS/SystemControlInfo.cs index 0bf1653..abcbecf 100644 --- a/N3DS/SystemControlInfo.cs +++ b/N3DS/SystemControlInfo.cs @@ -1,66 +1,75 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public sealed class SystemControlInfo { /// /// Application title (default is "CtrApp") /// - public string? ApplicationTitle { get; set; } + /// 8 bytes + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] + public string? ApplicationTitle; /// /// Reserved /// - public byte[]? Reserved1 { get; set; } + /// 5 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[]? Reserved1; /// /// Flag (bit 0: CompressExefsCode, bit 1: SDApplication) /// - public byte Flag { get; set; } + public byte Flag; /// /// Remaster version /// - public ushort RemasterVersion { get; set; } + public ushort RemasterVersion; /// /// Text code set info /// - public CodeSetInfo? TextCodeSetInfo { get; set; } + public CodeSetInfo? TextCodeSetInfo; /// /// Stack size /// - public uint StackSize { get; set; } + public uint StackSize; /// /// Read-only code set info /// - public CodeSetInfo? ReadOnlyCodeSetInfo { get; set; } + public CodeSetInfo? ReadOnlyCodeSetInfo; /// /// Reserved /// - public byte[]? Reserved2 { get; set; } + public uint Reserved2; /// /// Data code set info /// - public CodeSetInfo? DataCodeSetInfo { get; set; } + public CodeSetInfo? DataCodeSetInfo; /// /// BSS size /// - public uint BSSSize { get; set; } + public uint BSSSize; /// /// Dependency module (program ID) list /// - public ulong[]? DependencyModuleList { get; set; } + /// 48 entries + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public ulong[]? DependencyModuleList; /// /// SystemInfo /// - public SystemInfo? SystemInfo { get; set; } + public SystemInfo? SystemInfo; } } diff --git a/N3DS/SystemInfo.cs b/N3DS/SystemInfo.cs index 51d2d84..8d43af6 100644 --- a/N3DS/SystemInfo.cs +++ b/N3DS/SystemInfo.cs @@ -1,21 +1,26 @@ -namespace SabreTools.Models.N3DS +using System.Runtime.InteropServices; + +namespace SabreTools.Models.N3DS { /// + [StructLayout(LayoutKind.Sequential)] public sealed class SystemInfo { /// /// SaveData Size /// - public ulong SaveDataSize { get; set; } + public ulong SaveDataSize; /// /// Jump ID /// - public ulong JumpID { get; set; } + public ulong JumpID; /// /// Reserved /// - public byte[]? Reserved { get; set; } + /// 0x30 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x30)] + public byte[]? Reserved; } } diff --git a/N3DS/TestData.cs b/N3DS/TestData.cs index 85feae4..6c8770b 100644 --- a/N3DS/TestData.cs +++ b/N3DS/TestData.cs @@ -1,59 +1,80 @@ +using System.Runtime.InteropServices; + namespace SabreTools.Models.N3DS { /// /// The test data is the same one encountered in development DS/DSi cartridges. /// /// + [StructLayout(LayoutKind.Sequential)] public sealed class TestData { /// /// The bytes FF 00 FF 00 AA 55 AA 55. /// - public byte[]? Signature { get; set; } + /// 8 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[]? Signature; /// /// An ascending byte sequence equal to the offset mod 256 (08 09 0A ... FE FF 00 01 ... FF). /// - public byte[]? AscendingByteSequence { get; set; } + /// 0x1F8 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1F8)] + public byte[]? AscendingByteSequence; /// /// A descending byte sequence equal to 255 minus the offset mod 256 (FF FE FD ... 00 FF DE ... 00). /// - public byte[]? DescendingByteSequence { get; set; } + /// 0x200 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[]? DescendingByteSequence; /// /// Filled with 00 (0b00000000) bytes. /// - public byte[]? Filled00 { get; set; } + /// 0x200 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[]? Filled00; /// /// Filled with FF (0b11111111) bytes. /// - public byte[]? FilledFF { get; set; } + /// 0x200 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[]? FilledFF; /// /// Filled with 0F (0b00001111) bytes. /// - public byte[]? Filled0F { get; set; } + /// 0x200 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[]? Filled0F; /// /// Filled with F0 (0b11110000) bytes. /// - public byte[]? FilledF0 { get; set; } + /// 0x200 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[]? FilledF0; /// /// Filled with 55 (0b01010101) bytes. /// - public byte[]? Filled55 { get; set; } + /// 0x200 bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[]? Filled55; /// /// Filled with AA (0b10101010) bytes. /// - public byte[]? FilledAA { get; set; } + /// 0x1FF bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1FF)] + public byte[]? FilledAA; /// /// The final byte is 00 (0b00000000). /// - public byte FinalByte { get; set; } + public byte FinalByte; } }