2024-04-03 20:55:02 -04:00
|
|
|
using System.Collections.Generic;
|
2023-09-08 22:41:49 -04:00
|
|
|
using System.IO;
|
2024-04-03 20:55:02 -04:00
|
|
|
using System.Text;
|
2025-09-26 13:06:18 -04:00
|
|
|
using SabreTools.Data.Models.LinearExecutable;
|
2024-04-17 11:52:22 -04:00
|
|
|
using SabreTools.IO.Extensions;
|
2026-03-24 19:17:25 -04:00
|
|
|
using SabreTools.Numerics.Extensions;
|
2025-09-26 13:06:18 -04:00
|
|
|
using static SabreTools.Data.Models.LinearExecutable.Constants;
|
2023-09-08 22:41:49 -04:00
|
|
|
|
2026-01-27 12:03:01 -05:00
|
|
|
#pragma warning disable IDE0017 // Simplify object initialization
|
2025-09-26 14:57:20 -04:00
|
|
|
namespace SabreTools.Serialization.Readers
|
2023-09-08 22:41:49 -04:00
|
|
|
{
|
2025-09-26 15:02:43 -04:00
|
|
|
public class LinearExecutable : BaseBinaryReader<Executable>
|
2023-09-08 22:41:49 -04:00
|
|
|
{
|
2024-04-03 20:55:02 -04:00
|
|
|
/// <inheritdoc/>
|
2024-04-04 01:55:05 -04:00
|
|
|
public override Executable? Deserialize(Stream? data)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
|
|
|
|
// If the data is invalid
|
2026-01-25 14:30:18 -05:00
|
|
|
if (data is null || !data.CanRead)
|
2024-04-03 20:55:02 -04:00
|
|
|
return null;
|
|
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Cache the current offset
|
2025-08-19 09:09:33 -04:00
|
|
|
long initialOffset = data.Position;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create a new executable to fill
|
|
|
|
|
var executable = new Executable();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region MS-DOS Stub
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Parse the MS-DOS stub
|
|
|
|
|
var stub = new MSDOS().Deserialize(data);
|
2026-01-25 14:30:18 -05:00
|
|
|
if (stub?.Header is null || stub.Header.NewExeHeaderAddr == 0)
|
2024-11-28 22:57:12 -05:00
|
|
|
return null;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Set the MS-DOS stub
|
|
|
|
|
executable.Stub = stub;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Information Block
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the executable header
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(initialOffset + stub.Header.NewExeHeaderAddr, SeekOrigin.Begin);
|
2024-12-16 23:08:45 -05:00
|
|
|
var informationBlock = ParseInformationBlock(data);
|
|
|
|
|
if (informationBlock.Signature != LESignatureString && informationBlock.Signature != LXSignatureString)
|
2024-11-28 22:57:12 -05:00
|
|
|
return null;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Set the executable header
|
|
|
|
|
executable.InformationBlock = informationBlock;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Object Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the object table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
long offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.ObjectTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-11-28 22:57:12 -05:00
|
|
|
// Seek to the object table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the object table
|
|
|
|
|
executable.ObjectTable = new ObjectTableEntry[informationBlock.ObjectTableCount];
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the object table
|
|
|
|
|
for (int i = 0; i < executable.ObjectTable.Length; i++)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
executable.ObjectTable[i] = ParseObjectTableEntry(data);
|
2024-11-28 22:57:12 -05:00
|
|
|
}
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Object Page Map
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the object page map offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.ObjectPageMapOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-11-28 22:57:12 -05:00
|
|
|
// Seek to the object page map
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the object page map
|
|
|
|
|
executable.ObjectPageMap = new ObjectPageMapEntry[informationBlock.ObjectTableCount];
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the object page map
|
|
|
|
|
for (int i = 0; i < executable.ObjectPageMap.Length; i++)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
executable.ObjectPageMap[i] = ParseObjectPageMapEntry(data);
|
2024-11-28 22:57:12 -05:00
|
|
|
}
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Object Iterate Data Map
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.ObjectIterateDataMapOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the object page map
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// TODO: Implement when model found
|
|
|
|
|
// No model has been found in the documentation about what
|
|
|
|
|
// each of the entries looks like for this map.
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Resource Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the resource table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.ResourceTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-11-28 22:57:12 -05:00
|
|
|
// Seek to the resource table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the resource table
|
|
|
|
|
executable.ResourceTable = new ResourceTableEntry[informationBlock.ResourceTableCount];
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the resource table
|
|
|
|
|
for (int i = 0; i < executable.ResourceTable.Length; i++)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
executable.ResourceTable[i] = ParseResourceTableEntry(data);
|
2024-11-28 22:57:12 -05:00
|
|
|
}
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Resident Names Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the resident names table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.ResidentNamesTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-11-28 22:57:12 -05:00
|
|
|
// Seek to the resident names table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the resident names table
|
|
|
|
|
var residentNamesTable = new List<ResidentNamesTableEntry>();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the resident names table
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
var entry = ParseResidentNamesTableEntry(data);
|
|
|
|
|
residentNamesTable.Add(entry);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// If we have a 0-length entry
|
|
|
|
|
if (entry.Length == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Assign the resident names table
|
|
|
|
|
executable.ResidentNamesTable = [.. residentNamesTable];
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Entry Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the entry table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.EntryTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-11-28 22:57:12 -05:00
|
|
|
// Seek to the entry table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-11-28 22:57:12 -05:00
|
|
|
|
|
|
|
|
// Create the entry table
|
|
|
|
|
var entryTable = new List<EntryTableBundle>();
|
|
|
|
|
|
|
|
|
|
// Try to parse the entry table
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
var bundle = ParseEntryTableBundle(data);
|
2026-01-25 14:32:49 -05:00
|
|
|
if (bundle is not null)
|
2024-11-28 22:57:12 -05:00
|
|
|
entryTable.Add(bundle);
|
|
|
|
|
|
|
|
|
|
// If we have a 0-length entry
|
2026-01-25 14:30:18 -05:00
|
|
|
if (bundle is null || bundle.Entries == 0)
|
2024-11-28 22:57:12 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assign the entry table
|
|
|
|
|
executable.EntryTable = [.. entryTable];
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Module Format Directives Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the module format directives table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.ModuleDirectivesTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the module format directives table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the module format directives table
|
|
|
|
|
executable.ModuleFormatDirectivesTable = new ModuleFormatDirectivesTableEntry[informationBlock.ModuleDirectivesCount];
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the module format directives table
|
|
|
|
|
for (int i = 0; i < executable.ModuleFormatDirectivesTable.Length; i++)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
executable.ModuleFormatDirectivesTable[i] = ParseModuleFormatDirectivesTableEntry(data);
|
2024-11-28 22:57:12 -05:00
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Verify Record Directive Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// TODO: Figure out where the offset to this table is stored
|
|
|
|
|
// The documentation suggests it's either part of or immediately following
|
|
|
|
|
// the Module Format Directives Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Fix-up Page Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the fix-up page table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.FixupPageTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the fix-up page table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the fix-up page table
|
2026-01-25 16:15:05 -05:00
|
|
|
executable.FixupPageTable = new FixupPageTableEntry[(executable.ObjectPageMap?.Length ?? 0) + 1];
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the fix-up page table
|
|
|
|
|
for (int i = 0; i < executable.FixupPageTable.Length; i++)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
executable.FixupPageTable[i] = ParseFixupPageTableEntry(data);
|
2024-11-28 22:57:12 -05:00
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Fix-up Record Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the fix-up record table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.FixupRecordTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the fix-up record table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the fix-up record table
|
2026-01-25 16:15:05 -05:00
|
|
|
executable.FixupRecordTable = new FixupRecordTableEntry[(executable.ObjectPageMap?.Length ?? 0) + 1];
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the fix-up record table
|
|
|
|
|
for (int i = 0; i < executable.FixupRecordTable.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
var entry = ParseFixupRecordTableEntry(data);
|
2026-01-25 14:30:18 -05:00
|
|
|
if (entry is null)
|
2024-11-28 22:57:12 -05:00
|
|
|
return null;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
executable.FixupRecordTable[i] = entry;
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Imported Module Name Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the imported module name table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.ImportedModulesNameTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the imported module name table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the imported module name table
|
|
|
|
|
executable.ImportModuleNameTable = new ImportModuleNameTableEntry[informationBlock.ImportedModulesCount];
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the imported module name table
|
|
|
|
|
for (int i = 0; i < executable.ImportModuleNameTable.Length; i++)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
executable.ImportModuleNameTable[i] = ParseImportModuleNameTableEntry(data);
|
2024-11-28 22:57:12 -05:00
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Imported Module Procedure Name Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the imported module procedure name table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.ImportProcedureNameTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the imported module procedure name table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the size of the imported module procedure name table
|
|
|
|
|
long tableSize = informationBlock.FixupPageTableOffset
|
|
|
|
|
+ informationBlock.FixupSectionSize
|
|
|
|
|
- informationBlock.ImportProcedureNameTableOffset;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the imported module procedure name table
|
|
|
|
|
var importModuleProcedureNameTable = new List<ImportModuleProcedureNameTableEntry>();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the imported module procedure name table
|
|
|
|
|
while (data.Position < offset + tableSize)
|
|
|
|
|
{
|
|
|
|
|
var entry = ParseImportModuleProcedureNameTableEntry(data);
|
|
|
|
|
importModuleProcedureNameTable.Add(entry);
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Assign the resident names table
|
|
|
|
|
executable.ImportModuleProcedureNameTable = [.. importModuleProcedureNameTable];
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Per-Page Checksum Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the per-page checksum table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.PerPageChecksumTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the per-page checksum name table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the per-page checksum name table
|
|
|
|
|
executable.PerPageChecksumTable = new PerPageChecksumTableEntry[informationBlock.ModuleNumberPages];
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the per-page checksum name table
|
|
|
|
|
for (int i = 0; i < executable.PerPageChecksumTable.Length; i++)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
executable.PerPageChecksumTable[i] = ParsePerPageChecksumTableEntry(data);
|
2024-11-28 22:57:12 -05:00
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Non-Resident Names Table
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the non-resident names table offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.NonResidentNamesTableOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the non-resident names table
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Create the non-resident names table
|
|
|
|
|
var nonResidentNamesTable = new List<NonResidentNamesTableEntry>();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the non-resident names table
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
var entry = ParseNonResidentNameTableEntry(data);
|
|
|
|
|
nonResidentNamesTable.Add(entry);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// If we have a 0-length entry
|
|
|
|
|
if (entry.Length == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Assign the non-resident names table
|
|
|
|
|
executable.NonResidentNamesTable = [.. nonResidentNamesTable];
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#region Debug Information
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Get the debug information offset
|
2025-08-19 09:09:33 -04:00
|
|
|
offset = initialOffset
|
|
|
|
|
+ stub.Header.NewExeHeaderAddr
|
|
|
|
|
+ informationBlock.DebugInformationOffset;
|
|
|
|
|
if (offset > initialOffset + stub.Header.NewExeHeaderAddr && offset < data.Length)
|
2024-11-28 22:57:12 -05:00
|
|
|
{
|
|
|
|
|
// Seek to the debug information
|
2025-10-27 22:43:56 -04:00
|
|
|
data.SeekIfPossible(offset, SeekOrigin.Begin);
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Try to parse the debug information
|
|
|
|
|
var debugInformation = ParseDebugInformation(data, informationBlock.DebugInformationLength);
|
2024-12-16 23:08:45 -05:00
|
|
|
if (debugInformation.Signature != DebugInformationSignatureString)
|
2024-11-28 22:57:12 -05:00
|
|
|
return null;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
// Set the debug information
|
|
|
|
|
executable.DebugInformation = debugInformation;
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
#endregion
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-11-28 22:57:12 -05:00
|
|
|
return executable;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// Ignore the actual error
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// Parse a Stream into a DebugInformation
|
2024-04-03 20:55:02 -04:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// <param name="size">Total size of the debug information</param>
|
|
|
|
|
/// <returns>Filled DebugInformation on success, null on error</returns>
|
|
|
|
|
public static DebugInformation ParseDebugInformation(Stream data, long size)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
var obj = new DebugInformation();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
byte[] signature = data.ReadBytes(3);
|
|
|
|
|
obj.Signature = Encoding.ASCII.GetString(signature);
|
|
|
|
|
obj.FormatType = (DebugFormatType)data.ReadByteValue();
|
|
|
|
|
obj.DebuggerData = data.ReadBytes((int)(size - 4));
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
return obj;
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// Parse a Stream into an EntryTableBundle
|
2024-04-03 20:55:02 -04:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// <returns>Filled EntryTableBundle on success, null on error</returns>
|
2024-04-03 20:55:02 -04:00
|
|
|
public static EntryTableBundle? ParseEntryTableBundle(Stream data)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
var obj = new EntryTableBundle();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.Entries = data.ReadByteValue();
|
|
|
|
|
if (obj.Entries == 0)
|
|
|
|
|
return obj;
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.BundleType = (BundleType)data.ReadByteValue();
|
|
|
|
|
obj.TableEntries = new EntryTableEntry[obj.Entries];
|
|
|
|
|
for (int i = 0; i < obj.Entries; i++)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
|
|
|
|
var entry = new EntryTableEntry();
|
|
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
switch (obj.BundleType & ~BundleType.ParameterTypingInformationPresent)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
|
|
|
|
case BundleType.UnusedEntry:
|
|
|
|
|
// Empty entry with no information
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BundleType.SixteenBitEntry:
|
2024-12-16 23:08:45 -05:00
|
|
|
entry.SixteenBitObjectNumber = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
entry.SixteenBitEntryFlags = (EntryFlags)data.ReadByteValue();
|
2024-12-16 23:08:45 -05:00
|
|
|
entry.SixteenBitOffset = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BundleType.TwoEightySixCallGateEntry:
|
2024-12-16 23:08:45 -05:00
|
|
|
entry.TwoEightySixObjectNumber = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
entry.TwoEightySixEntryFlags = (EntryFlags)data.ReadByteValue();
|
2024-12-16 23:08:45 -05:00
|
|
|
entry.TwoEightySixOffset = data.ReadUInt16LittleEndian();
|
|
|
|
|
entry.TwoEightySixCallgate = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BundleType.ThirtyTwoBitEntry:
|
2024-12-16 23:08:45 -05:00
|
|
|
entry.ThirtyTwoBitObjectNumber = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
entry.ThirtyTwoBitEntryFlags = (EntryFlags)data.ReadByteValue();
|
2024-12-16 23:08:45 -05:00
|
|
|
entry.ThirtyTwoBitOffset = data.ReadUInt32LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BundleType.ForwarderEntry:
|
2024-12-16 23:08:45 -05:00
|
|
|
entry.ForwarderReserved = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
entry.ForwarderFlags = (ForwarderFlags)data.ReadByteValue();
|
2024-12-16 23:08:45 -05:00
|
|
|
entry.ForwarderModuleOrdinalNumber = data.ReadUInt16LittleEndian();
|
|
|
|
|
entry.ProcedureNameOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
entry.ImportOrdinalNumber = data.ReadUInt32LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
break;
|
|
|
|
|
|
2026-01-25 16:15:05 -05:00
|
|
|
// Bitflag that is ignored
|
|
|
|
|
case BundleType.ParameterTypingInformationPresent:
|
|
|
|
|
break;
|
|
|
|
|
|
2024-04-03 20:55:02 -04:00
|
|
|
default:
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.TableEntries[i] = entry;
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Stream into an FixupPageTableEntry
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
|
|
|
|
/// <returns>Filled FixupPageTableEntry on success, null on error</returns>
|
|
|
|
|
public static FixupPageTableEntry ParseFixupPageTableEntry(Stream data)
|
|
|
|
|
{
|
|
|
|
|
var obj = new FixupPageTableEntry();
|
|
|
|
|
|
|
|
|
|
obj.Offset = data.ReadUInt32LittleEndian();
|
|
|
|
|
|
|
|
|
|
return obj;
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// Parse a Stream into a FixupRecordTableEntry
|
2024-04-03 20:55:02 -04:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// <returns>Filled FixupRecordTableEntry on success, null on error</returns>
|
2024-04-03 20:55:02 -04:00
|
|
|
public static FixupRecordTableEntry? ParseFixupRecordTableEntry(Stream data)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
var obj = new FixupRecordTableEntry();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.SourceType = (FixupRecordSourceType)data.ReadByteValue();
|
|
|
|
|
obj.TargetFlags = (FixupRecordTargetFlags)data.ReadByteValue();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
|
|
|
|
// Source list flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.SourceType & FixupRecordSourceType.SourceListFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.SourceType.HasFlag(FixupRecordSourceType.SourceListFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.SourceOffsetListCount = data.ReadByteValue();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.SourceOffset = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
|
|
|
|
// OBJECT / TRGOFF
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.InternalReference) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.InternalReference))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// 16-bit Object Number/Module Ordinal Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.TargetObjectNumberWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.TargetObjectNumberByte = data.ReadByteValue();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
|
|
|
|
// 16-bit Selector fixup
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.SourceType & FixupRecordSourceType.SixteenBitSelectorFixup) == 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (!obj.SourceType.HasFlag(FixupRecordSourceType.SixteenBitSelectorFixup))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// 32-bit Target Offset Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.TargetOffsetDWORD = data.ReadUInt32LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.TargetOffsetWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MOD ORD# / IMPORT ORD / ADDITIVE
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
else if ((obj.TargetFlags & FixupRecordTargetFlags.ImportedReferenceByOrdinal) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
else if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ImportedReferenceByOrdinal))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// 16-bit Object Number/Module Ordinal Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
|
|
|
|
// 8-bit Ordinal Flag & 32-bit Target Offset Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.EightBitOrdinalFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.EightBitOrdinalFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.ImportedOrdinalNumberByte = data.ReadByteValue();
|
2024-04-03 20:55:02 -04:00
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
else if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
else if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.ImportedOrdinalNumberDWORD = data.ReadUInt32LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.ImportedOrdinalNumberWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
|
|
|
|
// Additive Fixup Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// 32-bit Additive Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.AdditiveFixupValueDWORD = data.ReadUInt32LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.AdditiveFixupValueWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MOD ORD# / PROCEDURE NAME OFFSET / ADDITIVE
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
else if ((obj.TargetFlags & FixupRecordTargetFlags.ImportedReferenceByName) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
else if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ImportedReferenceByName))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// 16-bit Object Number/Module Ordinal Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
|
|
|
|
// 32-bit Target Offset Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitTargetOffsetFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OffsetImportProcedureNameTableDWORD = data.ReadUInt32LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OffsetImportProcedureNameTableWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
|
|
|
|
// Additive Fixup Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// 32-bit Additive Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.AdditiveFixupValueDWORD = data.ReadUInt32LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.AdditiveFixupValueWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ORD # / ADDITIVE
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
else if ((obj.TargetFlags & FixupRecordTargetFlags.InternalReferenceViaEntryTable) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
else if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.InternalReferenceViaEntryTable))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// 16-bit Object Number/Module Ordinal Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.SixteenBitObjectNumberModuleOrdinalFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OrdinalIndexImportModuleNameTableWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OrdinalIndexImportModuleNameTableByte = data.ReadByteValue();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
|
|
|
|
// Additive Fixup Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.AdditiveFixupFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.AdditiveFixupFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
// 32-bit Additive Flag
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.TargetFlags & FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.TargetFlags.HasFlag(FixupRecordTargetFlags.ThirtyTwoBitAdditiveFixupFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.AdditiveFixupValueDWORD = data.ReadUInt32LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
else
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.AdditiveFixupValueWORD = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No other top-level flags recognized
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region SCROFFn
|
|
|
|
|
|
|
|
|
|
#if NET20 || NET35
|
2024-12-16 23:08:45 -05:00
|
|
|
if ((obj.SourceType & FixupRecordSourceType.SourceListFlag) != 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
#else
|
2024-12-16 23:08:45 -05:00
|
|
|
if (obj.SourceType.HasFlag(FixupRecordSourceType.SourceListFlag))
|
2024-04-03 20:55:02 -04:00
|
|
|
#endif
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.SourceOffsetList = new ushort[obj.SourceOffsetListCount];
|
|
|
|
|
for (int i = 0; i < obj.SourceOffsetList.Length; i++)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.SourceOffsetList[i] = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
return obj;
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// Parse a Stream into an ImportModuleNameTableEntry
|
2024-04-03 20:55:02 -04:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// <returns>Filled ImportModuleNameTableEntry on success, null on error</returns>
|
2024-04-03 20:55:02 -04:00
|
|
|
public static ImportModuleNameTableEntry ParseImportModuleNameTableEntry(Stream data)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
var obj = new ImportModuleNameTableEntry();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.Length = data.ReadByteValue();
|
|
|
|
|
if (obj.Length > 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
byte[] name = data.ReadBytes(obj.Length);
|
|
|
|
|
obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
return obj;
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// Parse a Stream into an ImportModuleProcedureNameTableEntry
|
2024-04-03 20:55:02 -04:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// <returns>Filled ImportModuleProcedureNameTableEntry on success, null on error</returns>
|
2024-04-03 20:55:02 -04:00
|
|
|
public static ImportModuleProcedureNameTableEntry ParseImportModuleProcedureNameTableEntry(Stream data)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
var obj = new ImportModuleProcedureNameTableEntry();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.Length = data.ReadByteValue();
|
|
|
|
|
if (obj.Length > 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
byte[] name = data.ReadBytes(obj.Length);
|
|
|
|
|
obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Stream into a InformationBlock
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
|
|
|
|
/// <returns>Filled InformationBlock on success, null on error</returns>
|
|
|
|
|
public static InformationBlock ParseInformationBlock(Stream data)
|
|
|
|
|
{
|
|
|
|
|
var obj = new InformationBlock();
|
|
|
|
|
|
|
|
|
|
byte[] signature = data.ReadBytes(2);
|
|
|
|
|
obj.Signature = Encoding.ASCII.GetString(signature);
|
|
|
|
|
obj.ByteOrder = (ByteOrder)data.ReadByteValue();
|
|
|
|
|
obj.WordOrder = (WordOrder)data.ReadByteValue();
|
|
|
|
|
obj.ExecutableFormatLevel = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.CPUType = (CPUType)data.ReadUInt16LittleEndian();
|
|
|
|
|
obj.ModuleOS = (OperatingSystem)data.ReadUInt16LittleEndian();
|
|
|
|
|
obj.ModuleVersion = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ModuleTypeFlags = (ModuleFlags)data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ModuleNumberPages = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.InitialObjectCS = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.InitialEIP = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.InitialObjectSS = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.InitialESP = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.MemoryPageSize = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.BytesOnLastPage = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.FixupSectionSize = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.FixupSectionChecksum = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.LoaderSectionSize = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.LoaderSectionChecksum = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ObjectTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ObjectTableCount = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ObjectPageMapOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ObjectIterateDataMapOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ResourceTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ResourceTableCount = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ResidentNamesTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.EntryTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ModuleDirectivesTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ModuleDirectivesCount = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.FixupPageTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.FixupRecordTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ImportedModulesNameTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ImportedModulesCount = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ImportProcedureNameTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.PerPageChecksumTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.DataPagesOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.PreloadPageCount = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.NonResidentNamesTableOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.NonResidentNamesTableLength = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.NonResidentNamesTableChecksum = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.AutomaticDataObject = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.DebugInformationOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.DebugInformationLength = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.PreloadInstancePagesNumber = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.DemandInstancePagesNumber = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ExtraHeapAllocation = data.ReadUInt32LittleEndian();
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Stream into a ModuleFormatDirectivesTableEntry
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
|
|
|
|
/// <returns>Filled ModuleFormatDirectivesTableEntry on success, null on error</returns>
|
|
|
|
|
public static ModuleFormatDirectivesTableEntry ParseModuleFormatDirectivesTableEntry(Stream data)
|
|
|
|
|
{
|
|
|
|
|
var obj = new ModuleFormatDirectivesTableEntry();
|
|
|
|
|
|
|
|
|
|
obj.DirectiveNumber = (DirectiveNumber)data.ReadUInt16LittleEndian();
|
|
|
|
|
obj.DirectiveDataLength = data.ReadUInt16LittleEndian();
|
|
|
|
|
obj.DirectiveDataOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
|
|
|
|
|
return obj;
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Stream into a non-resident names table entry
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
|
|
|
|
/// <returns>Filled non-resident names table entry on success, null on error</returns>
|
|
|
|
|
public static NonResidentNamesTableEntry ParseNonResidentNameTableEntry(Stream data)
|
|
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
var obj = new NonResidentNamesTableEntry();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.Length = data.ReadByteValue();
|
|
|
|
|
if (obj.Length > 0)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
byte[] name = data.ReadBytes(obj.Length);
|
|
|
|
|
obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OrdinalNumber = data.ReadUInt16LittleEndian();
|
|
|
|
|
|
|
|
|
|
return obj;
|
2024-04-03 20:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// Parse a Stream into a ObjectPageMapEntry
|
2024-04-03 20:55:02 -04:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
2024-12-16 23:08:45 -05:00
|
|
|
/// <returns>Filled ObjectPageMapEntry on success, null on error</returns>
|
|
|
|
|
public static ObjectPageMapEntry ParseObjectPageMapEntry(Stream data)
|
2024-04-03 20:55:02 -04:00
|
|
|
{
|
2024-12-16 23:08:45 -05:00
|
|
|
var obj = new ObjectPageMapEntry();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.PageDataOffset = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.DataSize = data.ReadUInt16LittleEndian();
|
|
|
|
|
obj.Flags = (ObjectPageFlags)data.ReadUInt16LittleEndian();
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Stream into a ObjectTableEntry
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
|
|
|
|
/// <returns>Filled ObjectTableEntry on success, null on error</returns>
|
|
|
|
|
public static ObjectTableEntry ParseObjectTableEntry(Stream data)
|
|
|
|
|
{
|
|
|
|
|
var obj = new ObjectTableEntry();
|
|
|
|
|
|
|
|
|
|
obj.RelocationBaseAddress = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ObjectFlags = (ObjectFlags)data.ReadUInt16LittleEndian();
|
|
|
|
|
obj.PageTableIndex = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.PageTableEntries = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.Reserved = data.ReadUInt32LittleEndian();
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Stream into a PerPageChecksumTableEntry
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
|
|
|
|
/// <returns>Filled PerPageChecksumTableEntry on success, null on error</returns>
|
|
|
|
|
public static PerPageChecksumTableEntry ParsePerPageChecksumTableEntry(Stream data)
|
|
|
|
|
{
|
|
|
|
|
var obj = new PerPageChecksumTableEntry();
|
|
|
|
|
|
|
|
|
|
obj.Checksum = data.ReadUInt32LittleEndian();
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Stream into a ResourceTableEntry
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
|
|
|
|
/// <returns>Filled ResourceTableEntry on success, null on error</returns>
|
|
|
|
|
public static ResourceTableEntry ParseResourceTableEntry(Stream data)
|
|
|
|
|
{
|
|
|
|
|
var obj = new ResourceTableEntry();
|
|
|
|
|
|
|
|
|
|
obj.TypeID = (ResourceTableEntryType)data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.NameID = data.ReadUInt16LittleEndian();
|
|
|
|
|
obj.ResourceSize = data.ReadUInt32LittleEndian();
|
|
|
|
|
obj.ObjectNumber = data.ReadUInt16LittleEndian();
|
|
|
|
|
obj.Offset = data.ReadUInt32LittleEndian();
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse a Stream into a ResidentNamesTableEntry
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Stream to parse</param>
|
|
|
|
|
/// <returns>Filled ResidentNamesTableEntry on success, null on error</returns>
|
|
|
|
|
public static ResidentNamesTableEntry ParseResidentNamesTableEntry(Stream data)
|
|
|
|
|
{
|
|
|
|
|
var obj = new ResidentNamesTableEntry();
|
|
|
|
|
|
|
|
|
|
obj.Length = data.ReadByteValue();
|
|
|
|
|
if (obj.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
byte[] name = data.ReadBytes(obj.Length);
|
|
|
|
|
obj.Name = Encoding.ASCII.GetString(name).TrimEnd('\0');
|
|
|
|
|
}
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
obj.OrdinalNumber = data.ReadUInt16LittleEndian();
|
2024-04-03 20:55:02 -04:00
|
|
|
|
2024-12-16 23:08:45 -05:00
|
|
|
return obj;
|
2024-04-03 17:27:08 -04:00
|
|
|
}
|
2023-09-08 22:41:49 -04:00
|
|
|
}
|
2025-07-24 09:31:28 -04:00
|
|
|
}
|