Add and fix some deserializers

This commit is contained in:
Matt Nadareski
2024-04-23 21:00:10 -04:00
parent 3fa8848e77
commit 52f0846d5d
25 changed files with 618 additions and 950 deletions

View File

@@ -70,20 +70,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled header on success, null on error</returns>
private static Header? ParseHeader(Stream data)
{
// TODO: Use marshalling here instead of building
Header header = new Header();
var header = data.ReadType<Header>();
byte[]? magic = data.ReadBytes(4);
if (magic == null)
if (header == null)
return null;
header.Magic = Encoding.ASCII.GetString(magic);
if (header.Magic != SignatureString)
return null;
header.Version = data.ReadInt32();
header.Files = data.ReadInt32();
return header;
}
@@ -95,7 +88,7 @@ namespace SabreTools.Serialization.Deserializers
private static FileEntry ParseFileEntry(Stream data)
{
// TODO: Use marshalling here instead of building
FileEntry fileEntry = new FileEntry();
var fileEntry = new FileEntry();
fileEntry.NameSize = data.ReadInt32();
if (fileEntry.NameSize > 0)

View File

@@ -47,6 +47,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < HL_BSP_LUMP_COUNT; i++)
{
var lump = ParseLump(data);
if (lump == null)
return null;
file.Lumps[i] = lump;
}
@@ -102,13 +105,13 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Level header on success, null on error</returns>
/// <remarks>Only recognized versions are 29 and 30</remarks>
private static Header? ParseHeader(Stream data)
{
// TODO: Use marshalling here instead of building
Header header = new Header();
var header = data.ReadType<Header>();
// Only recognized versions are 29 and 30
header.Version = data.ReadUInt32();
if (header == null)
return null;
if (header.Version != 29 && header.Version != 30)
return null;
@@ -120,15 +123,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled lump on success, null on error</returns>
private static Lump ParseLump(Stream data)
private static Lump? ParseLump(Stream data)
{
// TODO: Use marshalling here instead of building
Lump lump = new Lump();
lump.Offset = data.ReadUInt32();
lump.Length = data.ReadUInt32();
return lump;
return data.ReadType<Lump>();
}
/// <summary>
@@ -139,7 +136,7 @@ namespace SabreTools.Serialization.Deserializers
private static TextureHeader ParseTextureHeader(Stream data)
{
// TODO: Use marshalling here instead of building
TextureHeader textureHeader = new TextureHeader();
var textureHeader = new TextureHeader();
textureHeader.TextureCount = data.ReadUInt32();
@@ -166,7 +163,7 @@ namespace SabreTools.Serialization.Deserializers
private static Texture ParseTexture(Stream data, uint mipmap = 0)
{
// TODO: Use marshalling here instead of building
Texture texture = new Texture();
var texture = new Texture();
byte[]? name = data.ReadBytes(16)?.TakeWhile(c => c != '\0')?.ToArray();
if (name != null)

View File

@@ -234,7 +234,7 @@ namespace SabreTools.Serialization.Deserializers
private static FileHeader? ParseFileHeader(Stream data)
{
// TODO: Use marshalling here instead of building
FileHeader header = new FileHeader();
var header = new FileHeader();
header.Signature = data.ReadUInt64();
if (header.Signature != SignatureUInt64)
@@ -315,7 +315,7 @@ namespace SabreTools.Serialization.Deserializers
// TODO: Use marshalling here instead of building
const int directoryEntrySize = 64 + 2 + 1 + 1 + 4 + 4 + 4 + 16 + 4 + 8 + 8 + 4 + 8;
int sectorCount = (int)(Math.Pow(2, sectorShift) / directoryEntrySize);
DirectoryEntry[] directoryEntries = new DirectoryEntry[sectorCount];
var directoryEntries = new DirectoryEntry[sectorCount];
for (int i = 0; i < directoryEntries.Length; i++)
{
@@ -335,10 +335,10 @@ namespace SabreTools.Serialization.Deserializers
/// <param name="data">Stream to parse</param>
/// <param name="majorVersion">Major version from the header</param>
/// <returns>Filled directory entry on success, null on error</returns>
private static DirectoryEntry ParseDirectoryEntry(Stream data, ushort majorVersion)
private static DirectoryEntry? ParseDirectoryEntry(Stream data, ushort majorVersion)
{
// TODO: Use marshalling here instead of building
DirectoryEntry directoryEntry = new DirectoryEntry();
var directoryEntry = new DirectoryEntry();
byte[]? name = data.ReadBytes(64);
if (name != null)

View File

@@ -58,6 +58,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < blockEntryHeader.BlockCount; i++)
{
var blockEntry = ParseBlockEntry(data);
if (blockEntry == null)
return null;
file.BlockEntries[i] = blockEntry;
}
@@ -84,6 +87,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < fragmentationMapHeader.BlockCount; i++)
{
var fragmentationMap = ParseFragmentationMap(data);
if (fragmentationMap == null)
return null;
file.FragmentationMaps[i] = fragmentationMap;
}
@@ -115,6 +121,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < file.BlockEntryMapHeader.BlockCount; i++)
{
var blockEntryMap = ParseBlockEntryMap(data);
if (blockEntryMap == null)
return null;
file.BlockEntryMaps[i] = blockEntryMap;
}
}
@@ -200,6 +209,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.Info1Count; i++)
{
var directoryInfo1Entry = ParseDirectoryInfo1Entry(data);
if (directoryInfo1Entry == null)
return null;
file.DirectoryInfo1Entries[i] = directoryInfo1Entry;
}
@@ -214,6 +226,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.ItemCount; i++)
{
var directoryInfo2Entry = ParseDirectoryInfo2Entry(data);
if (directoryInfo2Entry == null)
return null;
file.DirectoryInfo2Entries[i] = directoryInfo2Entry;
}
@@ -228,6 +243,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.CopyCount; i++)
{
var directoryCopyEntry = ParseDirectoryCopyEntry(data);
if (directoryCopyEntry == null)
return null;
file.DirectoryCopyEntries[i] = directoryCopyEntry;
}
@@ -242,6 +260,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.LocalCount; i++)
{
var directoryLocalEntry = ParseDirectoryLocalEntry(data);
if (directoryLocalEntry == null)
return null;
file.DirectoryLocalEntries[i] = directoryLocalEntry;
}
@@ -274,6 +295,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.ItemCount; i++)
{
var directoryMapEntry = ParseDirectoryMapEntry(data);
if (directoryMapEntry == null)
return null;
file.DirectoryMapEntries[i] = directoryMapEntry;
}
@@ -315,6 +339,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < checksumMapHeader.ItemCount; i++)
{
var checksumMapEntry = ParseChecksumMapEntry(data);
if (checksumMapEntry == null)
return null;
file.ChecksumMapEntries[i] = checksumMapEntry;
}
@@ -329,6 +356,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < checksumMapHeader.ChecksumCount; i++)
{
var checksumEntry = ParseChecksumEntry(data);
if (checksumEntry == null)
return null;
file.ChecksumEntries[i] = checksumEntry;
}
@@ -359,30 +389,17 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life Game Cache on success, null on error</returns>
private static Header? ParseHeader(Stream data)
{
// TODO: Use marshalling here instead of building
Header header = new Header();
var header = data.ReadType<Header>();
header.Dummy0 = data.ReadUInt32();
if (header == null)
return null;
if (header.Dummy0 != 0x00000001)
return null;
header.MajorVersion = data.ReadUInt32();
if (header.MajorVersion != 0x00000001)
return null;
header.MinorVersion = data.ReadUInt32();
if (header.MinorVersion != 3 && header.MinorVersion != 5 && header.MinorVersion != 6)
return null;
header.CacheID = data.ReadUInt32();
header.LastVersionPlayed = data.ReadUInt32();
header.Dummy1 = data.ReadUInt32();
header.Dummy2 = data.ReadUInt32();
header.FileSize = data.ReadUInt32();
header.BlockSize = data.ReadUInt32();
header.BlockCount = data.ReadUInt32();
header.Dummy3 = data.ReadUInt32();
return header;
}
@@ -391,21 +408,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache block entry header on success, null on error</returns>
private static BlockEntryHeader ParseBlockEntryHeader(Stream data)
private static BlockEntryHeader? ParseBlockEntryHeader(Stream data)
{
// TODO: Use marshalling here instead of building
BlockEntryHeader blockEntryHeader = new BlockEntryHeader();
blockEntryHeader.BlockCount = data.ReadUInt32();
blockEntryHeader.BlocksUsed = data.ReadUInt32();
blockEntryHeader.Dummy0 = data.ReadUInt32();
blockEntryHeader.Dummy1 = data.ReadUInt32();
blockEntryHeader.Dummy2 = data.ReadUInt32();
blockEntryHeader.Dummy3 = data.ReadUInt32();
blockEntryHeader.Dummy4 = data.ReadUInt32();
blockEntryHeader.Checksum = data.ReadUInt32();
return blockEntryHeader;
return data.ReadType<BlockEntryHeader>();
}
/// <summary>
@@ -413,20 +418,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache block entry on success, null on error</returns>
private static BlockEntry ParseBlockEntry(Stream data)
private static BlockEntry? ParseBlockEntry(Stream data)
{
// TODO: Use marshalling here instead of building
BlockEntry blockEntry = new BlockEntry();
blockEntry.EntryFlags = data.ReadUInt32();
blockEntry.FileDataOffset = data.ReadUInt32();
blockEntry.FileDataSize = data.ReadUInt32();
blockEntry.FirstDataBlockIndex = data.ReadUInt32();
blockEntry.NextBlockEntryIndex = data.ReadUInt32();
blockEntry.PreviousBlockEntryIndex = data.ReadUInt32();
blockEntry.DirectoryIndex = data.ReadUInt32();
return blockEntry;
return data.ReadType<BlockEntry>();
}
/// <summary>
@@ -434,17 +428,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache fragmentation map header on success, null on error</returns>
private static FragmentationMapHeader ParseFragmentationMapHeader(Stream data)
private static FragmentationMapHeader? ParseFragmentationMapHeader(Stream data)
{
// TODO: Use marshalling here instead of building
FragmentationMapHeader fragmentationMapHeader = new FragmentationMapHeader();
fragmentationMapHeader.BlockCount = data.ReadUInt32();
fragmentationMapHeader.FirstUnusedEntry = data.ReadUInt32();
fragmentationMapHeader.Terminator = data.ReadUInt32();
fragmentationMapHeader.Checksum = data.ReadUInt32();
return fragmentationMapHeader;
return data.ReadType<FragmentationMapHeader>();
}
/// <summary>
@@ -452,14 +438,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache fragmentation map on success, null on error</returns>
private static FragmentationMap ParseFragmentationMap(Stream data)
private static FragmentationMap? ParseFragmentationMap(Stream data)
{
// TODO: Use marshalling here instead of building
FragmentationMap fragmentationMap = new FragmentationMap();
fragmentationMap.NextDataBlockIndex = data.ReadUInt32();
return fragmentationMap;
return data.ReadType<FragmentationMap>();
}
/// <summary>
@@ -467,18 +448,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache block entry map header on success, null on error</returns>
private static BlockEntryMapHeader ParseBlockEntryMapHeader(Stream data)
private static BlockEntryMapHeader? ParseBlockEntryMapHeader(Stream data)
{
// TODO: Use marshalling here instead of building
BlockEntryMapHeader blockEntryMapHeader = new BlockEntryMapHeader();
blockEntryMapHeader.BlockCount = data.ReadUInt32();
blockEntryMapHeader.FirstBlockEntryIndex = data.ReadUInt32();
blockEntryMapHeader.LastBlockEntryIndex = data.ReadUInt32();
blockEntryMapHeader.Dummy0 = data.ReadUInt32();
blockEntryMapHeader.Checksum = data.ReadUInt32();
return blockEntryMapHeader;
return data.ReadType<BlockEntryMapHeader>();
}
/// <summary>
@@ -486,15 +458,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache block entry map on success, null on error</returns>
private static BlockEntryMap ParseBlockEntryMap(Stream data)
private static BlockEntryMap? ParseBlockEntryMap(Stream data)
{
// TODO: Use marshalling here instead of building
BlockEntryMap blockEntryMap = new BlockEntryMap();
blockEntryMap.PreviousBlockEntryIndex = data.ReadUInt32();
blockEntryMap.NextBlockEntryIndex = data.ReadUInt32();
return blockEntryMap;
return data.ReadType<BlockEntryMap>();
}
/// <summary>
@@ -502,27 +468,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache directory header on success, null on error</returns>
private static DirectoryHeader ParseDirectoryHeader(Stream data)
private static DirectoryHeader? ParseDirectoryHeader(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryHeader directoryHeader = new DirectoryHeader();
directoryHeader.Dummy0 = data.ReadUInt32();
directoryHeader.CacheID = data.ReadUInt32();
directoryHeader.LastVersionPlayed = data.ReadUInt32();
directoryHeader.ItemCount = data.ReadUInt32();
directoryHeader.FileCount = data.ReadUInt32();
directoryHeader.Dummy1 = data.ReadUInt32();
directoryHeader.DirectorySize = data.ReadUInt32();
directoryHeader.NameSize = data.ReadUInt32();
directoryHeader.Info1Count = data.ReadUInt32();
directoryHeader.CopyCount = data.ReadUInt32();
directoryHeader.LocalCount = data.ReadUInt32();
directoryHeader.Dummy2 = data.ReadUInt32();
directoryHeader.Dummy3 = data.ReadUInt32();
directoryHeader.Checksum = data.ReadUInt32();
return directoryHeader;
return data.ReadType<DirectoryHeader>();
}
/// <summary>
@@ -533,7 +481,7 @@ namespace SabreTools.Serialization.Deserializers
private static DirectoryEntry ParseDirectoryEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryEntry directoryEntry = new DirectoryEntry();
var directoryEntry = new DirectoryEntry();
directoryEntry.NameOffset = data.ReadUInt32();
directoryEntry.ItemSize = data.ReadUInt32();
@@ -551,14 +499,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache directory info 1 entry on success, null on error</returns>
private static DirectoryInfo1Entry ParseDirectoryInfo1Entry(Stream data)
private static DirectoryInfo1Entry? ParseDirectoryInfo1Entry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryInfo1Entry directoryInfo1Entry = new DirectoryInfo1Entry();
directoryInfo1Entry.Dummy0 = data.ReadUInt32();
return directoryInfo1Entry;
return data.ReadType<DirectoryInfo1Entry>();
}
/// <summary>
@@ -566,14 +509,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache directory info 2 entry on success, null on error</returns>
private static DirectoryInfo2Entry ParseDirectoryInfo2Entry(Stream data)
private static DirectoryInfo2Entry? ParseDirectoryInfo2Entry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryInfo2Entry directoryInfo2Entry = new DirectoryInfo2Entry();
directoryInfo2Entry.Dummy0 = data.ReadUInt32();
return directoryInfo2Entry;
return data.ReadType<DirectoryInfo2Entry>();
}
/// <summary>
@@ -581,14 +519,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache directory copy entry on success, null on error</returns>
private static DirectoryCopyEntry ParseDirectoryCopyEntry(Stream data)
private static DirectoryCopyEntry? ParseDirectoryCopyEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryCopyEntry directoryCopyEntry = new DirectoryCopyEntry();
directoryCopyEntry.DirectoryIndex = data.ReadUInt32();
return directoryCopyEntry;
return data.ReadType<DirectoryCopyEntry>();
}
/// <summary>
@@ -596,14 +529,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache directory local entry on success, null on error</returns>
private static DirectoryLocalEntry ParseDirectoryLocalEntry(Stream data)
private static DirectoryLocalEntry? ParseDirectoryLocalEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryLocalEntry directoryLocalEntry = new DirectoryLocalEntry();
directoryLocalEntry.DirectoryIndex = data.ReadUInt32();
return directoryLocalEntry;
return data.ReadType<DirectoryLocalEntry>();
}
/// <summary>
@@ -613,14 +541,12 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life Game Cache directory map header on success, null on error</returns>
private static DirectoryMapHeader? ParseDirectoryMapHeader(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryMapHeader directoryMapHeader = new DirectoryMapHeader();
var directoryMapHeader = data.ReadType<DirectoryMapHeader>();
directoryMapHeader.Dummy0 = data.ReadUInt32();
if (directoryMapHeader == null)
return null;
if (directoryMapHeader.Dummy0 != 0x00000001)
return null;
directoryMapHeader.Dummy1 = data.ReadUInt32();
if (directoryMapHeader.Dummy1 != 0x00000000)
return null;
@@ -632,14 +558,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache directory map entry on success, null on error</returns>
private static DirectoryMapEntry ParseDirectoryMapEntry(Stream data)
private static DirectoryMapEntry? ParseDirectoryMapEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryMapEntry directoryMapEntry = new DirectoryMapEntry();
directoryMapEntry.FirstBlockIndex = data.ReadUInt32();
return directoryMapEntry;
return data.ReadType<DirectoryMapEntry>();
}
/// <summary>
@@ -649,15 +570,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life Game Cache checksum header on success, null on error</returns>
private static ChecksumHeader? ParseChecksumHeader(Stream data)
{
// TODO: Use marshalling here instead of building
ChecksumHeader checksumHeader = new ChecksumHeader();
var checksumHeader = data.ReadType<ChecksumHeader>();
checksumHeader.Dummy0 = data.ReadUInt32();
if (checksumHeader == null)
return null;
if (checksumHeader.Dummy0 != 0x00000001)
return null;
checksumHeader.ChecksumSize = data.ReadUInt32();
return checksumHeader;
}
@@ -668,20 +587,15 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life Game Cache checksum map header on success, null on error</returns>
private static ChecksumMapHeader? ParseChecksumMapHeader(Stream data)
{
// TODO: Use marshalling here instead of building
ChecksumMapHeader checksumMapHeader = new ChecksumMapHeader();
var checksumMapHeader = data.ReadType<ChecksumMapHeader>();
checksumMapHeader.Dummy0 = data.ReadUInt32();
if (checksumMapHeader == null)
return null;
if (checksumMapHeader.Dummy0 != 0x14893721)
return null;
checksumMapHeader.Dummy1 = data.ReadUInt32();
if (checksumMapHeader.Dummy1 != 0x00000001)
return null;
checksumMapHeader.ItemCount = data.ReadUInt32();
checksumMapHeader.ChecksumCount = data.ReadUInt32();
return checksumMapHeader;
}
@@ -690,15 +604,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache checksum map entry on success, null on error</returns>
private static ChecksumMapEntry ParseChecksumMapEntry(Stream data)
private static ChecksumMapEntry? ParseChecksumMapEntry(Stream data)
{
// TODO: Use marshalling here instead of building
ChecksumMapEntry checksumMapEntry = new ChecksumMapEntry();
checksumMapEntry.ChecksumCount = data.ReadUInt32();
checksumMapEntry.FirstChecksumIndex = data.ReadUInt32();
return checksumMapEntry;
return data.ReadType<ChecksumMapEntry>();
}
/// <summary>
@@ -706,14 +614,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Game Cache checksum entry on success, null on error</returns>
private static ChecksumEntry ParseChecksumEntry(Stream data)
private static ChecksumEntry? ParseChecksumEntry(Stream data)
{
// TODO: Use marshalling here instead of building
ChecksumEntry checksumEntry = new ChecksumEntry();
checksumEntry.Checksum = data.ReadUInt32();
return checksumEntry;
return data.ReadType<ChecksumEntry>();
}
/// <summary>
@@ -722,10 +625,10 @@ namespace SabreTools.Serialization.Deserializers
/// <param name="data">Stream to parse</param>
/// <param name="minorVersion">Minor version field from the header</param>
/// <returns>Filled Half-Life Game Cache data block header on success, null on error</returns>
private static DataBlockHeader ParseDataBlockHeader(Stream data, uint minorVersion)
private static DataBlockHeader? ParseDataBlockHeader(Stream data, uint minorVersion)
{
// TODO: Use marshalling here instead of building
DataBlockHeader dataBlockHeader = new DataBlockHeader();
var dataBlockHeader = new DataBlockHeader();
// In version 3 the DataBlockHeader is missing the LastVersionPlayed field.
if (minorVersion >= 5)

View File

@@ -20,7 +20,7 @@ namespace SabreTools.Serialization.Deserializers
// Cache the current offset
int initialOffset = (int)data.Position;
// Create a new media key block to fill
// Create a new IRD to fill
var ird = new Models.IRD.File();
ird.Magic = data.ReadBytes(4);

View File

@@ -96,14 +96,11 @@ namespace SabreTools.Serialization.Deserializers
public static Header? ParseHeader(Stream data)
{
var header = data.ReadType<Header>();
if (header == null)
return null;
// Invalid signature
if (header.Signature1 != 0x8C655D13) // TODO: Move constant to Models
return null;
// Invalid TOC address
if (header.TocAddress >= data.Length)
return null;

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.InstallShieldCabinet;
using static SabreTools.Models.InstallShieldCabinet.Constants;
@@ -335,21 +334,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled common header on success, null on error</returns>
public static CommonHeader? ParseCommonHeader(Stream data)
{
CommonHeader commonHeader = new CommonHeader();
var commonHeader = data.ReadType<CommonHeader>();
byte[]? signature = data.ReadBytes(4);
if (signature == null)
if (commonHeader == null)
return null;
commonHeader.Signature = Encoding.ASCII.GetString(signature);
if (commonHeader.Signature != SignatureString)
return null;
commonHeader.Version = data.ReadUInt32();
commonHeader.VolumeInfo = data.ReadUInt32();
commonHeader.DescriptorOffset = data.ReadUInt32();
commonHeader.DescriptorSize = data.ReadUInt32();
return commonHeader;
}
@@ -406,46 +397,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled descriptor on success, null on error</returns>
public static Descriptor ParseDescriptor(Stream data)
public static Descriptor? ParseDescriptor(Stream data)
{
Descriptor descriptor = new Descriptor();
descriptor.StringsOffset = data.ReadUInt32();
descriptor.Reserved0 = data.ReadUInt32();
descriptor.ComponentListOffset = data.ReadUInt32();
descriptor.FileTableOffset = data.ReadUInt32();
descriptor.Reserved1 = data.ReadUInt32();
descriptor.FileTableSize = data.ReadUInt32();
descriptor.FileTableSize2 = data.ReadUInt32();
descriptor.DirectoryCount = data.ReadUInt16();
descriptor.Reserved2 = data.ReadUInt32();
descriptor.Reserved3 = data.ReadUInt16();
descriptor.Reserved4 = data.ReadUInt32();
descriptor.FileCount = data.ReadUInt32();
descriptor.FileTableOffset2 = data.ReadUInt32();
descriptor.ComponentTableInfoCount = data.ReadUInt16();
descriptor.ComponentTableOffset = data.ReadUInt32();
descriptor.Reserved5 = data.ReadUInt32();
descriptor.Reserved6 = data.ReadUInt32();
descriptor.FileGroupOffsets = new uint[MAX_FILE_GROUP_COUNT];
for (int i = 0; i < descriptor.FileGroupOffsets.Length; i++)
{
descriptor.FileGroupOffsets[i] = data.ReadUInt32();
}
descriptor.ComponentOffsets = new uint[MAX_COMPONENT_COUNT];
for (int i = 0; i < descriptor.ComponentOffsets.Length; i++)
{
descriptor.ComponentOffsets[i] = data.ReadUInt32();
}
descriptor.SetupTypesOffset = data.ReadUInt32();
descriptor.SetupTableOffset = data.ReadUInt32();
descriptor.Reserved7 = data.ReadUInt32();
descriptor.Reserved8 = data.ReadUInt32();
return descriptor;
return data.ReadType<Descriptor>();
}
/// <summary>
@@ -457,7 +411,7 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled offset list on success, null on error</returns>
public static OffsetList ParseOffsetList(Stream data, int majorVersion, uint descriptorOffset)
{
OffsetList offsetList = new OffsetList();
var offsetList = new OffsetList();
offsetList.NameOffset = data.ReadUInt32();
offsetList.DescriptorOffset = data.ReadUInt32();
@@ -490,7 +444,7 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled file group on success, null on error</returns>
public static FileGroup ParseFileGroup(Stream data, int majorVersion, uint descriptorOffset)
{
FileGroup fileGroup = new FileGroup();
var fileGroup = new FileGroup();
fileGroup.NameOffset = data.ReadUInt32();
@@ -553,7 +507,7 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled component on success, null on error</returns>
public static Component ParseComponent(Stream data, int majorVersion, uint descriptorOffset)
{
Component component = new Component();
var component = new Component();
component.IdentifierOffset = data.ReadUInt32();
component.DescriptorOffset = data.ReadUInt32();

View File

@@ -425,63 +425,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled information block on success, null on error</returns>
public static InformationBlock? ParseInformationBlock(Stream data)
{
// TODO: Use marshalling here instead of building
var informationBlock = new InformationBlock();
var informationBlock = data.ReadType<InformationBlock>();
byte[]? magic = data.ReadBytes(2);
if (magic == null)
if (informationBlock == null)
return null;
informationBlock.Signature = Encoding.ASCII.GetString(magic);
if (informationBlock.Signature != LESignatureString && informationBlock.Signature != LXSignatureString)
return null;
informationBlock.ByteOrder = (ByteOrder)data.ReadByteValue();
informationBlock.WordOrder = (WordOrder)data.ReadByteValue();
informationBlock.ExecutableFormatLevel = data.ReadUInt32();
informationBlock.CPUType = (CPUType)data.ReadUInt16();
informationBlock.ModuleOS = (OperatingSystem)data.ReadUInt16();
informationBlock.ModuleVersion = data.ReadUInt32();
informationBlock.ModuleTypeFlags = (ModuleFlags)data.ReadUInt32();
informationBlock.ModuleNumberPages = data.ReadUInt32();
informationBlock.InitialObjectCS = data.ReadUInt32();
informationBlock.InitialEIP = data.ReadUInt32();
informationBlock.InitialObjectSS = data.ReadUInt32();
informationBlock.InitialESP = data.ReadUInt32();
informationBlock.MemoryPageSize = data.ReadUInt32();
informationBlock.BytesOnLastPage = data.ReadUInt32();
informationBlock.FixupSectionSize = data.ReadUInt32();
informationBlock.FixupSectionChecksum = data.ReadUInt32();
informationBlock.LoaderSectionSize = data.ReadUInt32();
informationBlock.LoaderSectionChecksum = data.ReadUInt32();
informationBlock.ObjectTableOffset = data.ReadUInt32();
informationBlock.ObjectTableCount = data.ReadUInt32();
informationBlock.ObjectPageMapOffset = data.ReadUInt32();
informationBlock.ObjectIterateDataMapOffset = data.ReadUInt32();
informationBlock.ResourceTableOffset = data.ReadUInt32();
informationBlock.ResourceTableCount = data.ReadUInt32();
informationBlock.ResidentNamesTableOffset = data.ReadUInt32();
informationBlock.EntryTableOffset = data.ReadUInt32();
informationBlock.ModuleDirectivesTableOffset = data.ReadUInt32();
informationBlock.ModuleDirectivesCount = data.ReadUInt32();
informationBlock.FixupPageTableOffset = data.ReadUInt32();
informationBlock.FixupRecordTableOffset = data.ReadUInt32();
informationBlock.ImportedModulesNameTableOffset = data.ReadUInt32();
informationBlock.ImportedModulesCount = data.ReadUInt32();
informationBlock.ImportProcedureNameTableOffset = data.ReadUInt32();
informationBlock.PerPageChecksumTableOffset = data.ReadUInt32();
informationBlock.DataPagesOffset = data.ReadUInt32();
informationBlock.PreloadPageCount = data.ReadUInt32();
informationBlock.NonResidentNamesTableOffset = data.ReadUInt32();
informationBlock.NonResidentNamesTableLength = data.ReadUInt32();
informationBlock.NonResidentNamesTableChecksum = data.ReadUInt32();
informationBlock.AutomaticDataObject = data.ReadUInt32();
informationBlock.DebugInformationOffset = data.ReadUInt32();
informationBlock.DebugInformationLength = data.ReadUInt32();
informationBlock.PreloadInstancePagesNumber = data.ReadUInt32();
informationBlock.DemandInstancePagesNumber = data.ReadUInt32();
informationBlock.ExtraHeapAllocation = data.ReadUInt32();
return informationBlock;
}
@@ -490,19 +440,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled object table entry on success, null on error</returns>
public static ObjectTableEntry ParseObjectTableEntry(Stream data)
public static ObjectTableEntry? ParseObjectTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new ObjectTableEntry();
entry.VirtualSegmentSize = data.ReadUInt32();
entry.RelocationBaseAddress = data.ReadUInt32();
entry.ObjectFlags = (ObjectFlags)data.ReadUInt16();
entry.PageTableIndex = data.ReadUInt32();
entry.PageTableEntries = data.ReadUInt32();
entry.Reserved = data.ReadUInt32();
return entry;
return data.ReadType<ObjectTableEntry>();
}
/// <summary>
@@ -510,16 +450,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled object page map entry on success, null on error</returns>
public static ObjectPageMapEntry ParseObjectPageMapEntry(Stream data)
public static ObjectPageMapEntry? ParseObjectPageMapEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new ObjectPageMapEntry();
entry.PageDataOffset = data.ReadUInt32();
entry.DataSize = data.ReadUInt16();
entry.Flags = (ObjectPageFlags)data.ReadUInt16();
return entry;
return data.ReadType<ObjectPageMapEntry>();
}
/// <summary>
@@ -527,18 +460,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled resource table entry on success, null on error</returns>
public static ResourceTableEntry ParseResourceTableEntry(Stream data)
public static ResourceTableEntry? ParseResourceTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new ResourceTableEntry();
entry.TypeID = (ResourceTableEntryType)data.ReadUInt32();
entry.NameID = data.ReadUInt16();
entry.ResourceSize = data.ReadUInt32();
entry.ObjectNumber = data.ReadUInt16();
entry.Offset = data.ReadUInt32();
return entry;
return data.ReadType<ResourceTableEntry>();
}
/// <summary>
@@ -631,16 +555,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled module format directives table entry on success, null on error</returns>
public static ModuleFormatDirectivesTableEntry ParseModuleFormatDirectivesTableEntry(Stream data)
public static ModuleFormatDirectivesTableEntry? ParseModuleFormatDirectivesTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new ModuleFormatDirectivesTableEntry();
entry.DirectiveNumber = (DirectiveNumber)data.ReadUInt16();
entry.DirectiveDataLength = data.ReadUInt16();
entry.DirectiveDataOffset = data.ReadUInt32();
return entry;
return data.ReadType<ModuleFormatDirectivesTableEntry>();
}
/// <summary>
@@ -648,20 +565,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled verify record directive table entry on success, null on error</returns>
public static VerifyRecordDirectiveTableEntry ParseVerifyRecordDirectiveTableEntry(Stream data)
public static VerifyRecordDirectiveTableEntry? ParseVerifyRecordDirectiveTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new VerifyRecordDirectiveTableEntry();
entry.EntryCount = data.ReadUInt16();
entry.OrdinalIndex = data.ReadUInt16();
entry.Version = data.ReadUInt16();
entry.ObjectEntriesCount = data.ReadUInt16();
entry.ObjectNumberInModule = data.ReadUInt16();
entry.ObjectLoadBaseAddress = data.ReadUInt16();
entry.ObjectVirtualAddressSize = data.ReadUInt16();
return entry;
return data.ReadType<VerifyRecordDirectiveTableEntry>();
}
/// <summary>
@@ -669,14 +575,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled fix-up page table entry on success, null on error</returns>
public static FixupPageTableEntry ParseFixupPageTableEntry(Stream data)
public static FixupPageTableEntry? ParseFixupPageTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new FixupPageTableEntry();
entry.Offset = data.ReadUInt32();
return entry;
return data.ReadType<FixupPageTableEntry>();
}
/// <summary>
@@ -945,14 +846,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled per-page checksum table entry on success, null on error</returns>
public static PerPageChecksumTableEntry ParsePerPageChecksumTableEntry(Stream data)
public static PerPageChecksumTableEntry? ParsePerPageChecksumTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new PerPageChecksumTableEntry();
entry.Checksum = data.ReadUInt32();
return entry;
return data.ReadType<PerPageChecksumTableEntry>();
}
/// <summary>

