diff --git a/SabreTools.Serialization/Deserializers/AACS.cs b/SabreTools.Serialization/Deserializers/AACS.cs
index 6c4c8ae9..4197e8b8 100644
--- a/SabreTools.Serialization/Deserializers/AACS.cs
+++ b/SabreTools.Serialization/Deserializers/AACS.cs
@@ -17,9 +17,6 @@ namespace SabreTools.Serialization.Deserializers
try
{
- // Create a new media key block to fill
- var mediaKeyBlock = new MediaKeyBlock();
-
#region Records
// Create the records list
@@ -49,7 +46,7 @@ namespace SabreTools.Serialization.Deserializers
// Set the records
if (records.Count > 0)
- return new MediaKeyBlock { Records = [.. records ]};
+ return new MediaKeyBlock { Records = [.. records] };
return null;
}
@@ -61,29 +58,29 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a record
+ /// Parse a Stream into a Record
///
/// Stream to parse
- /// Filled record on success, null on error
+ /// Filled Record on success, null on error
private static Record? ParseRecord(Stream data)
{
- // The first 4 bytes make up the type and length
+ // The first byte is the type
RecordType type = (RecordType)data.ReadByteValue();
- uint length = data.ReadUInt24();
+ data.Seek(-1, SeekOrigin.Current);
// Create a record based on the type
return type switch
{
// Known record types
- RecordType.EndOfMediaKeyBlock => ParseEndOfMediaKeyBlockRecord(data, type, length),
- RecordType.ExplicitSubsetDifference => ParseExplicitSubsetDifferenceRecord(data, type, length),
- RecordType.MediaKeyData => ParseMediaKeyDataRecord(data, type, length),
- RecordType.SubsetDifferenceIndex => ParseSubsetDifferenceIndexRecord(data, type, length),
- RecordType.TypeAndVersion => ParseTypeAndVersionRecord(data, type, length),
- RecordType.DriveRevocationList => ParseDriveRevocationListRecord(data, type, length),
- RecordType.HostRevocationList => ParseHostRevocationListRecord(data, type, length),
- RecordType.VerifyMediaKey => ParseVerifyMediaKeyRecord(data, type, length),
- RecordType.Copyright => ParseCopyrightRecord(data, type, length),
+ RecordType.EndOfMediaKeyBlock => ParseEndOfMediaKeyBlockRecord(data),
+ RecordType.ExplicitSubsetDifference => ParseExplicitSubsetDifferenceRecord(data),
+ RecordType.MediaKeyData => ParseMediaKeyDataRecord(data),
+ RecordType.SubsetDifferenceIndex => ParseSubsetDifferenceIndexRecord(data),
+ RecordType.TypeAndVersion => ParseTypeAndVersionRecord(data),
+ RecordType.DriveRevocationList => ParseDriveRevocationListRecord(data),
+ RecordType.HostRevocationList => ParseHostRevocationListRecord(data),
+ RecordType.VerifyMediaKey => ParseVerifyMediaKeyRecord(data),
+ RecordType.Copyright => ParseCopyrightRecord(data),
// Unknown record type
_ => null,
@@ -91,324 +88,327 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into an end of media key block record
+ /// Parse a Stream into a CopyrightRecord
///
/// Stream to parse
- /// Filled end of media key block record on success, null on error
- private static EndOfMediaKeyBlockRecord? ParseEndOfMediaKeyBlockRecord(Stream data, RecordType type, uint length)
+ /// Filled CopyrightRecord on success, null on error
+ public static CopyrightRecord ParseCopyrightRecord(Stream data)
{
- // Verify we're calling the right parser
- if (type != RecordType.EndOfMediaKeyBlock)
- return null;
+ var obj = new CopyrightRecord();
- var record = new EndOfMediaKeyBlockRecord();
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
+ if (obj.RecordLength > 4)
+ {
+ byte[] copyright = data.ReadBytes((int)(obj.RecordLength - 4));
+ obj.Copyright = Encoding.ASCII.GetString(copyright).TrimEnd('\0');
+ }
- record.RecordType = type;
- record.RecordLength = length;
- if (length > 4)
- record.SignatureData = data.ReadBytes((int)(length - 4));
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DriveRevocationListEntry
+ ///
+ /// Stream to parse
+ /// Filled DriveRevocationListEntry on success, null on error
+ public static DriveRevocationListEntry ParseDriveRevocationListEntry(Stream data)
+ {
+ var obj = new DriveRevocationListEntry();
- return record;
+ obj.Range = data.ReadUInt16BigEndian();
+ obj.DriveID = data.ReadBytes(6);
+
+ return obj;
}
///
- /// Parse a Stream into an explicit subset-difference record
+ /// Parse a Stream into a DriveRevocationListRecord
///
/// Stream to parse
- /// Filled explicit subset-difference record on success, null on error
- private static ExplicitSubsetDifferenceRecord? ParseExplicitSubsetDifferenceRecord(Stream data, RecordType type, uint length)
+ /// Filled DriveRevocationListRecord on success, null on error
+ public static DriveRevocationListRecord ParseDriveRevocationListRecord(Stream data)
{
- // Verify we're calling the right parser
- if (type != RecordType.ExplicitSubsetDifference)
- return null;
-
- var record = new ExplicitSubsetDifferenceRecord();
-
- record.RecordType = type;
- record.RecordLength = length;
-
// Cache the current offset
- long initialOffset = data.Position - 4;
+ long initialOffset = data.Position;
- // Create the subset difference list
- var subsetDifferences = new List();
+ var obj = new DriveRevocationListRecord();
+
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
+ obj.TotalNumberOfEntries = data.ReadUInt32BigEndian();
+
+ // Try to parse the signature blocks
+ var blocks = new List();
+ uint entryCount = 0;
+ while (entryCount < obj.TotalNumberOfEntries && data.Position < initialOffset + obj.RecordLength)
+ {
+ var block = ParseDriveRevocationSignatureBlock(data);
+ entryCount += block.NumberOfEntries;
+ blocks.Add(block);
+
+ // If we have an empty block
+ if (block.NumberOfEntries == 0)
+ break;
+ }
+
+ // Set the signature blocks
+ obj.SignatureBlocks = [.. blocks];
+
+ // If there's any data left, discard it
+ if (data.Position < initialOffset + obj.RecordLength)
+ _ = data.ReadBytes((int)(initialOffset + obj.RecordLength - data.Position));
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DriveRevocationSignatureBlock
+ ///
+ /// Stream to parse
+ /// Filled DriveRevocationSignatureBlock on success, null on error
+ public static DriveRevocationSignatureBlock ParseDriveRevocationSignatureBlock(Stream data)
+ {
+ var obj = new DriveRevocationSignatureBlock();
+
+ obj.NumberOfEntries = data.ReadUInt32BigEndian();
+ obj.EntryFields = new DriveRevocationListEntry[obj.NumberOfEntries];
+ for (int i = 0; i < obj.EntryFields.Length; i++)
+ {
+ obj.EntryFields[i] = ParseDriveRevocationListEntry(data);
+ }
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a EndOfMediaKeyBlockRecord
+ ///
+ /// Stream to parse
+ /// Filled EndOfMediaKeyBlockRecord on success, null on error
+ public static EndOfMediaKeyBlockRecord ParseEndOfMediaKeyBlockRecord(Stream data)
+ {
+ var obj = new EndOfMediaKeyBlockRecord();
+
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
+ if (obj.RecordLength > 4)
+ obj.SignatureData = data.ReadBytes((int)(obj.RecordLength - 4));
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ExplicitSubsetDifferenceRecord
+ ///
+ /// Stream to parse
+ /// Filled ExplicitSubsetDifferenceRecord on success, null on error
+ public static ExplicitSubsetDifferenceRecord ParseExplicitSubsetDifferenceRecord(Stream data)
+ {
+ // Cache the current offset
+ long initialOffset = data.Position;
+
+ var obj = new ExplicitSubsetDifferenceRecord();
+
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
// Try to parse the subset differences
- while (data.Position < initialOffset + length - 5)
+ var subsetDifferences = new List();
+ while (data.Position < initialOffset + obj.RecordLength - 5)
{
- var subsetDifference = new SubsetDifference();
-
- subsetDifference.Mask = data.ReadByteValue();
- subsetDifference.Number = data.ReadUInt32BigEndian();
-
+ var subsetDifference = ParseSubsetDifference(data);
subsetDifferences.Add(subsetDifference);
}
// Set the subset differences
- record.SubsetDifferences = [.. subsetDifferences];
+ obj.SubsetDifferences = [.. subsetDifferences];
// If there's any data left, discard it
- if (data.Position < initialOffset + length)
- _ = data.ReadBytes((int)(initialOffset + length - data.Position));
+ if (data.Position < initialOffset + obj.RecordLength)
+ _ = data.ReadBytes((int)(initialOffset + obj.RecordLength - data.Position));
- return record;
+ return obj;
}
///
- /// Parse a Stream into a media key data record
+ /// Parse a Stream into a HostRevocationListEntry
///
/// Stream to parse
- /// Filled media key data record on success, null on error
- private static MediaKeyDataRecord? ParseMediaKeyDataRecord(Stream data, RecordType type, uint length)
+ /// Filled HostRevocationListEntry on success, null on error
+ public static HostRevocationListEntry ParseHostRevocationListEntry(Stream data)
{
- // Verify we're calling the right parser
- if (type != RecordType.MediaKeyData)
- return null;
+ var obj = new HostRevocationListEntry();
- var record = new MediaKeyDataRecord();
+ obj.Range = data.ReadUInt16BigEndian();
+ obj.HostID = data.ReadBytes(6);
- record.RecordType = type;
- record.RecordLength = length;
+ return obj;
+ }
+ ///
+ /// Parse a Stream into a HostRevocationListRecord
+ ///
+ /// Stream to parse
+ /// Filled HostRevocationListRecord on success, null on error
+ public static HostRevocationListRecord ParseHostRevocationListRecord(Stream data)
+ {
// Cache the current offset
- long initialOffset = data.Position - 4;
+ long initialOffset = data.Position;
- // Create the media key list
- var mediaKeys = new List();
+ var obj = new HostRevocationListRecord();
+
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
+ obj.TotalNumberOfEntries = data.ReadUInt32BigEndian();
+
+ // Try to parse the signature blocks
+ var blocks = new List();
+ for (uint entryCount = 0; entryCount < obj.TotalNumberOfEntries && data.Position < initialOffset + obj.RecordLength;)
+ {
+ var block = ParseHostRevocationSignatureBlock(data);
+ entryCount += block.NumberOfEntries;
+ blocks.Add(block);
+
+ // If we have an empty block
+ if (block.NumberOfEntries == 0)
+ break;
+ }
+
+ // Set the signature blocks
+ obj.SignatureBlocks = [.. blocks];
+
+ // If there's any data left, discard it
+ if (data.Position < initialOffset + obj.RecordLength)
+ _ = data.ReadBytes((int)(initialOffset + obj.RecordLength - data.Position));
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a HostRevocationSignatureBlock
+ ///
+ /// Stream to parse
+ /// Filled HostRevocationSignatureBlock on success, null on error
+ public static HostRevocationSignatureBlock ParseHostRevocationSignatureBlock(Stream data)
+ {
+ var obj = new HostRevocationSignatureBlock();
+
+ obj.NumberOfEntries = data.ReadUInt32BigEndian();
+ obj.EntryFields = new HostRevocationListEntry[obj.NumberOfEntries];
+ for (int i = 0; i < obj.EntryFields.Length; i++)
+ {
+ obj.EntryFields[i] = ParseHostRevocationListEntry(data);
+ }
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a MediaKeyDataRecord
+ ///
+ /// Stream to parse
+ /// Filled MediaKeyDataRecord on success, null on error
+ public static MediaKeyDataRecord ParseMediaKeyDataRecord(Stream data)
+ {
+ // Cache the current offset
+ long initialOffset = data.Position;
+
+ var obj = new MediaKeyDataRecord();
+
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
// Try to parse the media keys
- while (data.Position < initialOffset + length)
+ var mediaKeys = new List();
+ while (data.Position < initialOffset + obj.RecordLength)
{
byte[] mediaKey = data.ReadBytes(0x10);
mediaKeys.Add(mediaKey);
}
// Set the media keys
- record.MediaKeyData = [.. mediaKeys];
+ obj.MediaKeyData = [.. mediaKeys];
- return record;
+ return obj;
}
///
- /// Parse a Stream into a subset-difference index record
+ /// Parse a Stream into a SubsetDifference
///
/// Stream to parse
- /// Filled subset-difference index record on success, null on error
- private static SubsetDifferenceIndexRecord? ParseSubsetDifferenceIndexRecord(Stream data, RecordType type, uint length)
+ /// Filled SubsetDifference on success, null on error
+ public static SubsetDifference ParseSubsetDifference(Stream data)
{
- // Verify we're calling the right parser
- if (type != RecordType.SubsetDifferenceIndex)
- return null;
+ var obj = new SubsetDifference();
- var record = new SubsetDifferenceIndexRecord();
+ obj.Mask = data.ReadByteValue();
+ obj.Number = data.ReadUInt32BigEndian();
- record.RecordType = type;
- record.RecordLength = length;
+ return obj;
+ }
+ ///
+ /// Parse a Stream into a SubsetDifferenceIndexRecord
+ ///
+ /// Stream to parse
+ /// Filled SubsetDifferenceIndexRecord on success, null on error
+ public static SubsetDifferenceIndexRecord ParseSubsetDifferenceIndexRecord(Stream data)
+ {
// Cache the current offset
- long initialOffset = data.Position - 4;
+ long initialOffset = data.Position;
- record.Span = data.ReadUInt32BigEndian();
+ var obj = new SubsetDifferenceIndexRecord();
- // Create the offset list
- var offsets = new List();
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
+ obj.Span = data.ReadUInt32BigEndian();
// Try to parse the offsets
- while (data.Position < initialOffset + length)
+ var offsets = new List();
+ while (data.Position < initialOffset + obj.RecordLength)
{
uint offset = data.ReadUInt32BigEndian();
offsets.Add(offset);
}
// Set the offsets
- record.Offsets = [.. offsets];
+ obj.Offsets = [.. offsets];
- return record;
+ return obj;
}
///
- /// Parse a Stream into a type and version record
+ /// Parse a Stream into a TypeAndVersionRecord
///
/// Stream to parse
- /// Filled type and version record on success, null on error
- private static TypeAndVersionRecord? ParseTypeAndVersionRecord(Stream data, RecordType type, uint length)
+ /// Filled TypeAndVersionRecord on success, null on error
+ public static TypeAndVersionRecord ParseTypeAndVersionRecord(Stream data)
{
- // Verify we're calling the right parser
- if (type != RecordType.TypeAndVersion)
- return null;
+ var obj = new TypeAndVersionRecord();
- var record = new TypeAndVersionRecord();
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
+ obj.MediaKeyBlockType = (MediaKeyBlockType)data.ReadUInt32BigEndian();
+ obj.VersionNumber = data.ReadUInt32BigEndian();
- record.RecordType = type;
- record.RecordLength = length;
- record.MediaKeyBlockType = (MediaKeyBlockType)data.ReadUInt32BigEndian();
- record.VersionNumber = data.ReadUInt32BigEndian();
-
- return record;
+ return obj;
}
///
- /// Parse a Stream into a drive revocation list record
+ /// Parse a Stream into a VerifyMediaKeyRecord
///
/// Stream to parse
- /// Filled drive revocation list record on success, null on error
- private static DriveRevocationListRecord? ParseDriveRevocationListRecord(Stream data, RecordType type, uint length)
+ /// Filled VerifyMediaKeyRecord on success, null on error
+ public static VerifyMediaKeyRecord ParseVerifyMediaKeyRecord(Stream data)
{
- // Verify we're calling the right parser
- if (type != RecordType.DriveRevocationList)
- return null;
+ var obj = new VerifyMediaKeyRecord();
- var record = new DriveRevocationListRecord();
+ obj.RecordType = (RecordType)data.ReadByteValue();
+ obj.RecordLength = data.ReadUInt24();
+ obj.CiphertextValue = data.ReadBytes(0x10);
- record.RecordType = type;
- record.RecordLength = length;
-
- // Cache the current offset
- long initialOffset = data.Position - 4;
-
- record.TotalNumberOfEntries = data.ReadUInt32BigEndian();
-
- // Create the signature blocks list
- var blocks = new List();
-
- // Try to parse the signature blocks
- int entryCount = 0;
- while (entryCount < record.TotalNumberOfEntries && data.Position < initialOffset + length)
- {
- var block = new DriveRevocationSignatureBlock();
-
- block.NumberOfEntries = data.ReadUInt32BigEndian();
- block.EntryFields = new DriveRevocationListEntry[block.NumberOfEntries];
- for (int i = 0; i < block.EntryFields.Length; i++)
- {
- var entry = new DriveRevocationListEntry();
-
- entry.Range = data.ReadUInt16BigEndian();
- entry.DriveID = data.ReadBytes(6);
-
- block.EntryFields[i] = entry;
- entryCount++;
- }
-
- blocks.Add(block);
-
- // If we have an empty block
- if (block.NumberOfEntries == 0)
- break;
- }
-
- // Set the signature blocks
- record.SignatureBlocks = [.. blocks];
-
- // If there's any data left, discard it
- if (data.Position < initialOffset + length)
- _ = data.ReadBytes((int)(initialOffset + length - data.Position));
-
- return record;
- }
-
- ///
- /// Parse a Stream into a host revocation list record
- ///
- /// Stream to parse
- /// Filled host revocation list record on success, null on error
- private static HostRevocationListRecord? ParseHostRevocationListRecord(Stream data, RecordType type, uint length)
- {
- // Verify we're calling the right parser
- if (type != RecordType.HostRevocationList)
- return null;
-
- var record = new HostRevocationListRecord();
-
- record.RecordType = type;
- record.RecordLength = length;
-
- // Cache the current offset
- long initialOffset = data.Position - 4;
-
- record.TotalNumberOfEntries = data.ReadUInt32BigEndian();
-
- // Create the signature blocks list
- var blocks = new List();
-
- // Try to parse the signature blocks
- int entryCount = 0;
- while (entryCount < record.TotalNumberOfEntries && data.Position < initialOffset + length)
- {
- var block = new HostRevocationSignatureBlock();
-
- block.NumberOfEntries = data.ReadUInt32BigEndian();
- block.EntryFields = new HostRevocationListEntry[block.NumberOfEntries];
- for (int i = 0; i < block.EntryFields.Length; i++)
- {
- var entry = new HostRevocationListEntry();
-
- entry.Range = data.ReadUInt16BigEndian();
- entry.HostID = data.ReadBytes(6);
-
- block.EntryFields[i] = entry;
- entryCount++;
- }
-
- blocks.Add(block);
-
- // If we have an empty block
- if (block.NumberOfEntries == 0)
- break;
- }
-
- // Set the signature blocks
- record.SignatureBlocks = [.. blocks];
-
- // If there's any data left, discard it
- if (data.Position < initialOffset + length)
- _ = data.ReadBytes((int)(initialOffset + length - data.Position));
-
- return record;
- }
-
- ///
- /// Parse a Stream into a verify media key record
- ///
- /// Stream to parse
- /// Filled verify media key record on success, null on error
- private static VerifyMediaKeyRecord? ParseVerifyMediaKeyRecord(Stream data, RecordType type, uint length)
- {
- // Verify we're calling the right parser
- if (type != RecordType.VerifyMediaKey)
- return null;
-
- var record = new VerifyMediaKeyRecord();
-
- record.RecordType = type;
- record.RecordLength = length;
- record.CiphertextValue = data.ReadBytes(0x10);
-
- return record;
- }
-
- ///
- /// Parse a Stream into a copyright record
- ///
- /// Stream to parse
- /// Filled copyright record on success, null on error
- private static CopyrightRecord? ParseCopyrightRecord(Stream data, RecordType type, uint length)
- {
- // Verify we're calling the right parser
- if (type != RecordType.Copyright)
- return null;
-
- var record = new CopyrightRecord();
-
- record.RecordType = type;
- record.RecordLength = length;
- if (length > 4)
- {
- byte[] copyright = data.ReadBytes((int)(length - 4));
- record.Copyright = Encoding.ASCII.GetString(copyright).TrimEnd('\0');
- }
-
- return record;
+ return obj;
}
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/BDPlus.cs b/SabreTools.Serialization/Deserializers/BDPlus.cs
index ab1bab52..09f7d945 100644
--- a/SabreTools.Serialization/Deserializers/BDPlus.cs
+++ b/SabreTools.Serialization/Deserializers/BDPlus.cs
@@ -35,8 +35,8 @@ namespace SabreTools.Serialization.Deserializers
if (svm.Day < 1 || svm.Day > 31)
return null;
- svm.Unknown2 = data.ReadUInt32();
- svm.Length = data.ReadUInt32();
+ svm.Unknown2 = data.ReadUInt32LittleEndian();
+ svm.Length = data.ReadUInt32LittleEndian();
if (svm.Length > 0)
svm.Data = data.ReadBytes((int)svm.Length);
diff --git a/SabreTools.Serialization/Deserializers/BFPK.cs b/SabreTools.Serialization/Deserializers/BFPK.cs
index 35e0218c..cbd898c9 100644
--- a/SabreTools.Serialization/Deserializers/BFPK.cs
+++ b/SabreTools.Serialization/Deserializers/BFPK.cs
@@ -23,8 +23,8 @@ namespace SabreTools.Serialization.Deserializers
#region Header
// Try to parse the header
- var header = data.ReadType();
- if (header?.Magic != SignatureString)
+ var header = ParseHeader(data);
+ if (header.Magic != SignatureString)
return null;
// Set the archive header
@@ -58,32 +58,49 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a file entry
+ /// Parse a Stream into a FileEntry
///
/// Stream to parse
- /// Filled file entry on success, null on error
- private static FileEntry ParseFileEntry(Stream data)
+ /// Filled FileEntry on success, null on error
+ public static FileEntry ParseFileEntry(Stream data)
{
var fileEntry = new FileEntry();
- fileEntry.NameSize = data.ReadInt32();
+ fileEntry.NameSize = data.ReadInt32LittleEndian();
if (fileEntry.NameSize > 0)
{
byte[] name = data.ReadBytes(fileEntry.NameSize);
fileEntry.Name = Encoding.ASCII.GetString(name);
}
- fileEntry.UncompressedSize = data.ReadInt32();
- fileEntry.Offset = data.ReadInt32();
+ fileEntry.UncompressedSize = data.ReadInt32LittleEndian();
+ fileEntry.Offset = data.ReadInt32LittleEndian();
if (fileEntry.Offset > 0)
{
long currentOffset = data.Position;
data.Seek(fileEntry.Offset, SeekOrigin.Begin);
- fileEntry.CompressedSize = data.ReadInt32();
+ fileEntry.CompressedSize = data.ReadInt32LittleEndian();
data.Seek(currentOffset, SeekOrigin.Begin);
}
return fileEntry;
}
+
+ ///
+ /// Parse a Stream into a Header
+ ///
+ /// Stream to parse
+ /// Filled Header on success, null on error
+ public static Header ParseHeader(Stream data)
+ {
+ var obj = new Header();
+
+ byte[] magic = data.ReadBytes(4);
+ obj.Magic = Encoding.ASCII.GetString(magic);
+ obj.Version = data.ReadInt32LittleEndian();
+ obj.Files = data.ReadInt32LittleEndian();
+
+ return obj;
+ }
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/BSP.cs b/SabreTools.Serialization/Deserializers/BSP.cs
index f1e69058..b68fc348 100644
--- a/SabreTools.Serialization/Deserializers/BSP.cs
+++ b/SabreTools.Serialization/Deserializers/BSP.cs
@@ -25,9 +25,7 @@ namespace SabreTools.Serialization.Deserializers
#region Header
// Try to parse the header
- var header = data.ReadType();
- if (header?.Lumps == null || header.Lumps.Length != BSP_HEADER_LUMPS)
- return null;
+ var header = ParseBspHeader(data);
if (header.Version < 29 || header.Version > 30)
return null;
@@ -41,7 +39,7 @@ namespace SabreTools.Serialization.Deserializers
for (int l = 0; l < BSP_HEADER_LUMPS; l++)
{
// Get the next lump entry
- var lumpEntry = header.Lumps[l];
+ var lumpEntry = header.Lumps![l];
if (lumpEntry == null)
continue;
if (lumpEntry.Offset == 0 || lumpEntry.Length == 0)
@@ -115,6 +113,272 @@ namespace SabreTools.Serialization.Deserializers
}
}
+ ///
+ /// Parse a Stream into BspFace
+ ///
+ /// Stream to parse
+ /// Filled BspFace on success, null on error
+ public static BspFace ParseBspFace(Stream data)
+ {
+ var obj = new BspFace();
+
+ obj.PlaneIndex = data.ReadUInt16LittleEndian();
+ obj.PlaneSideCount = data.ReadUInt16LittleEndian();
+ obj.FirstEdgeIndex = data.ReadUInt32LittleEndian();
+ obj.NumberOfEdges = data.ReadUInt16LittleEndian();
+ obj.TextureInfoIndex = data.ReadUInt16LittleEndian();
+ obj.LightingStyles = data.ReadBytes(4);
+ obj.LightmapOffset = data.ReadInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into BspHeader
+ ///
+ /// Stream to parse
+ /// Filled BspHeader on success, null on error
+ public static BspHeader ParseBspHeader(Stream data)
+ {
+ var obj = new BspHeader();
+
+ obj.Version = data.ReadInt32LittleEndian();
+ obj.Lumps = new BspLumpEntry[BSP_HEADER_LUMPS];
+ for (int i = 0; i < BSP_HEADER_LUMPS; i++)
+ {
+ obj.Lumps[i] = ParseBspLumpEntry(data);
+ }
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into BspLeaf
+ ///
+ /// Stream to parse
+ /// Filled BspLeaf on success, null on error
+ public static BspLeaf ParseBspLeaf(Stream data)
+ {
+ var obj = new BspLeaf();
+
+ obj.Contents = (BspContents)data.ReadInt32LittleEndian();
+ obj.VisOffset = data.ReadInt32LittleEndian();
+ obj.Mins = new short[3];
+ for (int i = 0; i < 3; i++)
+ {
+ obj.Mins[i] = data.ReadInt16LittleEndian();
+ }
+ obj.Maxs = new short[3];
+ for (int i = 0; i < 3; i++)
+ {
+ obj.Maxs[i] = data.ReadInt16LittleEndian();
+ }
+ obj.FirstMarkSurfaceIndex = data.ReadUInt16LittleEndian();
+ obj.MarkSurfacesCount = data.ReadUInt16LittleEndian();
+ obj.AmbientLevels = data.ReadBytes(4);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into BspLumpEntry
+ ///
+ /// Stream to parse
+ /// Filled BspLumpEntry on success, null on error
+ public static BspLumpEntry ParseBspLumpEntry(Stream data)
+ {
+ var obj = new BspLumpEntry();
+
+ obj.Offset = data.ReadInt32LittleEndian();
+ obj.Length = data.ReadInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into BspModel
+ ///
+ /// Stream to parse
+ /// Filled BspModel on success, null on error
+ public static BspModel ParseBspModel(Stream data)
+ {
+ var obj = new BspModel();
+
+ obj.Mins = ParseVector3D(data);
+ obj.Maxs = ParseVector3D(data);
+ obj.OriginVector = ParseVector3D(data);
+ obj.HeadnodesIndex = new int[MAX_MAP_HULLS];
+ for (int i = 0; i < MAX_MAP_HULLS; i++)
+ {
+ obj.HeadnodesIndex[i] = data.ReadInt32LittleEndian();
+ }
+ obj.VisLeafsCount = data.ReadInt32LittleEndian();
+ obj.FirstFaceIndex = data.ReadInt32LittleEndian();
+ obj.FacesCount = data.ReadInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into BspNode
+ ///
+ /// Stream to parse
+ /// Filled BspNode on success, null on error
+ public static BspNode ParseBspNode(Stream data)
+ {
+ var obj = new BspNode();
+
+ obj.PlaneIndex = data.ReadUInt32LittleEndian();
+ obj.Children = new ushort[2];
+ for (int i = 0; i < 2; i++)
+ {
+ obj.Children[i] = data.ReadUInt16LittleEndian();
+ }
+ obj.Mins = new ushort[3];
+ for (int i = 0; i < 3; i++)
+ {
+ obj.Mins[i] = data.ReadUInt16LittleEndian();
+ }
+ obj.Maxs = new ushort[3];
+ for (int i = 0; i < 3; i++)
+ {
+ obj.Maxs[i] = data.ReadUInt16LittleEndian();
+ }
+ obj.FirstFace = data.ReadUInt16LittleEndian();
+ obj.FaceCount = data.ReadUInt16LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into BspTexinfo
+ ///
+ /// Stream to parse
+ /// Filled BspTexinfo on success, null on error
+ public static BspTexinfo ParseBspTexinfo(Stream data)
+ {
+ var obj = new BspTexinfo();
+
+ obj.SVector = ParseVector3D(data);
+ obj.TextureSShift = data.ReadSingle();
+ obj.TVector = ParseVector3D(data);
+ obj.TextureTShift = data.ReadSingle();
+ obj.MiptexIndex = data.ReadUInt32LittleEndian();
+ obj.Flags = (TextureFlag)data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into Clipnode
+ ///
+ /// Stream to parse
+ /// Filled Clipnode on success, null on error
+ public static Clipnode ParseClipnode(Stream data)
+ {
+ var obj = new Clipnode();
+
+ obj.PlaneIndex = data.ReadInt32LittleEndian();
+ obj.ChildrenIndices = new short[2];
+ for (int i = 0; i < 2; i++)
+ {
+ obj.ChildrenIndices[i] = data.ReadInt16LittleEndian();
+ }
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into Edge
+ ///
+ /// Stream to parse
+ /// Filled Edge on success, null on error
+ public static Edge ParseEdge(Stream data)
+ {
+ var obj = new Edge();
+
+ obj.VertexIndices = new ushort[2];
+ for (int i = 0; i < 2; i++)
+ {
+ obj.VertexIndices[i] = data.ReadUInt16LittleEndian();
+ }
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into MipTexture
+ ///
+ /// Stream to parse
+ /// Filled MipTexture on success, null on error
+ public static MipTexture ParseMipTexture(Stream data)
+ {
+ var obj = new MipTexture();
+
+ byte[] name = data.ReadBytes(MAXTEXTURENAME);
+ obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
+ obj.Width = data.ReadUInt32LittleEndian();
+ obj.Height = data.ReadUInt32LittleEndian();
+ obj.Offsets = new uint[MIPLEVELS];
+ for (int i = 0; i < MIPLEVELS; i++)
+ {
+ obj.Offsets[i] = data.ReadUInt32LittleEndian();
+ }
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into Plane
+ ///
+ /// Stream to parse
+ /// Filled Plane on success, null on error
+ public static Plane ParsePlane(Stream data)
+ {
+ var obj = new Plane();
+
+ obj.NormalVector = ParseVector3D(data);
+ obj.Distance = data.ReadSingle();
+ obj.PlaneType = (PlaneType)data.ReadInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a TextureHeader
+ ///
+ /// Stream to parse
+ /// Filled TextureHeader on success, null on error
+ public static TextureHeader ParseTextureHeader(Stream data)
+ {
+ var obj = new TextureHeader();
+
+ obj.MipTextureCount = data.ReadUInt32LittleEndian();
+ obj.Offsets = new int[obj.MipTextureCount];
+ for (int i = 0; i < obj.Offsets.Length; i++)
+ {
+ obj.Offsets[i] = data.ReadInt16LittleEndian();
+ }
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into Vector3D
+ ///
+ /// Stream to parse
+ /// Filled Vector3D on success, null on error
+ public static Vector3D ParseVector3D(Stream data)
+ {
+ var obj = new Vector3D();
+
+ obj.X = data.ReadSingle();
+ obj.Y = data.ReadSingle();
+ obj.Z = data.ReadSingle();
+
+ return obj;
+ }
+
///
/// Parse a Stream into LUMP_ENTITIES
///
@@ -167,9 +431,8 @@ namespace SabreTools.Serialization.Deserializers
var planes = new List();
while (data.Position < offset + length)
{
- var plane = data.ReadType();
- if (plane != null)
- planes.Add(plane);
+ var plane = ParsePlane(data);
+ planes.Add(plane);
}
return new PlanesLump { Planes = [.. planes] };
@@ -188,34 +451,14 @@ namespace SabreTools.Serialization.Deserializers
var textures = new List();
while (data.Position < offset + length)
{
- var texture = data.ReadType();
- if (texture != null)
- textures.Add(texture);
+ var texture = ParseMipTexture(data);
+ textures.Add(texture);
}
lump.Textures = [.. textures];
return lump;
}
- ///
- /// Parse a Stream into a Half-Life Level texture header
- ///
- /// Stream to parse
- /// Filled Half-Life Level texture header on success, null on error
- private static TextureHeader ParseTextureHeader(Stream data)
- {
- var textureHeader = new TextureHeader();
-
- textureHeader.MipTextureCount = data.ReadUInt32();
- textureHeader.Offsets = new int[textureHeader.MipTextureCount];
- for (int i = 0; i < textureHeader.Offsets.Length; i++)
- {
- textureHeader.Offsets[i] = data.ReadInt32();
- }
-
- return textureHeader;
- }
-
///
/// Parse a Stream into LUMP_VERTICES
///
@@ -226,10 +469,7 @@ namespace SabreTools.Serialization.Deserializers
var vertices = new List();
while (data.Position < offset + length)
{
- var vertex = data.ReadType();
- if (vertex == null)
- break;
-
+ var vertex = ParseVector3D(data);
vertices.Add(vertex);
}
@@ -258,7 +498,7 @@ namespace SabreTools.Serialization.Deserializers
lump.ByteOffsets[i] = new int[2];
for (int j = 0; j < 2; j++)
{
- lump.ByteOffsets[i][j] = data.ReadInt32();
+ lump.ByteOffsets[i][j] = data.ReadInt32LittleEndian();
}
}
@@ -275,9 +515,8 @@ namespace SabreTools.Serialization.Deserializers
var nodes = new List();
while (data.Position < offset + length)
{
- var node = data.ReadType();
- if (node != null)
- nodes.Add(node);
+ var node = ParseBspNode(data);
+ nodes.Add(node);
}
return new BspNodesLump { Nodes = [.. nodes] };
@@ -293,9 +532,8 @@ namespace SabreTools.Serialization.Deserializers
var texinfos = new List();
while (data.Position < offset + length)
{
- var texinfo = data.ReadType();
- if (texinfo != null)
- texinfos.Add(texinfo);
+ var texinfo = ParseBspTexinfo(data);
+ texinfos.Add(texinfo);
}
return new BspTexinfoLump { Texinfos = [.. texinfos] };
@@ -311,9 +549,8 @@ namespace SabreTools.Serialization.Deserializers
var faces = new List();
while (data.Position < offset + length)
{
- var face = data.ReadType();
- if (face != null)
- faces.Add(face);
+ var face = ParseBspFace(data);
+ faces.Add(face);
}
return new BspFacesLump { Faces = [.. faces] };
@@ -347,9 +584,8 @@ namespace SabreTools.Serialization.Deserializers
var clipnodes = new List();
while (data.Position < offset + length)
{
- var clipnode = data.ReadType();
- if (clipnode != null)
- clipnodes.Add(clipnode);
+ var clipnode = ParseClipnode(data);
+ clipnodes.Add(clipnode);
}
return new ClipnodesLump { Clipnodes = [.. clipnodes] };
@@ -365,9 +601,8 @@ namespace SabreTools.Serialization.Deserializers
var leaves = new List();
while (data.Position < offset + length)
{
- var leaf = data.ReadType();
- if (leaf != null)
- leaves.Add(leaf);
+ var leaf = ParseBspLeaf(data);
+ leaves.Add(leaf);
}
return new BspLeavesLump { Leaves = [.. leaves] };
@@ -383,7 +618,7 @@ namespace SabreTools.Serialization.Deserializers
var marksurfaces = new List();
while (data.Position < offset + length)
{
- marksurfaces.Add(data.ReadUInt16());
+ marksurfaces.Add(data.ReadUInt16LittleEndian());
}
return new MarksurfacesLump { Marksurfaces = [.. marksurfaces] };
@@ -399,9 +634,8 @@ namespace SabreTools.Serialization.Deserializers
var edges = new List();
while (data.Position < offset + length)
{
- var edge = data.ReadType();
- if (edge != null)
- edges.Add(edge);
+ var edge = ParseEdge(data);
+ edges.Add(edge);
}
return new EdgesLump { Edges = [.. edges] };
@@ -417,7 +651,7 @@ namespace SabreTools.Serialization.Deserializers
var surfedges = new List();
while (data.Position < offset + length)
{
- surfedges.Add(data.ReadInt32());
+ surfedges.Add(data.ReadInt32LittleEndian());
}
return new SurfedgesLump { Surfedges = [.. surfedges] };
@@ -433,9 +667,8 @@ namespace SabreTools.Serialization.Deserializers
var models = new List();
while (data.Position < offset + length)
{
- var model = data.ReadType();
- if (model != null)
- models.Add(model);
+ var model = ParseBspModel(data);
+ models.Add(model);
}
return new BspModelsLump { Models = [.. models] };
diff --git a/SabreTools.Serialization/Deserializers/CFB.cs b/SabreTools.Serialization/Deserializers/CFB.cs
index 8267fb4c..398a58c4 100644
--- a/SabreTools.Serialization/Deserializers/CFB.cs
+++ b/SabreTools.Serialization/Deserializers/CFB.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
+using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.CFB;
using static SabreTools.Models.CFB.Constants;
@@ -26,7 +27,17 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the file header
var fileHeader = ParseFileHeader(data);
- if (fileHeader == null)
+ if (fileHeader?.Signature != SignatureUInt64)
+ return null;
+ if (fileHeader.ByteOrder != 0xFFFE)
+ return null;
+ if (fileHeader.MajorVersion == 3 && fileHeader.SectorShift != 0x0009)
+ return null;
+ else if (fileHeader.MajorVersion == 4 && fileHeader.SectorShift != 0x000C)
+ return null;
+ if (fileHeader.MajorVersion == 3 && fileHeader.NumberOfDirectorySectors != 0)
+ return null;
+ if (fileHeader.MiniStreamCutoffSize != 0x00001000)
return null;
// Set the file header
@@ -228,32 +239,69 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a file header
+ /// Parse a Stream into a DirectoryEntry
///
/// Stream to parse
- /// Filled file header on success, null on error
- private static FileHeader? ParseFileHeader(Stream data)
+ /// Filled DirectoryEntry on success, null on error
+ public static DirectoryEntry ParseDirectoryEntry(Stream data)
{
- var header = data.ReadType();
+ var obj = new DirectoryEntry();
- if (header?.Signature != SignatureUInt64)
- return null;
- if (header.ByteOrder != 0xFFFE)
- return null;
- if (header.MajorVersion == 3 && header.SectorShift != 0x0009)
- return null;
- else if (header.MajorVersion == 4 && header.SectorShift != 0x000C)
- return null;
- if (header.MajorVersion == 3 && header.NumberOfDirectorySectors != 0)
- return null;
- if (header.MiniStreamCutoffSize != 0x00001000)
- return null;
+ byte[] name = data.ReadBytes(32);
+ obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
+ obj.NameLength = data.ReadUInt16LittleEndian();
+ obj.ObjectType = (ObjectType)data.ReadByteValue();
+ obj.ColorFlag = (ColorFlag)data.ReadByteValue();
+ obj.LeftSiblingID = (StreamID)data.ReadUInt32LittleEndian();
+ obj.RightSiblingID = (StreamID)data.ReadUInt32LittleEndian();
+ obj.ChildID = (StreamID)data.ReadUInt32LittleEndian();
+ obj.CLSID = data.ReadGuid();
+ obj.StateBits = data.ReadUInt32LittleEndian();
+ obj.CreationTime = data.ReadUInt64LittleEndian();
+ obj.ModifiedTime = data.ReadUInt64LittleEndian();
+ obj.StartingSectorLocation = data.ReadUInt32LittleEndian();
+ obj.StreamSize = data.ReadUInt64LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a FileHeader
+ ///
+ /// Stream to parse
+ /// Filled FileHeader on success, null on error
+ public static FileHeader ParseFileHeader(Stream data)
+ {
+ var obj = new FileHeader();
+
+ obj.Signature = data.ReadUInt64LittleEndian();
+ obj.CLSID = data.ReadGuid();
+ obj.MinorVersion = data.ReadUInt16LittleEndian();
+ obj.MajorVersion = data.ReadUInt16LittleEndian();
+ obj.ByteOrder = data.ReadUInt16LittleEndian();
+ obj.SectorShift = data.ReadUInt16LittleEndian();
+ obj.MiniSectorShift = data.ReadUInt16LittleEndian();
+ obj.Reserved = data.ReadBytes(6);
+ obj.NumberOfDirectorySectors = data.ReadUInt32LittleEndian();
+ obj.NumberOfFATSectors = data.ReadUInt32LittleEndian();
+ obj.FirstDirectorySectorLocation = data.ReadUInt32LittleEndian();
+ obj.TransactionSignatureNumber = data.ReadUInt32LittleEndian();
+ obj.MiniStreamCutoffSize = data.ReadUInt32LittleEndian();
+ obj.FirstMiniFATSectorLocation = data.ReadUInt32LittleEndian();
+ obj.NumberOfMiniFATSectors = data.ReadUInt32LittleEndian();
+ obj.FirstDIFATSectorLocation = data.ReadUInt32LittleEndian();
+ obj.NumberOfDIFATSectors = data.ReadUInt32LittleEndian();
+ obj.DIFAT = new SectorNumber[109];
+ for (int i = 0; i < 109; i++)
+ {
+ obj.DIFAT[i] = (SectorNumber)data.ReadUInt32LittleEndian();
+ }
// Skip rest of sector for version 4
- if (header.MajorVersion == 4)
+ if (obj.MajorVersion == 4)
_ = data.ReadBytes(3584);
- return header;
+ return obj;
}
///
@@ -294,9 +342,7 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryEntries.Length; i++)
{
- var directoryEntry = data.ReadType();
- if (directoryEntry == null)
- return null;
+ var directoryEntry = ParseDirectoryEntry(data);
// Handle version 3 entries
if (majorVersion == 3)
diff --git a/SabreTools.Serialization/Deserializers/CHD.cs b/SabreTools.Serialization/Deserializers/CHD.cs
index 9dbfd7b7..9f073da2 100644
--- a/SabreTools.Serialization/Deserializers/CHD.cs
+++ b/SabreTools.Serialization/Deserializers/CHD.cs
@@ -22,15 +22,70 @@ namespace SabreTools.Serialization.Deserializers
uint version = GetVersion(data);
// Read and return the current CHD
- return version switch
+ switch (version)
{
- 1 => ParseHeaderV1(data),
- 2 => ParseHeaderV2(data),
- 3 => ParseHeaderV3(data),
- 4 => ParseHeaderV4(data),
- 5 => ParseHeaderV5(data),
- _ => null,
- };
+ case 1:
+ var headerV1 = ParseHeaderV1(data);
+
+ if (headerV1.Tag != Constants.SignatureString)
+ return null;
+ if (headerV1.Length != Constants.HeaderV1Size)
+ return null;
+ if (headerV1.Compression > CompressionType.CHDCOMPRESSION_ZLIB)
+ return null;
+
+ return headerV1;
+
+ case 2:
+ var headerV2 = ParseHeaderV2(data);
+
+ if (headerV2.Tag != Constants.SignatureString)
+ return null;
+ if (headerV2.Length != Constants.HeaderV2Size)
+ return null;
+ if (headerV2.Compression > CompressionType.CHDCOMPRESSION_ZLIB)
+ return null;
+
+ return headerV2;
+
+ case 3:
+ var headerV3 = ParseHeaderV3(data);
+
+ if (headerV3.Tag != Constants.SignatureString)
+ return null;
+ if (headerV3.Length != Constants.HeaderV3Size)
+ return null;
+ if (headerV3.Compression > CompressionType.CHDCOMPRESSION_ZLIB_PLUS)
+ return null;
+
+ return headerV3;
+
+ case 4:
+ var headerV4 = ParseHeaderV1(data);
+
+ if (headerV4.Tag != Constants.SignatureString)
+ return null;
+ if (headerV4.Length != Constants.HeaderV4Size)
+ return null;
+ if (headerV4.Compression > CompressionType.CHDCOMPRESSION_AV)
+ return null;
+
+ return headerV4;
+
+ case 5:
+ var headerV5 = ParseHeaderV1(data);
+
+ if (headerV5.Tag != Constants.SignatureString)
+ return null;
+ if (headerV5.Length != Constants.HeaderV5Size)
+ return null;
+
+ return headerV5;
+
+ default:
+ return null;
+
+ }
}
catch
{
@@ -83,81 +138,129 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a V1 header
+ /// Parse a Stream into a HeaderV1
///
- private static HeaderV1? ParseHeaderV1(Stream data)
+ public static HeaderV1 ParseHeaderV1(Stream data)
{
- var header = data.ReadType();
- if (header?.Tag != Constants.SignatureString)
- return null;
- if (header.Length != Constants.HeaderV1Size)
- return null;
- if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB)
- return null;
+ var obj = new HeaderV1();
- return header;
+ byte[] tag = data.ReadBytes(8);
+ obj.Tag = Encoding.ASCII.GetString(tag);
+ obj.Length = data.ReadUInt32LittleEndian();
+ obj.Version = data.ReadUInt32LittleEndian();
+ obj.Flags = (Flags)data.ReadUInt32LittleEndian();
+ obj.Compression = (CompressionType)data.ReadUInt32LittleEndian();
+ obj.HunkSize = data.ReadUInt32LittleEndian();
+ obj.TotalHunks = data.ReadUInt32LittleEndian();
+ obj.Cylinders = data.ReadUInt32LittleEndian();
+ obj.Heads = data.ReadUInt32LittleEndian();
+ obj.Sectors = data.ReadUInt32LittleEndian();
+ obj.MD5 = data.ReadBytes(16);
+ obj.ParentMD5 = data.ReadBytes(16);
+
+ return obj;
}
///
/// Parse a Stream into a V2 header
///
- private static HeaderV2? ParseHeaderV2(Stream data)
+ public static HeaderV2 ParseHeaderV2(Stream data)
{
- var header = data.ReadType();
- if (header?.Tag != Constants.SignatureString)
- return null;
- if (header.Length != Constants.HeaderV2Size)
- return null;
- if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB)
- return null;
+ var obj = new HeaderV2();
- return header;
+ byte[] tag = data.ReadBytes(8);
+ obj.Tag = Encoding.ASCII.GetString(tag);
+ obj.Length = data.ReadUInt32LittleEndian();
+ obj.Version = data.ReadUInt32LittleEndian();
+ obj.Flags = (Flags)data.ReadUInt32LittleEndian();
+ obj.Compression = (CompressionType)data.ReadUInt32LittleEndian();
+ obj.HunkSize = data.ReadUInt32LittleEndian();
+ obj.TotalHunks = data.ReadUInt32LittleEndian();
+ obj.Cylinders = data.ReadUInt32LittleEndian();
+ obj.Heads = data.ReadUInt32LittleEndian();
+ obj.Sectors = data.ReadUInt32LittleEndian();
+ obj.MD5 = data.ReadBytes(16);
+ obj.ParentMD5 = data.ReadBytes(16);
+ obj.BytesPerSector = data.ReadUInt32LittleEndian();
+
+ return obj;
}
///
/// Parse a Stream into a V3 header
///
- private static HeaderV3? ParseHeaderV3(Stream data)
+ public static HeaderV3 ParseHeaderV3(Stream data)
{
- var header = data.ReadType();
- if (header?.Tag != Constants.SignatureString)
- return null;
- if (header.Length != Constants.HeaderV3Size)
- return null;
- if (header.Compression > CompressionType.CHDCOMPRESSION_ZLIB_PLUS)
- return null;
+ var obj = new HeaderV3();
- return header;
+ byte[] tag = data.ReadBytes(8);
+ obj.Tag = Encoding.ASCII.GetString(tag);
+ obj.Length = data.ReadUInt32LittleEndian();
+ obj.Version = data.ReadUInt32LittleEndian();
+ obj.Flags = (Flags)data.ReadUInt32LittleEndian();
+ obj.Compression = (CompressionType)data.ReadUInt32LittleEndian();
+ obj.TotalHunks = data.ReadUInt32LittleEndian();
+ obj.LogicalBytes = data.ReadUInt64LittleEndian();
+ obj.MetaOffset = data.ReadUInt64LittleEndian();
+ obj.MD5 = data.ReadBytes(16);
+ obj.ParentMD5 = data.ReadBytes(16);
+ obj.HunkBytes = data.ReadUInt32LittleEndian();
+ obj.SHA1 = data.ReadBytes(20);
+ obj.ParentSHA1 = data.ReadBytes(20);
+
+ return obj;
}
///
/// Parse a Stream into a V4 header
///
- private static HeaderV4? ParseHeaderV4(Stream data)
+ public static HeaderV4? ParseHeaderV4(Stream data)
{
- var header = data.ReadType();
- if (header?.Tag != Constants.SignatureString)
- return null;
- if (header.Length != Constants.HeaderV4Size)
- return null;
- if (header.Compression > CompressionType.CHDCOMPRESSION_AV)
- return null;
+ var obj = new HeaderV4();
- return header;
+ byte[] tag = data.ReadBytes(8);
+ obj.Tag = Encoding.ASCII.GetString(tag);
+ obj.Length = data.ReadUInt32LittleEndian();
+ obj.Version = data.ReadUInt32LittleEndian();
+ obj.Flags = (Flags)data.ReadUInt32LittleEndian();
+ obj.Compression = (CompressionType)data.ReadUInt32LittleEndian();
+ obj.TotalHunks = data.ReadUInt32LittleEndian();
+ obj.LogicalBytes = data.ReadUInt64LittleEndian();
+ obj.MetaOffset = data.ReadUInt64LittleEndian();
+ obj.HunkBytes = data.ReadUInt32LittleEndian();
+ obj.SHA1 = data.ReadBytes(20);
+ obj.ParentSHA1 = data.ReadBytes(20);
+ obj.RawSHA1 = data.ReadBytes(20);
+
+ return obj;
}
///
/// Parse a Stream into a V5 header
///
- private static HeaderV5? ParseHeaderV5(Stream data)
+ public static HeaderV5 ParseHeaderV5(Stream data)
{
- var header = data.ReadType();
- if (header?.Tag != Constants.SignatureString)
- return null;
- if (header.Length != Constants.HeaderV5Size)
- return null;
+ var obj = new HeaderV5();
- return header;
+ byte[] tag = data.ReadBytes(8);
+ obj.Tag = Encoding.ASCII.GetString(tag);
+ obj.Length = data.ReadUInt32LittleEndian();
+ obj.Version = data.ReadUInt32LittleEndian();
+ obj.Compressors = new CodecType[4];
+ for (int i = 0; i < 4; i++)
+ {
+ obj.Compressors[i] = (CodecType)data.ReadUInt32LittleEndian();
+ }
+ obj.LogicalBytes = data.ReadUInt64LittleEndian();
+ obj.MapOffset = data.ReadUInt64LittleEndian();
+ obj.MetaOffset = data.ReadUInt64LittleEndian();
+ obj.HunkBytes = data.ReadUInt32LittleEndian();
+ obj.UnitBytes = data.ReadUInt32LittleEndian();
+ obj.RawSHA1 = data.ReadBytes(20);
+ obj.SHA1 = data.ReadBytes(20);
+ obj.ParentSHA1 = data.ReadBytes(20);
+
+ return obj;
}
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/CIA.cs b/SabreTools.Serialization/Deserializers/CIA.cs
index 3c91b6d3..e9134c44 100644
--- a/SabreTools.Serialization/Deserializers/CIA.cs
+++ b/SabreTools.Serialization/Deserializers/CIA.cs
@@ -22,9 +22,7 @@ namespace SabreTools.Serialization.Deserializers
#region CIA Header
// Try to parse the header
- var header = data.ReadType();
- if (header == null)
- return null;
+ var header = ParseCIAHeader(data);
if (header.CertificateChainSize > data.Length)
return null;
if (header.TicketSize > data.Length)
@@ -119,15 +117,7 @@ namespace SabreTools.Serialization.Deserializers
// If we have a meta data
if (header.MetaSize > 0)
- {
- // Try to parse the meta
- var meta = data.ReadType();
- if (meta == null)
- return null;
-
- // Set the meta
- cia.MetaData = meta;
- }
+ cia.MetaData = ParseMetaData(data);
#endregion
@@ -141,161 +131,235 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a certificate
+ /// Parse a Stream into a Certificate
///
/// Stream to parse
- /// Filled certificate on success, null on error
+ /// Filled Certificate on success, null on error
public static Certificate? ParseCertificate(Stream data)
{
- var certificate = new Certificate();
+ var obj = new Certificate();
- certificate.SignatureType = (SignatureType)data.ReadUInt32();
- switch (certificate.SignatureType)
+ obj.SignatureType = (SignatureType)data.ReadUInt32LittleEndian();
+ switch (obj.SignatureType)
{
case SignatureType.RSA_4096_SHA1:
case SignatureType.RSA_4096_SHA256:
- certificate.SignatureSize = 0x200;
- certificate.PaddingSize = 0x3C;
+ obj.SignatureSize = 0x200;
+ obj.PaddingSize = 0x3C;
break;
case SignatureType.RSA_2048_SHA1:
case SignatureType.RSA_2048_SHA256:
- certificate.SignatureSize = 0x100;
- certificate.PaddingSize = 0x3C;
+ obj.SignatureSize = 0x100;
+ obj.PaddingSize = 0x3C;
break;
case SignatureType.ECDSA_SHA1:
case SignatureType.ECDSA_SHA256:
- certificate.SignatureSize = 0x3C;
- certificate.PaddingSize = 0x40;
+ obj.SignatureSize = 0x3C;
+ obj.PaddingSize = 0x40;
break;
default:
return null;
}
- certificate.Signature = data.ReadBytes(certificate.SignatureSize);
- certificate.Padding = data.ReadBytes(certificate.PaddingSize);
+ obj.Signature = data.ReadBytes(obj.SignatureSize);
+ obj.Padding = data.ReadBytes(obj.PaddingSize);
byte[] issuer = data.ReadBytes(0x40);
- certificate.Issuer = Encoding.ASCII.GetString(issuer).TrimEnd('\0');
- certificate.KeyType = (PublicKeyType)data.ReadUInt32();
+ obj.Issuer = Encoding.ASCII.GetString(issuer).TrimEnd('\0');
+ obj.KeyType = (PublicKeyType)data.ReadUInt32LittleEndian();
byte[] name = data.ReadBytes(0x40);
- certificate.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
- certificate.ExpirationTime = data.ReadUInt32();
+ obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
+ obj.ExpirationTime = data.ReadUInt32LittleEndian();
- switch (certificate.KeyType)
+ switch (obj.KeyType)
{
case PublicKeyType.RSA_4096:
- certificate.RSAModulus = data.ReadBytes(0x200);
- certificate.RSAPublicExponent = data.ReadUInt32();
- certificate.RSAPadding = data.ReadBytes(0x34);
+ obj.RSAModulus = data.ReadBytes(0x200);
+ obj.RSAPublicExponent = data.ReadUInt32LittleEndian();
+ obj.RSAPadding = data.ReadBytes(0x34);
break;
case PublicKeyType.RSA_2048:
- certificate.RSAModulus = data.ReadBytes(0x100);
- certificate.RSAPublicExponent = data.ReadUInt32();
- certificate.RSAPadding = data.ReadBytes(0x34);
+ obj.RSAModulus = data.ReadBytes(0x100);
+ obj.RSAPublicExponent = data.ReadUInt32LittleEndian();
+ obj.RSAPadding = data.ReadBytes(0x34);
break;
case PublicKeyType.EllipticCurve:
- certificate.ECCPublicKey = data.ReadBytes(0x3C);
- certificate.ECCPadding = data.ReadBytes(0x3C);
+ obj.ECCPublicKey = data.ReadBytes(0x3C);
+ obj.ECCPadding = data.ReadBytes(0x3C);
break;
default:
return null;
}
- return certificate;
+ return obj;
}
///
- /// Parse a Stream into a ticket
+ /// Parse a Stream into a CIAHeader
+ ///
+ /// Stream to parse
+ /// Filled CIAHeader on success, null on error
+ public static CIAHeader ParseCIAHeader(Stream data)
+ {
+ var obj = new CIAHeader();
+
+ obj.HeaderSize = data.ReadUInt32LittleEndian();
+ obj.Type = data.ReadUInt16LittleEndian();
+ obj.Version = data.ReadUInt16LittleEndian();
+ obj.CertificateChainSize = data.ReadUInt32LittleEndian();
+ obj.TicketSize = data.ReadUInt32LittleEndian();
+ obj.TMDFileSize = data.ReadUInt32LittleEndian();
+ obj.MetaSize = data.ReadUInt32LittleEndian();
+ obj.ContentSize = data.ReadUInt64LittleEndian();
+ obj.ContentIndex = data.ReadBytes(0x2000);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ContentChunkRecord
+ ///
+ /// Stream to parse
+ /// Filled ContentChunkRecord on success, null on error
+ public static ContentChunkRecord ParseContentChunkRecord(Stream data)
+ {
+ var obj = new ContentChunkRecord();
+
+ obj.ContentId = data.ReadUInt32LittleEndian();
+ obj.ContentIndex = (ContentIndex)data.ReadUInt16LittleEndian();
+ obj.ContentType = (TMDContentType)data.ReadUInt16LittleEndian();
+ obj.ContentSize = data.ReadUInt64LittleEndian();
+ obj.SHA256Hash = data.ReadBytes(0x20);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ContentInfoRecord
+ ///
+ /// Stream to parse
+ /// Filled ContentInfoRecord on success, null on error
+ public static ContentInfoRecord ParseContentInfoRecord(Stream data)
+ {
+ var obj = new ContentInfoRecord();
+
+ obj.ContentIndexOffset = data.ReadUInt16LittleEndian();
+ obj.ContentCommandCount = data.ReadUInt16LittleEndian();
+ obj.UnhashedContentRecordsSHA256Hash = data.ReadBytes(0x20);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a MetaData
+ ///
+ /// Stream to parse
+ /// Filled MetaData on success, null on error
+ public static MetaData ParseMetaData(Stream data)
+ {
+ var obj = new MetaData();
+
+ obj.TitleIDDependencyList = data.ReadBytes(0x180);
+ obj.Reserved1 = data.ReadBytes(0x180);
+ obj.CoreVersion = data.ReadUInt32LittleEndian();
+ obj.Reserved2 = data.ReadBytes(0xFC);
+ obj.IconData = data.ReadBytes(0x36C0);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a Ticket
///
/// Stream to parse
/// Indicates if the ticket is from CDN
- /// Filled ticket on success, null on error
+ /// Filled Ticket on success, null on error
public static Ticket? ParseTicket(Stream data, bool fromCdn = false)
{
- var ticket = new Ticket();
+ var obj = new Ticket();
- ticket.SignatureType = (SignatureType)data.ReadUInt32();
- switch (ticket.SignatureType)
+ obj.SignatureType = (SignatureType)data.ReadUInt32LittleEndian();
+ switch (obj.SignatureType)
{
case SignatureType.RSA_4096_SHA1:
case SignatureType.RSA_4096_SHA256:
- ticket.SignatureSize = 0x200;
- ticket.PaddingSize = 0x3C;
+ obj.SignatureSize = 0x200;
+ obj.PaddingSize = 0x3C;
break;
case SignatureType.RSA_2048_SHA1:
case SignatureType.RSA_2048_SHA256:
- ticket.SignatureSize = 0x100;
- ticket.PaddingSize = 0x3C;
+ obj.SignatureSize = 0x100;
+ obj.PaddingSize = 0x3C;
break;
case SignatureType.ECDSA_SHA1:
case SignatureType.ECDSA_SHA256:
- ticket.SignatureSize = 0x3C;
- ticket.PaddingSize = 0x40;
+ obj.SignatureSize = 0x3C;
+ obj.PaddingSize = 0x40;
break;
default:
return null;
}
- ticket.Signature = data.ReadBytes(ticket.SignatureSize);
- ticket.Padding = data.ReadBytes(ticket.PaddingSize);
+ obj.Signature = data.ReadBytes(obj.SignatureSize);
+ obj.Padding = data.ReadBytes(obj.PaddingSize);
byte[] issuer = data.ReadBytes(0x40);
- ticket.Issuer = Encoding.ASCII.GetString(issuer).TrimEnd('\0');
- ticket.ECCPublicKey = data.ReadBytes(0x3C);
- ticket.Version = data.ReadByteValue();
- ticket.CaCrlVersion = data.ReadByteValue();
- ticket.SignerCrlVersion = data.ReadByteValue();
- ticket.TitleKey = data.ReadBytes(0x10);
- ticket.Reserved1 = data.ReadByteValue();
- ticket.TicketID = data.ReadUInt64();
- ticket.ConsoleID = data.ReadUInt32();
- ticket.TitleID = data.ReadUInt64();
- ticket.Reserved2 = data.ReadBytes(2);
- ticket.TicketTitleVersion = data.ReadUInt16();
- ticket.Reserved3 = data.ReadBytes(8);
- ticket.LicenseType = data.ReadByteValue();
- ticket.CommonKeyYIndex = data.ReadByteValue();
- ticket.Reserved4 = data.ReadBytes(0x2A);
- ticket.eShopAccountID = data.ReadUInt32();
- ticket.Reserved5 = data.ReadByteValue();
- ticket.Audit = data.ReadByteValue();
- ticket.Reserved6 = data.ReadBytes(0x42);
- ticket.Limits = new uint[0x10];
- for (int i = 0; i < ticket.Limits.Length; i++)
+ obj.Issuer = Encoding.ASCII.GetString(issuer).TrimEnd('\0');
+ obj.ECCPublicKey = data.ReadBytes(0x3C);
+ obj.Version = data.ReadByteValue();
+ obj.CaCrlVersion = data.ReadByteValue();
+ obj.SignerCrlVersion = data.ReadByteValue();
+ obj.TitleKey = data.ReadBytes(0x10);
+ obj.Reserved1 = data.ReadByteValue();
+ obj.TicketID = data.ReadUInt64LittleEndian();
+ obj.ConsoleID = data.ReadUInt32LittleEndian();
+ obj.TitleID = data.ReadUInt64LittleEndian();
+ obj.Reserved2 = data.ReadBytes(2);
+ obj.TicketTitleVersion = data.ReadUInt16LittleEndian();
+ obj.Reserved3 = data.ReadBytes(8);
+ obj.LicenseType = data.ReadByteValue();
+ obj.CommonKeyYIndex = data.ReadByteValue();
+ obj.Reserved4 = data.ReadBytes(0x2A);
+ obj.eShopAccountID = data.ReadUInt32LittleEndian();
+ obj.Reserved5 = data.ReadByteValue();
+ obj.Audit = data.ReadByteValue();
+ obj.Reserved6 = data.ReadBytes(0x42);
+ obj.Limits = new uint[0x10];
+ for (int i = 0; i < obj.Limits.Length; i++)
{
- ticket.Limits[i] = data.ReadUInt32();
+ obj.Limits[i] = data.ReadUInt32LittleEndian();
}
// Seek to the content index size
data.Seek(4, SeekOrigin.Current);
// Read the size (big-endian)
- ticket.ContentIndexSize = data.ReadUInt32BigEndian();
+ obj.ContentIndexSize = data.ReadUInt32BigEndian();
// Seek back to the start of the content index
data.Seek(-8, SeekOrigin.Current);
- ticket.ContentIndex = data.ReadBytes((int)ticket.ContentIndexSize);
+ obj.ContentIndex = data.ReadBytes((int)obj.ContentIndexSize);
// Certificates only exist in standalone CETK files
if (fromCdn)
{
- ticket.CertificateChain = new Certificate[2];
+ obj.CertificateChain = new Certificate[2];
for (int i = 0; i < 2; i++)
{
var certificate = ParseCertificate(data);
if (certificate == null)
return null;
- ticket.CertificateChain[i] = certificate;
+ obj.CertificateChain[i] = certificate;
}
}
- return ticket;
+ return obj;
}
///
@@ -306,90 +370,84 @@ namespace SabreTools.Serialization.Deserializers
/// Filled title metadata on success, null on error
public static TitleMetadata? ParseTitleMetadata(Stream data, bool fromCdn = false)
{
- var titleMetadata = new TitleMetadata();
+ var obj = new TitleMetadata();
- titleMetadata.SignatureType = (SignatureType)data.ReadUInt32();
- switch (titleMetadata.SignatureType)
+ obj.SignatureType = (SignatureType)data.ReadUInt32LittleEndian();
+ switch (obj.SignatureType)
{
case SignatureType.RSA_4096_SHA1:
case SignatureType.RSA_4096_SHA256:
- titleMetadata.SignatureSize = 0x200;
- titleMetadata.PaddingSize = 0x3C;
+ obj.SignatureSize = 0x200;
+ obj.PaddingSize = 0x3C;
break;
case SignatureType.RSA_2048_SHA1:
case SignatureType.RSA_2048_SHA256:
- titleMetadata.SignatureSize = 0x100;
- titleMetadata.PaddingSize = 0x3C;
+ obj.SignatureSize = 0x100;
+ obj.PaddingSize = 0x3C;
break;
case SignatureType.ECDSA_SHA1:
case SignatureType.ECDSA_SHA256:
- titleMetadata.SignatureSize = 0x3C;
- titleMetadata.PaddingSize = 0x40;
+ obj.SignatureSize = 0x3C;
+ obj.PaddingSize = 0x40;
break;
default:
return null;
}
- titleMetadata.Signature = data.ReadBytes(titleMetadata.SignatureSize);
- titleMetadata.Padding1 = data.ReadBytes(titleMetadata.PaddingSize);
+ obj.Signature = data.ReadBytes(obj.SignatureSize);
+ obj.Padding1 = data.ReadBytes(obj.PaddingSize);
byte[] issuer = data.ReadBytes(0x40);
- titleMetadata.Issuer = Encoding.ASCII.GetString(issuer).TrimEnd('\0');
- titleMetadata.Version = data.ReadByteValue();
- titleMetadata.CaCrlVersion = data.ReadByteValue();
- titleMetadata.SignerCrlVersion = data.ReadByteValue();
- titleMetadata.Reserved1 = data.ReadByteValue();
- titleMetadata.SystemVersion = data.ReadUInt64();
- titleMetadata.TitleID = data.ReadUInt64();
- titleMetadata.TitleType = data.ReadUInt32();
- titleMetadata.GroupID = data.ReadUInt16();
- titleMetadata.SaveDataSize = data.ReadUInt32();
- titleMetadata.SRLPrivateSaveDataSize = data.ReadUInt32();
- titleMetadata.Reserved2 = data.ReadBytes(4);
- titleMetadata.SRLFlag = data.ReadByteValue();
- titleMetadata.Reserved3 = data.ReadBytes(0x31);
- titleMetadata.AccessRights = data.ReadUInt32();
- titleMetadata.TitleVersion = data.ReadUInt16();
- titleMetadata.ContentCount = data.ReadUInt16BigEndian();
- titleMetadata.BootContent = data.ReadUInt16();
- titleMetadata.Padding2 = data.ReadBytes(2);
- titleMetadata.SHA256HashContentInfoRecords = data.ReadBytes(0x20);
- titleMetadata.ContentInfoRecords = new ContentInfoRecord[64];
+ obj.Issuer = Encoding.ASCII.GetString(issuer).TrimEnd('\0');
+ obj.Version = data.ReadByteValue();
+ obj.CaCrlVersion = data.ReadByteValue();
+ obj.SignerCrlVersion = data.ReadByteValue();
+ obj.Reserved1 = data.ReadByteValue();
+ obj.SystemVersion = data.ReadUInt64LittleEndian();
+ obj.TitleID = data.ReadUInt64LittleEndian();
+ obj.TitleType = data.ReadUInt32LittleEndian();
+ obj.GroupID = data.ReadUInt16LittleEndian();
+ obj.SaveDataSize = data.ReadUInt32LittleEndian();
+ obj.SRLPrivateSaveDataSize = data.ReadUInt32LittleEndian();
+ obj.Reserved2 = data.ReadBytes(4);
+ obj.SRLFlag = data.ReadByteValue();
+ obj.Reserved3 = data.ReadBytes(0x31);
+ obj.AccessRights = data.ReadUInt32LittleEndian();
+ obj.TitleVersion = data.ReadUInt16LittleEndian();
+ obj.ContentCount = data.ReadUInt16BigEndian();
+ obj.BootContent = data.ReadUInt16LittleEndian();
+ obj.Padding2 = data.ReadBytes(2);
+ obj.SHA256HashContentInfoRecords = data.ReadBytes(0x20);
+ obj.ContentInfoRecords = new ContentInfoRecord[64];
for (int i = 0; i < 64; i++)
{
- var contentInfoRecord = data.ReadType();
- if (contentInfoRecord == null)
- return null;
-
- titleMetadata.ContentInfoRecords[i] = contentInfoRecord;
+ var contentInfoRecord = ParseContentInfoRecord(data);
+ obj.ContentInfoRecords[i] = contentInfoRecord;
}
- titleMetadata.ContentChunkRecords = new ContentChunkRecord[titleMetadata.ContentCount];
- for (int i = 0; i < titleMetadata.ContentCount; i++)
+ obj.ContentChunkRecords = new ContentChunkRecord[obj.ContentCount];
+ for (int i = 0; i < obj.ContentCount; i++)
{
- var contentChunkRecord = data.ReadType();
- if (contentChunkRecord == null)
- return null;
-
- titleMetadata.ContentChunkRecords[i] = contentChunkRecord;
+ var contentChunkRecord = ParseContentChunkRecord(data);
+ obj.ContentChunkRecords[i] = contentChunkRecord;
}
// Certificates only exist in standalone TMD files
if (fromCdn)
{
- titleMetadata.CertificateChain = new Certificate[2];
+ obj.CertificateChain = new Certificate[2];
for (int i = 0; i < 2; i++)
{
var certificate = ParseCertificate(data);
if (certificate == null)
return null;
- titleMetadata.CertificateChain[i] = certificate;
+ obj.CertificateChain[i] = certificate;
}
}
- return titleMetadata;
+ return obj;
}
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/GCF.cs b/SabreTools.Serialization/Deserializers/GCF.cs
index 9af84b0d..94656513 100644
--- a/SabreTools.Serialization/Deserializers/GCF.cs
+++ b/SabreTools.Serialization/Deserializers/GCF.cs
@@ -22,10 +22,10 @@ namespace SabreTools.Serialization.Deserializers
#region Header
// Try to parse the header
- var header = data.ReadType();
- if (header?.Dummy0 != 0x00000001)
+ var header = ParseHeader(data);
+ if (header.Dummy0 != 0x00000001)
return null;
- if (header?.MajorVersion != 0x00000001)
+ if (header.MajorVersion != 0x00000001)
return null;
if (header.MinorVersion != 3 && header.MinorVersion != 5 && header.MinorVersion != 6)
return null;
@@ -37,74 +37,49 @@ namespace SabreTools.Serialization.Deserializers
#region Block Entry Header
- // Try to parse the block entry header
- var blockEntryHeader = data.ReadType();
- if (blockEntryHeader == null)
- return null;
-
// Set the game cache block entry header
- file.BlockEntryHeader = blockEntryHeader;
+ file.BlockEntryHeader = ParseBlockEntryHeader(data);
#endregion
#region Block Entries
// Create the block entry array
- file.BlockEntries = new BlockEntry[blockEntryHeader.BlockCount];
+ file.BlockEntries = new BlockEntry[file.BlockEntryHeader.BlockCount];
// Try to parse the block entries
- for (int i = 0; i < blockEntryHeader.BlockCount; i++)
+ for (int i = 0; i < file.BlockEntryHeader.BlockCount; i++)
{
- var blockEntry = data.ReadType();
- if (blockEntry == null)
- return null;
-
- file.BlockEntries[i] = blockEntry;
+ file.BlockEntries[i] = ParseBlockEntry(data);
}
#endregion
#region Fragmentation Map Header
- // Try to parse the fragmentation map header
- var fragmentationMapHeader = data.ReadType();
- if (fragmentationMapHeader == null)
- return null;
-
// Set the game cache fragmentation map header
- file.FragmentationMapHeader = fragmentationMapHeader;
+ file.FragmentationMapHeader = ParseFragmentationMapHeader(data);
#endregion
#region Fragmentation Maps
// Create the fragmentation map array
- file.FragmentationMaps = new FragmentationMap[fragmentationMapHeader.BlockCount];
+ file.FragmentationMaps = new FragmentationMap[file.FragmentationMapHeader.BlockCount];
// Try to parse the fragmentation maps
- for (int i = 0; i < fragmentationMapHeader.BlockCount; i++)
+ for (int i = 0; i < file.FragmentationMapHeader.BlockCount; i++)
{
- var fragmentationMap = data.ReadType();
- if (fragmentationMap == null)
- return null;
-
- file.FragmentationMaps[i] = fragmentationMap;
+ file.FragmentationMaps[i] = ParseFragmentationMap(data);
}
#endregion
#region Block Entry Map Header
+ // Set the game cache block entry map header
if (header.MinorVersion < 6)
- {
- // Try to parse the block entry map header
- var blockEntryMapHeader = data.ReadType();
- if (blockEntryMapHeader == null)
- return null;
-
- // Set the game cache block entry map header
- file.BlockEntryMapHeader = blockEntryMapHeader;
- }
+ file.BlockEntryMapHeader = ParseBlockEntryMapHeader(data);
#endregion
@@ -118,11 +93,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the block entry maps
for (int i = 0; i < file.BlockEntryMapHeader.BlockCount; i++)
{
- var blockEntryMap = data.ReadType();
- if (blockEntryMap == null)
- return null;
-
- file.BlockEntryMaps[i] = blockEntryMap;
+ file.BlockEntryMaps[i] = ParseBlockEntryMap(data); ;
}
}
@@ -133,42 +104,33 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Header
- // Try to parse the directory header
- var directoryHeader = data.ReadType();
- if (directoryHeader == null)
- return null;
-
// Set the game cache directory header
- file.DirectoryHeader = directoryHeader;
+ file.DirectoryHeader = ParseDirectoryHeader(data);
#endregion
#region Directory Entries
// Create the directory entry array
- file.DirectoryEntries = new DirectoryEntry[directoryHeader.ItemCount];
+ file.DirectoryEntries = new DirectoryEntry[file.DirectoryHeader.ItemCount];
// Try to parse the directory entries
- for (int i = 0; i < directoryHeader.ItemCount; i++)
+ for (int i = 0; i < file.DirectoryHeader.ItemCount; i++)
{
- var directoryEntry = data.ReadType();
- if (directoryEntry == null)
- return null;
-
- file.DirectoryEntries[i] = directoryEntry;
+ file.DirectoryEntries[i] = ParseDirectoryEntry(data);
}
#endregion
#region Directory Names
- if (directoryHeader.NameSize > 0)
+ if (file.DirectoryHeader.NameSize > 0)
{
// Get the current offset for adjustment
long directoryNamesStart = data.Position;
// Get the ending offset
- long directoryNamesEnd = data.Position + directoryHeader.NameSize;
+ long directoryNamesEnd = data.Position + file.DirectoryHeader.NameSize;
// Create the string dictionary
file.DirectoryNames = [];
@@ -194,16 +156,12 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Info 1 Entries
// Create the directory info 1 entry array
- file.DirectoryInfo1Entries = new DirectoryInfo1Entry[directoryHeader.Info1Count];
+ file.DirectoryInfo1Entries = new DirectoryInfo1Entry[file.DirectoryHeader.Info1Count];
// Try to parse the directory info 1 entries
- for (int i = 0; i < directoryHeader.Info1Count; i++)
+ for (int i = 0; i < file.DirectoryHeader.Info1Count; i++)
{
- var directoryInfo1Entry = data.ReadType();
- if (directoryInfo1Entry == null)
- return null;
-
- file.DirectoryInfo1Entries[i] = directoryInfo1Entry;
+ file.DirectoryInfo1Entries[i] = ParseDirectoryInfo1Entry(data);
}
#endregion
@@ -211,16 +169,12 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Info 2 Entries
// Create the directory info 2 entry array
- file.DirectoryInfo2Entries = new DirectoryInfo2Entry[directoryHeader.ItemCount];
+ file.DirectoryInfo2Entries = new DirectoryInfo2Entry[file.DirectoryHeader.ItemCount];
// Try to parse the directory info 2 entries
- for (int i = 0; i < directoryHeader.ItemCount; i++)
+ for (int i = 0; i < file.DirectoryHeader.ItemCount; i++)
{
- var directoryInfo2Entry = data.ReadType();
- if (directoryInfo2Entry == null)
- return null;
-
- file.DirectoryInfo2Entries[i] = directoryInfo2Entry;
+ file.DirectoryInfo2Entries[i] = ParseDirectoryInfo2Entry(data);
}
#endregion
@@ -228,16 +182,12 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Copy Entries
// Create the directory copy entry array
- file.DirectoryCopyEntries = new DirectoryCopyEntry[directoryHeader.CopyCount];
+ file.DirectoryCopyEntries = new DirectoryCopyEntry[file.DirectoryHeader.CopyCount];
// Try to parse the directory copy entries
- for (int i = 0; i < directoryHeader.CopyCount; i++)
+ for (int i = 0; i < file.DirectoryHeader.CopyCount; i++)
{
- var directoryCopyEntry = data.ReadType();
- if (directoryCopyEntry == null)
- return null;
-
- file.DirectoryCopyEntries[i] = directoryCopyEntry;
+ file.DirectoryCopyEntries[i] = ParseDirectoryCopyEntry(data);
}
#endregion
@@ -245,32 +195,28 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Local Entries
// Create the directory local entry array
- file.DirectoryLocalEntries = new DirectoryLocalEntry[directoryHeader.LocalCount];
+ file.DirectoryLocalEntries = new DirectoryLocalEntry[file.DirectoryHeader.LocalCount];
// Try to parse the directory local entries
- for (int i = 0; i < directoryHeader.LocalCount; i++)
+ for (int i = 0; i < file.DirectoryHeader.LocalCount; i++)
{
- var directoryLocalEntry = data.ReadType();
- if (directoryLocalEntry == null)
- return null;
-
- file.DirectoryLocalEntries[i] = directoryLocalEntry;
+ file.DirectoryLocalEntries[i] = ParseDirectoryLocalEntry(data);
}
#endregion
// Seek to end of directory section, just in case
- data.Seek(initialOffset + directoryHeader.DirectorySize, SeekOrigin.Begin);
+ data.Seek(initialOffset + file.DirectoryHeader.DirectorySize, SeekOrigin.Begin);
#region Directory Map Header
if (header.MinorVersion >= 5)
{
// Try to parse the directory map header
- var directoryMapHeader = data.ReadType();
- if (directoryMapHeader?.Dummy0 != 0x00000001)
+ var directoryMapHeader = ParseDirectoryMapHeader(data);
+ if (directoryMapHeader.Dummy0 != 0x00000001)
return null;
- if (directoryMapHeader?.Dummy1 != 0x00000000)
+ if (directoryMapHeader.Dummy1 != 0x00000000)
return null;
// Set the game cache directory map header
@@ -282,16 +228,12 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Map Entries
// Create the directory map entry array
- file.DirectoryMapEntries = new DirectoryMapEntry[directoryHeader.ItemCount];
+ file.DirectoryMapEntries = new DirectoryMapEntry[file.DirectoryHeader.ItemCount];
// Try to parse the directory map entries
- for (int i = 0; i < directoryHeader.ItemCount; i++)
+ for (int i = 0; i < file.DirectoryHeader.ItemCount; i++)
{
- var directoryMapEntry = data.ReadType();
- if (directoryMapEntry == null)
- return null;
-
- file.DirectoryMapEntries[i] = directoryMapEntry;
+ file.DirectoryMapEntries[i] = ParseDirectoryMapEntry(data);
}
#endregion
@@ -299,7 +241,7 @@ namespace SabreTools.Serialization.Deserializers
#region Checksum Header
// Try to parse the checksum header
- var checksumHeader = data.ReadType();
+ var checksumHeader = ParseChecksumHeader(data);
if (checksumHeader?.Dummy0 != 0x00000001)
return null;
@@ -314,7 +256,7 @@ namespace SabreTools.Serialization.Deserializers
#region Checksum Map Header
// Try to parse the checksum map header
- var checksumMapHeader = data.ReadType();
+ var checksumMapHeader = ParseChecksumMapHeader(data);
if (checksumMapHeader?.Dummy0 != 0x14893721)
return null;
if (checksumMapHeader?.Dummy1 != 0x00000001)
@@ -333,11 +275,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the checksum map entries
for (int i = 0; i < checksumMapHeader.ItemCount; i++)
{
- var checksumMapEntry = data.ReadType();
- if (checksumMapEntry == null)
- return null;
-
- file.ChecksumMapEntries[i] = checksumMapEntry;
+ file.ChecksumMapEntries[i] = ParseChecksumMapEntry(data);
}
#endregion
@@ -350,11 +288,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the checksum entries
for (int i = 0; i < checksumMapHeader.ChecksumCount; i++)
{
- var checksumEntry = data.ReadType();
- if (checksumEntry == null)
- return null;
-
- file.ChecksumEntries[i] = checksumEntry;
+ file.ChecksumEntries[i] = ParseChecksumEntry(data);
}
#endregion
@@ -384,26 +318,348 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a Half-Life Game Cache data block header
+ /// Parse a Stream into a BlockEntry
+ ///
+ /// Stream to parse
+ /// Filled BlockEntry on success, null on error
+ public static BlockEntry ParseBlockEntry(Stream data)
+ {
+ var obj = new BlockEntry();
+
+ obj.EntryFlags = data.ReadUInt32LittleEndian();
+ obj.FileDataOffset = data.ReadUInt32LittleEndian();
+ obj.FileDataSize = data.ReadUInt32LittleEndian();
+ obj.FirstDataBlockIndex = data.ReadUInt32LittleEndian();
+ obj.NextBlockEntryIndex = data.ReadUInt32LittleEndian();
+ obj.PreviousBlockEntryIndex = data.ReadUInt32LittleEndian();
+ obj.DirectoryIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a BlockEntryHeader
+ ///
+ /// Stream to parse
+ /// Filled BlockEntryHeader on success, null on error
+ public static BlockEntryHeader ParseBlockEntryHeader(Stream data)
+ {
+ var obj = new BlockEntryHeader();
+
+ obj.BlockCount = data.ReadUInt32LittleEndian();
+ obj.BlocksUsed = data.ReadUInt32LittleEndian();
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+ obj.Dummy2 = data.ReadUInt32LittleEndian();
+ obj.Dummy3 = data.ReadUInt32LittleEndian();
+ obj.Dummy4 = data.ReadUInt32LittleEndian();
+ obj.Checksum = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a BlockEntryMap
+ ///
+ /// Stream to parse
+ /// Filled BlockEntryMap on success, null on error
+ public static BlockEntryMap ParseBlockEntryMap(Stream data)
+ {
+ var obj = new BlockEntryMap();
+
+ obj.PreviousBlockEntryIndex = data.ReadUInt32LittleEndian();
+ obj.NextBlockEntryIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a BlockEntryMapHeader
+ ///
+ /// Stream to parse
+ /// Filled BlockEntryMapHeader on success, null on error
+ public static BlockEntryMapHeader ParseBlockEntryMapHeader(Stream data)
+ {
+ var obj = new BlockEntryMapHeader();
+
+ obj.BlockCount = data.ReadUInt32LittleEndian();
+ obj.FirstBlockEntryIndex = data.ReadUInt32LittleEndian();
+ obj.LastBlockEntryIndex = data.ReadUInt32LittleEndian();
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.Checksum = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ChecksumEntry
+ ///
+ /// Stream to parse
+ /// Filled ChecksumEntry on success, null on error
+ public static ChecksumEntry ParseChecksumEntry(Stream data)
+ {
+ var obj = new ChecksumEntry();
+
+ obj.Checksum = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ChecksumHeader
+ ///
+ /// Stream to parse
+ /// Filled ChecksumHeader on success, null on error
+ public static ChecksumHeader ParseChecksumHeader(Stream data)
+ {
+ var obj = new ChecksumHeader();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.ChecksumSize = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ChecksumMapEntry
+ ///
+ /// Stream to parse
+ /// Filled ChecksumMapEntry on success, null on error
+ public static ChecksumMapEntry ParseChecksumMapEntry(Stream data)
+ {
+ var obj = new ChecksumMapEntry();
+
+ obj.ChecksumCount = data.ReadUInt32LittleEndian();
+ obj.FirstChecksumIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ChecksumMapHeader
+ ///
+ /// Stream to parse
+ /// Filled ChecksumMapHeader on success, null on error
+ public static ChecksumMapHeader ParseChecksumMapHeader(Stream data)
+ {
+ var obj = new ChecksumMapHeader();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+ obj.ItemCount = data.ReadUInt32LittleEndian();
+ obj.ChecksumCount = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DataBlockHeader
///
/// Stream to parse
/// Minor version field from the header
- /// Filled Half-Life Game Cache data block header on success, null on error
- private static DataBlockHeader? ParseDataBlockHeader(Stream data, uint minorVersion)
+ /// Filled DataBlockHeader on success, null on error
+ public static DataBlockHeader ParseDataBlockHeader(Stream data, uint minorVersion)
{
- var dataBlockHeader = new DataBlockHeader();
+ var obj = new DataBlockHeader();
// In version 3 the DataBlockHeader is missing the LastVersionPlayed field.
if (minorVersion >= 5)
- dataBlockHeader.LastVersionPlayed = data.ReadUInt32();
+ obj.LastVersionPlayed = data.ReadUInt32LittleEndian();
- dataBlockHeader.BlockCount = data.ReadUInt32();
- dataBlockHeader.BlockSize = data.ReadUInt32();
- dataBlockHeader.FirstBlockOffset = data.ReadUInt32();
- dataBlockHeader.BlocksUsed = data.ReadUInt32();
- dataBlockHeader.Checksum = data.ReadUInt32();
+ obj.BlockCount = data.ReadUInt32LittleEndian();
+ obj.BlockSize = data.ReadUInt32LittleEndian();
+ obj.FirstBlockOffset = data.ReadUInt32LittleEndian();
+ obj.BlocksUsed = data.ReadUInt32LittleEndian();
+ obj.Checksum = data.ReadUInt32LittleEndian();
- return dataBlockHeader;
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryCopyEntry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryCopyEntry on success, null on error
+ public static DirectoryCopyEntry ParseDirectoryCopyEntry(Stream data)
+ {
+ var obj = new DirectoryCopyEntry();
+
+ obj.DirectoryIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryEntry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryEntry on success, null on error
+ public static DirectoryEntry ParseDirectoryEntry(Stream data)
+ {
+ var obj = new DirectoryEntry();
+
+ obj.NameOffset = data.ReadUInt32LittleEndian();
+ obj.ItemSize = data.ReadUInt32LittleEndian();
+ obj.ChecksumIndex = data.ReadUInt32LittleEndian();
+ obj.DirectoryFlags = (HL_GCF_FLAG)data.ReadUInt32LittleEndian();
+ obj.ParentIndex = data.ReadUInt32LittleEndian();
+ obj.NextIndex = data.ReadUInt32LittleEndian();
+ obj.FirstIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryHeader
+ ///
+ /// Stream to parse
+ /// Filled DirectoryHeader on success, null on error
+ public static DirectoryHeader ParseDirectoryHeader(Stream data)
+ {
+ var obj = new DirectoryHeader();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.CacheID = data.ReadUInt32LittleEndian();
+ obj.LastVersionPlayed = data.ReadUInt32LittleEndian();
+ obj.ItemCount = data.ReadUInt32LittleEndian();
+ obj.FileCount = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+ obj.DirectorySize = data.ReadUInt32LittleEndian();
+ obj.NameSize = data.ReadUInt32LittleEndian();
+ obj.Info1Count = data.ReadUInt32LittleEndian();
+ obj.CopyCount = data.ReadUInt32LittleEndian();
+ obj.LocalCount = data.ReadUInt32LittleEndian();
+ obj.Dummy2 = data.ReadUInt32LittleEndian();
+ obj.Dummy3 = data.ReadUInt32LittleEndian();
+ obj.Checksum = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryInfo1Entry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryInfo1Entry on success, null on error
+ public static DirectoryInfo1Entry ParseDirectoryInfo1Entry(Stream data)
+ {
+ var obj = new DirectoryInfo1Entry();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryInfo2Entry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryInfo2Entry on success, null on error
+ public static DirectoryInfo2Entry ParseDirectoryInfo2Entry(Stream data)
+ {
+ var obj = new DirectoryInfo2Entry();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryLocalEntry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryLocalEntry on success, null on error
+ public static DirectoryLocalEntry ParseDirectoryLocalEntry(Stream data)
+ {
+ var obj = new DirectoryLocalEntry();
+
+ obj.DirectoryIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryMapEntry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryMapEntry on success, null on error
+ public static DirectoryMapEntry ParseDirectoryMapEntry(Stream data)
+ {
+ var obj = new DirectoryMapEntry();
+
+ obj.FirstBlockIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryMapHeader
+ ///
+ /// Stream to parse
+ /// Filled DirectoryMapHeader on success, null on error
+ public static DirectoryMapHeader ParseDirectoryMapHeader(Stream data)
+ {
+ var obj = new DirectoryMapHeader();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a FragmentationMap
+ ///
+ /// Stream to parse
+ /// Filled FragmentationMap on success, null on error
+ public static FragmentationMap ParseFragmentationMap(Stream data)
+ {
+ var obj = new FragmentationMap();
+
+ obj.NextDataBlockIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a FragmentationMapHeader
+ ///
+ /// Stream to parse
+ /// Filled FragmentationMapHeader on success, null on error
+ public static FragmentationMapHeader ParseFragmentationMapHeader(Stream data)
+ {
+ var obj = new FragmentationMapHeader();
+
+ obj.BlockCount = data.ReadUInt32LittleEndian();
+ obj.FirstUnusedEntry = data.ReadUInt32LittleEndian();
+ obj.Terminator = data.ReadUInt32LittleEndian();
+ obj.Checksum = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a Header
+ ///
+ /// Stream to parse
+ /// Filled Header on success, null on error
+ public static Header ParseHeader(Stream data)
+ {
+ var obj = new Header();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.MajorVersion = data.ReadUInt32LittleEndian();
+ obj.MinorVersion = data.ReadUInt32LittleEndian();
+ obj.CacheID = data.ReadUInt32LittleEndian();
+ obj.LastVersionPlayed = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+ obj.Dummy2 = data.ReadUInt32LittleEndian();
+ obj.FileSize = data.ReadUInt32LittleEndian();
+ obj.BlockSize = data.ReadUInt32LittleEndian();
+ obj.BlockCount = data.ReadUInt32LittleEndian();
+ obj.Dummy3 = data.ReadUInt32LittleEndian();
+
+ return obj;
}
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/IRD.cs b/SabreTools.Serialization/Deserializers/IRD.cs
index a93afe2f..b75406a7 100644
--- a/SabreTools.Serialization/Deserializers/IRD.cs
+++ b/SabreTools.Serialization/Deserializers/IRD.cs
@@ -15,7 +15,7 @@ namespace SabreTools.Serialization.Deserializers
try
{
- // Create a new IRD to fill
+ // Deserialize the IRD
var ird = new Models.IRD.File();
ird.Magic = data.ReadBytes(4);
diff --git a/SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs b/SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs
index 63df856e..f4a721c4 100644
--- a/SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs
+++ b/SabreTools.Serialization/Deserializers/InstallShieldArchiveV3.cs
@@ -22,8 +22,8 @@ namespace SabreTools.Serialization.Deserializers
#region Header
// Try to parse the header
- var header = data.ReadType();
- if (header?.Signature1 != Constants.HeaderSignature)
+ var header = ParseHeader(data);
+ if (header.Signature1 != Constants.HeaderSignature)
return null;
if (header.TocAddress >= data.Length)
return null;
@@ -48,11 +48,8 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < header.DirCount; i++)
{
var directory = ParseDirectory(data);
- if (directory?.Name == null)
- return null;
-
directories.Add(directory);
- data.Seek(directory.ChunkSize - directory.Name.Length - 6, SeekOrigin.Current);
+ data.Seek(directory.ChunkSize - directory.Name!.Length - 6, SeekOrigin.Current);
}
// Set the directories
@@ -69,12 +66,9 @@ namespace SabreTools.Serialization.Deserializers
var directory = archive.Directories[i];
for (int j = 0; j < directory.FileCount; j++)
{
- var file = data.ReadType();
- if (file?.Name == null)
- return null;
-
+ var file = ParseFile(data);
files.Add(file);
- data.Seek(file.ChunkSize - file.Name.Length - 30, SeekOrigin.Current);
+ data.Seek(file.ChunkSize - file.Name!.Length - 30, SeekOrigin.Current);
}
}
@@ -93,22 +87,80 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a directory
+ /// Parse a Stream into a Directory
///
/// Stream to parse
- /// Filled directory on success, null on error
- public static Models.InstallShieldArchiveV3.Directory? ParseDirectory(Stream data)
+ /// Filled Directory on success, null on error
+ public static Models.InstallShieldArchiveV3.Directory ParseDirectory(Stream data)
{
- var directory = new Models.InstallShieldArchiveV3.Directory();
+ var obj = new Models.InstallShieldArchiveV3.Directory();
- directory.FileCount = data.ReadUInt16();
- directory.ChunkSize = data.ReadUInt16();
+ obj.FileCount = data.ReadUInt16();
+ obj.ChunkSize = data.ReadUInt16();
ushort nameLength = data.ReadUInt16();
byte[] nameBytes = data.ReadBytes(nameLength);
- directory.Name = Encoding.ASCII.GetString(nameBytes);
+ obj.Name = Encoding.ASCII.GetString(nameBytes);
- return directory;
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a File
+ ///
+ /// Stream to parse
+ /// Filled File on success, null on error
+ public static Models.InstallShieldArchiveV3.File ParseFile(Stream data)
+ {
+ var obj = new Models.InstallShieldArchiveV3.File();
+
+ obj.VolumeEnd = data.ReadByteValue();
+ obj.Index = data.ReadUInt16LittleEndian();
+ obj.UncompressedSize = data.ReadUInt32LittleEndian();
+ obj.CompressedSize = data.ReadUInt32LittleEndian();
+ obj.Offset = data.ReadUInt32LittleEndian();
+ obj.DateTime = data.ReadUInt32LittleEndian();
+ obj.Reserved0 = data.ReadUInt32LittleEndian();
+ obj.ChunkSize = data.ReadUInt16LittleEndian();
+ obj.Attrib = (Attributes)data.ReadByteValue();
+ obj.IsSplit = data.ReadByteValue();
+ obj.Reserved1 = data.ReadByteValue();
+ obj.VolumeStart = data.ReadByteValue();
+ obj.Name = data.ReadPrefixedAnsiString();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a Header
+ ///
+ /// Stream to parse
+ /// Filled Header on success, null on error
+ public static Header ParseHeader(Stream data)
+ {
+ var obj = new Header();
+
+ obj.Signature1 = data.ReadUInt32LittleEndian();
+ obj.Signature2 = data.ReadUInt32LittleEndian();
+ obj.Reserved0 = data.ReadUInt16LittleEndian();
+ obj.IsMultivolume = data.ReadUInt16LittleEndian();
+ obj.FileCount = data.ReadUInt16LittleEndian();
+ obj.DateTime = data.ReadUInt32LittleEndian();
+ obj.CompressedSize = data.ReadUInt32LittleEndian();
+ obj.UncompressedSize = data.ReadUInt32LittleEndian();
+ obj.Reserved1 = data.ReadUInt32LittleEndian();
+ obj.VolumeTotal = data.ReadByteValue();
+ obj.VolumeNumber = data.ReadByteValue();
+ obj.Reserved2 = data.ReadByteValue();
+ obj.SplitBeginAddress = data.ReadUInt32LittleEndian();
+ obj.SplitEndAddress = data.ReadUInt32LittleEndian();
+ obj.TocAddress = data.ReadUInt32LittleEndian();
+ obj.Reserved3 = data.ReadUInt32LittleEndian();
+ obj.DirCount = data.ReadUInt16LittleEndian();
+ obj.Reserved4 = data.ReadUInt32LittleEndian();
+ obj.Reserved5 = data.ReadUInt32LittleEndian();
+
+ return obj;
}
}
}
diff --git a/SabreTools.Serialization/Deserializers/InstallShieldCabinet.cs b/SabreTools.Serialization/Deserializers/InstallShieldCabinet.cs
index 6c2b676d..0a658f26 100644
--- a/SabreTools.Serialization/Deserializers/InstallShieldCabinet.cs
+++ b/SabreTools.Serialization/Deserializers/InstallShieldCabinet.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.InstallShieldCabinet;
using static SabreTools.Models.InstallShieldCabinet.Constants;
@@ -25,8 +26,8 @@ namespace SabreTools.Serialization.Deserializers
#region Common Header
// Try to parse the cabinet header
- var commonHeader = data.ReadType();
- if (commonHeader?.Signature != SignatureString)
+ var commonHeader = ParseCommonHeader(data);
+ if (commonHeader.Signature != SignatureString)
return null;
// Set the cabinet header
@@ -34,15 +35,13 @@ namespace SabreTools.Serialization.Deserializers
#endregion
+ // Get the major version
+ int majorVersion = GetMajorVersion(commonHeader);
+
#region Volume Header
- // Try to parse the volume header
- var volumeHeader = ParseVolumeHeader(data, GetMajorVersion(commonHeader));
- if (volumeHeader == null)
- return null;
-
// Set the volume header
- cabinet.VolumeHeader = volumeHeader;
+ cabinet.VolumeHeader = ParseVolumeHeader(data, majorVersion);
#endregion
@@ -56,20 +55,15 @@ namespace SabreTools.Serialization.Deserializers
// Seek to the descriptor
data.Seek(descriptorOffset, SeekOrigin.Begin);
- // Try to parse the descriptor
- var descriptor = data.ReadType();
- if (descriptor == null)
- return null;
-
// Set the descriptor
- cabinet.Descriptor = descriptor;
+ cabinet.Descriptor = ParseDescriptor(data);
#endregion
#region File Descriptor Offsets
// Get the file table offset
- uint fileTableOffset = commonHeader.DescriptorOffset + descriptor.FileTableOffset;
+ uint fileTableOffset = commonHeader.DescriptorOffset + cabinet.Descriptor.FileTableOffset;
if (fileTableOffset < 0 || fileTableOffset >= data.Length)
return null;
@@ -78,16 +72,16 @@ namespace SabreTools.Serialization.Deserializers
// Get the number of file table items
uint fileTableItems;
- if (GetMajorVersion(commonHeader) <= 5)
- fileTableItems = descriptor.DirectoryCount + descriptor.FileCount;
+ if (majorVersion <= 5)
+ fileTableItems = cabinet.Descriptor.DirectoryCount + cabinet.Descriptor.FileCount;
else
- fileTableItems = descriptor.DirectoryCount;
+ fileTableItems = cabinet.Descriptor.DirectoryCount;
// Create and fill the file table
cabinet.FileDescriptorOffsets = new uint[fileTableItems];
for (int i = 0; i < cabinet.FileDescriptorOffsets.Length; i++)
{
- cabinet.FileDescriptorOffsets[i] = data.ReadUInt32();
+ cabinet.FileDescriptorOffsets[i] = data.ReadUInt32LittleEndian();
}
#endregion
@@ -95,12 +89,12 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Descriptors
// Create and fill the directory descriptors
- cabinet.DirectoryNames = new string[descriptor.DirectoryCount];
- for (int i = 0; i < descriptor.DirectoryCount; i++)
+ cabinet.DirectoryNames = new string[cabinet.Descriptor.DirectoryCount];
+ for (int i = 0; i < cabinet.Descriptor.DirectoryCount; i++)
{
// Get the directory descriptor offset
uint offset = descriptorOffset
- + descriptor.FileTableOffset
+ + cabinet.Descriptor.FileTableOffset
+ cabinet.FileDescriptorOffsets[i];
// If we have an invalid offset
@@ -111,7 +105,7 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(offset, SeekOrigin.Begin);
// Create and add the file descriptor
- string? directoryName = ParseDirectoryName(data, GetMajorVersion(commonHeader));
+ string? directoryName = ParseDirectoryName(data, majorVersion);
if (directoryName != null)
cabinet.DirectoryNames[i] = directoryName;
}
@@ -121,22 +115,22 @@ namespace SabreTools.Serialization.Deserializers
#region File Descriptors
// Create and fill the file descriptors
- cabinet.FileDescriptors = new FileDescriptor[descriptor.FileCount];
- for (int i = 0; i < descriptor.FileCount; i++)
+ cabinet.FileDescriptors = new FileDescriptor[cabinet.Descriptor.FileCount];
+ for (int i = 0; i < cabinet.Descriptor.FileCount; i++)
{
// Get the file descriptor offset
uint offset;
- if (GetMajorVersion(commonHeader) <= 5)
+ if (majorVersion <= 5)
{
offset = descriptorOffset
- + descriptor.FileTableOffset
- + cabinet.FileDescriptorOffsets[descriptor.DirectoryCount + i];
+ + cabinet.Descriptor.FileTableOffset
+ + cabinet.FileDescriptorOffsets[cabinet.Descriptor.DirectoryCount + i];
}
else
{
offset = descriptorOffset
- + descriptor.FileTableOffset
- + descriptor.FileTableOffset2
+ + cabinet.Descriptor.FileTableOffset
+ + cabinet.Descriptor.FileTableOffset2
+ (uint)(i * 0x57);
}
@@ -148,8 +142,9 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(offset, SeekOrigin.Begin);
// Create and add the file descriptor
- FileDescriptor fileDescriptor = ParseFileDescriptor(data, GetMajorVersion(commonHeader), descriptorOffset + descriptor.FileTableOffset);
- cabinet.FileDescriptors[i] = fileDescriptor;
+ cabinet.FileDescriptors[i] = ParseFileDescriptor(data,
+ majorVersion,
+ descriptorOffset + cabinet.Descriptor.FileTableOffset);
}
#endregion
@@ -158,10 +153,10 @@ namespace SabreTools.Serialization.Deserializers
// Create and fill the file group offsets
cabinet.FileGroupOffsets = new Dictionary();
- for (int i = 0; i < (descriptor.FileGroupOffsets?.Length ?? 0); i++)
+ for (int i = 0; i < (cabinet.Descriptor.FileGroupOffsets?.Length ?? 0); i++)
{
// Get the file group offset
- uint offset = descriptor.FileGroupOffsets![i];
+ uint offset = cabinet.Descriptor.FileGroupOffsets![i];
if (offset == 0)
continue;
@@ -174,8 +169,8 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(offset, SeekOrigin.Begin);
// Create and add the offset
- OffsetList offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), descriptorOffset);
- cabinet.FileGroupOffsets[descriptor.FileGroupOffsets[i]] = offsetList;
+ OffsetList offsetList = ParseOffsetList(data, majorVersion, descriptorOffset);
+ cabinet.FileGroupOffsets[offset] = offsetList;
// If we have a nonzero next offset
uint nextOffset = offsetList.NextOffset;
@@ -188,7 +183,7 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(internalOffset, SeekOrigin.Begin);
// Create and add the offset
- offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), descriptorOffset);
+ offsetList = ParseOffsetList(data, majorVersion, descriptorOffset);
cabinet.FileGroupOffsets[nextOffset] = offsetList;
// Set the next offset
@@ -225,13 +220,8 @@ namespace SabreTools.Serialization.Deserializers
/// Seek to the file group
data.Seek(list.DescriptorOffset + descriptorOffset, SeekOrigin.Begin);
- // Try to parse the file group
- var fileGroup = ParseFileGroup(data, GetMajorVersion(commonHeader), descriptorOffset);
- if (fileGroup == null)
- return null;
-
// Add the file group
- cabinet.FileGroups[fileGroupId++] = fileGroup;
+ cabinet.FileGroups[fileGroupId++] = ParseFileGroup(data, majorVersion, descriptorOffset);
}
#endregion
@@ -240,10 +230,10 @@ namespace SabreTools.Serialization.Deserializers
// Create and fill the component offsets
cabinet.ComponentOffsets = new Dictionary();
- for (int i = 0; i < (descriptor.ComponentOffsets?.Length ?? 0); i++)
+ for (int i = 0; i < (cabinet.Descriptor.ComponentOffsets?.Length ?? 0); i++)
{
// Get the component offset
- uint offset = descriptor.ComponentOffsets![i];
+ uint offset = cabinet.Descriptor.ComponentOffsets![i];
if (offset == 0)
continue;
@@ -256,8 +246,8 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(offset, SeekOrigin.Begin);
// Create and add the offset
- OffsetList offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), descriptorOffset);
- cabinet.ComponentOffsets[descriptor.ComponentOffsets[i]] = offsetList;
+ OffsetList offsetList = ParseOffsetList(data, majorVersion, descriptorOffset);
+ cabinet.ComponentOffsets[cabinet.Descriptor.ComponentOffsets[i]] = offsetList;
// If we have a nonzero next offset
uint nextOffset = offsetList.NextOffset;
@@ -270,7 +260,7 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(internalOffset, SeekOrigin.Begin);
// Create and add the offset
- offsetList = ParseOffsetList(data, GetMajorVersion(commonHeader), descriptorOffset);
+ offsetList = ParseOffsetList(data, majorVersion, descriptorOffset);
cabinet.ComponentOffsets[nextOffset] = offsetList;
// Set the next offset
@@ -307,13 +297,8 @@ namespace SabreTools.Serialization.Deserializers
// Seek to the component
data.Seek(list.DescriptorOffset + descriptorOffset, SeekOrigin.Begin);
- // Try to parse the component
- var component = ParseComponent(data, GetMajorVersion(commonHeader), descriptorOffset);
- if (component == null)
- return null;
-
// Add the component
- cabinet.Components[componentId++] = component;
+ cabinet.Components[componentId++] = ParseComponent(data, majorVersion, descriptorOffset);
}
#endregion
@@ -330,251 +315,132 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a volume header
+ /// Parse a Stream into a CommonHeader
///
/// Stream to parse
- /// Major version of the cabinet
- /// Filled volume header on success, null on error
- public static VolumeHeader ParseVolumeHeader(Stream data, int majorVersion)
+ /// Filled CommonHeader on success, null on error
+ public static CommonHeader ParseCommonHeader(Stream data)
{
- var volumeHeader = new VolumeHeader();
+ var obj = new CommonHeader();
- // Read the descriptor based on version
- if (majorVersion <= 5)
- {
- volumeHeader.DataOffset = data.ReadUInt32();
- _ = data.ReadBytes(0x04); // Skip 0x04 bytes, unknown data?
- volumeHeader.FirstFileIndex = data.ReadUInt32();
- volumeHeader.LastFileIndex = data.ReadUInt32();
- volumeHeader.FirstFileOffset = data.ReadUInt32();
- volumeHeader.FirstFileSizeExpanded = data.ReadUInt32();
- volumeHeader.FirstFileSizeCompressed = data.ReadUInt32();
- volumeHeader.LastFileOffset = data.ReadUInt32();
- volumeHeader.LastFileSizeExpanded = data.ReadUInt32();
- volumeHeader.LastFileSizeCompressed = data.ReadUInt32();
- }
- else
- {
- volumeHeader.DataOffset = data.ReadUInt32();
- volumeHeader.DataOffsetHigh = data.ReadUInt32();
- volumeHeader.FirstFileIndex = data.ReadUInt32();
- volumeHeader.LastFileIndex = data.ReadUInt32();
- volumeHeader.FirstFileOffset = data.ReadUInt32();
- volumeHeader.FirstFileOffsetHigh = data.ReadUInt32();
- volumeHeader.FirstFileSizeExpanded = data.ReadUInt32();
- volumeHeader.FirstFileSizeExpandedHigh = data.ReadUInt32();
- volumeHeader.FirstFileSizeCompressed = data.ReadUInt32();
- volumeHeader.FirstFileSizeCompressedHigh = data.ReadUInt32();
- volumeHeader.LastFileOffset = data.ReadUInt32();
- volumeHeader.LastFileOffsetHigh = data.ReadUInt32();
- volumeHeader.LastFileSizeExpanded = data.ReadUInt32();
- volumeHeader.LastFileSizeExpandedHigh = data.ReadUInt32();
- volumeHeader.LastFileSizeCompressed = data.ReadUInt32();
- volumeHeader.LastFileSizeCompressedHigh = data.ReadUInt32();
- }
+ byte[] signature = data.ReadBytes(4);
+ obj.Signature = Encoding.ASCII.GetString(signature);
+ obj.Version = data.ReadUInt32LittleEndian();
+ obj.VolumeInfo = data.ReadUInt32LittleEndian();
+ obj.DescriptorOffset = data.ReadUInt32LittleEndian();
+ obj.DescriptorSize = data.ReadUInt32LittleEndian();
- return volumeHeader;
+ return obj;
}
///
- /// Parse a Stream into an offset list
+ /// Parse a Stream into a Component
///
/// Stream to parse
/// Major version of the cabinet
/// Offset of the cabinet descriptor
- /// Filled offset list on success, null on error
- public static OffsetList ParseOffsetList(Stream data, int majorVersion, uint descriptorOffset)
- {
- var offsetList = new OffsetList();
-
- offsetList.NameOffset = data.ReadUInt32();
- offsetList.DescriptorOffset = data.ReadUInt32();
- offsetList.NextOffset = data.ReadUInt32();
-
- // Cache the current offset
- long currentOffset = data.Position;
-
- // Seek to the name offset
- data.Seek(offsetList.NameOffset + descriptorOffset, SeekOrigin.Begin);
-
- // Read the string
- if (majorVersion >= 17)
- offsetList.Name = data.ReadNullTerminatedUnicodeString();
- else
- offsetList.Name = data.ReadNullTerminatedAnsiString();
-
- // Seek back to the correct offset
- data.Seek(currentOffset, SeekOrigin.Begin);
-
- return offsetList;
- }
-
- ///
- /// Parse a Stream into a file group
- ///
- /// Stream to parse
- /// Major version of the cabinet
- /// Offset of the cabinet descriptor
- /// Filled file group on success, null on error
- public static FileGroup ParseFileGroup(Stream data, int majorVersion, uint descriptorOffset)
- {
- var fileGroup = new FileGroup();
-
- fileGroup.NameOffset = data.ReadUInt32();
- fileGroup.ExpandedSize = data.ReadUInt32();
- fileGroup.CompressedSize = data.ReadUInt32();
- fileGroup.Attributes = (FileGroupAttributes)data.ReadUInt16();
-
- // TODO: Figure out what data lives in this area for V5 and below
- if (majorVersion <= 5)
- data.Seek(0x36, SeekOrigin.Current);
-
- fileGroup.FirstFile = data.ReadUInt32();
- fileGroup.LastFile = data.ReadUInt32();
- fileGroup.UnknownStringOffset = data.ReadUInt32();
- fileGroup.OperatingSystemOffset = data.ReadUInt32();
- fileGroup.LanguageOffset = data.ReadUInt32();
- fileGroup.HTTPLocationOffset = data.ReadUInt32();
- fileGroup.FTPLocationOffset = data.ReadUInt32();
- fileGroup.MiscOffset = data.ReadUInt32();
- fileGroup.TargetDirectoryOffset = data.ReadUInt32();
- fileGroup.OverwriteFlags = (FileGroupFlags)data.ReadUInt32();
- fileGroup.Reserved = new uint[4];
- for (int i = 0; i < fileGroup.Reserved.Length; i++)
- {
- fileGroup.Reserved[i] = data.ReadUInt32();
- }
-
- // Cache the current position
- long currentPosition = data.Position;
-
- // Read the name, if possible
- if (fileGroup.NameOffset != 0)
- {
- // Seek to the name
- data.Seek(fileGroup.NameOffset + descriptorOffset, SeekOrigin.Begin);
-
- // Read the string
- if (majorVersion >= 17)
- fileGroup.Name = data.ReadNullTerminatedUnicodeString();
- else
- fileGroup.Name = data.ReadNullTerminatedAnsiString();
- }
-
- // Seek back to the correct offset
- data.Seek(currentPosition, SeekOrigin.Begin);
-
- return fileGroup;
- }
-
- ///
- /// Parse a Stream into a component
- ///
- /// Stream to parse
- /// Major version of the cabinet
- /// Offset of the cabinet descriptor
- /// Filled component on success, null on error
+ /// Filled Component on success, null on error
public static Component ParseComponent(Stream data, int majorVersion, uint descriptorOffset)
{
- var component = new Component();
+ var obj = new Component();
- component.IdentifierOffset = data.ReadUInt32();
- component.DescriptorOffset = data.ReadUInt32();
- component.DisplayNameOffset = data.ReadUInt32();
- component.Status = (ComponentStatus)data.ReadUInt16();
- component.PasswordOffset = data.ReadUInt32();
- component.MiscOffset = data.ReadUInt32();
- component.ComponentIndex = data.ReadUInt16();
- component.NameOffset = data.ReadUInt32();
- component.CDRomFolderOffset = data.ReadUInt32();
- component.HTTPLocationOffset = data.ReadUInt32();
- component.FTPLocationOffset = data.ReadUInt32();
- component.Guid = new Guid[2];
- for (int i = 0; i < component.Guid.Length; i++)
+ obj.IdentifierOffset = data.ReadUInt32LittleEndian();
+ obj.DescriptorOffset = data.ReadUInt32LittleEndian();
+ obj.DisplayNameOffset = data.ReadUInt32LittleEndian();
+ obj.Status = (ComponentStatus)data.ReadUInt16LittleEndian();
+ obj.PasswordOffset = data.ReadUInt32LittleEndian();
+ obj.MiscOffset = data.ReadUInt32LittleEndian();
+ obj.ComponentIndex = data.ReadUInt16LittleEndian();
+ obj.NameOffset = data.ReadUInt32LittleEndian();
+ obj.CDRomFolderOffset = data.ReadUInt32LittleEndian();
+ obj.HTTPLocationOffset = data.ReadUInt32LittleEndian();
+ obj.FTPLocationOffset = data.ReadUInt32LittleEndian();
+ obj.Guid = new Guid[2];
+ for (int i = 0; i < obj.Guid.Length; i++)
{
- component.Guid[i] = data.ReadGuid();
+ obj.Guid[i] = data.ReadGuid();
}
- component.CLSIDOffset = data.ReadUInt32();
- component.Reserved2 = data.ReadBytes(28);
- component.Reserved3 = data.ReadBytes(majorVersion <= 5 ? 2 : 1);
- component.DependsCount = data.ReadUInt16();
- component.DependsOffset = data.ReadUInt32();
- component.FileGroupCount = data.ReadUInt16();
- component.FileGroupNamesOffset = data.ReadUInt32();
- component.X3Count = data.ReadUInt16();
- component.X3Offset = data.ReadUInt32();
- component.SubComponentsCount = data.ReadUInt16();
- component.SubComponentsOffset = data.ReadUInt32();
- component.NextComponentOffset = data.ReadUInt32();
- component.OnInstallingOffset = data.ReadUInt32();
- component.OnInstalledOffset = data.ReadUInt32();
- component.OnUninstallingOffset = data.ReadUInt32();
- component.OnUninstalledOffset = data.ReadUInt32();
+ obj.CLSIDOffset = data.ReadUInt32LittleEndian();
+ obj.Reserved2 = data.ReadBytes(28);
+ obj.Reserved3 = data.ReadBytes(majorVersion <= 5 ? 2 : 1);
+ obj.DependsCount = data.ReadUInt16LittleEndian();
+ obj.DependsOffset = data.ReadUInt32LittleEndian();
+ obj.FileGroupCount = data.ReadUInt16LittleEndian();
+ obj.FileGroupNamesOffset = data.ReadUInt32LittleEndian();
+ obj.X3Count = data.ReadUInt16LittleEndian();
+ obj.X3Offset = data.ReadUInt32LittleEndian();
+ obj.SubComponentsCount = data.ReadUInt16LittleEndian();
+ obj.SubComponentsOffset = data.ReadUInt32LittleEndian();
+ obj.NextComponentOffset = data.ReadUInt32LittleEndian();
+ obj.OnInstallingOffset = data.ReadUInt32LittleEndian();
+ obj.OnInstalledOffset = data.ReadUInt32LittleEndian();
+ obj.OnUninstallingOffset = data.ReadUInt32LittleEndian();
+ obj.OnUninstalledOffset = data.ReadUInt32LittleEndian();
// Cache the current position
long currentPosition = data.Position;
// Read the identifier, if possible
- if (component.IdentifierOffset != 0)
+ if (obj.IdentifierOffset != 0)
{
// Seek to the identifier
- data.Seek(component.IdentifierOffset + descriptorOffset, SeekOrigin.Begin);
+ data.Seek(obj.IdentifierOffset + descriptorOffset, SeekOrigin.Begin);
// Read the string
if (majorVersion >= 17)
- component.Identifier = data.ReadNullTerminatedUnicodeString();
+ obj.Identifier = data.ReadNullTerminatedUnicodeString();
else
- component.Identifier = data.ReadNullTerminatedAnsiString();
+ obj.Identifier = data.ReadNullTerminatedAnsiString();
}
// Read the display name, if possible
- if (component.DisplayNameOffset != 0)
+ if (obj.DisplayNameOffset != 0)
{
// Seek to the name
- data.Seek(component.DisplayNameOffset + descriptorOffset, SeekOrigin.Begin);
+ data.Seek(obj.DisplayNameOffset + descriptorOffset, SeekOrigin.Begin);
// Read the string
if (majorVersion >= 17)
- component.DisplayName = data.ReadNullTerminatedUnicodeString();
+ obj.DisplayName = data.ReadNullTerminatedUnicodeString();
else
- component.DisplayName = data.ReadNullTerminatedAnsiString();
+ obj.DisplayName = data.ReadNullTerminatedAnsiString();
}
// Read the name, if possible
- if (component.NameOffset != 0)
+ if (obj.NameOffset != 0)
{
// Seek to the name
- data.Seek(component.NameOffset + descriptorOffset, SeekOrigin.Begin);
+ data.Seek(obj.NameOffset + descriptorOffset, SeekOrigin.Begin);
// Read the string
if (majorVersion >= 17)
- component.Name = data.ReadNullTerminatedUnicodeString();
+ obj.Name = data.ReadNullTerminatedUnicodeString();
else
- component.Name = data.ReadNullTerminatedAnsiString();
+ obj.Name = data.ReadNullTerminatedAnsiString();
}
// Read the CLSID, if possible
- if (component.CLSIDOffset != 0)
+ if (obj.CLSIDOffset != 0)
{
// Seek to the CLSID
- data.Seek(component.CLSIDOffset + descriptorOffset, SeekOrigin.Begin);
+ data.Seek(obj.CLSIDOffset + descriptorOffset, SeekOrigin.Begin);
// Read the GUID
- component.CLSID = data.ReadGuid();
+ obj.CLSID = data.ReadGuid();
}
// Read the file group names, if possible
- if (component.FileGroupCount != 0 && component.FileGroupNamesOffset != 0)
+ if (obj.FileGroupCount != 0 && obj.FileGroupNamesOffset != 0)
{
// Seek to the file group table offset
- data.Seek(component.FileGroupNamesOffset + descriptorOffset, SeekOrigin.Begin);
+ data.Seek(obj.FileGroupNamesOffset + descriptorOffset, SeekOrigin.Begin);
// Read the file group names table
- component.FileGroupNames = new string[component.FileGroupCount];
- for (int j = 0; j < component.FileGroupCount; j++)
+ obj.FileGroupNames = new string[obj.FileGroupCount];
+ for (int j = 0; j < obj.FileGroupCount; j++)
{
// Get the name offset
- uint nameOffset = data.ReadUInt32();
+ uint nameOffset = data.ReadUInt32LittleEndian();
// Cache the current offset
long preNameOffset = data.Position;
@@ -583,9 +449,9 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(nameOffset + descriptorOffset, SeekOrigin.Begin);
if (majorVersion >= 17)
- component.FileGroupNames[j] = data.ReadNullTerminatedUnicodeString() ?? string.Empty;
+ obj.FileGroupNames[j] = data.ReadNullTerminatedUnicodeString() ?? string.Empty;
else
- component.FileGroupNames[j] = data.ReadNullTerminatedAnsiString() ?? string.Empty;
+ obj.FileGroupNames[j] = data.ReadNullTerminatedAnsiString() ?? string.Empty;
// Seek back to the original position
data.Seek(preNameOffset, SeekOrigin.Begin);
@@ -595,7 +461,51 @@ namespace SabreTools.Serialization.Deserializers
// Seek back to the correct offset
data.Seek(currentPosition, SeekOrigin.Begin);
- return component;
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a Descriptor
+ ///
+ /// Stream to parse
+ /// Filled Descriptor on success, null on error
+ public static Descriptor ParseDescriptor(Stream data)
+ {
+ var obj = new Descriptor();
+
+ obj.StringsOffset = data.ReadUInt32LittleEndian();
+ obj.Reserved0 = data.ReadUInt32LittleEndian();
+ obj.ComponentListOffset = data.ReadUInt32LittleEndian();
+ obj.FileTableOffset = data.ReadUInt32LittleEndian();
+ obj.Reserved1 = data.ReadUInt32LittleEndian();
+ obj.FileTableSize = data.ReadUInt32LittleEndian();
+ obj.FileTableSize2 = data.ReadUInt32LittleEndian();
+ obj.DirectoryCount = data.ReadUInt16LittleEndian();
+ obj.Reserved2 = data.ReadUInt32LittleEndian();
+ obj.Reserved3 = data.ReadUInt16LittleEndian();
+ obj.Reserved4 = data.ReadUInt32LittleEndian();
+ obj.FileCount = data.ReadUInt32LittleEndian();
+ obj.FileTableOffset2 = data.ReadUInt32LittleEndian();
+ obj.ComponentTableInfoCount = data.ReadUInt16LittleEndian();
+ obj.ComponentTableOffset = data.ReadUInt32LittleEndian();
+ obj.Reserved5 = data.ReadUInt32LittleEndian();
+ obj.Reserved6 = data.ReadUInt32LittleEndian();
+ obj.FileGroupOffsets = new uint[71];
+ for (int i = 0; i < 71; i++)
+ {
+ obj.FileGroupOffsets[i] = data.ReadUInt32LittleEndian();
+ }
+ obj.ComponentOffsets = new uint[71];
+ for (int i = 0; i < 71; i++)
+ {
+ obj.ComponentOffsets[i] = data.ReadUInt32LittleEndian();
+ }
+ obj.SetupTypesOffset = data.ReadUInt32LittleEndian();
+ obj.SetupTableOffset = data.ReadUInt32LittleEndian();
+ obj.Reserved7 = data.ReadUInt32LittleEndian();
+ obj.Reserved8 = data.ReadUInt32LittleEndian();
+
+ return obj;
}
///
@@ -614,68 +524,206 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a file descriptor
+ /// Parse a Stream into a FileDescriptor
///
/// Stream to parse
/// Major version of the cabinet
/// Offset of the cabinet descriptor
- /// Filled file descriptor on success, null on error
+ /// Filled FileDescriptor on success, null on error
public static FileDescriptor ParseFileDescriptor(Stream data, int majorVersion, uint descriptorOffset)
{
- var fileDescriptor = new FileDescriptor();
+ var obj = new FileDescriptor();
// Read the descriptor based on version
if (majorVersion <= 5)
{
- fileDescriptor.Volume = 0xFFFF; // Set by the header index
- fileDescriptor.NameOffset = data.ReadUInt32();
- fileDescriptor.DirectoryIndex = data.ReadUInt32();
- fileDescriptor.Flags = (FileFlags)data.ReadUInt16();
- fileDescriptor.ExpandedSize = data.ReadUInt32();
- fileDescriptor.CompressedSize = data.ReadUInt32();
+ obj.Volume = 0xFFFF; // Set by the header index
+ obj.NameOffset = data.ReadUInt32LittleEndian();
+ obj.DirectoryIndex = data.ReadUInt32LittleEndian();
+ obj.Flags = (FileFlags)data.ReadUInt16LittleEndian();
+ obj.ExpandedSize = data.ReadUInt32LittleEndian();
+ obj.CompressedSize = data.ReadUInt32LittleEndian();
_ = data.ReadBytes(0x14); // Skip 0x14 bytes, unknown data?
- fileDescriptor.DataOffset = data.ReadUInt32();
+ obj.DataOffset = data.ReadUInt32LittleEndian();
if (majorVersion == 5)
- fileDescriptor.MD5 = data.ReadBytes(0x10);
+ obj.MD5 = data.ReadBytes(0x10);
}
else
{
- fileDescriptor.Flags = (FileFlags)data.ReadUInt16();
- fileDescriptor.ExpandedSize = data.ReadUInt64();
- fileDescriptor.CompressedSize = data.ReadUInt64();
- fileDescriptor.DataOffset = data.ReadUInt64();
- fileDescriptor.MD5 = data.ReadBytes(0x10);
+ obj.Flags = (FileFlags)data.ReadUInt16LittleEndian();
+ obj.ExpandedSize = data.ReadUInt64LittleEndian();
+ obj.CompressedSize = data.ReadUInt64LittleEndian();
+ obj.DataOffset = data.ReadUInt64LittleEndian();
+ obj.MD5 = data.ReadBytes(0x10);
_ = data.ReadBytes(0x10); // Skip 0x10 bytes, unknown data?
- fileDescriptor.NameOffset = data.ReadUInt32();
- fileDescriptor.DirectoryIndex = data.ReadUInt16();
+ obj.NameOffset = data.ReadUInt32LittleEndian();
+ obj.DirectoryIndex = data.ReadUInt16LittleEndian();
_ = data.ReadBytes(0x0C); // Skip 0x0C bytes, unknown data?
- fileDescriptor.LinkPrevious = data.ReadUInt32();
- fileDescriptor.LinkNext = data.ReadUInt32();
- fileDescriptor.LinkFlags = (LinkFlags)data.ReadByteValue();
- fileDescriptor.Volume = data.ReadUInt16();
+ obj.LinkPrevious = data.ReadUInt32LittleEndian();
+ obj.LinkNext = data.ReadUInt32LittleEndian();
+ obj.LinkFlags = (LinkFlags)data.ReadByteValue();
+ obj.Volume = data.ReadUInt16LittleEndian();
}
// Cache the current position
long currentPosition = data.Position;
// Read the name, if possible
- if (fileDescriptor.NameOffset != 0)
+ if (obj.NameOffset != 0)
{
// Seek to the name
- data.Seek(fileDescriptor.NameOffset + descriptorOffset, SeekOrigin.Begin);
+ data.Seek(obj.NameOffset + descriptorOffset, SeekOrigin.Begin);
// Read the string
if (majorVersion >= 17)
- fileDescriptor.Name = data.ReadNullTerminatedUnicodeString();
+ obj.Name = data.ReadNullTerminatedUnicodeString();
else
- fileDescriptor.Name = data.ReadNullTerminatedAnsiString();
+ obj.Name = data.ReadNullTerminatedAnsiString();
}
// Seek back to the correct offset
data.Seek(currentPosition, SeekOrigin.Begin);
- return fileDescriptor;
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a FileGroup
+ ///
+ /// Stream to parse
+ /// Major version of the cabinet
+ /// Offset of the cabinet descriptor
+ /// Filled FileGroup on success, null on error
+ public static FileGroup ParseFileGroup(Stream data, int majorVersion, uint descriptorOffset)
+ {
+ var obj = new FileGroup();
+
+ obj.NameOffset = data.ReadUInt32LittleEndian();
+ obj.ExpandedSize = data.ReadUInt32LittleEndian();
+ obj.CompressedSize = data.ReadUInt32LittleEndian();
+ obj.Attributes = (FileGroupAttributes)data.ReadUInt16LittleEndian();
+
+ // TODO: Figure out what data lives in this area for V5 and below
+ if (majorVersion <= 5)
+ data.Seek(0x36, SeekOrigin.Current);
+
+ obj.FirstFile = data.ReadUInt32LittleEndian();
+ obj.LastFile = data.ReadUInt32LittleEndian();
+ obj.UnknownStringOffset = data.ReadUInt32LittleEndian();
+ obj.OperatingSystemOffset = data.ReadUInt32LittleEndian();
+ obj.LanguageOffset = data.ReadUInt32LittleEndian();
+ obj.HTTPLocationOffset = data.ReadUInt32LittleEndian();
+ obj.FTPLocationOffset = data.ReadUInt32LittleEndian();
+ obj.MiscOffset = data.ReadUInt32LittleEndian();
+ obj.TargetDirectoryOffset = data.ReadUInt32LittleEndian();
+ obj.OverwriteFlags = (FileGroupFlags)data.ReadUInt32LittleEndian();
+ obj.Reserved = new uint[4];
+ for (int i = 0; i < obj.Reserved.Length; i++)
+ {
+ obj.Reserved[i] = data.ReadUInt32LittleEndian();
+ }
+
+ // Cache the current position
+ long currentPosition = data.Position;
+
+ // Read the name, if possible
+ if (obj.NameOffset != 0)
+ {
+ // Seek to the name
+ data.Seek(obj.NameOffset + descriptorOffset, SeekOrigin.Begin);
+
+ // Read the string
+ if (majorVersion >= 17)
+ obj.Name = data.ReadNullTerminatedUnicodeString();
+ else
+ obj.Name = data.ReadNullTerminatedAnsiString();
+ }
+
+ // Seek back to the correct offset
+ data.Seek(currentPosition, SeekOrigin.Begin);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an OffsetList
+ ///
+ /// Stream to parse
+ /// Major version of the cabinet
+ /// Offset of the cabinet descriptor
+ /// Filled OffsetList on success, null on error
+ public static OffsetList ParseOffsetList(Stream data, int majorVersion, uint descriptorOffset)
+ {
+ var obj = new OffsetList();
+
+ obj.NameOffset = data.ReadUInt32LittleEndian();
+ obj.DescriptorOffset = data.ReadUInt32LittleEndian();
+ obj.NextOffset = data.ReadUInt32LittleEndian();
+
+ // Cache the current offset
+ long currentOffset = data.Position;
+
+ // Seek to the name offset
+ data.Seek(obj.NameOffset + descriptorOffset, SeekOrigin.Begin);
+
+ // Read the string
+ if (majorVersion >= 17)
+ obj.Name = data.ReadNullTerminatedUnicodeString();
+ else
+ obj.Name = data.ReadNullTerminatedAnsiString();
+
+ // Seek back to the correct offset
+ data.Seek(currentOffset, SeekOrigin.Begin);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a VolumeHeader
+ ///
+ /// Stream to parse
+ /// Major version of the cabinet
+ /// Filled VolumeHeader on success, null on error
+ public static VolumeHeader ParseVolumeHeader(Stream data, int majorVersion)
+ {
+ var obj = new VolumeHeader();
+
+ // Read the descriptor based on version
+ if (majorVersion <= 5)
+ {
+ obj.DataOffset = data.ReadUInt32LittleEndian();
+ _ = data.ReadBytes(0x04); // Skip 0x04 bytes, unknown data?
+ obj.FirstFileIndex = data.ReadUInt32LittleEndian();
+ obj.LastFileIndex = data.ReadUInt32LittleEndian();
+ obj.FirstFileOffset = data.ReadUInt32LittleEndian();
+ obj.FirstFileSizeExpanded = data.ReadUInt32LittleEndian();
+ obj.FirstFileSizeCompressed = data.ReadUInt32LittleEndian();
+ obj.LastFileOffset = data.ReadUInt32LittleEndian();
+ obj.LastFileSizeExpanded = data.ReadUInt32LittleEndian();
+ obj.LastFileSizeCompressed = data.ReadUInt32LittleEndian();
+ }
+ else
+ {
+ obj.DataOffset = data.ReadUInt32LittleEndian();
+ obj.DataOffsetHigh = data.ReadUInt32LittleEndian();
+ obj.FirstFileIndex = data.ReadUInt32LittleEndian();
+ obj.LastFileIndex = data.ReadUInt32LittleEndian();
+ obj.FirstFileOffset = data.ReadUInt32LittleEndian();
+ obj.FirstFileOffsetHigh = data.ReadUInt32LittleEndian();
+ obj.FirstFileSizeExpanded = data.ReadUInt32LittleEndian();
+ obj.FirstFileSizeExpandedHigh = data.ReadUInt32LittleEndian();
+ obj.FirstFileSizeCompressed = data.ReadUInt32LittleEndian();
+ obj.FirstFileSizeCompressedHigh = data.ReadUInt32LittleEndian();
+ obj.LastFileOffset = data.ReadUInt32LittleEndian();
+ obj.LastFileOffsetHigh = data.ReadUInt32LittleEndian();
+ obj.LastFileSizeExpanded = data.ReadUInt32LittleEndian();
+ obj.LastFileSizeExpandedHigh = data.ReadUInt32LittleEndian();
+ obj.LastFileSizeCompressed = data.ReadUInt32LittleEndian();
+ obj.LastFileSizeCompressedHigh = data.ReadUInt32LittleEndian();
+ }
+
+ return obj;
}
#region Helpers
diff --git a/SabreTools.Serialization/Deserializers/LinearExecutable.cs b/SabreTools.Serialization/Deserializers/LinearExecutable.cs
index 63cd7bcb..723551c3 100644
--- a/SabreTools.Serialization/Deserializers/LinearExecutable.cs
+++ b/SabreTools.Serialization/Deserializers/LinearExecutable.cs
@@ -40,8 +40,8 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the executable header
data.Seek(initialOffset + stub.Header.NewExeHeaderAddr, SeekOrigin.Begin);
- var informationBlock = data.ReadType();
- if (informationBlock?.Signature != LESignatureString && informationBlock?.Signature != LXSignatureString)
+ var informationBlock = ParseInformationBlock(data);
+ if (informationBlock.Signature != LESignatureString && informationBlock.Signature != LXSignatureString)
return null;
// Set the executable header
@@ -64,11 +64,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the object table
for (int i = 0; i < executable.ObjectTable.Length; i++)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
-
- executable.ObjectTable[i] = entry;
+ executable.ObjectTable[i] = ParseObjectTableEntry(data);
}
}
@@ -89,11 +85,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the object page map
for (int i = 0; i < executable.ObjectPageMap.Length; i++)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
-
- executable.ObjectPageMap[i] = entry;
+ executable.ObjectPageMap[i] = ParseObjectPageMapEntry(data);
}
}
@@ -129,11 +121,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the resource table
for (int i = 0; i < executable.ResourceTable.Length; i++)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
-
- executable.ResourceTable[i] = entry;
+ executable.ResourceTable[i] = ParseResourceTableEntry(data);
}
}
@@ -213,11 +201,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the module format directives table
for (int i = 0; i < executable.ModuleFormatDirectivesTable.Length; i++)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
-
- executable.ModuleFormatDirectivesTable[i] = entry;
+ executable.ModuleFormatDirectivesTable[i] = ParseModuleFormatDirectivesTableEntry(data);
}
}
@@ -246,11 +230,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the fix-up page table
for (int i = 0; i < executable.FixupPageTable.Length; i++)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
-
- executable.FixupPageTable[i] = entry;
+ executable.FixupPageTable[i] = ParseFixupPageTableEntry(data);
}
}
@@ -296,11 +276,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the imported module name table
for (int i = 0; i < executable.ImportModuleNameTable.Length; i++)
{
- var entry = ParseImportModuleNameTableEntry(data);
- if (entry == null)
- return null;
-
- executable.ImportModuleNameTable[i] = entry;
+ executable.ImportModuleNameTable[i] = ParseImportModuleNameTableEntry(data);
}
}
@@ -327,9 +303,6 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < offset + tableSize)
{
var entry = ParseImportModuleProcedureNameTableEntry(data);
- if (entry == null)
- return null;
-
importModuleProcedureNameTable.Add(entry);
}
@@ -354,11 +327,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the per-page checksum name table
for (int i = 0; i < executable.PerPageChecksumTable.Length; i++)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
-
- executable.PerPageChecksumTable[i] = entry;
+ executable.PerPageChecksumTable[i] = ParsePerPageChecksumTableEntry(data);
}
}
@@ -404,7 +373,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the debug information
var debugInformation = ParseDebugInformation(data, informationBlock.DebugInformationLength);
- if (debugInformation == null)
+ if (debugInformation.Signature != DebugInformationSignatureString)
return null;
// Set the debug information
@@ -423,276 +392,288 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a resident names table entry
+ /// Parse a Stream into a DebugInformation
///
/// Stream to parse
- /// Filled resident names table entry on success, null on error
- public static ResidentNamesTableEntry ParseResidentNamesTableEntry(Stream data)
+ /// Total size of the debug information
+ /// Filled DebugInformation on success, null on error
+ public static DebugInformation ParseDebugInformation(Stream data, long size)
{
- var entry = new ResidentNamesTableEntry();
+ var obj = new DebugInformation();
- entry.Length = data.ReadByteValue();
- if (entry.Length > 0)
- {
- byte[] name = data.ReadBytes(entry.Length);
- entry.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
- }
+ byte[] signature = data.ReadBytes(3);
+ obj.Signature = Encoding.ASCII.GetString(signature);
+ obj.FormatType = (DebugFormatType)data.ReadByteValue();
+ obj.DebuggerData = data.ReadBytes((int)(size - 4));
- entry.OrdinalNumber = data.ReadUInt16();
- return entry;
+ return obj;
}
///
- /// Parse a Stream into an entry table bundle
+ /// Parse a Stream into an EntryTableBundle
///
/// Stream to parse
- /// Filled entry table bundle on success, null on error
+ /// Filled EntryTableBundle on success, null on error
public static EntryTableBundle? ParseEntryTableBundle(Stream data)
{
- var bundle = new EntryTableBundle();
+ var obj = new EntryTableBundle();
- bundle.Entries = data.ReadByteValue();
- if (bundle.Entries == 0)
- return bundle;
+ obj.Entries = data.ReadByteValue();
+ if (obj.Entries == 0)
+ return obj;
- bundle.BundleType = (BundleType)data.ReadByteValue();
- bundle.TableEntries = new EntryTableEntry[bundle.Entries];
- for (int i = 0; i < bundle.Entries; i++)
+ obj.BundleType = (BundleType)data.ReadByteValue();
+ obj.TableEntries = new EntryTableEntry[obj.Entries];
+ for (int i = 0; i < obj.Entries; i++)
{
var entry = new EntryTableEntry();
- switch (bundle.BundleType & ~BundleType.ParameterTypingInformationPresent)
+ switch (obj.BundleType & ~BundleType.ParameterTypingInformationPresent)
{
case BundleType.UnusedEntry:
// Empty entry with no information
break;
case BundleType.SixteenBitEntry:
- entry.SixteenBitObjectNumber = data.ReadUInt16();
+ entry.SixteenBitObjectNumber = data.ReadUInt16LittleEndian();
entry.SixteenBitEntryFlags = (EntryFlags)data.ReadByteValue();
- entry.SixteenBitOffset = data.ReadUInt16();
+ entry.SixteenBitOffset = data.ReadUInt16LittleEndian();
break;
case BundleType.TwoEightySixCallGateEntry:
- entry.TwoEightySixObjectNumber = data.ReadUInt16();
+ entry.TwoEightySixObjectNumber = data.ReadUInt16LittleEndian();
entry.TwoEightySixEntryFlags = (EntryFlags)data.ReadByteValue();
- entry.TwoEightySixOffset = data.ReadUInt16();
- entry.TwoEightySixCallgate = data.ReadUInt16();
+ entry.TwoEightySixOffset = data.ReadUInt16LittleEndian();
+ entry.TwoEightySixCallgate = data.ReadUInt16LittleEndian();
break;
case BundleType.ThirtyTwoBitEntry:
- entry.ThirtyTwoBitObjectNumber = data.ReadUInt16();
+ entry.ThirtyTwoBitObjectNumber = data.ReadUInt16LittleEndian();
entry.ThirtyTwoBitEntryFlags = (EntryFlags)data.ReadByteValue();
- entry.ThirtyTwoBitOffset = data.ReadUInt32();
+ entry.ThirtyTwoBitOffset = data.ReadUInt32LittleEndian();
break;
case BundleType.ForwarderEntry:
- entry.ForwarderReserved = data.ReadUInt16();
+ entry.ForwarderReserved = data.ReadUInt16LittleEndian();
entry.ForwarderFlags = (ForwarderFlags)data.ReadByteValue();
- entry.ForwarderModuleOrdinalNumber = data.ReadUInt16();
- entry.ProcedureNameOffset = data.ReadUInt32();
- entry.ImportOrdinalNumber = data.ReadUInt32();
+ entry.ForwarderModuleOrdinalNumber = data.ReadUInt16LittleEndian();
+ entry.ProcedureNameOffset = data.ReadUInt32LittleEndian();
+ entry.ImportOrdinalNumber = data.ReadUInt32LittleEndian();
break;
default:
return null;
}
- bundle.TableEntries[i] = entry;
+ obj.TableEntries[i] = entry;
}
- return bundle;
+ return obj;
}
///
- /// Parse a Stream into a fix-up record table entry
+ /// Parse a Stream into an FixupPageTableEntry
///
/// Stream to parse
- /// Filled fix-up record table entry on success, null on error
+ /// Filled FixupPageTableEntry on success, null on error
+ public static FixupPageTableEntry ParseFixupPageTableEntry(Stream data)
+ {
+ var obj = new FixupPageTableEntry();
+
+ obj.Offset = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a FixupRecordTableEntry
+ ///
+ /// Stream to parse
+ /// Filled FixupRecordTableEntry on success, null on error
public static FixupRecordTableEntry? ParseFixupRecordTableEntry(Stream data)
{
- var entry = new FixupRecordTableEntry();
+ var obj = new FixupRecordTableEntry();
- entry.SourceType = (FixupRecordSourceType)data.ReadByteValue();
- entry.TargetFlags = (FixupRecordTargetFlags)data.ReadByteValue();
+ obj.SourceType = (FixupRecordSourceType)data.ReadByteValue();
+ obj.TargetFlags = (FixupRecordTargetFlags)data.ReadByteValue();
// Source list flag
#if NET20 || NET35
- if ((entry.SourceType & FixupRecordSourceType.SourceListFlag) != 0)
+ if ((obj.SourceType & FixupRecordSourceType.SourceListFlag) != 0)
#else
- if (entry.SourceType.HasFlag(FixupRecordSourceType.SourceListFlag))
+ if (obj.SourceType.HasFlag(FixupRecordSourceType.SourceListFlag))
#endif
- entry.SourceOffsetListCount = data.ReadByteValue();
+ obj.SourceOffsetListCount = data.ReadByteValue();
else
- entry.SourceOffset = data.ReadUInt16();
+ obj.SourceOffset = data.ReadUInt16LittleEndian();
// OBJECT / TRGOFF
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.InternalReference) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.InternalReference) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.InternalReference))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.InternalReference))
#endif
{
// 16-bit Object Number/Module Ordinal Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
#endif
- entry.TargetObjectNumberWORD = data.ReadUInt16();
+ obj.TargetObjectNumberWORD = data.ReadUInt16LittleEndian();
else
- entry.TargetObjectNumberByte = data.ReadByteValue();
+ obj.TargetObjectNumberByte = data.ReadByteValue();
// 16-bit Selector fixup
#if NET20 || NET35
- if ((entry.SourceType & FixupRecordSourceType.SixteenBitSelectorFixup) == 0)
+ if ((obj.SourceType & FixupRecordSourceType.SixteenBitSelectorFixup) == 0)
#else
- if (!entry.SourceType.HasFlag(FixupRecordSourceType.SixteenBitSelectorFixup))
+ if (!obj.SourceType.HasFlag(FixupRecordSourceType.SixteenBitSelectorFixup))
#endif
{
// 32-bit Target Offset Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
#endif
- entry.TargetOffsetDWORD = data.ReadUInt32();
+ obj.TargetOffsetDWORD = data.ReadUInt32LittleEndian();
else
- entry.TargetOffsetWORD = data.ReadUInt16();
+ obj.TargetOffsetWORD = data.ReadUInt16LittleEndian();
}
}
// MOD ORD# / IMPORT ORD / ADDITIVE
#if NET20 || NET35
- else if ((entry.TargetFlags & FixupRecordTargetFlags.ImportedReferenceByOrdinal) != 0)
+ else if ((obj.TargetFlags & FixupRecordTargetFlags.ImportedReferenceByOrdinal) != 0)
#else
- else if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ImportedReferenceByOrdinal))
+ else if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ImportedReferenceByOrdinal))
#endif
{
// 16-bit Object Number/Module Ordinal Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
#endif
- entry.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16();
+ obj.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16LittleEndian();
else
- entry.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
+ obj.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
// 8-bit Ordinal Flag & 32-bit Target Offset Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.EightBitOrdinalFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.EightBitOrdinalFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.EightBitOrdinalFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.EightBitOrdinalFlag))
#endif
- entry.ImportedOrdinalNumberByte = data.ReadByteValue();
+ obj.ImportedOrdinalNumberByte = data.ReadByteValue();
#if NET20 || NET35
- else if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
+ else if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
#else
- else if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
+ else if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
#endif
- entry.ImportedOrdinalNumberDWORD = data.ReadUInt32();
+ obj.ImportedOrdinalNumberDWORD = data.ReadUInt32LittleEndian();
else
- entry.ImportedOrdinalNumberWORD = data.ReadUInt16();
+ obj.ImportedOrdinalNumberWORD = data.ReadUInt16LittleEndian();
// Additive Fixup Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
#endif
{
// 32-bit Additive Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
#endif
- entry.AdditiveFixupValueDWORD = data.ReadUInt32();
+ obj.AdditiveFixupValueDWORD = data.ReadUInt32LittleEndian();
else
- entry.AdditiveFixupValueWORD = data.ReadUInt16();
+ obj.AdditiveFixupValueWORD = data.ReadUInt16LittleEndian();
}
}
// MOD ORD# / PROCEDURE NAME OFFSET / ADDITIVE
#if NET20 || NET35
- else if ((entry.TargetFlags & FixupRecordTargetFlags.ImportedReferenceByName) != 0)
+ else if ((obj.TargetFlags & FixupRecordTargetFlags.ImportedReferenceByName) != 0)
#else
- else if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ImportedReferenceByName))
+ else if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ImportedReferenceByName))
#endif
{
// 16-bit Object Number/Module Ordinal Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
#endif
- entry.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16();
+ obj.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16LittleEndian();
else
- entry.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
+ obj.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
// 32-bit Target Offset Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
#endif
- entry.OffsetImportProcedureNameTableDWORD = data.ReadUInt32();
+ obj.OffsetImportProcedureNameTableDWORD = data.ReadUInt32LittleEndian();
else
- entry.OffsetImportProcedureNameTableWORD = data.ReadUInt16();
+ obj.OffsetImportProcedureNameTableWORD = data.ReadUInt16LittleEndian();
// Additive Fixup Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
#endif
{
// 32-bit Additive Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
#endif
- entry.AdditiveFixupValueDWORD = data.ReadUInt32();
+ obj.AdditiveFixupValueDWORD = data.ReadUInt32LittleEndian();
else
- entry.AdditiveFixupValueWORD = data.ReadUInt16();
+ obj.AdditiveFixupValueWORD = data.ReadUInt16LittleEndian();
}
}
// ORD # / ADDITIVE
#if NET20 || NET35
- else if ((entry.TargetFlags & FixupRecordTargetFlags.InternalReferenceViaEntryTable) != 0)
+ else if ((obj.TargetFlags & FixupRecordTargetFlags.InternalReferenceViaEntryTable) != 0)
#else
- else if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.InternalReferenceViaEntryTable))
+ else if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.InternalReferenceViaEntryTable))
#endif
{
// 16-bit Object Number/Module Ordinal Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
#endif
- entry.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16();
+ obj.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16LittleEndian();
else
- entry.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
+ obj.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
// Additive Fixup Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
#endif
{
// 32-bit Additive Flag
#if NET20 || NET35
- if ((entry.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
+ if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
#else
- if (entry.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
+ if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
#endif
- entry.AdditiveFixupValueDWORD = data.ReadUInt32();
+ obj.AdditiveFixupValueDWORD = data.ReadUInt32LittleEndian();
else
- entry.AdditiveFixupValueWORD = data.ReadUInt16();
+ obj.AdditiveFixupValueWORD = data.ReadUInt16LittleEndian();
}
}
@@ -705,59 +686,135 @@ namespace SabreTools.Serialization.Deserializers
#region SCROFFn
#if NET20 || NET35
- if ((entry.SourceType & FixupRecordSourceType.SourceListFlag) != 0)
+ if ((obj.SourceType & FixupRecordSourceType.SourceListFlag) != 0)
#else
- if (entry.SourceType.HasFlag(FixupRecordSourceType.SourceListFlag))
+ if (obj.SourceType.HasFlag(FixupRecordSourceType.SourceListFlag))
#endif
{
- entry.SourceOffsetList = new ushort[entry.SourceOffsetListCount];
- for (int i = 0; i < entry.SourceOffsetList.Length; i++)
+ obj.SourceOffsetList = new ushort[obj.SourceOffsetListCount];
+ for (int i = 0; i < obj.SourceOffsetList.Length; i++)
{
- entry.SourceOffsetList[i] = data.ReadUInt16();
+ obj.SourceOffsetList[i] = data.ReadUInt16LittleEndian();
}
}
#endregion
- return entry;
+ return obj;
}
///
- /// Parse a Stream into a import module name table entry
+ /// Parse a Stream into an ImportModuleNameTableEntry
///
/// Stream to parse
- /// Filled import module name table entry on success, null on error
+ /// Filled ImportModuleNameTableEntry on success, null on error
public static ImportModuleNameTableEntry ParseImportModuleNameTableEntry(Stream data)
{
- var entry = new ImportModuleNameTableEntry();
+ var obj = new ImportModuleNameTableEntry();
- entry.Length = data.ReadByteValue();
- if (entry.Length > 0)
+ obj.Length = data.ReadByteValue();
+ if (obj.Length > 0)
{
- byte[] name = data.ReadBytes(entry.Length);
- entry.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
+ byte[] name = data.ReadBytes(obj.Length);
+ obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
}
- return entry;
+ return obj;
}
///
- /// Parse a Stream into a import module name table entry
+ /// Parse a Stream into an ImportModuleProcedureNameTableEntry
///
/// Stream to parse
- /// Filled import module name table entry on success, null on error
+ /// Filled ImportModuleProcedureNameTableEntry on success, null on error
public static ImportModuleProcedureNameTableEntry ParseImportModuleProcedureNameTableEntry(Stream data)
{
- var entry = new ImportModuleProcedureNameTableEntry();
+ var obj = new ImportModuleProcedureNameTableEntry();
- entry.Length = data.ReadByteValue();
- if (entry.Length > 0)
+ obj.Length = data.ReadByteValue();
+ if (obj.Length > 0)
{
- byte[] name = data.ReadBytes(entry.Length);
- entry.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
+ byte[] name = data.ReadBytes(obj.Length);
+ obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
}
- return entry;
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a InformationBlock
+ ///
+ /// Stream to parse
+ /// Filled InformationBlock on success, null on error
+ public static InformationBlock ParseInformationBlock(Stream data)
+ {
+ var obj = new InformationBlock();
+
+ byte[] signature = data.ReadBytes(2);
+ obj.Signature = Encoding.ASCII.GetString(signature);
+ obj.ByteOrder = (ByteOrder)data.ReadByteValue();
+ obj.WordOrder = (WordOrder)data.ReadByteValue();
+ obj.ExecutableFormatLevel = data.ReadUInt32LittleEndian();
+ obj.CPUType = (CPUType)data.ReadUInt16LittleEndian();
+ obj.ModuleOS = (OperatingSystem)data.ReadUInt16LittleEndian();
+ obj.ModuleVersion = data.ReadUInt32LittleEndian();
+ obj.ModuleTypeFlags = (ModuleFlags)data.ReadUInt32LittleEndian();
+ obj.ModuleNumberPages = data.ReadUInt32LittleEndian();
+ obj.InitialObjectCS = data.ReadUInt32LittleEndian();
+ obj.InitialEIP = data.ReadUInt32LittleEndian();
+ obj.InitialObjectSS = data.ReadUInt32LittleEndian();
+ obj.InitialESP = data.ReadUInt32LittleEndian();
+ obj.MemoryPageSize = data.ReadUInt32LittleEndian();
+ obj.BytesOnLastPage = data.ReadUInt32LittleEndian();
+ obj.FixupSectionSize = data.ReadUInt32LittleEndian();
+ obj.FixupSectionChecksum = data.ReadUInt32LittleEndian();
+ obj.LoaderSectionSize = data.ReadUInt32LittleEndian();
+ obj.LoaderSectionChecksum = data.ReadUInt32LittleEndian();
+ obj.ObjectTableOffset = data.ReadUInt32LittleEndian();
+ obj.ObjectTableCount = data.ReadUInt32LittleEndian();
+ obj.ObjectPageMapOffset = data.ReadUInt32LittleEndian();
+ obj.ObjectIterateDataMapOffset = data.ReadUInt32LittleEndian();
+ obj.ResourceTableOffset = data.ReadUInt32LittleEndian();
+ obj.ResourceTableCount = data.ReadUInt32LittleEndian();
+ obj.ResidentNamesTableOffset = data.ReadUInt32LittleEndian();
+ obj.EntryTableOffset = data.ReadUInt32LittleEndian();
+ obj.ModuleDirectivesTableOffset = data.ReadUInt32LittleEndian();
+ obj.ModuleDirectivesCount = data.ReadUInt32LittleEndian();
+ obj.FixupPageTableOffset = data.ReadUInt32LittleEndian();
+ obj.FixupRecordTableOffset = data.ReadUInt32LittleEndian();
+ obj.ImportedModulesNameTableOffset = data.ReadUInt32LittleEndian();
+ obj.ImportedModulesCount = data.ReadUInt32LittleEndian();
+ obj.ImportProcedureNameTableOffset = data.ReadUInt32LittleEndian();
+ obj.PerPageChecksumTableOffset = data.ReadUInt32LittleEndian();
+ obj.DataPagesOffset = data.ReadUInt32LittleEndian();
+ obj.PreloadPageCount = data.ReadUInt32LittleEndian();
+ obj.NonResidentNamesTableOffset = data.ReadUInt32LittleEndian();
+ obj.NonResidentNamesTableLength = data.ReadUInt32LittleEndian();
+ obj.NonResidentNamesTableChecksum = data.ReadUInt32LittleEndian();
+ obj.AutomaticDataObject = data.ReadUInt32LittleEndian();
+ obj.DebugInformationOffset = data.ReadUInt32LittleEndian();
+ obj.DebugInformationLength = data.ReadUInt32LittleEndian();
+ obj.PreloadInstancePagesNumber = data.ReadUInt32LittleEndian();
+ obj.DemandInstancePagesNumber = data.ReadUInt32LittleEndian();
+ obj.ExtraHeapAllocation = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ModuleFormatDirectivesTableEntry
+ ///
+ /// Stream to parse
+ /// Filled ModuleFormatDirectivesTableEntry on success, null on error
+ public static ModuleFormatDirectivesTableEntry ParseModuleFormatDirectivesTableEntry(Stream data)
+ {
+ var obj = new ModuleFormatDirectivesTableEntry();
+
+ obj.DirectiveNumber = (DirectiveNumber)data.ReadUInt16LittleEndian();
+ obj.DirectiveDataLength = data.ReadUInt16LittleEndian();
+ obj.DirectiveDataOffset = data.ReadUInt32LittleEndian();
+
+ return obj;
}
///
@@ -767,38 +824,105 @@ namespace SabreTools.Serialization.Deserializers
/// Filled non-resident names table entry on success, null on error
public static NonResidentNamesTableEntry ParseNonResidentNameTableEntry(Stream data)
{
- var entry = new NonResidentNamesTableEntry();
+ var obj = new NonResidentNamesTableEntry();
- entry.Length = data.ReadByteValue();
- if (entry.Length > 0)
+ obj.Length = data.ReadByteValue();
+ if (obj.Length > 0)
{
- byte[] name = data.ReadBytes(entry.Length);
- entry.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
+ byte[] name = data.ReadBytes(obj.Length);
+ obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
}
- entry.OrdinalNumber = data.ReadUInt16();
- return entry;
+ obj.OrdinalNumber = data.ReadUInt16LittleEndian();
+
+ return obj;
}
///
- /// Parse a Stream into a debug information
+ /// Parse a Stream into a ObjectPageMapEntry
///
/// Stream to parse
- /// Total size of the debug information
- /// Filled debug information on success, null on error
- public static DebugInformation? ParseDebugInformation(Stream data, long size)
+ /// Filled ObjectPageMapEntry on success, null on error
+ public static ObjectPageMapEntry ParseObjectPageMapEntry(Stream data)
{
- var debugInformation = new DebugInformation();
+ var obj = new ObjectPageMapEntry();
- byte[] signature = data.ReadBytes(3);
- debugInformation.Signature = Encoding.ASCII.GetString(signature);
- if (debugInformation.Signature != DebugInformationSignatureString)
- return null;
+ obj.PageDataOffset = data.ReadUInt32LittleEndian();
+ obj.DataSize = data.ReadUInt16LittleEndian();
+ obj.Flags = (ObjectPageFlags)data.ReadUInt16LittleEndian();
- debugInformation.FormatType = (DebugFormatType)data.ReadByteValue();
- debugInformation.DebuggerData = data.ReadBytes((int)(size - 4));
+ return obj;
+ }
- return debugInformation;
+ ///
+ /// Parse a Stream into a ObjectTableEntry
+ ///
+ /// Stream to parse
+ /// Filled ObjectTableEntry on success, null on error
+ public static ObjectTableEntry ParseObjectTableEntry(Stream data)
+ {
+ var obj = new ObjectTableEntry();
+
+ obj.RelocationBaseAddress = data.ReadUInt32LittleEndian();
+ obj.ObjectFlags = (ObjectFlags)data.ReadUInt16LittleEndian();
+ obj.PageTableIndex = data.ReadUInt32LittleEndian();
+ obj.PageTableEntries = data.ReadUInt32LittleEndian();
+ obj.Reserved = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a PerPageChecksumTableEntry
+ ///
+ /// Stream to parse
+ /// Filled PerPageChecksumTableEntry on success, null on error
+ public static PerPageChecksumTableEntry ParsePerPageChecksumTableEntry(Stream data)
+ {
+ var obj = new PerPageChecksumTableEntry();
+
+ obj.Checksum = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ResourceTableEntry
+ ///
+ /// Stream to parse
+ /// Filled ResourceTableEntry on success, null on error
+ public static ResourceTableEntry ParseResourceTableEntry(Stream data)
+ {
+ var obj = new ResourceTableEntry();
+
+ obj.TypeID = (ResourceTableEntryType)data.ReadUInt32LittleEndian();
+ obj.NameID = data.ReadUInt16LittleEndian();
+ obj.ResourceSize = data.ReadUInt32LittleEndian();
+ obj.ObjectNumber = data.ReadUInt16LittleEndian();
+ obj.Offset = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ResidentNamesTableEntry
+ ///
+ /// Stream to parse
+ /// Filled ResidentNamesTableEntry on success, null on error
+ public static ResidentNamesTableEntry ParseResidentNamesTableEntry(Stream data)
+ {
+ var obj = new ResidentNamesTableEntry();
+
+ obj.Length = data.ReadByteValue();
+ if (obj.Length > 0)
+ {
+ byte[] name = data.ReadBytes(obj.Length);
+ obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
+ }
+
+ obj.OrdinalNumber = data.ReadUInt16LittleEndian();
+
+ return obj;
}
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/MSDOS.cs b/SabreTools.Serialization/Deserializers/MSDOS.cs
index 9f9e1e5f..c8780c35 100644
--- a/SabreTools.Serialization/Deserializers/MSDOS.cs
+++ b/SabreTools.Serialization/Deserializers/MSDOS.cs
@@ -27,7 +27,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the executable header
var executableHeader = ParseExecutableHeader(data);
- if (executableHeader == null)
+ if (executableHeader.Magic != SignatureString)
return null;
// Set the executable header
@@ -44,12 +44,13 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the relocation table
data.Seek(tableAddress, SeekOrigin.Begin);
- var relocationTable = ParseRelocationTable(data, executableHeader.RelocationItems);
- if (relocationTable == null)
- return null;
// Set the relocation table
- executable.RelocationTable = relocationTable;
+ executable.RelocationTable = new RelocationEntry[executableHeader.RelocationItems];
+ for (int i = 0; i < executableHeader.RelocationItems; i++)
+ {
+ executable.RelocationTable[i] = ParseRelocationEntry(data);
+ }
#endregion
@@ -64,82 +65,72 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into an MS-DOS executable header
+ /// Parse a Stream into an ExecutableHeader
///
/// Stream to parse
- /// Filled executable header on success, null on error
- private static ExecutableHeader? ParseExecutableHeader(Stream data)
+ /// Filled ExecutableHeader on success, null on error
+ public static ExecutableHeader ParseExecutableHeader(Stream data)
{
- var header = new ExecutableHeader();
+ var obj = new ExecutableHeader();
#region Standard Fields
byte[] magic = data.ReadBytes(2);
- header.Magic = Encoding.ASCII.GetString(magic);
- if (header.Magic != SignatureString)
- return null;
-
- header.LastPageBytes = data.ReadUInt16();
- header.Pages = data.ReadUInt16();
- header.RelocationItems = data.ReadUInt16();
- header.HeaderParagraphSize = data.ReadUInt16();
- header.MinimumExtraParagraphs = data.ReadUInt16();
- header.MaximumExtraParagraphs = data.ReadUInt16();
- header.InitialSSValue = data.ReadUInt16();
- header.InitialSPValue = data.ReadUInt16();
- header.Checksum = data.ReadUInt16();
- header.InitialIPValue = data.ReadUInt16();
- header.InitialCSValue = data.ReadUInt16();
- header.RelocationTableAddr = data.ReadUInt16();
- header.OverlayNumber = data.ReadUInt16();
+ obj.Magic = Encoding.ASCII.GetString(magic);
+ obj.LastPageBytes = data.ReadUInt16LittleEndian();
+ obj.Pages = data.ReadUInt16LittleEndian();
+ obj.RelocationItems = data.ReadUInt16LittleEndian();
+ obj.HeaderParagraphSize = data.ReadUInt16LittleEndian();
+ obj.MinimumExtraParagraphs = data.ReadUInt16LittleEndian();
+ obj.MaximumExtraParagraphs = data.ReadUInt16LittleEndian();
+ obj.InitialSSValue = data.ReadUInt16LittleEndian();
+ obj.InitialSPValue = data.ReadUInt16LittleEndian();
+ obj.Checksum = data.ReadUInt16LittleEndian();
+ obj.InitialIPValue = data.ReadUInt16LittleEndian();
+ obj.InitialCSValue = data.ReadUInt16LittleEndian();
+ obj.RelocationTableAddr = data.ReadUInt16LittleEndian();
+ obj.OverlayNumber = data.ReadUInt16LittleEndian();
#endregion
// If we don't have enough data for PE extensions
if (data.Position >= data.Length || data.Length - data.Position < 36)
- return header;
+ return obj;
#region PE Extensions
- header.Reserved1 = new ushort[4];
- for (int i = 0; i < header.Reserved1.Length; i++)
+ obj.Reserved1 = new ushort[4];
+ for (int i = 0; i < obj.Reserved1.Length; i++)
{
- header.Reserved1[i] = data.ReadUInt16();
+ obj.Reserved1[i] = data.ReadUInt16LittleEndian();
}
- header.OEMIdentifier = data.ReadUInt16();
- header.OEMInformation = data.ReadUInt16();
- header.Reserved2 = new ushort[10];
- for (int i = 0; i < header.Reserved2.Length; i++)
+ obj.OEMIdentifier = data.ReadUInt16LittleEndian();
+ obj.OEMInformation = data.ReadUInt16LittleEndian();
+ obj.Reserved2 = new ushort[10];
+ for (int i = 0; i < obj.Reserved2.Length; i++)
{
- header.Reserved2[i] = data.ReadUInt16();
+ obj.Reserved2[i] = data.ReadUInt16LittleEndian();
}
- header.NewExeHeaderAddr = data.ReadUInt32();
+ obj.NewExeHeaderAddr = data.ReadUInt32LittleEndian();
#endregion
- return header;
+ return obj;
}
///
- /// Parse a Stream into a relocation table
+ /// Parse a Stream into an ExecutableHeader
///
/// Stream to parse
- /// Number of relocation table entries to read
- /// Filled relocation table on success, null on error
- private static RelocationEntry[]? ParseRelocationTable(Stream data, int count)
+ /// Filled ExecutableHeader on success, null on error
+ public static RelocationEntry ParseRelocationEntry(Stream data)
{
- var relocationTable = new RelocationEntry[count];
+ var obj = new RelocationEntry();
- for (int i = 0; i < count; i++)
- {
- var entry = data.ReadType();
- if (entry == null)
- return null;
+ obj.Offset = data.ReadUInt16LittleEndian();
+ obj.Segment = data.ReadUInt16LittleEndian();
- relocationTable[i] = entry;
- }
-
- return relocationTable;
+ return obj;
}
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/MoPaQ.cs b/SabreTools.Serialization/Deserializers/MoPaQ.cs
index 9a7d41d6..7e0ff2e0 100644
--- a/SabreTools.Serialization/Deserializers/MoPaQ.cs
+++ b/SabreTools.Serialization/Deserializers/MoPaQ.cs
@@ -25,7 +25,7 @@ namespace SabreTools.Serialization.Deserializers
#region User Data
// Check for User Data
- uint possibleSignature = data.ReadUInt32();
+ uint possibleSignature = data.ReadUInt32LittleEndian();
data.Seek(-4, SeekOrigin.Current);
if (possibleSignature == UserDataSignatureUInt32)
{
@@ -33,7 +33,7 @@ namespace SabreTools.Serialization.Deserializers
long basePtr = data.Position;
// Deserialize the user data, returning null if invalid
- var userData = data.ReadType();
+ var userData = ParseUserData(data);
if (userData?.Signature != UserDataSignatureString)
return null;
@@ -49,13 +49,13 @@ namespace SabreTools.Serialization.Deserializers
#region Archive Header
// Check for the Header
- possibleSignature = data.ReadUInt32();
+ possibleSignature = data.ReadUInt32LittleEndian();
data.Seek(-4, SeekOrigin.Current);
if (possibleSignature == ArchiveHeaderSignatureUInt32)
{
// Try to parse the archive header
var archiveHeader = ParseArchiveHeader(data);
- if (archiveHeader == null)
+ if (archiveHeader.Signature != ArchiveHeaderSignatureString)
return null;
// Set the archive header
@@ -90,10 +90,7 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < hashTableEnd)
{
- var hashEntry = data.ReadType();
- if (hashEntry == null)
- return null;
-
+ var hashEntry = ParseHashEntry(data);
hashTable.Add(hashEntry);
}
@@ -120,10 +117,7 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < hashTableEnd)
{
- var hashEntry = data.ReadType();
- if (hashEntry == null)
- return null;
-
+ var hashEntry = ParseHashEntry(data);
hashTable.Add(hashEntry);
}
@@ -149,10 +143,7 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < hashTableEnd)
{
- var hashEntry = data.ReadType();
- if (hashEntry == null)
- return null;
-
+ var hashEntry = ParseHashEntry(data);
hashTable.Add(hashEntry);
}
@@ -182,10 +173,7 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < blockTableEnd)
{
- var blockEntry = data.ReadType();
- if (blockEntry == null)
- return null;
-
+ var blockEntry = ParseBlockEntry(data);
blockTable.Add(blockEntry);
}
@@ -212,10 +200,7 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < blockTableEnd)
{
- var blockEntry = data.ReadType();
- if (blockEntry == null)
- return null;
-
+ var blockEntry = ParseBlockEntry(data);
blockTable.Add(blockEntry);
}
@@ -241,10 +226,7 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < blockTableEnd)
{
- var blockEntry = data.ReadType();
- if (blockEntry == null)
- return null;
-
+ var blockEntry = ParseBlockEntry(data);
blockTable.Add(blockEntry);
}
@@ -271,7 +253,7 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < (archive.BlockTable?.Length ?? 0); i++)
{
- short hiBlockEntry = data.ReadInt16();
+ short hiBlockEntry = data.ReadInt16LittleEndian();
hiBlockTable.Add(hiBlockEntry);
}
@@ -295,7 +277,7 @@ namespace SabreTools.Serialization.Deserializers
// Read in the BET table
var betTable = ParseBetTable(data);
- if (betTable != null)
+ if (betTable.Signature != BetTableSignatureString)
return null;
archive.BetTable = betTable;
@@ -318,7 +300,7 @@ namespace SabreTools.Serialization.Deserializers
// Read in the HET table
var hetTable = ParseHetTable(data);
- if (hetTable != null)
+ if (hetTable.Signature != HetTableSignatureString)
return null;
archive.HetTable = hetTable;
@@ -337,150 +319,195 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a archive header
+ /// Parse a Stream into an ArchiveHeader
///
/// Stream to parse
- /// Filled archive header on success, null on error
- private static ArchiveHeader? ParseArchiveHeader(Stream data)
+ /// Filled ArchiveHeader on success, null on error
+ public static ArchiveHeader ParseArchiveHeader(Stream data)
{
- ArchiveHeader archiveHeader = new ArchiveHeader();
+ var obj = new ArchiveHeader();
// V1 - Common
byte[] signature = data.ReadBytes(4);
- archiveHeader.Signature = Encoding.ASCII.GetString(signature);
- if (archiveHeader.Signature != ArchiveHeaderSignatureString)
- return null;
+ obj.Signature = Encoding.ASCII.GetString(signature);
- archiveHeader.HeaderSize = data.ReadUInt32();
- archiveHeader.ArchiveSize = data.ReadUInt32();
- archiveHeader.FormatVersion = (FormatVersion)data.ReadUInt16();
- archiveHeader.BlockSize = data.ReadUInt16();
- archiveHeader.HashTablePosition = data.ReadUInt32();
- archiveHeader.BlockTablePosition = data.ReadUInt32();
- archiveHeader.HashTableSize = data.ReadUInt32();
- archiveHeader.BlockTableSize = data.ReadUInt32();
+ obj.HeaderSize = data.ReadUInt32LittleEndian();
+ obj.ArchiveSize = data.ReadUInt32LittleEndian();
+ obj.FormatVersion = (FormatVersion)data.ReadUInt16LittleEndian();
+ obj.BlockSize = data.ReadUInt16LittleEndian();
+ obj.HashTablePosition = data.ReadUInt32LittleEndian();
+ obj.BlockTablePosition = data.ReadUInt32LittleEndian();
+ obj.HashTableSize = data.ReadUInt32LittleEndian();
+ obj.BlockTableSize = data.ReadUInt32LittleEndian();
// V2
- if (archiveHeader.FormatVersion >= FormatVersion.Format2)
+ if (obj.FormatVersion >= FormatVersion.Format2)
{
- archiveHeader.HiBlockTablePosition = data.ReadUInt64();
- archiveHeader.HashTablePositionHi = data.ReadUInt16();
- archiveHeader.BlockTablePositionHi = data.ReadUInt16();
+ obj.HiBlockTablePosition = data.ReadUInt64LittleEndian();
+ obj.HashTablePositionHi = data.ReadUInt16LittleEndian();
+ obj.BlockTablePositionHi = data.ReadUInt16LittleEndian();
}
// V3
- if (archiveHeader.FormatVersion >= FormatVersion.Format3)
+ if (obj.FormatVersion >= FormatVersion.Format3)
{
- archiveHeader.ArchiveSizeLong = data.ReadUInt64();
- archiveHeader.BetTablePosition = data.ReadUInt64();
- archiveHeader.HetTablePosition = data.ReadUInt64();
+ obj.ArchiveSizeLong = data.ReadUInt64LittleEndian();
+ obj.BetTablePosition = data.ReadUInt64LittleEndian();
+ obj.HetTablePosition = data.ReadUInt64LittleEndian();
}
// V4
- if (archiveHeader.FormatVersion >= FormatVersion.Format4)
+ if (obj.FormatVersion >= FormatVersion.Format4)
{
- archiveHeader.HashTableSizeLong = data.ReadUInt64();
- archiveHeader.BlockTableSizeLong = data.ReadUInt64();
- archiveHeader.HiBlockTableSize = data.ReadUInt64();
- archiveHeader.HetTableSize = data.ReadUInt64();
- archiveHeader.BetTablesize = data.ReadUInt64();
- archiveHeader.RawChunkSize = data.ReadUInt32();
+ obj.HashTableSizeLong = data.ReadUInt64LittleEndian();
+ obj.BlockTableSizeLong = data.ReadUInt64LittleEndian();
+ obj.HiBlockTableSize = data.ReadUInt64LittleEndian();
+ obj.HetTableSize = data.ReadUInt64LittleEndian();
+ obj.BetTablesize = data.ReadUInt64LittleEndian();
+ obj.RawChunkSize = data.ReadUInt32LittleEndian();
- archiveHeader.BlockTableMD5 = data.ReadBytes(0x10);
- archiveHeader.HashTableMD5 = data.ReadBytes(0x10);
- archiveHeader.HiBlockTableMD5 = data.ReadBytes(0x10);
- archiveHeader.BetTableMD5 = data.ReadBytes(0x10);
- archiveHeader.HetTableMD5 = data.ReadBytes(0x10);
- archiveHeader.HetTableMD5 = data.ReadBytes(0x10);
+ obj.BlockTableMD5 = data.ReadBytes(0x10);
+ obj.HashTableMD5 = data.ReadBytes(0x10);
+ obj.HiBlockTableMD5 = data.ReadBytes(0x10);
+ obj.BetTableMD5 = data.ReadBytes(0x10);
+ obj.HetTableMD5 = data.ReadBytes(0x10);
+ obj.HetTableMD5 = data.ReadBytes(0x10);
}
- return archiveHeader;
+ return obj;
}
///
- /// Parse a Stream into a HET table
+ /// Parse a Stream into a BetTable
///
/// Stream to parse
- /// Filled HET table on success, null on error
- private static HetTable? ParseHetTable(Stream data)
+ /// Filled BetTable on success, null on error
+ public static BetTable ParseBetTable(Stream data)
{
- var hetTable = new HetTable();
+ var obj = new BetTable();
// Common Headers
byte[] signature = data.ReadBytes(4);
- hetTable.Signature = Encoding.ASCII.GetString(signature);
- if (hetTable.Signature != HetTableSignatureString)
- return null;
-
- hetTable.Version = data.ReadUInt32();
- hetTable.DataSize = data.ReadUInt32();
-
- // HET-Specific
- hetTable.TableSize = data.ReadUInt32();
- hetTable.MaxFileCount = data.ReadUInt32();
- hetTable.HashTableSize = data.ReadUInt32();
- hetTable.TotalIndexSize = data.ReadUInt32();
- hetTable.IndexSizeExtra = data.ReadUInt32();
- hetTable.IndexSize = data.ReadUInt32();
- hetTable.BlockTableSize = data.ReadUInt32();
- hetTable.HashTable = data.ReadBytes((int)hetTable.HashTableSize);
-
- // TODO: Populate the file indexes array
- hetTable.FileIndexes = new byte[(int)hetTable.HashTableSize][];
-
- return hetTable;
- }
-
- ///
- /// Parse a Stream into a BET table
- ///
- /// Stream to parse
- /// Filled BET table on success, null on error
- private static BetTable? ParseBetTable(Stream data)
- {
- var betTable = new BetTable();
-
- // Common Headers
- byte[] signature = data.ReadBytes(4);
- betTable.Signature = Encoding.ASCII.GetString(signature);
- if (betTable.Signature != BetTableSignatureString)
- return null;
-
- betTable.Version = data.ReadUInt32();
- betTable.DataSize = data.ReadUInt32();
+ obj.Signature = Encoding.ASCII.GetString(signature);
+ obj.Version = data.ReadUInt32LittleEndian();
+ obj.DataSize = data.ReadUInt32LittleEndian();
// BET-Specific
- betTable.TableSize = data.ReadUInt32();
- betTable.FileCount = data.ReadUInt32();
- betTable.Unknown = data.ReadUInt32();
- betTable.TableEntrySize = data.ReadUInt32();
+ obj.TableSize = data.ReadUInt32LittleEndian();
+ obj.FileCount = data.ReadUInt32LittleEndian();
+ obj.Unknown = data.ReadUInt32LittleEndian();
+ obj.TableEntrySize = data.ReadUInt32LittleEndian();
- betTable.FilePositionBitIndex = data.ReadUInt32();
- betTable.FileSizeBitIndex = data.ReadUInt32();
- betTable.CompressedSizeBitIndex = data.ReadUInt32();
- betTable.FlagIndexBitIndex = data.ReadUInt32();
- betTable.UnknownBitIndex = data.ReadUInt32();
+ obj.FilePositionBitIndex = data.ReadUInt32LittleEndian();
+ obj.FileSizeBitIndex = data.ReadUInt32LittleEndian();
+ obj.CompressedSizeBitIndex = data.ReadUInt32LittleEndian();
+ obj.FlagIndexBitIndex = data.ReadUInt32LittleEndian();
+ obj.UnknownBitIndex = data.ReadUInt32LittleEndian();
- betTable.FilePositionBitCount = data.ReadUInt32();
- betTable.FileSizeBitCount = data.ReadUInt32();
- betTable.CompressedSizeBitCount = data.ReadUInt32();
- betTable.FlagIndexBitCount = data.ReadUInt32();
- betTable.UnknownBitCount = data.ReadUInt32();
+ obj.FilePositionBitCount = data.ReadUInt32LittleEndian();
+ obj.FileSizeBitCount = data.ReadUInt32LittleEndian();
+ obj.CompressedSizeBitCount = data.ReadUInt32LittleEndian();
+ obj.FlagIndexBitCount = data.ReadUInt32LittleEndian();
+ obj.UnknownBitCount = data.ReadUInt32LittleEndian();
- betTable.TotalBetHashSize = data.ReadUInt32();
- betTable.BetHashSizeExtra = data.ReadUInt32();
- betTable.BetHashSize = data.ReadUInt32();
- betTable.BetHashArraySize = data.ReadUInt32();
- betTable.FlagCount = data.ReadUInt32();
+ obj.TotalBetHashSize = data.ReadUInt32LittleEndian();
+ obj.BetHashSizeExtra = data.ReadUInt32LittleEndian();
+ obj.BetHashSize = data.ReadUInt32LittleEndian();
+ obj.BetHashArraySize = data.ReadUInt32LittleEndian();
+ obj.FlagCount = data.ReadUInt32LittleEndian();
- betTable.FlagsArray = new uint[betTable.FlagCount];
- byte[] flagsArray = data.ReadBytes((int)betTable.FlagCount * 4);
- Buffer.BlockCopy(flagsArray, 0, betTable.FlagsArray, 0, (int)betTable.FlagCount * 4);
+ obj.FlagsArray = new uint[obj.FlagCount];
+ byte[] flagsArray = data.ReadBytes((int)obj.FlagCount * 4);
+ Buffer.BlockCopy(flagsArray, 0, obj.FlagsArray, 0, (int)obj.FlagCount * 4);
// TODO: Populate the file table
// TODO: Populate the hash table
- return betTable;
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an BlockEntry
+ ///
+ /// Stream to parse
+ /// Filled BlockEntry on success, null on error
+ public static BlockEntry ParseBlockEntry(Stream data)
+ {
+ var obj = new BlockEntry();
+
+ obj.FilePosition = data.ReadUInt32LittleEndian();
+ obj.CompressedSize = data.ReadUInt32LittleEndian();
+ obj.UncompressedSize = data.ReadUInt32LittleEndian();
+ obj.Flags = (FileFlags)data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an HashEntry
+ ///
+ /// Stream to parse
+ /// Filled HashEntry on success, null on error
+ public static HashEntry ParseHashEntry(Stream data)
+ {
+ var obj = new HashEntry();
+
+ obj.NameHashPartA = data.ReadUInt32LittleEndian();
+ obj.NameHashPartB = data.ReadUInt32LittleEndian();
+ obj.Locale = (Locale)data.ReadInt16LittleEndian();
+ obj.Platform = data.ReadUInt16LittleEndian();
+ obj.BlockIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a HetTable
+ ///
+ /// Stream to parse
+ /// Filled HetTable on success, null on error
+ public static HetTable ParseHetTable(Stream data)
+ {
+ var obj = new HetTable();
+
+ // Common Headers
+ byte[] signature = data.ReadBytes(4);
+ obj.Signature = Encoding.ASCII.GetString(signature);
+ obj.Version = data.ReadUInt32LittleEndian();
+ obj.DataSize = data.ReadUInt32LittleEndian();
+
+ // HET-Specific
+ obj.TableSize = data.ReadUInt32LittleEndian();
+ obj.MaxFileCount = data.ReadUInt32LittleEndian();
+ obj.HashTableSize = data.ReadUInt32LittleEndian();
+ obj.TotalIndexSize = data.ReadUInt32LittleEndian();
+ obj.IndexSizeExtra = data.ReadUInt32LittleEndian();
+ obj.IndexSize = data.ReadUInt32LittleEndian();
+ obj.BlockTableSize = data.ReadUInt32LittleEndian();
+ obj.HashTable = data.ReadBytes((int)obj.HashTableSize);
+
+ // TODO: Populate the file indexes array
+ obj.FileIndexes = new byte[(int)obj.HashTableSize][];
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a UserData
+ ///
+ /// Stream to parse
+ /// Filled UserData on success, null on error
+ public static UserData ParseUserData(Stream data)
+ {
+ var obj = new UserData();
+
+ byte[] signature = data.ReadBytes(4);
+ obj.Signature = Encoding.ASCII.GetString(signature);
+ obj.UserDataSize = data.ReadUInt32LittleEndian();
+ obj.HeaderOffset = data.ReadUInt32LittleEndian();
+ obj.UserDataHeaderSize = data.ReadUInt32LittleEndian();
+
+ return obj;
}
#region Helpers
@@ -488,7 +515,7 @@ namespace SabreTools.Serialization.Deserializers
///
/// Buffer for encryption and decryption
///
- private uint[] _stormBuffer = new uint[STORM_BUFFER_SIZE];
+ private readonly uint[] _stormBuffer = new uint[STORM_BUFFER_SIZE];
///
/// Prepare the encryption table
diff --git a/SabreTools.Serialization/Deserializers/N3DS.cs b/SabreTools.Serialization/Deserializers/N3DS.cs
index 6b597906..2451cbc3 100644
--- a/SabreTools.Serialization/Deserializers/N3DS.cs
+++ b/SabreTools.Serialization/Deserializers/N3DS.cs
@@ -25,7 +25,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the header
var header = ParseNCSDHeader(data);
- if (header == null)
+ if (header.MagicNumber != NCSDMagicNumber)
return null;
// Set the cart image header
@@ -35,25 +35,15 @@ namespace SabreTools.Serialization.Deserializers
#region Card Info Header
- // Try to parse the card info header
- var cardInfoHeader = ParseCardInfoHeader(data);
- if (cardInfoHeader == null)
- return null;
-
// Set the card info header
- cart.CardInfoHeader = cardInfoHeader;
+ cart.CardInfoHeader = ParseCardInfoHeader(data);
#endregion
#region Development Card Info Header
- // Try to parse the development card info header
- var developmentCardInfoHeader = data.ReadType();
- if (developmentCardInfoHeader == null)
- return null;
-
// Set the development card info header
- cart.DevelopmentCardInfoHeader = developmentCardInfoHeader;
+ cart.DevelopmentCardInfoHeader = ParseDevelopmentCardInfoHeader(data);
#endregion
@@ -92,11 +82,7 @@ namespace SabreTools.Serialization.Deserializers
// Handle the extended header, if it exists
if (partition.ExtendedHeaderSizeInBytes > 0)
- {
- var extendedHeader = data.ReadType();
- if (extendedHeader != null)
- cart.ExtendedHeaders[i] = extendedHeader;
- }
+ cart.ExtendedHeaders[i] = ParseNCCHExtendedHeader(data);
// Handle the ExeFS, if it exists
if (partition.ExeFSSizeInMediaUnits > 0)
@@ -117,10 +103,10 @@ namespace SabreTools.Serialization.Deserializers
long offset = partition.RomFSOffsetInMediaUnits * mediaUnitSize;
data.Seek(partitionOffset + offset, SeekOrigin.Begin);
- var romFsHeader = data.ReadType();
- if (romFsHeader?.MagicString != RomFSMagicNumber)
+ var romFsHeader = ParseRomFSHeader(data);
+ if (romFsHeader.MagicString != RomFSMagicNumber)
continue;
- if (romFsHeader?.MagicNumber != RomFSSecondMagicNumber)
+ if (romFsHeader.MagicNumber != RomFSSecondMagicNumber)
continue;
cart.RomFSHeaders[i] = romFsHeader;
@@ -139,85 +125,193 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into an NCSD header
+ /// Parse a Stream into a AccessControlInfo
///
/// Stream to parse
- /// Filled NCSD header on success, null on error
- public static NCSDHeader? ParseNCSDHeader(Stream data)
+ /// Filled AccessControlInfo on success, null on error
+ public static AccessControlInfo ParseAccessControlInfo(Stream data)
{
- var header = new NCSDHeader();
+ var obj = new AccessControlInfo();
- header.RSA2048Signature = data.ReadBytes(0x100);
- byte[] magicNumber = data.ReadBytes(4);
- header.MagicNumber = Encoding.ASCII.GetString(magicNumber).TrimEnd('\0'); ;
- if (header.MagicNumber != NCSDMagicNumber)
- return null;
+ obj.ARM11LocalSystemCapabilities = ParseARM11LocalSystemCapabilities(data);
+ obj.ARM11KernelCapabilities = ParseARM11KernelCapabilities(data);
+ obj.ARM9AccessControl = ParseARM9AccessControl(data);
- header.ImageSizeInMediaUnits = data.ReadUInt32();
- header.MediaId = data.ReadBytes(8);
- header.PartitionsFSType = (FilesystemType)data.ReadUInt64();
- header.PartitionsCryptType = data.ReadBytes(8);
-
- header.PartitionsTable = new PartitionTableEntry[8];
- for (int i = 0; i < 8; i++)
- {
- var partitionTableEntry = data.ReadType();
- if (partitionTableEntry == null)
- return null;
-
- header.PartitionsTable[i] = partitionTableEntry;
- }
-
- if (header.PartitionsFSType == FilesystemType.Normal || header.PartitionsFSType == FilesystemType.None)
- {
- header.ExheaderHash = data.ReadBytes(0x20);
- header.AdditionalHeaderSize = data.ReadUInt32();
- header.SectorZeroOffset = data.ReadUInt32();
- header.PartitionFlags = data.ReadBytes(8);
-
- header.PartitionIdTable = new ulong[8];
- for (int i = 0; i < 8; i++)
- {
- header.PartitionIdTable[i] = data.ReadUInt64();
- }
-
- header.Reserved1 = data.ReadBytes(0x20);
- header.Reserved2 = data.ReadBytes(0x0E);
- header.FirmUpdateByte1 = data.ReadByteValue();
- header.FirmUpdateByte2 = data.ReadByteValue();
- }
- else if (header.PartitionsFSType == FilesystemType.FIRM)
- {
- header.Unknown = data.ReadBytes(0x5E);
- header.EncryptedMBR = data.ReadBytes(0x42);
- }
-
- return header;
+ return obj;
}
///
- /// Parse a Stream into a card info header
+ /// Parse a Stream into a ARM9AccessControl
///
/// Stream to parse
- /// Filled card info header on success, null on error
- public static CardInfoHeader? ParseCardInfoHeader(Stream data)
+ /// Filled ARM9AccessControl on success, null on error
+ public static ARM9AccessControl ParseARM9AccessControl(Stream data)
{
- var header = new CardInfoHeader();
+ var obj = new ARM9AccessControl();
- header.WritableAddressMediaUnits = data.ReadUInt32();
- header.CardInfoBitmask = data.ReadUInt32();
- 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);
+ obj.Descriptors = new ARM9AccessControlDescriptors[15];
+ for (int i = 0; i < 15; i++)
+ {
+ obj.Descriptors[i] = (ARM9AccessControlDescriptors)data.ReadByteValue();
+ }
+ obj.DescriptorVersion = data.ReadByteValue();
- return header;
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ARM11KernelCapabilities
+ ///
+ /// Stream to parse
+ /// Filled ARM11KernelCapabilities on success, null on error
+ public static ARM11KernelCapabilities ParseARM11KernelCapabilities(Stream data)
+ {
+ var obj = new ARM11KernelCapabilities();
+
+ obj.Descriptors = new uint[28];
+ for (int i = 0; i < 28; i++)
+ {
+ obj.Descriptors[i] = data.ReadUInt32LittleEndian();
+ }
+ obj.Reserved = data.ReadBytes(0x10);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ARM11LocalSystemCapabilities
+ ///
+ /// Stream to parse
+ /// Filled ARM11LocalSystemCapabilities on success, null on error
+ public static ARM11LocalSystemCapabilities ParseARM11LocalSystemCapabilities(Stream data)
+ {
+ var obj = new ARM11LocalSystemCapabilities();
+
+ obj.ProgramID = data.ReadUInt64LittleEndian();
+ obj.CoreVersion = data.ReadUInt32LittleEndian();
+ obj.Flag1 = (ARM11LSCFlag1)data.ReadByteValue();
+ obj.Flag2 = (ARM11LSCFlag2)data.ReadByteValue();
+ obj.Flag0 = (ARM11LSCFlag0)data.ReadByteValue();
+ obj.Priority = data.ReadByteValue();
+ obj.ResourceLimitDescriptors = new ushort[16];
+ for (int i = 0; i < 16; i++)
+ {
+ obj.ResourceLimitDescriptors[i] = data.ReadUInt16LittleEndian();
+ }
+ obj.StorageInfo = ParseStorageInfo(data);
+ obj.ServiceAccessControl = new ulong[32];
+ for (int i = 0; i < 32; i++)
+ {
+ obj.ServiceAccessControl[i] = data.ReadUInt64LittleEndian();
+ }
+ obj.ExtendedServiceAccessControl = new ulong[2];
+ for (int i = 0; i < 2; i++)
+ {
+ obj.ExtendedServiceAccessControl[i] = data.ReadUInt64LittleEndian();
+ }
+ obj.Reserved = data.ReadBytes(0x0F);
+ obj.ResourceLimitCategory = (ResourceLimitCategory)data.ReadByteValue();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a CardInfoHeader
+ ///
+ /// Stream to parse
+ /// Filled CardInfoHeader on success, null on error
+ public static CardInfoHeader ParseCardInfoHeader(Stream data)
+ {
+ var obj = new CardInfoHeader();
+
+ obj.WritableAddressMediaUnits = data.ReadUInt32LittleEndian();
+ obj.CardInfoBitmask = data.ReadUInt32LittleEndian();
+ obj.Reserved1 = data.ReadBytes(0xF8);
+ obj.FilledSize = data.ReadUInt32LittleEndian();
+ obj.Reserved2 = data.ReadBytes(0x0C);
+ obj.TitleVersion = data.ReadUInt16LittleEndian();
+ obj.CardRevision = data.ReadUInt16LittleEndian();
+ obj.Reserved3 = data.ReadBytes(0x0C);
+ obj.CVerTitleID = data.ReadBytes(0x08);
+ obj.CVerVersionNumber = data.ReadUInt16LittleEndian();
+ obj.Reserved4 = data.ReadBytes(0xCD6);
+ obj.InitialData = ParseInitialData(data);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a CodeSetInfo
+ ///
+ /// Stream to parse
+ /// Filled CodeSetInfo on success, null on error
+ public static CodeSetInfo ParseCodeSetInfo(Stream data)
+ {
+ var obj = new CodeSetInfo();
+
+ obj.Address = data.ReadUInt32LittleEndian();
+ obj.PhysicalRegionSizeInPages = data.ReadUInt32LittleEndian();
+ obj.SizeInBytes = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DevelopmentCardInfoHeader
+ ///
+ /// Stream to parse
+ /// Filled DevelopmentCardInfoHeader on success, null on error
+ public static DevelopmentCardInfoHeader ParseDevelopmentCardInfoHeader(Stream data)
+ {
+ var obj = new DevelopmentCardInfoHeader();
+
+ obj.CardDeviceReserved1 = data.ReadBytes(0x200);
+ obj.TitleKey = data.ReadBytes(0x10);
+ obj.CardDeviceReserved2 = data.ReadBytes(0x1BF0);
+ obj.TestData = ParseTestData(data);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ExeFSFileHeader
+ ///
+ /// Stream to parse
+ /// Filled ExeFSFileHeader on success, null on error
+ public static ExeFSFileHeader ParseExeFSFileHeader(Stream data)
+ {
+ var obj = new ExeFSFileHeader();
+
+ byte[] fileName = data.ReadBytes(8);
+ obj.FileName = Encoding.ASCII.GetString(fileName).TrimEnd('\0');
+ obj.FileOffset = data.ReadUInt32LittleEndian();
+ obj.FileSize = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an ExeFSHeader
+ ///
+ /// Stream to parse
+ /// Filled ExeFSHeader on success, null on error
+ public static ExeFSHeader ParseExeFSHeader(Stream data)
+ {
+ var obj = new ExeFSHeader();
+
+ obj.FileHeaders = new ExeFSFileHeader[10];
+ for (int i = 0; i < 10; i++)
+ {
+ obj.FileHeaders[i] = ParseExeFSFileHeader(data);
+ }
+ obj.Reserved = data.ReadBytes(0x20);
+ obj.FileHashes = new byte[10][];
+ for (int i = 0; i < 10; i++)
+ {
+ obj.FileHashes[i] = data.ReadBytes(0x20);
+ }
+
+ return obj;
}
///
@@ -227,92 +321,285 @@ namespace SabreTools.Serialization.Deserializers
/// Filled initial data on success, null on error
public static InitialData? ParseInitialData(Stream data)
{
- var id = new InitialData();
+ var obj = new InitialData();
- id.CardSeedKeyY = data.ReadBytes(0x10);
- id.EncryptedCardSeed = data.ReadBytes(0x10);
- id.CardSeedAESMAC = data.ReadBytes(0x10);
- id.CardSeedNonce = data.ReadBytes(0x0C);
- id.Reserved = data.ReadBytes(0xC4);
- id.BackupHeader = ParseNCCHHeader(data, skipSignature: true);
+ obj.CardSeedKeyY = data.ReadBytes(0x10);
+ obj.EncryptedCardSeed = data.ReadBytes(0x10);
+ obj.CardSeedAESMAC = data.ReadBytes(0x10);
+ obj.CardSeedNonce = data.ReadBytes(0x0C);
+ obj.Reserved = data.ReadBytes(0xC4);
+ obj.BackupHeader = ParseNCCHHeader(data, skipSignature: true);
- return id;
+ return obj;
}
///
- /// Parse a Stream into an NCCH header
+ /// Parse a Stream into a NCCHExtendedHeader
+ ///
+ /// Stream to parse
+ /// Filled NCCHExtendedHeader on success, null on error
+ public static NCCHExtendedHeader ParseNCCHExtendedHeader(Stream data)
+ {
+ var obj = new NCCHExtendedHeader();
+
+ obj.SCI = ParseSystemControlInfo(data);
+ obj.ACI = ParseAccessControlInfo(data);
+ obj.AccessDescSignature = data.ReadBytes(0x100);
+ obj.NCCHHDRPublicKey = data.ReadBytes(0x100);
+ obj.ACIForLimitations = ParseAccessControlInfo(data);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an NCCHHeader
///
/// Stream to parse
/// Indicates if the signature should be skipped
- /// Filled NCCH header on success, null on error
+ /// Filled NCCHHeader on success, null on error
public static NCCHHeader ParseNCCHHeader(Stream data, bool skipSignature = false)
{
- var header = new NCCHHeader();
+ var obj = new NCCHHeader();
if (!skipSignature)
- header.RSA2048Signature = data.ReadBytes(0x100);
+ obj.RSA2048Signature = data.ReadBytes(0x100);
byte[] magicId = data.ReadBytes(4);
- header.MagicID = Encoding.ASCII.GetString(magicId).TrimEnd('\0');
- header.ContentSizeInMediaUnits = data.ReadUInt32();
- header.PartitionId = data.ReadUInt64();
- header.MakerCode = data.ReadUInt16();
- header.Version = data.ReadUInt16();
- header.VerificationHash = data.ReadUInt32();
- header.ProgramId = data.ReadBytes(8);
- header.Reserved1 = data.ReadBytes(0x10);
- header.LogoRegionHash = data.ReadBytes(0x20);
+ obj.MagicID = Encoding.ASCII.GetString(magicId).TrimEnd('\0');
+ obj.ContentSizeInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.PartitionId = data.ReadUInt64();
+ obj.MakerCode = data.ReadUInt16LittleEndian();
+ obj.Version = data.ReadUInt16LittleEndian();
+ obj.VerificationHash = data.ReadUInt32LittleEndian();
+ obj.ProgramId = data.ReadBytes(8);
+ obj.Reserved1 = data.ReadBytes(0x10);
+ obj.LogoRegionHash = data.ReadBytes(0x20);
byte[] productCode = data.ReadBytes(0x10);
- header.ProductCode = Encoding.ASCII.GetString(productCode).TrimEnd('\0');
- header.ExtendedHeaderHash = data.ReadBytes(0x20);
- header.ExtendedHeaderSizeInBytes = data.ReadUInt32();
- header.Reserved2 = data.ReadUInt32();
- header.Flags = data.ReadType();
- header.PlainRegionOffsetInMediaUnits = data.ReadUInt32();
- header.PlainRegionSizeInMediaUnits = data.ReadUInt32();
- header.LogoRegionOffsetInMediaUnits = data.ReadUInt32();
- header.LogoRegionSizeInMediaUnits = data.ReadUInt32();
- header.ExeFSOffsetInMediaUnits = data.ReadUInt32();
- header.ExeFSSizeInMediaUnits = data.ReadUInt32();
- header.ExeFSHashRegionSizeInMediaUnits = data.ReadUInt32();
- header.Reserved3 = data.ReadUInt32();
- header.RomFSOffsetInMediaUnits = data.ReadUInt32();
- header.RomFSSizeInMediaUnits = data.ReadUInt32();
- header.RomFSHashRegionSizeInMediaUnits = data.ReadUInt32();
- header.Reserved4 = data.ReadUInt32();
- header.ExeFSSuperblockHash = data.ReadBytes(0x20);
- header.RomFSSuperblockHash = data.ReadBytes(0x20);
+ obj.ProductCode = Encoding.ASCII.GetString(productCode).TrimEnd('\0');
+ obj.ExtendedHeaderHash = data.ReadBytes(0x20);
+ obj.ExtendedHeaderSizeInBytes = data.ReadUInt32LittleEndian();
+ obj.Reserved2 = data.ReadUInt32LittleEndian();
+ obj.Flags = ParseNCCHHeaderFlags(data);
+ obj.PlainRegionOffsetInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.PlainRegionSizeInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.LogoRegionOffsetInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.LogoRegionSizeInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.ExeFSOffsetInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.ExeFSSizeInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.ExeFSHashRegionSizeInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.Reserved3 = data.ReadUInt32LittleEndian();
+ obj.RomFSOffsetInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.RomFSSizeInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.RomFSHashRegionSizeInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.Reserved4 = data.ReadUInt32LittleEndian();
+ obj.ExeFSSuperblockHash = data.ReadBytes(0x20);
+ obj.RomFSSuperblockHash = data.ReadBytes(0x20);
- return header;
+ return obj;
}
///
- /// Parse a Stream into an ExeFS header
+ /// Parse a Stream into an NCCHHeaderFlags
///
/// Stream to parse
- /// Filled ExeFS header on success, null on error
- public static ExeFSHeader? ParseExeFSHeader(Stream data)
+ /// Filled NCCHHeaderFlags on success, null on error
+ public static NCCHHeaderFlags ParseNCCHHeaderFlags(Stream data)
{
- var exeFSHeader = new ExeFSHeader();
+ var obj = new NCCHHeaderFlags();
- exeFSHeader.FileHeaders = new ExeFSFileHeader[10];
- for (int i = 0; i < 10; i++)
- {
- var exeFsFileHeader = data.ReadType();
- if (exeFsFileHeader == null)
- return null;
+ obj.Reserved0 = data.ReadByteValue();
+ obj.Reserved1 = data.ReadByteValue();
+ obj.Reserved2 = data.ReadByteValue();
+ obj.CryptoMethod = (CryptoMethod)data.ReadByteValue();
+ obj.ContentPlatform = (ContentPlatform)data.ReadByteValue();
+ obj.MediaPlatformIndex = (ContentType)data.ReadByteValue();
+ obj.ContentUnitSize = data.ReadByteValue();
+ obj.BitMasks = (BitMasks)data.ReadByteValue();
- exeFsFileHeader.FileName = exeFsFileHeader.FileName?.TrimEnd('\0');
- exeFSHeader.FileHeaders[i] = exeFsFileHeader;
- }
- exeFSHeader.Reserved = data.ReadBytes(0x20);
- exeFSHeader.FileHashes = new byte[10][];
- for (int i = 0; i < 10; i++)
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an NCSDHeader
+ ///
+ /// Stream to parse
+ /// Filled NCSDHeader on success, null on error
+ public static NCSDHeader ParseNCSDHeader(Stream data)
+ {
+ var obj = new NCSDHeader();
+
+ obj.RSA2048Signature = data.ReadBytes(0x100);
+ byte[] magicNumber = data.ReadBytes(4);
+ obj.MagicNumber = Encoding.ASCII.GetString(magicNumber).TrimEnd('\0');
+ obj.ImageSizeInMediaUnits = data.ReadUInt32LittleEndian();
+ obj.MediaId = data.ReadBytes(8);
+ obj.PartitionsFSType = (FilesystemType)data.ReadUInt64();
+ obj.PartitionsCryptType = data.ReadBytes(8);
+
+ obj.PartitionsTable = new PartitionTableEntry[8];
+ for (int i = 0; i < 8; i++)
{
- exeFSHeader.FileHashes[i] = data.ReadBytes(0x20) ?? [];
+ obj.PartitionsTable[i] = ParsePartitionTableEntry(data);
}
- return exeFSHeader;
+ if (obj.PartitionsFSType == FilesystemType.Normal || obj.PartitionsFSType == FilesystemType.None)
+ {
+ obj.ExheaderHash = data.ReadBytes(0x20);
+ obj.AdditionalHeaderSize = data.ReadUInt32LittleEndian();
+ obj.SectorZeroOffset = data.ReadUInt32LittleEndian();
+ obj.PartitionFlags = data.ReadBytes(8);
+
+ obj.PartitionIdTable = new ulong[8];
+ for (int i = 0; i < 8; i++)
+ {
+ obj.PartitionIdTable[i] = data.ReadUInt64();
+ }
+
+ obj.Reserved1 = data.ReadBytes(0x20);
+ obj.Reserved2 = data.ReadBytes(0x0E);
+ obj.FirmUpdateByte1 = data.ReadByteValue();
+ obj.FirmUpdateByte2 = data.ReadByteValue();
+ }
+ else if (obj.PartitionsFSType == FilesystemType.FIRM)
+ {
+ obj.Unknown = data.ReadBytes(0x5E);
+ obj.EncryptedMBR = data.ReadBytes(0x42);
+ }
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an PartitionTableEntry
+ ///
+ /// Stream to parse
+ /// Filled PartitionTableEntry on success, null on error
+ public static PartitionTableEntry ParsePartitionTableEntry(Stream data)
+ {
+ var obj = new PartitionTableEntry();
+
+ obj.Offset = data.ReadUInt32LittleEndian();
+ obj.Length = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an RomFSHeader
+ ///
+ /// Stream to parse
+ /// Filled RomFSHeader on success, null on error
+ public static RomFSHeader ParseRomFSHeader(Stream data)
+ {
+ var obj = new RomFSHeader();
+
+ byte[] magicString = data.ReadBytes(4);
+ obj.MagicString = Encoding.ASCII.GetString(magicString);
+ obj.MagicNumber = data.ReadUInt32LittleEndian();
+ obj.MasterHashSize = data.ReadUInt32LittleEndian();
+ obj.Level1LogicalOffset = data.ReadUInt64LittleEndian();
+ obj.Level1HashdataSize = data.ReadUInt64LittleEndian();
+ obj.Level1BlockSizeLog2 = data.ReadUInt32LittleEndian();
+ obj.Reserved1 = data.ReadUInt32LittleEndian();
+ obj.Level2LogicalOffset = data.ReadUInt64LittleEndian();
+ obj.Level2HashdataSize = data.ReadUInt64LittleEndian();
+ obj.Level2BlockSizeLog2 = data.ReadUInt32LittleEndian();
+ obj.Reserved2 = data.ReadUInt32LittleEndian();
+ obj.Level3LogicalOffset = data.ReadUInt64LittleEndian();
+ obj.Level3HashdataSize = data.ReadUInt64LittleEndian();
+ obj.Level3BlockSizeLog2 = data.ReadUInt32LittleEndian();
+ obj.Reserved3 = data.ReadUInt32LittleEndian();
+ obj.Reserved4 = data.ReadUInt32LittleEndian();
+ obj.OptionalInfoSize = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an StorageInfo
+ ///
+ /// Stream to parse
+ /// Filled StorageInfo on success, null on error
+ public static StorageInfo ParseStorageInfo(Stream data)
+ {
+ var obj = new StorageInfo();
+
+ obj.ExtdataID = data.ReadUInt64LittleEndian();
+ obj.SystemSavedataIDs = data.ReadBytes(8);
+ obj.StorageAccessibleUniqueIDs = data.ReadBytes(8);
+ obj.FileSystemAccessInfo = data.ReadBytes(7);
+ obj.OtherAttributes = (StorageInfoOtherAttributes)data.ReadByteValue();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an SystemControlInfo
+ ///
+ /// Stream to parse
+ /// Filled SystemControlInfo on success, null on error
+ public static SystemControlInfo ParseSystemControlInfo(Stream data)
+ {
+ var obj = new SystemControlInfo();
+
+ byte[] applicationTitle = data.ReadBytes(8);
+ obj.ApplicationTitle = Encoding.ASCII.GetString(applicationTitle).TrimEnd('\0');
+ obj.Reserved1 = data.ReadBytes(5);
+ obj.Flag = data.ReadByteValue();
+ obj.RemasterVersion = data.ReadUInt16LittleEndian();
+ obj.TextCodeSetInfo = ParseCodeSetInfo(data);
+ obj.StackSize = data.ReadUInt32LittleEndian();
+ obj.ReadOnlyCodeSetInfo = ParseCodeSetInfo(data);
+ obj.Reserved2 = data.ReadUInt32LittleEndian();
+ obj.DataCodeSetInfo = ParseCodeSetInfo(data);
+ obj.BSSSize = data.ReadUInt32LittleEndian();
+ obj.DependencyModuleList = new ulong[48];
+ for (int i = 0; i < 48; i++)
+ {
+ obj.DependencyModuleList[i] = data.ReadUInt64LittleEndian();
+ }
+ obj.SystemInfo = ParseSystemInfo(data);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an SystemInfo
+ ///
+ /// Stream to parse
+ /// Filled SystemInfo on success, null on error
+ public static SystemInfo ParseSystemInfo(Stream data)
+ {
+ var obj = new SystemInfo();
+
+ obj.SaveDataSize = data.ReadUInt64LittleEndian();
+ obj.JumpID = data.ReadUInt64LittleEndian();
+ obj.Reserved = data.ReadBytes(0x30);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an TestData
+ ///
+ /// Stream to parse
+ /// Filled TestData on success, null on error
+ public static TestData ParseTestData(Stream data)
+ {
+ var obj = new TestData();
+
+ obj.Signature = data.ReadBytes(8);
+ obj.AscendingByteSequence = data.ReadBytes(0x1F8);
+ obj.DescendingByteSequence = data.ReadBytes(0x200);
+ obj.Filled00 = data.ReadBytes(0x200);
+ obj.FilledFF = data.ReadBytes(0x200);
+ obj.Filled0F = data.ReadBytes(0x200);
+ obj.FilledF0 = data.ReadBytes(0x200);
+ obj.Filled55 = data.ReadBytes(0x200);
+ obj.FilledAA = data.ReadBytes(0x1FF);
+ obj.FinalByte = data.ReadByteValue();
+
+ return obj;
}
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/NCF.cs b/SabreTools.Serialization/Deserializers/NCF.cs
index 28305254..6108c536 100644
--- a/SabreTools.Serialization/Deserializers/NCF.cs
+++ b/SabreTools.Serialization/Deserializers/NCF.cs
@@ -23,12 +23,12 @@ namespace SabreTools.Serialization.Deserializers
#region Header
// Try to parse the header
- var header = data.ReadType();
- if (header?.Dummy0 != 0x00000001)
+ var header = ParseHeader(data);
+ if (header.Dummy0 != 0x00000001)
return null;
- if (header?.MajorVersion != 0x00000002)
+ if (header.MajorVersion != 0x00000002)
return null;
- if (header?.MinorVersion != 1)
+ if (header.MinorVersion != 1)
return null;
// Set the no cache header
@@ -42,8 +42,8 @@ namespace SabreTools.Serialization.Deserializers
#region Directory Header
// Try to parse the directory header
- var directoryHeader = data.ReadType();
- if (directoryHeader?.Dummy0 != 0x00000004)
+ var directoryHeader = ParseDirectoryHeader(data);
+ if (directoryHeader.Dummy0 != 0x00000004)
return null;
// Set the game cache directory header
@@ -59,11 +59,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the directory entries
for (int i = 0; i < directoryHeader.ItemCount; i++)
{
- var directoryEntry = data.ReadType();
- if (directoryEntry == null)
- return null;
-
- file.DirectoryEntries[i] = directoryEntry;
+ file.DirectoryEntries[i] = ParseDirectoryEntry(data);
}
#endregion
@@ -107,11 +103,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the directory info 1 entries
for (int i = 0; i < directoryHeader.Info1Count; i++)
{
- var directoryInfo1Entry = data.ReadType();
- if (directoryInfo1Entry == null)
- return null;
-
- file.DirectoryInfo1Entries[i] = directoryInfo1Entry;
+ file.DirectoryInfo1Entries[i] = ParseDirectoryInfo1Entry(data);
}
#endregion
@@ -124,11 +116,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the directory info 2 entries
for (int i = 0; i < directoryHeader.ItemCount; i++)
{
- var directoryInfo2Entry = data.ReadType();
- if (directoryInfo2Entry == null)
- return null;
-
- file.DirectoryInfo2Entries[i] = directoryInfo2Entry;
+ file.DirectoryInfo2Entries[i] = ParseDirectoryInfo2Entry(data);
}
#endregion
@@ -141,11 +129,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the directory copy entries
for (int i = 0; i < directoryHeader.CopyCount; i++)
{
- var directoryCopyEntry = data.ReadType();
- if (directoryCopyEntry == null)
- return null;
-
- file.DirectoryCopyEntries[i] = directoryCopyEntry;
+ file.DirectoryCopyEntries[i] = ParseDirectoryCopyEntry(data);
}
#endregion
@@ -158,11 +142,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the directory local entries
for (int i = 0; i < directoryHeader.LocalCount; i++)
{
- var directoryLocalEntry = data.ReadType();
- if (directoryLocalEntry == null)
- return null;
-
- file.DirectoryLocalEntries[i] = directoryLocalEntry;
+ file.DirectoryLocalEntries[i] = ParseDirectoryLocalEntry(data);
}
#endregion
@@ -173,10 +153,10 @@ namespace SabreTools.Serialization.Deserializers
#region Unknown Header
// Try to parse the unknown header
- var unknownHeader = data.ReadType();
- if (unknownHeader?.Dummy0 != 0x00000001)
+ var unknownHeader = ParseUnknownHeader(data);
+ if (unknownHeader.Dummy0 != 0x00000001)
return null;
- if (unknownHeader?.Dummy1 != 0x00000000)
+ if (unknownHeader.Dummy1 != 0x00000000)
return null;
// Set the game cache unknown header
@@ -192,11 +172,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the unknown entries
for (int i = 0; i < directoryHeader.ItemCount; i++)
{
- var unknownEntry = data.ReadType();
- if (unknownEntry == null)
- return null;
-
- file.UnknownEntries[i] = unknownEntry;
+ file.UnknownEntries[i] = ParseUnknownEntry(data);
}
#endregion
@@ -204,8 +180,8 @@ namespace SabreTools.Serialization.Deserializers
#region Checksum Header
// Try to parse the checksum header
- var checksumHeader = data.ReadType();
- if (checksumHeader?.Dummy0 != 0x00000001)
+ var checksumHeader = ParseChecksumHeader(data);
+ if (checksumHeader.Dummy0 != 0x00000001)
return null;
// Set the game cache checksum header
@@ -219,10 +195,10 @@ namespace SabreTools.Serialization.Deserializers
#region Checksum Map Header
// Try to parse the checksum map header
- var checksumMapHeader = data.ReadType();
- if (checksumMapHeader?.Dummy0 != 0x14893721)
+ var checksumMapHeader = ParseChecksumMapHeader(data);
+ if (checksumMapHeader.Dummy0 != 0x14893721)
return null;
- if (checksumMapHeader?.Dummy1 != 0x00000001)
+ if (checksumMapHeader.Dummy1 != 0x00000001)
return null;
// Set the game cache checksum map header
@@ -238,11 +214,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the checksum map entries
for (int i = 0; i < checksumMapHeader.ItemCount; i++)
{
- var checksumMapEntry = data.ReadType();
- if (checksumMapEntry == null)
- return null;
-
- file.ChecksumMapEntries[i] = checksumMapEntry;
+ file.ChecksumMapEntries[i] = ParseChecksumMapEntry(data);
}
#endregion
@@ -255,11 +227,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the checksum entries
for (int i = 0; i < checksumMapHeader.ChecksumCount; i++)
{
- var checksumEntry = data.ReadType();
- if (checksumEntry == null)
- return null;
-
- file.ChecksumEntries[i] = checksumEntry;
+ file.ChecksumEntries[i] = ParseChecksumEntry(data);
}
#endregion
@@ -275,5 +243,222 @@ namespace SabreTools.Serialization.Deserializers
return null;
}
}
+
+ ///
+ /// Parse a Stream into a ChecksumEntry
+ ///
+ /// Stream to parse
+ /// Filled ChecksumEntry on success, null on error
+ public static ChecksumEntry ParseChecksumEntry(Stream data)
+ {
+ var obj = new ChecksumEntry();
+
+ obj.Checksum = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ChecksumHeader
+ ///
+ /// Stream to parse
+ /// Filled ChecksumHeader on success, null on error
+ public static ChecksumHeader ParseChecksumHeader(Stream data)
+ {
+ var obj = new ChecksumHeader();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.ChecksumSize = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ChecksumMapEntry
+ ///
+ /// Stream to parse
+ /// Filled ChecksumMapEntry on success, null on error
+ public static ChecksumMapEntry ParseChecksumMapEntry(Stream data)
+ {
+ var obj = new ChecksumMapEntry();
+
+ obj.ChecksumCount = data.ReadUInt32LittleEndian();
+ obj.FirstChecksumIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ChecksumMapHeader
+ ///
+ /// Stream to parse
+ /// Filled ChecksumMapHeader on success, null on error
+ public static ChecksumMapHeader ParseChecksumMapHeader(Stream data)
+ {
+ var obj = new ChecksumMapHeader();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+ obj.ItemCount = data.ReadUInt32LittleEndian();
+ obj.ChecksumCount = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryCopyEntry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryCopyEntry on success, null on error
+ public static DirectoryCopyEntry ParseDirectoryCopyEntry(Stream data)
+ {
+ var obj = new DirectoryCopyEntry();
+
+ obj.DirectoryIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryEntry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryEntry on success, null on error
+ public static DirectoryEntry ParseDirectoryEntry(Stream data)
+ {
+ var obj = new DirectoryEntry();
+
+ obj.NameOffset = data.ReadUInt32LittleEndian();
+ obj.ItemSize = data.ReadUInt32LittleEndian();
+ obj.ChecksumIndex = data.ReadUInt32LittleEndian();
+ obj.DirectoryFlags = (HL_NCF_FLAG)data.ReadUInt32LittleEndian();
+ obj.ParentIndex = data.ReadUInt32LittleEndian();
+ obj.NextIndex = data.ReadUInt32LittleEndian();
+ obj.FirstIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryHeader
+ ///
+ /// Stream to parse
+ /// Filled DirectoryHeader on success, null on error
+ public static DirectoryHeader ParseDirectoryHeader(Stream data)
+ {
+ var obj = new DirectoryHeader();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.CacheID = data.ReadUInt32LittleEndian();
+ obj.LastVersionPlayed = data.ReadUInt32LittleEndian();
+ obj.ItemCount = data.ReadUInt32LittleEndian();
+ obj.FileCount = data.ReadUInt32LittleEndian();
+ obj.ChecksumDataLength = data.ReadUInt32LittleEndian();
+ obj.DirectorySize = data.ReadUInt32LittleEndian();
+ obj.NameSize = data.ReadUInt32LittleEndian();
+ obj.Info1Count = data.ReadUInt32LittleEndian();
+ obj.CopyCount = data.ReadUInt32LittleEndian();
+ obj.LocalCount = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+ obj.Dummy2 = data.ReadUInt32LittleEndian();
+ obj.Checksum = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryInfo1Entry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryInfo1Entry on success, null on error
+ public static DirectoryInfo1Entry ParseDirectoryInfo1Entry(Stream data)
+ {
+ var obj = new DirectoryInfo1Entry();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryInfo2Entry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryInfo2Entry on success, null on error
+ public static DirectoryInfo2Entry ParseDirectoryInfo2Entry(Stream data)
+ {
+ var obj = new DirectoryInfo2Entry();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a DirectoryLocalEntry
+ ///
+ /// Stream to parse
+ /// Filled DirectoryLocalEntry on success, null on error
+ public static DirectoryLocalEntry ParseDirectoryLocalEntry(Stream data)
+ {
+ var obj = new DirectoryLocalEntry();
+
+ obj.DirectoryIndex = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a Header
+ ///
+ /// Stream to parse
+ /// Filled Header on success, null on error
+ public static Header ParseHeader(Stream data)
+ {
+ var obj = new Header();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.MajorVersion = data.ReadUInt32LittleEndian();
+ obj.MinorVersion = data.ReadUInt32LittleEndian();
+ obj.CacheID = data.ReadUInt32LittleEndian();
+ obj.LastVersionPlayed = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+ obj.Dummy2 = data.ReadUInt32LittleEndian();
+ obj.FileSize = data.ReadUInt32LittleEndian();
+ obj.BlockSize = data.ReadUInt32LittleEndian();
+ obj.BlockCount = data.ReadUInt32LittleEndian();
+ obj.Dummy3 = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a UnknownEntry
+ ///
+ /// Stream to parse
+ /// Filled UnknownEntry on success, null on error
+ public static UnknownEntry ParseUnknownEntry(Stream data)
+ {
+ var obj = new UnknownEntry();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a UnknownHeader
+ ///
+ /// Stream to parse
+ /// Filled UnknownHeader on success, null on error
+ public static UnknownHeader ParseUnknownHeader(Stream data)
+ {
+ var obj = new UnknownHeader();
+
+ obj.Dummy0 = data.ReadUInt32LittleEndian();
+ obj.Dummy1 = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/NewExecutable.cs b/SabreTools.Serialization/Deserializers/NewExecutable.cs
index 8ba5f8e9..8bdb25ba 100644
--- a/SabreTools.Serialization/Deserializers/NewExecutable.cs
+++ b/SabreTools.Serialization/Deserializers/NewExecutable.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
+using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.NewExecutable;
using static SabreTools.Models.NewExecutable.Constants;
@@ -39,8 +40,8 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the executable header
data.Seek(initialOffset + stub.Header.NewExeHeaderAddr, SeekOrigin.Begin);
- var header = data.ReadType();
- if (header?.Magic != SignatureString)
+ var header = ParseExecutableHeader(data);
+ if (header.Magic != SignatureString)
return null;
// Set the executable header
@@ -57,14 +58,15 @@ namespace SabreTools.Serialization.Deserializers
if (tableAddress >= data.Length)
return executable;
- // Try to parse the segment table
+ // Seek to the segment table
data.Seek(tableAddress, SeekOrigin.Begin);
- var segmentTable = ParseSegmentTable(data, header.FileSegmentCount);
- if (segmentTable == null)
- return null;
// Set the segment table
- executable.SegmentTable = segmentTable;
+ executable.SegmentTable = new SegmentTableEntry[header.FileSegmentCount];
+ for (int i = 0; i < header.FileSegmentCount; i++)
+ {
+ executable.SegmentTable[i] = ParseSegmentTableEntry(data);
+ }
#endregion
@@ -77,14 +79,11 @@ namespace SabreTools.Serialization.Deserializers
if (tableAddress >= data.Length)
return executable;
- // Try to parse the resource table
+ // Seek to the resource table
data.Seek(tableAddress, SeekOrigin.Begin);
- var resourceTable = ParseResourceTable(data, header.ResourceEntriesCount);
- if (resourceTable == null)
- return null;
// Set the resource table
- executable.ResourceTable = resourceTable;
+ executable.ResourceTable = ParseResourceTable(data, header.ResourceEntriesCount); ;
#endregion
@@ -100,14 +99,11 @@ namespace SabreTools.Serialization.Deserializers
if (tableAddress >= data.Length)
return executable;
- // Try to parse the resident-name table
+ // Seek to the resident-name table
data.Seek(tableAddress, SeekOrigin.Begin);
- var residentNameTable = ParseResidentNameTable(data, endOffset);
- if (residentNameTable == null)
- return null;
// Set the resident-name table
- executable.ResidentNameTable = residentNameTable;
+ executable.ResidentNameTable = ParseResidentNameTable(data, endOffset);
#endregion
@@ -120,14 +116,15 @@ namespace SabreTools.Serialization.Deserializers
if (tableAddress >= data.Length)
return executable;
- // Try to parse the module-reference table
+ // Seek to the module-reference table
data.Seek(tableAddress, SeekOrigin.Begin);
- var moduleReferenceTable = ParseModuleReferenceTable(data, header.ModuleReferenceTableSize);
- if (moduleReferenceTable == null)
- return null;
// Set the module-reference table
- executable.ModuleReferenceTable = moduleReferenceTable;
+ executable.ModuleReferenceTable = new ModuleReferenceTableEntry[header.ModuleReferenceTableSize];
+ for (int i = 0; i < header.ModuleReferenceTableSize; i++)
+ {
+ executable.ModuleReferenceTable[i] = ParseModuleReferenceTableEntry(data);
+ }
#endregion
@@ -143,14 +140,11 @@ namespace SabreTools.Serialization.Deserializers
if (tableAddress >= data.Length)
return executable;
- // Try to parse the imported-name table
+ // Seek to the imported-name table
data.Seek(tableAddress, SeekOrigin.Begin);
- var importedNameTable = ParseImportedNameTable(data, endOffset);
- if (importedNameTable == null)
- return null;
// Set the imported-name table
- executable.ImportedNameTable = importedNameTable;
+ executable.ImportedNameTable = ParseImportedNameTable(data, endOffset);
#endregion
@@ -167,14 +161,11 @@ namespace SabreTools.Serialization.Deserializers
if (tableAddress >= data.Length)
return executable;
- // Try to parse the imported-name table
+ // Seek to the imported-name table
data.Seek(tableAddress, SeekOrigin.Begin);
- var entryTable = ParseEntryTable(data, endOffset);
- if (entryTable == null)
- return null;
// Set the entry table
- executable.EntryTable = entryTable;
+ executable.EntryTable = ParseEntryTable(data, endOffset);
#endregion
@@ -189,14 +180,11 @@ namespace SabreTools.Serialization.Deserializers
if (tableAddress >= data.Length)
return executable;
- // Try to parse the nonresident-name table
+ // Seek to the nonresident-name table
data.Seek(tableAddress, SeekOrigin.Begin);
- var nonResidentNameTable = ParseNonResidentNameTable(data, endOffset);
- if (nonResidentNameTable == null)
- return null;
// Set the nonresident-name table
- executable.NonResidentNameTable = nonResidentNameTable;
+ executable.NonResidentNameTable = ParseNonResidentNameTable(data, endOffset);
#endregion
@@ -210,68 +198,229 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a segment table
+ /// Parse a Stream into an entry table
///
/// Stream to parse
- /// Number of segment table entries to read
- /// Filled segment table on success, null on error
- public static SegmentTableEntry[]? ParseSegmentTable(Stream data, int count)
+ /// First address not part of the entry table
+ /// Filled entry table on success, null on error
+ public static EntryTableBundle[] ParseEntryTable(Stream data, int endOffset)
{
- var segmentTable = new SegmentTableEntry[count];
+ var entryTable = new List();
- for (int i = 0; i < count; i++)
+ while (data.Position < endOffset && data.Position < data.Length)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
+ var entry = new EntryTableBundle();
+ entry.EntryCount = data.ReadByteValue();
+ entry.SegmentIndicator = data.ReadByteValue();
+ switch (entry.GetEntryType())
+ {
+ case SegmentEntryType.Unused:
+ break;
- segmentTable[i] = entry;
+ case SegmentEntryType.FixedSegment:
+ entry.FixedFlagWord = (FixedSegmentEntryFlag)data.ReadByteValue();
+ entry.FixedOffset = data.ReadUInt16LittleEndian();
+ break;
+
+ case SegmentEntryType.MoveableSegment:
+ entry.MoveableFlagWord = (MoveableSegmentEntryFlag)data.ReadByteValue();
+ entry.MoveableReserved = data.ReadUInt16LittleEndian();
+ entry.MoveableSegmentNumber = data.ReadByteValue();
+ entry.MoveableOffset = data.ReadUInt16LittleEndian();
+ break;
+ }
+ entryTable.Add(entry);
}
- return segmentTable;
+ return [.. entryTable];
}
///
- /// Parse a Stream into a resource table
+ /// Parse a Stream into an ExecutableHeader
+ ///
+ /// Stream to parse
+ /// Filled ExecutableHeader on success, null on error
+ public static ExecutableHeader ParseExecutableHeader(Stream data)
+ {
+ var obj = new ExecutableHeader();
+
+ byte[] magic = data.ReadBytes(2);
+ obj.Magic = Encoding.ASCII.GetString(magic);
+ obj.LinkerVersion = data.ReadByteValue();
+ obj.LinkerRevision = data.ReadByteValue();
+ obj.EntryTableOffset = data.ReadUInt16LittleEndian();
+ obj.EntryTableSize = data.ReadUInt16LittleEndian();
+ obj.CrcChecksum = data.ReadUInt32LittleEndian();
+ obj.FlagWord = (HeaderFlag)data.ReadUInt16LittleEndian();
+ obj.AutomaticDataSegmentNumber = data.ReadUInt16LittleEndian();
+ obj.InitialHeapAlloc = data.ReadUInt16LittleEndian();
+ obj.InitialStackAlloc = data.ReadUInt16LittleEndian();
+ obj.InitialCSIPSetting = data.ReadUInt32LittleEndian();
+ obj.InitialSSSPSetting = data.ReadUInt32LittleEndian();
+ obj.FileSegmentCount = data.ReadUInt16LittleEndian();
+ obj.ModuleReferenceTableSize = data.ReadUInt16LittleEndian();
+ obj.NonResidentNameTableSize = data.ReadUInt16LittleEndian();
+ obj.SegmentTableOffset = data.ReadUInt16LittleEndian();
+ obj.ResourceTableOffset = data.ReadUInt16LittleEndian();
+ obj.ResidentNameTableOffset = data.ReadUInt16LittleEndian();
+ obj.ModuleReferenceTableOffset = data.ReadUInt16LittleEndian();
+ obj.ImportedNamesTableOffset = data.ReadUInt16LittleEndian();
+ obj.NonResidentNamesTableOffset = data.ReadUInt32LittleEndian();
+ obj.MovableEntriesCount = data.ReadUInt16LittleEndian();
+ obj.SegmentAlignmentShiftCount = data.ReadUInt16LittleEndian();
+ obj.ResourceEntriesCount = data.ReadUInt16LittleEndian();
+ obj.TargetOperatingSystem = (Models.NewExecutable.OperatingSystem)data.ReadByteValue();
+ obj.AdditionalFlags = (OS2Flag)data.ReadByteValue();
+ obj.ReturnThunkOffset = data.ReadUInt16LittleEndian();
+ obj.SegmentReferenceThunkOffset = data.ReadUInt16LittleEndian();
+ obj.MinCodeSwapAreaSize = data.ReadUInt16LittleEndian();
+ obj.WindowsSDKRevision = data.ReadByteValue();
+ obj.WindowsSDKVersion = data.ReadByteValue();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an imported-name table
+ ///
+ /// Stream to parse
+ /// First address not part of the imported-name table
+ /// Filled imported-name table on success, null on error
+ public static Dictionary ParseImportedNameTable(Stream data, int endOffset)
+ {
+ var importedNameTable = new Dictionary();
+
+ while (data.Position < endOffset && data.Position < data.Length)
+ {
+ ushort currentOffset = (ushort)data.Position;
+ importedNameTable[currentOffset] = ParseImportedNameTableEntry(data);
+ }
+
+ return importedNameTable;
+ }
+
+ ///
+ /// Parse a Stream into an ImportedNameTableEntry
+ ///
+ /// Stream to parse
+ /// Filled ImportedNameTableEntry on success, null on error
+ public static ImportedNameTableEntry ParseImportedNameTableEntry(Stream data)
+ {
+ var obj = new ImportedNameTableEntry();
+
+ obj.Length = data.ReadByteValue();
+ obj.NameString = data.ReadBytes(obj.Length);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into an ModuleReferenceTableEntry
+ ///
+ /// Stream to parse
+ /// Filled ModuleReferenceTableEntry on success, null on error
+ public static ModuleReferenceTableEntry ParseModuleReferenceTableEntry(Stream data)
+ {
+ var obj = new ModuleReferenceTableEntry();
+
+ obj.Offset = data.ReadUInt16LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a nonresident-name table
+ ///
+ /// Stream to parse
+ /// First address not part of the nonresident-name table
+ /// Filled nonresident-name table on success, null on error
+ public static NonResidentNameTableEntry[] ParseNonResidentNameTable(Stream data, int endOffset)
+ {
+ var residentNameTable = new List();
+
+ while (data.Position < endOffset && data.Position < data.Length)
+ {
+ var entry = ParseNonResidentNameTableEntry(data);
+ residentNameTable.Add(entry);
+ }
+
+ return [.. residentNameTable];
+ }
+
+ ///
+ /// Parse a Stream into a NonResidentNameTableEntry
+ ///
+ /// Stream to parse
+ /// Filled NonResidentNameTableEntry on success, null on error
+ public static NonResidentNameTableEntry ParseNonResidentNameTableEntry(Stream data)
+ {
+ var obj = new NonResidentNameTableEntry();
+
+ obj.Length = data.ReadByteValue();
+ obj.NameString = data.ReadBytes(obj.Length);
+ obj.OrdinalNumber = data.ReadUInt16LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a resident-name table
+ ///
+ /// Stream to parse
+ /// First address not part of the resident-name table
+ /// Filled resident-name table on success, null on error
+ public static ResidentNameTableEntry[] ParseResidentNameTable(Stream data, int endOffset)
+ {
+ var residentNameTable = new List();
+
+ while (data.Position < endOffset && data.Position < data.Length)
+ {
+ var entry = ParseResidentNameTableEntry(data);
+ residentNameTable.Add(entry);
+ }
+
+ return [.. residentNameTable];
+ }
+
+ ///
+ /// Parse a Stream into a ResidentNameTableEntry
+ ///
+ /// Stream to parse
+ /// Filled ResidentNameTableEntry on success, null on error
+ public static ResidentNameTableEntry ParseResidentNameTableEntry(Stream data)
+ {
+ var obj = new ResidentNameTableEntry();
+
+ obj.Length = data.ReadByteValue();
+ obj.NameString = data.ReadBytes(obj.Length);
+ obj.OrdinalNumber = data.ReadUInt16LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ResourceTable
///
/// Stream to parse
/// Number of resource table entries to read
- /// Filled resource table on success, null on error
- public static ResourceTable? ParseResourceTable(Stream data, ushort count)
+ /// Filled ResourceTable on success, null on error
+ public static ResourceTable ParseResourceTable(Stream data, ushort count)
{
long initialOffset = data.Position;
var resourceTable = new ResourceTable();
- resourceTable.AlignmentShiftCount = data.ReadUInt16();
+ resourceTable.AlignmentShiftCount = data.ReadUInt16LittleEndian();
var resourceTypes = new List();
for (int i = 0; i < count; i++)
{
- var entry = new ResourceTypeInformationEntry();
-
- entry.TypeID = data.ReadUInt16();
- entry.ResourceCount = data.ReadUInt16();
- entry.Reserved = data.ReadUInt32();
+ var entry = ParseResourceTypeInformationEntry(data);
+ resourceTypes.Add(entry);
// A zero type ID marks the end of the resource type information blocks.
if (entry.TypeID == 0)
- {
- resourceTypes.Add(entry);
break;
- }
-
- entry.Resources = new ResourceTypeResourceEntry[entry.ResourceCount];
- for (int j = 0; j < entry.ResourceCount; j++)
- {
- // TODO: Should we read and store the resource data?
- var resource = data.ReadType();
- if (resource == null)
- return null;
-
- entry.Resources[j] = resource;
- }
- resourceTypes.Add(entry);
}
resourceTable.ResourceTypes = [.. resourceTypes];
@@ -314,9 +463,6 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(stringOffset, SeekOrigin.Begin);
var str = ParseResourceTypeAndNameString(data);
- if (str == null)
- return null;
-
resourceTable.TypeAndNameStrings[stringOffsets[i]] = str;
}
@@ -324,192 +470,80 @@ namespace SabreTools.Serialization.Deserializers
}
///
- /// Parse a Stream into a resource type and name string
+ /// Parse a Stream into an ResourceTypeInformationEntry
///
/// Stream to parse
- /// Filled resource type and name string on success, null on error
- public static ResourceTypeAndNameString? ParseResourceTypeAndNameString(Stream data)
+ /// Filled ResourceTypeInformationEntry on success, null on error
+ public static ResourceTypeInformationEntry ParseResourceTypeInformationEntry(Stream data)
{
- var str = new ResourceTypeAndNameString();
+ var obj = new ResourceTypeInformationEntry();
- str.Length = data.ReadByteValue();
- str.Text = data.ReadBytes(str.Length);
+ obj.TypeID = data.ReadUInt16LittleEndian();
+ obj.ResourceCount = data.ReadUInt16LittleEndian();
+ obj.Reserved = data.ReadUInt32LittleEndian();
- return str;
- }
+ // A zero type ID marks the end of the resource type information blocks.
+ if (obj.TypeID == 0)
+ return obj;
- ///
- /// Parse a Stream into a resident-name table
- ///
- /// Stream to parse
- /// First address not part of the resident-name table
- /// Filled resident-name table on success, null on error
- public static ResidentNameTableEntry[]? ParseResidentNameTable(Stream data, int endOffset)
- {
- var residentNameTable = new List();
-
- while (data.Position < endOffset && data.Position < data.Length)
+ obj.Resources = new ResourceTypeResourceEntry[obj.ResourceCount];
+ for (int i = 0; i < obj.ResourceCount; i++)
{
- var entry = ParseResidentNameTableEntry(data);
- if (entry == null)
- return null;
-
- residentNameTable.Add(entry);
+ // TODO: Should we read and store the resource data?
+ obj.Resources[i] = ParseResourceTypeResourceEntry(data);
}
- return [.. residentNameTable];
+ return obj;
}
///
- /// Parse a Stream into a resident-name table entry
+ /// Parse a Stream into a ResourceTypeAndNameString
///
/// Stream to parse
- /// Filled resident-name table entry on success, null on error
- public static ResidentNameTableEntry? ParseResidentNameTableEntry(Stream data)
+ /// Filled rResourceTypeAndNameString on success, null on error
+ public static ResourceTypeAndNameString ParseResourceTypeAndNameString(Stream data)
{
- var entry = new ResidentNameTableEntry();
+ var obj = new ResourceTypeAndNameString();
- entry.Length = data.ReadByteValue();
- entry.NameString = data.ReadBytes(entry.Length);
- entry.OrdinalNumber = data.ReadUInt16();
+ obj.Length = data.ReadByteValue();
+ obj.Text = data.ReadBytes(obj.Length);
- return entry;
+ return obj;
}
///
- /// Parse a Stream into a module-reference table
+ /// Parse a Stream into an ResourceTypeResourceEntry
///
/// Stream to parse
- /// Number of module-reference table entries to read
- /// Filled module-reference table on success, null on error
- public static ModuleReferenceTableEntry[]? ParseModuleReferenceTable(Stream data, int count)
+ /// Filled ResourceTypeResourceEntry on success, null on error
+ public static ResourceTypeResourceEntry ParseResourceTypeResourceEntry(Stream data)
{
- var moduleReferenceTable = new ModuleReferenceTableEntry[count];
+ var obj = new ResourceTypeResourceEntry();
- for (int i = 0; i < count; i++)
- {
- var entry = data.ReadType();
- if (entry == null)
- return null;
+ obj.Offset = data.ReadUInt16LittleEndian();
+ obj.Length = data.ReadUInt16LittleEndian();
+ obj.FlagWord = (ResourceTypeResourceFlag)data.ReadUInt16LittleEndian();
+ obj.ResourceID = data.ReadUInt16LittleEndian();
+ obj.Reserved = data.ReadUInt32LittleEndian();
- moduleReferenceTable[i] = entry;
- }
-
- return moduleReferenceTable;
+ return obj;
}
///
- /// Parse a Stream into an imported-name table
+ /// Parse a Stream into an SegmentTableEntry
///
/// Stream to parse
- /// First address not part of the imported-name table
- /// Filled imported-name table on success, null on error
- public static Dictionary? ParseImportedNameTable(Stream data, int endOffset)
+ /// Filled SegmentTableEntry on success, null on error
+ public static SegmentTableEntry ParseSegmentTableEntry(Stream data)
{
- var importedNameTable = new Dictionary();
+ var obj = new SegmentTableEntry();
- while (data.Position < endOffset && data.Position < data.Length)
- {
- ushort currentOffset = (ushort)data.Position;
- var entry = ParseImportedNameTableEntry(data);
- if (entry == null)
- return null;
+ obj.Offset = data.ReadUInt16LittleEndian();
+ obj.Length = data.ReadUInt16LittleEndian();
+ obj.FlagWord = (SegmentTableEntryFlag)data.ReadUInt16LittleEndian();
+ obj.MinimumAllocationSize = data.ReadUInt16LittleEndian();
- importedNameTable[currentOffset] = entry;
- }
-
- return importedNameTable;
- }
-
- ///
- /// Parse a Stream into an imported-name table entry
- ///
- /// Stream to parse
- /// Filled imported-name table entry on success, null on error
- public static ImportedNameTableEntry? ParseImportedNameTableEntry(Stream data)
- {
- var entry = new ImportedNameTableEntry();
-
- entry.Length = data.ReadByteValue();
- entry.NameString = data.ReadBytes(entry.Length);
-
- return entry;
- }
-
- ///
- /// Parse a Stream into an entry table
- ///
- /// Stream to parse
- /// First address not part of the entry table
- /// Filled entry table on success, null on error
- public static EntryTableBundle[] ParseEntryTable(Stream data, int endOffset)
- {
- var entryTable = new List();
-
- while (data.Position < endOffset && data.Position < data.Length)
- {
- var entry = new EntryTableBundle();
- entry.EntryCount = data.ReadByteValue();
- entry.SegmentIndicator = data.ReadByteValue();
- switch (entry.GetEntryType())
- {
- case SegmentEntryType.Unused:
- break;
-
- case SegmentEntryType.FixedSegment:
- entry.FixedFlagWord = (FixedSegmentEntryFlag)data.ReadByteValue();
- entry.FixedOffset = data.ReadUInt16();
- break;
-
- case SegmentEntryType.MoveableSegment:
- entry.MoveableFlagWord = (MoveableSegmentEntryFlag)data.ReadByteValue();
- entry.MoveableReserved = data.ReadUInt16();
- entry.MoveableSegmentNumber = data.ReadByteValue();
- entry.MoveableOffset = data.ReadUInt16();
- break;
- }
- entryTable.Add(entry);
- }
-
- return [.. entryTable];
- }
-
- ///
- /// Parse a Stream into a nonresident-name table
- ///
- /// Stream to parse
- /// First address not part of the nonresident-name table
- /// Filled nonresident-name table on success, null on error
- public static NonResidentNameTableEntry[]? ParseNonResidentNameTable(Stream data, int endOffset)
- {
- var residentNameTable = new List();
-
- while (data.Position < endOffset && data.Position < data.Length)
- {
- var entry = ParseNonResidentNameTableEntry(data);
- if (entry == null)
- return null;
-
- residentNameTable.Add(entry);
- }
-
- return [.. residentNameTable];
- }
-
- ///
- /// Parse a Stream into a nonresident-name table entry
- ///
- /// Stream to parse
- /// Filled nonresident-name table entry on success, null on error
- public static NonResidentNameTableEntry? ParseNonResidentNameTableEntry(Stream data)
- {
- var entry = new NonResidentNameTableEntry();
-
- entry.Length = data.ReadByteValue();
- entry.NameString = data.ReadBytes(entry.Length);
- entry.OrdinalNumber = data.ReadUInt16();
-
- return entry;
+ return obj;
}
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/Nitro.cs b/SabreTools.Serialization/Deserializers/Nitro.cs
index 3ba47fb4..7407e963 100644
--- a/SabreTools.Serialization/Deserializers/Nitro.cs
+++ b/SabreTools.Serialization/Deserializers/Nitro.cs
@@ -22,27 +22,16 @@ namespace SabreTools.Serialization.Deserializers
#region Header
- // Try to parse the header
- var header = data.ReadType();
- if (header == null)
- return null;
-
// Set the cart image header
- cart.CommonHeader = header;
+ cart.CommonHeader = ParseCommonHeader(data);
#endregion
#region Extended DSi Header
// If we have a DSi-compatible cartridge
- if (header.UnitCode == Unitcode.NDSPlusDSi || header.UnitCode == Unitcode.DSi)
- {
- var extendedDSiHeader = data.ReadType();
- if (extendedDSiHeader == null)
- return null;
-
- cart.ExtendedDSiHeader = extendedDSiHeader;
- }
+ if (cart.CommonHeader.UnitCode == Unitcode.NDSPlusDSi || cart.CommonHeader.UnitCode == Unitcode.DSi)
+ cart.ExtendedDSiHeader = ParseExtendedDSiHeader(data);
#endregion
@@ -64,27 +53,22 @@ namespace SabreTools.Serialization.Deserializers
#region Name Table
// Try to get the name table offset
- long nameTableOffset = header.FileNameTableOffset;
+ long nameTableOffset = cart.CommonHeader.FileNameTableOffset;
if (nameTableOffset < 0 || nameTableOffset > data.Length)
return null;
// Seek to the name table
data.Seek(nameTableOffset, SeekOrigin.Begin);
- // Try to parse the name table
- var nameTable = ParseNameTable(data);
- if (nameTable == null)
- return null;
-
// Set the name table
- cart.NameTable = nameTable;
+ cart.NameTable = ParseNameTable(data);
#endregion
#region File Allocation Table
// Try to get the file allocation table offset
- long fileAllocationTableOffset = header.FileAllocationTableOffset;
+ long fileAllocationTableOffset = cart.CommonHeader.FileAllocationTableOffset;
if (fileAllocationTableOffset < 0 || fileAllocationTableOffset > data.Length)
return null;
@@ -95,12 +79,9 @@ namespace SabreTools.Serialization.Deserializers
var fileAllocationTable = new List();
// Try to parse the file allocation table
- while (data.Position - fileAllocationTableOffset < header.FileAllocationTableLength)
+ while (data.Position - fileAllocationTableOffset < cart.CommonHeader.FileAllocationTableLength)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
-
+ var entry = ParseFileAllocationTableEntry(data);
fileAllocationTable.Add(entry);
}
@@ -121,12 +102,203 @@ namespace SabreTools.Serialization.Deserializers
}
}
+ ///
+ /// Parse a Stream into a CommonHeader
+ ///
+ /// Stream to parse
+ /// Filled CommonHeader on success, null on error
+ public static CommonHeader ParseCommonHeader(Stream data)
+ {
+ var obj = new CommonHeader();
+
+ byte[] gameTitle = data.ReadBytes(12);
+ obj.GameTitle = Encoding.ASCII.GetString(gameTitle).TrimEnd('\0');
+ obj.GameCode = data.ReadUInt32LittleEndian();
+ byte[] makerCode = data.ReadBytes(2);
+ obj.MakerCode = Encoding.ASCII.GetString(makerCode);
+ obj.UnitCode = (Unitcode)data.ReadByteValue();
+ obj.EncryptionSeedSelect = data.ReadByteValue();
+ obj.DeviceCapacity = data.ReadByteValue();
+ obj.Reserved1 = data.ReadBytes(7);
+ obj.GameRevision = data.ReadUInt16LittleEndian();
+ obj.RomVersion = data.ReadByteValue();
+ obj.InternalFlags = data.ReadByteValue();
+ obj.ARM9RomOffset = data.ReadUInt32LittleEndian();
+ obj.ARM9EntryAddress = data.ReadUInt32LittleEndian();
+ obj.ARM9LoadAddress = data.ReadUInt32LittleEndian();
+ obj.ARM9Size = data.ReadUInt32LittleEndian();
+ obj.ARM7RomOffset = data.ReadUInt32LittleEndian();
+ obj.ARM7EntryAddress = data.ReadUInt32LittleEndian();
+ obj.ARM7LoadAddress = data.ReadUInt32LittleEndian();
+ obj.ARM7Size = data.ReadUInt32LittleEndian();
+ obj.FileNameTableOffset = data.ReadUInt32LittleEndian();
+ obj.FileNameTableLength = data.ReadUInt32LittleEndian();
+ obj.FileAllocationTableOffset = data.ReadUInt32LittleEndian();
+ obj.FileAllocationTableLength = data.ReadUInt32LittleEndian();
+ obj.ARM9OverlayOffset = data.ReadUInt32LittleEndian();
+ obj.ARM9OverlayLength = data.ReadUInt32LittleEndian();
+ obj.ARM7OverlayOffset = data.ReadUInt32LittleEndian();
+ obj.ARM7OverlayLength = data.ReadUInt32LittleEndian();
+ obj.NormalCardControlRegisterSettings = data.ReadUInt32LittleEndian();
+ obj.SecureCardControlRegisterSettings = data.ReadUInt32LittleEndian();
+ obj.IconBannerOffset = data.ReadUInt32LittleEndian();
+ obj.SecureAreaCRC = data.ReadUInt16LittleEndian();
+ obj.SecureTransferTimeout = data.ReadUInt16LittleEndian();
+ obj.ARM9Autoload = data.ReadUInt32LittleEndian();
+ obj.ARM7Autoload = data.ReadUInt32LittleEndian();
+ obj.SecureDisable = data.ReadBytes(8);
+ obj.NTRRegionRomSize = data.ReadUInt32LittleEndian();
+ obj.HeaderSize = data.ReadUInt32LittleEndian();
+ obj.Reserved2 = data.ReadBytes(56);
+ obj.NintendoLogo = data.ReadBytes(156);
+ obj.NintendoLogoCRC = data.ReadUInt16LittleEndian();
+ obj.HeaderCRC = data.ReadUInt16LittleEndian();
+ obj.DebuggerReserved = data.ReadBytes(0x20);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a ExtendedDSiHeader
+ ///
+ /// Stream to parse
+ /// Filled ExtendedDSiHeader on success, null on error
+ public static ExtendedDSiHeader ParseExtendedDSiHeader(Stream data)
+ {
+ var obj = new ExtendedDSiHeader();
+
+ obj.GlobalMBK15Settings = new uint[5];
+ for (int i = 0; i < 5; i++)
+ {
+ obj.GlobalMBK15Settings[i] = data.ReadUInt32LittleEndian();
+ }
+ obj.LocalMBK68SettingsARM9 = new uint[3];
+ for (int i = 0; i < 3; i++)
+ {
+ obj.LocalMBK68SettingsARM9[i] = data.ReadUInt32LittleEndian();
+ }
+ obj.LocalMBK68SettingsARM7 = new uint[3];
+ for (int i = 0; i < 3; i++)
+ {
+ obj.LocalMBK68SettingsARM7[i] = data.ReadUInt32LittleEndian();
+ }
+ obj.GlobalMBK9Setting = data.ReadUInt32LittleEndian();
+ obj.RegionFlags = data.ReadUInt32LittleEndian();
+ obj.AccessControl = data.ReadUInt32LittleEndian();
+ obj.ARM7SCFGEXTMask = data.ReadUInt32LittleEndian();
+ obj.ReservedFlags = data.ReadUInt32LittleEndian();
+ obj.ARM9iRomOffset = data.ReadUInt32LittleEndian();
+ obj.Reserved3 = data.ReadUInt32LittleEndian();
+ obj.ARM9iLoadAddress = data.ReadUInt32LittleEndian();
+ obj.ARM9iSize = data.ReadUInt32LittleEndian();
+ obj.ARM7iRomOffset = data.ReadUInt32LittleEndian();
+ obj.Reserved4 = data.ReadUInt32LittleEndian();
+ obj.ARM7iLoadAddress = data.ReadUInt32LittleEndian();
+ obj.ARM7iSize = data.ReadUInt32LittleEndian();
+ obj.DigestNTRRegionOffset = data.ReadUInt32LittleEndian();
+ obj.DigestNTRRegionLength = data.ReadUInt32LittleEndian();
+ obj.DigestTWLRegionOffset = data.ReadUInt32LittleEndian();
+ obj.DigestTWLRegionLength = data.ReadUInt32LittleEndian();
+ obj.DigestSectorHashtableRegionOffset = data.ReadUInt32LittleEndian();
+ obj.DigestSectorHashtableRegionLength = data.ReadUInt32LittleEndian();
+ obj.DigestBlockHashtableRegionOffset = data.ReadUInt32LittleEndian();
+ obj.DigestBlockHashtableRegionLength = data.ReadUInt32LittleEndian();
+ obj.DigestSectorSize = data.ReadUInt32LittleEndian();
+ obj.DigestBlockSectorCount = data.ReadUInt32LittleEndian();
+ obj.IconBannerSize = data.ReadUInt32LittleEndian();
+ obj.Unknown1 = data.ReadUInt32LittleEndian();
+ obj.NTRTWLRegionRomSize = data.ReadUInt32LittleEndian();
+ obj.Unknown2 = data.ReadBytes(12);
+ obj.ModcryptArea1Offset = data.ReadUInt32LittleEndian();
+ obj.ModcryptArea1Size = data.ReadUInt32LittleEndian();
+ obj.ModcryptArea2Offset = data.ReadUInt32LittleEndian();
+ obj.ModcryptArea2Size = data.ReadUInt32LittleEndian();
+ obj.TitleID = data.ReadBytes(8);
+ obj.DSiWarePublicSavSize = data.ReadUInt32LittleEndian();
+ obj.DSiWarePrivateSavSize = data.ReadUInt32LittleEndian();
+ obj.ReservedZero = data.ReadBytes(176);
+ obj.Unknown3 = data.ReadBytes(16);
+ obj.ARM9WithSecureAreaSHA1HMACHash = data.ReadBytes(20);
+ obj.ARM7SHA1HMACHash = data.ReadBytes(20);
+ obj.DigestMasterSHA1HMACHash = data.ReadBytes(20);
+ obj.BannerSHA1HMACHash = data.ReadBytes(20);
+ obj.ARM9iDecryptedSHA1HMACHash = data.ReadBytes(20);
+ obj.ARM7iDecryptedSHA1HMACHash = data.ReadBytes(20);
+ obj.Reserved5 = data.ReadBytes(40);
+ obj.ARM9NoSecureAreaSHA1HMACHash = data.ReadBytes(20);
+ obj.Reserved6 = data.ReadBytes(2636);
+ obj.ReservedAndUnchecked = data.ReadBytes(0x180);
+ obj.RSASignature = data.ReadBytes(0x80);
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a FileAllocationTableEntry
+ ///
+ /// Stream to parse
+ /// Filled FileAllocationTableEntry on success, null on error
+ public static FileAllocationTableEntry ParseFileAllocationTableEntry(Stream data)
+ {
+ var obj = new FileAllocationTableEntry();
+
+ obj.StartOffset = data.ReadUInt32LittleEndian();
+ obj.EndOffset = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a FolderAllocationTableEntry
+ ///
+ /// Stream to parse
+ /// Filled FolderAllocationTableEntry on success, null on error
+ public static FolderAllocationTableEntry ParseFolderAllocationTableEntry(Stream data)
+ {
+ var obj = new FolderAllocationTableEntry();
+
+ obj.StartOffset = data.ReadUInt32LittleEndian();
+ obj.FirstFileIndex = data.ReadUInt16LittleEndian();
+ obj.ParentFolderIndex = data.ReadByteValue();
+ obj.Unknown = data.ReadByteValue();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a NameListEntry
+ ///
+ /// Stream to parse
+ /// Filled NameListEntry on success, null on error
+ public static NameListEntry? ParseNameListEntry(Stream data)
+ {
+ var entry = new NameListEntry();
+
+ byte flagAndSize = data.ReadByteValue();
+ if (flagAndSize == 0xFF)
+ return null;
+
+ entry.Folder = (flagAndSize & 0x80) != 0;
+
+ byte size = (byte)(flagAndSize & ~0x80);
+ if (size > 0)
+ {
+ byte[] name = data.ReadBytes(size);
+ entry.Name = Encoding.UTF8.GetString(name);
+ }
+
+ if (entry.Folder)
+ entry.Index = data.ReadUInt16();
+
+ return entry;
+ }
+
///
/// Parse a Stream into a name table
///
/// Stream to parse
/// Filled name table on success, null on error
- private static NameTable? ParseNameTable(Stream data)
+ public static NameTable ParseNameTable(Stream data)
{
var nameTable = new NameTable();
@@ -135,10 +307,7 @@ namespace SabreTools.Serialization.Deserializers
int entryCount = int.MaxValue;
while (entryCount > 0)
{
- var entry = data.ReadType();
- if (entry == null)
- return null;
-
+ var entry = ParseFolderAllocationTableEntry(data);
folderAllocationTable.Add(entry);
// If we have the root entry
@@ -168,33 +337,5 @@ namespace SabreTools.Serialization.Deserializers
return nameTable;
}
-
- ///
- /// Parse a Stream into a name list entry
- ///
- /// Stream to parse
- /// Filled name list entry on success, null on error
- private static NameListEntry? ParseNameListEntry(Stream data)
- {
- var entry = new NameListEntry();
-
- byte flagAndSize = data.ReadByteValue();
- if (flagAndSize == 0xFF)
- return null;
-
- entry.Folder = (flagAndSize & 0x80) != 0;
-
- byte size = (byte)(flagAndSize & ~0x80);
- if (size > 0)
- {
- byte[] name = data.ReadBytes(size);
- entry.Name = Encoding.UTF8.GetString(name);
- }
-
- if (entry.Folder)
- entry.Index = data.ReadUInt16();
-
- return entry;
- }
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/PAK.cs b/SabreTools.Serialization/Deserializers/PAK.cs
index ea08e236..eb1aebea 100644
--- a/SabreTools.Serialization/Deserializers/PAK.cs
+++ b/SabreTools.Serialization/Deserializers/PAK.cs
@@ -1,4 +1,5 @@
using System.IO;
+using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.PAK;
using static SabreTools.Models.PAK.Constants;
@@ -22,8 +23,8 @@ namespace SabreTools.Serialization.Deserializers
#region Header
// Try to parse the header
- var header = data.ReadType();
- if (header?.Signature != SignatureString)
+ var header = ParseHeader(data);
+ if (header.Signature != SignatureString)
return null;
// Set the package header
@@ -47,11 +48,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the directory items
for (int i = 0; i < file.DirectoryItems.Length; i++)
{
- var directoryItem = data.ReadType();
- if (directoryItem == null)
- return null;
-
- file.DirectoryItems[i] = directoryItem;
+ file.DirectoryItems[i] = ParseDirectoryItem(data);
}
#endregion
@@ -64,5 +61,39 @@ namespace SabreTools.Serialization.Deserializers
return null;
}
}
+
+ ///
+ /// Parse a Stream into a DirectoryItem
+ ///
+ /// Stream to parse
+ /// Filled DirectoryItem on success, null on error
+ public static DirectoryItem ParseDirectoryItem(Stream data)
+ {
+ var obj = new DirectoryItem();
+
+ byte[] itemName = data.ReadBytes(56);
+ obj.ItemName = Encoding.ASCII.GetString(itemName).TrimEnd('\0');
+ obj.ItemOffset = data.ReadUInt32LittleEndian();
+ obj.ItemLength = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
+
+ ///
+ /// Parse a Stream into a Header
+ ///
+ /// Stream to parse
+ /// Filled Header on success, null on error
+ public static Header ParseHeader(Stream data)
+ {
+ var obj = new Header();
+
+ byte[] signature = data.ReadBytes(4);
+ obj.Signature = Encoding.ASCII.GetString(signature);
+ obj.DirectoryOffset = data.ReadUInt32LittleEndian();
+ obj.DirectoryLength = data.ReadUInt32LittleEndian();
+
+ return obj;
+ }
}
}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Deserializers/PFF.cs b/SabreTools.Serialization/Deserializers/PFF.cs
index 835bebb8..9ed490b4 100644
--- a/SabreTools.Serialization/Deserializers/PFF.cs
+++ b/SabreTools.Serialization/Deserializers/PFF.cs
@@ -24,8 +24,33 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the header
var header = ParseHeader(data);
- if (header == null)
+ if (header.Signature == Version0SignatureString)
+ {
+ if (header.FileSegmentSize != Version0HSegmentSize)
+ return null;
+ }
+ else if (header.Signature == Version2SignatureString)
+ {
+ if (header.FileSegmentSize != Version2SegmentSize)
+ return null;
+ }
+ else if (header.Signature == Version3SignatureString)
+ {
+ if (header.FileSegmentSize != Version2SegmentSize
+ && header.FileSegmentSize != Version3SegmentSize)
+ {
+ return null;
+ }
+ }
+ else if (header.Signature == Version4SignatureString)
+ {
+ if (header.FileSegmentSize != Version4SegmentSize)
+ return null;
+ }
+ else
+ {
return null;
+ }
// Set the archive header
archive.Header = header;
@@ -48,11 +73,7 @@ namespace SabreTools.Serialization.Deserializers
// Read all segments in turn
for (int i = 0; i < header.NumberOfFiles; i++)
{
- var file = ParseSegment(data, header.FileSegmentSize);
- if (file == null)
- continue;
-
- archive.Segments[i] = file;
+ archive.Segments[i] = ParseSegment(data, header.FileSegmentSize); ;
}
#endregion
@@ -67,13 +88,8 @@ namespace SabreTools.Serialization.Deserializers
// Seek to the footer
data.Seek(offset, SeekOrigin.Begin);
- // Try to parse the footer
- var footer = data.ReadType