mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-22 14:55:11 +00:00
Add more NE extensions
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user