View File

@@ -126,20 +126,31 @@ namespace SabreTools.Serialization.Deserializers
/// <param name="data">Stream to parse</param>
/// <param name="count">Number of relocation table entries to read</param>
/// <returns>Filled relocation table on success, null on error</returns>
private static RelocationEntry[] ParseRelocationTable(Stream data, int count)
private static RelocationEntry[]? ParseRelocationTable(Stream data, int count)
{
// TODO: Use marshalling here instead of building
var relocationTable = new RelocationEntry[count];
for (int i = 0; i < count; i++)
{
var entry = new RelocationEntry();
entry.Offset = data.ReadUInt16();
entry.Segment = data.ReadUInt16();
var entry = ParseRelocationEntry(data);
if (entry == null)
return null;
relocationTable[i] = entry;
}
return relocationTable;
}
/// <summary>
/// Parse a Stream into a relocation table entry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled relocation table entry on success, null on error</returns>
public static RelocationEntry? ParseRelocationEntry(Stream data)
{
return data.ReadType<RelocationEntry>();
}
}
}

View File

@@ -404,7 +404,7 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled user data on success, null on error</returns>
private static UserData? ParseUserData(Stream data)
{
UserData userData = new UserData();
var userData = new UserData();
byte[]? signature = data.ReadBytes(4);
if (signature == null)
@@ -428,7 +428,7 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled HET table on success, null on error</returns>
private static HetTable? ParseHetTable(Stream data)
{
HetTable hetTable = new HetTable();
var hetTable = new HetTable();
// Common Headers
byte[]? signature = data.ReadBytes(4);
@@ -465,7 +465,7 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled BET table on success, null on error</returns>
private static BetTable? ParseBetTable(Stream data)
{
BetTable betTable = new BetTable();
var betTable = new BetTable();
// Common Headers
byte[]? signature = data.ReadBytes(4);
@@ -519,18 +519,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled hash entry on success, null on error</returns>
private static HashEntry ParseHashEntry(Stream data)
private static HashEntry? ParseHashEntry(Stream data)
{
// TODO: Use marshalling here instead of building
HashEntry hashEntry = new HashEntry();
hashEntry.NameHashPartA = data.ReadUInt32();
hashEntry.NameHashPartB = data.ReadUInt32();
hashEntry.Locale = (Locale)data.ReadUInt16();
hashEntry.Platform = data.ReadUInt16();
hashEntry.BlockIndex = data.ReadUInt32();
return hashEntry;
return data.ReadType<HashEntry>();
}
/// <summary>
@@ -538,16 +529,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled block entry on success, null on error</returns>
private static BlockEntry ParseBlockEntry(Stream data)
private static BlockEntry? ParseBlockEntry(Stream data)
{
BlockEntry blockEntry = new BlockEntry();
blockEntry.FilePosition = data.ReadUInt32();
blockEntry.CompressedSize = data.ReadUInt32();
blockEntry.UncompressedSize = data.ReadUInt32();
blockEntry.Flags = (FileFlags)data.ReadUInt32();
return blockEntry;
return data.ReadType<BlockEntry>();
}
/// <summary>
@@ -558,7 +542,7 @@ namespace SabreTools.Serialization.Deserializers
private static PatchInfo ParsePatchInfo(Stream data)
{
// TODO: Use marshalling here instead of building
PatchInfo patchInfo = new PatchInfo();
var patchInfo = new PatchInfo();
patchInfo.Length = data.ReadUInt32();
patchInfo.Flags = data.ReadUInt32();

View File

@@ -137,7 +137,11 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(offset, SeekOrigin.Begin);
// Parse the ExeFS header
cart.ExeFSHeaders[i] = ParseExeFSHeader(data);
var exeFsHeader = ParseExeFSHeader(data);
if (exeFsHeader == null)
return null;
cart.ExeFSHeaders[i] = exeFsHeader;
}
#endregion
@@ -628,7 +632,7 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled ExeFS header on success, null on error</returns>
private static ExeFSHeader ParseExeFSHeader(Stream data)
private static ExeFSHeader? ParseExeFSHeader(Stream data)
{
// TODO: Use marshalling here instead of building
var exeFSHeader = new ExeFSHeader();
@@ -636,7 +640,11 @@ namespace SabreTools.Serialization.Deserializers
exeFSHeader.FileHeaders = new ExeFSFileHeader[10];
for (int i = 0; i < 10; i++)
{
exeFSHeader.FileHeaders[i] = ParseExeFSFileHeader(data);
var exeFsFileHeader = ParseExeFSFileHeader(data);
if (exeFsFileHeader == null)
return null;
exeFSHeader.FileHeaders[i] = exeFsFileHeader;
}
exeFSHeader.Reserved = data.ReadBytes(0x20);
exeFSHeader.FileHashes = new byte[10][];
@@ -653,7 +661,7 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled ExeFS file header on success, null on error</returns>
private static ExeFSFileHeader ParseExeFSFileHeader(Stream data)
private static ExeFSFileHeader? ParseExeFSFileHeader(Stream data)
{
// TODO: Use marshalling here instead of building
var exeFSFileHeader = new ExeFSFileHeader();

View File

@@ -61,6 +61,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.ItemCount; i++)
{
var directoryEntry = ParseDirectoryEntry(data);
if (directoryEntry == null)
return null;
file.DirectoryEntries[i] = directoryEntry;
}
@@ -116,6 +119,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.Info1Count; i++)
{
var directoryInfo1Entry = ParseDirectoryInfo1Entry(data);
if (directoryInfo1Entry == null)
return null;
file.DirectoryInfo1Entries[i] = directoryInfo1Entry;
}
@@ -130,6 +136,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.ItemCount; i++)
{
var directoryInfo2Entry = ParseDirectoryInfo2Entry(data);
if (directoryInfo2Entry == null)
return null;
file.DirectoryInfo2Entries[i] = directoryInfo2Entry;
}
@@ -144,6 +153,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.CopyCount; i++)
{
var directoryCopyEntry = ParseDirectoryCopyEntry(data);
if (directoryCopyEntry == null)
return null;
file.DirectoryCopyEntries[i] = directoryCopyEntry;
}
@@ -158,6 +170,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.LocalCount; i++)
{
var directoryLocalEntry = ParseDirectoryLocalEntry(data);
if (directoryLocalEntry == null)
return null;
file.DirectoryLocalEntries[i] = directoryLocalEntry;
}
@@ -187,6 +202,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < directoryHeader.ItemCount; i++)
{
var unknownEntry = ParseUnknownEntry(data);
if (unknownEntry == null)
return null;
file.UnknownEntries[i] = unknownEntry;
}
@@ -228,6 +246,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < checksumMapHeader.ItemCount; i++)
{
var checksumMapEntry = ParseChecksumMapEntry(data);
if (checksumMapEntry == null)
return null;
file.ChecksumMapEntries[i] = checksumMapEntry;
}
@@ -242,6 +263,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < checksumMapHeader.ChecksumCount; i++)
{
var checksumEntry = ParseChecksumEntry(data);
if (checksumEntry == null)
return null;
file.ChecksumEntries[i] = checksumEntry;
}
@@ -260,30 +284,17 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life No Cache header on success, null on error</returns>
private static Header? ParseHeader(Stream data)
{
// TODO: Use marshalling here instead of building
Header header = new Header();
var header = data.ReadType<Header>();
header.Dummy0 = data.ReadUInt32();
if (header == null)
return null;
if (header.Dummy0 != 0x00000001)
return null;
header.MajorVersion = data.ReadUInt32();
if (header.MajorVersion != 0x00000002)
return null;
header.MinorVersion = data.ReadUInt32();
if (header.MinorVersion != 1)
return null;
header.CacheID = data.ReadUInt32();
header.LastVersionPlayed = data.ReadUInt32();
header.Dummy1 = data.ReadUInt32();
header.Dummy2 = data.ReadUInt32();
header.FileSize = data.ReadUInt32();
header.BlockSize = data.ReadUInt32();
header.BlockCount = data.ReadUInt32();
header.Dummy3 = data.ReadUInt32();
return header;
}
@@ -294,27 +305,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life No Cache directory header on success, null on error</returns>
private static DirectoryHeader? ParseDirectoryHeader(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryHeader directoryHeader = new DirectoryHeader();
var directoryHeader = data.ReadType<DirectoryHeader>();
directoryHeader.Dummy0 = data.ReadUInt32();
if (directoryHeader == null)
return null;
if (directoryHeader.Dummy0 != 0x00000004)
return null;
directoryHeader.CacheID = data.ReadUInt32();
directoryHeader.LastVersionPlayed = data.ReadUInt32();
directoryHeader.ItemCount = data.ReadUInt32();
directoryHeader.FileCount = data.ReadUInt32();
directoryHeader.ChecksumDataLength = data.ReadUInt32();
directoryHeader.DirectorySize = data.ReadUInt32();
directoryHeader.NameSize = data.ReadUInt32();
directoryHeader.Info1Count = data.ReadUInt32();
directoryHeader.CopyCount = data.ReadUInt32();
directoryHeader.LocalCount = data.ReadUInt32();
directoryHeader.Dummy1 = data.ReadUInt32();
directoryHeader.Dummy2 = data.ReadUInt32();
directoryHeader.Checksum = data.ReadUInt32();
return directoryHeader;
}
@@ -323,10 +320,10 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life No Cache directory entry on success, null on error</returns>
private static DirectoryEntry ParseDirectoryEntry(Stream data)
private static DirectoryEntry? ParseDirectoryEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryEntry directoryEntry = new DirectoryEntry();
var directoryEntry = new DirectoryEntry();
directoryEntry.NameOffset = data.ReadUInt32();
directoryEntry.ItemSize = data.ReadUInt32();
@@ -344,14 +341,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life No Cache directory info 1 entry on success, null on error</returns>
private static DirectoryInfo1Entry ParseDirectoryInfo1Entry(Stream data)
private static DirectoryInfo1Entry? ParseDirectoryInfo1Entry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryInfo1Entry directoryInfo1Entry = new DirectoryInfo1Entry();
directoryInfo1Entry.Dummy0 = data.ReadUInt32();
return directoryInfo1Entry;
return data.ReadType<DirectoryInfo1Entry>();
}
/// <summary>
@@ -359,14 +351,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life No Cache directory info 2 entry on success, null on error</returns>
private static DirectoryInfo2Entry ParseDirectoryInfo2Entry(Stream data)
private static DirectoryInfo2Entry? ParseDirectoryInfo2Entry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryInfo2Entry directoryInfo2Entry = new DirectoryInfo2Entry();
directoryInfo2Entry.Dummy0 = data.ReadUInt32();
return directoryInfo2Entry;
return data.ReadType<DirectoryInfo2Entry>();
}
/// <summary>
@@ -374,14 +361,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life No Cache directory copy entry on success, null on error</returns>
private static DirectoryCopyEntry ParseDirectoryCopyEntry(Stream data)
private static DirectoryCopyEntry? ParseDirectoryCopyEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryCopyEntry directoryCopyEntry = new DirectoryCopyEntry();
directoryCopyEntry.DirectoryIndex = data.ReadUInt32();
return directoryCopyEntry;
return data.ReadType<DirectoryCopyEntry>();
}
/// <summary>
@@ -389,14 +371,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life No Cache directory local entry on success, null on error</returns>
private static DirectoryLocalEntry ParseDirectoryLocalEntry(Stream data)
private static DirectoryLocalEntry? ParseDirectoryLocalEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryLocalEntry directoryLocalEntry = new DirectoryLocalEntry();
directoryLocalEntry.DirectoryIndex = data.ReadUInt32();
return directoryLocalEntry;
return data.ReadType<DirectoryLocalEntry>();
}
/// <summary>
@@ -406,14 +383,12 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life No Cache unknown header on success, null on error</returns>
private static UnknownHeader? ParseUnknownHeader(Stream data)
{
// TODO: Use marshalling here instead of building
UnknownHeader unknownHeader = new UnknownHeader();
var unknownHeader = data.ReadType<UnknownHeader>();
unknownHeader.Dummy0 = data.ReadUInt32();
if (unknownHeader == null)
return null;
if (unknownHeader.Dummy0 != 0x00000001)
return null;
unknownHeader.Dummy1 = data.ReadUInt32();
if (unknownHeader.Dummy1 != 0x00000000)
return null;
@@ -425,14 +400,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life No Cacheunknown entry on success, null on error</returns>
private static UnknownEntry ParseUnknownEntry(Stream data)
private static UnknownEntry? ParseUnknownEntry(Stream data)
{
// TODO: Use marshalling here instead of building
UnknownEntry unknownEntry = new UnknownEntry();
unknownEntry.Dummy0 = data.ReadUInt32();
return unknownEntry;
return data.ReadType<UnknownEntry>();
}
/// <summary>
@@ -442,15 +412,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life No Cache checksum header on success, null on error</returns>
private static ChecksumHeader? ParseChecksumHeader(Stream data)
{
// TODO: Use marshalling here instead of building
ChecksumHeader checksumHeader = new ChecksumHeader();
var checksumHeader = data.ReadType<ChecksumHeader>();
checksumHeader.Dummy0 = data.ReadUInt32();
if (checksumHeader == null)
return null;
if (checksumHeader.Dummy0 != 0x00000001)
return null;
checksumHeader.ChecksumSize = data.ReadUInt32();
return checksumHeader;
}
@@ -461,20 +429,15 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life No Cache checksum map header on success, null on error</returns>
private static ChecksumMapHeader? ParseChecksumMapHeader(Stream data)
{
// TODO: Use marshalling here instead of building
ChecksumMapHeader checksumMapHeader = new ChecksumMapHeader();
var checksumMapHeader = data.ReadType<ChecksumMapHeader>();
checksumMapHeader.Dummy0 = data.ReadUInt32();
if (checksumMapHeader == null)
return null;
if (checksumMapHeader.Dummy0 != 0x14893721)
return null;
checksumMapHeader.Dummy1 = data.ReadUInt32();
if (checksumMapHeader.Dummy1 != 0x00000001)
return null;
checksumMapHeader.ItemCount = data.ReadUInt32();
checksumMapHeader.ChecksumCount = data.ReadUInt32();
return checksumMapHeader;
}
@@ -483,15 +446,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life No Cache checksum map entry on success, null on error</returns>
private static ChecksumMapEntry ParseChecksumMapEntry(Stream data)
private static ChecksumMapEntry? ParseChecksumMapEntry(Stream data)
{
// TODO: Use marshalling here instead of building
ChecksumMapEntry checksumMapEntry = new ChecksumMapEntry();
checksumMapEntry.ChecksumCount = data.ReadUInt32();
checksumMapEntry.FirstChecksumIndex = data.ReadUInt32();
return checksumMapEntry;
return data.ReadType<ChecksumMapEntry>();
}
/// <summary>
@@ -499,14 +456,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life No Cache checksum entry on success, null on error</returns>
private static ChecksumEntry ParseChecksumEntry(Stream data)
private static ChecksumEntry? ParseChecksumEntry(Stream data)
{
// TODO: Use marshalling here instead of building
ChecksumEntry checksumEntry = new ChecksumEntry();
checksumEntry.Checksum = data.ReadUInt32();
return checksumEntry;
return data.ReadType<ChecksumEntry>();
}
}
}

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.NewExecutable;
using static SabreTools.Models.NewExecutable.Constants;
@@ -214,48 +213,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled executable header on success, null on error</returns>
public static ExecutableHeader? ParseExecutableHeader(Stream data)
{
// TODO: Use marshalling here instead of building
var header = new ExecutableHeader();
var header = data.ReadType<ExecutableHeader>();
byte[]? magic = data.ReadBytes(2);
if (magic == null)
if (header == null)
return null;
header.Magic = Encoding.ASCII.GetString(magic);
if (header.Magic != SignatureString)
return null;
header.LinkerVersion = data.ReadByteValue();
header.LinkerRevision = data.ReadByteValue();
header.EntryTableOffset = data.ReadUInt16();
header.EntryTableSize = data.ReadUInt16();
header.CrcChecksum = data.ReadUInt32();
header.FlagWord = (HeaderFlag)data.ReadUInt16();
header.AutomaticDataSegmentNumber = data.ReadUInt16();
header.InitialHeapAlloc = data.ReadUInt16();
header.InitialStackAlloc = data.ReadUInt16();
header.InitialCSIPSetting = data.ReadUInt32();
header.InitialSSSPSetting = data.ReadUInt32();
header.FileSegmentCount = data.ReadUInt16();
header.ModuleReferenceTableSize = data.ReadUInt16();
header.NonResidentNameTableSize = data.ReadUInt16();
header.SegmentTableOffset = data.ReadUInt16();
header.ResourceTableOffset = data.ReadUInt16();
header.ResidentNameTableOffset = data.ReadUInt16();
header.ModuleReferenceTableOffset = data.ReadUInt16();
header.ImportedNamesTableOffset = data.ReadUInt16();
header.NonResidentNamesTableOffset = data.ReadUInt32();
header.MovableEntriesCount = data.ReadUInt16();
header.SegmentAlignmentShiftCount = data.ReadUInt16();
header.ResourceEntriesCount = data.ReadUInt16();
header.TargetOperatingSystem = (OperatingSystem)data.ReadByteValue();
header.AdditionalFlags = (OS2Flag)data.ReadByteValue();
header.ReturnThunkOffset = data.ReadUInt16();
header.SegmentReferenceThunkOffset = data.ReadUInt16();
header.MinCodeSwapAreaSize = data.ReadUInt16();
header.WindowsSDKRevision = data.ReadByteValue();
header.WindowsSDKVersion = data.ReadByteValue();
return header;
}
@@ -265,31 +229,40 @@ namespace SabreTools.Serialization.Deserializers
/// <param name="data">Stream to parse</param>
/// <param name="count">Number of segment table entries to read</param>
/// <returns>Filled segment table on success, null on error</returns>
public static SegmentTableEntry[] ParseSegmentTable(Stream data, int count)
public static SegmentTableEntry[]? ParseSegmentTable(Stream data, int count)
{
// TODO: Use marshalling here instead of building
var segmentTable = new SegmentTableEntry[count];
for (int i = 0; i < count; i++)
{
var entry = new SegmentTableEntry();
entry.Offset = data.ReadUInt16();
entry.Length = data.ReadUInt16();
entry.FlagWord = (SegmentTableEntryFlag)data.ReadUInt16();
entry.MinimumAllocationSize = data.ReadUInt16();
var entry = ParseSegmentTableEntry(data);
if (entry == null)
return null;
segmentTable[i] = entry;
}
return segmentTable;
}
/// <summary>
/// Parse a Stream into a segment table entry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled segment table entry on success, null on error</returns>
public static SegmentTableEntry? ParseSegmentTableEntry(Stream data)
{
return data.ReadType<SegmentTableEntry>();
}
/// <summary>
/// Parse a Stream into a resource table
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="count">Number of resource table entries to read</param>
/// <returns>Filled resource table on success, null on error</returns>
public static ResourceTable ParseResourceTable(Stream data, int count)
public static ResourceTable? ParseResourceTable(Stream data, int count)
{
long initialOffset = data.Position;
@@ -308,12 +281,10 @@ namespace SabreTools.Serialization.Deserializers
for (int j = 0; j < entry.ResourceCount; j++)
{
// TODO: Should we read and store the resource data?
var resource = new ResourceTypeResourceEntry();
resource.Offset = data.ReadUInt16();
resource.Length = data.ReadUInt16();
resource.FlagWord = (ResourceTypeResourceFlag)data.ReadUInt16();
resource.ResourceID = data.ReadUInt16();
resource.Reserved = data.ReadUInt32();
var resource = ParseResourceTypeResourceEntry(data);
if (resource == null)
return null;
entry.Resources[j] = resource;
}
resourceTable.ResourceTypes[i] = entry;
@@ -339,66 +310,124 @@ namespace SabreTools.Serialization.Deserializers
{
int stringOffset = (int)(stringOffsets[i] + initialOffset);
data.Seek(stringOffset, SeekOrigin.Begin);
var str = new ResourceTypeAndNameString();
str.Length = data.ReadByteValue();
str.Text = data.ReadBytes(str.Length);
var str = ParseResourceTypeAndNameString(data);
if (str == null)
return null;
resourceTable.TypeAndNameStrings[stringOffsets[i]] = str;
}
return resourceTable;
}
/// <summary>
/// Parse a Stream into a resource entry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled resource entry on success, null on error</returns>
public static ResourceTypeResourceEntry? ParseResourceTypeResourceEntry(Stream data)
{
// TODO: Should we read and store the resource data?
return data.ReadType<ResourceTypeResourceEntry>();
}
/// <summary>
/// Parse a Stream into a resource type and name string
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled resource type and name string on success, null on error</returns>
public static ResourceTypeAndNameString? ParseResourceTypeAndNameString(Stream data)
{
// TODO: Use marshalling here instead of building
var str = new ResourceTypeAndNameString();
str.Length = data.ReadByteValue();
str.Text = data.ReadBytes(str.Length);
return str;
}
/// <summary>
/// Parse a Stream into a resident-name table
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="endOffset">First address not part of the resident-name table</param>
/// <returns>Filled resident-name table on success, null on error</returns>
public static ResidentNameTableEntry[] ParseResidentNameTable(Stream data, int endOffset)
public static ResidentNameTableEntry[]? ParseResidentNameTable(Stream data, int endOffset)
{
// TODO: Use marshalling here instead of building
var residentNameTable = new List<ResidentNameTableEntry>();
while (data.Position < endOffset)
{
var entry = new ResidentNameTableEntry();
entry.Length = data.ReadByteValue();
entry.NameString = data.ReadBytes(entry.Length);
entry.OrdinalNumber = data.ReadUInt16();
var entry = ParseResidentNameTableEntry(data);
if (entry == null)
return null;
residentNameTable.Add(entry);
}
return [.. residentNameTable];
}
/// <summary>
/// Parse a Stream into a resident-name table entry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled resident-name table entry on success, null on error</returns>
public static ResidentNameTableEntry? ParseResidentNameTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new ResidentNameTableEntry();
entry.Length = data.ReadByteValue();
entry.NameString = data.ReadBytes(entry.Length);
entry.OrdinalNumber = data.ReadUInt16();
return entry;
}
/// <summary>
/// Parse a Stream into a module-reference table
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="count">Number of module-reference table entries to read</param>
/// <returns>Filled module-reference table on success, null on error</returns>
public static ModuleReferenceTableEntry[] ParseModuleReferenceTable(Stream data, int count)
public static ModuleReferenceTableEntry[]? ParseModuleReferenceTable(Stream data, int count)
{
// TODO: Use marshalling here instead of building
var moduleReferenceTable = new ModuleReferenceTableEntry[count];
for (int i = 0; i < count; i++)
{
var entry = new ModuleReferenceTableEntry();
entry.Offset = data.ReadUInt16();
var entry = ParseModuleReferenceTableEntry(data);
if (entry == null)
return null;
moduleReferenceTable[i] = entry;
}
return moduleReferenceTable;
}
/// <summary>
/// Parse a Stream into a module-reference table entry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled module-reference table entry on success, null on error</returns>
public static ModuleReferenceTableEntry? ParseModuleReferenceTableEntry(Stream data)
{
return data.ReadType<ModuleReferenceTableEntry>();
}
/// <summary>
/// Parse a Stream into an imported-name table
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="endOffset">First address not part of the imported-name table</param>
/// <returns>Filled imported-name table on success, null on error</returns>
public static Dictionary<ushort, ImportedNameTableEntry?> ParseImportedNameTable(Stream data, int endOffset)
public static Dictionary<ushort, ImportedNameTableEntry?>? ParseImportedNameTable(Stream data, int endOffset)
{
// TODO: Use marshalling here instead of building
var importedNameTable = new Dictionary<ushort, ImportedNameTableEntry?>();
@@ -406,15 +435,32 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < endOffset)
{
ushort currentOffset = (ushort)data.Position;
var entry = new ImportedNameTableEntry();
entry.Length = data.ReadByteValue();
entry.NameString = data.ReadBytes(entry.Length);
var entry = ParseImportedNameTableEntry(data);
if (entry == null)
return null;
importedNameTable[currentOffset] = entry;
}
return importedNameTable;
}
/// <summary>
/// Parse a Stream into an imported-name table entry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled imported-name table entry on success, null on error</returns>
public static ImportedNameTableEntry? ParseImportedNameTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new ImportedNameTableEntry();
entry.Length = data.ReadByteValue();
entry.NameString = data.ReadBytes(entry.Length);
return entry;
}
/// <summary>
/// Parse a Stream into an entry table
/// </summary>
@@ -460,21 +506,38 @@ namespace SabreTools.Serialization.Deserializers
/// <param name="data">Stream to parse</param>
/// <param name="endOffset">First address not part of the nonresident-name table</param>
/// <returns>Filled nonresident-name table on success, null on error</returns>
public static NonResidentNameTableEntry[] ParseNonResidentNameTable(Stream data, int endOffset)
public static NonResidentNameTableEntry[]? ParseNonResidentNameTable(Stream data, int endOffset)
{
// TODO: Use marshalling here instead of building
var residentNameTable = new List<NonResidentNameTableEntry>();
while (data.Position < endOffset)
{
var entry = new NonResidentNameTableEntry();
entry.Length = data.ReadByteValue();
entry.NameString = data.ReadBytes(entry.Length);
entry.OrdinalNumber = data.ReadUInt16();
var entry = ParseNonResidentNameTableEntry(data);
if (entry == null)
return null;
residentNameTable.Add(entry);
}
return [.. residentNameTable];
}
/// <summary>
/// Parse a Stream into a nonresident-name table entry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled nonresident-name table entry on success, null on error</returns>
public static NonResidentNameTableEntry? ParseNonResidentNameTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
var entry = new NonResidentNameTableEntry();
entry.Length = data.ReadByteValue();
entry.NameString = data.ReadBytes(entry.Length);
entry.OrdinalNumber = data.ReadUInt16();
return entry;
}
}
}

