Add more NE extensions

This commit is contained in:
Matt Nadareski
2025-08-01 07:58:54 -04:00
parent c54f5b3c5d
commit ca7a109037
2 changed files with 295 additions and 26 deletions

View File

@@ -24,12 +24,278 @@ namespace SabreTools.Serialization.Wrappers
/// <inheritdoc cref="Models.NewExecutable.Executable.NonResidentNameTable"/>
public Models.NewExecutable.NonResidentNameTableEntry[]? NonResidentNameTable => Model.NonResidentNameTable;
/// <summary>
/// Address of the overlay, if it exists
/// </summary>
/// <see href="https://codeberg.org/CYBERDEV/REWise/src/branch/master/src/exefile.c"/>
public int OverlayAddress
{
get
{
lock (_sourceDataLock)
{
// Use the cached data if possible
if (_overlayAddress != null)
return _overlayAddress.Value;
// Get the end of the file, if possible
int endOfFile = GetEndOfFile();
if (endOfFile == -1)
return -1;
// If a required property is missing
if (Header == null || SegmentTable == null || ResourceTable?.ResourceTypes == null)
return -1;
// Search through the segments table to find the furthest
int endOfSectionData = -1;
foreach (var entry in SegmentTable)
{
int offset = (entry.Offset << Header.SegmentAlignmentShiftCount) + entry.Length;
if (offset > endOfSectionData)
endOfSectionData = offset;
}
// Search through the resources table to find the furthest
foreach (var entry in ResourceTable.ResourceTypes)
{
// Skip invalid entries
if (entry.ResourceCount == 0 || entry.Resources == null || entry.Resources.Length == 0)
continue;
foreach (var resource in entry.Resources)
{
int offset = (resource.Offset << ResourceTable.AlignmentShiftCount) + resource.Length;
if (offset > endOfSectionData)
endOfSectionData = offset;
}
}
// If we didn't find the end of section data
if (endOfSectionData <= 0)
endOfSectionData = -1;
// Adjust the position of the data by 705 bytes
// TODO: Investigate what the byte data is
endOfSectionData += 705;
// Cache and return the position
_overlayAddress = endOfSectionData;
return _overlayAddress.Value;
}
}
}
/// <summary>
/// Overlay data, if it exists
/// </summary>
/// <see href="https://codeberg.org/CYBERDEV/REWise/src/branch/master/src/exefile.c"/>
public byte[]? OverlayData
{
get
{
lock (_sourceDataLock)
{
// Use the cached data if possible
if (_overlayData != null)
return _overlayData;
// Get the end of the file, if possible
int endOfFile = GetEndOfFile();
if (endOfFile == -1)
return null;
// If a required property is missing
if (Header == null || SegmentTable == null || ResourceTable?.ResourceTypes == null)
return null;
// Search through the segments table to find the furthest
int endOfSectionData = -1;
foreach (var entry in SegmentTable)
{
int offset = (entry.Offset << Header.SegmentAlignmentShiftCount) + entry.Length;
if (offset > endOfSectionData)
endOfSectionData = offset;
}
// Search through the resources table to find the furthest
foreach (var entry in ResourceTable.ResourceTypes)
{
// Skip invalid entries
if (entry.ResourceCount == 0 || entry.Resources == null || entry.Resources.Length == 0)
continue;
foreach (var resource in entry.Resources)
{
int offset = (resource.Offset << ResourceTable.AlignmentShiftCount) + resource.Length;
if (offset > endOfSectionData)
endOfSectionData = offset;
}
}
// If we didn't find the end of section data
if (endOfSectionData <= 0)
return null;
// Adjust the position of the data by 705 bytes
// TODO: Investigate what the byte data is
endOfSectionData += 705;
// If we're at the end of the file, cache an empty byte array
if (endOfSectionData >= endOfFile)
{
_overlayData = [];
return _overlayData;
}
// Otherwise, cache and return the data
int overlayLength = endOfFile - endOfSectionData;
_overlayData = ReadFromDataSource(endOfSectionData, overlayLength);
return _overlayData;
}
}
}
/// <summary>
/// Overlay strings, if they exist
/// </summary>
public List<string>? OverlayStrings
{
get
{
lock (_sourceDataLock)
{
// Use the cached data if possible
if (_overlayStrings != null)
return _overlayStrings;
// Get the end of the file, if possible
int endOfFile = GetEndOfFile();
if (endOfFile == -1)
return null;
// If a required property is missing
if (Header == null || SegmentTable == null || ResourceTable?.ResourceTypes == null)
return null;
// Search through the segments table to find the furthest
int endOfSectionData = -1;
foreach (var entry in SegmentTable)
{
int offset = (entry.Offset << Header.SegmentAlignmentShiftCount) + entry.Length;
if (offset > endOfSectionData)
endOfSectionData = offset;
}
// Search through the resources table to find the furthest
foreach (var entry in ResourceTable.ResourceTypes)
{
// Skip invalid entries
if (entry.ResourceCount == 0 || entry.Resources == null || entry.Resources.Length == 0)
continue;
foreach (var resource in entry.Resources)
{
int offset = (resource.Offset << ResourceTable.AlignmentShiftCount) + resource.Length;
if (offset > endOfSectionData)
endOfSectionData = offset;
}
}
// If we didn't find the end of section data
if (endOfSectionData <= 0)
return null;
// Adjust the position of the data by 705 bytes
// TODO: Investigate what the byte data is
endOfSectionData += 705;
// If we're at the end of the file, cache an empty list
if (endOfSectionData >= endOfFile)
{
_overlayStrings = [];
return _overlayStrings;
}
// TODO: Revisit the 16 MiB limit
// Cap the check for overlay strings to 16 MiB (arbitrary)
int overlayLength = Math.Min(endOfFile - endOfSectionData, 16 * 1024 * 1024);
// Otherwise, cache and return the strings
_overlayStrings = ReadStringsFromDataSource(endOfSectionData, overlayLength, charLimit: 3);
return _overlayStrings;
}
}
}
/// <inheritdoc cref="Models.NewExecutable.Executable.ResidentNameTable"/>
public Models.NewExecutable.ResidentNameTableEntry[]? ResidentNameTable => Model.ResidentNameTable;
/// <inheritdoc cref="Models.NewExecutable.Executable.ResourceTable"/>
public Models.NewExecutable.ResourceTable? ResourceTable => Model.ResourceTable;
/// <inheritdoc cref="Models.NewExecutable.Executable.SegmentTable"/>
public Models.NewExecutable.SegmentTableEntry[]? SegmentTable => Model.SegmentTable;
/// <inheritdoc cref="Models.NewExecutable.Executable.Stub"/>
public Models.MSDOS.Executable? Stub => Model.Stub;
/// <summary>
/// Stub executable data, if it exists
/// </summary>
public byte[]? StubExecutableData
{
get
{
lock (_sourceDataLock)
{
// If we already have cached data, just use that immediately
if (_stubExecutableData != null)
return _stubExecutableData;
if (Stub?.Header?.NewExeHeaderAddr == null)
return null;
// Populate the raw stub executable data based on the source
int endOfStubHeader = 0x40;
int lengthOfStubExecutableData = (int)Stub.Header.NewExeHeaderAddr - endOfStubHeader;
_stubExecutableData = ReadFromDataSource(endOfStubHeader, lengthOfStubExecutableData);
// Cache and return the stub executable data, even if null
return _stubExecutableData;
}
}
}
#endregion
#region Instance Variables
/// <summary>
/// Address of the overlay, if it exists
/// </summary>
private int? _overlayAddress = null;
/// <summary>
/// Overlay data, if it exists
/// </summary>
private byte[]? _overlayData = null;
/// <summary>
/// Overlay strings, if they exist
/// </summary>
private List<string>? _overlayStrings = null;
/// <summary>
/// Stub executable data, if it exists
/// </summary>
private byte[]? _stubExecutableData = null;
/// <summary>
/// Lock object for reading from the source
/// </summary>
private readonly object _sourceDataLock = new();
#endregion
#region Constructors

