Compare commits

..

10 Commits
1.6.5 ... 1.6.7

Author SHA1 Message Date
Matt Nadareski
b7978cafa5 Bump version 2024-06-13 11:12:40 -04:00
Matt Nadareski
17f376c76f Remove all instances of this. 2024-06-05 22:49:27 -04:00
Matt Nadareski
2774fdf158 Clean up enumerables and namespace use 2024-06-05 22:48:42 -04:00
Matt Nadareski
11081efcb0 Make PE header reading even saferer 2024-06-05 22:22:22 -04:00
TheRogueArchivist
1b412c3027 Add header length safeguards to PortableExecutable wrapper (#9) 2024-06-05 22:19:35 -04:00
Matt Nadareski
73ec66e627 Fix ISv3 deserialization 2024-06-03 11:55:12 -04:00
Matt Nadareski
4ae4cd80b1 Bump version 2024-05-30 21:07:04 -04:00
Matt Nadareski
6eb27c66fc Merge pull request #8 from TheRogueArchivist/streamdatalock
Add lock for reading data from stream
2024-05-30 12:30:33 -04:00
TheRogueArchivist
f96fd17fd3 Add lock for reading data from stream 2024-05-27 15:36:04 -06:00
Matt Nadareski
c255a2494d Fix IS-CAB file group name parsing 2024-05-18 21:27:09 -04:00
12 changed files with 224 additions and 191 deletions

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
using SabreTools.Models.InstallShieldArchiveV3;
@@ -114,7 +115,17 @@ namespace SabreTools.Serialization.Deserializers
/// <returns>Filled directory on success, null on error</returns>
public static Models.InstallShieldArchiveV3.Directory? ParseDirectory(Stream data)
{
return data.ReadType<Models.InstallShieldArchiveV3.Directory>();
var directory = new Models.InstallShieldArchiveV3.Directory();
directory.FileCount = data.ReadUInt16();
directory.ChunkSize = data.ReadUInt16();
// TODO: Is there any equivilent automatic type for UInt16-prefixed ANSI?
ushort nameLength = data.ReadUInt16();
byte[] nameBytes = data.ReadBytes(nameLength);
directory.Name = Encoding.ASCII.GetString(nameBytes);
return directory;
}
/// <summary>

View File

@@ -489,7 +489,7 @@ namespace SabreTools.Serialization.Deserializers
if (majorVersion >= 17)
fileGroup.Name = data.ReadNullTerminatedUnicodeString();
else
fileGroup.Name = data.ReadNullTerminatedUnicodeString();
fileGroup.Name = data.ReadNullTerminatedAnsiString();
}
// Seek back to the correct offset

View File

@@ -8,7 +8,7 @@
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.6.5</Version>
<Version>1.6.7</Version>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>

View File