View File

@@ -184,7 +184,7 @@ namespace SabreTools.Serialization.Deserializers
private static ExtendedDSiHeader ParseExtendedDSiHeader(Stream data)
{
// TODO: Use marshalling here instead of building
ExtendedDSiHeader extendedDSiHeader = new ExtendedDSiHeader();
var extendedDSiHeader = new ExtendedDSiHeader();
extendedDSiHeader.GlobalMBK15Settings = new uint[5];
for (int i = 0; i < 5; i++)
@@ -226,6 +226,8 @@ namespace SabreTools.Serialization.Deserializers
extendedDSiHeader.DigestBlockSectorCount = data.ReadUInt32();
extendedDSiHeader.IconBannerSize = data.ReadUInt32();
extendedDSiHeader.Unknown1 = data.ReadUInt32();
extendedDSiHeader.NTRTWLRegionRomSize = data.ReadUInt32();
extendedDSiHeader.Unknown2 = data.ReadBytes(12);
extendedDSiHeader.ModcryptArea1Offset = data.ReadUInt32();
extendedDSiHeader.ModcryptArea1Size = data.ReadUInt32();
extendedDSiHeader.ModcryptArea2Offset = data.ReadUInt32();
@@ -304,7 +306,7 @@ namespace SabreTools.Serialization.Deserializers
private static FolderAllocationTableEntry ParseFolderAllocationTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
FolderAllocationTableEntry entry = new FolderAllocationTableEntry();
var entry = new FolderAllocationTableEntry();
entry.StartOffset = data.ReadUInt32();
entry.FirstFileIndex = data.ReadUInt16();
@@ -322,7 +324,7 @@ namespace SabreTools.Serialization.Deserializers
private static NameListEntry? ParseNameListEntry(Stream data)
{
// TODO: Use marshalling here instead of building
NameListEntry entry = new NameListEntry();
var entry = new NameListEntry();
byte flagAndSize = data.ReadByteValue();
if (flagAndSize == 0xFF)
@@ -352,7 +354,7 @@ namespace SabreTools.Serialization.Deserializers
private static FileAllocationTableEntry ParseFileAllocationTableEntry(Stream data)
{
// TODO: Use marshalling here instead of building
FileAllocationTableEntry entry = new FileAllocationTableEntry();
var entry = new FileAllocationTableEntry();
entry.StartOffset = data.ReadUInt32();
entry.EndOffset = data.ReadUInt32();

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.PAK;
using static SabreTools.Models.PAK.Constants;
@@ -54,6 +53,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < file.DirectoryItems.Length; i++)
{
var directoryItem = ParseDirectoryItem(data);
if (directoryItem == null)
return null;
file.DirectoryItems[i] = directoryItem;
}
@@ -69,20 +71,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Half-Life Package header on success, null on error</returns>
private static Header? ParseHeader(Stream data)
{
// TODO: Use marshalling here instead of building
Header header = new Header();
var header = data.ReadType<Header>();
byte[]? signature = data.ReadBytes(4);
if (signature == null)
if (header == null)
return null;
header.Signature = Encoding.ASCII.GetString(signature);
if (header.Signature != SignatureString)
return null;
header.DirectoryOffset = data.ReadUInt32();
header.DirectoryLength = data.ReadUInt32();
return header;
}
@@ -91,18 +86,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Half-Life Package directory item on success, null on error</returns>
private static DirectoryItem ParseDirectoryItem(Stream data)
private static DirectoryItem? ParseDirectoryItem(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryItem directoryItem = new DirectoryItem();
byte[]? itemName = data.ReadBytes(56);
if (itemName != null)
directoryItem.ItemName = Encoding.ASCII.GetString(itemName).TrimEnd('\0');
directoryItem.ItemOffset = data.ReadUInt32();
directoryItem.ItemLength = data.ReadUInt32();
return directoryItem;
return data.ReadType<DirectoryItem>();
}
}
}