View File

@@ -58,21 +58,21 @@ namespace SabreTools.Serialization.Wrappers
lock (_sourceDataLock)
{
// If the section table is missing
if (Model.SectionTable == null)
if (SectionTable == null)
return null;
// If the address is missing
if (Model.OptionalHeader?.AddressOfEntryPoint == null)
if (OptionalHeader?.AddressOfEntryPoint == null)
return null;
// If we have no entry point
int entryPointAddress = (int)Model.OptionalHeader.AddressOfEntryPoint.ConvertVirtualAddress(Model.SectionTable);
int entryPointAddress = (int)OptionalHeader.AddressOfEntryPoint.ConvertVirtualAddress(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 && Model.OptionalHeader.AddressOfEntryPoint == Model.SectionTable[entryPointSection]?.VirtualAddress)
if (entryPointSection >= 0 && OptionalHeader.AddressOfEntryPoint == SectionTable[entryPointSection]?.VirtualAddress)
return GetSectionData(entryPointSection);
// If we already have cached data, just use that immediately
@@ -213,27 +213,27 @@ namespace SabreTools.Serialization.Wrappers
return -1;
// If the section table is missing
if (Model.SectionTable == null)
if (SectionTable == null)
return -1;
// If we have certificate data, use that as the end
if (Model.OptionalHeader?.CertificateTable != null)
if (OptionalHeader?.CertificateTable != null)
{
int certificateTableAddress = (int)Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
int certificateTableAddress = (int)OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(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 Model.SectionTable)
foreach (var section in SectionTable)
{
// If we have an invalid section
if (section == null)
continue;
// If we have an invalid section address
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(SectionTable);
if (sectionAddress == 0)
continue;
@@ -284,27 +284,27 @@ namespace SabreTools.Serialization.Wrappers
return null;
// If the section table is missing
if (Model.SectionTable == null)
if (SectionTable == null)
return null;
// If we have certificate data, use that as the end
if (Model.OptionalHeader?.CertificateTable != null)
if (OptionalHeader?.CertificateTable != null)
{
int certificateTableAddress = (int)Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
int certificateTableAddress = (int)OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(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 Model.SectionTable)
foreach (var section in SectionTable)
{
// If we have an invalid section
if (section == null)
continue;
// If we have an invalid section address
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(SectionTable);
if (sectionAddress == 0)
continue;
@@ -362,27 +362,27 @@ namespace SabreTools.Serialization.Wrappers
return null;
// If the section table is missing
if (Model.SectionTable == null)
if (SectionTable == null)
return null;
// If we have certificate data, use that as the end
if (Model.OptionalHeader?.CertificateTable != null)
if (OptionalHeader?.CertificateTable != null)
{
int certificateTableAddress = (int)Model.OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
int certificateTableAddress = (int)OptionalHeader.CertificateTable.VirtualAddress.ConvertVirtualAddress(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 Model.SectionTable)
foreach (var section in SectionTable)
{
// If we have an invalid section
if (section == null)
continue;
// If we have an invalid section address
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(Model.SectionTable);
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(SectionTable);
if (sectionAddress == 0)
continue;
@@ -424,6 +424,9 @@ namespace SabreTools.Serialization.Wrappers
}
}
/// <inheritdoc cref="Models.PortableExecutable.Executable.ResourceDirectoryTable"/>
public Models.PortableExecutable.ResourceDirectoryTable? ResourceDirectoryTable => Model.ResourceDirectoryTable;
/// <summary>
/// Sanitized section names
/// </summary>
@@ -438,14 +441,14 @@ namespace SabreTools.Serialization.Wrappers
return _sectionNames;
// If there are no sections
if (Model.SectionTable == null)
if (SectionTable == null)
return null;
// Otherwise, build and return the cached array
_sectionNames = new string[Model.SectionTable.Length];
_sectionNames = new string[SectionTable.Length];
for (int i = 0; i < _sectionNames.Length; i++)
{
var section = Model.SectionTable[i];
var section = SectionTable[i];
if (section == null)
continue;
@@ -510,13 +513,13 @@ namespace SabreTools.Serialization.Wrappers
return _resourceData;
// If we have no resource table, just return
if (Model.OptionalHeader?.ResourceTable == null
|| Model.OptionalHeader.ResourceTable.VirtualAddress == 0
|| Model.ResourceDirectoryTable == null)
if (OptionalHeader?.ResourceTable == null
|| OptionalHeader.ResourceTable.VirtualAddress == 0
|| ResourceDirectoryTable == null)
return null;
// Otherwise, build and return the cached dictionary
ParseResourceDirectoryTable(Model.ResourceDirectoryTable, types: []);
ParseResourceDirectoryTable(ResourceDirectoryTable, types: []);
return _resourceData;
}
}