Files
NDecrypt/NDecrypt.Core/N3DS/Extensions.cs

281 lines
8.4 KiB
C#
Raw Normal View History

2024-08-08 11:53:47 -04:00
using System;
using System.Numerics;
using SabreTools.Models.N3DS;
namespace NDecrypt.N3DS
{
internal static class Extensions
{
#region ExeFSFileHeader
/// <summary>
/// Determines if a file header represents a CODE block
/// </summary>
public static bool IsCodeBinary(this ExeFSFileHeader? header)
{
if (header == null)
return false;
return header.FileName == ".code\0\0\0";
}
#endregion
#region NCCHHeader
2024-08-08 15:49:36 -04:00
/// <summary>
/// Get the initial value for the plain counter
/// </summary>
public static byte[] PlainIV(this Cart cart, int partitionIndex)
{
if (cart.Partitions == null)
return [];
if (partitionIndex < 0 || partitionIndex >= cart.Partitions.Length)
return [];
var header = cart.Partitions[partitionIndex];
return PlainIV(header);
}
2024-08-08 11:53:47 -04:00
/// <summary>
/// Get the initial value for the plain counter
/// </summary>
public static byte[] PlainIV(this NCCHHeader? header)
{
if (header == null)
return [];
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
return [.. partitionIdBytes, .. Constants.PlainCounter];
}
/// <summary>
/// Get the initial value for the ExeFS counter
/// </summary>
2024-08-08 15:49:36 -04:00
public static byte[] ExeFSIV(this Cart cart, int partitionIndex)
2024-08-08 11:53:47 -04:00
{
2024-08-08 15:49:36 -04:00
if (cart.Partitions == null)
return [];
if (partitionIndex < 0 || partitionIndex >= cart.Partitions.Length)
2024-08-08 11:53:47 -04:00
return [];
2024-08-08 15:49:36 -04:00
var header = cart.Partitions[partitionIndex];
return ExeFSIV(header);
2024-08-08 11:53:47 -04:00
}
/// <summary>
2024-08-08 15:49:36 -04:00
/// Get the initial value for the ExeFS counter
2024-08-08 11:53:47 -04:00
/// </summary>
2024-08-08 15:49:36 -04:00
public static byte[] ExeFSIV(this NCCHHeader? header)
2024-08-08 11:53:47 -04:00
{
if (header == null)
return [];
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
2024-08-08 15:49:36 -04:00
return [.. partitionIdBytes, .. Constants.ExefsCounter];
2024-08-08 11:53:47 -04:00
}
/// <summary>
2024-08-08 15:49:36 -04:00
/// Get the initial value for the RomFS counter
2024-08-08 11:53:47 -04:00
/// </summary>
2024-08-08 15:49:36 -04:00
public static byte[] RomFSIV(this Cart cart, int partitionIndex)
{
if (cart.Partitions == null)
return [];
if (partitionIndex < 0 || partitionIndex >= cart.Partitions.Length)
return [];
2024-08-08 11:53:47 -04:00
2024-08-08 15:49:36 -04:00
var header = cart.Partitions[partitionIndex];
return RomFSIV(header);
}
2024-08-08 11:53:47 -04:00
/// <summary>
2024-08-08 15:49:36 -04:00
/// Get the initial value for the RomFS counter
2024-08-08 11:53:47 -04:00
/// </summary>
2024-08-08 15:49:36 -04:00
public static byte[] RomFSIV(this NCCHHeader? header)
{
if (header == null)
return [];
byte[] partitionIdBytes = BitConverter.GetBytes(header.PartitionId);
return [.. partitionIdBytes, .. Constants.RomfsCounter];
}
2024-08-08 11:53:47 -04:00
#endregion
#region NCCHHeaderFlags
/// <summary>
/// Get if the NoCrypto bit is set
/// </summary>
public static bool PossblyDecrypted(this NCCHHeaderFlags flags)
{
if (flags == null)
return false;
return flags.BitMasks.HasFlag(BitMasks.NoCrypto);
}
#endregion
#region NCSDHeader
/// <summary>
/// Partition table entry for Executable Content (CXI)
/// </summary>
public static PartitionTableEntry? ExecutableContent(this NCSDHeader? header)
{
if (header?.PartitionsTable == null)
return null;
return header.PartitionsTable[0];
}
/// <summary>
/// Partition table entry for E-Manual (CFA)
/// </summary>
public static PartitionTableEntry? EManual(this NCSDHeader? header)
{
if (header?.PartitionsTable == null)
return null;
return header.PartitionsTable[1];
}
/// <summary>
/// Partition table entry for Download Play Child container (CFA)
/// </summary>
public static PartitionTableEntry? DownloadPlayChildContainer(this NCSDHeader? header)
{
if (header?.PartitionsTable == null)
return null;
return header.PartitionsTable[2];
}
/// <summary>
/// Partition table entry for New3DS Update Data (CFA)
/// </summary>
public static PartitionTableEntry? New3DSUpdateData(this NCSDHeader? header)
{
if (header?.PartitionsTable == null)
return null;
return header.PartitionsTable[6];
}
/// <summary>
/// Partition table entry for Update Data (CFA)
/// </summary>
public static PartitionTableEntry? UpdateData(this NCSDHeader? header)
{
if (header?.PartitionsTable == null)
return null;
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(this 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(this 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(this 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(this NCSDHeader? header)
{
if (header?.PartitionFlags == null)
return default;
return (MediaTypeIndex)header.PartitionFlags[(int)NCSDFlags.MediaTypeIndex];
}
2024-08-08 15:49:36 -04:00
/// <summary>
/// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6];
/// </summary>
public static uint MediaUnitSize(this Cart cart)
{
return cart.Header.MediaUnitSize();
}
2024-08-08 11:53:47 -04:00
/// <summary>
/// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6];
/// </summary>
public static uint MediaUnitSize(this 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(this NCSDHeader? header)
{
if (header?.PartitionFlags == null)
return default;
return (MediaCardDeviceType)header.PartitionFlags[(int)NCSDFlags.MediaCardDevice2X];
}
#endregion
#region Ticket
/// <summary>
/// Denotes if the ticket denotes a demo or not
/// </summary>
public static bool IsDemo(this Ticket? ticket)
{
if (ticket?.Limits == null || ticket.Limits.Length == 0)
return false;
return ticket.Limits[0] == 0x0004;
}
/// <summary>
/// Denotes if the max playcount for a demo
/// </summary>
public static uint PlayCount(this Ticket ticket)
{
if (ticket?.Limits == null || ticket.Limits.Length == 0)
return 0;
return ticket.Limits[1];
}
#endregion
}
}