View File

@@ -1,4 +1,5 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.PFF;
@@ -92,47 +93,27 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled header on success, null on error</returns>
private static Header? ParseHeader(Stream data)
{
// TODO: Use marshalling here instead of building
Header header = new Header();
header.HeaderSize = data.ReadUInt32();
byte[]? signature = data.ReadBytes(4);
if (signature == null)
var header = data.ReadType<Header>();
if (header == null)
return null;
header.Signature = Encoding.ASCII.GetString(signature);
header.NumberOfFiles = data.ReadUInt32();
header.FileSegmentSize = data.ReadUInt32();
switch (header.Signature)
return header.Signature switch
{
case Version0SignatureString:
if (header.FileSegmentSize != Version0HSegmentSize)
return null;
break;
Version0SignatureString when header.FileSegmentSize != Version0HSegmentSize => null,
Version0SignatureString => header,
case Version2SignatureString:
if (header.FileSegmentSize != Version2SegmentSize)
return null;
break;
Version2SignatureString when header.FileSegmentSize != Version2SegmentSize => null,
Version2SignatureString => header,
// Version 3 can sometimes have Version 2 segment sizes
case Version3SignatureString:
if (header.FileSegmentSize != Version2SegmentSize && header.FileSegmentSize != Version3SegmentSize)
return null;
break;
Version3SignatureString when header.FileSegmentSize != Version2SegmentSize
&& header.FileSegmentSize != Version3SegmentSize => null,
Version3SignatureString => header,
case Version4SignatureString:
if (header.FileSegmentSize != Version4SegmentSize)
return null;
break;
Version4SignatureString when header.FileSegmentSize != Version4SegmentSize => null,
Version4SignatureString => header,
default:
return null;
}
header.FileListOffset = data.ReadUInt32();
return header;
_ => null,
};
}
/// <summary>
@@ -140,18 +121,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled footer on success, null on error</returns>
private static Footer ParseFooter(Stream data)
private static Footer? ParseFooter(Stream data)
{
// TODO: Use marshalling here instead of building
Footer footer = new Footer();
footer.SystemIP = data.ReadUInt32();
footer.Reserved = data.ReadUInt32();
byte[]? kingTag = data.ReadBytes(4);
if (kingTag != null)
footer.KingTag = Encoding.ASCII.GetString(kingTag);
return footer;
return data.ReadType<Footer>();
}
/// <summary>
@@ -163,7 +135,7 @@ namespace SabreTools.Serialization.Deserializers
private static Segment ParseSegment(Stream data, uint segmentSize)
{
// TODO: Use marshalling here instead of building
Segment segment = new Segment();
var segment = new Segment();
segment.Deleted = data.ReadUInt32();
segment.FileLocation = data.ReadUInt32();

View File

@@ -106,25 +106,12 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled disc information unit header on success, null on error</returns>
private static DiscInformationUnitHeader? ParseDiscInformationUnitHeader(Stream data)
{
// TODO: Use marshalling here instead of building
var header = new DiscInformationUnitHeader();
var header = data.ReadType<DiscInformationUnitHeader>();
// We only accept Disc Information units, not Emergency Brake or other
byte[]? dic = data.ReadBytes(2);
if (dic == null)
if (header?.DiscInformationIdentifier != "DI")
return null;
header.DiscInformationIdentifier = Encoding.ASCII.GetString(dic);
if (header.DiscInformationIdentifier != "DI")
return null;
header.DiscInformationFormat = data.ReadByteValue();
header.NumberOfUnitsInBlock = data.ReadByteValue();
header.Reserved0 = data.ReadByteValue();
header.SequenceNumber = data.ReadByteValue();
header.BytesInUse = data.ReadByteValue();
header.Reserved1 = data.ReadByteValue();
return header;
}
@@ -165,17 +152,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled disc information unit trailer on success, null on error</returns>
private static DiscInformationUnitTrailer ParseDiscInformationUnitTrailer(Stream data)
private static DiscInformationUnitTrailer? ParseDiscInformationUnitTrailer(Stream data)
{
// TODO: Use marshalling here instead of building
var trailer = new DiscInformationUnitTrailer();
trailer.DiscManufacturerID = data.ReadBytes(6);
trailer.MediaTypeID = data.ReadBytes(3);
trailer.TimeStamp = data.ReadUInt16();
trailer.ProductRevisionNumber = data.ReadByteValue();
return trailer;
return data.ReadType<DiscInformationUnitTrailer>();
}
#endregion

View File

@@ -203,7 +203,7 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the debug table
data.Seek(debugTableAddress, SeekOrigin.Begin);
int endOffset = (int)(debugTableAddress + optionalHeader.Debug.Size);
var debugTable = ParseDebugTable(data, endOffset, executable.SectionTable);
var debugTable = ParseDebugTable(data, endOffset);
if (debugTable == null)
return null;
@@ -291,20 +291,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled executable header on success, null on error</returns>
public static COFFFileHeader ParseCOFFFileHeader(Stream data)
public static COFFFileHeader? ParseCOFFFileHeader(Stream data)
{
// TODO: Use marshalling here instead of building
var fileHeader = new COFFFileHeader();
fileHeader.Machine = (MachineType)data.ReadUInt16();
fileHeader.NumberOfSections = data.ReadUInt16();
fileHeader.TimeDateStamp = data.ReadUInt32();
fileHeader.PointerToSymbolTable = data.ReadUInt32();
fileHeader.NumberOfSymbols = data.ReadUInt32();
fileHeader.SizeOfOptionalHeader = data.ReadUInt16();
fileHeader.Characteristics = (Characteristics)data.ReadUInt16();
return fileHeader;
return data.ReadType<COFFFileHeader>();
}
/// <summary>
@@ -380,97 +369,52 @@ namespace SabreTools.Serialization.Deserializers
#region Data Directories
if (optionalHeader.NumberOfRvaAndSizes >= 1 && data.Position - initialOffset < optionalSize)
{
optionalHeader.ExportTable = new DataDirectory();
optionalHeader.ExportTable.VirtualAddress = data.ReadUInt32();
optionalHeader.ExportTable.Size = data.ReadUInt32();
}
optionalHeader.ExportTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 2 && data.Position - initialOffset < optionalSize)
{
optionalHeader.ImportTable = new DataDirectory();
optionalHeader.ImportTable.VirtualAddress = data.ReadUInt32();
optionalHeader.ImportTable.Size = data.ReadUInt32();
}
optionalHeader.ImportTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 3 && data.Position - initialOffset < optionalSize)
{
optionalHeader.ResourceTable = new DataDirectory();
optionalHeader.ResourceTable.VirtualAddress = data.ReadUInt32();
optionalHeader.ResourceTable.Size = data.ReadUInt32();
}
optionalHeader.ResourceTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 4 && data.Position - initialOffset < optionalSize)
{
optionalHeader.ExceptionTable = new DataDirectory();
optionalHeader.ExceptionTable.VirtualAddress = data.ReadUInt32();
optionalHeader.ExceptionTable.Size = data.ReadUInt32();
}
optionalHeader.ExceptionTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 5 && data.Position - initialOffset < optionalSize)
{
optionalHeader.CertificateTable = new DataDirectory();
optionalHeader.CertificateTable.VirtualAddress = data.ReadUInt32();
optionalHeader.CertificateTable.Size = data.ReadUInt32();
}
optionalHeader.CertificateTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 6 && data.Position - initialOffset < optionalSize)
{
optionalHeader.BaseRelocationTable = new DataDirectory();
optionalHeader.BaseRelocationTable.VirtualAddress = data.ReadUInt32();
optionalHeader.BaseRelocationTable.Size = data.ReadUInt32();
}
optionalHeader.BaseRelocationTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 7 && data.Position - initialOffset < optionalSize)
{
optionalHeader.Debug = new DataDirectory();
optionalHeader.Debug.VirtualAddress = data.ReadUInt32();
optionalHeader.Debug.Size = data.ReadUInt32();
}
optionalHeader.Debug = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 8 && data.Position - initialOffset < optionalSize)
{
optionalHeader.Architecture = data.ReadUInt64();
}
if (optionalHeader.NumberOfRvaAndSizes >= 9 && data.Position - initialOffset < optionalSize)
{
optionalHeader.GlobalPtr = new DataDirectory();
optionalHeader.GlobalPtr.VirtualAddress = data.ReadUInt32();
optionalHeader.GlobalPtr.Size = data.ReadUInt32();
}
optionalHeader.GlobalPtr = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 10 && data.Position - initialOffset < optionalSize)
{
optionalHeader.ThreadLocalStorageTable = new DataDirectory();
optionalHeader.ThreadLocalStorageTable.VirtualAddress = data.ReadUInt32();
optionalHeader.ThreadLocalStorageTable.Size = data.ReadUInt32();
}
optionalHeader.ThreadLocalStorageTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 11 && data.Position - initialOffset < optionalSize)
{
optionalHeader.LoadConfigTable = new DataDirectory();
optionalHeader.LoadConfigTable.VirtualAddress = data.ReadUInt32();
optionalHeader.LoadConfigTable.Size = data.ReadUInt32();
}
optionalHeader.LoadConfigTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 12 && data.Position - initialOffset < optionalSize)
{
optionalHeader.BoundImport = new DataDirectory();
optionalHeader.BoundImport.VirtualAddress = data.ReadUInt32();
optionalHeader.BoundImport.Size = data.ReadUInt32();
}
optionalHeader.BoundImport = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 13 && data.Position - initialOffset < optionalSize)
{
optionalHeader.ImportAddressTable = new DataDirectory();
optionalHeader.ImportAddressTable.VirtualAddress = data.ReadUInt32();
optionalHeader.ImportAddressTable.Size = data.ReadUInt32();
}
optionalHeader.ImportAddressTable = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 14 && data.Position - initialOffset < optionalSize)
{
optionalHeader.DelayImportDescriptor = new DataDirectory();
optionalHeader.DelayImportDescriptor.VirtualAddress = data.ReadUInt32();
optionalHeader.DelayImportDescriptor.Size = data.ReadUInt32();
}
optionalHeader.DelayImportDescriptor = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 15 && data.Position - initialOffset < optionalSize)
{
optionalHeader.CLRRuntimeHeader = new DataDirectory();
optionalHeader.CLRRuntimeHeader.VirtualAddress = data.ReadUInt32();
optionalHeader.CLRRuntimeHeader.Size = data.ReadUInt32();
}
optionalHeader.CLRRuntimeHeader = data.ReadType<DataDirectory>();
if (optionalHeader.NumberOfRvaAndSizes >= 16 && data.Position - initialOffset < optionalSize)
{
optionalHeader.Reserved = data.ReadUInt64();
}
#endregion
@@ -742,21 +686,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled delay-load directory table on success, null on error</returns>
public static DelayLoadDirectoryTable ParseDelayLoadDirectoryTable(Stream data)
public static DelayLoadDirectoryTable? ParseDelayLoadDirectoryTable(Stream data)
{
// TODO: Use marshalling here instead of building
var delayLoadDirectoryTable = new DelayLoadDirectoryTable();
delayLoadDirectoryTable.Attributes = data.ReadUInt32();
delayLoadDirectoryTable.Name = data.ReadUInt32();
delayLoadDirectoryTable.ModuleHandle = data.ReadUInt32();
delayLoadDirectoryTable.DelayImportAddressTable = data.ReadUInt32();
delayLoadDirectoryTable.DelayImportNameTable = data.ReadUInt32();
delayLoadDirectoryTable.BoundDelayImportTable = data.ReadUInt32();
delayLoadDirectoryTable.UnloadDelayImportTable = data.ReadUInt32();
delayLoadDirectoryTable.TimeStamp = data.ReadUInt32();
return delayLoadDirectoryTable;
return data.ReadType<DelayLoadDirectoryTable>();
}
/// <summary>
@@ -805,9 +737,8 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <param name="endOffset">First address not part of the debug table</param>
/// <param name="sections">Section table to use for virtual address translation</param>
/// <returns>Filled debug table on success, null on error</returns>
public static DebugTable ParseDebugTable(Stream data, int endOffset, SectionHeader?[] sections)
public static DebugTable? ParseDebugTable(Stream data, int endOffset)
{
// TODO: Use marshalling here instead of building
var debugTable = new DebugTable();
@@ -816,21 +747,14 @@ namespace SabreTools.Serialization.Deserializers
while (data.Position < endOffset)
{
var debugDirectoryEntry = new DebugDirectoryEntry();
debugDirectoryEntry.Characteristics = data.ReadUInt32();
debugDirectoryEntry.TimeDateStamp = data.ReadUInt32();
debugDirectoryEntry.MajorVersion = data.ReadUInt16();
debugDirectoryEntry.MinorVersion = data.ReadUInt16();
debugDirectoryEntry.DebugType = (DebugType)data.ReadUInt32();
debugDirectoryEntry.SizeOfData = data.ReadUInt32();
debugDirectoryEntry.AddressOfRawData = data.ReadUInt32();
debugDirectoryEntry.PointerToRawData = data.ReadUInt32();
var debugDirectoryEntry = data.ReadType<DebugDirectoryEntry>();
if (debugDirectoryEntry == null)
return null;
debugDirectoryTable.Add(debugDirectoryEntry);
}
debugTable.DebugDirectoryTable = debugDirectoryTable.ToArray();
debugTable.DebugDirectoryTable = [.. debugDirectoryTable];
// TODO: Should we read the debug data in? Most of it is unformatted or undocumented
// TODO: Implement .debug$F (Object Only) / IMAGE_DEBUG_TYPE_FPO
@@ -844,7 +768,7 @@ namespace SabreTools.Serialization.Deserializers
/// <param name="data">Stream to parse</param>
/// <param name="sections">Section table to use for virtual address translation</param>
/// <returns>Filled export table on success, null on error</returns>
public static ExportTable ParseExportTable(Stream data, SectionHeader?[] sections)
public static ExportTable? ParseExportTable(Stream data, SectionHeader?[] sections)
{
// TODO: Use marshalling here instead of building
var exportTable = new ExportTable();
@@ -885,11 +809,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < exportDirectoryTable.AddressTableEntries; i++)
{
var addressTableEntry = new ExportAddressTableEntry();
// TODO: Use the optional header address and length to determine if export or forwarder
addressTableEntry.ExportRVA = data.ReadUInt32();
addressTableEntry.ForwarderRVA = addressTableEntry.ExportRVA;
var addressTableEntry = data.ReadType<ExportAddressTableEntry>();
if (addressTableEntry == null)
return null;
exportAddressTable[i] = addressTableEntry;
}

View File

@@ -73,23 +73,13 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled header on success, null on error</returns>
private static Header? ParseHeader(Stream data)
{
// TODO: Use marshalling here instead of building
Header header = new Header();
var header = data.ReadType<Header>();
byte[]? signature = data.ReadBytes(2);
if (signature == null)
if (header == null)
return null;
header.Signature = Encoding.ASCII.GetString(signature);
if (header.Signature != SignatureString)
return null;
header.MajorVersion = data.ReadByteValue();
header.MinorVersion = data.ReadByteValue();
header.FileCount = data.ReadUInt16();
header.TableSize = data.ReadByteValue();
header.CompressionFlags = data.ReadByteValue();
return header;
}
@@ -102,7 +92,7 @@ namespace SabreTools.Serialization.Deserializers
private static FileDescriptor ParseFileDescriptor(Stream data, byte minorVersion)
{
// TODO: Use marshalling here instead of building
FileDescriptor fileDescriptor = new FileDescriptor();
var fileDescriptor = new FileDescriptor();
fileDescriptor.FileNameSize = ReadVariableLength(data);
if (fileDescriptor.FileNameSize > 0)

View File

@@ -0,0 +1,35 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
namespace SabreTools.Serialization.Deserializers
{
public class SFB : BaseBinaryDeserializer<Models.PlayStation3.SFB>
{
/// <inheritdoc/>
public override Models.PlayStation3.SFB? Deserialize(Stream? data)
{
// If the data is invalid
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
return null;
// If the offset is out of bounds
if (data.Position < 0 || data.Position >= data.Length)
return null;
// Cache the current offset
int initialOffset = (int)data.Position;
// Deserialize the SFB
var sfb = data.ReadType<Models.PlayStation3.SFB>();
if (sfb == null)
return null;
string magic = Encoding.ASCII.GetString(sfb.Magic);
if (magic != ".SFB")
return null;
return sfb;
}
}
}

View File

@@ -0,0 +1,91 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
namespace SabreTools.Serialization.Deserializers
{
public class SFO : BaseBinaryDeserializer<Models.PlayStation3.SFO>
{
/// <inheritdoc/>
public override Models.PlayStation3.SFO? Deserialize(Stream? data)
{
// If the data is invalid
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
return null;
// If the offset is out of bounds
if (data.Position < 0 || data.Position >= data.Length)
return null;
// Cache the current offset
int initialOffset = (int)data.Position;
// Create a new SFO to fill
var sfo = new Models.PlayStation3.SFO();
#region Header
// Try to parse the header
var header = ParseHeader(data);
if (header == null)
return null;
// Assign the header
sfo.Header = header;
#endregion
#region Index Table
// TODO: Determine how many entries are in the index table
#endregion
#region Key Table
// TODO: Finish implementation
#endregion
// Padding
// TODO: Finish implementation
#region Data Table
// TODO: Finish implementation
#endregion
return sfo;
}
/// <summary>
/// Parse a Stream into an SFO header
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SFO header on success, null on error</returns>
public Models.PlayStation3.SFOHeader? ParseHeader(Stream data)
{
var sfoHeader = data.ReadType<Models.PlayStation3.SFOHeader>();
if (sfoHeader == null)
return null;
string magic = Encoding.ASCII.GetString(sfoHeader.Magic);
if (magic != "\0PSF")
return null;
return sfoHeader;
}
/// <summary>
/// Parse a Stream into an SFO index table entry
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled SFO index table entry on success, null on error</returns>
public Models.PlayStation3.SFOIndexTableEntry? ParseIndexTableEntry(Stream data)
{
return data.ReadType<Models.PlayStation3.SFOIndexTableEntry>();
}
}
}

View File

@@ -65,7 +65,11 @@ namespace SabreTools.Serialization.Deserializers
header.Lumps = new Lump[HL_VBSP_LUMP_COUNT];
for (int i = 0; i < HL_VBSP_LUMP_COUNT; i++)
{
header.Lumps[i] = ParseLump(data, header.Version);
var lump = ParseLump(data, header.Version);
if (lump == null)
return null;
header.Lumps[i] = lump;
}
header.MapRevision = data.ReadInt32();
@@ -79,19 +83,9 @@ namespace SabreTools.Serialization.Deserializers
/// <param name="data">Stream to parse</param>
/// <param name="version">VBSP version</param>
/// <returns>Filled Half-Life 2 Level lump on success, null on error</returns>
private static Lump ParseLump(Stream data, int version)
private static Lump? ParseLump(Stream data, int version)
{
// TODO: Use marshalling here instead of building
Lump lump = new Lump();
lump.Offset = data.ReadUInt32();
lump.Length = data.ReadUInt32();
lump.Version = data.ReadUInt32();
lump.FourCC = new char[4];
for (int i = 0; i < 4; i++)
{
lump.FourCC[i] = (char)data.ReadByte();
}
return data.ReadType<Lump>();
// This block was commented out because test VBSPs with header
// version 21 had the values in the "right" order already and
@@ -104,8 +98,8 @@ namespace SabreTools.Serialization.Deserializers
// lump.Offset = lump.Length;
// lump.Length = temp;
//}
return lump;
//
//return lump
}
}
}

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.VPK;
using static SabreTools.Models.VPK.Constants;
@@ -31,6 +30,8 @@ namespace SabreTools.Serialization.Deserializers
// Try to parse the header
// The original version had no signature.
var header = ParseHeader(data);
if (header == null)
return null;
// Set the package header
file.Header = header;
@@ -56,6 +57,8 @@ namespace SabreTools.Serialization.Deserializers
// Create the directory items tree
var directoryItems = ParseDirectoryItemTree(data);
if (directoryItems == null)
return null;
// Set the directory items
file.DirectoryItems = directoryItems;
@@ -79,7 +82,7 @@ namespace SabreTools.Serialization.Deserializers
archiveHashes.Add(archiveHash);
}
file.ArchiveHashes = archiveHashes.ToArray();
file.ArchiveHashes = [.. archiveHashes];
}
#endregion
@@ -94,19 +97,15 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled Valve Package header on success, null on error</returns>
private static Header? ParseHeader(Stream data)
{
// TODO: Use marshalling here instead of building
Header header = new Header();
var header = data.ReadType<Header>();
header.Signature = data.ReadUInt32();
if (header == null)
return null;
if (header.Signature != SignatureUInt32)
return null;
header.Version = data.ReadUInt32();
if (header.Version > 2)
return null;
header.DirectoryLength = data.ReadUInt32();
return header;
}
@@ -115,17 +114,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Valve Package extended header on success, null on error</returns>
private static ExtendedHeader ParseExtendedHeader(Stream data)
private static ExtendedHeader? ParseExtendedHeader(Stream data)
{
// TODO: Use marshalling here instead of building
ExtendedHeader extendedHeader = new ExtendedHeader();
extendedHeader.Dummy0 = data.ReadUInt32();
extendedHeader.ArchiveHashLength = data.ReadUInt32();
extendedHeader.ExtraLength = data.ReadUInt32();
extendedHeader.Dummy1 = data.ReadUInt32();
return extendedHeader;
return data.ReadType<ExtendedHeader>();
}
/// <summary>
@@ -136,7 +127,7 @@ namespace SabreTools.Serialization.Deserializers
private static ArchiveHash ParseArchiveHash(Stream data)
{
// TODO: Use marshalling here instead of building
ArchiveHash archiveHash = new ArchiveHash();
var archiveHash = new ArchiveHash();
archiveHash.ArchiveIndex = data.ReadUInt32();
archiveHash.ArchiveOffset = data.ReadUInt32();
@@ -151,7 +142,7 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Valve Package directory item tree on success, null on error</returns>
private static DirectoryItem[] ParseDirectoryItemTree(Stream data)
private static DirectoryItem[]? ParseDirectoryItemTree(Stream data)
{
// Create the directory items list
var directoryItems = new List<DirectoryItem>();
@@ -197,6 +188,8 @@ namespace SabreTools.Serialization.Deserializers
// Get the directory item
var directoryItem = ParseDirectoryItem(data, extensionString!, pathString!, nameString!);
if (directoryItem == null)
return null;
// Add the directory item
directoryItems.Add(directoryItem);
@@ -212,9 +205,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Valve Package directory item on success, null on error</returns>
private static DirectoryItem ParseDirectoryItem(Stream data, string extension, string path, string name)
private static DirectoryItem? ParseDirectoryItem(Stream data, string extension, string path, string name)
{
DirectoryItem directoryItem = new DirectoryItem();
var directoryItem = new DirectoryItem();
directoryItem.Extension = extension;
directoryItem.Path = path;
@@ -222,6 +215,8 @@ namespace SabreTools.Serialization.Deserializers
// Get the directory entry
var directoryEntry = ParseDirectoryEntry(data);
if (directoryEntry == null)
return null;
// Set the directory entry
directoryItem.DirectoryEntry = directoryEntry;
@@ -267,19 +262,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled Valve Package directory entry on success, null on error</returns>
private static DirectoryEntry ParseDirectoryEntry(Stream data)
private static DirectoryEntry? ParseDirectoryEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryEntry directoryEntry = new DirectoryEntry();
directoryEntry.CRC = data.ReadUInt32();
directoryEntry.PreloadBytes = data.ReadUInt16();
directoryEntry.ArchiveIndex = data.ReadUInt16();
directoryEntry.EntryOffset = data.ReadUInt32();
directoryEntry.EntryLength = data.ReadUInt32();
directoryEntry.Dummy0 = data.ReadUInt16();
return directoryEntry;
return data.ReadType<DirectoryEntry>();
}
}
}

