mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-02-04 05:36:12 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5716143168 | ||
|
|
2a59b23149 | ||
|
|
bdbec4ed02 | ||
|
|
25193f1805 |
@@ -27,7 +27,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.5.0" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.5.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
#region Extended Headers
|
||||
|
||||
// Create the extended header table
|
||||
cart.ExtendedHeaders = new NCCHExtendedHeader[8];
|
||||
cart.ExtendedHeaders = new NCCHExtendedHeader?[8];
|
||||
|
||||
// Iterate and build the extended headers
|
||||
for (int i = 0; i < 8; i++)
|
||||
@@ -115,7 +115,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
#region ExeFS Headers
|
||||
|
||||
// Create the ExeFS header table
|
||||
cart.ExeFSHeaders = new ExeFSHeader[8];
|
||||
cart.ExeFSHeaders = new ExeFSHeader?[8];
|
||||
|
||||
// Iterate and build the ExeFS headers
|
||||
for (int i = 0; i < 8; i++)
|
||||
@@ -149,7 +149,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
#region RomFS Headers
|
||||
|
||||
// Create the RomFS header table
|
||||
cart.RomFSHeaders = new RomFSHeader[8];
|
||||
cart.RomFSHeaders = new RomFSHeader?[8];
|
||||
|
||||
// Iterate and build the RomFS headers
|
||||
for (int i = 0; i < 8; i++)
|
||||
@@ -264,25 +264,20 @@ namespace SabreTools.Serialization.Deserializers
|
||||
|
||||
header.WritableAddressMediaUnits = data.ReadUInt32();
|
||||
header.CardInfoBitmask = data.ReadUInt32();
|
||||
header.Reserved3 = data.ReadBytes(0x108);
|
||||
header.Reserved1 = data.ReadBytes(0xF8);
|
||||
header.FilledSize = data.ReadUInt32();
|
||||
header.Reserved2 = data.ReadBytes(0x0C);
|
||||
header.TitleVersion = data.ReadUInt16();
|
||||
header.CardRevision = data.ReadUInt16();
|
||||
header.Reserved3 = data.ReadBytes(0x0C);
|
||||
header.CVerTitleID = data.ReadBytes(0x08);
|
||||
header.CVerVersionNumber = data.ReadUInt16();
|
||||
header.Reserved4 = data.ReadBytes(0xCD6);
|
||||
header.InitialData = ParseInitialData(data);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a development card info header
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled development card info header on success, null on error</returns>
|
||||
public static DevelopmentCardInfoHeader? ParseDevelopmentCardInfoHeader(Stream data)
|
||||
{
|
||||
return data.ReadType<DevelopmentCardInfoHeader>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into initial data
|
||||
/// </summary>
|
||||
@@ -303,6 +298,16 @@ namespace SabreTools.Serialization.Deserializers
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a development card info header
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled development card info header on success, null on error</returns>
|
||||
public static DevelopmentCardInfoHeader? ParseDevelopmentCardInfoHeader(Stream data)
|
||||
{
|
||||
return data.ReadType<DevelopmentCardInfoHeader>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an NCCH header
|
||||
/// </summary>
|
||||
|
||||
@@ -44,26 +44,26 @@ namespace SabreTools.Serialization.Printers
|
||||
builder.AppendLine(header.PartitionsCryptType, " Partitions crypt type");
|
||||
builder.AppendLine();
|
||||
|
||||
builder.AppendLine(" Partition table:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
builder.AppendLine(" Partition table:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
if (header.PartitionsTable == null || header.PartitionsTable.Length == 0)
|
||||
{
|
||||
builder.AppendLine(" No partition table entries");
|
||||
builder.AppendLine(" No partition table entries");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < header.PartitionsTable.Length; i++)
|
||||
{
|
||||
var partitionTableEntry = header.PartitionsTable[i];
|
||||
builder.AppendLine($" Partition table entry {i}");
|
||||
builder.AppendLine($" Partition table entry {i}");
|
||||
if (partitionTableEntry == null)
|
||||
{
|
||||
builder.AppendLine(" [NULL]");
|
||||
builder.AppendLine(" [NULL]");
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.AppendLine(partitionTableEntry.Offset, " Offset");
|
||||
builder.AppendLine(partitionTableEntry.Length, " Length");
|
||||
builder.AppendLine(partitionTableEntry.Offset, " Offset");
|
||||
builder.AppendLine(partitionTableEntry.Length, " Length");
|
||||
}
|
||||
}
|
||||
builder.AppendLine();
|
||||
@@ -77,17 +77,17 @@ namespace SabreTools.Serialization.Printers
|
||||
builder.AppendLine(header.PartitionFlags, " Partition flags");
|
||||
builder.AppendLine();
|
||||
|
||||
builder.AppendLine(" Partition ID table:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
builder.AppendLine(" Partition ID table:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
if (header.PartitionIdTable == null || header.PartitionIdTable.Length == 0)
|
||||
{
|
||||
builder.AppendLine(" No partition ID table entries");
|
||||
builder.AppendLine(" No partition ID table entries");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < header.PartitionIdTable.Length; i++)
|
||||
{
|
||||
builder.AppendLine(header.PartitionIdTable[i], $" Partition {i} ID");
|
||||
builder.AppendLine(header.PartitionIdTable[i], $" Partition {i} ID");
|
||||
}
|
||||
}
|
||||
builder.AppendLine();
|
||||
@@ -146,62 +146,6 @@ namespace SabreTools.Serialization.Printers
|
||||
return;
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" Initial Data:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
if (header.InitialData == null)
|
||||
{
|
||||
builder.AppendLine(" No initial data");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine(header.InitialData.CardSeedKeyY, " Card seed keyY");
|
||||
builder.AppendLine(header.InitialData.EncryptedCardSeed, " Encrypted card seed");
|
||||
builder.AppendLine(header.InitialData.CardSeedAESMAC, " Card seed AES-MAC");
|
||||
builder.AppendLine(header.InitialData.CardSeedNonce, " Card seed nonce");
|
||||
builder.AppendLine(header.InitialData.Reserved, " Reserved");
|
||||
builder.AppendLine();
|
||||
|
||||
builder.AppendLine(" Backup Header:");
|
||||
builder.AppendLine(" -------------------------");
|
||||
if (header.InitialData.BackupHeader == null)
|
||||
{
|
||||
builder.AppendLine(" No backup header");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine(header.InitialData.BackupHeader.MagicID, " Magic ID");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ContentSizeInMediaUnits, " Content size in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.PartitionId, " Partition ID");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.MakerCode, " Maker code");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.Version, " Version");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.VerificationHash, " Verification hash");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ProgramId, " Program ID");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.Reserved1, " Reserved 1");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.LogoRegionHash, " Logo region SHA-256 hash");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ProductCode, " Product code");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ExtendedHeaderHash, " Extended header SHA-256 hash");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ExtendedHeaderSizeInBytes, " Extended header size in bytes");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.Reserved2, " Reserved 2");
|
||||
builder.AppendLine($" Flags: {header.InitialData.BackupHeader.Flags} (0x{header.InitialData.BackupHeader.Flags:X})");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.PlainRegionOffsetInMediaUnits, " Plain region offset, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.PlainRegionSizeInMediaUnits, " Plain region size, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.LogoRegionOffsetInMediaUnits, " Logo region offset, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.LogoRegionSizeInMediaUnits, " Logo region size, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ExeFSOffsetInMediaUnits, " ExeFS offset, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ExeFSSizeInMediaUnits, " ExeFS size, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ExeFSHashRegionSizeInMediaUnits, " ExeFS hash region size, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.Reserved3, " Reserved 3");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.RomFSOffsetInMediaUnits, " RomFS offset, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.RomFSSizeInMediaUnits, " RomFS size, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.RomFSHashRegionSizeInMediaUnits, " RomFS hash region size, in media units");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.Reserved4, " Reserved 4");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.ExeFSSuperblockHash, " ExeFS superblock SHA-256 hash");
|
||||
builder.AppendLine(header.InitialData.BackupHeader.RomFSSuperblockHash, " RomFS superblock SHA-256 hash");
|
||||
}
|
||||
}
|
||||
builder.AppendLine();
|
||||
|
||||
builder.AppendLine(header.CardDeviceReserved1, " Card device reserved 1");
|
||||
builder.AppendLine(header.TitleKey, " Title key");
|
||||
builder.AppendLine(header.CardDeviceReserved2, " Card device reserved 2");
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.7.0</Version>
|
||||
<Version>1.7.1</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
@@ -52,7 +52,7 @@
|
||||
<PackageReference Include="SabreTools.ASN1" Version="1.4.0" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.4.0" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.5.0" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.5.0" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.5.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.Models.N3DS;
|
||||
using static SabreTools.Models.N3DS.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
public class N3DS : WrapperBase<Models.N3DS.Cart>
|
||||
public class N3DS : WrapperBase<Cart>
|
||||
{
|
||||
#region Descriptive Properties
|
||||
|
||||
@@ -13,17 +14,180 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extension Properties
|
||||
|
||||
/// <summary>
|
||||
/// Backup Write Wait Time (The time to wait to write save to backup after the card is recognized (0-255
|
||||
/// seconds)). NATIVE_FIRM loads this flag from the gamecard NCSD header starting with 6.0.0-11.
|
||||
/// </summary>
|
||||
public byte BackupWriteWaitTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return Model.Header.PartitionFlags[(int)NCSDFlags.BackupWriteWaitTime];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (Only SDK 2.X)
|
||||
/// </summary>
|
||||
public MediaCardDeviceType MediaCardDevice2X
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaCardDeviceType)Model.Header.PartitionFlags[(int)NCSDFlags.MediaCardDevice2X];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (SDK 3.X+)
|
||||
/// </summary>
|
||||
public MediaCardDeviceType MediaCardDevice3X
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaCardDeviceType)Model.Header.PartitionFlags[(int)NCSDFlags.MediaCardDevice3X];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Platform Index (1 = CTR)
|
||||
/// </summary>
|
||||
public MediaPlatformIndex MediaPlatformIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaPlatformIndex)Model.Header.PartitionFlags[(int)NCSDFlags.MediaPlatformIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Type Index (0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device)
|
||||
/// </summary>
|
||||
public MediaTypeIndex MediaTypeIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaTypeIndex)Model.Header.PartitionFlags[(int)NCSDFlags.MediaTypeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media unit size in bytes
|
||||
/// </summary>
|
||||
public uint MediaUnitSize
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (uint)(0x200 * Math.Pow(2, Model.Header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
|
||||
}
|
||||
}
|
||||
|
||||
#region Partition Entries
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Executable Content (CXI)
|
||||
/// </summary>
|
||||
public PartitionTableEntry? ExecutableContentEntry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for E-Manual (CFA)
|
||||
/// </summary>
|
||||
public PartitionTableEntry? EManualEntry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Download Play Child container (CFA)
|
||||
/// </summary>
|
||||
public PartitionTableEntry? DownloadPlayChildContainerEntry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[2];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for New3DS Update Data (CFA)
|
||||
/// </summary>
|
||||
public PartitionTableEntry? New3DSUpdateDataEntry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[6];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Update Data (CFA)
|
||||
/// </summary>
|
||||
public PartitionTableEntry? UpdateDataEntry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[7];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <inheritdoc/>
|
||||
public N3DS(Models.N3DS.Cart? model, byte[]? data, int offset)
|
||||
public N3DS(Cart? model, byte[]? data, int offset)
|
||||
: base(model, data, offset)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public N3DS(Models.N3DS.Cart? model, Stream? data)
|
||||
public N3DS(Cart? model, Stream? data)
|
||||
: base(model, data)
|
||||
{
|
||||
// All logic is handled by the base class
|
||||
@@ -77,177 +241,273 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Hook these up for external use
|
||||
#region Currently Unused Extensions
|
||||
|
||||
#region ExeFSFileHeader
|
||||
#region Data
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a file header represents a CODE block
|
||||
/// </summary>
|
||||
public static bool IsCodeBinary(ExeFSFileHeader? header)
|
||||
public bool IsCodeBinary(int fsIndex, int headerIndex)
|
||||
{
|
||||
if (header == null)
|
||||
if (Model.ExeFSHeaders == null)
|
||||
return false;
|
||||
if (fsIndex < 0 || fsIndex >= Model.ExeFSHeaders.Length)
|
||||
return false;
|
||||
|
||||
return header.FileName == ".code\0\0\0";
|
||||
var fsHeader = Model.ExeFSHeaders[fsIndex];
|
||||
if (fsHeader?.FileHeaders == null)
|
||||
return false;
|
||||
|
||||
if (headerIndex < 0 || headerIndex >= fsHeader.FileHeaders.Length)
|
||||
return false;
|
||||
|
||||
var fileHeader = fsHeader.FileHeaders[headerIndex];
|
||||
if (fileHeader == null)
|
||||
return false;
|
||||
|
||||
return fileHeader.FileName == ".code\0\0\0";
|
||||
}
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Get the initial value for the plain counter
|
||||
/// </summary>
|
||||
public byte[] PlainIV(int partitionIndex)
|
||||
{
|
||||
if (Model.Partitions == null)
|
||||
return [];
|
||||
if (partitionIndex < 0 || partitionIndex >= Model.Partitions.Length)
|
||||
return [];
|
||||
|
||||
#region NCCHHeaderFlags
|
||||
var header = Model.Partitions[partitionIndex];
|
||||
if (header == null)
|
||||
return [];
|
||||
|
||||
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
|
||||
return [.. partitionIdBytes, .. PlainCounter];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the initial value for the ExeFS counter
|
||||
/// </summary>
|
||||
public byte[] ExeFSIV(int partitionIndex)
|
||||
{
|
||||
if (Model.Partitions == null)
|
||||
return [];
|
||||
if (partitionIndex < 0 || partitionIndex >= Model.Partitions.Length)
|
||||
return [];
|
||||
|
||||
var header = Model.Partitions[partitionIndex];
|
||||
if (header == null)
|
||||
return [];
|
||||
|
||||
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
|
||||
return [.. partitionIdBytes, .. ExefsCounter];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the initial value for the RomFS counter
|
||||
/// </summary>
|
||||
public byte[] RomFSIV(int partitionIndex)
|
||||
{
|
||||
if (Model.Partitions == null)
|
||||
return [];
|
||||
if (partitionIndex < 0 || partitionIndex >= Model.Partitions.Length)
|
||||
return [];
|
||||
|
||||
var header = Model.Partitions[partitionIndex];
|
||||
if (header == null)
|
||||
return [];
|
||||
|
||||
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
|
||||
return [.. partitionIdBytes, .. RomfsCounter];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get if the NoCrypto bit is set
|
||||
/// </summary>
|
||||
public static bool PossiblyDecrypted(NCCHHeaderFlags flags)
|
||||
public bool PossiblyDecrypted(int index)
|
||||
{
|
||||
if (flags == null)
|
||||
if (Model.Partitions == null)
|
||||
return false;
|
||||
|
||||
if (index < 0 || index >= Model.Partitions.Length)
|
||||
return false;
|
||||
|
||||
var partition = Model.Partitions[index];
|
||||
if (partition?.Flags == null)
|
||||
return false;
|
||||
|
||||
#if NET20 || NET35
|
||||
return (flags.BitMasks & BitMasks.NoCrypto) != 0;
|
||||
return (partition.Flags.BitMasks & BitMasks.NoCrypto) != 0;
|
||||
#else
|
||||
return flags.BitMasks.HasFlag(BitMasks.NoCrypto);
|
||||
return partition.Flags.BitMasks.HasFlag(BitMasks.NoCrypto);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region NCSDHeader
|
||||
#region Offsets
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Executable Content (CXI)
|
||||
/// Get the offset of a partition ExeFS
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? ExecutableContent(NCSDHeader? header)
|
||||
/// <returns>Offset to the ExeFS of the partition, 0 on error</returns>
|
||||
public uint GetExeFSOffset(int index)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
// Empty partitions table means no size is available
|
||||
var partitionsTable = Model.Header?.PartitionsTable;
|
||||
if (partitionsTable == null)
|
||||
return 0;
|
||||
|
||||
return header.PartitionsTable[0];
|
||||
// Invalid partition table entry means no size is available
|
||||
var entry = partitionsTable[index];
|
||||
if (entry == null)
|
||||
return 0;
|
||||
|
||||
// Empty partitions array means no size is available
|
||||
var partitions = Model.Partitions;
|
||||
if (partitions == null)
|
||||
return 0;
|
||||
|
||||
// Invalid partition means no size is available
|
||||
var header = partitions[index];
|
||||
if (header == null)
|
||||
return 0;
|
||||
|
||||
// If the offset is 0, return 0
|
||||
uint exeFsOffsetMU = header.ExeFSOffsetInMediaUnits;
|
||||
if (exeFsOffsetMU == 0)
|
||||
return 0;
|
||||
|
||||
// Return the adjusted offset
|
||||
uint partitionOffsetMU = entry.Offset;
|
||||
return (partitionOffsetMU + exeFsOffsetMU) * MediaUnitSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for E-Manual (CFA)
|
||||
/// Get the offset of a partition
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? EManual(NCSDHeader? header)
|
||||
/// <returns>Offset to the partition, 0 on error</returns>
|
||||
public uint GetPartitionOffset(int index)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
// Empty partitions table means no size is available
|
||||
var partitionsTable = Model.Header?.PartitionsTable;
|
||||
if (partitionsTable == null)
|
||||
return 0;
|
||||
|
||||
return header.PartitionsTable[1];
|
||||
// Invalid partition table entry means no size is available
|
||||
var entry = partitionsTable[index];
|
||||
if (entry == null)
|
||||
return 0;
|
||||
|
||||
// Return the adjusted offset
|
||||
uint partitionOffsetMU = entry.Offset;
|
||||
if (entry.Offset == 0)
|
||||
return 0;
|
||||
|
||||
// Return the adjusted offset
|
||||
return partitionOffsetMU * MediaUnitSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Download Play Child container (CFA)
|
||||
/// Get the offset of a partition RomFS
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? DownloadPlayChildContainer(NCSDHeader? header)
|
||||
/// <returns>Offset to the RomFS of the partition, 0 on error</returns>
|
||||
public uint GetRomFSOffset(int index)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
// Empty partitions table means no size is available
|
||||
var partitionsTable = Model.Header?.PartitionsTable;
|
||||
if (partitionsTable == null)
|
||||
return 0;
|
||||
|
||||
return header.PartitionsTable[2];
|
||||
}
|
||||
// Invalid partition table entry means no size is available
|
||||
var entry = partitionsTable[index];
|
||||
if (entry == null)
|
||||
return 0;
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for New3DS Update Data (CFA)
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? New3DSUpdateData(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
// Empty partitions array means no size is available
|
||||
var partitions = Model.Partitions;
|
||||
if (partitions == null)
|
||||
return 0;
|
||||
|
||||
return header.PartitionsTable[6];
|
||||
}
|
||||
// Invalid partition means no size is available
|
||||
var header = partitions[index];
|
||||
if (header == null)
|
||||
return 0;
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Update Data (CFA)
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? UpdateData(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionsTable == null)
|
||||
return null;
|
||||
// If the offset is 0, return 0
|
||||
uint romFsOffsetMU = header.RomFSOffsetInMediaUnits;
|
||||
if (romFsOffsetMU == 0)
|
||||
return 0;
|
||||
|
||||
return header.PartitionsTable[7];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Backup Write Wait Time (The time to wait to write save to backup after the card is recognized (0-255
|
||||
/// seconds)).NATIVE_FIRM loads this flag from the gamecard NCSD header starting with 6.0.0-11.
|
||||
/// </summary>
|
||||
public static byte BackupWriteWaitTime(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return header.PartitionFlags[(int)NCSDFlags.BackupWriteWaitTime];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (SDK 3.X+)
|
||||
/// </summary>
|
||||
public static MediaCardDeviceType MediaCardDevice3X(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaCardDeviceType)header.PartitionFlags[(int)NCSDFlags.MediaCardDevice3X];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Platform Index (1 = CTR)
|
||||
/// </summary>
|
||||
public static MediaPlatformIndex MediaPlatformIndex(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaPlatformIndex)header.PartitionFlags[(int)NCSDFlags.MediaPlatformIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Type Index (0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device)
|
||||
/// </summary>
|
||||
public static MediaTypeIndex MediaTypeIndex(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaTypeIndex)header.PartitionFlags[(int)NCSDFlags.MediaTypeIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6];
|
||||
/// </summary>
|
||||
public static uint MediaUnitSize(Cart cart)
|
||||
{
|
||||
return MediaUnitSize(cart.Header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6];
|
||||
/// </summary>
|
||||
public static uint MediaUnitSize(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (Only SDK 2.X)
|
||||
/// </summary>
|
||||
public static MediaCardDeviceType MediaCardDevice2X(NCSDHeader? header)
|
||||
{
|
||||
if (header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return (MediaCardDeviceType)header.PartitionFlags[(int)NCSDFlags.MediaCardDevice2X];
|
||||
// Return the adjusted offset
|
||||
uint partitionOffsetMU = entry.Offset;
|
||||
return (partitionOffsetMU + romFsOffsetMU) * MediaUnitSize;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sizes
|
||||
|
||||
/// <summary>
|
||||
/// Get the size of a partition ExeFS
|
||||
/// </summary>
|
||||
/// <returns>Size of the partition ExeFS in bytes, 0 on error</returns>
|
||||
public uint GetExeFSSize(int index)
|
||||
{
|
||||
// Empty partitions array means no size is available
|
||||
var partitions = Model.Partitions;
|
||||
if (partitions == null)
|
||||
return 0;
|
||||
|
||||
// Invalid partition header means no size is available
|
||||
var header = partitions[index];
|
||||
if (header == null)
|
||||
return 0;
|
||||
|
||||
// Return the adjusted size
|
||||
return header.ExeFSSizeInMediaUnits * MediaUnitSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the size of a partition extended header
|
||||
/// </summary>
|
||||
/// <returns>Size of the partition extended header in bytes, 0 on error</returns>
|
||||
public uint GetExtendedHeaderSize(int index)
|
||||
{
|
||||
// Empty partitions array means no size is available
|
||||
var partitions = Model.Partitions;
|
||||
if (partitions == null)
|
||||
return 0;
|
||||
|
||||
// Invalid partition header means no size is available
|
||||
var header = partitions[index];
|
||||
if (header == null)
|
||||
return 0;
|
||||
|
||||
// Return the adjusted size
|
||||
return header.ExtendedHeaderSizeInBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the size of a partition RomFS
|
||||
/// </summary>
|
||||
/// <returns>Size of the partition RomFS in bytes, 0 on error</returns>
|
||||
public uint GetRomFSSize(int index)
|
||||
{
|
||||
// Empty partitions array means no size is available
|
||||
var partitions = Model.Partitions;
|
||||
if (partitions == null)
|
||||
return 0;
|
||||
|
||||
// Invalid partition header means no size is available
|
||||
var header = partitions[index];
|
||||
if (header == null)
|
||||
return 0;
|
||||
|
||||
// Return the adjusted size
|
||||
return header.RomFSSizeInMediaUnits * MediaUnitSize;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user