mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-02-04 05:36:12 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
695309bc32 | ||
|
|
97b2f68ec7 | ||
|
|
593044dbf3 | ||
|
|
1fcf44fb8d | ||
|
|
a2a472baf9 | ||
|
|
b5b4a50d94 | ||
|
|
f1b5464052 | ||
|
|
2c0224db22 | ||
|
|
1e78eecb40 | ||
|
|
3626faea60 | ||
|
|
a0177f1174 | ||
|
|
db5fe4a2cd |
@@ -9,7 +9,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.7.0</Version>
|
||||
<Version>1.7.4</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Support All Frameworks -->
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
return null;
|
||||
|
||||
// Cache the current offset
|
||||
int initialOffset = (int)data.Position;
|
||||
long initialOffset = data.Position;
|
||||
|
||||
// Create a new cart image to fill
|
||||
var cart = new Cart();
|
||||
@@ -62,118 +62,74 @@ namespace SabreTools.Serialization.Deserializers
|
||||
|
||||
#endregion
|
||||
|
||||
#region Partitions
|
||||
|
||||
// Create the partition table
|
||||
cart.Partitions = new NCCHHeader[8];
|
||||
|
||||
// Iterate and build the partitions
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
cart.Partitions[i] = ParseNCCHHeader(data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// Cache the media unit size for further use
|
||||
long mediaUnitSize = 0;
|
||||
if (header.PartitionFlags != null)
|
||||
mediaUnitSize = (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
|
||||
|
||||
#region Extended Headers
|
||||
#region Partitions
|
||||
|
||||
// Create the extended header table
|
||||
// Create the tables
|
||||
cart.Partitions = new NCCHHeader[8];
|
||||
cart.ExtendedHeaders = 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;
|
||||
|
||||
// If we have no partitions table
|
||||
if (cart.Header!.PartitionsTable == null)
|
||||
continue;
|
||||
|
||||
// Get the extended header offset
|
||||
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
|
||||
var extendedHeader = ParseNCCHExtendedHeader(data);
|
||||
if (extendedHeader != null)
|
||||
cart.ExtendedHeaders[i] = extendedHeader;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ExeFS Headers
|
||||
|
||||
// Create the ExeFS header table
|
||||
cart.ExeFSHeaders = new ExeFSHeader?[8];
|
||||
|
||||
// Iterate and build the ExeFS headers
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// If we have an encrypted or invalid partition
|
||||
if (cart.Partitions[i]!.MagicID != NCCHMagicNumber)
|
||||
continue;
|
||||
|
||||
// If we have no partitions table
|
||||
if (cart.Header!.PartitionsTable == null)
|
||||
continue;
|
||||
|
||||
// Get the ExeFS header offset
|
||||
long offset = (cart.Header.PartitionsTable[i]!.Offset + cart.Partitions[i]!.ExeFSOffsetInMediaUnits) * mediaUnitSize;
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
continue;
|
||||
|
||||
// Seek to the ExeFS header
|
||||
data.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
// Parse the ExeFS header
|
||||
var exeFsHeader = ParseExeFSHeader(data);
|
||||
if (exeFsHeader == null)
|
||||
return null;
|
||||
|
||||
cart.ExeFSHeaders[i] = exeFsHeader;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RomFS Headers
|
||||
|
||||
// Create the RomFS header table
|
||||
cart.RomFSHeaders = new RomFSHeader?[8];
|
||||
|
||||
// Iterate and build the RomFS headers
|
||||
// Iterate and build the partitions
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// If we have an encrypted or invalid partition
|
||||
if (cart.Partitions[i]!.MagicID != NCCHMagicNumber)
|
||||
// Find the offset to the partition
|
||||
long partitionOffset = cart.Header.PartitionsTable?[i]?.Offset ?? 0;
|
||||
partitionOffset *= mediaUnitSize;
|
||||
if (partitionOffset == 0)
|
||||
continue;
|
||||
|
||||
// If we have no partitions table
|
||||
if (cart.Header!.PartitionsTable == null)
|
||||
// Seek to the start of the partition
|
||||
data.Seek(partitionOffset, SeekOrigin.Begin);
|
||||
|
||||
// Handle the normal header
|
||||
var partition = ParseNCCHHeader(data);
|
||||
if (partition == null || partition.MagicID != NCCHMagicNumber)
|
||||
continue;
|
||||
|
||||
// Get the RomFS header offset
|
||||
long offset = (cart.Header.PartitionsTable[i]!.Offset + cart.Partitions[i]!.RomFSOffsetInMediaUnits) * mediaUnitSize;
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
continue;
|
||||
// Set the normal header
|
||||
cart.Partitions[i] = partition;
|
||||
|
||||
// Seek to the RomFS header
|
||||
data.Seek(offset, SeekOrigin.Begin);
|
||||
// Handle the extended header, if it exists
|
||||
if (partition.ExtendedHeaderSizeInBytes > 0)
|
||||
{
|
||||
var extendedHeader = ParseNCCHExtendedHeader(data);
|
||||
if (extendedHeader != null)
|
||||
cart.ExtendedHeaders[i] = extendedHeader;
|
||||
}
|
||||
|
||||
// Handle the ExeFS, if it exists
|
||||
if (partition.ExeFSSizeInMediaUnits > 0)
|
||||
{
|
||||
long offset = partition.ExeFSOffsetInMediaUnits * mediaUnitSize;
|
||||
data.Seek(partitionOffset + offset, SeekOrigin.Begin);
|
||||
|
||||
var exeFsHeader = ParseExeFSHeader(data);
|
||||
if (exeFsHeader == null)
|
||||
return null;
|
||||
|
||||
cart.ExeFSHeaders[i] = exeFsHeader;
|
||||
}
|
||||
|
||||
// Handle the RomFS, if it exists
|
||||
if (partition.RomFSSizeInMediaUnits > 0)
|
||||
{
|
||||
long offset = partition.RomFSOffsetInMediaUnits * mediaUnitSize;
|
||||
data.Seek(partitionOffset + offset, SeekOrigin.Begin);
|
||||
|
||||
var romFsHeader = ParseRomFSHeader(data);
|
||||
if (romFsHeader == null)
|
||||
continue;
|
||||
else if (romFsHeader.MagicString != RomFSMagicNumber || romFsHeader.MagicNumber != RomFSSecondMagicNumber)
|
||||
continue;
|
||||
|
||||
// Parse the RomFS header
|
||||
var romFsHeader = ParseRomFSHeader(data);
|
||||
if (romFsHeader != null)
|
||||
cart.RomFSHeaders[i] = romFsHeader;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -375,7 +331,51 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <returns>Filled NCCH extended header on success, null on error</returns>
|
||||
public static NCCHExtendedHeader? ParseNCCHExtendedHeader(Stream data)
|
||||
{
|
||||
return data.ReadType<NCCHExtendedHeader>();
|
||||
// TODO: Replace with `data.ReadType<NCCHExtendedHeader>();` when enum serialization fixed
|
||||
var header = new NCCHExtendedHeader();
|
||||
|
||||
header.SCI = data.ReadType<SystemControlInfo>();
|
||||
header.ACI = ParseAccessControlInfo(data);
|
||||
header.AccessDescSignature = data.ReadBytes(0x100);
|
||||
header.NCCHHDRPublicKey = data.ReadBytes(0x100);
|
||||
header.ACIForLimitations = ParseAccessControlInfo(data);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an access control info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled access control info on success, null on error</returns>
|
||||
public static AccessControlInfo? ParseAccessControlInfo(Stream data)
|
||||
{
|
||||
var aci = new AccessControlInfo();
|
||||
|
||||
aci.ARM11LocalSystemCapabilities = data.ReadType<ARM11LocalSystemCapabilities>();
|
||||
aci.ARM11KernelCapabilities = data.ReadType<ARM11KernelCapabilities>();
|
||||
aci.ARM9AccessControl = ParseARM9AccessControl(data);
|
||||
|
||||
return aci;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an ARM9 access control
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ARM9 access control on success, null on error</returns>
|
||||
public static ARM9AccessControl? ParseARM9AccessControl(Stream data)
|
||||
{
|
||||
var a9ac = new ARM9AccessControl();
|
||||
|
||||
a9ac.Descriptors = new ARM9AccessControlDescriptors[15];
|
||||
for (int i = 0; i < a9ac.Descriptors.Length; i++)
|
||||
{
|
||||
a9ac.Descriptors[i] = (ARM9AccessControlDescriptors)data.ReadByteValue();
|
||||
}
|
||||
a9ac.DescriptorVersion = data.ReadByteValue();
|
||||
|
||||
return a9ac;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using SabreTools.Models.N3DS;
|
||||
using SabreTools.Serialization.Interfaces;
|
||||
@@ -491,14 +492,20 @@ namespace SabreTools.Serialization.Printers
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($" Descriptors: {entry.ACI.ARM9AccessControl.Descriptors} (0x{entry.ACI.ARM9AccessControl.Descriptors:X})");
|
||||
string descriptorsStr = "[NULL]";
|
||||
if (entry.ACI.ARM9AccessControl.Descriptors != null)
|
||||
{
|
||||
var descriptors = Array.ConvertAll(entry.ACI.ARM9AccessControl.Descriptors, d => d.ToString());
|
||||
descriptorsStr = string.Join(", ", descriptors);
|
||||
}
|
||||
builder.AppendLine(descriptorsStr, " Descriptors");
|
||||
builder.AppendLine(entry.ACI.ARM9AccessControl.DescriptorVersion, " Descriptor version");
|
||||
}
|
||||
|
||||
builder.AppendLine(entry.AccessDescSignature, " AccessDec signature (RSA-2048-SHA256)");
|
||||
builder.AppendLine(entry.NCCHHDRPublicKey, " NCCH HDR RSA-2048 public key");
|
||||
}
|
||||
|
||||
builder.AppendLine(entry.AccessDescSignature, " AccessDec signature (RSA-2048-SHA256)");
|
||||
builder.AppendLine(entry.NCCHHDRPublicKey, " NCCH HDR RSA-2048 public key");
|
||||
|
||||
builder.AppendLine(" Access control info (for limitations of first ACI):");
|
||||
if (entry.ACIForLimitations == null)
|
||||
{
|
||||
@@ -559,7 +566,13 @@ namespace SabreTools.Serialization.Printers
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($" Descriptors: {entry.ACIForLimitations.ARM9AccessControl.Descriptors} (0x{entry.ACIForLimitations.ARM9AccessControl.Descriptors:X})");
|
||||
string descriptorsStr = "[NULL]";
|
||||
if (entry.ACIForLimitations.ARM9AccessControl.Descriptors != null)
|
||||
{
|
||||
var descriptors = Array.ConvertAll(entry.ACIForLimitations.ARM9AccessControl.Descriptors, d => d.ToString());
|
||||
descriptorsStr = string.Join(", ", descriptors);
|
||||
}
|
||||
builder.AppendLine(descriptorsStr, " Descriptors");
|
||||
builder.AppendLine(entry.ACIForLimitations.ARM9AccessControl.DescriptorVersion, " Descriptor version");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.7.1</Version>
|
||||
<Version>1.7.4</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
|
||||
@@ -17,76 +17,15 @@ namespace SabreTools.Serialization.Wrappers
|
||||
#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.
|
||||
/// Backup header
|
||||
/// </summary>
|
||||
public byte BackupWriteWaitTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionFlags == null)
|
||||
return default;
|
||||
|
||||
return Model.Header.PartitionFlags[(int)NCSDFlags.BackupWriteWaitTime];
|
||||
}
|
||||
}
|
||||
public NCCHHeader? BackupHeader => Model.CardInfoHeader?.InitialData?.BackupHeader;
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (Only SDK 2.X)
|
||||
/// ExeFS headers
|
||||
/// </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];
|
||||
}
|
||||
}
|
||||
|
||||
public ExeFSHeader?[] ExeFSHeaders => Model.ExeFSHeaders ?? [];
|
||||
|
||||
/// <summary>
|
||||
/// Media unit size in bytes
|
||||
/// </summary>
|
||||
@@ -101,7 +40,17 @@ namespace SabreTools.Serialization.Wrappers
|
||||
}
|
||||
}
|
||||
|
||||
#region Partition Entries
|
||||
/// <summary>
|
||||
/// Partitions data table
|
||||
/// </summary>
|
||||
public NCCHHeader?[] Partitions => Model.Partitions ?? [];
|
||||
|
||||
/// <summary>
|
||||
/// Partitions header table
|
||||
/// </summary>
|
||||
public PartitionTableEntry?[] PartitionsTable => Model.Header?.PartitionsTable ?? [];
|
||||
|
||||
#region Named Partition Entries
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Executable Content (CXI)
|
||||
@@ -110,10 +59,10 @@ namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
if (PartitionsTable == null || PartitionsTable.Length == 0)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[0];
|
||||
return PartitionsTable[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,10 +73,10 @@ namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
if (PartitionsTable == null || PartitionsTable.Length == 0)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[1];
|
||||
return PartitionsTable[1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,10 +87,10 @@ namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
if (PartitionsTable == null || PartitionsTable.Length == 0)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[2];
|
||||
return PartitionsTable[2];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,10 +101,10 @@ namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
if (PartitionsTable == null || PartitionsTable.Length == 0)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[6];
|
||||
return PartitionsTable[6];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,10 +115,90 @@ namespace SabreTools.Serialization.Wrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Model.Header?.PartitionsTable == null)
|
||||
if (PartitionsTable == null || PartitionsTable.Length == 0)
|
||||
return null;
|
||||
|
||||
return Model.Header.PartitionsTable[7];
|
||||
return PartitionsTable[7];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Partitions flags
|
||||
/// </summary>
|
||||
public byte[] PartitionFlags => Model.Header?.PartitionFlags ?? [];
|
||||
|
||||
#region Partition Flags
|
||||
|
||||
/// <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 (PartitionFlags == null || PartitionFlags.Length == 0)
|
||||
return default;
|
||||
|
||||
return 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 (PartitionFlags == null || PartitionFlags.Length == 0)
|
||||
return default;
|
||||
|
||||
return (MediaCardDeviceType)PartitionFlags[(int)NCSDFlags.MediaCardDevice2X];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (SDK 3.X+)
|
||||
/// </summary>
|
||||
public MediaCardDeviceType MediaCardDevice3X
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PartitionFlags == null || PartitionFlags.Length == 0)
|
||||
return default;
|
||||
|
||||
return (MediaCardDeviceType)PartitionFlags[(int)NCSDFlags.MediaCardDevice3X];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Platform Index (1 = CTR)
|
||||
/// </summary>
|
||||
public MediaPlatformIndex MediaPlatformIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PartitionFlags == null || PartitionFlags.Length == 0)
|
||||
return default;
|
||||
|
||||
return (MediaPlatformIndex)PartitionFlags[(int)NCSDFlags.MediaPlatformIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media Type Index (0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device)
|
||||
/// </summary>
|
||||
public MediaTypeIndex MediaTypeIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PartitionFlags == null || PartitionFlags.Length == 0)
|
||||
return default;
|
||||
|
||||
return (MediaTypeIndex)PartitionFlags[(int)NCSDFlags.MediaTypeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,17 +272,51 @@ namespace SabreTools.Serialization.Wrappers
|
||||
|
||||
#region Data
|
||||
|
||||
/// <summary>
|
||||
/// Get the bit masks for a partition
|
||||
/// </summary>
|
||||
public BitMasks GetBitMasks(int index)
|
||||
{
|
||||
if (Partitions == null)
|
||||
return 0;
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return 0;
|
||||
|
||||
var partition = Partitions[index];
|
||||
if (partition?.Flags == null)
|
||||
return 0;
|
||||
|
||||
return partition.Flags.BitMasks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the crypto method for a partition
|
||||
/// </summary>
|
||||
public CryptoMethod GetCryptoMethod(int index)
|
||||
{
|
||||
if (Partitions == null)
|
||||
return 0;
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return 0;
|
||||
|
||||
var partition = Partitions[index];
|
||||
if (partition?.Flags == null)
|
||||
return 0;
|
||||
|
||||
return partition.Flags.CryptoMethod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a file header represents a CODE block
|
||||
/// </summary>
|
||||
public bool IsCodeBinary(int fsIndex, int headerIndex)
|
||||
{
|
||||
if (Model.ExeFSHeaders == null)
|
||||
if (ExeFSHeaders == null)
|
||||
return false;
|
||||
if (fsIndex < 0 || fsIndex >= Model.ExeFSHeaders.Length)
|
||||
if (fsIndex < 0 || fsIndex >= ExeFSHeaders.Length)
|
||||
return false;
|
||||
|
||||
var fsHeader = Model.ExeFSHeaders[fsIndex];
|
||||
var fsHeader = ExeFSHeaders[fsIndex];
|
||||
if (fsHeader?.FileHeaders == null)
|
||||
return false;
|
||||
|
||||
@@ -264,60 +327,63 @@ namespace SabreTools.Serialization.Wrappers
|
||||
if (fileHeader == null)
|
||||
return false;
|
||||
|
||||
return fileHeader.FileName == ".code\0\0\0";
|
||||
return fileHeader.FileName == ".code";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the initial value for the plain counter
|
||||
/// </summary>
|
||||
public byte[] PlainIV(int partitionIndex)
|
||||
public byte[] PlainIV(int index)
|
||||
{
|
||||
if (Model.Partitions == null)
|
||||
if (Partitions == null)
|
||||
return [];
|
||||
if (partitionIndex < 0 || partitionIndex >= Model.Partitions.Length)
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return [];
|
||||
|
||||
var header = Model.Partitions[partitionIndex];
|
||||
if (header == null)
|
||||
var header = Partitions[index];
|
||||
if (header == null || header.MagicID != NCCHMagicNumber)
|
||||
return [];
|
||||
|
||||
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
|
||||
Array.Reverse(partitionIdBytes);
|
||||
return [.. partitionIdBytes, .. PlainCounter];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the initial value for the ExeFS counter
|
||||
/// </summary>
|
||||
public byte[] ExeFSIV(int partitionIndex)
|
||||
public byte[] ExeFSIV(int index)
|
||||
{
|
||||
if (Model.Partitions == null)
|
||||
if (Partitions == null)
|
||||
return [];
|
||||
if (partitionIndex < 0 || partitionIndex >= Model.Partitions.Length)
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return [];
|
||||
|
||||
var header = Model.Partitions[partitionIndex];
|
||||
if (header == null)
|
||||
var header = Partitions[index];
|
||||
if (header == null || header.MagicID != NCCHMagicNumber)
|
||||
return [];
|
||||
|
||||
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
|
||||
Array.Reverse(partitionIdBytes);
|
||||
return [.. partitionIdBytes, .. ExefsCounter];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the initial value for the RomFS counter
|
||||
/// </summary>
|
||||
public byte[] RomFSIV(int partitionIndex)
|
||||
public byte[] RomFSIV(int index)
|
||||
{
|
||||
if (Model.Partitions == null)
|
||||
if (Partitions == null)
|
||||
return [];
|
||||
if (partitionIndex < 0 || partitionIndex >= Model.Partitions.Length)
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return [];
|
||||
|
||||
var header = Model.Partitions[partitionIndex];
|
||||
if (header == null)
|
||||
var header = Partitions[index];
|
||||
if (header == null || header.MagicID != NCCHMagicNumber)
|
||||
return [];
|
||||
|
||||
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
|
||||
Array.Reverse(partitionIdBytes);
|
||||
return [.. partitionIdBytes, .. RomfsCounter];
|
||||
}
|
||||
|
||||
@@ -326,20 +392,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// </summary>
|
||||
public bool PossiblyDecrypted(int index)
|
||||
{
|
||||
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;
|
||||
|
||||
var bitMasks = GetBitMasks(index);
|
||||
#if NET20 || NET35
|
||||
return (partition.Flags.BitMasks & BitMasks.NoCrypto) != 0;
|
||||
return (bitMasks & BitMasks.NoCrypto) != 0;
|
||||
#else
|
||||
return partition.Flags.BitMasks.HasFlag(BitMasks.NoCrypto);
|
||||
return bitMasks.HasFlag(BitMasks.NoCrypto);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -353,24 +410,20 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <returns>Offset to the ExeFS of the partition, 0 on error</returns>
|
||||
public uint GetExeFSOffset(int index)
|
||||
{
|
||||
// Empty partitions table means no size is available
|
||||
var partitionsTable = Model.Header?.PartitionsTable;
|
||||
if (partitionsTable == null)
|
||||
// No partitions means no size is available
|
||||
if (PartitionsTable == null || Partitions == null)
|
||||
return 0;
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return 0;
|
||||
|
||||
// Invalid partition table entry means no size is available
|
||||
var entry = partitionsTable[index];
|
||||
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)
|
||||
var header = Partitions[index];
|
||||
if (header == null || header.MagicID != NCCHMagicNumber)
|
||||
return 0;
|
||||
|
||||
// If the offset is 0, return 0
|
||||
@@ -389,13 +442,14 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <returns>Offset to the partition, 0 on error</returns>
|
||||
public uint GetPartitionOffset(int index)
|
||||
{
|
||||
// Empty partitions table means no size is available
|
||||
var partitionsTable = Model.Header?.PartitionsTable;
|
||||
if (partitionsTable == null)
|
||||
// No partitions means no size is available
|
||||
if (PartitionsTable == null)
|
||||
return 0;
|
||||
if (index < 0 || index >= PartitionsTable.Length)
|
||||
return 0;
|
||||
|
||||
// Invalid partition table entry means no size is available
|
||||
var entry = partitionsTable[index];
|
||||
var entry = PartitionsTable[index];
|
||||
if (entry == null)
|
||||
return 0;
|
||||
|
||||
@@ -414,24 +468,20 @@ namespace SabreTools.Serialization.Wrappers
|
||||
/// <returns>Offset to the RomFS of the partition, 0 on error</returns>
|
||||
public uint GetRomFSOffset(int index)
|
||||
{
|
||||
// Empty partitions table means no size is available
|
||||
var partitionsTable = Model.Header?.PartitionsTable;
|
||||
if (partitionsTable == null)
|
||||
// No partitions means no size is available
|
||||
if (PartitionsTable == null || Partitions == null)
|
||||
return 0;
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return 0;
|
||||
|
||||
// Invalid partition table entry means no size is available
|
||||
var entry = partitionsTable[index];
|
||||
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)
|
||||
var header = Partitions[index];
|
||||
if (header == null || header.MagicID != NCCHMagicNumber)
|
||||
return 0;
|
||||
|
||||
// If the offset is 0, return 0
|
||||
@@ -455,12 +505,13 @@ namespace SabreTools.Serialization.Wrappers
|
||||
public uint GetExeFSSize(int index)
|
||||
{
|
||||
// Empty partitions array means no size is available
|
||||
var partitions = Model.Partitions;
|
||||
if (partitions == null)
|
||||
if (Partitions == null)
|
||||
return 0;
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return 0;
|
||||
|
||||
// Invalid partition header means no size is available
|
||||
var header = partitions[index];
|
||||
var header = Partitions[index];
|
||||
if (header == null)
|
||||
return 0;
|
||||
|
||||
@@ -475,12 +526,13 @@ namespace SabreTools.Serialization.Wrappers
|
||||
public uint GetExtendedHeaderSize(int index)
|
||||
{
|
||||
// Empty partitions array means no size is available
|
||||
var partitions = Model.Partitions;
|
||||
if (partitions == null)
|
||||
if (Partitions == null)
|
||||
return 0;
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return 0;
|
||||
|
||||
// Invalid partition header means no size is available
|
||||
var header = partitions[index];
|
||||
var header = Partitions[index];
|
||||
if (header == null)
|
||||
return 0;
|
||||
|
||||
@@ -495,12 +547,13 @@ namespace SabreTools.Serialization.Wrappers
|
||||
public uint GetRomFSSize(int index)
|
||||
{
|
||||
// Empty partitions array means no size is available
|
||||
var partitions = Model.Partitions;
|
||||
if (partitions == null)
|
||||
if (Partitions == null)
|
||||
return 0;
|
||||
if (index < 0 || index >= Partitions.Length)
|
||||
return 0;
|
||||
|
||||
// Invalid partition header means no size is available
|
||||
var header = partitions[index];
|
||||
var header = Partitions[index];
|
||||
if (header == null)
|
||||
return 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user