View File

@@ -46,6 +46,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < header.DirectoryEntryCount; i++)
{
var directoryEntry = ParseDirectoryEntry(data);
if (directoryEntry == null)
return null;
file.DirectoryEntries[i] = directoryEntry;
}
@@ -62,6 +65,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < header.PreloadDirectoryEntryCount; i++)
{
var directoryEntry = ParseDirectoryEntry(data);
if (directoryEntry == null)
return null;
file.PreloadDirectoryEntries[i] = directoryEntry;
}
}
@@ -79,6 +85,9 @@ namespace SabreTools.Serialization.Deserializers
for (int i = 0; i < header.PreloadDirectoryEntryCount; i++)
{
var directoryMapping = ParseDirectoryMapping(data);
if (directoryMapping == null)
return null;
file.PreloadDirectoryMappings[i] = directoryMapping;
}
}
@@ -166,16 +175,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled XBox Package File directory entry on success, null on error</returns>
private static DirectoryEntry ParseDirectoryEntry(Stream data)
private static DirectoryEntry? ParseDirectoryEntry(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryEntry directoryEntry = new DirectoryEntry();
directoryEntry.FileNameCRC = data.ReadUInt32();
directoryEntry.EntryLength = data.ReadUInt32();
directoryEntry.EntryOffset = data.ReadUInt32();
return directoryEntry;
return data.ReadType<DirectoryEntry>();
}
/// <summary>
@@ -183,14 +185,9 @@ namespace SabreTools.Serialization.Deserializers
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled XBox Package File directory mapping on success, null on error</returns>
private static DirectoryMapping ParseDirectoryMapping(Stream data)
private static DirectoryMapping? ParseDirectoryMapping(Stream data)
{
// TODO: Use marshalling here instead of building
DirectoryMapping directoryMapping = new DirectoryMapping();
directoryMapping.PreloadDirectoryEntryIndex = data.ReadUInt16();
return directoryMapping;
return data.ReadType<DirectoryMapping>();
}
/// <summary>

