mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-22 23:05:12 +00:00
Handle more directly-marshalled types
This commit is contained in:
@@ -85,7 +85,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled file entry on success, null on error</returns>
|
||||
private static FileEntry ParseFileEntry(Stream data)
|
||||
private static FileEntry? ParseFileEntry(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var fileEntry = new FileEntry();
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
#region DIFAT Sector Numbers
|
||||
|
||||
// Create a DIFAT sector table
|
||||
var difatSectors = new List<SectorNumber?>();
|
||||
var difatSectors = new List<SectorNumber>();
|
||||
|
||||
// Add the sectors from the header
|
||||
if (fileHeader.DIFAT != null)
|
||||
@@ -84,7 +84,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
#region FAT Sector Numbers
|
||||
|
||||
// Create a FAT sector table
|
||||
var fatSectors = new List<SectorNumber?>();
|
||||
var fatSectors = new List<SectorNumber>();
|
||||
|
||||
// Loop through and add the FAT sectors
|
||||
currentSector = binary.DIFATSectorNumbers[0];
|
||||
@@ -122,7 +122,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
#region Mini FAT Sector Numbers
|
||||
|
||||
// Create a mini FAT sector table
|
||||
var miniFatSectors = new List<SectorNumber?>();
|
||||
var miniFatSectors = new List<SectorNumber>();
|
||||
|
||||
// Loop through and add the mini FAT sectors
|
||||
currentSector = (SectorNumber)fileHeader.FirstMiniFATSectorLocation;
|
||||
@@ -233,49 +233,23 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <returns>Filled file header on success, null on error</returns>
|
||||
private static FileHeader? ParseFileHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var header = new FileHeader();
|
||||
var header = data.ReadType<FileHeader>();
|
||||
|
||||
header.Signature = data.ReadUInt64();
|
||||
if (header == null)
|
||||
return null;
|
||||
if (header.Signature != SignatureUInt64)
|
||||
return null;
|
||||
|
||||
header.CLSID = data.ReadGuid();
|
||||
header.MinorVersion = data.ReadUInt16();
|
||||
header.MajorVersion = data.ReadUInt16();
|
||||
header.ByteOrder = data.ReadUInt16();
|
||||
if (header.ByteOrder != 0xFFFE)
|
||||
return null;
|
||||
|
||||
header.SectorShift = data.ReadUInt16();
|
||||
if (header.MajorVersion == 3 && header.SectorShift != 0x0009)
|
||||
return null;
|
||||
else if (header.MajorVersion == 4 && header.SectorShift != 0x000C)
|
||||
return null;
|
||||
|
||||
header.MiniSectorShift = data.ReadUInt16();
|
||||
header.Reserved = data.ReadBytes(6);
|
||||
header.NumberOfDirectorySectors = data.ReadUInt32();
|
||||
if (header.MajorVersion == 3 && header.NumberOfDirectorySectors != 0)
|
||||
return null;
|
||||
|
||||
header.NumberOfFATSectors = data.ReadUInt32();
|
||||
header.FirstDirectorySectorLocation = data.ReadUInt32();
|
||||
header.TransactionSignatureNumber = data.ReadUInt32();
|
||||
header.MiniStreamCutoffSize = data.ReadUInt32();
|
||||
if (header.MiniStreamCutoffSize != 0x00001000)
|
||||
return null;
|
||||
|
||||
header.FirstMiniFATSectorLocation = data.ReadUInt32();
|
||||
header.NumberOfMiniFATSectors = data.ReadUInt32();
|
||||
header.FirstDIFATSectorLocation = data.ReadUInt32();
|
||||
header.NumberOfDIFATSectors = data.ReadUInt32();
|
||||
header.DIFAT = new SectorNumber?[109];
|
||||
for (int i = 0; i < header.DIFAT.Length; i++)
|
||||
{
|
||||
header.DIFAT[i] = (SectorNumber)data.ReadUInt32();
|
||||
}
|
||||
|
||||
// Skip rest of sector for version 4
|
||||
if (header.MajorVersion == 4)
|
||||
_ = data.ReadBytes(3584);
|
||||
@@ -289,11 +263,11 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="sectorShift">Sector shift from the header</param>
|
||||
/// <returns>Filled sector full of sector numbers on success, null on error</returns>
|
||||
private static SectorNumber?[] ParseSectorNumbers(Stream data, ushort sectorShift)
|
||||
private static SectorNumber[] ParseSectorNumbers(Stream data, ushort sectorShift)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
int sectorCount = (int)(Math.Pow(2, sectorShift) / sizeof(uint));
|
||||
var sectorNumbers = new SectorNumber?[sectorCount];
|
||||
var sectorNumbers = new SectorNumber[sectorCount];
|
||||
|
||||
for (int i = 0; i < sectorNumbers.Length; i++)
|
||||
{
|
||||
@@ -337,24 +311,15 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <returns>Filled directory entry on success, null on error</returns>
|
||||
private static DirectoryEntry? ParseDirectoryEntry(Stream data, ushort majorVersion)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var directoryEntry = new DirectoryEntry();
|
||||
var directoryEntry = data.ReadType<DirectoryEntry>();
|
||||
|
||||
byte[]? name = data.ReadBytes(64);
|
||||
if (name != null)
|
||||
directoryEntry.Name = Encoding.Unicode.GetString(name).TrimEnd('\0');
|
||||
directoryEntry.NameLength = data.ReadUInt16();
|
||||
directoryEntry.ObjectType = (ObjectType)data.ReadByteValue();
|
||||
directoryEntry.ColorFlag = (ColorFlag)data.ReadByteValue();
|
||||
directoryEntry.LeftSiblingID = (StreamID)data.ReadUInt32();
|
||||
directoryEntry.RightSiblingID = (StreamID)data.ReadUInt32();
|
||||
directoryEntry.ChildID = (StreamID)data.ReadUInt32();
|
||||
directoryEntry.CLSID = data.ReadGuid();
|
||||
directoryEntry.StateBits = data.ReadUInt32();
|
||||
directoryEntry.CreationTime = data.ReadUInt64();
|
||||
directoryEntry.ModifiedTime = data.ReadUInt64();
|
||||
directoryEntry.StartingSectorLocation = data.ReadUInt32();
|
||||
directoryEntry.StreamSize = data.ReadUInt64();
|
||||
if (directoryEntry == null)
|
||||
return null;
|
||||
|
||||
// TEMPORARY FIX FOR ASCII -> UNICODE
|
||||
directoryEntry.Name = Encoding.Unicode.GetString(Encoding.ASCII.GetBytes(directoryEntry.Name));
|
||||
|
||||
// Handle version 3 entries
|
||||
if (majorVersion == 3)
|
||||
directoryEntry.StreamSize &= 0x0000FFFF;
|
||||
|
||||
|
||||
@@ -145,22 +145,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled CIA header on success, null on error</returns>
|
||||
private static CIAHeader ParseCIAHeader(Stream data)
|
||||
public static CIAHeader? ParseCIAHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
CIAHeader ciaHeader = new CIAHeader();
|
||||
|
||||
ciaHeader.HeaderSize = data.ReadUInt32();
|
||||
ciaHeader.Type = data.ReadUInt16();
|
||||
ciaHeader.Version = data.ReadUInt16();
|
||||
ciaHeader.CertificateChainSize = data.ReadUInt32();
|
||||
ciaHeader.TicketSize = data.ReadUInt32();
|
||||
ciaHeader.TMDFileSize = data.ReadUInt32();
|
||||
ciaHeader.MetaSize = data.ReadUInt32();
|
||||
ciaHeader.ContentSize = data.ReadUInt64();
|
||||
ciaHeader.ContentIndex = data.ReadBytes(0x2000);
|
||||
|
||||
return ciaHeader;
|
||||
return data.ReadType<CIAHeader>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -168,7 +155,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled certificate on success, null on error</returns>
|
||||
private static Certificate? ParseCertificate(Stream data)
|
||||
public static Certificate? ParseCertificate(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
Certificate certificate = new Certificate();
|
||||
@@ -244,7 +231,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="fromCdn">Indicates if the ticket is from CDN</param>
|
||||
/// <returns>Filled ticket on success, null on error</returns>
|
||||
private static Ticket? ParseTicket(Stream data, bool fromCdn = false)
|
||||
public static Ticket? ParseTicket(Stream data, bool fromCdn = false)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
Ticket ticket = new Ticket();
|
||||
@@ -349,10 +336,10 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="fromCdn">Indicates if the ticket is from CDN</param>
|
||||
/// <returns>Filled title metadata on success, null on error</returns>
|
||||
private static TitleMetadata? ParseTitleMetadata(Stream data, bool fromCdn = false)
|
||||
public static TitleMetadata? ParseTitleMetadata(Stream data, bool fromCdn = false)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
TitleMetadata titleMetadata = new TitleMetadata();
|
||||
var titleMetadata = new TitleMetadata();
|
||||
|
||||
titleMetadata.SignatureType = (SignatureType)data.ReadUInt32();
|
||||
switch (titleMetadata.SignatureType)
|
||||
@@ -420,11 +407,19 @@ namespace SabreTools.Serialization.Deserializers
|
||||
titleMetadata.ContentInfoRecords = new ContentInfoRecord[64];
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
var contentInfoRecord = ParseContentInfoRecord(data);
|
||||
if (contentInfoRecord == null)
|
||||
return null;
|
||||
|
||||
titleMetadata.ContentInfoRecords[i] = ParseContentInfoRecord(data);
|
||||
}
|
||||
titleMetadata.ContentChunkRecords = new ContentChunkRecord[titleMetadata.ContentCount];
|
||||
for (int i = 0; i < titleMetadata.ContentCount; i++)
|
||||
{
|
||||
var contentChunkRecord = ParseContentChunkRecord(data);
|
||||
if (contentChunkRecord == null)
|
||||
return null;
|
||||
|
||||
titleMetadata.ContentChunkRecords[i] = ParseContentChunkRecord(data);
|
||||
}
|
||||
|
||||
@@ -450,16 +445,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled content info record on success, null on error</returns>
|
||||
private static ContentInfoRecord ParseContentInfoRecord(Stream data)
|
||||
public static ContentInfoRecord? ParseContentInfoRecord(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
ContentInfoRecord contentInfoRecord = new ContentInfoRecord();
|
||||
|
||||
contentInfoRecord.ContentIndexOffset = data.ReadUInt16();
|
||||
contentInfoRecord.ContentCommandCount = data.ReadUInt16();
|
||||
contentInfoRecord.UnhashedContentRecordsSHA256Hash = data.ReadBytes(0x20);
|
||||
|
||||
return contentInfoRecord;
|
||||
return data.ReadType<ContentInfoRecord>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -467,18 +455,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled content chunk record on success, null on error</returns>
|
||||
private static ContentChunkRecord ParseContentChunkRecord(Stream data)
|
||||
public static ContentChunkRecord? ParseContentChunkRecord(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
ContentChunkRecord contentChunkRecord = new ContentChunkRecord();
|
||||
|
||||
contentChunkRecord.ContentId = data.ReadUInt32();
|
||||
contentChunkRecord.ContentIndex = (ContentIndex)data.ReadUInt16();
|
||||
contentChunkRecord.ContentType = (TMDContentType)data.ReadUInt16();
|
||||
contentChunkRecord.ContentSize = data.ReadUInt64();
|
||||
contentChunkRecord.SHA256Hash = data.ReadBytes(0x20);
|
||||
|
||||
return contentChunkRecord;
|
||||
return data.ReadType<ContentChunkRecord>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -486,18 +465,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled meta data on success, null on error</returns>
|
||||
private static MetaData ParseMetaData(Stream data)
|
||||
public static MetaData? ParseMetaData(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
MetaData metaData = new MetaData();
|
||||
|
||||
metaData.TitleIDDependencyList = data.ReadBytes(0x180);
|
||||
metaData.Reserved1 = data.ReadBytes(0x180);
|
||||
metaData.CoreVersion = data.ReadUInt32();
|
||||
metaData.Reserved2 = data.ReadBytes(0xFC);
|
||||
metaData.IconData = data.ReadBytes(0x36C0);
|
||||
|
||||
return metaData;
|
||||
return data.ReadType<MetaData>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,6 +154,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
for (int i = 0; i < directoryHeader.ItemCount; i++)
|
||||
{
|
||||
var directoryEntry = ParseDirectoryEntry(data);
|
||||
if (directoryEntry == null)
|
||||
return null;
|
||||
|
||||
file.DirectoryEntries[i] = directoryEntry;
|
||||
}
|
||||
|
||||
@@ -189,13 +192,6 @@ namespace SabreTools.Serialization.Deserializers
|
||||
|
||||
file.DirectoryNames[nameOffset] = directoryName;
|
||||
}
|
||||
|
||||
// Loop and assign to entries
|
||||
foreach (var directoryEntry in file.DirectoryEntries)
|
||||
{
|
||||
if (directoryEntry != null)
|
||||
directoryEntry.Name = file.DirectoryNames[directoryEntry.NameOffset];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -478,20 +474,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled Half-Life Game Cache directory entry on success, null on error</returns>
|
||||
private static DirectoryEntry ParseDirectoryEntry(Stream data)
|
||||
private static DirectoryEntry? ParseDirectoryEntry(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var directoryEntry = new DirectoryEntry();
|
||||
|
||||
directoryEntry.NameOffset = data.ReadUInt32();
|
||||
directoryEntry.ItemSize = data.ReadUInt32();
|
||||
directoryEntry.ChecksumIndex = data.ReadUInt32();
|
||||
directoryEntry.DirectoryFlags = (HL_GCF_FLAG)data.ReadUInt32();
|
||||
directoryEntry.ParentIndex = data.ReadUInt32();
|
||||
directoryEntry.NextIndex = data.ReadUInt32();
|
||||
directoryEntry.FirstIndex = data.ReadUInt32();
|
||||
|
||||
return directoryEntry;
|
||||
return data.ReadType<DirectoryEntry>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -404,20 +404,13 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <returns>Filled user data on success, null on error</returns>
|
||||
private static UserData? ParseUserData(Stream data)
|
||||
{
|
||||
var userData = new UserData();
|
||||
var userData = data.ReadType<UserData>();
|
||||
|
||||
byte[]? signature = data.ReadBytes(4);
|
||||
if (signature == null)
|
||||
if (userData == null)
|
||||
return null;
|
||||
|
||||
userData.Signature = Encoding.ASCII.GetString(signature);
|
||||
if (userData.Signature != UserDataSignatureString)
|
||||
return null;
|
||||
|
||||
userData.UserDataSize = data.ReadUInt32();
|
||||
userData.HeaderOffset = data.ReadUInt32();
|
||||
userData.UserDataHeaderSize = data.ReadUInt32();
|
||||
|
||||
return userData;
|
||||
}
|
||||
|
||||
@@ -539,19 +532,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled patch info on success, null on error</returns>
|
||||
private static PatchInfo ParsePatchInfo(Stream data)
|
||||
private static PatchInfo? ParsePatchInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var patchInfo = new PatchInfo();
|
||||
|
||||
patchInfo.Length = data.ReadUInt32();
|
||||
patchInfo.Flags = data.ReadUInt32();
|
||||
patchInfo.DataSize = data.ReadUInt32();
|
||||
patchInfo.MD5 = data.ReadBytes(0x10);
|
||||
|
||||
// TODO: Fill the sector offset table
|
||||
|
||||
return patchInfo;
|
||||
return data.ReadType<PatchInfo>();
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled NCSD header on success, null on error</returns>
|
||||
private static NCSDHeader? ParseNCSDHeader(Stream data)
|
||||
public static NCSDHeader? ParseNCSDHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var header = new NCSDHeader();
|
||||
@@ -208,7 +208,11 @@ namespace SabreTools.Serialization.Deserializers
|
||||
header.PartitionsTable = new PartitionTableEntry[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
header.PartitionsTable[i] = ParsePartitionTableEntry(data);
|
||||
var partitionTableEntry = ParsePartitionTableEntry(data);
|
||||
if (partitionTableEntry == null)
|
||||
return null;
|
||||
|
||||
header.PartitionsTable[i] = partitionTableEntry;
|
||||
}
|
||||
|
||||
if (header.PartitionsFSType == FilesystemType.Normal || header.PartitionsFSType == FilesystemType.None)
|
||||
@@ -243,15 +247,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled partition table entry on success, null on error</returns>
|
||||
private static PartitionTableEntry ParsePartitionTableEntry(Stream data)
|
||||
public static PartitionTableEntry? ParsePartitionTableEntry(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var partitionTableEntry = new PartitionTableEntry();
|
||||
|
||||
partitionTableEntry.Offset = data.ReadUInt32();
|
||||
partitionTableEntry.Length = data.ReadUInt32();
|
||||
|
||||
return partitionTableEntry;
|
||||
return data.ReadType<PartitionTableEntry>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -259,24 +257,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled card info header on success, null on error</returns>
|
||||
private static CardInfoHeader ParseCardInfoHeader(Stream data)
|
||||
public static CardInfoHeader? ParseCardInfoHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var cardInfoHeader = new CardInfoHeader();
|
||||
|
||||
cardInfoHeader.WritableAddressMediaUnits = data.ReadUInt32();
|
||||
cardInfoHeader.CardInfoBitmask = data.ReadUInt32();
|
||||
cardInfoHeader.Reserved1 = data.ReadBytes(0xF8);
|
||||
cardInfoHeader.FilledSize = data.ReadUInt32();
|
||||
cardInfoHeader.Reserved2 = data.ReadBytes(0x0C);
|
||||
cardInfoHeader.TitleVersion = data.ReadUInt16();
|
||||
cardInfoHeader.CardRevision = data.ReadUInt16();
|
||||
cardInfoHeader.Reserved3 = data.ReadBytes(0x0C);
|
||||
cardInfoHeader.CVerTitleID = data.ReadBytes(8);
|
||||
cardInfoHeader.CVerVersionNumber = data.ReadUInt16();
|
||||
cardInfoHeader.Reserved4 = data.ReadBytes(0xCD6);
|
||||
|
||||
return cardInfoHeader;
|
||||
return data.ReadType<CardInfoHeader>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -284,46 +267,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled development card info header on success, null on error</returns>
|
||||
private static DevelopmentCardInfoHeader? ParseDevelopmentCardInfoHeader(Stream data)
|
||||
public static DevelopmentCardInfoHeader? ParseDevelopmentCardInfoHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var developmentCardInfoHeader = new DevelopmentCardInfoHeader();
|
||||
|
||||
developmentCardInfoHeader.InitialData = ParseInitialData(data);
|
||||
if (developmentCardInfoHeader.InitialData == null)
|
||||
return null;
|
||||
|
||||
developmentCardInfoHeader.CardDeviceReserved1 = data.ReadBytes(0x200);
|
||||
developmentCardInfoHeader.TitleKey = data.ReadBytes(0x10);
|
||||
developmentCardInfoHeader.CardDeviceReserved2 = data.ReadBytes(0x1BF0);
|
||||
|
||||
developmentCardInfoHeader.TestData = ParseTestData(data);
|
||||
if (developmentCardInfoHeader.TestData == null)
|
||||
return null;
|
||||
|
||||
return developmentCardInfoHeader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an initial data
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled initial data on success, null on error</returns>
|
||||
private static InitialData? ParseInitialData(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var initialData = new InitialData();
|
||||
|
||||
initialData.CardSeedKeyY = data.ReadBytes(0x10);
|
||||
initialData.EncryptedCardSeed = data.ReadBytes(0x10);
|
||||
initialData.CardSeedAESMAC = data.ReadBytes(0x10);
|
||||
initialData.CardSeedNonce = data.ReadBytes(0xC);
|
||||
initialData.Reserved = data.ReadBytes(0xC4);
|
||||
initialData.BackupHeader = ParseNCCHHeader(data, true);
|
||||
if (initialData.BackupHeader == null)
|
||||
return null;
|
||||
|
||||
return initialData;
|
||||
return data.ReadType<DevelopmentCardInfoHeader>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -332,7 +278,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="skipSignature">Indicates if the signature should be skipped</param>
|
||||
/// <returns>Filled NCCH header on success, null on error</returns>
|
||||
internal static NCCHHeader ParseNCCHHeader(Stream data, bool skipSignature = false)
|
||||
public static NCCHHeader ParseNCCHHeader(Stream data, bool skipSignature = false)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var header = new NCCHHeader();
|
||||
@@ -356,7 +302,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
header.ProductCode = Encoding.ASCII.GetString(productCode).TrimEnd('\0');
|
||||
header.ExtendedHeaderHash = data.ReadBytes(0x20);
|
||||
header.ExtendedHeaderSizeInBytes = data.ReadUInt32();
|
||||
header.Reserved2 = data.ReadBytes(4);
|
||||
header.Reserved2 = data.ReadUInt32();
|
||||
header.Flags = ParseNCCHHeaderFlags(data);
|
||||
header.PlainRegionOffsetInMediaUnits = data.ReadUInt32();
|
||||
header.PlainRegionSizeInMediaUnits = data.ReadUInt32();
|
||||
@@ -365,11 +311,11 @@ namespace SabreTools.Serialization.Deserializers
|
||||
header.ExeFSOffsetInMediaUnits = data.ReadUInt32();
|
||||
header.ExeFSSizeInMediaUnits = data.ReadUInt32();
|
||||
header.ExeFSHashRegionSizeInMediaUnits = data.ReadUInt32();
|
||||
header.Reserved3 = data.ReadBytes(4);
|
||||
header.Reserved3 = data.ReadUInt32();
|
||||
header.RomFSOffsetInMediaUnits = data.ReadUInt32();
|
||||
header.RomFSSizeInMediaUnits = data.ReadUInt32();
|
||||
header.RomFSHashRegionSizeInMediaUnits = data.ReadUInt32();
|
||||
header.Reserved4 = data.ReadBytes(4);
|
||||
header.Reserved4 = data.ReadUInt32();
|
||||
header.ExeFSSuperblockHash = data.ReadBytes(0x20);
|
||||
header.RomFSSuperblockHash = data.ReadBytes(0x20);
|
||||
|
||||
@@ -381,46 +327,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled NCCH header flags on success, null on error</returns>
|
||||
private static NCCHHeaderFlags ParseNCCHHeaderFlags(Stream data)
|
||||
public static NCCHHeaderFlags? ParseNCCHHeaderFlags(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var headerFlags = new NCCHHeaderFlags();
|
||||
|
||||
headerFlags.Reserved0 = data.ReadByteValue();
|
||||
headerFlags.Reserved1 = data.ReadByteValue();
|
||||
headerFlags.Reserved2 = data.ReadByteValue();
|
||||
headerFlags.CryptoMethod = (CryptoMethod)data.ReadByteValue();
|
||||
headerFlags.ContentPlatform = (ContentPlatform)data.ReadByteValue();
|
||||
headerFlags.MediaPlatformIndex = (ContentType)data.ReadByteValue();
|
||||
headerFlags.ContentUnitSize = data.ReadByteValue();
|
||||
headerFlags.BitMasks = (BitMasks)data.ReadByteValue();
|
||||
|
||||
return headerFlags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an initial data
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled initial data on success, null on error</returns>
|
||||
private static TestData ParseTestData(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var testData = new TestData();
|
||||
|
||||
// TODO: Validate some of the values
|
||||
testData.Signature = data.ReadBytes(8);
|
||||
testData.AscendingByteSequence = data.ReadBytes(0x1F8);
|
||||
testData.DescendingByteSequence = data.ReadBytes(0x200);
|
||||
testData.Filled00 = data.ReadBytes(0x200);
|
||||
testData.FilledFF = data.ReadBytes(0x200);
|
||||
testData.Filled0F = data.ReadBytes(0x200);
|
||||
testData.FilledF0 = data.ReadBytes(0x200);
|
||||
testData.Filled55 = data.ReadBytes(0x200);
|
||||
testData.FilledAA = data.ReadBytes(0x1FF);
|
||||
testData.FinalByte = data.ReadByteValue();
|
||||
|
||||
return testData;
|
||||
return data.ReadType<NCCHHeaderFlags>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -428,203 +337,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled NCCH extended header on success, null on error</returns>
|
||||
private static NCCHExtendedHeader? ParseNCCHExtendedHeader(Stream data)
|
||||
public static NCCHExtendedHeader? ParseNCCHExtendedHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var extendedHeader = new NCCHExtendedHeader();
|
||||
|
||||
extendedHeader.SCI = ParseSystemControlInfo(data);
|
||||
if (extendedHeader.SCI == null)
|
||||
return null;
|
||||
|
||||
extendedHeader.ACI = ParseAccessControlInfo(data);
|
||||
if (extendedHeader.ACI == null)
|
||||
return null;
|
||||
|
||||
extendedHeader.AccessDescSignature = data.ReadBytes(0x100);
|
||||
extendedHeader.NCCHHDRPublicKey = data.ReadBytes(0x100);
|
||||
|
||||
extendedHeader.ACIForLimitations = ParseAccessControlInfo(data);
|
||||
if (extendedHeader.ACI == null)
|
||||
return null;
|
||||
|
||||
return extendedHeader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a system control info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled system control info on success, null on error</returns>
|
||||
private static SystemControlInfo ParseSystemControlInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var systemControlInfo = new SystemControlInfo();
|
||||
|
||||
byte[]? applicationTitle = data.ReadBytes(8);
|
||||
if (applicationTitle != null)
|
||||
systemControlInfo.ApplicationTitle = Encoding.ASCII.GetString(applicationTitle).TrimEnd('\0');
|
||||
systemControlInfo.Reserved1 = data.ReadBytes(5);
|
||||
systemControlInfo.Flag = data.ReadByteValue();
|
||||
systemControlInfo.RemasterVersion = data.ReadUInt16();
|
||||
systemControlInfo.TextCodeSetInfo = ParseCodeSetInfo(data);
|
||||
systemControlInfo.StackSize = data.ReadUInt32();
|
||||
systemControlInfo.ReadOnlyCodeSetInfo = ParseCodeSetInfo(data);
|
||||
systemControlInfo.Reserved2 = data.ReadBytes(4);
|
||||
systemControlInfo.DataCodeSetInfo = ParseCodeSetInfo(data);
|
||||
systemControlInfo.BSSSize = data.ReadUInt32();
|
||||
systemControlInfo.DependencyModuleList = new ulong[48];
|
||||
for (int i = 0; i < 48; i++)
|
||||
{
|
||||
systemControlInfo.DependencyModuleList[i] = data.ReadUInt64();
|
||||
}
|
||||
systemControlInfo.SystemInfo = ParseSystemInfo(data);
|
||||
|
||||
return systemControlInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a code set info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled code set info on success, null on error</returns>
|
||||
private static CodeSetInfo ParseCodeSetInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var codeSetInfo = new CodeSetInfo();
|
||||
|
||||
codeSetInfo.Address = data.ReadUInt32();
|
||||
codeSetInfo.PhysicalRegionSizeInPages = data.ReadUInt32();
|
||||
codeSetInfo.SizeInBytes = data.ReadUInt32();
|
||||
|
||||
return codeSetInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a system info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled system info on success, null on error</returns>
|
||||
private static SystemInfo ParseSystemInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var systemInfo = new SystemInfo();
|
||||
|
||||
systemInfo.SaveDataSize = data.ReadUInt64();
|
||||
systemInfo.JumpID = data.ReadUInt64();
|
||||
systemInfo.Reserved = data.ReadBytes(0x30);
|
||||
|
||||
return systemInfo;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
private static AccessControlInfo ParseAccessControlInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var accessControlInfo = new AccessControlInfo();
|
||||
|
||||
accessControlInfo.ARM11LocalSystemCapabilities = ParseARM11LocalSystemCapabilities(data);
|
||||
accessControlInfo.ARM11KernelCapabilities = ParseARM11KernelCapabilities(data);
|
||||
accessControlInfo.ARM9AccessControl = ParseARM9AccessControl(data);
|
||||
|
||||
return accessControlInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an ARM11 local system capabilities
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ARM11 local system capabilities on success, null on error</returns>
|
||||
private static ARM11LocalSystemCapabilities ParseARM11LocalSystemCapabilities(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var arm11LocalSystemCapabilities = new ARM11LocalSystemCapabilities();
|
||||
|
||||
arm11LocalSystemCapabilities.ProgramID = data.ReadUInt64();
|
||||
arm11LocalSystemCapabilities.CoreVersion = data.ReadUInt32();
|
||||
arm11LocalSystemCapabilities.Flag1 = (ARM11LSCFlag1)data.ReadByteValue();
|
||||
arm11LocalSystemCapabilities.Flag2 = (ARM11LSCFlag2)data.ReadByteValue();
|
||||
arm11LocalSystemCapabilities.Flag0 = (ARM11LSCFlag0)data.ReadByteValue();
|
||||
arm11LocalSystemCapabilities.Priority = data.ReadByteValue();
|
||||
arm11LocalSystemCapabilities.ResourceLimitDescriptors = new ushort[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
arm11LocalSystemCapabilities.ResourceLimitDescriptors[i] = data.ReadUInt16();
|
||||
}
|
||||
arm11LocalSystemCapabilities.StorageInfo = ParseStorageInfo(data);
|
||||
arm11LocalSystemCapabilities.ServiceAccessControl = new ulong[32];
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
arm11LocalSystemCapabilities.ServiceAccessControl[i] = data.ReadUInt64();
|
||||
}
|
||||
arm11LocalSystemCapabilities.ExtendedServiceAccessControl = new ulong[2];
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
arm11LocalSystemCapabilities.ExtendedServiceAccessControl[i] = data.ReadUInt64();
|
||||
}
|
||||
arm11LocalSystemCapabilities.Reserved = data.ReadBytes(0x0F);
|
||||
arm11LocalSystemCapabilities.ResourceLimitCategory = (ResourceLimitCategory)data.ReadByteValue();
|
||||
|
||||
return arm11LocalSystemCapabilities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a storage info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled storage info on success, null on error</returns>
|
||||
private static StorageInfo ParseStorageInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var storageInfo = new StorageInfo();
|
||||
|
||||
storageInfo.ExtdataID = data.ReadUInt64();
|
||||
storageInfo.SystemSavedataIDs = data.ReadBytes(8);
|
||||
storageInfo.StorageAccessibleUniqueIDs = data.ReadBytes(8);
|
||||
storageInfo.FileSystemAccessInfo = data.ReadBytes(7);
|
||||
storageInfo.OtherAttributes = (StorageInfoOtherAttributes)data.ReadByteValue();
|
||||
|
||||
return storageInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an ARM11 kernel capabilities
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ARM11 kernel capabilities on success, null on error</returns>
|
||||
private static ARM11KernelCapabilities ParseARM11KernelCapabilities(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var arm11KernelCapabilities = new ARM11KernelCapabilities();
|
||||
|
||||
arm11KernelCapabilities.Descriptors = new uint[28];
|
||||
for (int i = 0; i < 28; i++)
|
||||
{
|
||||
arm11KernelCapabilities.Descriptors[i] = data.ReadUInt32();
|
||||
}
|
||||
arm11KernelCapabilities.Reserved = data.ReadBytes(0x10);
|
||||
|
||||
return arm11KernelCapabilities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an ARM11 access control
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ARM11 access control on success, null on error</returns>
|
||||
private static ARM9AccessControl ParseARM9AccessControl(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var arm9AccessControl = new ARM9AccessControl();
|
||||
|
||||
arm9AccessControl.Descriptors = data.ReadBytes(15);
|
||||
arm9AccessControl.DescriptorVersion = data.ReadByteValue();
|
||||
|
||||
return arm9AccessControl;
|
||||
return data.ReadType<NCCHExtendedHeader>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -632,7 +347,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ExeFS header on success, null on error</returns>
|
||||
private static ExeFSHeader? ParseExeFSHeader(Stream data)
|
||||
public static ExeFSHeader? ParseExeFSHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var exeFSHeader = new ExeFSHeader();
|
||||
@@ -661,7 +376,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ExeFS file header on success, null on error</returns>
|
||||
private static ExeFSFileHeader? ParseExeFSFileHeader(Stream data)
|
||||
public static ExeFSFileHeader? ParseExeFSFileHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var exeFSFileHeader = new ExeFSFileHeader();
|
||||
@@ -680,39 +395,17 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled RomFS header on success, null on error</returns>
|
||||
private static RomFSHeader? ParseRomFSHeader(Stream data)
|
||||
public static RomFSHeader? ParseRomFSHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var romFSHeader = new RomFSHeader();
|
||||
var romFSHeader = data.ReadType<RomFSHeader>();
|
||||
|
||||
byte[]? magicString = data.ReadBytes(4);
|
||||
if (magicString == null)
|
||||
if (romFSHeader == null)
|
||||
return null;
|
||||
|
||||
romFSHeader.MagicString = Encoding.ASCII.GetString(magicString).TrimEnd('\0');
|
||||
if (romFSHeader.MagicString != RomFSMagicNumber)
|
||||
return null;
|
||||
|
||||
romFSHeader.MagicNumber = data.ReadUInt32();
|
||||
if (romFSHeader.MagicNumber != RomFSSecondMagicNumber)
|
||||
return null;
|
||||
|
||||
romFSHeader.MasterHashSize = data.ReadUInt32();
|
||||
romFSHeader.Level1LogicalOffset = data.ReadUInt64();
|
||||
romFSHeader.Level1HashdataSize = data.ReadUInt64();
|
||||
romFSHeader.Level1BlockSizeLog2 = data.ReadUInt32();
|
||||
romFSHeader.Reserved1 = data.ReadBytes(4);
|
||||
romFSHeader.Level2LogicalOffset = data.ReadUInt64();
|
||||
romFSHeader.Level2HashdataSize = data.ReadUInt64();
|
||||
romFSHeader.Level2BlockSizeLog2 = data.ReadUInt32();
|
||||
romFSHeader.Reserved2 = data.ReadBytes(4);
|
||||
romFSHeader.Level3LogicalOffset = data.ReadUInt64();
|
||||
romFSHeader.Level3HashdataSize = data.ReadUInt64();
|
||||
romFSHeader.Level3BlockSizeLog2 = data.ReadUInt32();
|
||||
romFSHeader.Reserved3 = data.ReadBytes(4);
|
||||
romFSHeader.Reserved4 = data.ReadBytes(4);
|
||||
romFSHeader.OptionalInfoSize = data.ReadUInt32();
|
||||
|
||||
return romFSHeader;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,13 +99,6 @@ namespace SabreTools.Serialization.Deserializers
|
||||
|
||||
file.DirectoryNames[nameOffset] = directoryName;
|
||||
}
|
||||
|
||||
// Loop and assign to entries
|
||||
foreach (var directoryEntry in file.DirectoryEntries)
|
||||
{
|
||||
if (directoryEntry != null)
|
||||
directoryEntry.Name = file.DirectoryNames[directoryEntry.NameOffset];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -322,18 +315,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <returns>Filled Half-Life No Cache directory entry on success, null on error</returns>
|
||||
private static DirectoryEntry? ParseDirectoryEntry(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var directoryEntry = new DirectoryEntry();
|
||||
|
||||
directoryEntry.NameOffset = data.ReadUInt32();
|
||||
directoryEntry.ItemSize = data.ReadUInt32();
|
||||
directoryEntry.ChecksumIndex = data.ReadUInt32();
|
||||
directoryEntry.DirectoryFlags = (HL_NCF_FLAG)data.ReadUInt32();
|
||||
directoryEntry.ParentIndex = data.ReadUInt32();
|
||||
directoryEntry.NextIndex = data.ReadUInt32();
|
||||
directoryEntry.FirstIndex = data.ReadUInt32();
|
||||
|
||||
return directoryEntry;
|
||||
return data.ReadType<DirectoryEntry>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -103,6 +103,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
while (data.Position - fileAllocationTableOffset < header.FileAllocationTableLength)
|
||||
{
|
||||
var entry = ParseFileAllocationTableEntry(data);
|
||||
if (entry == null)
|
||||
return null;
|
||||
|
||||
fileAllocationTable.Add(entry);
|
||||
}
|
||||
|
||||
@@ -122,58 +125,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled common header on success, null on error</returns>
|
||||
private static CommonHeader ParseCommonHeader(Stream data)
|
||||
private static CommonHeader? ParseCommonHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
CommonHeader commonHeader = new CommonHeader();
|
||||
|
||||
byte[]? gameTitle = data.ReadBytes(12);
|
||||
if (gameTitle != null)
|
||||
commonHeader.GameTitle = Encoding.ASCII.GetString(gameTitle).TrimEnd('\0');
|
||||
commonHeader.GameCode = data.ReadUInt32();
|
||||
byte[]? makerCode = data.ReadBytes(2);
|
||||
if (makerCode != null)
|
||||
commonHeader.MakerCode = Encoding.ASCII.GetString(bytes: makerCode).TrimEnd('\0');
|
||||
commonHeader.UnitCode = (Unitcode)data.ReadByteValue();
|
||||
commonHeader.EncryptionSeedSelect = data.ReadByteValue();
|
||||
commonHeader.DeviceCapacity = data.ReadByteValue();
|
||||
commonHeader.Reserved1 = data.ReadBytes(7);
|
||||
commonHeader.GameRevision = data.ReadUInt16();
|
||||
commonHeader.RomVersion = data.ReadByteValue();
|
||||
commonHeader.InternalFlags = data.ReadByteValue();
|
||||
commonHeader.ARM9RomOffset = data.ReadUInt32();
|
||||
commonHeader.ARM9EntryAddress = data.ReadUInt32();
|
||||
commonHeader.ARM9LoadAddress = data.ReadUInt32();
|
||||
commonHeader.ARM9Size = data.ReadUInt32();
|
||||
commonHeader.ARM7RomOffset = data.ReadUInt32();
|
||||
commonHeader.ARM7EntryAddress = data.ReadUInt32();
|
||||
commonHeader.ARM7LoadAddress = data.ReadUInt32();
|
||||
commonHeader.ARM7Size = data.ReadUInt32();
|
||||
commonHeader.FileNameTableOffset = data.ReadUInt32();
|
||||
commonHeader.FileNameTableLength = data.ReadUInt32();
|
||||
commonHeader.FileAllocationTableOffset = data.ReadUInt32();
|
||||
commonHeader.FileAllocationTableLength = data.ReadUInt32();
|
||||
commonHeader.ARM9OverlayOffset = data.ReadUInt32();
|
||||
commonHeader.ARM9OverlayLength = data.ReadUInt32();
|
||||
commonHeader.ARM7OverlayOffset = data.ReadUInt32();
|
||||
commonHeader.ARM7OverlayLength = data.ReadUInt32();
|
||||
commonHeader.NormalCardControlRegisterSettings = data.ReadUInt32();
|
||||
commonHeader.SecureCardControlRegisterSettings = data.ReadUInt32();
|
||||
commonHeader.IconBannerOffset = data.ReadUInt32();
|
||||
commonHeader.SecureAreaCRC = data.ReadUInt16();
|
||||
commonHeader.SecureTransferTimeout = data.ReadUInt16();
|
||||
commonHeader.ARM9Autoload = data.ReadUInt32();
|
||||
commonHeader.ARM7Autoload = data.ReadUInt32();
|
||||
commonHeader.SecureDisable = data.ReadBytes(8);
|
||||
commonHeader.NTRRegionRomSize = data.ReadUInt32();
|
||||
commonHeader.HeaderSize = data.ReadUInt32();
|
||||
commonHeader.Reserved2 = data.ReadBytes(56);
|
||||
commonHeader.NintendoLogo = data.ReadBytes(156);
|
||||
commonHeader.NintendoLogoCRC = data.ReadUInt16();
|
||||
commonHeader.HeaderCRC = data.ReadUInt16();
|
||||
commonHeader.DebuggerReserved = data.ReadBytes(0x20);
|
||||
|
||||
return commonHeader;
|
||||
return data.ReadType<CommonHeader>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -181,75 +135,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled extended DSi header on success, null on error</returns>
|
||||
private static ExtendedDSiHeader ParseExtendedDSiHeader(Stream data)
|
||||
private static ExtendedDSiHeader? ParseExtendedDSiHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var extendedDSiHeader = new ExtendedDSiHeader();
|
||||
|
||||
extendedDSiHeader.GlobalMBK15Settings = new uint[5];
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
extendedDSiHeader.GlobalMBK15Settings[i] = data.ReadUInt32();
|
||||
}
|
||||
extendedDSiHeader.LocalMBK68SettingsARM9 = new uint[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
extendedDSiHeader.LocalMBK68SettingsARM9[i] = data.ReadUInt32();
|
||||
}
|
||||
extendedDSiHeader.LocalMBK68SettingsARM7 = new uint[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
extendedDSiHeader.LocalMBK68SettingsARM7[i] = data.ReadUInt32();
|
||||
}
|
||||
extendedDSiHeader.GlobalMBK9Setting = data.ReadUInt32();
|
||||
extendedDSiHeader.RegionFlags = data.ReadUInt32();
|
||||
extendedDSiHeader.AccessControl = data.ReadUInt32();
|
||||
extendedDSiHeader.ARM7SCFGEXTMask = data.ReadUInt32();
|
||||
extendedDSiHeader.ReservedFlags = data.ReadUInt32();
|
||||
extendedDSiHeader.ARM9iRomOffset = data.ReadUInt32();
|
||||
extendedDSiHeader.Reserved3 = data.ReadUInt32();
|
||||
extendedDSiHeader.ARM9iLoadAddress = data.ReadUInt32();
|
||||
extendedDSiHeader.ARM9iSize = data.ReadUInt32();
|
||||
extendedDSiHeader.ARM7iRomOffset = data.ReadUInt32();
|
||||
extendedDSiHeader.Reserved4 = data.ReadUInt32();
|
||||
extendedDSiHeader.ARM7iLoadAddress = data.ReadUInt32();
|
||||
extendedDSiHeader.ARM7iSize = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestNTRRegionOffset = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestNTRRegionLength = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestTWLRegionOffset = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestTWLRegionLength = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestSectorHashtableRegionOffset = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestSectorHashtableRegionLength = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestBlockHashtableRegionOffset = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestBlockHashtableRegionLength = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestSectorSize = data.ReadUInt32();
|
||||
extendedDSiHeader.DigestBlockSectorCount = data.ReadUInt32();
|
||||
extendedDSiHeader.IconBannerSize = data.ReadUInt32();
|
||||
extendedDSiHeader.Unknown1 = data.ReadUInt32();
|
||||
extendedDSiHeader.NTRTWLRegionRomSize = data.ReadUInt32();
|
||||
extendedDSiHeader.Unknown2 = data.ReadBytes(12);
|
||||
extendedDSiHeader.ModcryptArea1Offset = data.ReadUInt32();
|
||||
extendedDSiHeader.ModcryptArea1Size = data.ReadUInt32();
|
||||
extendedDSiHeader.ModcryptArea2Offset = data.ReadUInt32();
|
||||
extendedDSiHeader.ModcryptArea2Size = data.ReadUInt32();
|
||||
extendedDSiHeader.TitleID = data.ReadBytes(8);
|
||||
extendedDSiHeader.DSiWarePublicSavSize = data.ReadUInt32();
|
||||
extendedDSiHeader.DSiWarePrivateSavSize = data.ReadUInt32();
|
||||
extendedDSiHeader.ReservedZero = data.ReadBytes(176);
|
||||
extendedDSiHeader.Unknown2 = data.ReadBytes(0x10);
|
||||
extendedDSiHeader.ARM9WithSecureAreaSHA1HMACHash = data.ReadBytes(20);
|
||||
extendedDSiHeader.ARM7SHA1HMACHash = data.ReadBytes(20);
|
||||
extendedDSiHeader.DigestMasterSHA1HMACHash = data.ReadBytes(20);
|
||||
extendedDSiHeader.BannerSHA1HMACHash = data.ReadBytes(20);
|
||||
extendedDSiHeader.ARM9iDecryptedSHA1HMACHash = data.ReadBytes(20);
|
||||
extendedDSiHeader.ARM7iDecryptedSHA1HMACHash = data.ReadBytes(20);
|
||||
extendedDSiHeader.Reserved5 = data.ReadBytes(40);
|
||||
extendedDSiHeader.ARM9NoSecureAreaSHA1HMACHash = data.ReadBytes(20);
|
||||
extendedDSiHeader.Reserved6 = data.ReadBytes(2636);
|
||||
extendedDSiHeader.ReservedAndUnchecked = data.ReadBytes(0x180);
|
||||
extendedDSiHeader.RSASignature = data.ReadBytes(0x80);
|
||||
|
||||
return extendedDSiHeader;
|
||||
return data.ReadType<ExtendedDSiHeader>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -257,10 +145,10 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled name table on success, null on error</returns>
|
||||
private static NameTable ParseNameTable(Stream data)
|
||||
private static NameTable? ParseNameTable(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
NameTable nameTable = new NameTable();
|
||||
var nameTable = new NameTable();
|
||||
|
||||
// Create a variable-length table
|
||||
var folderAllocationTable = new List<FolderAllocationTableEntry>();
|
||||
@@ -268,6 +156,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
while (entryCount > 0)
|
||||
{
|
||||
var entry = ParseFolderAllocationTableEntry(data);
|
||||
if (entry == null)
|
||||
return null;
|
||||
|
||||
folderAllocationTable.Add(entry);
|
||||
|
||||
// If we have the root entry
|
||||
@@ -303,17 +194,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled folder allocation table entry on success, null on error</returns>
|
||||
private static FolderAllocationTableEntry ParseFolderAllocationTableEntry(Stream data)
|
||||
private static FolderAllocationTableEntry? ParseFolderAllocationTableEntry(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var entry = new FolderAllocationTableEntry();
|
||||
|
||||
entry.StartOffset = data.ReadUInt32();
|
||||
entry.FirstFileIndex = data.ReadUInt16();
|
||||
entry.ParentFolderIndex = data.ReadByteValue();
|
||||
entry.Unknown = data.ReadByteValue();
|
||||
|
||||
return entry;
|
||||
return data.ReadType<FolderAllocationTableEntry>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -351,15 +234,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled name list entry on success, null on error</returns>
|
||||
private static FileAllocationTableEntry ParseFileAllocationTableEntry(Stream data)
|
||||
private static FileAllocationTableEntry? ParseFileAllocationTableEntry(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var entry = new FileAllocationTableEntry();
|
||||
|
||||
entry.StartOffset = data.ReadUInt32();
|
||||
entry.EndOffset = data.ReadUInt32();
|
||||
|
||||
return entry;
|
||||
return data.ReadType<FileAllocationTableEntry>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -883,7 +883,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="magic">Optional header magic number indicating PE32 or PE32+</param>
|
||||
/// <param name="sections">Section table to use for virtual address translation</param>
|
||||
/// <returns>Filled import table on success, null on error</returns>
|
||||
public static ImportTable ParseImportTable(Stream data, OptionalHeaderMagicNumber magic, SectionHeader?[] sections)
|
||||
public static ImportTable? ParseImportTable(Stream data, OptionalHeaderMagicNumber magic, SectionHeader?[] sections)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var importTable = new ImportTable();
|
||||
@@ -1085,21 +1085,30 @@ namespace SabreTools.Serialization.Deserializers
|
||||
int hintNameTableEntryAddress = hintNameTableEntryAddresses[i];
|
||||
data.Seek(hintNameTableEntryAddress, SeekOrigin.Begin);
|
||||
|
||||
var hintNameTableEntry = new HintNameTableEntry();
|
||||
|
||||
hintNameTableEntry.Hint = data.ReadUInt16();
|
||||
hintNameTableEntry.Name = data.ReadNullTerminatedAnsiString();
|
||||
var hintNameTableEntry = ParseHintNameTableEntry(data);
|
||||
if (hintNameTableEntry == null)
|
||||
return null;
|
||||
|
||||
importHintNameTable.Add(hintNameTableEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
importTable.HintNameTable = importHintNameTable.ToArray();
|
||||
importTable.HintNameTable = [.. importHintNameTable];
|
||||
|
||||
return importTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a hint name table entry
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled hint name table entry on success, null on error</returns>
|
||||
public static HintNameTableEntry? ParseHintNameTableEntry(Stream data)
|
||||
{
|
||||
return data.ReadType<HintNameTableEntry>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a resource directory table
|
||||
/// </summary>
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
private static Header? ParseHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
Header header = new Header();
|
||||
var header = new Header();
|
||||
|
||||
byte[]? signature = data.ReadBytes(4);
|
||||
if (signature == null)
|
||||
|
||||
@@ -79,6 +79,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
while (data.Position < initialOffset + file.ExtendedHeader.ArchiveHashLength)
|
||||
{
|
||||
var archiveHash = ParseArchiveHash(data);
|
||||
if (archiveHash == null)
|
||||
return null;
|
||||
|
||||
archiveHashes.Add(archiveHash);
|
||||
}
|
||||
|
||||
@@ -124,17 +127,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled Valve Package archive hash on success, null on error</returns>
|
||||
private static ArchiveHash ParseArchiveHash(Stream data)
|
||||
private static ArchiveHash? ParseArchiveHash(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var archiveHash = new ArchiveHash();
|
||||
|
||||
archiveHash.ArchiveIndex = data.ReadUInt32();
|
||||
archiveHash.ArchiveOffset = data.ReadUInt32();
|
||||
archiveHash.Length = data.ReadUInt32();
|
||||
archiveHash.Hash = data.ReadBytes(0x10);
|
||||
|
||||
return archiveHash;
|
||||
return data.ReadType<ArchiveHash>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -52,6 +52,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
for (int i = 0; i < header.LumpCount; i++)
|
||||
{
|
||||
var lump = ParseLump(data);
|
||||
if (lump == null)
|
||||
return null;
|
||||
|
||||
file.Lumps[i] = lump;
|
||||
}
|
||||
|
||||
@@ -104,20 +107,13 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <returns>Filled Half-Life Texture Package header on success, null on error</returns>
|
||||
private static Header? ParseHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
Header header = new Header();
|
||||
var header = data.ReadType<Header>();
|
||||
|
||||
byte[]? signature = data.ReadBytes(4);
|
||||
if (signature == null)
|
||||
if (header == null)
|
||||
return null;
|
||||
|
||||
header.Signature = Encoding.ASCII.GetString(signature);
|
||||
if (header.Signature != SignatureString)
|
||||
return null;
|
||||
|
||||
header.LumpCount = data.ReadUInt32();
|
||||
header.LumpOffset = data.ReadUInt32();
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -126,23 +122,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled Half-Life Texture Package lump on success, null on error</returns>
|
||||
private static Lump ParseLump(Stream data)
|
||||
private static Lump? ParseLump(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
Lump lump = new Lump();
|
||||
|
||||
lump.Offset = data.ReadUInt32();
|
||||
lump.DiskLength = data.ReadUInt32();
|
||||
lump.Length = data.ReadUInt32();
|
||||
lump.Type = data.ReadByteValue();
|
||||
lump.Compression = data.ReadByteValue();
|
||||
lump.Padding0 = data.ReadByteValue();
|
||||
lump.Padding1 = data.ReadByteValue();
|
||||
byte[]? name = data.ReadBytes(16);
|
||||
if (name != null)
|
||||
lump.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
|
||||
|
||||
return lump;
|
||||
return data.ReadType<Lump>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,7 +164,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
lumpInfo.Width = data.ReadUInt32();
|
||||
lumpInfo.Height = data.ReadUInt32();
|
||||
lumpInfo.PixelOffset = data.ReadUInt32();
|
||||
_ = data.ReadBytes(12); // Unknown data
|
||||
lumpInfo.UnknownData = data.ReadBytes(12);
|
||||
|
||||
// Cache the current offset
|
||||
long currentOffset = data.Position;
|
||||
|
||||
@@ -144,29 +144,15 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <returns>Filled XBox Package File header on success, null on error</returns>
|
||||
private static Header? ParseHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
Header header = new Header();
|
||||
var header = data.ReadType<Header>();
|
||||
|
||||
byte[]? signature = data.ReadBytes(4);
|
||||
if (signature == null)
|
||||
if (header == null)
|
||||
return null;
|
||||
|
||||
header.Signature = Encoding.ASCII.GetString(signature);
|
||||
if (header.Signature != HeaderSignatureString)
|
||||
return null;
|
||||
|
||||
header.Version = data.ReadUInt32();
|
||||
if (header.Version != 6)
|
||||
return null;
|
||||
|
||||
header.PreloadDirectoryEntryCount = data.ReadUInt32();
|
||||
header.DirectoryEntryCount = data.ReadUInt32();
|
||||
header.PreloadBytes = data.ReadUInt32();
|
||||
header.HeaderLength = data.ReadUInt32();
|
||||
header.DirectoryItemCount = data.ReadUInt32();
|
||||
header.DirectoryItemOffset = data.ReadUInt32();
|
||||
header.DirectoryItemLength = data.ReadUInt32();
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -226,15 +212,10 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <returns>Filled XBox Package File footer on success, null on error</returns>
|
||||
private static Footer? ParseFooter(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
Footer footer = new Footer();
|
||||
var footer = data.ReadType<Footer>();
|
||||
|
||||
footer.FileLength = data.ReadUInt32();
|
||||
byte[]? signature = data.ReadBytes(4);
|
||||
if (signature == null)
|
||||
if (footer == null)
|
||||
return null;
|
||||
|
||||
footer.Signature = Encoding.ASCII.GetString(signature);
|
||||
if (footer.Signature != FooterSignatureString)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -118,24 +118,15 @@ namespace SabreTools.Serialization
|
||||
/// <param name="data">Data to parse into a database</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled RSDS Program Database on success, null on error</returns>
|
||||
public static RSDSProgramDatabase? AsRSDSProgramDatabase(this byte[]? data, ref int offset)
|
||||
public static RSDSProgramDatabase? AsRSDSProgramDatabase(this byte[] data, ref int offset)
|
||||
{
|
||||
// If we have data that's invalid, we can't do anything
|
||||
if (data == null)
|
||||
var rsdsProgramDatabase = data.ReadType<RSDSProgramDatabase>(ref offset);
|
||||
|
||||
if (rsdsProgramDatabase == null)
|
||||
return null;
|
||||
|
||||
var rsdsProgramDatabase = new RSDSProgramDatabase();
|
||||
|
||||
rsdsProgramDatabase.Signature = data.ReadUInt32(ref offset);
|
||||
if (rsdsProgramDatabase.Signature != 0x53445352)
|
||||
return null;
|
||||
|
||||
var guid = data.ReadBytes(ref offset, 0x10);
|
||||
if (guid != null)
|
||||
rsdsProgramDatabase.GUID = new Guid(guid);
|
||||
rsdsProgramDatabase.Age = data.ReadUInt32(ref offset);
|
||||
rsdsProgramDatabase.PathAndFileName = data.ReadNullTerminatedAnsiString(ref offset); // TODO: Actually null-terminated UTF-8
|
||||
|
||||
return rsdsProgramDatabase;
|
||||
}
|
||||
|
||||
@@ -951,28 +942,19 @@ namespace SabreTools.Serialization
|
||||
|
||||
while (offset < entry.Data.Length)
|
||||
{
|
||||
var menuItem = new MenuItem();
|
||||
|
||||
// Determine if this is a popup
|
||||
int flagsOffset = offset;
|
||||
var initialFlags = (MenuFlags)entry.Data.ReadUInt16(ref flagsOffset);
|
||||
|
||||
MenuItem? menuItem;
|
||||
#if NET20 || NET35
|
||||
if ((initialFlags & MenuFlags.MF_POPUP) != 0)
|
||||
#else
|
||||
if (initialFlags.HasFlag(MenuFlags.MF_POPUP))
|
||||
#endif
|
||||
{
|
||||
menuItem.PopupItemType = (MenuFlags)entry.Data.ReadUInt32(ref offset);
|
||||
menuItem.PopupState = (MenuFlags)entry.Data.ReadUInt32(ref offset);
|
||||
menuItem.PopupID = entry.Data.ReadUInt32(ref offset);
|
||||
menuItem.PopupResInfo = (MenuFlags)entry.Data.ReadUInt32(ref offset);
|
||||
menuItem.PopupMenuText = entry.Data.ReadNullTerminatedUnicodeString(ref offset);
|
||||
}
|
||||
menuItem = entry.Data.ReadType<PopupMenuItem>(ref offset);
|
||||
else
|
||||
{
|
||||
menuItem.NormalResInfo = (MenuFlags)entry.Data.ReadUInt16(ref offset);
|
||||
menuItem.NormalMenuText = entry.Data.ReadNullTerminatedUnicodeString(ref offset);
|
||||
}
|
||||
menuItem = entry.Data.ReadType<NormalMenuItem>(ref offset);
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
if (offset < entry.Data.Length)
|
||||
@@ -981,6 +963,9 @@ namespace SabreTools.Serialization
|
||||
_ = entry.Data.ReadByte(ref offset);
|
||||
}
|
||||
|
||||
if (menuItem == null)
|
||||
return null;
|
||||
|
||||
menuItems.Add(menuItem);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user