using System.IO; using System.Text; namespace BinaryObjectScanner.Wrappers { public class N3DS : WrapperBase { #region Descriptive Properties /// public override string DescriptionString => "Nintendo 3DS Cart Image"; #endregion #region Pass-Through Properties #region Header #region Common to all NCSD files /// #if NET48 public byte[] RSA2048Signature => _model.Header.RSA2048Signature; #else public byte[]? RSA2048Signature => _model.Header?.RSA2048Signature; #endif /// #if NET48 public string MagicNumber => _model.Header.MagicNumber; #else public string? MagicNumber => _model.Header?.MagicNumber; #endif /// #if NET48 public uint ImageSizeInMediaUnits => _model.Header.ImageSizeInMediaUnits; #else public uint? ImageSizeInMediaUnits => _model.Header?.ImageSizeInMediaUnits; #endif /// #if NET48 public byte[] MediaId => _model.Header.MediaId; #else public byte[]? MediaId => _model.Header?.MediaId; #endif /// #if NET48 public SabreTools.Models.N3DS.FilesystemType PartitionsFSType => _model.Header.PartitionsFSType; #else public SabreTools.Models.N3DS.FilesystemType? PartitionsFSType => _model.Header?.PartitionsFSType; #endif /// #if NET48 public byte[] PartitionsCryptType => _model.Header.PartitionsCryptType; #else public byte[]? PartitionsCryptType => _model.Header?.PartitionsCryptType; #endif /// #if NET48 public SabreTools.Models.N3DS.PartitionTableEntry[] PartitionsTable => _model.Header.PartitionsTable; #else public SabreTools.Models.N3DS.PartitionTableEntry?[]? PartitionsTable => _model.Header?.PartitionsTable; #endif #endregion #region CTR Cart Image (CCI) Specific /// #if NET48 public byte[] ExheaderHash => _model.Header.ExheaderHash; #else public byte[]? ExheaderHash => _model.Header?.ExheaderHash; #endif /// #if NET48 public uint AdditionalHeaderSize => _model.Header.AdditionalHeaderSize; #else public uint? AdditionalHeaderSize => _model.Header?.AdditionalHeaderSize; #endif /// #if NET48 public uint SectorZeroOffset => _model.Header.SectorZeroOffset; #else public uint? SectorZeroOffset => _model.Header?.SectorZeroOffset; #endif /// #if NET48 public byte[] PartitionFlags => _model.Header.PartitionFlags; #else public byte[]? PartitionFlags => _model.Header?.PartitionFlags; #endif /// #if NET48 public ulong[] PartitionIdTable => _model.Header.PartitionIdTable; #else public ulong[]? PartitionIdTable => _model.Header?.PartitionIdTable; #endif /// #if NET48 public byte[] Reserved1 => _model.Header.Reserved1; #else public byte[]? Reserved1 => _model.Header?.Reserved1; #endif /// #if NET48 public byte[] Reserved2 => _model.Header.Reserved2; #else public byte[]? Reserved2 => _model.Header?.Reserved2; #endif /// #if NET48 public byte FirmUpdateByte1 => _model.Header.FirmUpdateByte1; #else public byte? FirmUpdateByte1 => _model.Header?.FirmUpdateByte1; #endif /// #if NET48 public byte FirmUpdateByte2 => _model.Header.FirmUpdateByte2; #else public byte? FirmUpdateByte2 => _model.Header?.FirmUpdateByte2; #endif #endregion #region Raw NAND Format Specific /// #if NET48 public byte[] Unknown => _model.Header.Unknown; #else public byte[]? Unknown => _model.Header?.Unknown; #endif /// #if NET48 public byte[] EncryptedMBR => _model.Header.EncryptedMBR; #else public byte[]? EncryptedMBR => _model.Header?.EncryptedMBR; #endif #endregion #endregion #region Card Info Header /// #if NET48 public uint CIH_WritableAddressMediaUnits => _model.CardInfoHeader.WritableAddressMediaUnits; #else public uint? CIH_WritableAddressMediaUnits => _model.CardInfoHeader?.WritableAddressMediaUnits; #endif /// #if NET48 public uint CIH_CardInfoBitmask => _model.CardInfoHeader.CardInfoBitmask; #else public uint? CIH_CardInfoBitmask => _model.CardInfoHeader?.CardInfoBitmask; #endif /// #if NET48 public byte[] CIH_Reserved1 => _model.CardInfoHeader.Reserved1; #else public byte[]? CIH_Reserved1 => _model.CardInfoHeader?.Reserved1; #endif /// #if NET48 public uint CIH_FilledSize => _model.CardInfoHeader.FilledSize; #else public uint? CIH_FilledSize => _model.CardInfoHeader?.FilledSize; #endif /// #if NET48 public byte[] CIH_Reserved2 => _model.CardInfoHeader.Reserved2; #else public byte[]? CIH_Reserved2 => _model.CardInfoHeader?.Reserved2; #endif /// #if NET48 public ushort CIH_TitleVersion => _model.CardInfoHeader.TitleVersion; #else public ushort? CIH_TitleVersion => _model.CardInfoHeader?.TitleVersion; #endif /// #if NET48 public ushort CIH_CardRevision => _model.CardInfoHeader.CardRevision; #else public ushort? CIH_CardRevision => _model.CardInfoHeader?.CardRevision; #endif /// #if NET48 public byte[] CIH_Reserved3 => _model.CardInfoHeader.Reserved3; #else public byte[]? CIH_Reserved3 => _model.CardInfoHeader?.Reserved3; #endif /// #if NET48 public byte[] CIH_CVerTitleID => _model.CardInfoHeader.CVerTitleID; #else public byte[]? CIH_CVerTitleID => _model.CardInfoHeader?.CVerTitleID; #endif /// #if NET48 public ushort CIH_CVerVersionNumber => _model.CardInfoHeader.CVerVersionNumber; #else public ushort? CIH_CVerVersionNumber => _model.CardInfoHeader?.CVerVersionNumber; #endif /// #if NET48 public byte[] CIH_Reserved4 => _model.CardInfoHeader.Reserved4; #else public byte[]? CIH_Reserved4 => _model.CardInfoHeader?.Reserved4; #endif #endregion #region Development Card Info Header #region Initial Data /// #if NET48 public byte[] DCIH_ID_CardSeedKeyY => _model.DevelopmentCardInfoHeader?.InitialData?.CardSeedKeyY; #else public byte[]? DCIH_ID_CardSeedKeyY => _model.DevelopmentCardInfoHeader?.InitialData?.CardSeedKeyY; #endif /// #if NET48 public byte[] DCIH_ID_EncryptedCardSeed => _model.DevelopmentCardInfoHeader?.InitialData?.EncryptedCardSeed; #else public byte[]? DCIH_ID_EncryptedCardSeed => _model.DevelopmentCardInfoHeader?.InitialData?.EncryptedCardSeed; #endif /// #if NET48 public byte[] DCIH_ID_CardSeedAESMAC => _model.DevelopmentCardInfoHeader?.InitialData?.CardSeedAESMAC; #else public byte[]? DCIH_ID_CardSeedAESMAC => _model.DevelopmentCardInfoHeader?.InitialData?.CardSeedAESMAC; #endif /// #if NET48 public byte[] DCIH_ID_CardSeedNonce => _model.DevelopmentCardInfoHeader?.InitialData?.CardSeedNonce; #else public byte[]? DCIH_ID_CardSeedNonce => _model.DevelopmentCardInfoHeader?.InitialData?.CardSeedNonce; #endif /// #if NET48 public byte[] DCIH_ID_Reserved => _model.DevelopmentCardInfoHeader?.InitialData?.Reserved; #else public byte[]? DCIH_ID_Reserved => _model.DevelopmentCardInfoHeader?.InitialData?.Reserved; #endif /// #if NET48 public SabreTools.Models.N3DS.NCCHHeader DCIH_ID_BackupHeader => _model.DevelopmentCardInfoHeader?.InitialData?.BackupHeader; #else public SabreTools.Models.N3DS.NCCHHeader? DCIH_ID_BackupHeader => _model.DevelopmentCardInfoHeader?.InitialData?.BackupHeader; #endif #endregion /// #if NET48 public byte[] DCIH_CardDeviceReserved1 => _model.DevelopmentCardInfoHeader?.CardDeviceReserved1; #else public byte[]? DCIH_CardDeviceReserved1 => _model.DevelopmentCardInfoHeader?.CardDeviceReserved1; #endif /// #if NET48 public byte[] DCIH_TitleKey => _model.DevelopmentCardInfoHeader?.TitleKey; #else public byte[]? DCIH_TitleKey => _model.DevelopmentCardInfoHeader?.TitleKey; #endif /// #if NET48 public byte[] DCIH_CardDeviceReserved2 => _model.DevelopmentCardInfoHeader?.CardDeviceReserved2; #else public byte[]? DCIH_CardDeviceReserved2 => _model.DevelopmentCardInfoHeader?.CardDeviceReserved2; #endif #region Test Data /// #if NET48 public byte[] DCIH_TD_Signature => _model.DevelopmentCardInfoHeader?.TestData?.Signature; #else public byte[]? DCIH_TD_Signature => _model.DevelopmentCardInfoHeader?.TestData?.Signature; #endif /// #if NET48 public byte[] DCIH_TD_AscendingByteSequence => _model.DevelopmentCardInfoHeader?.TestData?.AscendingByteSequence; #else public byte[]? DCIH_TD_AscendingByteSequence => _model.DevelopmentCardInfoHeader?.TestData?.AscendingByteSequence; #endif /// #if NET48 public byte[] DCIH_TD_DescendingByteSequence => _model.DevelopmentCardInfoHeader?.TestData?.DescendingByteSequence; #else public byte[]? DCIH_TD_DescendingByteSequence => _model.DevelopmentCardInfoHeader?.TestData?.DescendingByteSequence; #endif /// #if NET48 public byte[] DCIH_TD_Filled00 => _model.DevelopmentCardInfoHeader?.TestData?.Filled00; #else public byte[]? DCIH_TD_Filled00 => _model.DevelopmentCardInfoHeader?.TestData?.Filled00; #endif /// #if NET48 public byte[] DCIH_TD_FilledFF => _model.DevelopmentCardInfoHeader?.TestData?.FilledFF; #else public byte[]? DCIH_TD_FilledFF => _model.DevelopmentCardInfoHeader?.TestData?.FilledFF; #endif /// #if NET48 public byte[] DCIH_TD_Filled0F => _model.DevelopmentCardInfoHeader?.TestData?.Filled0F; #else public byte[]? DCIH_TD_Filled0F => _model.DevelopmentCardInfoHeader?.TestData?.Filled0F; #endif /// #if NET48 public byte[] DCIH_TD_FilledF0 => _model.DevelopmentCardInfoHeader?.TestData?.FilledF0; #else public byte[]? DCIH_TD_FilledF0 => _model.DevelopmentCardInfoHeader?.TestData?.FilledF0; #endif /// #if NET48 public byte[] DCIH_TD_Filled55 => _model.DevelopmentCardInfoHeader?.TestData?.Filled55; #else public byte[]? DCIH_TD_Filled55 => _model.DevelopmentCardInfoHeader?.TestData?.Filled55; #endif /// #if NET48 public byte[] DCIH_TD_FilledAA => _model.DevelopmentCardInfoHeader?.TestData?.FilledAA; #else public byte[]? DCIH_TD_FilledAA => _model.DevelopmentCardInfoHeader?.TestData?.FilledAA; #endif /// public byte? DCIH_TD_FinalByte => _model.DevelopmentCardInfoHeader?.TestData?.FinalByte; #endregion #endregion #region Partitions /// #if NET48 public SabreTools.Models.N3DS.NCCHHeader[] Partitions => _model.Partitions; #else public SabreTools.Models.N3DS.NCCHHeader?[]? Partitions => _model.Partitions; #endif #endregion #region Extended Headers /// #if NET48 public SabreTools.Models.N3DS.NCCHExtendedHeader[] ExtendedHeaders => _model.ExtendedHeaders; #else public SabreTools.Models.N3DS.NCCHExtendedHeader?[]? ExtendedHeaders => _model.ExtendedHeaders; #endif #endregion #region ExeFS Headers /// #if NET48 public SabreTools.Models.N3DS.ExeFSHeader[] ExeFSHeaders => _model.ExeFSHeaders; #else public SabreTools.Models.N3DS.ExeFSHeader?[]? ExeFSHeaders => _model.ExeFSHeaders; #endif #endregion #region RomFS Headers /// #if NET48 public SabreTools.Models.N3DS.RomFSHeader[] RomFSHeaders => _model.RomFSHeaders; #else public SabreTools.Models.N3DS.RomFSHeader?[]? RomFSHeaders => _model.RomFSHeaders; #endif #endregion #endregion #region Constructors /// #if NET48 public N3DS(SabreTools.Models.N3DS.Cart model, byte[] data, int offset) #else public N3DS(SabreTools.Models.N3DS.Cart? model, byte[]? data, int offset) #endif : base(model, data, offset) { // All logic is handled by the base class } /// #if NET48 public N3DS(SabreTools.Models.N3DS.Cart model, Stream data) #else public N3DS(SabreTools.Models.N3DS.Cart? model, Stream? data) #endif : base(model, data) { // All logic is handled by the base class } /// /// Create a 3DS cart image from a byte array and offset /// /// Byte array representing the archive /// Offset within the array to parse /// A 3DS cart image wrapper on success, null on failure #if NET48 public static N3DS Create(byte[] data, int offset) #else public static N3DS? Create(byte[]? data, int offset) #endif { // 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 3DS cart image from a Stream /// /// Stream representing the archive /// A 3DS cart image wrapper on success, null on failure #if NET48 public static N3DS Create(Stream data) #else public static N3DS? Create(Stream? data) #endif { // If the data is invalid if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead) return null; var archive = new SabreTools.Serialization.Streams.N3DS().Deserialize(data); if (archive == null) return null; try { return new N3DS(archive, data); } catch { return null; } } #endregion #region Printing /// public override StringBuilder PrettyPrint() { StringBuilder builder = new StringBuilder(); Printing.N3DS.Print(builder, _model); return builder; } #if NET6_0_OR_GREATER /// public override string ExportJSON() => System.Text.Json.JsonSerializer.Serialize(_model, _jsonSerializerOptions); #endif #endregion } }