View File

@@ -102,21 +102,13 @@ namespace SabreTools.Serialization
/// <returns>A filled NB10 Program Database on success, null on error</returns>
public static NB10ProgramDatabase? AsNB10ProgramDatabase(this byte[] data, ref int offset)
{
// If we have data that's invalid, we can't do anything
if (data == null)
var nb10ProgramDatabase = data.ReadType<NB10ProgramDatabase>(ref offset);
if (nb10ProgramDatabase == null)
return null;
var nb10ProgramDatabase = new NB10ProgramDatabase();
nb10ProgramDatabase.Signature = data.ReadUInt32(ref offset);
if (nb10ProgramDatabase.Signature != 0x3031424E)
return null;
nb10ProgramDatabase.Offset = data.ReadUInt32(ref offset);
nb10ProgramDatabase.Timestamp = data.ReadUInt32(ref offset);
nb10ProgramDatabase.Age = data.ReadUInt32(ref offset);
nb10ProgramDatabase.PdbFileName = data.ReadNullTerminatedAnsiString(ref offset); // TODO: Actually null-terminated UTF-8?
return nb10ProgramDatabase;
}
@@ -157,12 +149,8 @@ namespace SabreTools.Serialization
/// <param name="data">Data to parse into overlay data</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled SecuROM AddD overlay data on success, null on error</returns>
public static SecuROMAddD? AsSecuROMAddD(this byte[]? data, ref int offset)
public static SecuROMAddD? AsSecuROMAddD(this byte[] data, ref int offset)
{
// If we have data that's invalid, we can't do anything
if (data == null)
return null;
// Read in the table
var addD = new SecuROMAddD();
@@ -193,18 +181,9 @@ namespace SabreTools.Serialization
addD.Entries = new SecuROMAddDEntry[addD.EntryCount];
for (int i = 0; i < addD.EntryCount; i++)
{
var addDEntry = new SecuROMAddDEntry();
addDEntry.PhysicalOffset = data.ReadUInt32(ref offset);
addDEntry.Length = data.ReadUInt32(ref offset);
addDEntry.Unknown08h = data.ReadUInt32(ref offset);
addDEntry.Unknown0Ch = data.ReadUInt32(ref offset);
addDEntry.Unknown10h = data.ReadUInt32(ref offset);
addDEntry.Unknown14h = data.ReadUInt32(ref offset);
addDEntry.Unknown18h = data.ReadUInt32(ref offset);
addDEntry.Unknown1Ch = data.ReadUInt32(ref offset);
addDEntry.FileName = data.ReadNullTerminatedAnsiString(ref offset);
addDEntry.Unknown2Ch = data.ReadUInt32(ref offset);
var addDEntry = data.ReadType<SecuROMAddDEntry>(ref offset);
if (addDEntry == null)
return null;
addD.Entries[i] = addDEntry;
}
@@ -223,7 +202,7 @@ namespace SabreTools.Serialization
/// <param name="data">Data to parse into a resource header</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled resource header on success, null on error</returns>
public static ResourceHeader? AsResourceHeader(this byte[]? data, ref int offset)
public static ResourceHeader? AsResourceHeader(this byte[] data, ref int offset)
{
// If we have data that's invalid, we can't do anything
if (data == null)
@@ -267,12 +246,9 @@ namespace SabreTools.Serialization
// Read in the table
for (int i = 0; i < count; i++)
{
var acceleratorTableEntry = new AcceleratorTableEntry();
acceleratorTableEntry.Flags = (AcceleratorTableFlags)entry.Data.ReadUInt16(ref offset);
acceleratorTableEntry.Ansi = entry.Data.ReadUInt16(ref offset);
acceleratorTableEntry.Id = entry.Data.ReadUInt16(ref offset);
acceleratorTableEntry.Padding = entry.Data.ReadUInt16(ref offset);
var acceleratorTableEntry = entry.Data.ReadType<AcceleratorTableEntry>(ref offset);
if (acceleratorTableEntry == null)
return null;
table[i] = acceleratorTableEntry;
}
@@ -920,11 +896,9 @@ namespace SabreTools.Serialization
{
#region Extended menu header
var menuHeaderExtended = new MenuHeaderExtended();
menuHeaderExtended.Version = entry.Data.ReadUInt16(ref offset);
menuHeaderExtended.Offset = entry.Data.ReadUInt16(ref offset);
menuHeaderExtended.HelpID = entry.Data.ReadUInt32(ref offset);
var menuHeaderExtended = entry.Data.ReadType<MenuHeaderExtended>(ref offset);
if (menuHeaderExtended == null)
return null;
menuResource.ExtendedMenuHeader = menuHeaderExtended;
@@ -940,13 +914,9 @@ namespace SabreTools.Serialization
while (offset < entry.Data.Length)
{
var extendedMenuItem = new MenuItemExtended();
extendedMenuItem.ItemType = (MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.State = (MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.ID = entry.Data.ReadUInt32(ref offset);
extendedMenuItem.Flags = (MenuFlags)entry.Data.ReadUInt32(ref offset);
extendedMenuItem.MenuText = entry.Data.ReadNullTerminatedUnicodeString(ref offset);
var extendedMenuItem = entry.Data.ReadType<MenuItemExtended>(ref offset);
if (extendedMenuItem == null)
return null;
// Align to the DWORD boundary if we're not at the end
if (offset < entry.Data.Length)
@@ -967,10 +937,9 @@ namespace SabreTools.Serialization
{
#region Menu header
var menuHeader = new MenuHeader();
menuHeader.Version = entry.Data.ReadUInt16(ref offset);
menuHeader.HeaderSize = entry.Data.ReadUInt16(ref offset);
var menuHeader = entry.Data.ReadType<MenuHeader>(ref offset);
if (menuHeader == null)
return null;
menuResource.MenuHeader = menuHeader;
@@ -1048,11 +1017,9 @@ namespace SabreTools.Serialization
for (int i = 0; i < messageResourceData.NumberOfBlocks; i++)
{
var messageResourceBlock = new MessageResourceBlock();
messageResourceBlock.LowId = entry.Data.ReadUInt32(ref offset);
messageResourceBlock.HighId = entry.Data.ReadUInt32(ref offset);
messageResourceBlock.OffsetToEntries = entry.Data.ReadUInt32(ref offset);
var messageResourceBlock = entry.Data.ReadType<MessageResourceBlock>(ref offset);
if (messageResourceBlock == null)
return null;
messageResourceBlocks.Add(messageResourceBlock);
}
@@ -1168,23 +1135,13 @@ namespace SabreTools.Serialization
// Read fixed file info
if (versionInfo.ValueLength > 0)
{
var fixedFileInfo = new FixedFileInfo();
fixedFileInfo.Signature = entry.Data.ReadUInt32(ref offset);
var fixedFileInfo = entry.Data.ReadType<FixedFileInfo>(ref offset);
if (fixedFileInfo == null)
return null;
if (fixedFileInfo.Signature != 0xFEEF04BD)
return null;
fixedFileInfo.StrucVersion = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileVersionMS = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileVersionLS = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.ProductVersionMS = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.ProductVersionLS = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileFlagsMask = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileFlags = (FixedFileInfoFlags)(entry.Data.ReadUInt32(ref offset) & fixedFileInfo.FileFlagsMask);
fixedFileInfo.FileOS = (FixedFileInfoOS)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileType = (FixedFileInfoFileType)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileSubtype = (FixedFileInfoFileSubtype)entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileDateMS = entry.Data.ReadUInt32(ref offset);
fixedFileInfo.FileDateLS = entry.Data.ReadUInt32(ref offset);
versionInfo.Value = fixedFileInfo;
}
@@ -1246,7 +1203,7 @@ namespace SabreTools.Serialization
/// <param name="data">Data to parse into a string file info</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled string file info resource on success, null on error</returns>
private static StringFileInfo? AsStringFileInfo(byte[] data, ref int offset)
public static StringFileInfo? AsStringFileInfo(byte[] data, ref int offset)
{
var stringFileInfo = new StringFileInfo();
@@ -1341,7 +1298,7 @@ namespace SabreTools.Serialization
/// <param name="data">Data to parse into a var file info</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled var file info resource on success, null on error</returns>
private static VarFileInfo? AsVarFileInfo(byte[] data, ref int offset)
public static VarFileInfo? AsVarFileInfo(byte[] data, ref int offset)
{
var varFileInfo = new VarFileInfo();