@@ -18,12 +18,12 @@ namespace SabreTools.Serialization.Wrappers
/// <summary>
/// Normal sector size in bytes
/// </summary>
public long SectorSize => (long)Math.Pow(2, this.Model.Header?.SectorShift ?? 0);
public long SectorSize => (long)Math.Pow(2, Model.Header?.SectorShift ?? 0);
/// <summary>
/// Mini sector size in bytes
/// </summary>
public long MiniSectorSize => (long)Math.Pow(2, this.Model.Header?.MiniSectorShift ?? 0);
public long MiniSectorSize => (long)Math.Pow(2, Model.Header?.MiniSectorShift ?? 0);
#endregion
@@ -101,7 +101,7 @@ namespace SabreTools.Serialization.Wrappers
public List<Models.CFB.SectorNumber?>? GetFATSectorChain(Models.CFB.SectorNumber? startingSector)
{
// If we have an invalid sector
if (startingSector == null || startingSector < 0 || this.Model.FATSectorNumbers == null || (long)startingSector >= this.Model.FATSectorNumbers.Length)
if (startingSector == null || startingSector < 0 || Model.FATSectorNumbers == null || (long)startingSector >= Model.FATSectorNumbers.Length)
return null;
// Setup the returned list
@@ -114,10 +114,10 @@ namespace SabreTools.Serialization.Wrappers
break;
// Get the next sector from the lookup table
var nextSector = this.Model.FATSectorNumbers[(uint)lastSector!.Value];
var nextSector = Model.FATSectorNumbers[(uint)lastSector!.Value];
// If we have an end of chain or free sector
if (nextSector == SabreTools.Models.CFB.SectorNumber.ENDOFCHAIN || nextSector == SabreTools.Models.CFB.SectorNumber.FREESECT)
if (nextSector == Models.CFB.SectorNumber.ENDOFCHAIN || nextSector == Models.CFB.SectorNumber.FREESECT)
break;
// Add the next sector to the list and replace the last sector
@@ -188,7 +188,7 @@ namespace SabreTools.Serialization.Wrappers
public List<Models.CFB.SectorNumber?>? GetMiniFATSectorChain(Models.CFB.SectorNumber? startingSector)
{
// If we have an invalid sector
if (startingSector == null || startingSector < 0 || this.Model.MiniFATSectorNumbers == null || (long)startingSector >= this.Model.MiniFATSectorNumbers.Length)
if (startingSector == null || startingSector < 0 || Model.MiniFATSectorNumbers == null || (long)startingSector >= Model.MiniFATSectorNumbers.Length)
return null;
// Setup the returned list
@@ -201,10 +201,10 @@ namespace SabreTools.Serialization.Wrappers
break;
// Get the next sector from the lookup table
var nextSector = this.Model.MiniFATSectorNumbers[(uint)lastSector!.Value];
var nextSector = Model.MiniFATSectorNumbers[(uint)lastSector!.Value];
// If we have an end of chain or free sector
if (nextSector == SabreTools.Models.CFB.SectorNumber.ENDOFCHAIN || nextSector == SabreTools.Models.CFB.SectorNumber.FREESECT)
if (nextSector == Models.CFB.SectorNumber.ENDOFCHAIN || nextSector == Models.CFB.SectorNumber.FREESECT)
break;
// Add the next sector to the list and replace the last sector

View File

@@ -26,16 +26,16 @@ namespace SabreTools.Serialization.Wrappers
return _files;
// If we don't have a required property
if (this.Model.DirectoryEntries == null || this.Model.DirectoryMapEntries == null || this.Model.BlockEntries == null)
if (Model.DirectoryEntries == null || Model.DirectoryMapEntries == null || Model.BlockEntries == null)
return null;
// Otherwise, scan and build the files
var files = new List<FileInfo>();
for (int i = 0; i < this.Model.DirectoryEntries.Length; i++)
for (int i = 0; i < Model.DirectoryEntries.Length; i++)
{
// Get the directory entry
var directoryEntry = this.Model.DirectoryEntries[i];
var directoryMapEntry = this.Model.DirectoryMapEntries[i];
var directoryEntry = Model.DirectoryEntries[i];
var directoryMapEntry = Model.DirectoryMapEntries[i];
if (directoryEntry == null || directoryMapEntry == null)
continue;
@@ -57,26 +57,26 @@ namespace SabreTools.Serialization.Wrappers
Encrypted = directoryEntry.DirectoryFlags.HasFlag(Models.GCF.HL_GCF_FLAG.HL_GCF_FLAG_ENCRYPTED),
#endif
};
var pathParts = new List<string> { this.Model.DirectoryNames![directoryEntry.NameOffset] ?? string.Empty };
var pathParts = new List<string> { Model.DirectoryNames![directoryEntry.NameOffset] ?? string.Empty };
var blockEntries = new List<Models.GCF.BlockEntry?>();
// Traverse the parent tree
uint index = directoryEntry.ParentIndex;
while (index != 0xFFFFFFFF)
{
var parentDirectoryEntry = this.Model.DirectoryEntries[index];
var parentDirectoryEntry = Model.DirectoryEntries[index];
if (parentDirectoryEntry == null)
break;
pathParts.Add(this.Model.DirectoryNames![parentDirectoryEntry.NameOffset] ?? string.Empty);
pathParts.Add(Model.DirectoryNames![parentDirectoryEntry.NameOffset] ?? string.Empty);
index = parentDirectoryEntry.ParentIndex;
}
// Traverse the block entries
index = directoryMapEntry.FirstBlockIndex;
while (index != this.Model.DataBlockHeader?.BlockCount)
while (index != Model.DataBlockHeader?.BlockCount)
{
var nextBlock = this.Model.BlockEntries[index];
var nextBlock = Model.BlockEntries[index];
if (nextBlock == null)
break;
@@ -134,14 +134,14 @@ namespace SabreTools.Serialization.Wrappers
return _dataBlockOffsets;
// If we don't have a block count, offset, or size
if (this.Model.DataBlockHeader?.BlockCount == null || this.Model.DataBlockHeader?.FirstBlockOffset == null || this.Model.DataBlockHeader?.BlockSize == null)
if (Model.DataBlockHeader?.BlockCount == null || Model.DataBlockHeader?.FirstBlockOffset == null || Model.DataBlockHeader?.BlockSize == null)
return null;
// Otherwise, build the data block set
_dataBlockOffsets = new long[this.Model.DataBlockHeader.BlockCount];
for (int i = 0; i < this.Model.DataBlockHeader.BlockCount; i++)
_dataBlockOffsets = new long[Model.DataBlockHeader.BlockCount];
for (int i = 0; i < Model.DataBlockHeader.BlockCount; i++)
{
long dataBlockOffset = this.Model.DataBlockHeader.FirstBlockOffset + (i * this.Model.DataBlockHeader.BlockSize);
long dataBlockOffset = Model.DataBlockHeader.FirstBlockOffset + (i * Model.DataBlockHeader.BlockSize);
_dataBlockOffsets[i] = dataBlockOffset;
}

View File

@@ -53,7 +53,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
uint majorVersion = this.Model.CommonHeader?.Version ?? 0;
uint majorVersion = Model.CommonHeader?.Version ?? 0;
if (majorVersion >> 24 == 1)
{
majorVersion = (majorVersion >> 12) & 0x0F;

View File

@@ -124,11 +124,11 @@ namespace SabreTools.Serialization.Wrappers
public DateTime? GetDateTime(int fileIndex)
{
// If we have an invalid file index
if (fileIndex < 0 || this.Model.Files == null || fileIndex >= this.Model.Files.Length)
if (fileIndex < 0 || Model.Files == null || fileIndex >= Model.Files.Length)
return null;
// Get the file header
var file = this.Model.Files[fileIndex];
var file = Model.Files[fileIndex];
if (file == null)
return null;

View File

@@ -33,19 +33,26 @@ namespace SabreTools.Serialization.Wrappers
// TODO: Don't scan the known header data as well
// If the section table is missing
if (this.Model.SectionTable == null)
return null;
// If any required pieces are missing
if (Model.Stub?.Header == null)
return [];
if (Model.SectionTable == null)
return [];
// Populate the raw header padding data based on the source
uint headerStartAddress = this.Model.Stub?.Header?.NewExeHeaderAddr ?? 0;
uint firstSectionAddress = this.Model.SectionTable
uint headerStartAddress = Model.Stub.Header.NewExeHeaderAddr;
uint firstSectionAddress = Model.SectionTable
.Select(s => s?.PointerToRawData ?? 0)
.Where(s => s != 0)
.Where(s => s != 0 && s >= headerStartAddress)
.OrderBy(s => s)
.First();
.FirstOrDefault();
// Check if the header length is more than 0 before reading data
int headerLength = (int)(firstSectionAddress - headerStartAddress);
_headerPaddingData = ReadFromDataSource((int)headerStartAddress, headerLength);
if (headerLength <= 0)
_headerPaddingData = [];
else
_headerPaddingData = ReadFromDataSource((int)headerStartAddress, headerLength);
// Cache and return the header padding data, even if null
return _headerPaddingData;
@@ -68,19 +75,26 @@ namespace SabreTools.Serialization.Wrappers
// TODO: Don't scan the known header data as well
// If the section table is missing
if (this.Model.SectionTable == null)
return null;
// If any required pieces are missing
if (Model.Stub?.Header == null)
return [];
if (Model.SectionTable == null)
return [];
// Populate the raw header padding data based on the source
uint headerStartAddress = this.Model.Stub?.Header?.NewExeHeaderAddr ?? 0;
uint firstSectionAddress = this.Model.SectionTable
// Populate the header padding strings based on the source
uint headerStartAddress = Model.Stub.Header.NewExeHeaderAddr;
uint firstSectionAddress = Model.SectionTable
.Select(s => s?.PointerToRawData ?? 0)
.Where(s => s != 0)
.Where(s => s != 0 && s >= headerStartAddress)
.OrderBy(s => s)
.First();
.FirstOrDefault();
// Check if the header length is more than 0 before reading strings
int headerLength = (int)(firstSectionAddress - headerStartAddress);
_headerPaddingStrings = ReadStringsFromDataSource((int)headerStartAddress, headerLength, charLimit: 3);
if (headerLength <= 0)
_headerPaddingStrings = [];
else
_headerPaddingStrings = ReadStringsFromDataSource((int)headerStartAddress, headerLength, charLimit: 3);
// Cache and return the header padding data, even if null
return _headerPaddingStrings;
@@ -98,21 +112,21 @@ namespace SabreTools.Serialization.Wrappers
lock (_sourceDataLock)
{
// If the section table is missing
if (this.Model.SectionTable == null)
if (Model.SectionTable == null)
return null;
// If the address is missing
if (this.Model.OptionalHeader?.AddressOfEntryPoint == null)
if (Model.OptionalHeader?.AddressOfEntryPoint == null)
return null;
// If we have no entry point
int entryPointAddress = (int)this.Model.OptionalHeader.AddressOfEntryPoint.ConvertVirtualAddress(this.Model.SectionTable);
int entryPointAddress = (int)Model.OptionalHeader.AddressOfEntryPoint.ConvertVirtualAddress(Model.SectionTable);
if (entryPointAddress == 0)
return null;
// If the entry point matches with the start of a section, use that
int entryPointSection = FindEntryPointSectionIndex();
if (entryPointSection >= 0 && this.Model.OptionalHeader.AddressOfEntryPoint == this.Model.SectionTable[entryPointSection]?.VirtualAddress)
if (entryPointSection >= 0 && Model.OptionalHeader.AddressOfEntryPoint == Model.SectionTable[entryPointSection]?.VirtualAddress)
return GetSectionData(entryPointSection);
// If we already have cached data, just use that immediately
@@ -148,27 +162,27 @@ namespace SabreTools.Serialization.Wrappers
return -1;
// If the section table is missing
if (this.Model.SectionTable == null)
if (Model.SectionTable == null)
return -1;
// If we have certificate data, use that as the end
if (this.Model.OptionalHeader?.CertificateTable != null)
if (Model.OptionalHeader?.CertificateTable != null)
{
int certificateTableAddress = (int)this.Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
int certificateTableAddress = (int)Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (certificateTableAddress != 0 && certificateTableAddress < endOfFile)
endOfFile = certificateTableAddress;
}
// Search through all sections and find the furthest a section goes
int endOfSectionData = -1;
foreach (var section in this.Model.SectionTable)
foreach (var section in Model.SectionTable)
{
// If we have an invalid section
if (section == null)
continue;
// If we have an invalid section address
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (sectionAddress == 0)
continue;
@@ -219,27 +233,27 @@ namespace SabreTools.Serialization.Wrappers
return null;
// If the section table is missing
if (this.Model.SectionTable == null)
if (Model.SectionTable == null)
return null;
// If we have certificate data, use that as the end
if (this.Model.OptionalHeader?.CertificateTable != null)
if (Model.OptionalHeader?.CertificateTable != null)
{
int certificateTableAddress = (int)this.Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
int certificateTableAddress = (int)Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (certificateTableAddress != 0 && certificateTableAddress < endOfFile)
endOfFile = certificateTableAddress;
}
// Search through all sections and find the furthest a section goes
int endOfSectionData = -1;
foreach (var section in this.Model.SectionTable)
foreach (var section in Model.SectionTable)
{
// If we have an invalid section
if (section == null)
continue;
// If we have an invalid section address
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (sectionAddress == 0)
continue;
@@ -297,27 +311,27 @@ namespace SabreTools.Serialization.Wrappers
return null;
// If the section table is missing
if (this.Model.SectionTable == null)
if (Model.SectionTable == null)
return null;
// If we have certificate data, use that as the end
if (this.Model.OptionalHeader?.CertificateTable != null)
if (Model.OptionalHeader?.CertificateTable != null)
{
int certificateTableAddress = (int)this.Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
int certificateTableAddress = (int)Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (certificateTableAddress != 0 && certificateTableAddress < endOfFile)
endOfFile = certificateTableAddress;
}
// Search through all sections and find the furthest a section goes
int endOfSectionData = -1;
foreach (var section in this.Model.SectionTable)
foreach (var section in Model.SectionTable)
{
// If we have an invalid section
if (section == null)
continue;
// If we have an invalid section address
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (sectionAddress == 0)
continue;
@@ -370,14 +384,14 @@ namespace SabreTools.Serialization.Wrappers
return _sectionNames;
// If there are no sections
if (this.Model.SectionTable == null)
if (Model.SectionTable == null)
return null;
// Otherwise, build and return the cached array
_sectionNames = new string[this.Model.SectionTable.Length];
_sectionNames = new string[Model.SectionTable.Length];
for (int i = 0; i < _sectionNames.Length; i++)
{
var section = this.Model.SectionTable[i];
var section = Model.SectionTable[i];
if (section == null)
continue;
@@ -408,12 +422,12 @@ namespace SabreTools.Serialization.Wrappers
if (_stubExecutableData != null)
return _stubExecutableData;
if (this.Model.Stub?.Header?.NewExeHeaderAddr == null)
if (Model.Stub?.Header?.NewExeHeaderAddr == null)
return null;
// Populate the raw stub executable data based on the source
int endOfStubHeader = 0x40;
int lengthOfStubExecutableData = (int)this.Model.Stub.Header.NewExeHeaderAddr - endOfStubHeader;
int lengthOfStubExecutableData = (int)Model.Stub.Header.NewExeHeaderAddr - endOfStubHeader;
_stubExecutableData = ReadFromDataSource(endOfStubHeader, lengthOfStubExecutableData);
// Cache and return the stub executable data, even if null
@@ -436,8 +450,8 @@ namespace SabreTools.Serialization.Wrappers
return _debugData;
// If we have no resource table, just return
if (this.Model.DebugTable?.DebugDirectoryTable == null
|| this.Model.DebugTable.DebugDirectoryTable.Length == 0)
if (Model.DebugTable?.DebugDirectoryTable == null
|| Model.DebugTable.DebugDirectoryTable.Length == 0)
return null;
// Otherwise, build and return the cached dictionary
@@ -461,13 +475,13 @@ namespace SabreTools.Serialization.Wrappers
return _resourceData;
// If we have no resource table, just return
if (this.Model.OptionalHeader?.ResourceTable == null
|| this.Model.OptionalHeader.ResourceTable.VirtualAddress == 0
|| this.Model.ResourceDirectoryTable == null)
if (Model.OptionalHeader?.ResourceTable == null
|| Model.OptionalHeader.ResourceTable.VirtualAddress == 0
|| Model.ResourceDirectoryTable == null)
return null;
// Otherwise, build and return the cached dictionary
ParseResourceDirectoryTable(this.Model.ResourceDirectoryTable, types: []);
ParseResourceDirectoryTable(Model.ResourceDirectoryTable, types: []);
return _resourceData;
}
}
@@ -585,15 +599,15 @@ namespace SabreTools.Serialization.Wrappers
/// <remarks>The internal version is either the file version, product version, or assembly version, in that order</remarks>
public string? GetInternalVersion()
{
string? version = this.FileVersion;
string? version = FileVersion;
if (!string.IsNullOrEmpty(version))
return version!.Replace(", ", ".");
version = this.ProductVersion;
version = ProductVersion;
if (!string.IsNullOrEmpty(version))
return version!.Replace(", ", ".");
version = this.AssemblyVersion;
version = AssemblyVersion;
if (!string.IsNullOrEmpty(version))
return version;
@@ -864,7 +878,7 @@ namespace SabreTools.Serialization.Wrappers
{
// Ensure that we have the debug data cached
if (DebugData == null)
return Enumerable.Empty<object?>();
return [];
var nb10Found = DebugData.Select(r => r.Value)
.Select(r => r as SabreTools.Models.PortableExecutable.NB10ProgramDatabase)
@@ -890,7 +904,7 @@ namespace SabreTools.Serialization.Wrappers
{
// Ensure that we have the resource data cached
if (DebugData == null)
return Enumerable.Empty<byte[]?>();
return [];
return DebugData.Select(r => r.Value)
.Select(b => b as byte[])
@@ -935,13 +949,13 @@ namespace SabreTools.Serialization.Wrappers
private void ParseDebugTable()
{
// If there is no debug table
if (this.Model.DebugTable?.DebugDirectoryTable == null)
if (Model.DebugTable?.DebugDirectoryTable == null)
return;
// Loop through all debug table entries
for (int i = 0; i < this.Model.DebugTable.DebugDirectoryTable.Length; i++)
for (int i = 0; i < Model.DebugTable.DebugDirectoryTable.Length; i++)
{
var entry = this.Model.DebugTable.DebugDirectoryTable[i];
var entry = Model.DebugTable.DebugDirectoryTable[i];
if (entry == null)
continue;
@@ -953,7 +967,7 @@ namespace SabreTools.Serialization.Wrappers
continue;
// If we have CodeView debug data, try to parse it
if (entry.DebugType == SabreTools.Models.PortableExecutable.DebugType.IMAGE_DEBUG_TYPE_CODEVIEW)
if (entry.DebugType == Models.PortableExecutable.DebugType.IMAGE_DEBUG_TYPE_CODEVIEW)
{
// Read the signature
int offset = 0;
@@ -1004,7 +1018,7 @@ namespace SabreTools.Serialization.Wrappers
{
// Ensure that we have the resource data cached
if (ResourceData == null)
return Enumerable.Empty<Models.PortableExecutable.DialogBoxResource?>();
return [];
return ResourceData.Select(r => r.Value)
.Select(r => r as SabreTools.Models.PortableExecutable.DialogBoxResource)
@@ -1025,7 +1039,7 @@ namespace SabreTools.Serialization.Wrappers
{
// Ensure that we have the resource data cached
if (ResourceData == null)
return Enumerable.Empty<Models.PortableExecutable.DialogBoxResource?>();
return [];
return ResourceData.Select(r => r.Value)
.Select(r => r as SabreTools.Models.PortableExecutable.DialogBoxResource)
@@ -1058,7 +1072,7 @@ namespace SabreTools.Serialization.Wrappers
{
// Ensure that we have the resource data cached
if (ResourceData == null)
return Enumerable.Empty<Dictionary<int, string?>?>();
return [];
return ResourceData.Select(r => r.Value)
.Select(r => r as Dictionary<int, string?>)
@@ -1076,7 +1090,7 @@ namespace SabreTools.Serialization.Wrappers
{
// Ensure that we have the resource data cached
if (ResourceData == null)
return Enumerable.Empty<byte[]?>();
return [];
return ResourceData.Where(kvp => kvp.Key.Contains(typeName))
.Select(kvp => kvp.Value as byte[])
@@ -1092,7 +1106,7 @@ namespace SabreTools.Serialization.Wrappers
{
// Ensure that we have the resource data cached
if (ResourceData == null)
return Enumerable.Empty<byte[]?>();
return [];
return ResourceData.Select(r => r.Value)
.Select(r => r as byte[])
@@ -1311,19 +1325,19 @@ namespace SabreTools.Serialization.Wrappers
public int FindEntryPointSectionIndex()
{
// If the section table is missing
if (this.Model.SectionTable == null)
if (Model.SectionTable == null)
return -1;
// If the address is missing
if (this.Model.OptionalHeader?.AddressOfEntryPoint == null)
if (Model.OptionalHeader?.AddressOfEntryPoint == null)
return -1;
// If we don't have an entry point
if (this.Model.OptionalHeader.AddressOfEntryPoint.ConvertVirtualAddress(this.Model.SectionTable) == 0)
if (Model.OptionalHeader.AddressOfEntryPoint.ConvertVirtualAddress(Model.SectionTable) == 0)
return -1;
// Otherwise, find the section it exists within
return this.Model.OptionalHeader.AddressOfEntryPoint.ContainingSectionIndex(this.Model.SectionTable
return Model.OptionalHeader.AddressOfEntryPoint.ContainingSectionIndex(Model.SectionTable
.Where(sh => sh != null)
.Cast<Models.PortableExecutable.SectionHeader>()
.ToArray());
@@ -1338,7 +1352,7 @@ namespace SabreTools.Serialization.Wrappers
public Models.PortableExecutable.SectionHeader? GetFirstSection(string? name, bool exact = false)
{
// If we have no sections
if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (SectionNames == null || !SectionNames.Any() || Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
@@ -1351,7 +1365,7 @@ namespace SabreTools.Serialization.Wrappers
return null;
// Return the section
return this.Model.SectionTable[index];
return Model.SectionTable[index];
}
/// <summary>
@@ -1363,7 +1377,7 @@ namespace SabreTools.Serialization.Wrappers
public Models.PortableExecutable.SectionHeader? GetLastSection(string? name, bool exact = false)
{
// If we have no sections
if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (SectionNames == null || !SectionNames.Any() || Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
@@ -1376,7 +1390,7 @@ namespace SabreTools.Serialization.Wrappers
return null;
// Return the section
return this.Model.SectionTable[index];
return Model.SectionTable[index];
}
/// <summary>
@@ -1387,15 +1401,15 @@ namespace SabreTools.Serialization.Wrappers
public Models.PortableExecutable.SectionHeader? GetSection(int index)
{
// If we have no sections
if (this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
if (index < 0 || index >= this.Model.SectionTable.Length)
if (index < 0 || index >= Model.SectionTable.Length)
return null;
// Return the section
return this.Model.SectionTable[index];
return Model.SectionTable[index];
}
/// <summary>
@@ -1407,7 +1421,7 @@ namespace SabreTools.Serialization.Wrappers
public byte[]? GetFirstSectionData(string? name, bool exact = false)
{
// If we have no sections
if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (SectionNames == null || !SectionNames.Any() || Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
@@ -1428,7 +1442,7 @@ namespace SabreTools.Serialization.Wrappers
public byte[]? GetLastSectionData(string? name, bool exact = false)
{
// If we have no sections
if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (SectionNames == null || !SectionNames.Any() || Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
@@ -1448,19 +1462,19 @@ namespace SabreTools.Serialization.Wrappers
public byte[]? GetSectionData(int index)
{
// If we have no sections
if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (SectionNames == null || !SectionNames.Any() || Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
if (index < 0 || index >= this.Model.SectionTable.Length)
if (index < 0 || index >= Model.SectionTable.Length)
return null;
// Get the section data from the table
var section = this.Model.SectionTable[index];
var section = Model.SectionTable[index];
if (section == null)
return null;
uint address = section.VirtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
uint address = section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (address == 0)
return null;
@@ -1493,7 +1507,7 @@ namespace SabreTools.Serialization.Wrappers
public List<string>? GetFirstSectionStrings(string? name, bool exact = false)
{
// If we have no sections
if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (SectionNames == null || !SectionNames.Any() || Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
@@ -1514,7 +1528,7 @@ namespace SabreTools.Serialization.Wrappers
public List<string>? GetLastSectionStrings(string? name, bool exact = false)
{
// If we have no sections
if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (SectionNames == null || !SectionNames.Any() || Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
@@ -1534,19 +1548,19 @@ namespace SabreTools.Serialization.Wrappers
public List<string>? GetSectionStrings(int index)
{
// If we have no sections
if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any())
if (SectionNames == null || !SectionNames.Any() || Model.SectionTable == null || !Model.SectionTable.Any())
return null;
// If the section doesn't exist
if (index < 0 || index >= this.Model.SectionTable.Length)
if (index < 0 || index >= Model.SectionTable.Length)
return null;
// Get the section data from the table
var section = this.Model.SectionTable[index];
var section = Model.SectionTable[index];
if (section == null)
return null;
uint address = section.VirtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
uint address = section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (address == 0)
return null;
@@ -1582,7 +1596,7 @@ namespace SabreTools.Serialization.Wrappers
public byte[]? GetTableData(int index)
{
// If the table doesn't exist
if (this.Model.OptionalHeader == null || index < 0 || index > 16)
if (Model.OptionalHeader == null || index < 0 || index > 16)
return null;
// Get the virtual address and size from the entries
@@ -1590,64 +1604,64 @@ namespace SabreTools.Serialization.Wrappers
switch (index)
{
case 1:
virtualAddress = this.Model.OptionalHeader.ExportTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ExportTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ExportTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ExportTable?.Size ?? 0;
break;
case 2:
virtualAddress = this.Model.OptionalHeader.ImportTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ImportTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ImportTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ImportTable?.Size ?? 0;
break;
case 3:
virtualAddress = this.Model.OptionalHeader.ResourceTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ResourceTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ResourceTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ResourceTable?.Size ?? 0;
break;
case 4:
virtualAddress = this.Model.OptionalHeader.ExceptionTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ExceptionTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ExceptionTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ExceptionTable?.Size ?? 0;
break;
case 5:
virtualAddress = this.Model.OptionalHeader.CertificateTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.CertificateTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.CertificateTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.CertificateTable?.Size ?? 0;
break;
case 6:
virtualAddress = this.Model.OptionalHeader.BaseRelocationTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.BaseRelocationTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.BaseRelocationTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.BaseRelocationTable?.Size ?? 0;
break;
case 7:
virtualAddress = this.Model.OptionalHeader.Debug?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.Debug?.Size ?? 0;
virtualAddress = Model.OptionalHeader.Debug?.VirtualAddress ?? 0;
size = Model.OptionalHeader.Debug?.Size ?? 0;
break;
case 8: // Architecture Table
virtualAddress = 0;
size = 0;
break;
case 9:
virtualAddress = this.Model.OptionalHeader.GlobalPtr?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.GlobalPtr?.Size ?? 0;
virtualAddress = Model.OptionalHeader.GlobalPtr?.VirtualAddress ?? 0;
size = Model.OptionalHeader.GlobalPtr?.Size ?? 0;
break;
case 10:
virtualAddress = this.Model.OptionalHeader.ThreadLocalStorageTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ThreadLocalStorageTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ThreadLocalStorageTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ThreadLocalStorageTable?.Size ?? 0;
break;
case 11:
virtualAddress = this.Model.OptionalHeader.LoadConfigTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.LoadConfigTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.LoadConfigTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.LoadConfigTable?.Size ?? 0;
break;
case 12:
virtualAddress = this.Model.OptionalHeader.BoundImport?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.BoundImport?.Size ?? 0;
virtualAddress = Model.OptionalHeader.BoundImport?.VirtualAddress ?? 0;
size = Model.OptionalHeader.BoundImport?.Size ?? 0;
break;
case 13:
virtualAddress = this.Model.OptionalHeader.ImportAddressTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ImportAddressTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ImportAddressTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ImportAddressTable?.Size ?? 0;
break;
case 14:
virtualAddress = this.Model.OptionalHeader.DelayImportDescriptor?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.DelayImportDescriptor?.Size ?? 0;
virtualAddress = Model.OptionalHeader.DelayImportDescriptor?.VirtualAddress ?? 0;
size = Model.OptionalHeader.DelayImportDescriptor?.Size ?? 0;
break;
case 15:
virtualAddress = this.Model.OptionalHeader.CLRRuntimeHeader?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.CLRRuntimeHeader?.Size ?? 0;
virtualAddress = Model.OptionalHeader.CLRRuntimeHeader?.VirtualAddress ?? 0;
size = Model.OptionalHeader.CLRRuntimeHeader?.Size ?? 0;
break;
case 16: // Reserved
virtualAddress = 0;
@@ -1656,11 +1670,11 @@ namespace SabreTools.Serialization.Wrappers
}
// If there is no section table
if (this.Model.SectionTable == null)
if (Model.SectionTable == null)
return null;
// Get the physical address from the virtual one
uint address = virtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
uint address = virtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (address == 0 || size == 0)
return null;
@@ -1690,7 +1704,7 @@ namespace SabreTools.Serialization.Wrappers
public List<string>? GetTableStrings(int index)
{
// If the table doesn't exist
if (this.Model.OptionalHeader == null || index < 0 || index > 16)
if (Model.OptionalHeader == null || index < 0 || index > 16)
return null;
// Get the virtual address and size from the entries
@@ -1698,64 +1712,64 @@ namespace SabreTools.Serialization.Wrappers
switch (index)
{
case 1:
virtualAddress = this.Model.OptionalHeader.ExportTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ExportTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ExportTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ExportTable?.Size ?? 0;
break;
case 2:
virtualAddress = this.Model.OptionalHeader.ImportTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ImportTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ImportTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ImportTable?.Size ?? 0;
break;
case 3:
virtualAddress = this.Model.OptionalHeader.ResourceTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ResourceTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ResourceTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ResourceTable?.Size ?? 0;
break;
case 4:
virtualAddress = this.Model.OptionalHeader.ExceptionTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ExceptionTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ExceptionTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ExceptionTable?.Size ?? 0;
break;
case 5:
virtualAddress = this.Model.OptionalHeader.CertificateTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.CertificateTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.CertificateTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.CertificateTable?.Size ?? 0;
break;
case 6:
virtualAddress = this.Model.OptionalHeader.BaseRelocationTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.BaseRelocationTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.BaseRelocationTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.BaseRelocationTable?.Size ?? 0;
break;
case 7:
virtualAddress = this.Model.OptionalHeader.Debug?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.Debug?.Size ?? 0;
virtualAddress = Model.OptionalHeader.Debug?.VirtualAddress ?? 0;
size = Model.OptionalHeader.Debug?.Size ?? 0;
break;
case 8: // Architecture Table
virtualAddress = 0;
size = 0;
break;
case 9:
virtualAddress = this.Model.OptionalHeader.GlobalPtr?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.GlobalPtr?.Size ?? 0;
virtualAddress = Model.OptionalHeader.GlobalPtr?.VirtualAddress ?? 0;
size = Model.OptionalHeader.GlobalPtr?.Size ?? 0;
break;
case 10:
virtualAddress = this.Model.OptionalHeader.ThreadLocalStorageTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ThreadLocalStorageTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ThreadLocalStorageTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ThreadLocalStorageTable?.Size ?? 0;
break;
case 11:
virtualAddress = this.Model.OptionalHeader.LoadConfigTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.LoadConfigTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.LoadConfigTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.LoadConfigTable?.Size ?? 0;
break;
case 12:
virtualAddress = this.Model.OptionalHeader.BoundImport?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.BoundImport?.Size ?? 0;
virtualAddress = Model.OptionalHeader.BoundImport?.VirtualAddress ?? 0;
size = Model.OptionalHeader.BoundImport?.Size ?? 0;
break;
case 13:
virtualAddress = this.Model.OptionalHeader.ImportAddressTable?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.ImportAddressTable?.Size ?? 0;
virtualAddress = Model.OptionalHeader.ImportAddressTable?.VirtualAddress ?? 0;
size = Model.OptionalHeader.ImportAddressTable?.Size ?? 0;
break;
case 14:
virtualAddress = this.Model.OptionalHeader.DelayImportDescriptor?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.DelayImportDescriptor?.Size ?? 0;
virtualAddress = Model.OptionalHeader.DelayImportDescriptor?.VirtualAddress ?? 0;
size = Model.OptionalHeader.DelayImportDescriptor?.Size ?? 0;
break;
case 15:
virtualAddress = this.Model.OptionalHeader.CLRRuntimeHeader?.VirtualAddress ?? 0;
size = this.Model.OptionalHeader.CLRRuntimeHeader?.Size ?? 0;
virtualAddress = Model.OptionalHeader.CLRRuntimeHeader?.VirtualAddress ?? 0;
size = Model.OptionalHeader.CLRRuntimeHeader?.Size ?? 0;
break;
case 16: // Reserved
virtualAddress = 0;
@@ -1764,11 +1778,11 @@ namespace SabreTools.Serialization.Wrappers
}
// If there is no section table
if (this.Model.SectionTable == null)
if (Model.SectionTable == null)
return null;
// Get the physical address from the virtual one
uint address = virtualAddress.ConvertVirtualAddress(this.Model.SectionTable);
uint address = virtualAddress.ConvertVirtualAddress(Model.SectionTable);
if (address == 0 || size == 0)
return null;

View File

@@ -43,9 +43,9 @@ namespace SabreTools.Serialization.Wrappers
return null;
// Get the archive count
int archiveCount = this.Model.DirectoryItems == null
int archiveCount = Model.DirectoryItems == null
? 0
: this.Model.DirectoryItems
: Model.DirectoryItems
.Select(di => di?.DirectoryEntry)
.Select(de => de?.ArchiveIndex ?? 0)
.Where(ai => ai != HL_VPK_NO_ARCHIVE)

View File

@@ -29,6 +29,11 @@ namespace SabreTools.Serialization.Wrappers
/// </summary>
protected DataSource _dataSource = DataSource.UNKNOWN;
/// <summary>
/// Lock object for reading from the source
/// </summary>
private readonly object _streamDataLock = new();
/// <summary>
/// Source byte array data
/// </summary>
@@ -86,7 +91,7 @@ namespace SabreTools.Serialization.Wrappers
if (offset < 0 || offset >= data.Length)
throw new ArgumentOutOfRangeException(nameof(offset));
this.Model = model;
Model = model;
_dataSource = DataSource.ByteArray;
_byteArrayData = data;
_byteArrayOffset = offset;
@@ -104,7 +109,7 @@ namespace SabreTools.Serialization.Wrappers
if (data.Length == 0 || !data.CanSeek || !data.CanRead)
throw new ArgumentOutOfRangeException(nameof(data));
this.Model = model;
Model = model;
_dataSource = DataSource.Stream;
_streamData = data;
}
@@ -193,11 +198,14 @@ namespace SabreTools.Serialization.Wrappers
break;
case DataSource.Stream:
long currentLocation = _streamData!.Position;
_streamData.Seek(position, SeekOrigin.Begin);
sectionData = _streamData.ReadBytes(length);
_streamData.Seek(currentLocation, SeekOrigin.Begin);
break;
lock (_streamDataLock)
{
long currentLocation = _streamData!.Position;
_streamData.Seek(position, SeekOrigin.Begin);
sectionData = _streamData.ReadBytes(length);
_streamData.Seek(currentLocation, SeekOrigin.Begin);
break;
}
}
return sectionData;

View File

@@ -22,7 +22,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
var publisherIdentifier = this.Model.PublisherIdentifier;
var publisherIdentifier = Model.PublisherIdentifier;
if (string.IsNullOrEmpty(publisherIdentifier))
return "Unknown";
@@ -40,7 +40,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
var regionIdentifier = this.Model.RegionIdentifier;
var regionIdentifier = Model.RegionIdentifier;
if (Regions.ContainsKey(regionIdentifier))
return Regions[regionIdentifier];
@@ -51,12 +51,12 @@ namespace SabreTools.Serialization.Wrappers
/// <summary>
/// Get the human-readable serial string
/// </summary>
public string Serial => $"{this.Model.PublisherIdentifier}-{this.Model.GameID}";
public string Serial => $"{Model.PublisherIdentifier}-{Model.GameID}";
/// <summary>
/// Get the human-readable version string
/// </summary>
public string Version => $"1.{this.Model.VersionNumber}";
public string Version => $"1.{Model.VersionNumber}";
#endregion

View File

@@ -22,7 +22,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
char mediaSubtype = this.Model.MediaSubtypeIdentifier;
char mediaSubtype = Model.MediaSubtypeIdentifier;
if (MediaSubtypes.ContainsKey(mediaSubtype))
return MediaSubtypes[mediaSubtype];
@@ -37,7 +37,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
var publisherIdentifier = this.Model.PublisherIdentifier;
var publisherIdentifier = Model.PublisherIdentifier;
if (string.IsNullOrEmpty(publisherIdentifier))
return "Unknown";
@@ -55,7 +55,7 @@ namespace SabreTools.Serialization.Wrappers
{
get
{
var regionIdentifier = this.Model.RegionIdentifier;
var regionIdentifier = Model.RegionIdentifier;
if (Regions.ContainsKey(regionIdentifier))
return Regions[regionIdentifier];
@@ -66,12 +66,12 @@ namespace SabreTools.Serialization.Wrappers
/// <summary>
/// Get the human-readable serial string
/// </summary>
public string Serial => $"{this.Model.PublisherIdentifier}-{this.Model.PlatformIdentifier}{this.Model.GameID}";
public string Serial => $"{Model.PublisherIdentifier}-{Model.PlatformIdentifier}{Model.GameID}";
/// <summary>
/// Get the human-readable version string
/// </summary>
public string Version => $"1.{this.Model.SKU}";
public string Version => $"1.{Model.SKU}";
#endregion