mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-22 23:05:12 +00:00
Start making fixes to N3DS
This commit is contained in:
@@ -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,34 @@ 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)
|
||||
{
|
||||
// TODO: Go back to `data.ReadType<DevelopmentCardInfoHeader>();` when Models is fixed
|
||||
var header = new DevelopmentCardInfoHeader();
|
||||
|
||||
header.CardDeviceReserved1 = data.ReadBytes(0x200);
|
||||
header.TitleKey = data.ReadBytes(0x10);
|
||||
header.CardDeviceReserved2 = data.ReadBytes(0x1BF0);
|
||||
header.TestData = ParseTestData(data);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into test data
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled test data on success, null on error</returns>
|
||||
public static TestData? ParseTestData(Stream data)
|
||||
{
|
||||
return data.ReadType<TestData>();
|
||||
}
|
||||
|
||||
/// <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");
|
||||
|
||||
@@ -13,6 +13,169 @@ 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/>
|
||||
@@ -77,177 +240,54 @@ 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;
|
||||
|
||||
var fsHeader = Model.ExeFSHeaders[fsIndex];
|
||||
if (fsHeader?.FileHeaders == null)
|
||||
return false;
|
||||
|
||||
return header.FileName == ".code\0\0\0";
|
||||
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
|
||||
|
||||
#region NCCHHeaderFlags
|
||||
|
||||
/// <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
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Executable Content (CXI)
|
||||
/// </summary>
|
||||
public static PartitionTableEntry? ExecutableContent(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(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(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(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(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(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];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user