diff --git a/SabreTools.Serialization.Test/SabreTools.Serialization.Test.csproj b/SabreTools.Serialization.Test/SabreTools.Serialization.Test.csproj
index df50e683..698dfe96 100644
--- a/SabreTools.Serialization.Test/SabreTools.Serialization.Test.csproj
+++ b/SabreTools.Serialization.Test/SabreTools.Serialization.Test.csproj
@@ -28,7 +28,6 @@
- runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/SabreTools.Serialization/Deserializers/LinearExecutable.cs b/SabreTools.Serialization/Deserializers/LinearExecutable.cs
index e9a47460..b5d0c339 100644
--- a/SabreTools.Serialization/Deserializers/LinearExecutable.cs
+++ b/SabreTools.Serialization/Deserializers/LinearExecutable.cs
@@ -2,8 +2,8 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.LinearExecutable;
-using static SabreTools.Models.LinearExecutable.Constants;
+using SabreTools.Serialization.Models.LinearExecutable;
+using static SabreTools.Serialization.Models.LinearExecutable.Constants;
namespace SabreTools.Serialization.Deserializers
{
diff --git a/SabreTools.Serialization/Deserializers/MSDOS.cs b/SabreTools.Serialization/Deserializers/MSDOS.cs
index b026a24a..48c18296 100644
--- a/SabreTools.Serialization/Deserializers/MSDOS.cs
+++ b/SabreTools.Serialization/Deserializers/MSDOS.cs
@@ -1,8 +1,8 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.MSDOS;
-using static SabreTools.Models.MSDOS.Constants;
+using SabreTools.Serialization.Models.MSDOS;
+using static SabreTools.Serialization.Models.MSDOS.Constants;
namespace SabreTools.Serialization.Deserializers
{
diff --git a/SabreTools.Serialization/Deserializers/NewExecutable.cs b/SabreTools.Serialization/Deserializers/NewExecutable.cs
index 313cab6e..8e59dc3e 100644
--- a/SabreTools.Serialization/Deserializers/NewExecutable.cs
+++ b/SabreTools.Serialization/Deserializers/NewExecutable.cs
@@ -2,9 +2,9 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.NewExecutable;
using SabreTools.Serialization.Extensions;
-using static SabreTools.Models.NewExecutable.Constants;
+using SabreTools.Serialization.Models.NewExecutable;
+using static SabreTools.Serialization.Models.NewExecutable.Constants;
namespace SabreTools.Serialization.Deserializers
{
@@ -253,7 +253,7 @@ namespace SabreTools.Serialization.Deserializers
obj.MovableEntriesCount = data.ReadUInt16LittleEndian();
obj.SegmentAlignmentShiftCount = data.ReadUInt16LittleEndian();
obj.ResourceEntriesCount = data.ReadUInt16LittleEndian();
- obj.TargetOperatingSystem = (SabreTools.Models.NewExecutable.OperatingSystem)data.ReadByteValue();
+ obj.TargetOperatingSystem = (SabreTools.Serialization.Models.NewExecutable.OperatingSystem)data.ReadByteValue();
obj.AdditionalFlags = (OS2Flag)data.ReadByteValue();
obj.ReturnThunkOffset = data.ReadUInt16LittleEndian();
obj.SegmentReferenceThunkOffset = data.ReadUInt16LittleEndian();
diff --git a/SabreTools.Serialization/Deserializers/PortableExecutable.cs b/SabreTools.Serialization/Deserializers/PortableExecutable.cs
index dd7ac092..36bbfaa8 100644
--- a/SabreTools.Serialization/Deserializers/PortableExecutable.cs
+++ b/SabreTools.Serialization/Deserializers/PortableExecutable.cs
@@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.COFF;
-using SabreTools.Models.COFF.SymbolTableEntries;
-using SabreTools.Models.PortableExecutable;
using SabreTools.Serialization.Extensions;
-using static SabreTools.Models.COFF.Constants;
-using static SabreTools.Models.PortableExecutable.Constants;
+using SabreTools.Serialization.Models.COFF;
+using SabreTools.Serialization.Models.COFF.SymbolTableEntries;
+using SabreTools.Serialization.Models.PortableExecutable;
+using static SabreTools.Serialization.Models.COFF.Constants;
+using static SabreTools.Serialization.Models.PortableExecutable.Constants;
namespace SabreTools.Serialization.Deserializers
{
@@ -74,7 +74,7 @@ namespace SabreTools.Serialization.Deserializers
#region Optional Header
// If the optional header exists
- SabreTools.Models.PortableExecutable.OptionalHeader? optionalHeader = null;
+ SabreTools.Serialization.Models.PortableExecutable.OptionalHeader? optionalHeader = null;
if (fileHeader.SizeOfOptionalHeader > 0)
{
// Parse the optional header
@@ -337,12 +337,12 @@ namespace SabreTools.Serialization.Deserializers
int length = tableSize - tableOffset;
// Add the hidden entry
- pex.ResourceDirectoryTable.Entries[localEntries.Length - 1] = new SabreTools.Models.PortableExecutable.Resource.DirectoryEntry
+ pex.ResourceDirectoryTable.Entries[localEntries.Length - 1] = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryEntry
{
- Name = new SabreTools.Models.PortableExecutable.Resource.DirectoryString { UnicodeString = Encoding.Unicode.GetBytes("HIDDEN RESOURCE") },
+ Name = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryString { UnicodeString = Encoding.Unicode.GetBytes("HIDDEN RESOURCE") },
IntegerID = uint.MaxValue,
DataEntryOffset = (uint)tableOffset,
- DataEntry = new SabreTools.Models.PortableExecutable.Resource.DataEntry
+ DataEntry = new SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry
{
Size = (uint)length,
Data = tableData.ReadBytes(ref tableOffset, length),
@@ -471,12 +471,12 @@ namespace SabreTools.Serialization.Deserializers
///
/// Byte array to parse
/// Filled attribute certificate on success, null on error
- public static SabreTools.Models.PortableExecutable.AttributeCertificate.Entry[]? ParseAttributeCertificateTable(byte[]? data)
+ public static SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate.Entry[]? ParseAttributeCertificateTable(byte[]? data)
{
if (data == null)
return null;
- var obj = new List();
+ var obj = new List();
int offset = 0;
while (offset < data.Length)
@@ -502,9 +502,9 @@ namespace SabreTools.Serialization.Deserializers
///
/// Byte array to parse
/// Filled AttributeCertificateTableEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.AttributeCertificate.Entry? ParseAttributeCertificateTableEntry(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate.Entry? ParseAttributeCertificateTableEntry(byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.AttributeCertificate.Entry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate.Entry();
obj.Length = data.ReadUInt32LittleEndian(ref offset);
if (obj.Length < 8)
@@ -526,9 +526,9 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled BaseRelocationBlock on success, null on error
- public static SabreTools.Models.PortableExecutable.BaseRelocation.Block? ParseBaseRelocationBlock(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.Block? ParseBaseRelocationBlock(byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.BaseRelocation.Block();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.Block();
obj.PageRVA = data.ReadUInt32LittleEndian(ref offset);
obj.BlockSize = data.ReadUInt32LittleEndian(ref offset);
@@ -542,7 +542,7 @@ namespace SabreTools.Serialization.Deserializers
return obj;
int entryCount = ((int)obj.BlockSize - 8) / 2;
- obj.TypeOffsetFieldEntries = new SabreTools.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry[entryCount];
+ obj.TypeOffsetFieldEntries = new SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry[entryCount];
for (int i = 0; i < obj.TypeOffsetFieldEntries.Length; i++)
{
if (offset + 2 >= data.Length)
@@ -559,12 +559,12 @@ namespace SabreTools.Serialization.Deserializers
///
/// Byte array to parse
/// Filled base relocation table on success, null on error
- public static SabreTools.Models.PortableExecutable.BaseRelocation.Block[]? ParseBaseRelocationTable(byte[]? data)
+ public static SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.Block[]? ParseBaseRelocationTable(byte[]? data)
{
if (data == null)
return null;
- var obj = new List();
+ var obj = new List();
int offset = 0;
while (offset + 8 <= data.Length)
@@ -591,9 +591,9 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled BaseRelocationTypeOffsetFieldEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry ParseBaseRelocationTypeOffsetFieldEntry(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry ParseBaseRelocationTypeOffsetFieldEntry(byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry();
ushort typeAndOffsetField = data.ReadUInt16LittleEndian(ref offset);
obj.BaseRelocationType = (BaseRelocationTypes)(typeAndOffsetField >> 12);
@@ -640,9 +640,9 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled DebugDirectoryEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.DebugData.Entry ParseDebugDirectoryEntry(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.DebugData.Entry ParseDebugDirectoryEntry(byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.DebugData.Entry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.DebugData.Entry();
obj.Characteristics = data.ReadUInt32LittleEndian(ref offset);
obj.TimeDateStamp = data.ReadUInt32LittleEndian(ref offset);
@@ -661,14 +661,14 @@ namespace SabreTools.Serialization.Deserializers
///
/// Byte array to parse
/// Filled DebugTable on success, null on error
- public static SabreTools.Models.PortableExecutable.DebugData.Table? ParseDebugTable(byte[]? data)
+ public static SabreTools.Serialization.Models.PortableExecutable.DebugData.Table? ParseDebugTable(byte[]? data)
{
if (data == null)
return null;
- var obj = new SabreTools.Models.PortableExecutable.DebugData.Table();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.DebugData.Table();
- var table = new List();
+ var table = new List();
int offset = 0;
while (offset < data.Length)
@@ -693,12 +693,12 @@ namespace SabreTools.Serialization.Deserializers
///
/// Byte array to parse
/// Filled DelayLoadDirectoryTable on success, null on error
- public static SabreTools.Models.PortableExecutable.DelayLoad.DirectoryTable? ParseDelayLoadDirectoryTable(byte[]? data)
+ public static SabreTools.Serialization.Models.PortableExecutable.DelayLoad.DirectoryTable? ParseDelayLoadDirectoryTable(byte[]? data)
{
if (data == null)
return null;
- var obj = new SabreTools.Models.PortableExecutable.DelayLoad.DirectoryTable();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.DelayLoad.DirectoryTable();
int offset = 0;
obj.Attributes = data.ReadUInt32LittleEndian(ref offset);
@@ -737,9 +737,9 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// Number of entries in the table
/// Filled ExportAddressTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Export.AddressTableEntry[] ParseExportAddressTable(Stream data, uint entries)
+ public static SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry[] ParseExportAddressTable(Stream data, uint entries)
{
- var obj = new SabreTools.Models.PortableExecutable.Export.AddressTableEntry[entries];
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry[entries];
for (int i = 0; i < obj.Length; i++)
{
@@ -754,9 +754,9 @@ namespace SabreTools.Serialization.Deserializers
///
/// Stream to parse
/// Filled ExportAddressTableEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.Export.AddressTableEntry ParseExportAddressTableEntry(Stream data)
+ public static SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry ParseExportAddressTableEntry(Stream data)
{
- var obj = new SabreTools.Models.PortableExecutable.Export.AddressTableEntry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry();
obj.ExportRVA = data.ReadUInt32LittleEndian();
obj.ForwarderRVA = obj.ExportRVA;
@@ -770,9 +770,9 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled ExportDirectoryTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Export.DirectoryTable ParseExportDirectoryTable(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.Export.DirectoryTable ParseExportDirectoryTable(byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.Export.DirectoryTable();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.DirectoryTable();
obj.ExportFlags = data.ReadUInt32LittleEndian(ref offset);
obj.TimeDateStamp = data.ReadUInt32LittleEndian(ref offset);
@@ -797,9 +797,9 @@ namespace SabreTools.Serialization.Deserializers
/// Set of pointers to process
/// Section table to use for virtual address translation
/// Filled ExportNameTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Export.NameTable ParseExportNameTable(Stream data, long initialOffset, uint[] pointers, SectionHeader[] sections)
+ public static SabreTools.Serialization.Models.PortableExecutable.Export.NameTable ParseExportNameTable(Stream data, long initialOffset, uint[] pointers, SectionHeader[] sections)
{
- var obj = new SabreTools.Models.PortableExecutable.Export.NameTable();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.NameTable();
obj.Strings = new string[pointers.Length];
for (int i = 0; i < obj.Strings.Length; i++)
@@ -827,9 +827,9 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// Number of entries in the table
/// Filled ExportNamePointerTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Export.NamePointerTable ParseExportNamePointerTable(Stream data, uint entries)
+ public static SabreTools.Serialization.Models.PortableExecutable.Export.NamePointerTable ParseExportNamePointerTable(Stream data, uint entries)
{
- var obj = new SabreTools.Models.PortableExecutable.Export.NamePointerTable();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.NamePointerTable();
obj.Pointers = new uint[entries];
for (int i = 0; i < obj.Pointers.Length; i++)
@@ -846,9 +846,9 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// Number of entries in the table
/// Filled ExportOrdinalTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Export.OrdinalTable ParseExportOrdinalTable(Stream data, uint entries)
+ public static SabreTools.Serialization.Models.PortableExecutable.Export.OrdinalTable ParseExportOrdinalTable(Stream data, uint entries)
{
- var obj = new SabreTools.Models.PortableExecutable.Export.OrdinalTable();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.OrdinalTable();
obj.Indexes = new ushort[entries];
for (int i = 0; i < obj.Indexes.Length; i++)
@@ -921,13 +921,13 @@ namespace SabreTools.Serialization.Deserializers
/// Import address tables
/// Section table to use for virtual address translation
/// Filled HintNameTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Import.HintNameTableEntry[] ParseHintNameTable(Stream data,
+ public static SabreTools.Serialization.Models.PortableExecutable.Import.HintNameTableEntry[] ParseHintNameTable(Stream data,
long initialOffset,
- Dictionary importLookupTables,
- Dictionary importAddressTables,
+ Dictionary importLookupTables,
+ Dictionary importAddressTables,
SectionHeader[] sections)
{
- var importHintNameTable = new List();
+ var importHintNameTable = new List();
if (importLookupTables.Count > 0 || importAddressTables.Count > 0)
{
@@ -1005,9 +1005,9 @@ namespace SabreTools.Serialization.Deserializers
///
/// Stream to parse
/// Filled HintNameTableEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.Import.HintNameTableEntry ParseHintNameTableEntry(Stream data)
+ public static SabreTools.Serialization.Models.PortableExecutable.Import.HintNameTableEntry ParseHintNameTableEntry(Stream data)
{
- var obj = new SabreTools.Models.PortableExecutable.Import.HintNameTableEntry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Import.HintNameTableEntry();
obj.Hint = data.ReadUInt16LittleEndian();
obj.Name = data.ReadNullTerminatedAnsiString();
@@ -1021,9 +1021,9 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// Optional header magic number indicating PE32 or PE32+
/// Filled ImportAddressTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Import.AddressTableEntry[] ParseImportAddressTable(Stream data, OptionalHeaderMagicNumber magic)
+ public static SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry[] ParseImportAddressTable(Stream data, OptionalHeaderMagicNumber magic)
{
- var obj = new List();
+ var obj = new List();
// Loop until the last item (all nulls) are found
while (data.Position < data.Length)
@@ -1050,13 +1050,13 @@ namespace SabreTools.Serialization.Deserializers
/// Directory table entries containing the addresses
/// Section table to use for virtual address translation
/// Filled ImportAddressTables on success, null on error
- public static Dictionary ParseImportAddressTables(Stream data,
+ public static Dictionary ParseImportAddressTables(Stream data,
long initialOffset,
OptionalHeaderMagicNumber magic,
- SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry[] entries,
+ SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry[] entries,
SectionHeader[] sections)
{
- var obj = new Dictionary();
+ var obj = new Dictionary();
for (int i = 0; i < entries.Length; i++)
{
@@ -1083,9 +1083,9 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// Optional header magic number
/// Filled ImportAddressTableEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.Import.AddressTableEntry ParseImportAddressTableEntry(Stream data, OptionalHeaderMagicNumber magic)
+ public static SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry ParseImportAddressTableEntry(Stream data, OptionalHeaderMagicNumber magic)
{
- var obj = new SabreTools.Models.PortableExecutable.Import.AddressTableEntry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry();
if (magic == OptionalHeaderMagicNumber.PE32)
{
@@ -1115,9 +1115,9 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled ImportDirectoryTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry[] ParseImportDirectoryTable(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry[] ParseImportDirectoryTable(byte[] data, ref int offset)
{
- var obj = new List();
+ var obj = new List();
// Loop until the last item (all nulls) are found
while (offset < data.Length)
@@ -1143,9 +1143,9 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled ImportDirectoryTableEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry ParseImportDirectoryTableEntry(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry ParseImportDirectoryTableEntry(byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry();
obj.ImportLookupTableRVA = data.ReadUInt32LittleEndian(ref offset);
obj.TimeDateStamp = data.ReadUInt32LittleEndian(ref offset);
@@ -1162,9 +1162,9 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// Optional header magic number indicating PE32 or PE32+
/// Filled ImportLookupTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Import.LookupTableEntry[] ParseImportLookupTable(Stream data, OptionalHeaderMagicNumber magic)
+ public static SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry[] ParseImportLookupTable(Stream data, OptionalHeaderMagicNumber magic)
{
- var obj = new List();
+ var obj = new List();
// Loop until the last item (all nulls) are found
while (data.Position < data.Length)
@@ -1191,14 +1191,14 @@ namespace SabreTools.Serialization.Deserializers
/// Directory table entries containing the addresses
/// Section table to use for virtual address translation
/// Filled ImportLookupTables on success, null on error
- public static Dictionary ParseImportLookupTables(Stream data,
+ public static Dictionary ParseImportLookupTables(Stream data,
long initialOffset,
OptionalHeaderMagicNumber magic,
- SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry[] entries,
+ SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry[] entries,
SectionHeader[] sections)
{
// Lookup tables
- var obj = new Dictionary();
+ var obj = new Dictionary();
for (int i = 0; i < entries.Length; i++)
{
@@ -1225,9 +1225,9 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// Optional header magic number
/// Filled ImportLookupTableEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.Import.LookupTableEntry ParseImportLookupTableEntry(Stream data, OptionalHeaderMagicNumber magic)
+ public static SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry ParseImportLookupTableEntry(Stream data, OptionalHeaderMagicNumber magic)
{
- var obj = new SabreTools.Models.PortableExecutable.Import.LookupTableEntry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry();
if (magic == OptionalHeaderMagicNumber.PE32)
{
@@ -1275,11 +1275,11 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// Size of the optional header
/// Filled OptionalHeader on success, null on error
- public static SabreTools.Models.PortableExecutable.OptionalHeader ParseOptionalHeader(Stream data, int optionalSize)
+ public static SabreTools.Serialization.Models.PortableExecutable.OptionalHeader ParseOptionalHeader(Stream data, int optionalSize)
{
long initialOffset = data.Position;
- var obj = new SabreTools.Models.PortableExecutable.OptionalHeader();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.OptionalHeader();
#region Standard Fields
@@ -1431,7 +1431,7 @@ namespace SabreTools.Serialization.Deserializers
ref int dataOffset,
long tableStart,
long tableLength,
- SabreTools.Models.PortableExecutable.Resource.DirectoryTable? table,
+ SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryTable? table,
SectionHeader[] sections)
{
if (tableData == null)
@@ -1484,9 +1484,9 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled ResourceDataEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.Resource.DataEntry ParseResourceDataEntry(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry ParseResourceDataEntry(byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.Resource.DataEntry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry();
obj.DataRVA = data.ReadUInt32LittleEndian(ref offset);
obj.Size = data.ReadUInt32LittleEndian(ref offset);
@@ -1503,9 +1503,9 @@ namespace SabreTools.Serialization.Deserializers
/// Offset into the byte array
/// Indicates if the value is a name entry or not
/// Filled ResourceDirectoryEntry on success, null on error
- public static SabreTools.Models.PortableExecutable.Resource.DirectoryEntry ParseResourceDirectoryEntry(byte[] data, ref int offset, bool nameEntry)
+ public static SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryEntry ParseResourceDirectoryEntry(byte[] data, ref int offset, bool nameEntry)
{
- var obj = new SabreTools.Models.PortableExecutable.Resource.DirectoryEntry();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryEntry();
// TODO: Figure out why the high bit is set for names
// The original version of this code also had this fix, but there
@@ -1532,9 +1532,9 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled ResourceDirectoryString on success, null on error
- public static SabreTools.Models.PortableExecutable.Resource.DirectoryString ParseResourceDirectoryString(byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryString ParseResourceDirectoryString(byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.Resource.DirectoryString();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryString();
obj.Length = data.ReadUInt16LittleEndian(ref offset);
if (obj.Length > 0 && offset + (obj.Length * 2) <= data.Length)
@@ -1549,12 +1549,12 @@ namespace SabreTools.Serialization.Deserializers
/// Byte array to parse
/// Offset into the byte array
/// Filled ResourceDirectoryTable on success, null on error
- public static SabreTools.Models.PortableExecutable.Resource.DirectoryTable? ParseResourceDirectoryTable(byte[]? tableData, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryTable? ParseResourceDirectoryTable(byte[]? tableData, ref int offset)
{
if (tableData == null)
return null;
- var obj = new SabreTools.Models.PortableExecutable.Resource.DirectoryTable();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryTable();
obj.Characteristics = tableData.ReadUInt32LittleEndian(ref offset);
if (obj.Characteristics != 0)
@@ -1568,7 +1568,7 @@ namespace SabreTools.Serialization.Deserializers
// Create the entry array
int totalEntryCount = obj.NumberOfNameEntries + obj.NumberOfIDEntries;
- obj.Entries = new SabreTools.Models.PortableExecutable.Resource.DirectoryEntry[totalEntryCount];
+ obj.Entries = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryEntry[totalEntryCount];
if (obj.Entries.Length == 0)
return obj;
diff --git a/SabreTools.Serialization/Deserializers/SecuROMAddD.cs b/SabreTools.Serialization/Deserializers/SecuROMAddD.cs
index dbcd9553..ac263574 100644
--- a/SabreTools.Serialization/Deserializers/SecuROMAddD.cs
+++ b/SabreTools.Serialization/Deserializers/SecuROMAddD.cs
@@ -1,7 +1,7 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.SecuROM;
+using SabreTools.Serialization.Models.SecuROM;
namespace SabreTools.Serialization.Deserializers
{
diff --git a/SabreTools.Serialization/Deserializers/SecuROMDFA.cs b/SabreTools.Serialization/Deserializers/SecuROMDFA.cs
index 78265255..65690441 100644
--- a/SabreTools.Serialization/Deserializers/SecuROMDFA.cs
+++ b/SabreTools.Serialization/Deserializers/SecuROMDFA.cs
@@ -2,8 +2,8 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.SecuROM;
-using static SabreTools.Models.SecuROM.Constants;
+using SabreTools.Serialization.Models.SecuROM;
+using static SabreTools.Serialization.Models.SecuROM.Constants;
namespace SabreTools.Serialization.Deserializers
{
diff --git a/SabreTools.Serialization/Deserializers/SecuROMMatroschkaPackage.cs b/SabreTools.Serialization/Deserializers/SecuROMMatroschkaPackage.cs
index 671cc45d..3fbdfb4c 100644
--- a/SabreTools.Serialization/Deserializers/SecuROMMatroschkaPackage.cs
+++ b/SabreTools.Serialization/Deserializers/SecuROMMatroschkaPackage.cs
@@ -1,8 +1,8 @@
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.SecuROM;
-using static SabreTools.Models.SecuROM.Constants;
+using SabreTools.Serialization.Models.SecuROM;
+using static SabreTools.Serialization.Models.SecuROM.Constants;
namespace SabreTools.Serialization.Deserializers
{
diff --git a/SabreTools.Serialization/Deserializers/WiseOverlayHeader.cs b/SabreTools.Serialization/Deserializers/WiseOverlayHeader.cs
index 6dc54c7f..4b186f9c 100644
--- a/SabreTools.Serialization/Deserializers/WiseOverlayHeader.cs
+++ b/SabreTools.Serialization/Deserializers/WiseOverlayHeader.cs
@@ -2,7 +2,7 @@ using System;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.WiseInstaller;
+using SabreTools.Serialization.Models.WiseInstaller;
namespace SabreTools.Serialization.Deserializers
{
diff --git a/SabreTools.Serialization/Deserializers/WiseScript.cs b/SabreTools.Serialization/Deserializers/WiseScript.cs
index 863b0b92..14466ec4 100644
--- a/SabreTools.Serialization/Deserializers/WiseScript.cs
+++ b/SabreTools.Serialization/Deserializers/WiseScript.cs
@@ -2,8 +2,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using SabreTools.IO.Extensions;
-using SabreTools.Models.WiseInstaller;
-using SabreTools.Models.WiseInstaller.Actions;
+using SabreTools.Serialization.Models.WiseInstaller;
+using SabreTools.Serialization.Models.WiseInstaller.Actions;
namespace SabreTools.Serialization.Deserializers
{
diff --git a/SabreTools.Serialization/Deserializers/WiseSectionHeader.cs b/SabreTools.Serialization/Deserializers/WiseSectionHeader.cs
index 87a12e8a..541cea5d 100644
--- a/SabreTools.Serialization/Deserializers/WiseSectionHeader.cs
+++ b/SabreTools.Serialization/Deserializers/WiseSectionHeader.cs
@@ -2,8 +2,8 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using SabreTools.IO.Extensions;
-using SabreTools.Models.WiseInstaller;
-using static SabreTools.Models.WiseInstaller.Constants;
+using SabreTools.Serialization.Models.WiseInstaller;
+using static SabreTools.Serialization.Models.WiseInstaller.Constants;
namespace SabreTools.Serialization.Deserializers
{
diff --git a/SabreTools.Serialization/Extensions/NewExecutable.cs b/SabreTools.Serialization/Extensions/NewExecutable.cs
index 319daee7..55b6b6c0 100644
--- a/SabreTools.Serialization/Extensions/NewExecutable.cs
+++ b/SabreTools.Serialization/Extensions/NewExecutable.cs
@@ -1,4 +1,4 @@
-using SabreTools.Models.NewExecutable;
+using SabreTools.Serialization.Models.NewExecutable;
namespace SabreTools.Serialization.Extensions
{
diff --git a/SabreTools.Serialization/Extensions/PortableExecutable.cs b/SabreTools.Serialization/Extensions/PortableExecutable.cs
index 5a86c4e8..dd1521ee 100644
--- a/SabreTools.Serialization/Extensions/PortableExecutable.cs
+++ b/SabreTools.Serialization/Extensions/PortableExecutable.cs
@@ -4,10 +4,10 @@ using System.IO;
using System.Text;
using System.Xml.Serialization;
using SabreTools.IO.Extensions;
-using SabreTools.Models.COFF;
-using SabreTools.Models.PortableExecutable;
-using SabreTools.Models.PortableExecutable.Resource.Entries;
-using SabreTools.Models.SecuROM;
+using SabreTools.Serialization.Models.COFF;
+using SabreTools.Serialization.Models.PortableExecutable;
+using SabreTools.Serialization.Models.PortableExecutable.Resource.Entries;
+using SabreTools.Serialization.Models.SecuROM;
namespace SabreTools.Serialization.Extensions
{
@@ -110,9 +110,9 @@ namespace SabreTools.Serialization.Extensions
/// Data to parse
/// Offset into the byte array
/// A filled NB10ProgramDatabase on success, null on error
- public static SabreTools.Models.PortableExecutable.DebugData.NB10ProgramDatabase? ParseNB10ProgramDatabase(this byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.DebugData.NB10ProgramDatabase? ParseNB10ProgramDatabase(this byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.DebugData.NB10ProgramDatabase();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.DebugData.NB10ProgramDatabase();
obj.Signature = data.ReadUInt32LittleEndian(ref offset);
if (obj.Signature != 0x3031424E)
@@ -132,9 +132,9 @@ namespace SabreTools.Serialization.Extensions
/// Data to parse
/// Offset into the byte array
/// A filled RSDSProgramDatabase on success, null on error
- public static SabreTools.Models.PortableExecutable.DebugData.RSDSProgramDatabase? ParseRSDSProgramDatabase(this byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.DebugData.RSDSProgramDatabase? ParseRSDSProgramDatabase(this byte[] data, ref int offset)
{
- var obj = new SabreTools.Models.PortableExecutable.DebugData.RSDSProgramDatabase();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.DebugData.RSDSProgramDatabase();
obj.Signature = data.ReadUInt32LittleEndian(ref offset);
if (obj.Signature != 0x53445352)
@@ -231,7 +231,7 @@ namespace SabreTools.Serialization.Extensions
///
/// Resource data entry to parse into an accelerator table resource
/// A filled accelerator table resource on success, null on error
- public static AcceleratorTableEntry[]? AsAcceleratorTableResource(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
+ public static AcceleratorTableEntry[]? AsAcceleratorTableResource(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
{
// If we have data that's invalid for this resource type, we can't do anything
if (entry?.Data == null || entry.Data.Length % 8 != 0)
@@ -260,7 +260,7 @@ namespace SabreTools.Serialization.Extensions
///
/// Resource data entry to parse into a side-by-side assembly manifest
/// A filled side-by-side assembly manifest on success, null on error
- public static AssemblyManifest? AsAssemblyManifest(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
+ public static AssemblyManifest? AsAssemblyManifest(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
{
// If we have an invalid entry, just skip
if (entry?.Data == null)
@@ -282,7 +282,7 @@ namespace SabreTools.Serialization.Extensions
///
/// Resource data entry to parse into a dialog box
/// A filled dialog box on success, null on error
- public static DialogBoxResource? AsDialogBox(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
+ public static DialogBoxResource? AsDialogBox(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
{
// If we have an invalid entry, just skip
if (entry?.Data == null)
@@ -759,7 +759,7 @@ namespace SabreTools.Serialization.Extensions
///
/// Resource data entry to parse into a font group
/// A filled font group on success, null on error
- public static FontGroupHeader? AsFontGroup(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
+ public static FontGroupHeader? AsFontGroup(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
{
// If we have an invalid entry, just skip
if (entry?.Data == null)
@@ -828,7 +828,7 @@ namespace SabreTools.Serialization.Extensions
///
/// Resource data entry to parse into a menu
/// A filled menu on success, null on error
- public static MenuResource? AsMenu(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
+ public static MenuResource? AsMenu(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
{
// If we have an invalid entry, just skip
if (entry?.Data == null)
@@ -924,7 +924,7 @@ namespace SabreTools.Serialization.Extensions
///
/// Resource data entry to parse into a message table resource
/// A filled message table resource on success, null on error
- public static MessageResourceData? AsMessageResourceData(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
+ public static MessageResourceData? AsMessageResourceData(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
{
// If we have an invalid entry, just skip
if (entry?.Data == null)
@@ -1012,10 +1012,10 @@ namespace SabreTools.Serialization.Extensions
// Align to the DWORD boundary if we're not at the end
data.AlignToBoundary(ref offset, 4);
- var stringFileInfoChildren = new List();
+ var stringFileInfoChildren = new List();
while ((offset - currentOffset) < stringFileInfo.Length)
{
- var stringTable = new SabreTools.Models.PortableExecutable.Resource.Entries.StringTable();
+ var stringTable = new SabreTools.Serialization.Models.PortableExecutable.Resource.Entries.StringTable();
stringTable.Length = data.ReadUInt16LittleEndian(ref offset);
stringTable.ValueLength = data.ReadUInt16LittleEndian(ref offset);
@@ -1069,7 +1069,7 @@ namespace SabreTools.Serialization.Extensions
///
/// Resource data entry to parse into a string table resource
/// A filled string table resource on success, null on error
- public static Dictionary? AsStringTable(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
+ public static Dictionary? AsStringTable(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
{
// If we have an invalid entry, just skip
if (entry?.Data == null)
@@ -1161,7 +1161,7 @@ namespace SabreTools.Serialization.Extensions
///
/// Resource data entry to parse into a version info resource
/// A filled version info resource on success, null on error
- public static VersionInfo? AsVersionInfo(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
+ public static VersionInfo? AsVersionInfo(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
{
// If we have an invalid entry, just skip
if (entry?.Data == null)
@@ -1358,10 +1358,10 @@ namespace SabreTools.Serialization.Extensions
/// Data to parse
/// Offset into the byte array
/// A filled ResourceHeader on success, null on error
- public static SabreTools.Models.PortableExecutable.Resource.ResourceHeader ParseResourceHeader(this byte[] data, ref int offset)
+ public static SabreTools.Serialization.Models.PortableExecutable.Resource.ResourceHeader ParseResourceHeader(this byte[] data, ref int offset)
{
// Read in the table
- var obj = new SabreTools.Models.PortableExecutable.Resource.ResourceHeader();
+ var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.ResourceHeader();
obj.DataSize = data.ReadUInt32LittleEndian(ref offset);
obj.HeaderSize = data.ReadUInt32LittleEndian(ref offset);
diff --git a/SabreTools.Serialization/Models/AdvancedInstaller/FileEntry.cs b/SabreTools.Serialization/Models/AdvancedInstaller/FileEntry.cs
new file mode 100644
index 00000000..733afeed
--- /dev/null
+++ b/SabreTools.Serialization/Models/AdvancedInstaller/FileEntry.cs
@@ -0,0 +1,61 @@
+namespace SabreTools.Serialization.Models.AdvancedInstaller
+{
+ ///
+ /// Single entry in the file table
+ ///
+ public class FileEntry
+ {
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Observed values:
+ /// - 00 00 00 00 (INI)
+ /// - 01 00 00 00 (MSI, CAB)
+ /// - 05 00 00 00 (DLL)
+ ///
+ public uint Unknown0 { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Observed values:
+ /// - 00 00 00 00 (MSI)
+ /// - 01 00 00 00 (CAB)
+ /// - 03 00 00 00 (INI)
+ /// - 0C 00 00 00 (DLL)
+ ///
+ public uint? Unknown1 { get; set; }
+
+ ///
+ /// Unknown, always 0?
+ ///
+ ///
+ /// Observed values:
+ /// - 00 00 00 00 (DLL, MSI, CAB, INI)
+ ///
+ public uint? Unknown2 { get; set; }
+
+ ///
+ /// Size of the file
+ ///
+ public uint FileSize { get; set; }
+
+ ///
+ /// Offset of the file relative to the start
+ /// of the SFX stub
+ ///
+ public uint FileOffset { get; set; }
+
+ ///
+ /// Size of the file name in characters
+ ///
+ public uint NameSize { get; set; }
+
+ ///
+ /// Unicode-encoded file name
+ ///
+ public string? Name { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/AdvancedInstaller/Footer.cs b/SabreTools.Serialization/Models/AdvancedInstaller/Footer.cs
new file mode 100644
index 00000000..b237ac6a
--- /dev/null
+++ b/SabreTools.Serialization/Models/AdvancedInstaller/Footer.cs
@@ -0,0 +1,109 @@
+namespace SabreTools.Serialization.Models.AdvancedInstaller
+{
+ ///
+ /// Structure similar to the end of central directory
+ /// header in PKZIP files
+ ///
+ public class Footer
+ {
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Observed values:
+ /// - 00 00 00 00
+ ///
+ public uint Unknown0 { get; set; }
+
+ ///
+ /// Size of the original filename?
+ ///
+ /// Doesn't exist in some cases?
+ public uint? OriginalFilenameSize { get; set; }
+
+ ///
+ /// Unicode-encoded original filename?
+ ///
+ /// Doesn't exist in some cases?
+ public string? OriginalFilename { get; set; }
+
+ ///
+ /// Unknown, possibly a string count?
+ ///
+ ///
+ /// Only seen when the preceeding two fields exist
+ ///
+ /// Observed values:
+ /// - 01 00 00 00
+ ///
+ public uint? Unknown1 { get; set; }
+
+ ///
+ /// Pointer to ?
+ ///
+ public uint FooterOffset { get; set; }
+
+ ///
+ /// Number of entries that preceed the footer
+ ///
+ public uint EntryCount { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Observed values:
+ /// - 64 00 00 00
+ ///
+ public uint Unknown2 { get; set; }
+
+ ///
+ /// Unknown offset
+ ///
+ ///
+ /// Points to if no original filename.
+ /// Points to if contains an original filename.
+ ///
+ public uint UnknownOffset { get; set; }
+
+ ///
+ /// Offset of the start of the file table
+ ///
+ public uint TablePointer { get; set; }
+
+ ///
+ /// Offset to the start of the file data
+ ///
+ public uint FileDataStart { get; set; }
+
+ ///
+ /// Hex string that looks like a key or other identifier
+ ///
+ /// 32 bytes
+ public string? HexString { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Offset pointer to
+ /// relative to the end of the signature if no filename
+ /// exists.
+ ///
+ /// Observed values:
+ /// - 32 00 00 00 (No original filename)
+ /// - 13 02 00 00 (Original filename)
+ ///
+ public uint Unknown3 { get; set; }
+
+ ///
+ /// "ADVINSTSFX"
+ ///
+ public string? Signature { get; set; }
+
+ ///
+ /// Unknown, always 0? Padding?
+ ///
+ public ushort? Unknown4 { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/AdvancedInstaller/SFX.cs b/SabreTools.Serialization/Models/AdvancedInstaller/SFX.cs
new file mode 100644
index 00000000..537f9190
--- /dev/null
+++ b/SabreTools.Serialization/Models/AdvancedInstaller/SFX.cs
@@ -0,0 +1,29 @@
+namespace SabreTools.Serialization.Models.AdvancedInstaller
+{
+ ///
+ /// Represents the structure at the end of a Caphyon
+ /// Advanced Installer SFX file. These SFX files store
+ /// all files uncompressed sequentially in the overlay
+ /// of an executable.
+ ///
+ /// The design is similar to the end of central directory
+ /// in a PKZIP file. The footer needs to be read before
+ /// the entry table as both the pointer to the start of
+ /// the table as well as the entry count are included there.
+ ///
+ /// The layout of this is derived from the layout in the
+ /// physical file.
+ ///
+ public class SFX
+ {
+ ///
+ /// Set of file entries
+ ///
+ public FileEntry[]? Entries { get; set; }
+
+ ///
+ /// Footer representing the central directory
+ ///
+ public Footer? Footer { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/COFF/Constants.cs b/SabreTools.Serialization/Models/COFF/Constants.cs
new file mode 100644
index 00000000..202dc33a
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/Constants.cs
@@ -0,0 +1,20 @@
+namespace SabreTools.Serialization.Models.COFF
+{
+ public static class Constants
+ {
+ ///
+ /// Fixed size of
+ ///
+ public const int FileHeaderSize = 20;
+
+ ///
+ /// Fixed size of
+ ///
+ public const int SectionHeaderSize = 40;
+
+ ///
+ /// Fixed size of
+ ///
+ public const int SymbolTableEntrySize = 18;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/COFF/Enums.cs b/SabreTools.Serialization/Models/COFF/Enums.cs
new file mode 100644
index 00000000..cf9acfbd
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/Enums.cs
@@ -0,0 +1,1726 @@
+using System;
+
+namespace SabreTools.Serialization.Models.COFF
+{
+ [Flags]
+ public enum Characteristics : ushort
+ {
+ ///
+ /// Image only, Windows CE, and Microsoft Windows NT and later.
+ /// This indicates that the file does not contain base relocations
+ /// and must therefore be loaded at its preferred base address.
+ /// If the base address is not available, the loader reports an
+ /// error. The default behavior of the linker is to strip base
+ /// relocations from executable (EXE) files.
+ ///
+ IMAGE_FILE_RELOCS_STRIPPED = 0x0001,
+
+ ///
+ /// Image only. This indicates that the image file is valid and
+ /// can be run. If this flag is not set, it indicates a linker error.
+ ///
+ IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002,
+
+ ///
+ /// COFF line numbers have been removed. This flag is deprecated
+ /// and should be zero.
+ ///
+ IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004,
+
+ ///
+ /// COFF symbol table entries for local symbols have been removed.
+ /// This flag is deprecated and should be zero.
+ ///
+ IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008,
+
+ ///
+ /// Obsolete. Aggressively trim working set. This flag is deprecated
+ /// for Windows 2000 and later and must be zero.
+ ///
+ IMAGE_FILE_AGGRESSIVE_WS_TRIM = 0x0010,
+
+ ///
+ /// Application can handle > 2-GB addresses.
+ ///
+ IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020,
+
+ ///
+ /// This flag is reserved for future use.
+ ///
+ RESERVED = 0x0040,
+
+ ///
+ /// Little endian: the least significant bit (LSB) precedes the most
+ /// significant bit (MSB) in memory. This flag is deprecated and
+ /// should be zero.
+ ///
+ IMAGE_FILE_BYTES_REVERSED_LO = 0x0080,
+
+ ///
+ /// Machine is based on a 32-bit-word architecture.
+ ///
+ IMAGE_FILE_32BIT_MACHINE = 0x0100,
+
+ ///
+ /// Debugging information is removed from the image file.
+ ///
+ IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
+
+ ///
+ /// If the image is on removable media, fully load it and
+ /// copy it to the swap file.
+ ///
+ IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400,
+
+ ///
+ /// If the image is on network media, fully load it and copy
+ /// it to the swap file.
+ ///
+ IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800,
+
+ ///
+ /// The image file is a system file, not a user program.
+ ///
+ IMAGE_FILE_SYSTEM = 0x1000,
+
+ ///
+ /// The image file is a dynamic-link library (DLL). Such files
+ /// are considered executable files for almost all purposes,
+ /// although they cannot be directly run.
+ ///
+ IMAGE_FILE_DLL = 0x2000,
+
+ ///
+ /// The file should be run only on a uniprocessor machine.
+ ///
+ IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000,
+
+ ///
+ /// Big endian: the MSB precedes the LSB in memory. This flag
+ /// is deprecated and should be zero.
+ ///
+ IMAGE_FILE_BYTES_REVERSED_HI = 0x8000,
+ }
+
+ public enum MachineType : ushort
+ {
+ ///
+ /// The content of this field is assumed to be applicable to any machine type
+ ///
+ IMAGE_FILE_MACHINE_UNKNOWN = 0x0000,
+
+ ///
+ /// Matsushita AM33
+ ///
+ IMAGE_FILE_MACHINE_AM33 = 0x01D3,
+
+ ///
+ /// x64
+ ///
+ IMAGE_FILE_MACHINE_AMD64 = 0x8664,
+
+ ///
+ /// ARM little endian
+ ///
+ IMAGE_FILE_MACHINE_ARM = 0x01C0,
+
+ ///
+ /// ARM64 little endian
+ ///
+ IMAGE_FILE_MACHINE_ARM64 = 0xAA64,
+
+ ///
+ /// ARM Thumb-2 little endian
+ ///
+ IMAGE_FILE_MACHINE_ARMNT = 0x01C4,
+
+ ///
+ /// EFI byte code
+ ///
+ IMAGE_FILE_MACHINE_EBC = 0x0EBC,
+
+ ///
+ /// Intel 386 or later processors and compatible processors
+ ///
+ IMAGE_FILE_MACHINE_I386 = 0x014C,
+
+ ///
+ /// Intel Itanium processor family
+ ///
+ IMAGE_FILE_MACHINE_IA64 = 0x0200,
+
+ ///
+ /// LoongArch 32-bit processor family
+ ///
+ IMAGE_FILE_MACHINE_LOONGARCH32 = 0x6232,
+
+ ///
+ /// LoongArch 64-bit processor family
+ ///
+ IMAGE_FILE_MACHINE_LOONGARCH64 = 0x6264,
+
+ ///
+ /// Mitsubishi M32R little endian
+ ///
+ IMAGE_FILE_MACHINE_M32R = 0x9041,
+
+ ///
+ /// MIPS16
+ ///
+ IMAGE_FILE_MACHINE_MIPS16 = 0x0266,
+
+ ///
+ /// MIPS with FPU
+ ///
+ IMAGE_FILE_MACHINE_MIPSFPU = 0x0366,
+
+ ///
+ /// MIPS16 with FPU
+ ///
+ IMAGE_FILE_MACHINE_MIPSFPU16 = 0x0466,
+
+ ///
+ /// Power PC little endian
+ ///
+ IMAGE_FILE_MACHINE_POWERPC = 0x01F0,
+
+ ///
+ /// Power PC with floating point support
+ ///
+ IMAGE_FILE_MACHINE_POWERPCFP = 0x01F1,
+
+ ///
+ /// MIPS little endian
+ ///
+ IMAGE_FILE_MACHINE_R4000 = 0x0166,
+
+ ///
+ /// RISC-V 32-bit address space
+ ///
+ IMAGE_FILE_MACHINE_RISCV32 = 0x5032,
+
+ ///
+ /// RISC-V 64-bit address space
+ ///
+ IMAGE_FILE_MACHINE_RISCV64 = 0x5064,
+
+ ///
+ /// RISC-V 128-bit address space
+ ///
+ IMAGE_FILE_MACHINE_RISCV128 = 0x5128,
+
+ ///
+ /// Hitachi SH3
+ ///
+ IMAGE_FILE_MACHINE_SH3 = 0x01A2,
+
+ ///
+ /// Hitachi SH3 DSP
+ ///
+ IMAGE_FILE_MACHINE_SH3DSP = 0x01A3,
+
+ ///
+ /// Hitachi SH4
+ ///
+ IMAGE_FILE_MACHINE_SH4 = 0x01A6,
+
+ ///
+ /// Hitachi SH5
+ ///
+ IMAGE_FILE_MACHINE_SH5 = 0x01A8,
+
+ ///
+ /// Thumb
+ ///
+ IMAGE_FILE_MACHINE_THUMB = 0x01C2,
+
+ ///
+ /// MIPS little-endian WCE v2
+ ///
+ IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x0169,
+ }
+
+ public enum OptionalHeaderMagicNumber : ushort
+ {
+ ROMImage = 0x0107,
+
+ PE32 = 0x010B,
+
+ PE32Plus = 0x020B,
+ }
+
+ public enum RelocationType : ushort
+ {
+ #region x64 Processors
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_AMD64_ABSOLUTE = 0x0000,
+
+ ///
+ /// The 64-bit VA of the relocation target.
+ ///
+ IMAGE_REL_AMD64_ADDR64 = 0x0001,
+
+ ///
+ /// The 32-bit VA of the relocation target.
+ ///
+ IMAGE_REL_AMD64_ADDR32 = 0x0002,
+
+ ///
+ /// The 32-bit address without an image base (RVA).
+ ///
+ IMAGE_REL_AMD64_ADDR32NB = 0x0003,
+
+ ///
+ /// The 32-bit relative address from the byte following the relocation.
+ ///
+ IMAGE_REL_AMD64_REL32 = 0x0004,
+
+ ///
+ /// The 32-bit address relative to byte distance 1 from the relocation.
+ ///
+ IMAGE_REL_AMD64_REL32_1 = 0x0005,
+
+ ///
+ /// The 32-bit address relative to byte distance 2 from the relocation.
+ ///
+ IMAGE_REL_AMD64_REL32_2 = 0x0006,
+
+ ///
+ /// The 32-bit address relative to byte distance 3 from the relocation.
+ ///
+ IMAGE_REL_AMD64_REL32_3 = 0x0007,
+
+ ///
+ /// The 32-bit address relative to byte distance 4 from the relocation.
+ ///
+ IMAGE_REL_AMD64_REL32_4 = 0x0008,
+
+ ///
+ /// The 32-bit address relative to byte distance 5 from the relocation.
+ ///
+ IMAGE_REL_AMD64_REL32_5 = 0x0009,
+
+ ///
+ /// The 16-bit section index of the section that contains the target.
+ /// This is used to support debugging information.
+ ///
+ IMAGE_REL_AMD64_SECTION = 0x000A,
+
+ ///
+ /// The 32-bit offset of the target from the beginning of its section.
+ /// This is used to support debugging information and static thread
+ /// local storage.
+ ///
+ IMAGE_REL_AMD64_SECREL = 0x000B,
+
+ ///
+ /// A 7-bit unsigned offset from the base of the section that contains
+ /// the target.
+ ///
+ IMAGE_REL_AMD64_SECREL7 = 0x000C,
+
+ ///
+ /// CLR tokens.
+ ///
+ IMAGE_REL_AMD64_TOKEN = 0x000D,
+
+ ///
+ /// A 32-bit signed span-dependent value emitted into the object.
+ ///
+ IMAGE_REL_AMD64_SREL32 = 0x000E,
+
+ ///
+ /// A pair that must immediately follow every span-dependent value.
+ ///
+ IMAGE_REL_AMD64_PAIR = 0x000F,
+
+ ///
+ /// A 32-bit signed span-dependent value that is applied at link time.
+ ///
+ IMAGE_REL_AMD64_SSPAN32 = 0x0010,
+
+ #endregion
+
+ #region ARM Processors
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_ARM_ABSOLUTE = 0x0000,
+
+ ///
+ /// The 32-bit VA of the target.
+ ///
+ IMAGE_REL_ARM_ADDR32 = 0x0001,
+
+ ///
+ /// The 32-bit RVA of the target.
+ ///
+ IMAGE_REL_ARM_ADDR32NB = 0x0002,
+
+ ///
+ /// The 24-bit relative displacement to the target.
+ ///
+ IMAGE_REL_ARM_BRANCH24 = 0x0003,
+
+ ///
+ /// The reference to a subroutine call. The reference
+ /// consists of two 16-bit instructions with 11-bit offsets.
+ ///
+ IMAGE_REL_ARM_BRANCH11 = 0x0004,
+
+ ///
+ /// The 32-bit relative address from the byte following the relocation.
+ ///
+ IMAGE_REL_ARM_REL32 = 0x000A,
+
+ ///
+ /// The 16-bit section index of the section that contains the target.
+ /// This is used to support debugging information.
+ ///
+ IMAGE_REL_ARM_SECTION = 0x000E,
+
+ ///
+ /// The 32-bit offset of the target from the beginning of its section.
+ /// This is used to support debugging information and static thread
+ /// local storage.
+ ///
+ IMAGE_REL_ARM_SECREL = 0x000F,
+
+ ///
+ /// The 32-bit VA of the target.This relocation is applied using a MOVW
+ /// instruction for the low 16 bits followed by a MOVT for the high 16 bits.
+ ///
+ IMAGE_REL_ARM_MOV32 = 0x0010,
+
+ ///
+ /// The 32-bit VA of the target.This relocation is applied using a MOVW
+ /// instruction for the low 16 bits followed by a MOVT for the high 16 bits.
+ ///
+ IMAGE_REL_THUMB_MOV32 = 0x0011,
+
+ ///
+ /// The instruction is fixed up with the 21 - bit relative displacement to
+ /// the 2-byte aligned target. The least significant bit of the displacement
+ /// is always zero and is not stored. This relocation corresponds to a
+ /// Thumb-2 32-bit conditional B instruction.
+ ///
+ IMAGE_REL_THUMB_BRANCH20 = 0x0012,
+
+ Unused = 0x0013,
+
+ ///
+ /// The instruction is fixed up with the 25-bit relative displacement to
+ /// the 2-byte aligned target. The least significant bit of the displacement
+ /// is zero and is not stored. This relocation corresponds to a Thumb-2 B
+ /// instruction.
+ ///
+ IMAGE_REL_THUMB_BRANCH24 = 0x0014,
+
+ ///
+ /// The instruction is fixed up with the 25-bit relative displacement to
+ /// the 4-byte aligned target. The low 2 bits of the displacement are zero
+ /// and are not stored. This relocation corresponds to a Thumb-2 BLX instruction.
+ ///
+ IMAGE_REL_THUMB_BLX23 = 0x0015,
+
+ ///
+ /// The relocation is valid only when it immediately follows a ARM_REFHI or
+ /// THUMB_REFHI. Its SymbolTableIndex contains a displacement and not an index
+ /// into the symbol table.
+ ///
+ IMAGE_REL_ARM_PAIR = 0x0016,
+
+ #endregion
+
+ #region ARM64 Processors
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_ARM64_ABSOLUTE = 0x0000,
+
+ ///
+ /// The 32-bit VA of the target.
+ ///
+ IMAGE_REL_ARM64_ADDR32 = 0x0001,
+
+ ///
+ /// The 32-bit RVA of the target.
+ ///
+ IMAGE_REL_ARM64_ADDR32NB = 0x0002,
+
+ ///
+ /// The 26-bit relative displacement to the target, for B and BL instructions.
+ ///
+ IMAGE_REL_ARM64_BRANCH26 = 0x0003,
+
+ ///
+ /// The page base of the target, for ADRP instruction.
+ ///
+ IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004,
+
+ ///
+ /// The 12-bit relative displacement to the target, for instruction ADR
+ ///
+ IMAGE_REL_ARM64_REL21 = 0x0005,
+
+ ///
+ /// The 12-bit page offset of the target, for instructions ADD/ADDS (immediate)
+ /// with zero shift.
+ ///
+ IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006,
+
+ ///
+ /// The 12-bit page offset of the target, for instruction LDR (indexed,
+ /// unsigned immediate).
+ ///
+ IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007,
+
+ ///
+ /// The 32-bit offset of the target from the beginning of its section.
+ /// This is used to support debugging information and static thread local storage.
+ ///
+ IMAGE_REL_ARM64_SECREL = 0x0008,
+
+ ///
+ /// Bit 0:11 of section offset of the target, for instructions ADD/ADDS(immediate)
+ /// with zero shift.
+ ///
+ IMAGE_REL_ARM64_SECREL_LOW12A = 0x0009,
+
+ ///
+ /// Bit 12:23 of section offset of the target, for instructions ADD/ADDS(immediate)
+ /// with zero shift.
+ ///
+ IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A,
+
+ ///
+ /// Bit 0:11 of section offset of the target, for instruction LDR(indexed,
+ /// unsigned immediate).
+ ///
+ IMAGE_REL_ARM64_SECREL_LOW12L = 0x000B,
+
+ ///
+ /// CLR token.
+ ///
+ IMAGE_REL_ARM64_TOKEN = 0x000C,
+
+ ///
+ /// The 16-bit section index of the section that contains the target.
+ /// This is used to support debugging information.
+ ///
+ IMAGE_REL_ARM64_SECTION = 0x000D,
+
+ ///
+ /// The 64-bit VA of the relocation target.
+ ///
+ IMAGE_REL_ARM64_ADDR64 = 0x000E,
+
+ ///
+ /// The 19-bit offset to the relocation target, for conditional B instruction.
+ ///
+ IMAGE_REL_ARM64_BRANCH19 = 0x000F,
+
+ ///
+ /// The 14-bit offset to the relocation target, for instructions TBZ and TBNZ.
+ ///
+ IMAGE_REL_ARM64_BRANCH14 = 0x0010,
+
+ ///
+ /// The 32-bit relative address from the byte following the relocation.
+ ///
+ IMAGE_REL_ARM64_REL32 = 0x0011,
+
+ #endregion
+
+ #region Hitachi SuperH Processors
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_SH3_ABSOLUTE = 0x0000,
+
+ ///
+ /// A reference to the 16-bit location that contains the VA of
+ /// the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT16 = 0x0001,
+
+ ///
+ /// The 32-bit VA of the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT32 = 0x0002,
+
+ ///
+ /// A reference to the 8-bit location that contains the VA of
+ /// the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT8 = 0x0003,
+
+ ///
+ /// A reference to the 8-bit instruction that contains the
+ /// effective 16-bit VA of the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT8_WORD = 0x0004,
+
+ ///
+ /// A reference to the 8-bit instruction that contains the
+ /// effective 32-bit VA of the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT8_LONG = 0x0005,
+
+ ///
+ /// A reference to the 8-bit location whose low 4 bits contain
+ /// the VA of the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT4 = 0x0006,
+
+ ///
+ /// A reference to the 8-bit instruction whose low 4 bits contain
+ /// the effective 16-bit VA of the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT4_WORD = 0x0007,
+
+ ///
+ /// A reference to the 8-bit instruction whose low 4 bits contain
+ /// the effective 32-bit VA of the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT4_LONG = 0x0008,
+
+ ///
+ /// A reference to the 8-bit instruction that contains the
+ /// effective 16-bit relative offset of the target symbol.
+ ///
+ IMAGE_REL_SH3_PCREL8_WORD = 0x0009,
+
+ ///
+ /// A reference to the 8-bit instruction that contains the
+ /// effective 32-bit relative offset of the target symbol.
+ ///
+ IMAGE_REL_SH3_PCREL8_LONG = 0x000A,
+
+ ///
+ /// A reference to the 16-bit instruction whose low 12 bits contain
+ /// the effective 16-bit relative offset of the target symbol.
+ ///
+ IMAGE_REL_SH3_PCREL12_WORD = 0x000B,
+
+ ///
+ /// A reference to a 32-bit location that is the VA of the
+ /// section that contains the target symbol.
+ ///
+ IMAGE_REL_SH3_STARTOF_SECTION = 0x000C,
+
+ ///
+ /// A reference to the 32-bit location that is the size of the
+ /// section that contains the target symbol.
+ ///
+ IMAGE_REL_SH3_SIZEOF_SECTION = 0x000D,
+
+ ///
+ /// The 16-bit section index of the section that contains the target.
+ /// This is used to support debugging information.
+ ///
+ IMAGE_REL_SH3_SECTION = 0x000E,
+
+ ///
+ /// The 32-bit offset of the target from the beginning of its section.
+ /// This is used to support debugging information and static thread
+ /// local storage.
+ ///
+ IMAGE_REL_SH3_SECREL = 0x000F,
+
+ ///
+ /// The 32-bit RVA of the target symbol.
+ ///
+ IMAGE_REL_SH3_DIRECT32_NB = 0x0010,
+
+ ///
+ /// GP relative.
+ ///
+ IMAGE_REL_SH3_GPREL4_LONG = 0x0011,
+
+ ///
+ /// CLR token.
+ ///
+ IMAGE_REL_SH3_TOKEN = 0x0012,
+
+ ///
+ /// The offset from the current instruction in longwords. If the NOMODE
+ /// bit is not set, insert the inverse of the low bit at bit 32 to
+ /// select PTA or PTB.
+ ///
+ IMAGE_REL_SHM_PCRELPT = 0x0013,
+
+ ///
+ /// The low 16 bits of the 32-bit address.
+ ///
+ IMAGE_REL_SHM_REFLO = 0x0014,
+
+ ///
+ /// The high 16 bits of the 32-bit address.
+ ///
+ IMAGE_REL_SHM_REFHALF = 0x0015,
+
+ ///
+ /// The low 16 bits of the relative address.
+ ///
+ IMAGE_REL_SHM_RELLO = 0x0016,
+
+ ///
+ /// The high 16 bits of the relative address.
+ ///
+ IMAGE_REL_SHM_RELHALF = 0x0017,
+
+ ///
+ /// The relocation is valid only when it immediately follows a REFHALF,
+ /// RELHALF, or RELLO relocation. The SymbolTableIndex field of the
+ /// relocation contains a displacement and not an index into the symbol table.
+ ///
+ IMAGE_REL_SHM_PAIR = 0x0018,
+
+ ///
+ /// The relocation ignores section mode.
+ ///
+ IMAGE_REL_SHM_NOMODE = 0x8000,
+
+ #endregion
+
+ #region IBM PowerPC Processors
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_PPC_ABSOLUTE = 0x0000,
+
+ ///
+ /// The 64-bit VA of the target.
+ ///
+ IMAGE_REL_PPC_ADDR64 = 0x0001,
+
+ ///
+ /// The 32-bit VA of the target.
+ ///
+ IMAGE_REL_PPC_ADDR32 = 0x0002,
+
+ ///
+ /// The low 24 bits of the VA of the target. This is valid only when
+ /// the target symbol is absolute and can be sign-extended to its
+ /// original value.
+ ///
+ IMAGE_REL_PPC_ADDR24 = 0x0003,
+
+ ///
+ /// The low 16 bits of the target's VA.
+ ///
+ IMAGE_REL_PPC_ADDR16 = 0x0004,
+
+ ///
+ /// The low 14 bits of the target's VA. This is valid only when the
+ /// target symbol is absolute and can be sign-extended to its original
+ /// value.
+ ///
+ IMAGE_REL_PPC_ADDR14 = 0x0005,
+
+ ///
+ /// A 24-bit PC-relative offset to the symbol's location.
+ ///
+ IMAGE_REL_PPC_REL24 = 0x0006,
+
+ ///
+ /// A 14-bit PC-relative offset to the symbol's location.
+ ///
+ IMAGE_REL_PPC_REL14 = 0x0007,
+
+ ///
+ /// The 32-bit RVA of the target.
+ ///
+ IMAGE_REL_PPC_ADDR32NB = 0x000A,
+
+ ///
+ /// The 32-bit offset of the target from the beginning of its section.
+ /// This is used to support debugging information and static thread
+ /// local storage.
+ ///
+ IMAGE_REL_PPC_SECREL = 0x000B,
+
+ ///
+ /// The 16-bit section index of the section that contains the target.
+ /// This is used to support debugging information.
+ ///
+ IMAGE_REL_PPC_SECTION = 0x000C,
+
+ ///
+ /// The 16-bit offset of the target from the beginning of its section.
+ /// This is used to support debugging information and static thread
+ /// local storage.
+ ///
+ IMAGE_REL_PPC_SECREL16 = 0x000F,
+
+ ///
+ /// The high 16 bits of the target's 32-bit VA. This is used for the
+ /// first instruction in a two-instruction sequence that loads a full
+ /// address. This relocation must be immediately followed by a PAIR
+ /// relocation whose SymbolTableIndex contains a signed 16-bit
+ /// displacement that is added to the upper 16 bits that was taken
+ /// from the location that is being relocated.
+ ///
+ IMAGE_REL_PPC_REFHI = 0x0010,
+
+ ///
+ /// The low 16 bits of the target's VA.
+ ///
+ IMAGE_REL_PPC_REFLO = 0x0011,
+
+ ///
+ /// A relocation that is valid only when it immediately follows a REFHI
+ /// or SECRELHI relocation. Its SymbolTableIndex contains a displacement
+ /// and not an index into the symbol table.
+ ///
+ IMAGE_REL_PPC_PAIR = 0x0012,
+
+ ///
+ /// The low 16 bits of the 32-bit offset of the target from the beginning
+ /// of its section.
+ ///
+ IMAGE_REL_PPC_SECRELLO = 0x0013,
+
+ ///
+ /// The 16-bit signed displacement of the target relative to the GP register.
+ ///
+ IMAGE_REL_PPC_GPREL = 0x0015,
+
+ ///
+ /// The CLR token.
+ ///
+ IMAGE_REL_PPC_TOKEN = 0x0016,
+
+ #endregion
+
+ #region Intel 386 Processors
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_I386_ABSOLUTE = 0x0000,
+
+ ///
+ /// Not supported.
+ ///
+ IMAGE_REL_I386_DIR16 = 0x0001,
+
+ ///
+ /// Not supported.
+ ///
+ IMAGE_REL_I386_REL16 = 0x0002,
+
+ ///
+ /// The target's 32-bit VA.
+ ///
+ IMAGE_REL_I386_DIR32 = 0x0006,
+
+ ///
+ /// The target's 32-bit RVA.
+ ///
+ IMAGE_REL_I386_DIR32NB = 0x0007,
+
+ ///
+ /// Not supported.
+ ///
+ IMAGE_REL_I386_SEG12 = 0x0009,
+
+ ///
+ /// The 16-bit section index of the section that contains the target.
+ /// This is used to support debugging information.
+ ///
+ IMAGE_REL_I386_SECTION = 0x000A,
+
+ ///
+ /// The 32-bit offset of the target from the beginning of its section.
+ /// This is used to support debugging information and static thread
+ /// local storage.
+ ///
+ IMAGE_REL_I386_SECREL = 0x000B,
+
+ ///
+ /// The CLR token.
+ ///
+ IMAGE_REL_I386_TOKEN = 0x000C,
+
+ ///
+ /// A 7-bit offset from the base of the section that contains the target.
+ ///
+ IMAGE_REL_I386_SECREL7 = 0x000D,
+
+ ///
+ /// The 32-bit relative displacement to the target.This supports the x86 relative branch and call instructions.
+ ///
+ IMAGE_REL_I386_REL32 = 0x0014,
+
+ #endregion
+
+ #region Intel Itanium Processor Family (IPF)
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_IA64_ABSOLUTE = 0x0000,
+
+ ///
+ /// The instruction relocation can be followed by an ADDEND relocation whose value is
+ /// added to the target address before it is inserted into the specified slot in the
+ /// IMM14 bundle. The relocation target must be absolute or the image must be fixed.
+ ///
+ IMAGE_REL_IA64_IMM14 = 0x0001,
+
+ ///
+ /// The instruction relocation can be followed by an ADDEND relocation whose value is
+ /// added to the target address before it is inserted into the specified slot in the
+ /// IMM22 bundle. The relocation target must be absolute or the image must be fixed.
+ ///
+ IMAGE_REL_IA64_IMM22 = 0x0002,
+
+ ///
+ /// The slot number of this relocation must be one (1). The relocation can be followed
+ /// by an ADDEND relocation whose value is added to the target address before it is
+ /// stored in all three slots of the IMM64 bundle.
+ ///
+ IMAGE_REL_IA64_IMM64 = 0x0003,
+
+ ///
+ /// The target's 32-bit VA. This is supported only for /LARGEADDRESSAWARE:NO images.
+ ///
+ IMAGE_REL_IA64_DIR32 = 0x0004,
+
+ ///
+ /// The target's 64-bit VA.
+ ///
+ IMAGE_REL_IA64_DIR64 = 0x0005,
+
+ ///
+ /// The instruction is fixed up with the 25-bit relative displacement to the 16-bit
+ /// aligned target. The low 4 bits of the displacement are zero and are not stored.
+ ///
+ IMAGE_REL_IA64_PCREL21B = 0x0006,
+
+ ///
+ /// The instruction is fixed up with the 25-bit relative displacement to the 16-bit
+ /// aligned target. The low 4 bits of the displacement, which are zero, are not stored.
+ ///
+ IMAGE_REL_IA64_PCREL21M = 0x0007,
+
+ ///
+ /// The LSBs of this relocation's offset must contain the slot number whereas the rest
+ /// is the bundle address. The bundle is fixed up with the 25-bit relative displacement
+ /// to the 16-bit aligned target. The low 4 bits of the displacement are zero and are
+ /// not stored.
+ ///
+ IMAGE_REL_IA64_PCREL21F = 0x0008,
+
+ ///
+ /// The instruction relocation can be followed by an ADDEND relocation whose value is
+ /// added to the target address and then a 22-bit GP-relative offset that is calculated
+ /// and applied to the GPREL22 bundle.
+ ///
+ IMAGE_REL_IA64_GPREL22 = 0x0009,
+
+ ///
+ /// The instruction is fixed up with the 22-bit GP-relative offset to the target symbol's
+ /// literal table entry. The linker creates this literal table entry based on this
+ /// relocation and the ADDEND relocation that might follow.
+ ///
+ IMAGE_REL_IA64_LTOFF22 = 0x000A,
+
+ ///
+ /// The 16-bit section index of the section contains the target. This is used to support
+ /// debugging information.
+ ///
+ IMAGE_REL_IA64_SECTION = 0x000B,
+
+ ///
+ /// The instruction is fixed up with the 22-bit offset of the target from the beginning of
+ /// its section.This relocation can be followed immediately by an ADDEND relocation,
+ /// whose Value field contains the 32-bit unsigned offset of the target from the beginning
+ /// of the section.
+ ///
+ IMAGE_REL_IA64_SECREL22 = 0x000C,
+
+ ///
+ /// The slot number for this relocation must be one (1). The instruction is fixed up with
+ /// the 64-bit offset of the target from the beginning of its section. This relocation can
+ /// be followed immediately by an ADDEND relocation whose Value field contains the 32-bit
+ /// unsigned offset of the target from the beginning of the section.
+ ///
+ IMAGE_REL_IA64_SECREL64I = 0x000D,
+
+ ///
+ /// The address of data to be fixed up with the 32-bit offset of the target from the beginning
+ /// of its section.
+ ///
+ IMAGE_REL_IA64_SECREL32 = 0x000E,
+
+ ///
+ /// The target's 32-bit RVA.
+ ///
+ IMAGE_REL_IA64_DIR32NB = 0x0010,
+
+ ///
+ /// This is applied to a signed 14-bit immediate that contains the difference between two
+ /// relocatable targets. This is a declarative field for the linker that indicates that the
+ /// compiler has already emitted this value.
+ ///
+ IMAGE_REL_IA64_SREL14 = 0x0011,
+
+ ///
+ /// This is applied to a signed 22-bit immediate that contains the difference between two
+ /// relocatable targets. This is a declarative field for the linker that indicates that the
+ /// compiler has already emitted this value.
+ ///
+ IMAGE_REL_IA64_SREL22 = 0x0012,
+
+ ///
+ /// This is applied to a signed 32-bit immediate that contains the difference between two
+ /// relocatable values.This is a declarative field for the linker that indicates that the
+ /// compiler has already emitted this value.
+ ///
+ IMAGE_REL_IA64_SREL32 = 0x0013,
+
+ ///
+ /// This is applied to an unsigned 32-bit immediate that contains the difference between
+ /// two relocatable values. This is a declarative field for the linker that indicates that
+ /// the compiler has already emitted this value.
+ ///
+ IMAGE_REL_IA64_UREL32 = 0x0014,
+
+ ///
+ /// A 60-bit PC-relative fixup that always stays as a BRL instruction of an MLX bundle.
+ ///
+ IMAGE_REL_IA64_PCREL60X = 0x0015,
+
+ ///
+ /// A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field,
+ /// convert the entire bundle to an MBB bundle with NOP. B in slot 1 and a 25-bit BR
+ /// instruction (with the 4 lowest bits all zero and dropped) in slot 2.
+ ///
+ IMAGE_REL_IA64_PCREL60B = 0x0016,
+
+ ///
+ /// A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field,
+ /// convert the entire bundle to an MFB bundle with NOP. F in slot 1 and a 25-bit
+ /// (4 lowest bits all zero and dropped) BR instruction in slot 2.
+ ///
+ IMAGE_REL_IA64_PCREL60F = 0x0017,
+
+ ///
+ /// A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field,
+ /// convert the entire bundle to an MIB bundle with NOP. I in slot 1 and a 25-bit
+ /// (4 lowest bits all zero and dropped) BR instruction in slot 2.
+ ///
+ IMAGE_REL_IA64_PCREL60I = 0x0018,
+
+ ///
+ /// A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field,
+ /// convert the entire bundle to an MMB bundle with NOP. M in slot 1 and a 25-bit
+ /// (4 lowest bits all zero and dropped) BR instruction in slot 2.
+ ///
+ IMAGE_REL_IA64_PCREL60M = 0x0019,
+
+ ///
+ /// A 64-bit GP-relative fixup.
+ ///
+ IMAGE_REL_IA64_IMMGPREL64 = 0x001a,
+
+ ///
+ /// A CLR token.
+ ///
+ IMAGE_REL_IA64_TOKEN = 0x001b,
+
+ ///
+ /// A 32-bit GP-relative fixup.
+ ///
+ IMAGE_REL_IA64_GPREL32 = 0x001c,
+
+ ///
+ /// The relocation is valid only when it immediately follows one of the following relocations:
+ /// IMM14, IMM22, IMM64, GPREL22, LTOFF22, LTOFF64, SECREL22, SECREL64I, or SECREL32.
+ /// Its value contains the addend to apply to instructions within a bundle, not for data.
+ ///
+ IMAGE_REL_IA64_ADDEND = 0x001F,
+
+ #endregion
+
+ #region MIPS Processors
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_MIPS_ABSOLUTE = 0x0000,
+
+ ///
+ /// The high 16 bits of the target's 32-bit VA.
+ ///
+ IMAGE_REL_MIPS_REFHALF = 0x0001,
+
+ ///
+ /// The target's 32-bit VA.
+ ///
+ IMAGE_REL_MIPS_REFWORD = 0x0002,
+
+ ///
+ /// The low 26 bits of the target's VA. This supports the MIPS J and JAL instructions.
+ ///
+ IMAGE_REL_MIPS_JMPADDR = 0x0003,
+
+ ///
+ /// The high 16 bits of the target's 32-bit VA. This is used for the first instruction in a
+ /// two-instruction sequence that loads a full address. This relocation must be immediately
+ /// followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement
+ /// that is added to the upper 16 bits that are taken from the location that is being relocated.
+ ///
+ IMAGE_REL_MIPS_REFHI = 0x0004,
+
+ ///
+ /// The low 16 bits of the target's VA.
+ ///
+ IMAGE_REL_MIPS_REFLO = 0x0005,
+
+ ///
+ /// A 16-bit signed displacement of the target relative to the GP register.
+ ///
+ IMAGE_REL_MIPS_GPREL = 0x0006,
+
+ ///
+ /// The same as IMAGE_REL_MIPS_GPREL.
+ ///
+ IMAGE_REL_MIPS_LITERAL = 0x0007,
+
+ ///
+ /// The 16-bit section index of the section contains the target.
+ /// This is used to support debugging information.
+ ///
+ IMAGE_REL_MIPS_SECTION = 0x000A,
+
+ ///
+ /// The 32-bit offset of the target from the beginning of its section.
+ /// This is used to support debugging information and static thread local storage.
+ ///
+ IMAGE_REL_MIPS_SECREL = 0x000B,
+
+ ///
+ /// The low 16 bits of the 32-bit offset of the target from the beginning of its section.
+ ///
+ IMAGE_REL_MIPS_SECRELLO = 0x000C,
+
+ ///
+ /// The high 16 bits of the 32-bit offset of the target from the beginning of its section.
+ /// An IMAGE_REL_MIPS_PAIR relocation must immediately follow this one. The SymbolTableIndex
+ /// of the PAIR relocation contains a signed 16-bit displacement that is added to the upper
+ /// 16 bits that are taken from the location that is being relocated.
+ ///
+ IMAGE_REL_MIPS_SECRELHI = 0x000D,
+
+ ///
+ /// The low 26 bits of the target's VA. This supports the MIPS16 JAL instruction.
+ ///
+ IMAGE_REL_MIPS_JMPADDR16 = 0x0010,
+
+ ///
+ /// The target's 32-bit RVA.
+ ///
+ IMAGE_REL_MIPS_REFWORDNB = 0x0022,
+
+ ///
+ /// The relocation is valid only when it immediately follows a REFHI or SECRELHI relocation.
+ /// Its SymbolTableIndex contains a displacement and not an index into the symbol table.
+ ///
+ IMAGE_REL_MIPS_PAIR = 0x0025,
+
+ #endregion
+
+ #region Mitsubishi M32R
+
+ ///
+ /// The relocation is ignored.
+ ///
+ IMAGE_REL_M32R_ABSOLUTE = 0x0000,
+
+ ///
+ /// The target's 32-bit VA.
+ ///
+ IMAGE_REL_M32R_ADDR32 = 0x0001,
+
+ ///
+ /// The target's 32-bit RVA.
+ ///
+ IMAGE_REL_M32R_ADDR32NB = 0x0002,
+
+ ///
+ /// The target's 24-bit VA.
+ ///
+ IMAGE_REL_M32R_ADDR24 = 0x0003,
+
+ ///
+ /// The target's 16-bit offset from the GP register.
+ ///
+ IMAGE_REL_M32R_GPREL16 = 0x0004,
+
+ ///
+ /// The target's 24-bit offset from the program counter (PC), shifted left by
+ /// 2 bits and sign-extended
+ ///
+ IMAGE_REL_M32R_PCREL24 = 0x0005,
+
+ ///
+ /// The target's 16-bit offset from the PC, shifted left by 2 bits and
+ /// sign-extended
+ ///
+ IMAGE_REL_M32R_PCREL16 = 0x0006,
+
+ ///
+ /// The target's 8-bit offset from the PC, shifted left by 2 bits and
+ /// sign-extended
+ ///
+ IMAGE_REL_M32R_PCREL8 = 0x0007,
+
+ ///
+ /// The 16 MSBs of the target VA.
+ ///
+ IMAGE_REL_M32R_REFHALF = 0x0008,
+
+ ///
+ /// The 16 MSBs of the target VA, adjusted for LSB sign extension. This is used for
+ /// the first instruction in a two-instruction sequence that loads a full 32-bit address.
+ /// This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex
+ /// contains a signed 16-bit displacement that is added to the upper 16 bits that are
+ /// taken from the location that is being relocated.
+ ///
+ IMAGE_REL_M32R_REFHI = 0x0009,
+
+ ///
+ /// The 16 LSBs of the target VA.
+ ///
+ IMAGE_REL_M32R_REFLO = 0x000A,
+
+ ///
+ /// The relocation must follow the REFHI relocation.Its SymbolTableIndex contains a displacement
+ /// and not an index into the symbol table.
+ ///
+ IMAGE_REL_M32R_PAIR = 0x000B,
+
+ ///
+ /// The 16-bit section index of the section that contains the target. This is used to support
+ /// debugging information.
+ ///
+ IMAGE_REL_M32R_SECTION = 0x000C,
+
+ ///
+ /// The 32-bit offset of the target from the beginning of its section.This is used to support
+ /// debugging information and static thread local storage.
+ ///
+ IMAGE_REL_M32R_SECREL = 0x000D,
+
+ ///
+ /// The CLR token.
+ ///
+ IMAGE_REL_M32R_TOKEN = 0x000E,
+
+ #endregion
+ }
+
+ [Flags]
+ public enum SectionFlags : uint
+ {
+ ///
+ /// Reserved for future use.
+ ///
+ RESERVED0 = 0x00000001,
+
+ ///
+ /// Reserved for future use.
+ ///
+ RESERVED1 = 0x00000002,
+
+ ///
+ /// Reserved for future use.
+ ///
+ RESERVED2 = 0x00000004,
+
+ ///
+ /// The section should not be padded to the next boundary.
+ /// This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES.
+ /// This is valid only for object files.
+ ///
+ IMAGE_SCN_TYPE_NO_PAD = 0x00000008,
+
+ ///
+ /// Reserved for future use.
+ ///
+ RESERVED4 = 0x00000010,
+
+ ///
+ /// The section contains executable code.
+ ///
+ IMAGE_SCN_CNT_CODE = 0x00000020,
+
+ ///
+ /// The section contains initialized data.
+ ///
+ IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
+
+ ///
+ /// The section contains uninitialized data.
+ ///
+ IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
+
+ ///
+ /// Reserved for future use.
+ ///
+ IMAGE_SCN_LNK_OTHER = 0x00000100,
+
+ ///
+ /// The section contains comments or other information. The .drectve
+ /// section has this type. This is valid for object files only.
+ ///
+ IMAGE_SCN_LNK_INFO = 0x00000200,
+
+ ///
+ /// Reserved for future use.
+ ///
+ RESERVED10 = 0x00000400,
+
+ ///
+ /// The section will not become part of the image. This is valid
+ /// only for object files.
+ ///
+ IMAGE_SCN_LNK_REMOVE = 0x00000800,
+
+ ///
+ /// The section contains COMDAT data. For more information, see COMDAT Sections
+ /// (Object Only). This is valid only for object files.
+ ///
+ IMAGE_SCN_LNK_COMDAT = 0x00001000,
+
+ ///
+ /// The section contains data referenced through the global pointer (GP).
+ ///
+ IMAGE_SCN_GPREL = 0x00008000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ IMAGE_SCN_MEM_PURGEABLE = 0x00010000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ IMAGE_SCN_MEM_16BIT = 0x00020000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ IMAGE_SCN_MEM_LOCKED = 0x00040000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ IMAGE_SCN_MEM_PRELOAD = 0x00080000,
+
+ ///
+ /// Align data on a 1-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_1BYTES = 0x00100000,
+
+ ///
+ /// Align data on a 2-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_2BYTES = 0x00200000,
+
+ ///
+ /// Align data on a 4-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_4BYTES = 0x00300000,
+
+ ///
+ /// Align data on an 8-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_8BYTES = 0x00400000,
+
+ ///
+ /// Align data on a 16-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_16BYTES = 0x00500000,
+
+ ///
+ /// Align data on a 32-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_32BYTES = 0x00600000,
+
+ ///
+ /// Align data on a 64-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_64BYTES = 0x00700000,
+
+ ///
+ /// Align data on a 128-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_128BYTES = 0x00800000,
+
+ ///
+ /// Align data on a 256-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_256BYTES = 0x00900000,
+
+ ///
+ /// Align data on a 512-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_512BYTES = 0x00A00000,
+
+ ///
+ /// Align data on a 1024-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000,
+
+ ///
+ /// Align data on a 2048-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000,
+
+ ///
+ /// Align data on a 4096-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000,
+
+ ///
+ /// Align data on an 8192-byte boundary. Valid only for object files.
+ ///
+ IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000,
+
+ ///
+ /// The section contains extended relocations.
+ ///
+ IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000,
+
+ ///
+ /// The section can be discarded as needed.
+ ///
+ IMAGE_SCN_MEM_DISCARDABLE = 0x02000000,
+
+ ///
+ /// The section cannot be cached.
+ ///
+ IMAGE_SCN_MEM_NOT_CACHED = 0x04000000,
+
+ ///
+ /// The section is not pageable.
+ ///
+ IMAGE_SCN_MEM_NOT_PAGED = 0x08000000,
+
+ ///
+ /// The section can be shared in memory.
+ ///
+ IMAGE_SCN_MEM_SHARED = 0x10000000,
+
+ ///
+ /// The section can be executed as code.
+ ///
+ IMAGE_SCN_MEM_EXECUTE = 0x20000000,
+
+ ///
+ /// The section can be read.
+ ///
+ IMAGE_SCN_MEM_READ = 0x40000000,
+
+ ///
+ /// The section can be written to.
+ ///
+ IMAGE_SCN_MEM_WRITE = 0x80000000,
+ }
+
+ public enum SectionNumber : short
+ {
+ ///
+ /// The symbol record is not yet assigned a section. A value of
+ /// zero indicates that a reference to an external symbol is
+ /// defined elsewhere. A value of non-zero is a common symbol
+ /// with a size that is specified by the value.
+ ///
+ IMAGE_SYM_UNDEFINED = 0,
+
+ ///
+ /// The symbol has an absolute (non-relocatable) value and
+ /// is not an address.
+ ///
+ IMAGE_SYM_ABSOLUTE = -1,
+
+ ///
+ /// The symbol provides general type or debugging information
+ /// but does not correspond to a section. Microsoft tools use
+ /// this setting along with .file records (storage class FILE).
+ ///
+ IMAGE_SYM_DEBUG = -2,
+ }
+
+ public enum StorageClass : byte
+ {
+ ///
+ /// A special symbol that represents the end of function, for debugging purposes.
+ ///
+ IMAGE_SYM_CLASS_END_OF_FUNCTION = 0xFF,
+
+ ///
+ /// No assigned storage class.
+ ///
+ IMAGE_SYM_CLASS_NULL = 0x00,
+
+ ///
+ /// The automatic (stack) variable.The Value field specifies the stack frame offset.
+ ///
+ IMAGE_SYM_CLASS_AUTOMATIC = 0x01,
+
+ ///
+ /// A value that Microsoft tools use for external symbols. The Value field indicates
+ /// the size if the section number is IMAGE_SYM_UNDEFINED (0). If the section number
+ /// is not zero, then the Value field specifies the offset within the section.
+ ///
+ IMAGE_SYM_CLASS_EXTERNAL = 0x02,
+
+ ///
+ /// The offset of the symbol within the section. If the Value field is zero, then
+ /// the symbol represents a section name.
+ ///
+ IMAGE_SYM_CLASS_STATIC = 0x03,
+
+ ///
+ /// A register variable.The Value field specifies the register number.
+ ///
+ IMAGE_SYM_CLASS_REGISTER = 0x04,
+
+ ///
+ /// A symbol that is defined externally.
+ ///
+ IMAGE_SYM_CLASS_EXTERNAL_DEF = 0x05,
+
+ ///
+ /// A code label that is defined within the module. The Value field specifies the
+ /// offset of the symbol within the section.
+ ///
+ IMAGE_SYM_CLASS_LABEL = 0x06,
+
+ ///
+ /// A reference to a code label that is not defined.
+ ///
+ IMAGE_SYM_CLASS_UNDEFINED_LABEL = 0x07,
+
+ ///
+ /// The structure member. The Value field specifies the n th member.
+ ///
+ IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 0x08,
+
+ ///
+ /// A formal argument (parameter) of a function. The Value field specifies the
+ /// n th argument.
+ ///
+ IMAGE_SYM_CLASS_ARGUMENT = 0x09,
+
+ ///
+ /// The structure tag-name entry.
+ ///
+ IMAGE_SYM_CLASS_STRUCT_TAG = 0x0A,
+
+ ///
+ /// A union member. The Value field specifies the n th member.
+ ///
+ IMAGE_SYM_CLASS_MEMBER_OF_UNION = 0x0B,
+
+ ///
+ /// The Union tag-name entry.
+ ///
+ IMAGE_SYM_CLASS_UNION_TAG = 0x0C,
+
+ ///
+ /// A Typedef entry.
+ ///
+ IMAGE_SYM_CLASS_TYPE_DEFINITION = 0x0D,
+
+ ///
+ /// A static data declaration.
+ ///
+ IMAGE_SYM_CLASS_UNDEFINED_STATIC = 0x0E,
+
+ ///
+ /// An enumerated type tagname entry.
+ ///
+ IMAGE_SYM_CLASS_ENUM_TAG = 0x0F,
+
+ ///
+ /// A member of an enumeration. The Value field specifies the
+ /// n th member.
+ ///
+ IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 0x10,
+
+ ///
+ /// A register parameter.
+ ///
+ IMAGE_SYM_CLASS_REGISTER_PARAM = 0x11,
+
+ ///
+ /// A bit-field reference. The Value field specifies the
+ /// n th bit in the bit field.
+ ///
+ IMAGE_SYM_CLASS_BIT_FIELD = 0x12,
+
+ ///
+ /// A .bb (beginning of block) or .eb (end of block) record.
+ /// The Value field is the relocatable address of the code location.
+ ///
+ IMAGE_SYM_CLASS_BLOCK = 0x64,
+
+ ///
+ /// A value that Microsoft tools use for symbol records that define the extent
+ /// of a function: begin function (.bf ), end function (.ef), and lines in
+ /// function (.lf). For .lf records, the Value field gives the number of source
+ /// lines in the function. For .ef records, the Value field gives the size of
+ /// the function code.
+ ///
+ IMAGE_SYM_CLASS_FUNCTION = 0x65,
+
+ ///
+ /// An end-of-structure entry.
+ ///
+ IMAGE_SYM_CLASS_END_OF_STRUCT = 0x66,
+
+ ///
+ /// A value that Microsoft tools, as well as traditional COFF format, use for the
+ /// source-file symbol record. The symbol is followed by auxiliary records that
+ /// name the file.
+ ///
+ IMAGE_SYM_CLASS_FILE = 0x67,
+
+ ///
+ /// A definition of a section (Microsoft tools use STATIC storage class instead).
+ ///
+ IMAGE_SYM_CLASS_SECTION = 0x68,
+
+ ///
+ /// A weak external.For more information, see Auxiliary Format 3: Weak Externals.
+ ///
+ IMAGE_SYM_CLASS_WEAK_EXTERNAL = 0x69,
+
+ ///
+ /// A CLR token symbol. The name is an ASCII string that consists of the hexadecimal
+ /// value of the token. For more information, see CLR Token Definition (Object Only).
+ ///
+ IMAGE_SYM_CLASS_CLR_TOKEN = 0x6A,
+ }
+
+ [Flags]
+ public enum SymbolType : ushort
+ {
+ #region Simple (Base) Data Type
+
+ ///
+ /// No type information or unknown base type. Microsoft tools use this setting
+ ///
+ IMAGE_SYM_TYPE_NULL = 0x00,
+
+ ///
+ /// No valid type; used with void pointers and functions
+ ///
+ IMAGE_SYM_TYPE_VOID = 0x01,
+
+ ///
+ /// A character (signed byte)
+ ///
+ IMAGE_SYM_TYPE_CHAR = 0x02,
+
+ ///
+ /// A 2-byte signed integer
+ ///
+ IMAGE_SYM_TYPE_SHORT = 0x03,
+
+ ///
+ /// A natural integer type (normally 4 bytes in Windows)
+ ///
+ IMAGE_SYM_TYPE_INT = 0x04,
+
+ ///
+ /// A 4-byte signed integer
+ ///
+ IMAGE_SYM_TYPE_LONG = 0x05,
+
+ ///
+ /// A 4-byte floating-point number
+ ///
+ IMAGE_SYM_TYPE_FLOAT = 0x06,
+
+ ///
+ /// An 8-byte floating-point number
+ ///
+ IMAGE_SYM_TYPE_DOUBLE = 0x07,
+
+ ///
+ /// A structure
+ ///
+ IMAGE_SYM_TYPE_STRUCT = 0x08,
+
+ ///
+ /// A union
+ ///
+ IMAGE_SYM_TYPE_UNION = 0x09,
+
+ ///
+ /// An enumerated type
+ ///
+ IMAGE_SYM_TYPE_ENUM = 0x0A,
+
+ ///
+ /// A member of enumeration (a specific value)
+ ///
+ IMAGE_SYM_TYPE_MOE = 0x0B,
+
+ ///
+ /// A byte; unsigned 1-byte integer
+ ///
+ IMAGE_SYM_TYPE_BYTE = 0x0C,
+
+ ///
+ /// A word; unsigned 2-byte integer
+ ///
+ IMAGE_SYM_TYPE_WORD = 0x0D,
+
+ ///
+ /// An unsigned integer of natural size (normally, 4 bytes)
+ ///
+ IMAGE_SYM_TYPE_UINT = 0x0E,
+
+ ///
+ /// An unsigned 4-byte integer
+ ///
+ IMAGE_SYM_TYPE_DWORD = 0x0F,
+
+ #endregion
+
+ #region Complex Type
+
+ ///
+ /// The symbol is a pointer to base type
+ ///
+ IMAGE_SYM_DTYPE_POINTER = 0x10,
+
+ ///
+ /// The symbol is a function that returns a base type
+ ///
+ IMAGE_SYM_DTYPE_FUNCTION = 0x20,
+
+ ///
+ /// The symbol is an array of base type
+ ///
+ IMAGE_SYM_DTYPE_ARRAY = 0x30,
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Serialization/Models/COFF/FileHeader.cs b/SabreTools.Serialization/Models/COFF/FileHeader.cs
new file mode 100644
index 00000000..86ed66ab
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/FileHeader.cs
@@ -0,0 +1,58 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.COFF
+{
+ ///
+ /// At the beginning of an object file, or immediately after the signature
+ /// of an image file, is a standard COFF file header in the following format.
+ /// Note that the Windows loader limits the number of sections to 96.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class FileHeader
+ {
+ ///
+ /// The number that identifies the type of target machine.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public MachineType Machine;
+
+ ///
+ /// The number of sections. This indicates the size of the section table,
+ /// which immediately follows the headers.
+ ///
+ public ushort NumberOfSections;
+
+ ///
+ /// The low 32 bits of the number of seconds since 00:00 January 1, 1970
+ /// (a C run-time time_t value), which indicates when the file was created.
+ ///
+ public uint TimeDateStamp;
+
+ ///
+ /// The file offset of the COFF symbol table, or zero if no COFF symbol table
+ /// is present. This value should be zero for an image because COFF debugging
+ /// information is deprecated.
+ ///
+ public uint PointerToSymbolTable;
+
+ ///
+ /// The number of entries in the symbol table. This data can be used to locate
+ /// the string table, which immediately follows the symbol table. This value
+ /// should be zero for an image because COFF debugging information is deprecated.
+ ///
+ public uint NumberOfSymbols;
+
+ ///
+ /// The size of the optional header, which is required for executable files but
+ /// not for object files. This value should be zero for an object file.
+ ///
+ public ushort SizeOfOptionalHeader;
+
+ ///
+ /// The flags that indicate the attributes of the file.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public Characteristics Characteristics;
+ }
+}
diff --git a/SabreTools.Serialization/Models/COFF/LineNumber.cs b/SabreTools.Serialization/Models/COFF/LineNumber.cs
new file mode 100644
index 00000000..8311eb42
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/LineNumber.cs
@@ -0,0 +1,42 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.COFF
+{
+ ///
+ /// COFF line numbers are no longer produced and, in the future, will
+ /// not be consumed.
+ ///
+ /// COFF line numbers indicate the relationship between code and line
+ /// numbers in source files. The Microsoft format for COFF line numbers
+ /// is similar to standard COFF, but it has been extended to allow a
+ /// single section to relate to line numbers in multiple source files.
+ ///
+ /// COFF line numbers consist of an array of fixed-length records.
+ /// The location (file offset) and size of the array are specified in
+ /// the section header.
+ ///
+ ///
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class LineNumber
+ {
+ ///
+ /// Used when Linenumber is zero: index to symbol table entry for a function.
+ /// This format is used to indicate the function to which a group of
+ /// line-number records refers.
+ ///
+ [FieldOffset(0)] public uint SymbolTableIndex;
+
+ ///
+ /// Used when Linenumber is non-zero: the RVA of the executable code that
+ /// corresponds to the source line indicated. In an object file, this
+ /// contains the VA within the section.
+ ///
+ [FieldOffset(0)] public uint VirtualAddress;
+
+ ///
+ /// When nonzero, this field specifies a one-based line number. When zero,
+ /// the Type field is interpreted as a symbol table index for a function.
+ ///
+ [FieldOffset(4)] public ushort Linenumber;
+ }
+}
diff --git a/SabreTools.Serialization/Models/COFF/OptionalHeader.cs b/SabreTools.Serialization/Models/COFF/OptionalHeader.cs
new file mode 100644
index 00000000..95ee2694
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/OptionalHeader.cs
@@ -0,0 +1,88 @@
+namespace SabreTools.Serialization.Models.COFF
+{
+ ///
+ /// Every image file has an optional header that provides information to the loader.
+ /// This header is optional in the sense that some files (specifically, object files)
+ /// do not have it. For image files, this header is required. An object file can have
+ /// an optional header, but generally this header has no function in an object file
+ /// except to increase its size.
+ ///
+ /// Note that the size of the optional header is not fixed. The SizeOfOptionalHeader
+ /// field in the COFF header must be used to validate that a probe into the file for
+ /// a particular data directory does not go beyond SizeOfOptionalHeader.
+ ///
+ /// The NumberOfRvaAndSizes field of the optional header should also be used to ensure
+ /// that no probe for a particular data directory entry goes beyond the optional header.
+ /// In addition, it is important to validate the optional header magic number for format
+ /// compatibility.
+ ///
+ /// The optional header magic number determines whether an image is a PE32 or
+ /// PE32+ executable.
+ ///
+ /// PE32+ images allow for a 64-bit address space while limiting the image size to
+ /// 2 gigabytes. Other PE32+ modifications are addressed in their respective sections.
+ ///
+ /// The first eight fields of the optional header are standard fields that are defined
+ /// for every implementation of COFF. These fields contain general information that is
+ /// useful for loading and running an executable file. They are unchanged for the
+ /// PE32+ format.
+ ///
+ ///
+ public class OptionalHeader
+ {
+ ///
+ /// The unsigned integer that identifies the state of the image file. The most
+ /// common number is 0x10B, which identifies it as a normal executable file.
+ /// 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable.
+ ///
+ public OptionalHeaderMagicNumber Magic { get; set; }
+
+ ///
+ /// The linker major version number.
+ ///
+ public byte MajorLinkerVersion { get; set; }
+
+ ///
+ /// The linker minor version number.
+ ///
+ public byte MinorLinkerVersion { get; set; }
+
+ ///
+ /// The size of the code (text) section, or the sum of all code sections if there
+ /// are multiple sections.
+ ///
+ public uint SizeOfCode { get; set; }
+
+ ///
+ /// The size of the initialized data section, or the sum of all such sections if
+ /// there are multiple data sections.
+ ///
+ public uint SizeOfInitializedData { get; set; }
+
+ ///
+ /// The size of the uninitialized data section (BSS), or the sum of all such sections
+ /// if there are multiple BSS sections.
+ ///
+ public uint SizeOfUninitializedData { get; set; }
+
+ ///
+ /// The address of the entry point relative to the image base when the executable file
+ /// is loaded into memory. For program images, this is the starting address. For
+ /// device drivers, this is the address of the initialization function. An entry point
+ /// is optional for DLLs. When no entry point is present, this field must be zero.
+ ///
+ public uint AddressOfEntryPoint { get; set; }
+
+ ///
+ /// The address that is relative to the image base of the beginning-of-code section when
+ /// it is loaded into memory.
+ ///
+ public uint BaseOfCode { get; set; }
+
+ ///
+ /// The address that is relative to the image base of the beginning-of-data section when
+ /// it is loaded into memory.
+ ///
+ public uint BaseOfData { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/COFF/Relocation.cs b/SabreTools.Serialization/Models/COFF/Relocation.cs
new file mode 100644
index 00000000..1f5f5022
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/Relocation.cs
@@ -0,0 +1,47 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.COFF
+{
+ ///
+ /// Object files contain COFF relocations, which specify how the section data
+ /// should be modified when placed in the image file and subsequently loaded
+ /// into memory.
+ ///
+ /// Image files do not contain COFF relocations, because all referenced symbols
+ /// have already been assigned addresses in a flat address space. An image
+ /// contains relocation information in the form of base relocations in the
+ /// .reloc section (unless the image has the IMAGE_FILE_RELOCS_STRIPPED attribute).
+ ///
+ /// For each section in an object file, an array of fixed-length records holds
+ /// the section's COFF relocations. The position and length of the array are
+ /// specified in the section header.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Relocation
+ {
+ ///
+ /// The address of the item to which relocation is applied. This is the
+ /// offset from the beginning of the section, plus the value of the
+ /// section's RVA/Offset field. See Section Table (Section Headers).
+ /// For example, if the first byte of the section has an address of 0x10,
+ /// the third byte has an address of 0x12.
+ ///
+ public uint VirtualAddress;
+
+ ///
+ /// A zero-based index into the symbol table. This symbol gives the address
+ /// that is to be used for the relocation. If the specified symbol has section
+ /// storage class, then the symbol's address is the address with the first
+ /// section of the same name.
+ ///
+ public uint SymbolTableIndex;
+
+ ///
+ /// A value that indicates the kind of relocation that should be performed.
+ /// Valid relocation types depend on machine type.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public RelocationType TypeIndicator;
+ }
+}
diff --git a/SabreTools.Serialization/Models/COFF/SectionHeader.cs b/SabreTools.Serialization/Models/COFF/SectionHeader.cs
new file mode 100644
index 00000000..42b133d7
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SectionHeader.cs
@@ -0,0 +1,111 @@
+namespace SabreTools.Serialization.Models.COFF
+{
+ ///
+ /// Each row of the section table is, in effect, a section header. This table
+ /// immediately follows the optional header, if any. This positioning is required
+ /// because the file header does not contain a direct pointer to the section table.
+ /// Instead, the location of the section table is determined by calculating the
+ /// location of the first byte after the headers. Make sure to use the size of
+ /// the optional header as specified in the file header.
+ ///
+ /// The number of entries in the section table is given by the NumberOfSections
+ /// field in the file header. Entries in the section table are numbered starting
+ /// from one (1). The code and data memory section entries are in the order chosen
+ /// by the linker.
+ ///
+ /// In an image file, the VAs for sections must be assigned by the linker so that
+ /// they are in ascending order and adjacent, and they must be a multiple of the
+ /// SectionAlignment value in the optional header.
+ ///
+ ///
+ public sealed class SectionHeader
+ {
+ ///
+ /// An 8-byte, null-padded UTF-8 encoded string. If the string is exactly 8
+ /// characters long, there is no terminating null. For longer names, this field
+ /// contains a slash (/) that is followed by an ASCII representation of a
+ /// decimal number that is an offset into the string table. Executable images
+ /// do not use a string table and do not support section names longer than 8
+ /// characters. Long names in object files are truncated if they are emitted
+ /// to an executable file.
+ ///
+ /// 8 bytes
+ public byte[]? Name { get; set; }
+
+ ///
+ /// The total size of the section when loaded into memory. If this value is
+ /// greater than SizeOfRawData, the section is zero-padded. This field is valid
+ /// only for executable images and should be set to zero for object files.
+ ///
+ public uint VirtualSize { get; set; }
+
+ ///
+ /// For executable images, the address of the first byte of the section relative
+ /// to the image base when the section is loaded into memory. For object files,
+ /// this field is the address of the first byte before relocation is applied { get; set; }
+ /// for simplicity, compilers should set this to zero. Otherwise, it is an
+ /// arbitrary value that is subtracted from offsets during relocation.
+ ///
+ public uint VirtualAddress { get; set; }
+
+ ///
+ /// The size of the section (for object files) or the size of the initialized
+ /// data on disk (for image files). For executable images, this must be a multiple
+ /// of FileAlignment from the optional header. If this is less than VirtualSize,
+ /// the remainder of the section is zero-filled. Because the SizeOfRawData field
+ /// is rounded but the VirtualSize field is not, it is possible for SizeOfRawData
+ /// to be greater than VirtualSize as well. When a section contains only
+ /// uninitialized data, this field should be zero.
+ ///
+ public uint SizeOfRawData { get; set; }
+
+ ///
+ /// The file pointer to the first page of the section within the COFF file. For
+ /// executable images, this must be a multiple of FileAlignment from the optional
+ /// header. For object files, the value should be aligned on a 4-byte boundary
+ /// for best performance. When a section contains only uninitialized data, this
+ /// field should be zero.
+ ///
+ public uint PointerToRawData { get; set; }
+
+ ///
+ /// The file pointer to the beginning of relocation entries for the section. This
+ /// is set to zero for executable images or if there are no relocations.
+ ///
+ public uint PointerToRelocations { get; set; }
+
+ ///
+ /// The file pointer to the beginning of line-number entries for the section. This
+ /// is set to zero if there are no COFF line numbers. This value should be zero for
+ /// an image because COFF debugging information is deprecated.
+ ///
+ public uint PointerToLinenumbers { get; set; }
+
+ ///
+ /// The number of relocation entries for the section. This is set to zero for
+ /// executable images.
+ ///
+ public ushort NumberOfRelocations { get; set; }
+
+ ///
+ /// The number of line-number entries for the section. This value should be zero
+ /// for an image because COFF debugging information is deprecated.
+ ///
+ public ushort NumberOfLinenumbers { get; set; }
+
+ ///
+ /// The flags that describe the characteristics of the section.
+ ///
+ public SectionFlags Characteristics { get; set; }
+
+ ///
+ /// COFF Relocations (Object Only)
+ ///
+ public Relocation[]? COFFRelocations { get; set; }
+
+ ///
+ /// COFF Line Numbers (Deprecated)
+ ///
+ public LineNumber[]? COFFLineNumbers { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/COFF/StringTable.cs b/SabreTools.Serialization/Models/COFF/StringTable.cs
new file mode 100644
index 00000000..d45708d4
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/StringTable.cs
@@ -0,0 +1,25 @@
+namespace SabreTools.Serialization.Models.COFF
+{
+ ///
+ /// Immediately following the COFF symbol table is the COFF string table. The
+ /// position of this table is found by taking the symbol table address in the
+ /// COFF header and adding the number of symbols multiplied by the size of a symbol.
+ ///
+ ///
+ public sealed class StringTable
+ {
+ ///
+ /// At the beginning of the COFF string table are 4 bytes that contain the
+ /// total size (in bytes) of the rest of the string table. This size includes
+ /// the size field itself, so that the value in this location would be 4 if no
+ /// strings were present.
+ ///
+ public uint TotalSize { get; set; }
+
+ ///
+ /// Following the size are null-terminated strings that are pointed to by symbols
+ /// in the COFF symbol table.
+ ///
+ public string[]? Strings { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/COFF/SymbolTableEntries/BaseEntry.cs b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/BaseEntry.cs
new file mode 100644
index 00000000..f7478984
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/BaseEntry.cs
@@ -0,0 +1,32 @@
+namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
+{
+ ///
+ /// The symbol table in this section is inherited from the traditional
+ /// COFF format. It is distinct from Microsoft Visual C++ debug information.
+ /// A file can contain both a COFF symbol table and Visual C++ debug
+ /// information, and the two are kept separate. Some Microsoft tools use
+ /// the symbol table for limited but important purposes, such as
+ /// communicating COMDAT information to the linker. Section names and file
+ /// names, as well as code and data symbols, are listed in the symbol table.
+ ///
+ /// The location of the symbol table is indicated in the COFF header.
+ ///
+ /// The symbol table is an array of records, each 18 bytes long. Each record
+ /// is either a standard or auxiliary symbol-table record. A standard record
+ /// defines a symbol or name.
+ ///
+ /// Auxiliary symbol table records always follow, and apply to, some standard
+ /// symbol table record. An auxiliary record can have any format that the tools
+ /// can recognize, but 18 bytes must be allocated for them so that symbol table
+ /// is maintained as an array of regular size. Currently, Microsoft tools
+ /// recognize auxiliary formats for the following kinds of records: function
+ /// definitions, function begin and end symbols (.bf and .ef), weak externals,
+ /// file names, and section definitions.
+ ///
+ /// The traditional COFF design also includes auxiliary-record formats for arrays
+ /// and structures.Microsoft tools do not use these, but instead place that
+ /// symbolic information in Visual C++ debug format in the debug sections.
+ ///
+ ///
+ public abstract class BaseEntry { }
+}
diff --git a/SabreTools.Serialization/Models/COFF/SymbolTableEntries/CLRTokenDefinition.cs b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/CLRTokenDefinition.cs
new file mode 100644
index 00000000..18c5f20f
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/CLRTokenDefinition.cs
@@ -0,0 +1,33 @@
+namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
+{
+ ///
+ /// Auxiliary Format 6: CLR Token Definition (Object Only)
+ ///
+ /// This auxiliary symbol generally follows the IMAGE_SYM_CLASS_CLR_TOKEN. It is
+ /// used to associate a token with the COFF symbol table's namespace.
+ ///
+ ///
+ public class CLRTokenDefinition : BaseEntry
+ {
+ ///
+ /// Must be IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF (1).
+ ///
+ public byte AuxType { get; set; }
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ public byte Reserved1 { get; set; }
+
+ ///
+ /// The symbol index of the COFF symbol to which this CLR token definition refers.
+ ///
+ public uint SymbolTableIndex { get; set; }
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ /// 12 bytes
+ public byte[]? Reserved2 { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/COFF/SymbolTableEntries/Descriptor.cs b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/Descriptor.cs
new file mode 100644
index 00000000..fc766f09
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/Descriptor.cs
@@ -0,0 +1,53 @@
+namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
+{
+ ///
+ /// Auxiliary Format 2: .bf and .ef Symbols
+ ///
+ /// For each function definition in the symbol table, three items describe
+ /// the beginning, ending, and number of lines. Each of these symbols has
+ /// storage class FUNCTION (101):
+ ///
+ /// A symbol record named .bf (begin function). The Value field is unused.
+ ///
+ /// A symbol record named .lf (lines in function). The Value field gives the
+ /// number of lines in the function.
+ ///
+ /// A symbol record named .ef (end of function). The Value field has the same
+ /// number as the Total Size field in the function-definition symbol record.
+ ///
+ // The .bf and .ef symbol records (but not .lf records) are followed by an
+ // auxiliary record with the following format:
+ ///
+ ///
+ public class Descriptor : BaseEntry
+ {
+ ///
+ /// Unused
+ ///
+ public uint Unused1 { get; set; }
+
+ ///
+ /// The actual ordinal line number (1, 2, 3, and so on) within the source file,
+ /// corresponding to the .bf or .ef record.
+ ///
+ public ushort Linenumber { get; set; }
+
+ ///
+ /// Unused
+ ///
+ /// 6 bytes
+ public byte[]? Unused2 { get; set; }
+
+ ///
+ /// The symbol-table index of the next .bf symbol record. If the function is the
+ /// last in the symbol table, this field is set to zero. It is not used for
+ /// .ef records.
+ ///
+ public uint PointerToNextFunction { get; set; }
+
+ ///
+ /// Unused
+ ///
+ public ushort Unused3 { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/COFF/SymbolTableEntries/FileRecord.cs b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/FileRecord.cs
new file mode 100644
index 00000000..8d84283a
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/FileRecord.cs
@@ -0,0 +1,20 @@
+namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
+{
+ ///
+ /// Auxiliary Format 4: Files
+ ///
+ /// This format follows a symbol-table record with storage class FILE (103).
+ /// The symbol name itself should be .file, and the auxiliary record that
+ /// follows it gives the name of a source-code file.
+ ///
+ ///
+ public class FileRecord : BaseEntry
+ {
+ ///
+ /// An ANSI string that gives the name of the source file. This is padded
+ /// with nulls if it is less than the maximum length.
+ ///
+ /// 18 bytes
+ public byte[]? FileName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/COFF/SymbolTableEntries/FunctionDefinition.cs b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/FunctionDefinition.cs
new file mode 100644
index 00000000..7a460a90
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/FunctionDefinition.cs
@@ -0,0 +1,47 @@
+namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
+{
+ ///
+ /// Auxiliary Format 1: Function Definitions
+ ///
+ /// A symbol table record marks the beginning of a function definition if it
+ /// has all of the following: a storage class of EXTERNAL (2), a Type value
+ /// that indicates it is a function (0x20), and a section number that is
+ /// greater than zero. Note that a symbol table record that has a section
+ /// number of UNDEFINED (0) does not define the function and does not have
+ /// an auxiliary record. Function-definition symbol records are followed by
+ /// an auxiliary record in the format described below:
+ ///
+ ///
+ public class FunctionDefinition : BaseEntry
+ {
+ ///
+ /// The symbol-table index of the corresponding .bf (begin function)
+ /// symbol record.
+ ///
+ public uint TagIndex { get; set; }
+
+ ///
+ /// The size of the executable code for the function itself. If the function
+ /// is in its own section, the SizeOfRawData in the section header is greater
+ /// or equal to this field, depending on alignment considerations.
+ ///
+ public uint TotalSize { get; set; }
+
+ ///
+ /// The file offset of the first COFF line-number entry for the function, or
+ /// zero if none exists.
+ ///
+ public uint PointerToLinenumber { get; set; }
+
+ ///
+ /// The symbol-table index of the record for the next function. If the function
+ /// is the last in the symbol table, this field is set to zero.
+ ///
+ public uint PointerToNextFunction { get; set; }
+
+ ///
+ /// Unused
+ ///
+ public ushort Unused { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/COFF/SymbolTableEntries/SectionDefinition.cs b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/SectionDefinition.cs
new file mode 100644
index 00000000..881b1efd
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/SectionDefinition.cs
@@ -0,0 +1,54 @@
+namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
+{
+ ///
+ /// Auxiliary Format 5: Section Definitions
+ ///
+ /// This format follows a symbol-table record that defines a section. Such a
+ /// record has a symbol name that is the name of a section (such as .text or
+ /// .drectve) and has storage class STATIC (3). The auxiliary record provides
+ /// information about the section to which it refers. Thus, it duplicates some
+ /// of the information in the section header.
+ ///
+ ///
+ public class SectionDefinition : BaseEntry
+ {
+ ///
+ /// The size of section data; the same as SizeOfRawData in the section header.
+ ///
+ public uint Length { get; set; }
+
+ ///
+ /// The number of relocation entries for the section.
+ ///
+ public ushort NumberOfRelocations { get; set; }
+
+ ///
+ /// The number of line-number entries for the section.
+ ///
+ public ushort NumberOfLinenumbers { get; set; }
+
+ ///
+ /// The checksum for communal data. It is applicable if the IMAGE_SCN_LNK_COMDAT
+ /// flag is set in the section header.
+ ///
+ public uint CheckSum { get; set; }
+
+ ///
+ /// One-based index into the section table for the associated section. This is
+ /// used when the COMDAT selection setting is 5.
+ ///
+ public ushort Number { get; set; }
+
+ ///
+ /// The COMDAT selection number. This is applicable if the section is a
+ /// COMDAT section.
+ ///
+ public byte Selection { get; set; }
+
+ ///
+ /// Unused
+ ///
+ /// 3 bytes
+ public byte[]? Unused { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/COFF/SymbolTableEntries/StandardRecord.cs b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/StandardRecord.cs
new file mode 100644
index 00000000..a79ad94f
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/StandardRecord.cs
@@ -0,0 +1,58 @@
+namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
+{
+ ///
+ /// A standard record defines a symbol or name.
+ ///
+ ///
+ public class StandardRecord : BaseEntry
+ {
+ #region Symbol Name
+
+ ///
+ /// An array of 8 bytes. This array is padded with nulls on the right if
+ /// the name is less than 8 bytes long.
+ ///
+ public byte[]? ShortName { get; set; } = new byte[8];
+
+ ///
+ /// A field that is set to all zeros if the name is longer than 8 bytes.
+ ///
+ public uint Zeroes { get; set; }
+
+ ///
+ /// An offset into the string table.
+ ///
+ public uint Offset { get; set; }
+
+ #endregion
+
+ ///
+ /// The value that is associated with the symbol. The interpretation of this
+ /// field depends on SectionNumber and StorageClass. A typical meaning is the
+ /// relocatable address.
+ ///
+ public uint Value { get; set; }
+
+ ///
+ /// The signed integer that identifies the section, using a one-based index
+ /// into the section table. Some values have special meaning.
+ ///
+ public SectionNumber SectionNumber { get; set; }
+
+ ///
+ /// A number that represents type. Microsoft tools set this field to 0x20
+ /// (function) or 0x0 (not a function).
+ ///
+ public SymbolType SymbolType { get; set; }
+
+ ///
+ /// An enumerated value that represents storage class.
+ ///
+ public StorageClass StorageClass { get; set; }
+
+ ///
+ /// The number of auxiliary symbol table entries that follow this record.
+ ///
+ public byte NumberOfAuxSymbols { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/COFF/SymbolTableEntries/WeakExternal.cs b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/WeakExternal.cs
new file mode 100644
index 00000000..a96a5b16
--- /dev/null
+++ b/SabreTools.Serialization/Models/COFF/SymbolTableEntries/WeakExternal.cs
@@ -0,0 +1,45 @@
+namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
+{
+ ///
+ /// Auxiliary Format 3: Weak Externals
+ ///
+ /// "Weak externals" are a mechanism for object files that allows flexibility at
+ /// link time. A module can contain an unresolved external symbol (sym1), but it
+ /// can also include an auxiliary record that indicates that if sym1 is not
+ /// present at link time, another external symbol (sym2) is used to resolve
+ /// references instead.
+ ///
+ /// If a definition of sym1 is linked, then an external reference to the symbol
+ /// is resolved normally. If a definition of sym1 is not linked, then all references
+ /// to the weak external for sym1 refer to sym2 instead. The external symbol, sym2,
+ /// must always be linked; typically, it is defined in the module that contains
+ /// the weak reference to sym1.
+ ///
+ /// Weak externals are represented by a symbol table record with EXTERNAL storage
+ /// class, UNDEF section number, and a value of zero. The weak-external symbol
+ /// record is followed by an auxiliary record with the following format:
+ ///
+ ///
+ public class WeakExternal : BaseEntry
+ {
+ ///
+ /// The symbol-table index of sym2, the symbol to be linked if sym1 is not found.
+ ///
+ public uint TagIndex { get; set; }
+
+ ///
+ /// A value of IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY indicates that no library search
+ /// for sym1 should be performed.
+ /// A value of IMAGE_WEAK_EXTERN_SEARCH_LIBRARY indicates that a library search for
+ /// sym1 should be performed.
+ /// A value of IMAGE_WEAK_EXTERN_SEARCH_ALIAS indicates that sym1 is an alias for sym2.
+ ///
+ public uint Characteristics { get; set; }
+
+ ///
+ /// Unused
+ ///
+ /// 10 bytes
+ public byte[]? Unused { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/Delphi/Constants.cs b/SabreTools.Serialization/Models/Delphi/Constants.cs
new file mode 100644
index 00000000..1e5928a0
--- /dev/null
+++ b/SabreTools.Serialization/Models/Delphi/Constants.cs
@@ -0,0 +1,14 @@
+///
+/// Information sourced from https://stackoverflow.com/questions/18720045/what-are-the-list-of-all-possible-values-for-dvclal
+///
+namespace SabreTools.Serialization.Models.Delphi
+{
+ public static class Constants
+ {
+ public static readonly byte[] DVCLALStandard = [0x23, 0x78, 0x5D, 0x23, 0xB6, 0xA5, 0xF3, 0x19, 0x43, 0xF3, 0x40, 0x02, 0x26, 0xD1, 0x11, 0xC7];
+
+ public static readonly byte[] DVCLALProfessional = [0xA2, 0x8C, 0xDF, 0x98, 0x7B, 0x3C, 0x3A, 0x79, 0x26, 0x71, 0x3F, 0x09, 0x0F, 0x2A, 0x25, 0x17];
+
+ public static readonly byte[] DVCLALEnterprise = [0x26, 0x3D, 0x4F, 0x38, 0xC2, 0x82, 0x37, 0xB8, 0xF3, 0x24, 0x42, 0x03, 0x17, 0x9B, 0x3A, 0x83];
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/Delphi/PackageInfoTable.cs b/SabreTools.Serialization/Models/Delphi/PackageInfoTable.cs
new file mode 100644
index 00000000..f7e9ff0f
--- /dev/null
+++ b/SabreTools.Serialization/Models/Delphi/PackageInfoTable.cs
@@ -0,0 +1,14 @@
+///
+/// Information sourced from https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.PackageInfoTable
+///
+namespace SabreTools.Serialization.Models.Delphi
+{
+ public class PackageInfoTable
+ {
+ public int UnitCount { get; set; }
+
+ public PackageUnitEntry[]? UnitInfo { get; set; }
+
+ public PackageTypeInfo? TypeInfo { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/Delphi/PackageTypeInfo.cs b/SabreTools.Serialization/Models/Delphi/PackageTypeInfo.cs
new file mode 100644
index 00000000..2dc4e7c2
--- /dev/null
+++ b/SabreTools.Serialization/Models/Delphi/PackageTypeInfo.cs
@@ -0,0 +1,19 @@
+///
+/// Information sourced from https://docwiki.embarcadero.com/Libraries/Sydney/en/System.TPackageTypeInfo
+///
+namespace SabreTools.Serialization.Models.Delphi
+{
+ public class PackageTypeInfo
+ {
+ public int TypeCount { get; set; }
+
+ ///
+ /// System-dependent pointer type, assumed to be encoded for x86
+ ///
+ public uint[]? TypeTable { get; set; }
+
+ public int UnitCount { get; set; }
+
+ public string[]? UnitNames { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/Delphi/PackageUnitEntry.cs b/SabreTools.Serialization/Models/Delphi/PackageUnitEntry.cs
new file mode 100644
index 00000000..1604d931
--- /dev/null
+++ b/SabreTools.Serialization/Models/Delphi/PackageUnitEntry.cs
@@ -0,0 +1,21 @@
+using System.Runtime.InteropServices;
+
+///
+/// Information sourced from https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.PackageUnitEntry
+///
+namespace SabreTools.Serialization.Models.Delphi
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public class PackageUnitEntry
+ {
+ ///
+ /// System-dependent pointer type, assumed to be encoded for x86
+ ///
+ public uint Init;
+
+ ///
+ /// System-dependent pointer type, assumed to be encoded for x86
+ ///
+ public uint FInit;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/LinearExecutable/Constants.cs b/SabreTools.Serialization/Models/LinearExecutable/Constants.cs
new file mode 100644
index 00000000..4948a169
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/Constants.cs
@@ -0,0 +1,21 @@
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ public static class Constants
+ {
+ public static readonly byte[] DebugInformationSignatureBytes = [0x4e, 0x42, 0x30];
+
+ public const string DebugInformationSignatureString = "NB0";
+
+ public static readonly byte[] LESignatureBytes = [0x4c, 0x45];
+
+ public const string LESignatureString = "LE";
+
+ public const ushort LESignatureUInt16 = 0x454c;
+
+ public static readonly byte[] LXSignatureBytes = [0x4c, 0x58];
+
+ public const string LXSignatureString = "LX";
+
+ public const ushort LXSignatureUInt16 = 0x584c;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/LinearExecutable/DebugInformation.cs b/SabreTools.Serialization/Models/LinearExecutable/DebugInformation.cs
new file mode 100644
index 00000000..cc6e815e
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/DebugInformation.cs
@@ -0,0 +1,35 @@
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The debug information is defined by the debugger and is not controlled by
+ /// the linear EXE format or linker. The only data defined by the linear EXE
+ /// format relative to the debug information is it's offset in the EXE file and
+ /// length in bytes as defined in the linear EXE header.
+ ///
+ /// To support multiple debuggers the first word of the debug information is a
+ /// type field which determines the format of the debug information.
+ ///
+ ///
+ ///
+ public sealed class DebugInformation
+ {
+ ///
+ /// The signature consists of a string of three (3) ASCII characters: "NB0"
+ ///
+ public string? Signature { get; set; }
+
+ ///
+ /// This defines the type of debugger data that exists in the remainder of the
+ /// debug information.
+ ///
+ public DebugFormatType FormatType { get; set; }
+
+ ///
+ /// The format of the debugger data is defined by the debugger that is being used.
+ /// The values defined for the type field are not enforced by the system. It is
+ /// the responsibility of the linker or debugging tools to follow the convention
+ /// for the type field that is defined here.
+ ///
+ public byte[]? DebuggerData { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/EntryTableBundle.cs b/SabreTools.Serialization/Models/LinearExecutable/EntryTableBundle.cs
new file mode 100644
index 00000000..1998bc47
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/EntryTableBundle.cs
@@ -0,0 +1,56 @@
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The entry table contains object and offset information that is used to resolve
+ /// fixup references to the entry points within this module. Not all entry points
+ /// in the entry table will be exported, some entry points will only be used
+ /// within the module. An ordinal number is used to index into the entry table.
+ /// The entry table entries are numbered starting from one.
+ ///
+ /// The list of entries are compressed into 'bundles', where possible. The entries
+ /// within each bundle are all the same size. A bundle starts with a count field
+ /// which indicates the number of entries in the bundle. The count is followed by
+ /// a type field which identifies the bundle format. This provides both a means
+ /// for saving space as well as a mechanism for extending the bundle types.
+ ///
+ ///
+ ///
+ public sealed class EntryTableBundle
+ {
+ ///
+ /// Number of entries.
+ ///
+ ///
+ /// This is the number of entries in this bundle.
+ ///
+ /// A zero value for the number of entries identifies the end of the
+ /// entry table. There is no further bundle information when the number
+ /// of entries is zero. In other words the entry table is terminated by
+ /// a single zero byte.
+ ///
+ /// For , this is the number of unused
+ /// entries to skip.
+ /// For , this is the number of 16-bit
+ /// entries in this bundle. The flags and offset value are repeated this
+ /// number of times.
+ /// For , this is the number
+ /// of 286 call gate entries in this bundle. The flags, callgate, and offset
+ /// value are repeated this number of times.
+ /// For , this is the number
+ /// of 32-bit entries in this bundle. The flags and offset value are repeated
+ /// this number of times.
+ /// For , this field is reserved for future use.
+ ///
+ public byte Entries { get; set; }
+
+ ///
+ /// This defines the bundle type which determines the contents of the BUNDLE INFO.
+ ///
+ public BundleType BundleType { get; set; }
+
+ ///
+ /// Table entries in the bundle
+ ///
+ public EntryTableEntry[]? TableEntries { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/EntryTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/EntryTableEntry.cs
new file mode 100644
index 00000000..ba301b85
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/EntryTableEntry.cs
@@ -0,0 +1,190 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ ///
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class EntryTableEntry
+ {
+ #region 16-bit Entry
+
+ ///
+ /// Object number.
+ ///
+ ///
+ /// This is the object number for the entries in this bundle.
+ ///
+ [FieldOffset(0)] public ushort SixteenBitObjectNumber;
+
+ ///
+ /// Entry flags.
+ ///
+ ///
+ /// These are the flags for this entry point.
+ ///
+ [FieldOffset(2)] public EntryFlags SixteenBitEntryFlags;
+
+ ///
+ /// Offset in object.
+ ///
+ ///
+ /// This is the offset in the object for the entry point defined at this ordinal number.
+ ///
+ [FieldOffset(3)] public ushort SixteenBitOffset;
+
+ #endregion
+
+ #region 286 Call Gate Entry
+
+ ///
+ /// Object number.
+ ///
+ ///
+ /// This is the object number for the entries in this bundle.
+ ///
+ [FieldOffset(0)] public ushort TwoEightySixObjectNumber;
+
+ ///
+ /// Entry flags.
+ ///
+ ///
+ /// These are the flags for this entry point.
+ ///
+ [FieldOffset(2)] public EntryFlags TwoEightySixEntryFlags;
+
+ ///
+ /// Offset in object.
+ ///
+ ///
+ /// This is the offset in the object for the entry point defined at this ordinal number.
+ ///
+ [FieldOffset(3)] public ushort TwoEightySixOffset;
+
+ ///
+ /// Callgate selector.
+ ///
+ ///
+ /// The callgate selector is a reserved field used by the loader to store a call
+ /// gate selector value for references to ring 2 entry points. When a ring 3
+ /// reference to a ring 2 entry point is made, the callgate selector with a zero
+ /// offset is place in the relocation fixup address. The segment number and offset
+ /// in segment is placed in the LDT callgate.
+ ///
+ [FieldOffset(5)] public ushort TwoEightySixCallgate;
+
+ #endregion
+
+ #region 32-bit Entry
+
+ ///
+ /// Object number.
+ ///
+ ///
+ /// This is the object number for the entries in this bundle.
+ ///
+ [FieldOffset(0)] public ushort ThirtyTwoBitObjectNumber;
+
+ ///
+ /// Entry flags.
+ ///
+ ///
+ /// These are the flags for this entry point.
+ ///
+ [FieldOffset(2)] public EntryFlags ThirtyTwoBitEntryFlags;
+
+ ///
+ /// Offset in object.
+ ///
+ ///
+ /// This is the offset in the object for the entry point defined at this ordinal number.
+ ///
+ [FieldOffset(3)] public uint ThirtyTwoBitOffset;
+
+ #endregion
+
+ #region Forwarder Entry
+
+ ///
+ /// 0
+ ///
+ ///
+ /// This field is reserved for future use.
+ ///
+ [FieldOffset(0)] public ushort ForwarderReserved;
+
+ ///
+ /// Forwarder flags.
+ ///
+ ///
+ /// These are the flags for this entry point.
+ ///
+ [FieldOffset(2)] public ForwarderFlags ForwarderFlags;
+
+ ///
+ /// Module Ordinal Number
+ ///
+ ///
+ /// This is the index into the Import Module Name Table for this forwarder.
+ ///
+ [FieldOffset(3)] public ushort ForwarderModuleOrdinalNumber;
+
+ ///
+ /// Procedure Name Offset
+ ///
+ ///
+ /// If the FLAGS field indicates import by ordinal, then this field is the
+ /// ordinal number into the Entry Table of the target module, otherwise this
+ /// field is the offset into the Procedure Names Table of the target module.
+ ///
+ /// A Forwarder entry (type = 4) is an entry point whose value is an imported
+ /// reference. When a load time fixup occurs whose target is a forwarder, the
+ /// loader obtains the address imported by the forwarder and uses that imported
+ /// address to resolve the fixup.
+ ///
+ /// A forwarder may refer to an entry point in another module which is itself a
+ /// forwarder, so there can be a chain of forwarders. The loader will traverse
+ /// the chain until it finds a non-forwarded entry point which terminates the
+ /// chain, and use this to resolve the original fixup. Circular chains are
+ /// detected by the loader and result in a load time error. A maximum of 1024
+ /// forwarders is allowed in a chain; more than this results in a load time error.
+ ///
+ /// Forwarders are useful for merging and recombining API calls into different
+ /// sets of libraries, while maintaining compatibility with applications. For
+ /// example, if one wanted to combine MONCALLS, MOUCALLS, and VIOCALLS into a
+ /// single libraries, one could provide entry points for the three libraries
+ /// that are forwarders pointing to the common implementation.
+ ///
+ [FieldOffset(5)] public uint ProcedureNameOffset;
+
+ ///
+ /// Import Ordinal Number
+ ///
+ ///
+ /// If the FLAGS field indicates import by ordinal, then this field is the
+ /// ordinal number into the Entry Table of the target module, otherwise this
+ /// field is the offset into the Procedure Names Table of the target module.
+ ///
+ /// A Forwarder entry (type = 4) is an entry point whose value is an imported
+ /// reference. When a load time fixup occurs whose target is a forwarder, the
+ /// loader obtains the address imported by the forwarder and uses that imported
+ /// address to resolve the fixup.
+ ///
+ /// A forwarder may refer to an entry point in another module which is itself a
+ /// forwarder, so there can be a chain of forwarders. The loader will traverse
+ /// the chain until it finds a non-forwarded entry point which terminates the
+ /// chain, and use this to resolve the original fixup. Circular chains are
+ /// detected by the loader and result in a load time error. A maximum of 1024
+ /// forwarders is allowed in a chain; more than this results in a load time error.
+ ///
+ /// Forwarders are useful for merging and recombining API calls into different
+ /// sets of libraries, while maintaining compatibility with applications. For
+ /// example, if one wanted to combine MONCALLS, MOUCALLS, and VIOCALLS into a
+ /// single libraries, one could provide entry points for the three libraries
+ /// that are forwarders pointing to the common implementation.
+ ///
+ [FieldOffset(5)] public uint ImportOrdinalNumber;
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/LinearExecutable/Enums.cs b/SabreTools.Serialization/Models/LinearExecutable/Enums.cs
new file mode 100644
index 00000000..21fc1fac
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/Enums.cs
@@ -0,0 +1,680 @@
+using System;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ [Flags]
+ public enum BundleType : byte
+ {
+ ///
+ /// Unused Entry.
+ ///
+ UnusedEntry = 0x00,
+
+ ///
+ /// 16-bit Entry.
+ ///
+ SixteenBitEntry = 0x01,
+
+ ///
+ /// 286 Call Gate Entry.
+ ///
+ TwoEightySixCallGateEntry = 0x02,
+
+ ///
+ /// 32-bit Entry.
+ ///
+ ThirtyTwoBitEntry = 0x03,
+
+ ///
+ /// Forwarder Entry.
+ ///
+ ForwarderEntry = 0x04,
+
+ ///
+ /// Parameter Typing Information Present.
+ ///
+ ///
+ /// This bit signifies that additional information is contained in the
+ /// linear EXE module and will be used in the future for parameter type checking.
+ ///
+ ParameterTypingInformationPresent = 0x80,
+ }
+
+ public enum ByteOrder : byte
+ {
+ ///
+ /// little-endian
+ ///
+ LE = 0x00,
+
+ ///
+ /// big-endian
+ ///
+ /// non-zero
+ BE = 0x01,
+ }
+
+ public enum CPUType : ushort
+ {
+ ///
+ /// Intel 80286 or upwardly compatible
+ ///
+ Intel80286 = 0x01,
+
+ ///
+ /// Intel 80386 or upwardly compatible
+ ///
+ Intel80386 = 0x02,
+
+ ///
+ /// Intel 80486 or upwardly compatible
+ ///
+ Intel80486 = 0x03,
+
+ ///
+ /// Intel 80586 or upwardly compatible
+ ///
+ Intel80586 = 0x04,
+
+ ///
+ /// Intel i860 (N10) or compatible
+ ///
+ Inteli860 = 0x20,
+
+ ///
+ /// Intel "N11" or compatible
+ ///
+ IntelN11 = 0x21,
+
+ ///
+ /// MIPS Mark I (R2000, R3000) or compatible
+ ///
+ MIPSMarkI = 0x40,
+
+ ///
+ /// MIPS Mark II ( R6000 ) or compatible
+ ///
+ MIPSMarkII = 0x41,
+
+ ///
+ /// MIPS Mark III ( R4000 ) or compatible
+ ///
+ MIPSMarkIII = 0x42,
+ }
+
+ public enum DebugFormatType : byte
+ {
+ ///
+ /// 32-bit CodeView debugger format.
+ ///
+ CodeView32Bit = 0x00,
+
+ ///
+ /// AIX debugger format.
+ ///
+ AIXDebugger = 0x01,
+
+ ///
+ /// 16-bit CodeView debugger format.
+ ///
+ CodeView16Bit = 0x02,
+
+ ///
+ /// 32-bit OS/2 PM debugger (IBM) format.
+ ///
+ OS2PM32Bit = 0x04,
+ }
+
+ public enum DirectiveNumber : ushort
+ {
+ ///
+ /// Resident Flag Mask.
+ ///
+ ///
+ /// Directive numbers with this bit set indicate that the directive data
+ /// is in the resident area and will be kept resident in memory when the
+ /// module is loaded.
+ ///
+ ResidentFlagMask = 0x8000,
+
+ ///
+ /// Verify Record Directive. (Verify record is a resident table.)
+ ///
+ VerifyRecordDirective = 0x8001,
+
+ ///
+ /// Language Information Directive. (This is a non-resident table.)
+ ///
+ LanguageInformationDirective = 0x0002,
+
+ ///
+ /// Co-Processor Required Support Table.
+ ///
+ CoProcessorRequiredSupportTable = 0x0003,
+
+ ///
+ /// Thread State Initialization Directive.
+ ///
+ ThreadStateInitializationDirective = 0x0004,
+
+ // Additional directives can be added as needed in the future, as long as
+ // they do not overlap previously defined directive numbers.
+ }
+
+ [Flags]
+ public enum EntryFlags : byte
+ {
+ ///
+ /// Exported entry flag.
+ ///
+ ExportedEntry = 0x01,
+
+ ///
+ /// Parameter word count mask.
+ ///
+ ParameterWordCountMask = 0xF8,
+ }
+
+ [Flags]
+ public enum FixupRecordSourceType : byte
+ {
+ ///
+ /// Source mask.
+ ///
+ SourceMask = 0x0F,
+
+ ///
+ /// Byte fixup (8-bits).
+ ///
+ ByteFixup = 0x00,
+
+ ///
+ /// (undefined).
+ ///
+ Undefined1 = 0x01,
+
+ ///
+ /// 16-bit Selector fixup (16-bits).
+ ///
+ SixteenBitSelectorFixup = 0x02,
+
+ ///
+ /// 16:16 Pointer fixup (32-bits).
+ ///
+ SixteenSixteenPointerFixup = 0x03,
+
+ ///
+ /// (undefined).
+ ///
+ Undefined4 = 0x04,
+
+ ///
+ /// 16-bit Offset fixup (16-bits).
+ ///
+ SixteenBitOffsetFixup = 0x05,
+
+ ///
+ /// 16:32 Pointer fixup (48-bits).
+ ///
+ SixteenThirtyTwoPointerFixup = 0x06,
+
+ ///
+ /// 32-bit Offset fixup (32-bits).
+ ///
+ ThirtyTwoBitOffsetFixup = 0x07,
+
+ ///
+ /// 32-bit Self-relative offset fixup (32-bits).
+ ///
+ ThirtyTwoBitSelfRelativeOffsetFixup = 0x08,
+
+ ///
+ /// Fixup to Alias Flag.
+ ///
+ ///
+ /// When the 'Fixup to Alias' Flag is set, the source fixup refers to
+ /// the 16:16 alias for the object. This is only valid for source types
+ /// of 2, 3, and 6. For fixups such as this, the linker and loader will
+ /// be required to perform additional checks such as ensuring that the
+ /// target offset for this fixup is less than 64K.
+ ///
+ FixupToAliasFlag = 0x10,
+
+ ///
+ /// Source List Flag.
+ ///
+ ///
+ /// When the 'Source List' Flag is set, the SRCOFF field is compressed
+ /// to a byte and contains the number of source offsets, and a list of source
+ /// offsets follows the end of fixup record (after the optional additive value).
+ ///
+ SourceListFlag = 0x20,
+ }
+
+ [Flags]
+ public enum FixupRecordTargetFlags : byte
+ {
+ ///
+ /// Fixup target type mask.
+ ///
+ FixupTargetTypeMask = 0x03,
+
+ ///
+ /// Internal reference.
+ ///
+ InternalReference = 0x00,
+
+ ///
+ /// Imported reference by ordinal.
+ ///
+ ImportedReferenceByOrdinal = 0x01,
+
+ ///
+ /// Imported reference by name.
+ ///
+ ImportedReferenceByName = 0x02,
+
+ ///
+ /// Internal reference via entry table.
+ ///
+ InternalReferenceViaEntryTable = 0x03,
+
+ ///
+ /// Additive Fixup Flag.
+ ///
+ ///
+ /// When set, an additive value trails the fixup record (before the optional
+ /// source offset list).
+ ///
+ AdditiveFixupFlag = 0x04,
+
+ ///
+ /// Reserved. Must be zero.
+ ///
+ Reserved = 0x08,
+
+ ///
+ /// 32-bit Target Offset Flag.
+ ///
+ ///
+ /// When set, the target offset is 32-bits, otherwise it is 16-bits.
+ ///
+ ThirtyTwoBitTargetOffsetFlag = 0x10,
+
+ ///
+ /// 32-bit Additive Fixup Flag.
+ ///
+ /// When set, the additive value is 32-bits, otherwise it is 16-bits.
+ ///
+ ThirtyTwoBitAdditiveFixupFlag = 0x20,
+
+ ///
+ /// 16-bit Object Number/Module Ordinal Flag.
+ ///
+ ///
+ /// When set, the object number or module ordinal number is 16-bits,
+ /// otherwise it is 8-bits.
+ ///
+ SixteenBitObjectNumberModuleOrdinalFlag = 0x40,
+
+ ///
+ /// 8-bit Ordinal Flag.
+ ///
+ ///
+ /// When set, the ordinal number is 8-bits, otherwise it is 16-bits.
+ ///
+ EightBitOrdinalFlag = 0x80,
+ }
+
+ [Flags]
+ public enum ForwarderFlags : byte
+ {
+ ///
+ /// Import by ordinal.
+ ///
+ ImportByOrdinal = 0x01,
+
+ ///
+ /// Reserved for future use; should be zero.
+ ///
+ Reserved = 0xF7,
+ }
+
+ [Flags]
+ public enum ModuleFlags : uint
+ {
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved0 = 0x00000001,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved1 = 0x00000002,
+
+ ///
+ /// Per-Process Library Initialization.
+ ///
+ ///
+ /// The setting of this bit requires the EIP Object # and EIP fields
+ /// to have valid values. If the EIP Object # and EIP fields are
+ /// valid and this bit is NOT set, then Global Library Initialization
+ /// is assumed. Setting this bit for an EXE file is invalid.
+ ///
+ Initialization = 0x00000004,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved3 = 0x00000008,
+
+ ///
+ /// Internal fixups for the module have been applied.
+ ///
+ ///
+ /// The setting of this bit in a Linear Executable Module indicates that
+ /// each object of the module has a preferred load address specified in
+ /// the Object Table Reloc Base Addr. If the module's objects can not be
+ /// loaded at these preferred addresses, then the relocation records that
+ /// have been retained in the file data will be applied.
+ ///
+ InternalFixupsApplied = 0x00000010,
+
+ ///
+ /// External fixups for the module have been applied.
+ ///
+ ExternalFixupsApplied = 0x00000020,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved6 = 0x00000040,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved7 = 0x00000080,
+
+ ///
+ /// Incompatible with PM windowing.
+ ///
+ IncompatibleWithPMWindowing = 0x00000100,
+
+ ///
+ /// Incompatible with PM windowing.
+ ///
+ CompatibleWithPMWindowing = 0x00000200,
+
+ ///
+ /// Uses PM windowing API.
+ ///
+ UsesPMWindowing = 0x00000300,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved10 = 0x00000400,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved11 = 0x00000800,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved12 = 0x00001000,
+
+ ///
+ /// Module is not loadable.
+ ///
+ ///
+ /// When the 'Module is not loadable' flag is set, it indicates that
+ /// either errors were detected at link time or that the module is
+ /// being incrementally linked and therefore can't be loaded.
+ ///
+ ModuleNotLoadable = 0x00002000,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved14 = 0x00004000,
+
+ ///
+ /// Module type mask.
+ ///
+ ModuleTypeMask = 0x00038000,
+
+ ///
+ /// Program module.
+ ///
+ ///
+ /// A module can not contain dynamic links to other modules that have
+ /// the 'program module' type.
+ ///
+ ProgramModule = 0x00000000,
+
+ ///
+ /// Library module.
+ ///
+ LibraryModule = 0x00008000,
+
+ ///
+ /// Protected Memory Library module.
+ ///
+ ProtectedMemoryLibraryModule = 0x00018000,
+
+ ///
+ /// Physical Device Driver module.
+ ///
+ PhysicalDeviceDriverModule = 0x00020000,
+
+ ///
+ /// Virtual Device Driver module.
+ ///
+ VirtualDeviceDriverModule = 0x00028000,
+
+ ///
+ /// Per-process Library Termination.
+ ///
+ ///
+ /// The setting of this bit requires the EIP Object # and EIP fields
+ /// to have valid values. If the EIP Object # and EIP fields are
+ /// valid and this bit is NOT set, then Global Library Termination
+ /// is assumed. Setting this bit for an EXE file is invalid.
+ ///
+ PerProcessLibraryTermination = 0x40000000,
+ }
+
+ [Flags]
+ public enum ObjectFlags : ushort
+ {
+ ///
+ /// Readable Object.
+ ///
+ ReadableObject = 0x0001,
+
+ ///
+ /// Writable Object.
+ ///
+ WritableObject = 0x0002,
+
+ ///
+ /// Executable Object.
+ ///
+ ExecutableObject = 0x0004,
+
+ // The readable, writable and executable flags provide support for all possible
+ // protections. In systems where all of these protections are not supported,
+ // the loader will be responsible for making the appropriate protection match
+ // for the system.
+
+ ///
+ /// Resource Object.
+ ///
+ ResourceObject = 0x0008,
+
+ ///
+ /// Discardable Object.
+ ///
+ DiscardableObject = 0x0010,
+
+ ///
+ /// Object is Shared.
+ ///
+ Shared = 0x0020,
+
+ ///
+ /// Object has Preload Pages.
+ ///
+ HasPreloadPages = 0x0040,
+
+ ///
+ /// Object has Invalid Pages.
+ ///
+ HasInvalidPages = 0x0080,
+
+ ///
+ /// Object has Zero Filled Pages.
+ ///
+ HasZeroFilledPages = 0x0100,
+
+ ///
+ /// Object is Resident (valid for VDDs, PDDs only).
+ ///
+ Resident = 0x0200,
+
+ ///
+ /// Object is Resident & Contiguous (VDDs, PDDs only).
+ ///
+ ResidentAndContiguous = 0x0300,
+
+ ///
+ /// Object is Resident & 'long-lockable' (VDDs, PDDs only).
+ ///
+ ResidentAndLongLockable = 0x0400,
+
+ ///
+ /// Reserved for system use.
+ ///
+ Reserved = 0x0800,
+
+ ///
+ /// 16:16 Alias Required (80x86 Specific).
+ ///
+ AliasRequired = 0x1000,
+
+ ///
+ /// Big/Default Bit Setting (80x86 Specific).
+ ///
+ BitSetting = 0x2000,
+
+ // The 'big/default' bit, for data segments, controls the setting of the
+ // Big bit in the segment descriptor. (The Big bit, or B-bit, determines
+ // whether ESP or SP is used as the stack pointer.) For code segments,
+ // this bit controls the setting of the Default bit in the segment
+ // descriptor. (The Default bit, or D-bit, determines whether the default
+ // word size is 32-bits or 16-bits. It also affects the interpretation of
+ // the instruction stream.)
+
+ ///
+ /// Object is conforming for code (80x86 Specific).
+ ///
+ Conforming = 0x4000,
+
+ ///
+ /// Object I/O privilege level (80x86 Specific). Only used for 16:16 Alias Objects.
+ ///
+ PrivilegeLevel = 0x8000,
+ }
+
+ [Flags]
+ public enum ObjectPageFlags : ushort
+ {
+ ///
+ /// Legal Physical Page in the module (Offset from Preload Page Section).
+ ///
+ LegalPhysicalPage = 0x0000,
+
+ ///
+ /// Iterated Data Page (Offset from Iterated Data Pages Section).
+ ///
+ IteratedDataPage = 0x0001,
+
+ ///
+ /// Invalid Page (zero).
+ ///
+ InvalidPage = 0x0002,
+
+ ///
+ /// Zero Filled Page (zero).
+ ///
+ ZeroFilledPage = 0x0003,
+
+ ///
+ /// Range of Pages.
+ ///
+ RangeOfPages = 0x0004,
+ }
+
+ public enum OperatingSystem : ushort
+ {
+ ///
+ /// Unknown (any "new-format" OS)
+ ///
+ Unknown = 0x00,
+
+ ///
+ /// OS/2 (default)
+ ///
+ OS2 = 0x01,
+
+ ///
+ /// Windows
+ ///
+ Windows = 0x02,
+
+ ///
+ /// DOS 4.x
+ ///
+ DOS4x = 0x03,
+
+ ///
+ /// Windows 386
+ ///
+ Windows386 = 0x04,
+ }
+
+ public enum ResourceTableEntryType : uint
+ {
+ ///
+ /// "BTMP" - Bitmap
+ ///
+ BTMP = 0x504d5442,
+
+ ///
+ /// "EMSG" - Error message string
+ ///
+ EMSG = 0x47534d45,
+
+ ///
+ /// "FONT" - Fonts
+ ///
+ FONT = 0x544e4f46,
+ }
+
+ public enum WordOrder : byte
+ {
+ ///
+ /// little-endian
+ ///
+ LE = 0x00,
+
+ ///
+ /// big-endian
+ ///
+ /// non-zero
+ BE = 0x01,
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/Executable.cs b/SabreTools.Serialization/Models/LinearExecutable/Executable.cs
new file mode 100644
index 00000000..39f35c60
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/Executable.cs
@@ -0,0 +1,97 @@
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The `LINEAR` executable-file header contains information that the loader requires for
+ /// segmented executable files. This information includes the linker version number, data
+ /// specified by linker, data specified by resource compiler, tables of segment data, tables
+ /// of resource data, and so on. The following illustrations shows the LE file header:
+ ///
+ ///
+ ///
+ public sealed class Executable
+ {
+ ///
+ /// MS-DOS executable stub
+ ///
+ public MSDOS.Executable? Stub { get; set; }
+
+ ///
+ /// Information block
+ ///
+ public InformationBlock? InformationBlock { get; set; }
+
+ ///
+ /// Object table
+ ///
+ public ObjectTableEntry[]? ObjectTable { get; set; }
+
+ ///
+ /// Object page map
+ ///
+ public ObjectPageMapEntry[]? ObjectPageMap { get; set; }
+
+ // TODO: Object iterate data map table (Undefined)
+
+ ///
+ /// Resource table
+ ///
+ public ResourceTableEntry[]? ResourceTable { get; set; }
+
+ ///
+ /// Resident Name table
+ ///
+ public ResidentNamesTableEntry[]? ResidentNamesTable { get; set; }
+
+ ///
+ /// Entry table
+ ///
+ public EntryTableBundle[]? EntryTable { get; set; }
+
+ ///
+ /// Module format directives table (optional)
+ ///
+ public ModuleFormatDirectivesTableEntry[]? ModuleFormatDirectivesTable { get; set; }
+
+ ///
+ /// Verify record directive table (optional)
+ ///
+ public VerifyRecordDirectiveTableEntry[]? VerifyRecordDirectiveTable { get; set; }
+
+ ///
+ /// Fix-up page table
+ ///
+ public FixupPageTableEntry[]? FixupPageTable { get; set; }
+
+ ///
+ /// Fix-up record table
+ ///
+ public FixupRecordTableEntry[]? FixupRecordTable { get; set; }
+
+ ///
+ /// Import module name table
+ ///
+ public ImportModuleNameTableEntry[]? ImportModuleNameTable { get; set; }
+
+ ///
+ /// Import procedure name table
+ ///
+ public ImportModuleProcedureNameTableEntry[]? ImportModuleProcedureNameTable { get; set; }
+
+ ///
+ /// Per-Page checksum table
+ ///
+ public PerPageChecksumTableEntry[]? PerPageChecksumTable { get; set; }
+
+ ///
+ /// Non-Resident Name table
+ ///
+ public NonResidentNamesTableEntry[]? NonResidentNamesTable { get; set; }
+
+ // TODO: Non-resident directives data (Undefined)
+
+ ///
+ /// Debug information
+ ///
+ public DebugInformation? DebugInformation { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/FixupPageTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/FixupPageTableEntry.cs
new file mode 100644
index 00000000..a4171d16
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/FixupPageTableEntry.cs
@@ -0,0 +1,36 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The Fixup Page Table provides a simple mapping of a logical page number
+ /// to an offset into the Fixup Record Table for that page.
+ ///
+ /// This table is parallel to the Object Page Table, except that there is
+ /// one additional entry in this table to indicate the end of the Fixup
+ /// Record Table.
+ ///
+ /// The fixup records are kept in order by logical page in the fixup record
+ /// table. This allows the end of each page's fixup records is defined by the
+ /// offset for the next logical page's fixup records. This last entry provides
+ /// support of this mechanism for the last page in the fixup page table.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class FixupPageTableEntry
+ {
+ ///
+ /// Offset for fixup record for this page. (1 to n)
+ /// Offset to the end of the fixup records. (n + 1)
+ ///
+ ///
+ /// This field specifies the offset, from the beginning of the fixup record
+ /// table, to the first fixup record for this page. (1 to n)
+ ///
+ /// This field specifies the offset following the last fixup record in the
+ /// fixup record table. This is the last entry in the fixup page table. (n + 1)
+ ///
+ public uint Offset;
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/FixupRecordTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/FixupRecordTableEntry.cs
new file mode 100644
index 00000000..2ff41447
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/FixupRecordTableEntry.cs
@@ -0,0 +1,363 @@
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The Fixup Record Table contains entries for all fixups in the linear EXE module.
+ /// The fixup records for a logical page are grouped together and kept in sorted
+ /// order by logical page number. The fixups for each page are further sorted such
+ /// that all external fixups and internal selector/pointer fixups come before
+ /// internal non-selector/non-pointer fixups. This allows the loader to ignore
+ /// internal fixups if the loader is able to load all objects at the addresses
+ /// specified in the object table.
+ ///
+ ///
+ ///
+ public sealed class FixupRecordTableEntry
+ {
+ ///
+ /// Source type.
+ ///
+ ///
+ /// The source type specifies the size and type of the fixup to be performed
+ /// on the fixup source.
+ ///
+ public FixupRecordSourceType SourceType { get; set; }
+
+ ///
+ /// Target Flags.
+ ///
+ ///
+ /// The target flags specify how the target information is interpreted.
+ ///
+ public FixupRecordTargetFlags TargetFlags { get; set; }
+
+ #region Source List Flag
+
+ #region Set
+
+ ///
+ /// Source offset.
+ ///
+ ///
+ /// This field contains either an offset or a count depending on the Source
+ /// List Flag. If the Source List Flag is set, a list of source offsets
+ /// follows the additive field and this field contains the count of the
+ /// entries in the source offset list. Otherwise, this is the single source
+ /// offset for the fixup. Source offsets are relative to the beginning of
+ /// the page where the fixup is to be made.
+ ///
+ /// Note that for fixups that cross page boundaries, a separate fixup record
+ /// is specified for each page. An offset is still used for the 2nd page but
+ /// it now becomes a negative offset since the fixup originated on the
+ /// preceding page. (For example, if only the last one byte of a 32-bit
+ /// address is on the page to be fixed up, then the offset would have a value
+ /// of -3.)
+ ///
+ public ushort SourceOffset { get; set; }
+
+ #endregion
+
+ #region Unset
+
+ ///
+ /// Source offset list count.
+ ///
+ ///
+ /// This field contains either an offset or a count depending on the Source
+ /// List Flag. If the Source List Flag is set, a list of source offsets
+ /// follows the additive field and this field contains the count of the
+ /// entries in the source offset list. Otherwise, this is the single source
+ /// offset for the fixup. Source offsets are relative to the beginning of
+ /// the page where the fixup is to be made.
+ ///
+ /// Note that for fixups that cross page boundaries, a separate fixup record
+ /// is specified for each page. An offset is still used for the 2nd page but
+ /// it now becomes a negative offset since the fixup originated on the
+ /// preceding page. (For example, if only the last one byte of a 32-bit
+ /// address is on the page to be fixed up, then the offset would have a value
+ /// of -3.)
+ ///
+ public byte SourceOffsetListCount { get; set; }
+
+ #endregion
+
+ #endregion
+
+ #region OBJECT / TRGOFF
+
+ #region 16-bit Object Number/Module Ordinal Flag
+
+ #region Set
+
+ ///
+ /// Target object number.
+ ///
+ ///
+ /// This field is an index into the current module's Object Table to specify
+ /// the target Object. It is a Byte value when the '16-bit Object Number/Module
+ /// Ordinal Flag' bit in the target flags field is clear and a Word value when
+ /// the bit is set.
+ ///
+ public ushort TargetObjectNumberWORD { get; set; }
+
+ #endregion
+
+ #region Unset
+
+ ///
+ /// Target object number.
+ ///
+ ///
+ /// This field is an index into the current module's Object Table to specify
+ /// the target Object. It is a Byte value when the '16-bit Object Number/Module
+ /// Ordinal Flag' bit in the target flags field is clear and a Word value when
+ /// the bit is set.
+ ///
+ public byte TargetObjectNumberByte { get; set; }
+
+ #endregion
+
+ #endregion
+
+ #region 32-bit Target Offset Flag
+
+ #region Set
+
+ ///
+ /// Target offset.
+ ///
+ ///
+ /// This field is an offset into the specified target Object. It is not
+ /// present when the Source Type specifies a 16-bit Selector fixup. It
+ /// is a Word value when the '32-bit Target Offset Flag' bit in the target
+ /// flags field is clear and a Dword value when the bit is set.
+ ///
+ public uint TargetOffsetDWORD { get; set; }
+
+ #endregion
+
+ #region Unset
+
+ ///
+ /// Target offset.
+ ///
+ ///
+ /// This field is an offset into the specified target Object. It is not
+ /// present when the Source Type specifies a 16-bit Selector fixup. It
+ /// is a Word value when the '32-bit Target Offset Flag' bit in the target
+ /// flags field is clear and a Dword value when the bit is set.
+ ///
+ public ushort TargetOffsetWORD { get; set; }
+
+ #endregion
+
+ #endregion
+
+ #endregion
+
+ #region 16-bit Object Number/Module Ordinal Flag [Incompatible with OBJECT / TRGOFF]
+
+ #region Set
+
+ ///
+ /// Ordinal index into the Import Module Name Table.
+ ///
+ ///
+ /// This value is an ordered index in to the Import Module Name Table for
+ /// the module containing the procedure entry point. It is a Byte value
+ /// when the '16-bit Object Number/Module Ordinal' Flag bit in the target
+ /// flags field is clear and a Word value when the bit is set. The loader
+ /// creates a table of pointers with each pointer in the table corresponds
+ /// to the modules named in the Import Module Name Table. This value is used
+ /// by the loader to index into this table created by the loader to locate
+ /// the referenced module.
+ ///
+ public ushort OrdinalIndexImportModuleNameTableWORD { get; set; }
+
+ #endregion
+
+ #region Unset
+
+ ///
+ /// Ordinal index into the Import Module Name Table.
+ ///
+ ///
+ /// This value is an ordered index in to the Import Module Name Table for
+ /// the module containing the procedure entry point. It is a Byte value
+ /// when the '16-bit Object Number/Module Ordinal' Flag bit in the target
+ /// flags field is clear and a Word value when the bit is set. The loader
+ /// creates a table of pointers with each pointer in the table corresponds
+ /// to the modules named in the Import Module Name Table. This value is used
+ /// by the loader to index into this table created by the loader to locate
+ /// the referenced module.
+ ///
+ public byte OrdinalIndexImportModuleNameTableByte { get; set; }
+
+ #endregion
+
+ #endregion
+
+ #region MOD ORD# / PROCEDURE NAME OFFSET / ADDITIVE
+
+ #region 32-bit Target Offset Flag
+
+ #region Set
+
+ ///
+ /// Offset into the Import Procedure Name Table.
+ ///
+ ///
+ /// This field is an offset into the Import Procedure Name Table. It is
+ /// a Word value when the '32-bit Target Offset Flag' bit in the target
+ /// flags field is clear and a Dword value when the bit is set.
+ ///
+ public uint OffsetImportProcedureNameTableDWORD { get; set; }
+
+ #endregion
+
+ #region Unset
+
+ ///
+ /// Offset into the Import Procedure Name Table.
+ ///
+ ///
+ /// This field is an offset into the Import Procedure Name Table. It is
+ /// a Word value when the '32-bit Target Offset Flag' bit in the target
+ /// flags field is clear and a Dword value when the bit is set.
+ ///
+ public ushort OffsetImportProcedureNameTableWORD { get; set; }
+
+ #endregion
+
+ #endregion
+
+ #endregion
+
+ #region MOD ORD# / IMPORT ORD / ADDITIVE
+
+ #region 8-bit Ordinal Flag
+
+ #region Set
+
+ ///
+ /// Imported ordinal number.
+ ///
+ ///
+ /// This is the imported procedure's ordinal number. It is a Byte value when the
+ /// '8-bit Ordinal' bit in the target flags field is set. Otherwise it is a Word value
+ /// when the '32-bit Target Offset Flag' bit in the target flags field is clear and a
+ /// Dword value when the bit is set.
+ ///
+ public byte ImportedOrdinalNumberByte { get; set; }
+
+ #endregion
+
+ #region Unset
+
+ #region 32-bit Target Offset Flag
+
+ #region Set
+
+ ///
+ /// Imported ordinal number.
+ ///
+ ///
+ /// This is the imported procedure's ordinal number. It is a Byte value when the
+ /// '8-bit Ordinal' bit in the target flags field is set. Otherwise it is a Word value
+ /// when the '32-bit Target Offset Flag' bit in the target flags field is clear and a
+ /// Dword value when the bit is set.
+ ///
+ public uint ImportedOrdinalNumberDWORD { get; set; }
+
+ #endregion
+
+ #region Unset
+
+ ///
+ /// Imported ordinal number.
+ ///
+ ///
+ /// This is the imported procedure's ordinal number. It is a Byte value when the
+ /// '8-bit Ordinal' bit in the target flags field is set. Otherwise it is a Word value
+ /// when the '32-bit Target Offset Flag' bit in the target flags field is clear and a
+ /// Dword value when the bit is set.
+ ///
+ public uint ImportedOrdinalNumberWORD { get; set; }
+
+ #endregion
+
+ #endregion
+
+ #endregion
+
+ #endregion
+
+ #endregion
+
+ #region Additive Fixup Flag [Incompatible with OBJECT / TRGOFF]
+
+ #region Set
+
+ #region 32-bit Additive Fixup Flag
+
+ #region Set
+
+ ///
+ /// Additive fixup value.
+ ///
+ ///
+ /// This field exists in the fixup record only when the 'Additive Fixup Flag'
+ /// bit in the target flags field is set. When the 'Additive Fixup Flag' is
+ /// clear the fixup record does not contain this field and is immediately
+ /// followed by the next fixup record (or by the source offset list for this
+ /// fixup record).
+ ///
+ /// This value is added to the address derived from the target entry point.
+ /// This field is a Word value when the '32-bit Additive Flag' bit in the
+ /// target flags field is clear and a Dword value when the bit is set.
+ ///
+ public uint AdditiveFixupValueDWORD { get; set; }
+
+ #endregion
+
+ #region Unset
+
+ ///
+ /// Additive fixup value.
+ ///
+ ///
+ /// This field exists in the fixup record only when the 'Additive Fixup Flag'
+ /// bit in the target flags field is set. When the 'Additive Fixup Flag' is
+ /// clear the fixup record does not contain this field and is immediately
+ /// followed by the next fixup record (or by the source offset list for this
+ /// fixup record).
+ ///
+ /// This value is added to the address derived from the target entry point.
+ /// This field is a Word value when the '32-bit Additive Flag' bit in the
+ /// target flags field is clear and a Dword value when the bit is set.
+ ///
+ public ushort AdditiveFixupValueWORD { get; set; }
+
+ #endregion
+
+ #endregion
+
+ #endregion
+
+ #endregion
+
+ #region SCROFFn
+
+ ///
+ /// Source offset list.
+ ///
+ ///
+ /// This list is present if the Source List Flag is set in the Target Flags field.
+ /// The number of entries in the source offset list is defined in the SRCOFF/CNT
+ /// field. The source offsets are relative to the beginning of the page where the
+ /// fixups are to be made.
+ ///
+ public ushort[]? SourceOffsetList { get; set; }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/ImportModuleNameTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/ImportModuleNameTableEntry.cs
new file mode 100644
index 00000000..5c352a83
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/ImportModuleNameTableEntry.cs
@@ -0,0 +1,38 @@
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The import module name table defines the module name strings imported through
+ /// dynamic link references. These strings are referenced through the imported
+ /// relocation fixups.
+ ///
+ /// To determine the length of the import module name table subtract the import
+ /// module name table offset from the import procedure name table offset. These
+ /// values are located in the linear EXE header. The end of the import module
+ /// name table is not terminated by a special character, it is followed directly
+ /// by the import procedure name table.
+ ///
+ /// The strings are CASE SENSITIVE and NOT NULL TERMINATED.
+ ///
+ ///
+ ///
+ public sealed class ImportModuleNameTableEntry
+ {
+ ///
+ /// String Length.
+ ///
+ ///
+ /// This defines the length of the string in bytes. The length of each
+ /// ascii name string is limited to 127 characters.
+ ///
+ public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
+
+ ///
+ /// ASCII String.
+ ///
+ ///
+ /// This is a variable length string with it's length defined in bytes by
+ /// the LEN field. The string is case sensitive and is not null terminated.
+ ///
+ public string? Name { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/ImportProcedureNameTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/ImportProcedureNameTableEntry.cs
new file mode 100644
index 00000000..34fe3eac
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/ImportProcedureNameTableEntry.cs
@@ -0,0 +1,46 @@
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The import procedure name table defines the procedure name strings imported
+ /// by this module through dynamic link references. These strings are referenced
+ /// through the imported relocation fixups.
+ ///
+ /// To determine the length of the import procedure name table add the fixup
+ /// section size to the fixup page table offset, this computes the offset to
+ /// the end of the fixup section, then subtract the import procedure name table
+ /// offset. These values are located in the linear EXE header. The import
+ /// procedure name table is followed by the data pages section. Since the data
+ /// pages section is aligned on a 'page size' boundary, padded space may exist
+ /// between the last import name string and the first page in the data pages
+ /// section. If this padded space exists it will be zero filled.
+ ///
+ /// The strings are CASE SENSITIVE and NOT NULL TERMINATED.
+ ///
+ ///
+ ///
+ public sealed class ImportModuleProcedureNameTableEntry
+ {
+ ///
+ /// String Length.
+ ///
+ ///
+ /// This defines the length of the string in bytes. The length of each
+ /// ascii name string is limited to 127 characters.
+ ///
+ /// The high bit in the LEN field (bit 7) is defined as an Overload bit.
+ /// This bit signifies that additional information is contained in the
+ /// linear EXE module and will be used in the future for parameter type
+ /// checking.
+ ///
+ public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
+
+ ///
+ /// ASCII String.
+ ///
+ ///
+ /// This is a variable length string with it's length defined in bytes by
+ /// the LEN field. The string is case sensitive and is not null terminated.
+ ///
+ public string? Name { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/InformationBlock.cs b/SabreTools.Serialization/Models/LinearExecutable/InformationBlock.cs
new file mode 100644
index 00000000..67970046
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/InformationBlock.cs
@@ -0,0 +1,432 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The `information block` in the LE header contains the linker version number,
+ /// length of various tables that further describe the executable file, the
+ /// offsets from the beginning of the header to the beginning of these tables,
+ /// the heap and stack sizes, and so on. The following list summarizes the
+ /// contents of the header `information block` (the locations are relative to
+ /// the beginning of the block):
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public sealed class InformationBlock
+ {
+ ///
+ /// Specifies the signature word
+ /// 'LE' (4Ch 45H)
+ /// 'LX' (4Ch 58H)
+ ///
+ ///
+ /// The signature word is used by the loader to identify the EXE
+ /// file as a valid 32-bit Linear Executable Module Format.
+ ///
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
+ public string? Signature;
+
+ ///
+ /// Byte Ordering.
+ ///
+ ///
+ /// This byte specifies the byte ordering for the linear EXE format.
+ ///
+ [MarshalAs(UnmanagedType.U1)]
+ public ByteOrder ByteOrder;
+
+ ///
+ /// Word Ordering.
+ ///
+ ///
+ /// This byte specifies the Word ordering for the linear EXE format.
+ ///
+ [MarshalAs(UnmanagedType.U1)]
+ public WordOrder WordOrder;
+
+ ///
+ /// Linear EXE Format Level.
+ ///
+ ///
+ /// The Linear EXE Format Level is set to 0 for the initial version of the
+ /// 32-bit linear EXE format. Each incompatible change to the linear EXE
+ /// format must increment this value. This allows the system to recognized
+ /// future EXE file versions so that an appropriate error message may be
+ /// displayed if an attempt is made to load them.
+ ///
+ public uint ExecutableFormatLevel;
+
+ ///
+ /// Module CPU Type.
+ ///
+ ///
+ /// This field specifies the type of CPU required by this module to run.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public CPUType CPUType;
+
+ ///
+ /// Module OS Type.
+ ///
+ ///
+ /// This field specifies the type of Operating system required to run this module.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public OperatingSystem ModuleOS;
+
+ ///
+ /// Module version
+ ///
+ ///
+ /// This is useful for differentiating between revisions of dynamic linked modules.
+ /// This value is specified at link time by the user.
+ ///
+ public uint ModuleVersion;
+
+ ///
+ /// Module type flags
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public ModuleFlags ModuleTypeFlags;
+
+ ///
+ /// Number of pages in module.
+ ///
+ ///
+ /// This field specifies the number of pages physically contained in this module.
+ /// In other words, pages containing either enumerated or iterated data, or
+ /// zero-fill pages that have relocations, not invalid or zero-fill pages implied
+ /// by the Virtual Size in the Object Table being larger than the number of pages
+ /// actually in the linear EXE file. These pages are contained in the 'preload
+ /// pages', 'demand load pages' and 'iterated data pages' sections of the linear
+ /// EXE module. This is used to determine the size of the page information tables
+ /// in the linear EXE module.
+ ///
+ public uint ModuleNumberPages;
+
+ ///
+ /// The Object number to which the Entry Address is relative.
+ ///
+ ///
+ /// This specifies the object to which the Entry Address is relative. This must be
+ /// a nonzero value for a program module to be correctly loaded. A zero value for
+ /// a library module indicates that no library entry routine exists. If this value
+ /// is zero, then both the Per-process Library Initialization bit and the Per-process
+ /// Library Termination bit must be clear in the module flags, or else the loader
+ /// will fail to load the module. Further, if the Per-process Library Termination bit
+ /// is set, then the object to which this field refers must be a 32-bit object (i.e.,
+ /// the Big/Default bit must be set in the object flags; see below).
+ ///
+ public uint InitialObjectCS;
+
+ ///
+ /// Entry Address of module.
+ ///
+ ///
+ /// The Entry Address is the starting address for program modules and the library
+ /// initialization and Library termination address for library modules.
+ ///
+ public uint InitialEIP;
+
+ ///
+ /// The Object number to which the ESP is relative.
+ ///
+ ///
+ /// This specifies the object to which the starting ESP is relative. This must be a
+ /// nonzero value for a program module to be correctly loaded. This field is ignored
+ /// for a library module.
+ ///
+ public uint InitialObjectSS;
+
+ ///
+ /// Starting stack address of module.
+ ///
+ ///
+ /// The ESP defines the starting stack pointer address for program modules. A zero
+ /// value in this field indicates that the stack pointer is to be initialized to the
+ /// highest address/offset in the object. This field is ignored for a library module.
+ ///
+ public uint InitialESP;
+
+ ///
+ /// The size of one page for this system.
+ ///
+ ///
+ /// This field specifies the page size used by the linear EXE format and the system.
+ /// For the initial version of this linear EXE format the page size is 4Kbytes.
+ /// (The 4K page size is specified by a value of 4096 in this field.)
+ ///
+ public uint MemoryPageSize;
+
+ ///
+ /// The shift left bits for page offsets.
+ ///
+ ///
+ /// This field gives the number of bit positions to shift left when interpreting
+ /// the Object Page Table entries' page offset field. This determines the alignment
+ /// of the page information in the file. For example, a value of 4 in this field
+ /// would align all pages in the Data Pages and Iterated Pages sections on 16 byte
+ /// (paragraph) boundaries. A Page Offset Shift of 9 would align all pages on a
+ /// 512 byte (disk sector) basis. The default value for this field is 12 (decimal),
+ /// which give a 4096 byte alignment. All other offsets are byte aligned.
+ ///
+ public uint BytesOnLastPage;
+
+ ///
+ /// Total size of the fixup information in bytes.
+ ///
+ ///
+ /// This includes the following 4 tables:
+ /// - Fixup Page Table
+ /// - Fixup Record Table
+ /// - Import Module name Table
+ /// - Import Procedure Name Table
+ ///
+ public uint FixupSectionSize;
+
+ ///
+ /// Checksum for fixup information.
+ ///
+ ///
+ /// This is a cryptographic checksum covering all of the fixup information. The
+ /// checksum for the fixup information is kept separate because the fixup data is
+ /// not always loaded into main memory with the 'loader section'. If the checksum
+ /// feature is not implemented, then the linker will set these fields to zero.
+ ///
+ public uint FixupSectionChecksum;
+
+ ///
+ /// Size of memory resident tables.
+ ///
+ ///
+ /// This is the total size in bytes of the tables required to be memory resident
+ /// for the module, while the module is in use. This total size includes all
+ /// tables from the Object Table down to and including the Per-Page Checksum Table.
+ ///
+ public uint LoaderSectionSize;
+
+ ///
+ /// Checksum for loader section.
+ ///
+ ///
+ /// This is a cryptographic checksum covering all of the loader section information.
+ /// If the checksum feature is not implemented, then the linker will set these fields
+ /// to zero.
+ ///
+ public uint LoaderSectionChecksum;
+
+ ///
+ /// Object Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint ObjectTableOffset;
+
+ ///
+ /// Object Table Count.
+ ///
+ ///
+ /// This defines the number of entries in Object Table.
+ ///
+ public uint ObjectTableCount;
+
+ ///
+ /// Object Page Table offset
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint ObjectPageMapOffset;
+
+ ///
+ /// Object Iterated Pages offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint ObjectIterateDataMapOffset;
+
+ ///
+ /// Resource Table offset
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint ResourceTableOffset;
+
+ ///
+ /// Number of entries in Resource Table.
+ ///
+ public uint ResourceTableCount;
+
+ ///
+ /// Resident Name Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint ResidentNamesTableOffset;
+
+ ///
+ /// Entry Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint EntryTableOffset;
+
+ ///
+ /// Module Format Directives Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint ModuleDirectivesTableOffset;
+
+ ///
+ /// Number of Module Format Directives in the Table.
+ ///
+ ///
+ /// This field specifies the number of entries in the
+ /// Module Format Directives Table.
+ ///
+ public uint ModuleDirectivesCount;
+
+ ///
+ /// Fixup Page Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint FixupPageTableOffset;
+
+ ///
+ /// Fixup Record Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint FixupRecordTableOffset;
+
+ ///
+ /// Import Module Name Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint ImportedModulesNameTableOffset;
+
+ ///
+ /// The number of entries in the Import Module Name Table.
+ ///
+ public uint ImportedModulesCount;
+
+ ///
+ /// Import Procedure Name Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint ImportProcedureNameTableOffset;
+
+ ///
+ /// Per-page Checksum Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint PerPageChecksumTableOffset;
+
+ ///
+ /// Data Pages Offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the EXE file.
+ ///
+ public uint DataPagesOffset;
+
+ ///
+ /// Number of Preload pages for this module.
+ ///
+ ///
+ /// Note that OS/2 2.0 does not respect the preload of pages as specified
+ /// in the executable file for performance reasons.
+ ///
+ public uint PreloadPageCount;
+
+ ///
+ /// Non-Resident Name Table offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the EXE file.
+ ///
+ public uint NonResidentNamesTableOffset;
+
+ ///
+ /// Number of bytes in the Non-resident name table.
+ ///
+ public uint NonResidentNamesTableLength;
+
+ ///
+ /// Non-Resident Name Table Checksum.
+ ///
+ ///
+ /// This is a cryptographic checksum of the Non-Resident Name Table.
+ ///
+ public uint NonResidentNamesTableChecksum;
+
+ ///
+ /// The Auto Data Segment Object number.
+ ///
+ ///
+ /// This is the object number for the Auto Data Segment used by 16-bit modules.
+ /// This field is supported for 16-bit compatibility only and is not used by
+ /// 32-bit modules.
+ ///
+ public uint AutomaticDataObject;
+
+ ///
+ /// Debug Information offset.
+ ///
+ ///
+ /// This offset is relative to the beginning of the linear EXE header.
+ ///
+ public uint DebugInformationOffset;
+
+ ///
+ /// Debug Information length.
+ ///
+ ///
+ /// The length of the debug information in bytes.
+ ///
+ public uint DebugInformationLength;
+
+ ///
+ /// Instance pages in preload section.
+ ///
+ ///
+ /// The number of instance data pages found in the preload section.
+ ///
+ public uint PreloadInstancePagesNumber;
+
+ ///
+ /// Instance pages in demand section.
+ ///
+ ///
+ /// The number of instance data pages found in the demand section.
+ ///
+ public uint DemandInstancePagesNumber;
+
+ ///
+ /// Heap size added to the Auto DS Object.
+ ///
+ ///
+ /// The heap size is the number of bytes added to the Auto Data Segment
+ /// by the loader. This field is supported for 16-bit compatibility only and
+ /// is not used by 32-bit modules.
+ ///
+ public uint ExtraHeapAllocation;
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/ModuleFormatDirectivesTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/ModuleFormatDirectivesTableEntry.cs
new file mode 100644
index 00000000..c5770cfe
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/ModuleFormatDirectivesTableEntry.cs
@@ -0,0 +1,49 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The Module Format Directives Table is an optional table that allows additional
+ /// options to be specified. It also allows for the extension of the linear EXE
+ /// format by allowing additional tables of information to be added to the linear
+ /// EXE module without affecting the format of the linear EXE header. Likewise,
+ /// module format directives provide a place in the linear EXE module for
+ /// 'temporary tables' of information, such as incremental linking information
+ /// and statistic information gathered on the module. When there are no module
+ /// format directives for a linear EXE module, the fields in the linear EXE header
+ /// referencing the module format directives table are zero.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ModuleFormatDirectivesTableEntry
+ {
+ ///
+ /// Directive number.
+ ///
+ ///
+ /// The directive number specifies the type of directive defined. This can be
+ /// used to determine the format of the information in the directive data.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public DirectiveNumber DirectiveNumber;
+
+ ///
+ /// Directive data length.
+ ///
+ ///
+ /// This specifies the length in byte of the directive data for this directive number.
+ ///
+ public ushort DirectiveDataLength;
+
+ ///
+ /// Directive data offset.
+ ///
+ ///
+ /// This is the offset to the directive data for this directive number. It is relative
+ /// to beginning of linear EXE header for a resident table, and relative to the
+ /// beginning of the EXE file for non-resident tables.
+ ///
+ public uint DirectiveDataOffset;
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/NonResidentNamesTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/NonResidentNamesTableEntry.cs
new file mode 100644
index 00000000..87437363
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/NonResidentNamesTableEntry.cs
@@ -0,0 +1,64 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The resident and non-resident name tables define the ASCII names and ordinal
+ /// numbers for exported entries in the module. In addition the first entry in
+ /// the resident name table contains the module name. These tables are used to
+ /// translate a procedure name string into an ordinal number by searching for a
+ /// matching name string. The ordinal number is used to locate the entry point
+ /// information in the entry table.
+ ///
+ /// The resident name table is kept resident in system memory while the module is
+ /// loaded.It is intended to contain the exported entry point names that are
+ /// frequently dynamically linked to by name.Non-resident names are not kept in
+ /// memory and are read from the EXE file when a dynamic link reference is made.
+ /// Exported entry point names that are infrequently dynamically linked to by name
+ /// or are commonly referenced by ordinal number should be placed in the
+ /// non-resident name table.The trade off made for references by name is performance
+ /// vs memory usage.
+ ///
+ /// Import references by name require these tables to be searched to obtain the entry
+ /// point ordinal number.Import references by ordinal number provide the fastest
+ /// lookup since the search of these tables is not required.
+ ///
+ /// The strings are CASE SENSITIVE and are NOT NULL TERMINATED.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class NonResidentNamesTableEntry
+ {
+ ///
+ /// String Length.
+ ///
+ ///
+ /// This defines the length of the string in bytes. A zero length indicates there are
+ /// no more entries in table. The length of each ascii name string is limited to 127
+ /// characters.
+ ///
+ /// The high bit in the LEN field (bit 7) is defined as an Overload bit. This bit
+ /// signifies that additional information is contained in the linear EXE module and
+ /// will be used in the future for parameter type checking.
+ ///
+ public byte Length { get; set; }
+
+ ///
+ /// ASCII String.
+ ///
+ ///
+ /// This is a variable length string with it's length defined in bytes by the LEN field.
+ /// The string is case case sensitive and is not null terminated.
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// Ordinal number.
+ ///
+ ///
+ /// The ordinal number in an ordered index into the entry table for this entry point.
+ ///
+ public ushort OrdinalNumber { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/ObjectPageMapEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/ObjectPageMapEntry.cs
new file mode 100644
index 00000000..3e3076db
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/ObjectPageMapEntry.cs
@@ -0,0 +1,61 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The Object page table provides information about a logical page in an object.
+ /// A logical page may be an enumerated page, a pseudo page or an iterated page.
+ /// The structure of the object page table in conjunction with the structure of
+ /// the object table allows for efficient access of a page when a page fault occurs,
+ /// while still allowing the physical page data to be located in the preload page,
+ /// demand load page or iterated data page sections in the linear EXE module. The
+ /// logical page entries in the Object Page Table are numbered starting from one.
+ /// The Object Page Table is parallel to the Fixup Page Table as they are both
+ /// indexed by the logical page number.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ObjectPageMapEntry
+ {
+ ///
+ /// Offset to the page data in the EXE file.
+ ///
+ ///
+ /// This field, when bit shifted left by the PAGE OFFSET SHIFT from the module
+ /// header, specifies the offset from the beginning of the Preload Page section
+ /// of the physical page data in the EXE file that corresponds to this logical
+ /// page entry. The page data may reside in the Preload Pages, Demand Load Pages
+ /// or the Iterated Data Pages sections.
+ ///
+ /// If the FLAGS field specifies that this is a zero-Filled page then the PAGE
+ /// DATA OFFSET field will contain a 0.
+ ///
+ /// If the logical page is specified as an iterated data page, as indicated by
+ /// the FLAGS field, then this field specifies the offset into the Iterated Data
+ /// Pages section.
+ ///
+ /// The logical page number (Object Page Table index), is used to index the Fixup
+ /// Page Table to find any fixups associated with the logical page.
+ ///
+ public uint PageDataOffset;
+
+ ///
+ /// Number of bytes of data for this page.
+ ///
+ ///
+ /// This field specifies the actual number of bytes that represent the page in the
+ /// file. If the PAGE SIZE field from the module header is greater than the value
+ /// of this field and the FLAGS field indicates a Legal Physical Page, the remaining
+ /// bytes are to be filled with zeros. If the FLAGS field indicates an Iterated Data
+ /// Page, the iterated data records will completely fill out the remainder.
+ ///
+ public ushort DataSize;
+
+ ///
+ /// Attributes specifying characteristics of this logical page.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public ObjectPageFlags Flags;
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/ObjectTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/ObjectTableEntry.cs
new file mode 100644
index 00000000..74226357
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/ObjectTableEntry.cs
@@ -0,0 +1,83 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The object table contains information that describes each segment in
+ /// an executable file. This information includes segment length, segment
+ /// type, and segment-relocation data. The following list summarizes the
+ /// values found in in the segment table (the locations are relative to
+ /// the beginning of each entry):
+ ///
+ ///
+ /// Entries in the Object Table are numbered starting from one.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ObjectTableEntry
+ {
+ ///
+ /// Virtual memory size.
+ ///
+ ///
+ /// This is the size of the object that will be allocated when the object
+ /// is loaded. The object's virtual size (rounded up to the page size value)
+ /// must be greater than or equal to the total size of the pages in the EXE
+ /// file for the object. This memory size must also be large enough to
+ /// contain all of the iterated data and uninitialized data in the EXE file.
+ ///
+ public uint VirtualSegmentSize;
+
+ ///
+ /// Relocation Base Address.
+ ///
+ ///
+ /// The relocation base address the object is currently relocated to. If the
+ /// internal relocation fixups for the module have been removed, this is the
+ /// address the object will be allocated at by the loader.
+ ///
+ public uint RelocationBaseAddress;
+
+ ///
+ /// Flag bits for the object.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public ObjectFlags ObjectFlags;
+
+ ///
+ /// Object Page Table Index.
+ ///
+ ///
+ /// This specifies the number of the first object page table entry for this object.
+ /// The object page table specifies where in the EXE file a page can be found for
+ /// a given object and specifies per-page attributes.
+ ///
+ /// The object table entries are ordered by logical page in the object table. In
+ /// other words the object table entries are sorted based on the object page table
+ /// index value.
+ ///
+ public uint PageTableIndex;
+
+ ///
+ /// # of object page table entries for this object.
+ ///
+ ///
+ /// Any logical pages at the end of an object that do not have an entry in the object
+ /// page table associated with them are handled as zero filled or invalid pages by
+ /// the loader.
+ ///
+ /// When the last logical pages of an object are not specified with an object page
+ /// table entry, they are treated as either zero filled pages or invalid pages based
+ /// on the last entry in the object page table for that object. If the last entry
+ /// was neither a zero filled or invalid page, then the additional pages are treated
+ /// as zero filled pages.
+ ///
+ public uint PageTableEntries;
+
+ ///
+ /// Reserved for future use. Must be set to zero.
+ ///
+ public uint Reserved;
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/PerPageChecksumTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/PerPageChecksumTableEntry.cs
new file mode 100644
index 00000000..89fac5fe
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/PerPageChecksumTableEntry.cs
@@ -0,0 +1,24 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The Per-Page Checksum table provides space for a cryptographic checksum for
+ /// each physical page in the EXE file.
+ ///
+ /// The checksum table is arranged such that the first entry in the table corresponds
+ /// to the first logical page of code/data in the EXE file (usually a preload page)
+ /// and the last entry corresponds to the last logical page in the EXE file (usually
+ /// a iterated data page).
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class PerPageChecksumTableEntry
+ {
+ ///
+ /// Cryptographic checksum.
+ ///
+ public uint Checksum;
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/ResidentNamesTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/ResidentNamesTableEntry.cs
new file mode 100644
index 00000000..955796b1
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/ResidentNamesTableEntry.cs
@@ -0,0 +1,61 @@
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The resident and non-resident name tables define the ASCII names and ordinal
+ /// numbers for exported entries in the module. In addition the first entry in
+ /// the resident name table contains the module name. These tables are used to
+ /// translate a procedure name string into an ordinal number by searching for a
+ /// matching name string. The ordinal number is used to locate the entry point
+ /// information in the entry table.
+ ///
+ /// The resident name table is kept resident in system memory while the module is
+ /// loaded. It is intended to contain the exported entry point names that are
+ /// frequently dynamically linked to by name. Non-resident names are not kept in
+ /// memory and are read from the EXE file when a dynamic link reference is made.
+ /// Exported entry point names that are infrequently dynamically linked to by name
+ /// or are commonly referenced by ordinal number should be placed in the
+ /// non-resident name table. The trade off made for references by name is performance
+ /// vs memory usage.
+ ///
+ /// Import references by name require these tables to be searched to obtain the entry
+ /// point ordinal number.Import references by ordinal number provide the fastest
+ /// lookup since the search of these tables is not required.
+ ///
+ /// The strings are CASE SENSITIVE and are NOT NULL TERMINATED.
+ ///
+ ///
+ ///
+ public sealed class ResidentNamesTableEntry
+ {
+ ///
+ /// String Length.
+ ///
+ ///
+ /// This defines the length of the string in bytes. A zero length indicates there are
+ /// no more entries in table. The length of each ascii name string is limited to 127
+ /// characters.
+ ///
+ /// The high bit in the LEN field (bit 7) is defined as an Overload bit. This bit
+ /// signifies that additional information is contained in the linear EXE module and
+ /// will be used in the future for parameter type checking.
+ ///
+ public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
+
+ ///
+ /// ASCII String.
+ ///
+ ///
+ /// This is a variable length string with it's length defined in bytes by the LEN field.
+ /// The string is case case sensitive and is not null terminated.
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// Ordinal number.
+ ///
+ ///
+ /// The ordinal number in an ordered index into the entry table for this entry point.
+ ///
+ public ushort OrdinalNumber { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/ResourceTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/ResourceTableEntry.cs
new file mode 100644
index 00000000..714a8a14
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/ResourceTableEntry.cs
@@ -0,0 +1,47 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The resource table is an array of resource table entries. Each resource table
+ /// entry contains a type ID and name ID. These entries are used to locate resource
+ /// objects contained in the Object table. The number of entries in the resource
+ /// table is defined by the Resource Table Count located in the linear EXE header.
+ /// More than one resource may be contained within a single object. Resource table
+ /// entries are in a sorted order, (ascending, by Resource Name ID within the
+ /// Resource Type ID). This allows the DosGetResource API function to use a binary
+ /// search when looking up a resource in a 32-bit module instead of the linear search
+ /// being used in the current 16-bit module.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ResourceTableEntry
+ {
+ ///
+ /// Resource type ID.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public ResourceTableEntryType TypeID;
+
+ ///
+ /// An ID used as a name for the resource when referred to.
+ ///
+ public ushort NameID;
+
+ ///
+ /// The number of bytes the resource consists of.
+ ///
+ public uint ResourceSize;
+
+ ///
+ /// The number of the object which contains the resource.
+ ///
+ public ushort ObjectNumber;
+
+ ///
+ /// The offset within the specified object where the resource begins.
+ ///
+ public uint Offset;
+ }
+}
diff --git a/SabreTools.Serialization/Models/LinearExecutable/VerifyRecordDirectiveTableEntry.cs b/SabreTools.Serialization/Models/LinearExecutable/VerifyRecordDirectiveTableEntry.cs
new file mode 100644
index 00000000..7546c128
--- /dev/null
+++ b/SabreTools.Serialization/Models/LinearExecutable/VerifyRecordDirectiveTableEntry.cs
@@ -0,0 +1,85 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.LinearExecutable
+{
+ ///
+ /// The Verify Record Directive Table is an optional table. It maintains a record
+ /// of the pages in the EXE file that have been fixed up and written back to the
+ /// original linear EXE module, along with the module dependencies used to perform
+ /// these fixups. This table provides an efficient means for verifying the virtual
+ /// addresses required for the fixed up pages when the module is loaded.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class VerifyRecordDirectiveTableEntry
+ {
+ ///
+ /// Number of module dependencies.
+ ///
+ ///
+ /// This field specifies how many entries there are in the verify record
+ /// directive table. This is equal to the number of modules referenced by
+ /// this module.
+ ///
+ public ushort EntryCount;
+
+ ///
+ /// Ordinal index into the Import Module Name Table.
+ ///
+ ///
+ /// This value is an ordered index in to the Import Module Name Table for
+ /// the referenced module.
+ ///
+ public ushort OrdinalIndex;
+
+ ///
+ /// Module Version.
+ ///
+ ///
+ /// This is the version of the referenced module that the fixups were
+ /// originally performed.This is used to insure the same version of the
+ /// referenced module is loaded that was fixed up in this module and
+ /// therefore the fixups are still correct. This requires the version
+ /// number in a module to be incremented anytime the entry point offsets
+ /// change.
+ ///
+ public ushort Version;
+
+ ///
+ /// Module # of Object Entries.
+ ///
+ ///
+ /// This field is used to identify the number of object verify entries
+ /// that follow for the referenced module.
+ ///
+ public ushort ObjectEntriesCount;
+
+ ///
+ /// Object # in Module.
+ ///
+ ///
+ /// This field specifies the object number in the referenced module that
+ /// is being verified.
+ ///
+ public ushort ObjectNumberInModule;
+
+ ///
+ /// Object load base address.
+ ///
+ ///
+ /// This is the address that the object was loaded at when the fixups were
+ /// performed.
+ ///
+ public ushort ObjectLoadBaseAddress;
+
+ ///
+ /// Object virtual address size.
+ ///
+ ///
+ /// This field specifies the total amount of virtual memory required for
+ /// this object.
+ ///
+ public ushort ObjectVirtualAddressSize;
+ }
+}
diff --git a/SabreTools.Serialization/Models/MSDOS/Constants.cs b/SabreTools.Serialization/Models/MSDOS/Constants.cs
new file mode 100644
index 00000000..c20d9d54
--- /dev/null
+++ b/SabreTools.Serialization/Models/MSDOS/Constants.cs
@@ -0,0 +1,11 @@
+namespace SabreTools.Serialization.Models.MSDOS
+{
+ public static class Constants
+ {
+ public static readonly byte[] SignatureBytes = [0x4d, 0x5a];
+
+ public const string SignatureString = "MZ";
+
+ public const ushort SignatureUInt16 = 0x5a4d;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/MSDOS/Executable.cs b/SabreTools.Serialization/Models/MSDOS/Executable.cs
new file mode 100644
index 00000000..3a2bd3dc
--- /dev/null
+++ b/SabreTools.Serialization/Models/MSDOS/Executable.cs
@@ -0,0 +1,29 @@
+namespace SabreTools.Serialization.Models.MSDOS
+{
+ ///
+ /// The MS-DOS EXE format, also known as MZ after its signature (the initials of Microsoft engineer Mark Zbykowski),
+ /// was introduced with MS-DOS 2.0 (version 1.0 only sported the simple COM format). It is designed as a relocatable
+ /// executable running under real mode. As such, only DOS and Windows 9x can use this format natively, but there are
+ /// several free DOS emulators (e.g., DOSBox) that support it and that run under various operating systems (e.g.,
+ /// Linux, Amiga, Windows NT, etc.). Although they can exist on their own, MZ executables are embedded in all NE, LE,
+ /// and PE executables, usually as stubs so that when they are ran under DOS, they display a warning.
+ ///
+ ///
+ public sealed class Executable
+ {
+ ///
+ /// MS-DOS executable header
+ ///
+ public ExecutableHeader? Header { get; set; }
+
+ ///
+ /// After loading the executable into memory, the program loader goes through
+ /// every entry in relocation table. For each relocation entry, the loader
+ /// adds the start segment address into word value pointed to by the
+ /// segment:offset pair. So, for example, a relocation entry 0001:001A will
+ /// make the loader add start segment address to the value at offset
+ /// 1*0x10+0x1A=0x2A within the program data.
+ ///
+ public RelocationEntry[]? RelocationTable { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/MSDOS/ExecutableHeader.cs b/SabreTools.Serialization/Models/MSDOS/ExecutableHeader.cs
new file mode 100644
index 00000000..3ff62962
--- /dev/null
+++ b/SabreTools.Serialization/Models/MSDOS/ExecutableHeader.cs
@@ -0,0 +1,133 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.MSDOS
+{
+ ///
+ /// MZ executables only consists of 2 structures: the header and the relocation table.
+ /// The header, which is followed by the program image, looks like this.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public sealed class ExecutableHeader
+ {
+ #region Standard Fields
+
+ ///
+ /// 0x5A4D (ASCII for 'M' and 'Z')
+ ///
+ /// 15 bytes
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
+ public string? Magic;
+
+ ///
+ /// Number of bytes in the last page.
+ ///
+ public ushort LastPageBytes;
+
+ ///
+ /// Number of whole/partial pages.
+ ///
+ /// A page (or block) is 512 bytes long.
+ public ushort Pages;
+
+ ///
+ /// Number of entries in the relocation table.
+ ///
+ public ushort RelocationItems;
+
+ ///
+ /// The number of paragraphs taken up by the header. It can be any value, as the loader
+ /// just uses it to find where the actual executable data starts. It may be larger than
+ /// what the "standard" fields take up, and you may use it if you want to include your
+ /// own header metadata, or put the relocation table there, or use it for any other purpose. [08]
+ ///
+ /// A paragraph is 16 bytes in size
+ public ushort HeaderParagraphSize;
+
+ ///
+ /// The number of paragraphs required by the program, excluding the PSP and program image.
+ /// If no free block is big enough, the loading stops.
+ ///
+ /// A paragraph is 16 bytes in size
+ public ushort MinimumExtraParagraphs;
+
+ ///
+ /// The number of paragraphs requested by the program.
+ /// If no free block is big enough, the biggest one possible is allocated.
+ ///
+ /// A paragraph is 16 bytes in size
+ public ushort MaximumExtraParagraphs;
+
+ ///
+ /// Relocatable segment address for SS.
+ ///
+ public ushort InitialSSValue;
+
+ ///
+ /// Initial value for SP.
+ ///
+ public ushort InitialSPValue;
+
+ ///
+ /// When added to the sum of all other words in the file, the result should be zero.
+ ///
+ public ushort Checksum;
+
+ ///
+ /// Initial value for IP. [14]
+ ///
+ public ushort InitialIPValue;
+
+ ///
+ /// Relocatable segment address for CS.
+ ///
+ public ushort InitialCSValue;
+
+ ///
+ /// The (absolute) offset to the relocation table.
+ ///
+ public ushort RelocationTableAddr;
+
+ ///
+ /// Value used for overlay management.
+ /// If zero, this is the main executable.
+ ///
+ public ushort OverlayNumber;
+
+ #endregion
+
+ #region PE Extensions
+
+ ///
+ /// Reserved words
+ ///
+ /// 4 entries/remarks>
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public ushort[]? Reserved1;
+
+ ///
+ /// Defined by name but no other information is given; typically zeroes
+ ///
+ public ushort OEMIdentifier;
+
+ ///
+ /// Defined by name but no other information is given; typically zeroes
+ ///
+ public ushort OEMInformation;
+
+ ///
+ /// Reserved words
+ ///
+ /// 10 entries/remarks>
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
+ public ushort[]? Reserved2;
+
+ ///
+ /// Starting address of the PE header
+ ///
+ public uint NewExeHeaderAddr;
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Serialization/Models/MSDOS/RelocationEntry.cs b/SabreTools.Serialization/Models/MSDOS/RelocationEntry.cs
new file mode 100644
index 00000000..82d9625e
--- /dev/null
+++ b/SabreTools.Serialization/Models/MSDOS/RelocationEntry.cs
@@ -0,0 +1,22 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.MSDOS
+{
+ ///
+ /// Each pointer in the relocation table looks as such
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class RelocationEntry
+ {
+ ///
+ /// Offset of the relocation within provided segment.
+ ///
+ public ushort Offset;
+
+ ///
+ /// Segment of the relocation, relative to the load segment address.
+ ///
+ public ushort Segment;
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/Constants.cs b/SabreTools.Serialization/Models/NewExecutable/Constants.cs
new file mode 100644
index 00000000..5684d231
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/Constants.cs
@@ -0,0 +1,11 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ public static class Constants
+ {
+ public static readonly byte[] SignatureBytes = [0x4e, 0x45];
+
+ public const string SignatureString = "NE";
+
+ public const ushort SignatureUInt16 = 0x454e;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/NewExecutable/EntryTableBundle.cs b/SabreTools.Serialization/Models/NewExecutable/EntryTableBundle.cs
new file mode 100644
index 00000000..c779d56c
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/EntryTableBundle.cs
@@ -0,0 +1,84 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The entry table follows the imported-name table. This table contains
+ /// bundles of entry-point definitions. Bundling is done to save space in
+ /// the entry table. The entry table is accessed by an ordinal value.
+ /// Ordinal number one is defined to index the first entry in the entry
+ /// table. To find an entry point, the bundles are scanned searching for a
+ /// specific entry point using an ordinal number. The ordinal number is
+ /// adjusted as each bundle is checked. When the bundle that contains the
+ /// entry point is found, the ordinal number is multiplied by the size of
+ /// the bundle's entries to index the proper entry.
+ ///
+ ///
+ /// The linker forms bundles in the most dense manner it can, under the
+ /// restriction that it cannot reorder entry points to improve bundling.
+ /// The reason for this restriction is that other .EXE files may refer to
+ /// entry points within this bundle by their ordinal number. The following
+ /// describes the format of the entry table bundles.
+ ///
+ ///
+ public sealed class EntryTableBundle
+ {
+ ///
+ /// Number of entries in this bundle. All records in one bundle
+ /// are either moveable or refer to the same fixed segment. A zero
+ /// value in this field indicates the end of the entry table.
+ ///
+ public byte EntryCount { get; set; }
+
+ ///
+ /// Segment indicator for this bundle. This defines the type of
+ /// entry table entry data within the bundle. There are three
+ /// types of entries that are defined.
+ /// - 000h = Unused entries. There is no entry data in an unused
+ /// bundle. The next bundle follows this field. This is
+ /// used by the linker to skip ordinal numbers.
+ /// - 001h-0FEh = Segment number for fixed segment entries. A fixed
+ /// segment entry is 3 bytes long.
+ /// - 0FFH = Moveable segment entries. The entry data contains the
+ /// segment number for the entry points. A moveable segment
+ /// entry is 6 bytes long.
+ ///
+ public byte SegmentIndicator { get; set; }
+
+ #region Fixed Segment Entry
+
+ ///
+ /// Flag word.
+ ///
+ public FixedSegmentEntryFlag FixedFlagWord { get; set; }
+
+ ///
+ /// Offset within segment to entry point.
+ ///
+ public ushort FixedOffset { get; set; }
+
+ #endregion
+
+ #region Moveable Segment Entry
+
+ ///
+ /// Flag word.
+ ///
+ public MoveableSegmentEntryFlag MoveableFlagWord { get; set; }
+
+ ///
+ /// INT 3FH.
+ ///
+ public ushort MoveableReserved { get; set; }
+
+ ///
+ /// Segment number.
+ ///
+ public byte MoveableSegmentNumber { get; set; }
+
+ ///
+ /// Offset within segment to entry point.
+ ///
+ public ushort MoveableOffset { get; set; }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/Enums.cs b/SabreTools.Serialization/Models/NewExecutable/Enums.cs
new file mode 100644
index 00000000..bfb2ec1d
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/Enums.cs
@@ -0,0 +1,325 @@
+using System;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ [Flags]
+ public enum FixedSegmentEntryFlag : byte
+ {
+ ///
+ /// Set if the entry is exported.
+ ///
+ Exported = 0x01,
+
+ ///
+ /// Set if the entry uses a global (shared) data segments.
+ ///
+ ///
+ /// The first assembly-language instruction in the
+ /// entry point prologue must be "MOV AX,data
+ /// segment number". This may be set only for
+ /// SINGLEDATA library modules.
+ ///
+ Global = 0x02,
+ }
+
+ [Flags]
+ public enum HeaderFlag : ushort
+ {
+ #region Program Flags
+
+ NOAUTODATA = 0x0000,
+
+ ///
+ /// Shared automatic data segment
+ ///
+ SINGLEDATA = 0x0001,
+
+ ///
+ /// Instanced automatic data segment
+ ///
+ MULTIPLEDATA = 0x0002,
+
+ ///
+ /// Global initialization
+ ///
+ GlobalInitialization = 0x0004,
+
+ ///
+ /// Protected mode only
+ ///
+ ProtectedModeOnly = 0x0008,
+
+ ///
+ /// 8086 instructions
+ ///
+ Instructions8086 = 0x0010,
+
+ ///
+ /// 80286 instructions
+ ///
+ Instructions80286 = 0x0020,
+
+ ///
+ /// 80386 instructions
+ ///
+ Instructions80386 = 0x0040,
+
+ ///
+ /// 80x87 instructions
+ ///
+ Instructions80x87 = 0x0080,
+
+ #endregion
+
+ #region Application Flags
+
+ ///
+ /// Full screen (not aware of Windows/P.M. API)
+ ///
+ FullScreen = 0x0100,
+
+ ///
+ /// Compatible with Windows/P.M. API
+ ///
+ WindowsPMCompatible = 0x0200,
+
+ ///
+ /// Uses Windows/P.M. API
+ ///
+ WindowsPM = 0x0400,
+
+ ///
+ /// OS/2 family application
+ ///
+ OS2FamilyApplication = 0x0800,
+
+ ///
+ /// Unknown (Reserved?)
+ ///
+ UnknownReserved = 0x1000,
+
+ ///
+ /// Errors detected at link time, module will not load
+ ///
+ ErrorsDetectedAtLinkTime = 0x2000,
+
+ ///
+ /// Unknown (non-conforming program)
+ ///
+ UnknownNonConforming = 0x4000,
+
+ ///
+ /// Library module.
+ /// The SS:SP information is invalid, CS:IP points
+ /// to an initialization procedure that is called
+ /// with AX equal to the module handle. This
+ /// initialization procedure must perform a far
+ /// return to the caller, with AX not equal to
+ /// zero to indicate success, or AX equal to zero
+ /// to indicate failure to initialize. DS is set
+ /// to the library's data segment if the
+ /// SINGLEDATA flag is set. Otherwise, DS is set
+ /// to the caller's data segment.
+ ///
+ ///
+ /// A program or DLL can only contain dynamic
+ /// links to executable files that have this
+ /// library module flag set. One program cannot
+ /// dynamic-link to another program.
+ ///
+ LibraryModule = 0x8000,
+
+ #endregion
+ }
+
+ [Flags]
+ public enum MoveableSegmentEntryFlag : byte
+ {
+ ///
+ /// Set if the entry is exported.
+ ///
+ Exported = 0x01,
+
+ ///
+ /// Set if the entry uses a global (shared) data segments.
+ ///
+ Global = 0x02,
+ }
+
+ public enum OperatingSystem : byte
+ {
+ Unknown = 0x00,
+ OS2 = 0x01,
+ WINDOWS = 0x02,
+ EU_MSDOS4 = 0x03,
+ WINDOWS_386 = 0x04,
+ BOSS = 0x05,
+ }
+
+ [Flags]
+ public enum OS2Flag : byte
+ {
+ ///
+ /// Long filename support
+ ///
+ LongFilenameSupport = 0x01,
+
+ ///
+ /// 2.x protected mode
+ ///
+ ProtectedMode = 0x02,
+
+ ///
+ /// 2.x proportional fonts
+ ///
+ ProportionalFonts = 0x04,
+
+ ///
+ /// Executable has gangload area
+ ///
+ HasGangload = 0x08,
+
+ ///
+ /// Unknown
+ ///
+ Unknown = 0xF0,
+ }
+
+ public enum OSFixupType : ushort
+ {
+ ///
+ /// FIARQQ, FJARQQ
+ ///
+ FIARQQ = 0x0001,
+
+ ///
+ /// FISRQQ, FJSRQQ
+ ///
+ FISRQQ = 0x0002,
+
+ ///
+ /// FICRQQ, FJCRQQ
+ ///
+ FICRQQ = 0x0003,
+
+ FIERQQ = 0x0004,
+
+ FIDRQQ = 0x0005,
+
+ FIWRQQ = 0x0006,
+ }
+
+ [Flags]
+ public enum RelocationRecordFlag : byte
+ {
+ TARGET_MASK = 0x03,
+
+ INTERNALREF = 0x00,
+
+ IMPORTORDINAL = 0x01,
+
+ IMPORTNAME = 0x02,
+
+ OSFIXUP = 0x03,
+
+ ADDITIVE = 0x04,
+ }
+
+ public enum RelocationRecordSourceType : byte
+ {
+ SOURCE_MASK = 0x0F,
+
+ LOBYTE = 0x00,
+
+ SEGMENT = 0x02,
+
+ ///
+ /// 32-bit pointer
+ ///
+ FAR_ADDR = 0x03,
+
+ ///
+ /// 16-bit offset
+ ///
+ OFFSET = 0x05,
+ }
+
+ [Flags]
+ public enum ResourceTypeResourceFlag : ushort
+ {
+ ///
+ /// Resource is not fixed.
+ ///
+ MOVEABLE = 0x0010,
+
+ ///
+ /// Resource can be shared.
+ ///
+ PURE = 0x0020,
+
+ ///
+ /// Resource is preloaded.
+ ///
+ PRELOAD = 0x0040,
+ }
+
+ public enum SegmentEntryType
+ {
+ ///
+ /// 000h - There is no entry data in an unused bundle. The next bundle
+ /// follows this field. This is used by the linker to skip ordinal numbers.
+ ///
+ Unused,
+
+ ///
+ /// 001h-0FEh - Segment number for fixed segment entries. A fixed segment
+ /// entry is 3 bytes long.
+ ///
+ FixedSegment,
+
+ ///
+ /// 0FFH - Moveable segment entries. The entry data contains the segment
+ /// number for the entry points. A moveable segment entry is 6 bytes long.
+ ///
+ MoveableSegment,
+ }
+
+ [Flags]
+ public enum SegmentTableEntryFlag : ushort
+ {
+ ///
+ /// Segment-type field.
+ ///
+ TYPE_MASK = 0x0007,
+
+ ///
+ /// Code-segment type.
+ ///
+ CODE = 0x0000,
+
+ ///
+ /// Data-segment type.
+ ///
+ DATA = 0x0001,
+
+ ///
+ /// Segment is not fixed.
+ ///
+ MOVEABLE = 0x0010,
+
+ ///
+ /// Segment will be preloaded; read-only if this is a data segment.
+ ///
+ PRELOAD = 0x0040,
+
+ ///
+ /// Set if segment has relocation records.
+ ///
+ RELOCINFO = 0x0100,
+
+ ///
+ /// Discard priority.
+ ///
+ DISCARD = 0xF000,
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/Executable.cs b/SabreTools.Serialization/Models/NewExecutable/Executable.cs
new file mode 100644
index 00000000..4ae94ee1
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/Executable.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The segmented EXE header contains general information about the EXE
+ /// file and contains information on the location and size of the other
+ /// sections. The Windows loader copies this section, along with other
+ /// data, into the module table in the system data. The module table is
+ /// internal data used by the loader to manage the loaded executable
+ /// modules in the system and to support dynamic linking.
+ ///
+ ///
+ ///
+ public sealed class Executable
+ {
+ ///
+ /// MS-DOS executable stub
+ ///
+ public MSDOS.Executable? Stub { get; set; }
+
+ ///
+ /// New Executable header
+ ///
+ public ExecutableHeader? Header { get; set; }
+
+ ///
+ /// Segment table
+ ///
+ public SegmentTableEntry[]? SegmentTable { get; set; }
+
+ ///
+ /// Resource table
+ ///
+ public ResourceTable? ResourceTable { get; set; }
+
+ ///
+ /// Resident-Name table
+ ///
+ public ResidentNameTableEntry[]? ResidentNameTable { get; set; }
+
+ ///
+ /// Module-Reference table
+ ///
+ public ModuleReferenceTableEntry[]? ModuleReferenceTable { get; set; }
+
+ ///
+ /// Imported-Name table
+ ///
+ public Dictionary? ImportedNameTable { get; set; }
+
+ ///
+ /// Entry table
+ ///
+ public EntryTableBundle[]? EntryTable { get; set; }
+
+ ///
+ /// Nonresident-Name table
+ ///
+ public NonResidentNameTableEntry[]? NonResidentNameTable { get; set; }
+
+ ///
+ /// Segment relocation data
+ ///
+ public PerSegmentData[]? SegmentRelocationData { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ExecutableHeader.cs b/SabreTools.Serialization/Models/NewExecutable/ExecutableHeader.cs
new file mode 100644
index 00000000..fecca6c1
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ExecutableHeader.cs
@@ -0,0 +1,209 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The NE header is a relatively large structure with multiple characteristics.
+ /// Because of the age of the format some items are unclear in meaning.
+ ///
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public sealed class ExecutableHeader
+ {
+ ///
+ /// "NE"
+ ///
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
+ public string? Magic;
+
+ ///
+ /// Version number of the linker.
+ ///
+ /// Also known as the major linker version
+ public byte LinkerVersion;
+
+ ///
+ /// Revision number of the linker.
+ ///
+ /// Also known as the minor linker version
+ public byte LinkerRevision;
+
+ ///
+ /// Entry Table file offset, relative to the beginning of the segmented EXE header.
+ ///
+ public ushort EntryTableOffset;
+
+ ///
+ /// Length of entry table in bytes
+ ///
+ public ushort EntryTableSize;
+
+ ///
+ /// 32-bit CRC of entire contents of file.
+ ///
+ /// These words are taken as 00 during the calculation.
+ public uint CrcChecksum;
+
+ ///
+ /// Flag word
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public HeaderFlag FlagWord;
+
+ ///
+ /// Segment number of automatic data segment.
+ /// This value is set to zero if SINGLEDATA and
+ /// MULTIPLEDATA flag bits are clear, NOAUTODATA is
+ /// indicated in the flags word.
+ ///
+ ///
+ /// A Segment number is an index into the module's segment
+ /// table. The first entry in the segment table is segment
+ /// number 1.
+ ///
+ public ushort AutomaticDataSegmentNumber;
+
+ ///
+ /// Initial size, in bytes, of dynamic heap added to the
+ /// data segment. This value is zero if no initial local
+ /// heap is allocated.
+ ///
+ public ushort InitialHeapAlloc;
+
+ ///
+ /// Initial size, in bytes, of stack added to the data
+ /// segment. This value is zero to indicate no initial
+ /// stack allocation, or when SS is not equal to DS.
+ ///
+ public ushort InitialStackAlloc;
+
+ ///
+ /// Segment number:offset of CS:IP.
+ ///
+ /// CS:IP entry point, CS is index into segment table
+ public uint InitialCSIPSetting;
+
+ ///
+ /// Segment number:offset of SS:SP.
+ ///
+ ///
+ /// SS:SP initial stack pointer, SS is index into segment table
+ ///
+ /// If SS equals the automatic data segment and SP equals
+ /// zero, the stack pointer is set to the top of the
+ /// automatic data segment just below the additional heap
+ /// area.
+ ///
+ public uint InitialSSSPSetting;
+
+ ///
+ /// Number of entries in the Segment Table.
+ ///
+ public ushort FileSegmentCount;
+
+ ///
+ /// Number of entries in the Module Reference Table.
+ ///
+ public ushort ModuleReferenceTableSize;
+
+ ///
+ /// Size of non-resident names table in bytes
+ ///
+ public ushort NonResidentNameTableSize;
+
+ ///
+ /// Segment Table file offset, relative to the beginning
+ /// of the segmented EXE header.
+ ///
+ public ushort SegmentTableOffset;
+
+ ///
+ /// Resource Table file offset, relative to the beginning
+ /// of the segmented EXE header.
+ ///
+ public ushort ResourceTableOffset;
+
+ ///
+ /// Resident Name Table file offset, relative to the
+ /// beginning of the segmented EXE header.
+ ///
+ public ushort ResidentNameTableOffset;
+
+ ///
+ /// Module Reference Table file offset, relative to the
+ /// beginning of the segmented EXE header.
+ ///
+ public ushort ModuleReferenceTableOffset;
+
+ ///
+ /// Imported Names Table file offset, relative to the
+ /// beginning of the segmented EXE header.
+ ///
+ public ushort ImportedNamesTableOffset;
+
+ ///
+ /// Non-Resident Name Table offset, relative to the
+ /// beginning of the file.
+ ///
+ public uint NonResidentNamesTableOffset;
+
+ ///
+ /// Number of movable entries in the Entry Table.
+ ///
+ public ushort MovableEntriesCount;
+
+ ///
+ /// Logical sector alignment shift count, log(base 2) of
+ /// the segment sector size (default 9).
+ ///
+ public ushort SegmentAlignmentShiftCount;
+
+ ///
+ /// Number of resource entries.
+ ///
+ public ushort ResourceEntriesCount;
+
+ ///
+ /// Executable type, used by loader.
+ ///
+ [MarshalAs(UnmanagedType.U1)]
+ public OperatingSystem TargetOperatingSystem;
+
+ #region OS/2 Specific
+
+ ///
+ /// Other OS/2 flags
+ ///
+ [MarshalAs(UnmanagedType.U1)]
+ public OS2Flag AdditionalFlags;
+
+ ///
+ /// Offset to return thunks or start of gangload area
+ ///
+ public ushort ReturnThunkOffset;
+
+ ///
+ /// Offset to segment reference thunks or size of gangload area
+ ///
+ public ushort SegmentReferenceThunkOffset;
+
+ ///
+ /// Minimum code swap area size
+ ///
+ public ushort MinCodeSwapAreaSize;
+
+ ///
+ /// Windows SDK revison number
+ ///
+ public byte WindowsSDKRevision;
+
+ ///
+ /// Windows SDK version number
+ ///
+ public byte WindowsSDKVersion;
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ImportNameRelocationRecord.cs b/SabreTools.Serialization/Models/NewExecutable/ImportNameRelocationRecord.cs
new file mode 100644
index 00000000..8b915bef
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ImportNameRelocationRecord.cs
@@ -0,0 +1,19 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ImportNameRelocationRecord
+ {
+ ///
+ /// Index into module reference table for the imported module.
+ ///
+ public ushort Index;
+
+ ///
+ /// Offset within Imported Names Table to procedure name string.
+ ///
+ public ushort Offset;
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ImportOrdinalRelocationRecord.cs b/SabreTools.Serialization/Models/NewExecutable/ImportOrdinalRelocationRecord.cs
new file mode 100644
index 00000000..03054078
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ImportOrdinalRelocationRecord.cs
@@ -0,0 +1,19 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ImportOrdinalRelocationRecord
+ {
+ ///
+ /// Index into module reference table for the imported module.
+ ///
+ public ushort Index;
+
+ ///
+ /// Procedure ordinal number.
+ ///
+ public ushort Ordinal;
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ImportedNameTableEntry.cs b/SabreTools.Serialization/Models/NewExecutable/ImportedNameTableEntry.cs
new file mode 100644
index 00000000..22d0d18c
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ImportedNameTableEntry.cs
@@ -0,0 +1,25 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The imported-name table follows the module-reference table. This table
+ /// contains the names of modules and procedures that are imported by the
+ /// executable file. Each entry is composed of a 1-byte field that
+ /// contains the length of the string, followed by any number of
+ /// characters. The strings are not null-terminated and are case
+ /// sensitive.
+ ///
+ ///
+ public sealed class ImportedNameTableEntry
+ {
+ ///
+ /// Length of the name string that follows. A zero value indicates
+ /// the end of the name table.
+ ///
+ public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
+
+ ///
+ /// ASCII text of the name string.
+ ///
+ public byte[]? NameString { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/InternalRefRelocationRecord.cs b/SabreTools.Serialization/Models/NewExecutable/InternalRefRelocationRecord.cs
new file mode 100644
index 00000000..33501eae
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/InternalRefRelocationRecord.cs
@@ -0,0 +1,26 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class InternalRefRelocationRecord
+ {
+ ///
+ /// Segment number for a fixed segment, or 0FFh for a
+ /// movable segment.
+ ///
+ public byte SegmentNumber;
+
+ ///
+ /// Always 0
+ ///
+ public byte Reserved;
+
+ ///
+ /// Offset into segment if fixed segment, or ordinal
+ /// number index into Entry Table if movable segment.
+ ///
+ public ushort Offset;
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ModuleReferenceTableEntry.cs b/SabreTools.Serialization/Models/NewExecutable/ModuleReferenceTableEntry.cs
new file mode 100644
index 00000000..be15e73d
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ModuleReferenceTableEntry.cs
@@ -0,0 +1,19 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The module-reference table follows the resident-name table. Each entry
+ /// contains an offset for the module-name string within the imported-
+ /// names table; each entry is 2 bytes long.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ModuleReferenceTableEntry
+ {
+ ///
+ /// Offset within Imported Names Table to referenced module name string.
+ ///
+ public ushort Offset;
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/NonResidentNameTableEntry.cs b/SabreTools.Serialization/Models/NewExecutable/NonResidentNameTableEntry.cs
new file mode 100644
index 00000000..89ffd4e6
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/NonResidentNameTableEntry.cs
@@ -0,0 +1,31 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The nonresident-name table follows the entry table, and contains a
+ /// module description and nonresident exported procedure name strings.
+ /// The first string in this table is a module description. These name
+ /// strings are case-sensitive and are not null-terminated. The name
+ /// strings follow the same format as those defined in the resident name
+ /// table.
+ ///
+ ///
+ public sealed class NonResidentNameTableEntry
+ {
+ ///
+ /// Length of the name string that follows. A zero value indicates
+ /// the end of the name table.
+ ///
+ public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
+
+ ///
+ /// ASCII text of the name string.
+ ///
+ public byte[]? NameString { get; set; }
+
+ ///
+ /// Ordinal number (index into entry table). This value is ignored
+ /// for the module name.
+ ///
+ public ushort OrdinalNumber { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/OSFixupRelocationRecord.cs b/SabreTools.Serialization/Models/NewExecutable/OSFixupRelocationRecord.cs
new file mode 100644
index 00000000..e0105cf6
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/OSFixupRelocationRecord.cs
@@ -0,0 +1,21 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class OSFixupRelocationRecord
+ {
+ ///
+ /// Operating system fixup type.
+ /// Floating-point fixups.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public OSFixupType FixupType;
+
+ ///
+ /// 0
+ ///
+ public ushort Reserved;
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/PerSegmentData.cs b/SabreTools.Serialization/Models/NewExecutable/PerSegmentData.cs
new file mode 100644
index 00000000..1ab42db8
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/PerSegmentData.cs
@@ -0,0 +1,30 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The location and size of the per-segment data is defined in the
+ /// segment table entry for the segment. If the segment has relocation
+ /// fixups, as defined in the segment table entry flags, they directly
+ /// follow the segment data in the file. The relocation fixup information
+ /// is defined as follows:
+ ///
+ ///
+ /// To find the relocation data for a segment, seek to:
+ ///
+ /// * (1 << )
+ /// +
+ ///
+ ///
+ ///
+ public sealed class PerSegmentData
+ {
+ ///
+ /// Number of relocation records that follow.
+ ///
+ public ushort RelocationRecordCount { get; set; }
+
+ ///
+ /// A table of relocation records follows.
+ ///
+ public RelocationRecord[]? RelocationRecords { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/RelocationRecord.cs b/SabreTools.Serialization/Models/NewExecutable/RelocationRecord.cs
new file mode 100644
index 00000000..1f0c6eb3
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/RelocationRecord.cs
@@ -0,0 +1,57 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// A table of relocation records follows. The following is the format
+ /// of each relocation record.
+ ///
+ ///
+ public sealed class RelocationRecord
+ {
+ ///
+ /// Source type.
+ ///
+ public RelocationRecordSourceType SourceType { get; set; }
+
+ ///
+ /// Flags byte.
+ ///
+ /// The target value has four types that are defined in the flag
+ /// byte field.
+ ///
+ public RelocationRecordFlag Flags { get; set; }
+
+ ///
+ /// Offset within this segment of the source chain.
+ /// If the ADDITIVE flag is set, then target value is added to
+ /// the source contents, instead of replacing the source and
+ /// following the chain. The source chain is an 0FFFFh
+ /// terminated linked list within this segment of all
+ /// references to the target.
+ ///
+ public ushort Offset { get; set; }
+
+ ///
+ /// INTERNALREF
+ ///
+ /// Must be null if is not set to
+ public InternalRefRelocationRecord? InternalRefRelocationRecord { get; set; }
+
+ ///
+ /// IMPORTNAME
+ ///
+ /// Must be null if is not set to
+ public ImportNameRelocationRecord? ImportNameRelocationRecord { get; set; }
+
+ ///
+ /// IMPORTORDINAL
+ ///
+ /// Must be null if is not set to
+ public ImportOrdinalRelocationRecord? ImportOrdinalRelocationRecord { get; set; }
+
+ ///
+ /// IMPORTORDINAL
+ ///
+ /// Must be null if is not set to
+ public OSFixupRelocationRecord? OSFixupRelocationRecord { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ResidentNameTableEntry.cs b/SabreTools.Serialization/Models/NewExecutable/ResidentNameTableEntry.cs
new file mode 100644
index 00000000..7ba15dc6
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ResidentNameTableEntry.cs
@@ -0,0 +1,30 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The resident-name table follows the resource table, and contains this
+ /// module's name string and resident exported procedure name strings. The
+ /// first string in this table is this module's name. These name strings
+ /// are case-sensitive and are not null-terminated. The following
+ /// describes the format of the name strings:
+ ///
+ ///
+ public sealed class ResidentNameTableEntry
+ {
+ ///
+ /// Length of the name string that follows. A zero value indicates
+ /// the end of the name table.
+ ///
+ public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
+
+ ///
+ /// ASCII text of the name string.
+ ///
+ public byte[]? NameString { get; set; }
+
+ ///
+ /// Ordinal number (index into entry table). This value is ignored
+ /// for the module name.
+ ///
+ public ushort OrdinalNumber { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ResourceTable.cs b/SabreTools.Serialization/Models/NewExecutable/ResourceTable.cs
new file mode 100644
index 00000000..c41f18a2
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ResourceTable.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The resource table follows the segment table and contains entries for
+ /// each resource in the executable file. The resource table consists of
+ /// an alignment shift count, followed by a table of resource records. The
+ /// resource records define the type ID for a set of resources. Each
+ /// resource record contains a table of resource entries of the defined
+ /// type. The resource entry defines the resource ID or name ID for the
+ /// resource. It also defines the location and size of the resource. The
+ /// following describes the contents of each of these structures:
+ ///
+ ///
+ public sealed class ResourceTable
+ {
+ ///
+ /// Alignment shift count for resource data.
+ ///
+ public ushort AlignmentShiftCount { get; set; }
+
+ ///
+ /// A table of resource type information blocks follows.
+ ///
+ public ResourceTypeInformationEntry[]? ResourceTypes { get; set; }
+
+ ///
+ /// Resource type and name strings are stored at the end of the
+ /// resource table.
+ ///
+ public Dictionary? TypeAndNameStrings { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ResourceTypeAndNameString.cs b/SabreTools.Serialization/Models/NewExecutable/ResourceTypeAndNameString.cs
new file mode 100644
index 00000000..c321076a
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ResourceTypeAndNameString.cs
@@ -0,0 +1,23 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// Resource type and name strings are stored at the end of the
+ /// resource table. Note that these strings are NOT null terminated and
+ /// are case sensitive.
+ ///
+ ///
+ public sealed class ResourceTypeAndNameString
+ {
+ ///
+ /// Length of the type or name string that follows. A zero value
+ /// indicates the end of the resource type and name string, also
+ /// the end of the resource table.
+ ///
+ public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
+
+ ///
+ /// ASCII text of the type or name string.
+ ///
+ public byte[]? Text { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ResourceTypeInformationEntry.cs b/SabreTools.Serialization/Models/NewExecutable/ResourceTypeInformationEntry.cs
new file mode 100644
index 00000000..b6f7efa7
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ResourceTypeInformationEntry.cs
@@ -0,0 +1,34 @@
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// A table of resource type information blocks follows. The following
+ /// is the format of each type information block:
+ ///
+ ///
+ public sealed class ResourceTypeInformationEntry
+ {
+ ///
+ /// Type ID. This is an integer type if the high-order bit is
+ /// set (8000h); otherwise, it is an offset to the type string,
+ /// the offset is relative to the beginning of the resource
+ /// table. A zero type ID marks the end of the resource type
+ /// information blocks.
+ ///
+ public ushort TypeID { get; set; }
+
+ ///
+ /// Number of resources for this type.
+ ///
+ public ushort ResourceCount { get; set; }
+
+ ///
+ /// Reserved.
+ ///
+ public uint Reserved { get; set; }
+
+ ///
+ /// A table of resources for this type follows.
+ ///
+ public ResourceTypeResourceEntry[]? Resources { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/ResourceTypeResourceEntry.cs b/SabreTools.Serialization/Models/NewExecutable/ResourceTypeResourceEntry.cs
new file mode 100644
index 00000000..304cb90a
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/ResourceTypeResourceEntry.cs
@@ -0,0 +1,48 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// A table of resources for this type follows. The following is
+ /// the format of each resource (8 bytes each):
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ResourceTypeResourceEntry
+ {
+ ///
+ /// File offset to the contents of the resource data,
+ /// relative to beginning of file. The offset is in terms
+ /// of the alignment shift count value specified at
+ /// beginning of the resource table.
+ ///
+ /// Byte offset is: Offset * (1 << )
+ public ushort Offset;
+
+ ///
+ /// Length of the resource in the file (in bytes).
+ ///
+ /// Byte length is: Length * (1 << )
+ public ushort Length;
+
+ ///
+ /// Flag word.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public ResourceTypeResourceFlag FlagWord;
+
+ ///
+ /// Resource ID. This is an integer type if the high-order
+ /// bit is set (8000h), otherwise it is the offset to the
+ /// resource string, the offset is relative to the
+ /// beginning of the resource table.
+ ///
+ public ushort ResourceID;
+
+ ///
+ /// Reserved.
+ ///
+ public uint Reserved;
+ }
+}
diff --git a/SabreTools.Serialization/Models/NewExecutable/SegmentTableEntry.cs b/SabreTools.Serialization/Models/NewExecutable/SegmentTableEntry.cs
new file mode 100644
index 00000000..ab709d8e
--- /dev/null
+++ b/SabreTools.Serialization/Models/NewExecutable/SegmentTableEntry.cs
@@ -0,0 +1,60 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.NewExecutable
+{
+ ///
+ /// The segment table contains an entry for each segment in the executable
+ /// file. The number of segment table entries are defined in the segmented
+ /// EXE header. The first entry in the segment table is segment number 1.
+ /// The following is the structure of a segment table entry.
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class SegmentTableEntry
+ {
+ ///
+ /// Logical-sector offset (n byte) to the contents of the segment
+ /// data, relative to the beginning of the file. Zero means no
+ /// file data.
+ ///
+ /// Byte offset is: Offset * (1 << )
+ public ushort Offset { get; set; }
+
+ ///
+ /// Length of the segment in the file, in bytes. Zero means 64K.
+ ///
+ public ushort Length { get; set; }
+
+ ///
+ /// Flag word.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public SegmentTableEntryFlag FlagWord;
+
+ ///
+ /// Minimum allocation size of the segment, in bytes. Total size
+ /// of the segment. Zero means 64K.
+ ///
+ public ushort MinimumAllocationSize { get; set; }
+
+ ///
+ /// Segment data
+ ///
+ ///
+ /// Data is not sequential to the entry header. It lives at
+ /// the and has a size of
+ ///
+ public byte[]? Data { get; set; }
+
+ ///
+ /// Per-segment data
+ ///
+ ///
+ /// This only exists if has a flag value
+ /// of . It immediately
+ /// follows .
+ ///
+ public PerSegmentData? PerSegmentData { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/AttributeCertificate/Entry.cs b/SabreTools.Serialization/Models/PortableExecutable/AttributeCertificate/Entry.cs
new file mode 100644
index 00000000..d008ff64
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/AttributeCertificate/Entry.cs
@@ -0,0 +1,63 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate
+{
+ ///
+ /// Attribute certificates can be associated with an image by adding an attribute
+ /// certificate table. The attribute certificate table is composed of a set of
+ /// contiguous, quadword-aligned attribute certificate entries. Zero padding is
+ /// inserted between the original end of the file and the beginning of the attribute
+ /// certificate table to achieve this alignment.
+ ///
+ /// The virtual address value from the Certificate Table entry in the Optional
+ /// Header Data Directory is a file offset to the first attribute certificate
+ /// entry. Subsequent entries are accessed by advancing that entry's dwLength
+ /// bytes, rounded up to an 8-byte multiple, from the start of the current
+ /// attribute certificate entry. This continues until the sum of the rounded dwLength
+ /// values equals the Size value from the Certificates Table entry in the Optional
+ /// Header Data Directory. If the sum of the rounded dwLength values does not equal
+ /// the Size value, then either the attribute certificate table or the Size field
+ /// is corrupted.
+ ///
+ /// The first certificate starts at offset 0x5000 from the start of the file on disk.
+ /// To advance through all the attribute certificate entries:
+ ///
+ /// 1. Add the first attribute certificate's dwLength value to the starting offset.
+ /// 2. Round the value from step 1 up to the nearest 8-byte multiple to find the offset
+ /// of the second attribute certificate entry.
+ /// 3. Add the offset value from step 2 to the second attribute certificate entry's
+ /// dwLength value and round up to the nearest 8-byte multiple to determine the offset
+ /// of the third attribute certificate entry.
+ /// 4. Repeat step 3 for each successive certificate until the calculated offset equals
+ /// 0x6000 (0x5000 start + 0x1000 total size), which indicates that you've walked
+ /// the entire table.
+ ///
+ /// Attribute certificate table entries can contain any certificate type, as long as
+ /// the entry has the correct dwLength value, a unique wRevision value, and a unique
+ /// wCertificateType value. The most common type of certificate table entry is a
+ /// WIN_CERTIFICATE structure, which is documented in Wintrust.h and discussed in
+ /// the remainder of this section.
+ ///
+ ///
+ public sealed class Entry
+ {
+ ///
+ /// Specifies the length of the attribute certificate entry.
+ ///
+ public uint Length { get; set; }
+
+ ///
+ /// Contains the certificate version number.
+ ///
+ public WindowsCertificateRevision Revision { get; set; }
+
+ ///
+ /// Specifies the type of content in Certificate.
+ ///
+ public WindowsCertificateType CertificateType { get; set; }
+
+ ///
+ /// Contains a certificate, such as an Authenticode signature.
+ ///
+ ///
+ public byte[]? Certificate { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/BaseRelocation/Block.cs b/SabreTools.Serialization/Models/PortableExecutable/BaseRelocation/Block.cs
new file mode 100644
index 00000000..07f5b4da
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/BaseRelocation/Block.cs
@@ -0,0 +1,51 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.BaseRelocation
+{
+ ///
+ /// The base relocation table contains entries for all base relocations in
+ /// the image. The Base Relocation Table field in the optional header data
+ /// directories gives the number of bytes in the base relocation table. For
+ /// more information, see Optional Header Data Directories (Image Only).
+ /// The base relocation table is divided into blocks. Each block represents
+ /// the base relocations for a 4K page. Each block must start on a 32-bit boundary.
+ ///
+ /// The loader is not required to process base relocations that are resolved by
+ /// the linker, unless the load image cannot be loaded at the image base that is
+ /// specified in the PE header.
+ ///
+ /// To apply a base relocation, the difference is calculated between the preferred
+ /// base address and the base where the image is actually loaded. If the image is
+ /// loaded at its preferred base, the difference is zero and thus the base
+ /// relocations do not have to be applied.
+ ///
+ ///
+ public sealed class Block
+ {
+ ///
+ /// The image base plus the page RVA is added to each offset to create
+ /// the VA where the base relocation must be applied.
+ ///
+ public uint PageRVA { get; set; }
+
+ ///
+ /// The total number of bytes in the base relocation block, including
+ /// the Page RVA and Block Size fields and the Type/Offset fields that
+ /// follow.
+ ///
+ public uint BlockSize { get; set; }
+
+ ///
+ /// The Block Size field is then followed by any number of Type or Offset
+ /// field entries. Each entry is a WORD (2 bytes) and has the following
+ /// structure:
+ ///
+ /// 4 bits - Type - Stored in the high 4 bits of the WORD, a value
+ /// that indicates the type of base relocation to be
+ /// applied. For more information, see
+ /// 12 bits - Offset - Stored in the remaining 12 bits of the WORD, an
+ /// offset from the starting address that was specified
+ /// in the Page RVA field for the block. This offset
+ /// specifies where the base relocation is to be applied.
+ ///
+ public TypeOffsetFieldEntry[]? TypeOffsetFieldEntries { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/BaseRelocation/TypeOffsetFieldEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/BaseRelocation/TypeOffsetFieldEntry.cs
new file mode 100644
index 00000000..94ecd2de
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/BaseRelocation/TypeOffsetFieldEntry.cs
@@ -0,0 +1,22 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.BaseRelocation
+{
+ ///
+ /// Type or Offset field entry is a WORD (2 bytes).
+ ///
+ ///
+ public sealed class TypeOffsetFieldEntry
+ {
+ ///
+ /// Stored in the high 4 bits of the WORD, a value that indicates the type
+ /// of base relocation to be applied. For more information, see
+ ///
+ public BaseRelocationTypes BaseRelocationType { get; set; }
+
+ ///
+ /// Stored in the remaining 12 bits of the WORD, an offset from the starting
+ /// address that was specified in the Page RVA field for the block. This
+ /// offset specifies where the base relocation is to be applied.
+ ///
+ public ushort Offset { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Constants.cs b/SabreTools.Serialization/Models/PortableExecutable/Constants.cs
new file mode 100644
index 00000000..b201cc00
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Constants.cs
@@ -0,0 +1,13 @@
+namespace SabreTools.Serialization.Models.PortableExecutable
+{
+ // TODO: Add more constants around sizes
+ // - Debug Directory entry size is a constant value of 28 (0x1C)
+ public static class Constants
+ {
+ public static readonly byte[] SignatureBytes = [0x50, 0x45, 0x00, 0x00];
+
+ public const string SignatureString = "PE\0\0";
+
+ public const uint SignatureUInt32 = 0x00004550;
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/PortableExecutable/DataDirectory.cs b/SabreTools.Serialization/Models/PortableExecutable/DataDirectory.cs
new file mode 100644
index 00000000..6a4950b1
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/DataDirectory.cs
@@ -0,0 +1,29 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable
+{
+ ///
+ /// Each data directory gives the address and size of a table or string that Windows uses.
+ /// These data directory entries are all loaded into memory so that the system can use them
+ /// at run time.
+ ///
+ /// Also, do not assume that the RVAs in this table point to the beginning of a section or
+ /// that the sections that contain specific tables have specific names.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class DataDirectory
+ {
+ ///
+ /// The first field, VirtualAddress, is actually the RVA of the table. The RVA
+ /// is the address of the table relative to the base address of the image when
+ /// the table is loaded.
+ ///
+ public uint VirtualAddress;
+
+ ///
+ /// The second field gives the size in bytes.
+ ///
+ public uint Size;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/DebugData/Entry.cs b/SabreTools.Serialization/Models/PortableExecutable/DebugData/Entry.cs
new file mode 100644
index 00000000..dd43a34a
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/DebugData/Entry.cs
@@ -0,0 +1,67 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.DebugData
+{
+ ///
+ /// Image files contain an optional debug directory that indicates what form
+ /// of debug information is present and where it is. This directory consists
+ /// of an array of debug directory entries whose location and size are indicated
+ /// in the image optional header.
+ ///
+ /// The debug directory can be in a discardable .debug section (if one exists),
+ /// or it can be included in any other section in the image file, or not be in
+ /// a section at all.
+ ///
+ /// Each debug directory entry identifies the location and size of a block of
+ /// debug information. The specified RVA can be zero if the debug information
+ /// is not covered by a section header (that is, it resides in the image file
+ /// and is not mapped into the run-time address space). If it is mapped, the
+ /// RVA is its address.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class Entry
+ {
+ ///
+ /// Reserved, must be zero.
+ ///
+ public uint Characteristics;
+
+ ///
+ /// The time and date that the debug data was created.
+ ///
+ public uint TimeDateStamp;
+
+ ///
+ /// The major version number of the debug data format.
+ ///
+ public ushort MajorVersion;
+
+ ///
+ /// The minor version number of the debug data format.
+ ///
+ public ushort MinorVersion;
+
+ ///
+ /// The format of debugging information. This field enables support
+ /// of multiple debuggers.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public DebugType DebugType;
+
+ ///
+ /// The size of the debug data (not including the debug directory itself).
+ ///
+ public uint SizeOfData;
+
+ ///
+ /// The address of the debug data when loaded, relative to the image base.
+ ///
+ public uint AddressOfRawData;
+
+ ///
+ /// The file pointer to the debug data.
+ ///
+ public uint PointerToRawData;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/DebugData/NB10ProgramDatabase.cs b/SabreTools.Serialization/Models/PortableExecutable/DebugData/NB10ProgramDatabase.cs
new file mode 100644
index 00000000..20c4d460
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/DebugData/NB10ProgramDatabase.cs
@@ -0,0 +1,44 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.DebugData
+{
+ ///
+ /// PDB 2.0 files
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class NB10ProgramDatabase
+ {
+ ///
+ /// "CodeView signature, equal to “NB10”
+ ///
+ public uint Signature;
+
+ ///
+ /// CodeView offset. Set to 0, because debug information
+ /// is stored in a separate file.
+ ///
+ public uint Offset;
+
+ ///
+ /// The time when debug information was created (in seconds
+ /// since 01.01.1970)
+ ///
+ public uint Timestamp;
+
+ ///
+ /// Ever-incrementing value, which is initially set to 1 and
+ /// incremented every time when a part of the PDB file is updated
+ /// without rewriting the whole file.
+ ///
+ public uint Age;
+
+ ///
+ /// Null-terminated name of the PDB file. It can also contain full
+ /// or partial path to the file.
+ ///
+ /// Is this Unicode?
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string? PdbFileName;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/DebugData/RSDSProgramDatabase.cs b/SabreTools.Serialization/Models/PortableExecutable/DebugData/RSDSProgramDatabase.cs
new file mode 100644
index 00000000..433de95b
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/DebugData/RSDSProgramDatabase.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.DebugData
+{
+ ///
+ /// This file describes the format of the pdb (Program Database) files of the "RSDS"
+ /// or "DS" type which are emitted by Miscrosoft's link.exe from version 7 and above.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class RSDSProgramDatabase
+ {
+ ///
+ /// "RSDS" signature
+ ///
+ public uint Signature;
+
+ ///
+ /// 16-byte Globally Unique Identifier
+ ///
+ public Guid GUID;
+
+ ///
+ /// Ever-incrementing value, which is initially set to 1 and
+ /// incremented every time when a part of the PDB file is updated
+ /// without rewriting the whole file.
+ ///
+ public uint Age;
+
+ ///
+ /// zero terminated UTF8 path and file name
+ ///
+#if NET472_OR_GREATER || NETCOREAPP
+ [MarshalAs(UnmanagedType.LPUTF8Str)]
+#else
+ [MarshalAs(UnmanagedType.LPStr)]
+#endif
+ public string? PathAndFileName;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/DebugData/Table.cs b/SabreTools.Serialization/Models/PortableExecutable/DebugData/Table.cs
new file mode 100644
index 00000000..da052f8d
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/DebugData/Table.cs
@@ -0,0 +1,38 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.DebugData
+{
+ ///
+ /// The .debug section is used in object files to contain compiler-generated debug
+ /// information and in image files to contain all of the debug information that is
+ /// generated. This section describes the packaging of debug information in object
+ /// and image files.
+ ///
+ /// The next section describes the format of the debug directory, which can be
+ /// anywhere in the image. Subsequent sections describe the "groups" in object
+ /// files that contain debug information.
+ ///
+ /// The default for the linker is that debug information is not mapped into the
+ /// address space of the image. A .debug section exists only when debug information
+ /// is mapped in the address space.
+ ///
+ ///
+ public sealed class Table
+ {
+ ///
+ /// Image files contain an optional debug directory that indicates what form
+ /// of debug information is present and where it is. This directory consists
+ /// of an array of debug directory entries whose location and size are
+ /// indicated in the image optional header.
+ ///
+ /// The debug directory can be in a discardable .debug section (if one exists),
+ /// or it can be included in any other section in the image file, or not be
+ /// in a section at all.
+ ///
+ /// Each debug directory entry identifies the location and size of a block of
+ /// debug information. The specified RVA can be zero if the debug information
+ /// is not covered by a section header (that is, it resides in the image
+ /// file and is not mapped into the run-time address space). If it is mapped,
+ /// the RVA is its address.
+ ///
+ public Entry[]? DebugDirectoryTable { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/DelayLoad/DirectoryTable.cs b/SabreTools.Serialization/Models/PortableExecutable/DelayLoad/DirectoryTable.cs
new file mode 100644
index 00000000..1b78a62c
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/DelayLoad/DirectoryTable.cs
@@ -0,0 +1,107 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.DelayLoad
+{
+ ///
+ /// The delay-load directory table is the counterpart to the import directory
+ /// table. It can be retrieved through the Delay Import Descriptor entry in
+ /// the optional header data directories list (offset 200).
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class DirectoryTable
+ {
+ ///
+ /// Must be zero.
+ ///
+ ///
+ /// As yet, no attribute flags are defined. The linker sets this field to
+ /// zero in the image. This field can be used to extend the record by
+ /// indicating the presence of new fields, or it can be used to indicate
+ /// behaviors to the delay or unload helper functions.
+ ///
+ public uint Attributes;
+
+ ///
+ /// The RVA of the name of the DLL to be loaded. The name resides in the
+ /// read-only data section of the image.
+ ///
+ ///
+ /// The name of the DLL to be delay-loaded resides in the read-only data
+ /// section of the image. It is referenced through the szName field.
+ ///
+ public uint NameRVA;
+
+ ///
+ /// The RVA of the module handle (in the data section of the image) of the DLL
+ /// to be delay-loaded. It is used for storage by the routine that is supplied
+ /// to manage delay-loading.
+ ///
+ ///
+ /// The handle of the DLL to be delay-loaded is in the data section of the image.
+ /// The phmod field points to the handle. The supplied delay-load helper uses
+ /// this location to store the handle to the loaded DLL.
+ ///
+ public uint ModuleHandle;
+
+ ///
+ /// The RVA of the delay-load import address table.
+ ///
+ ///
+ /// The delay import address table (IAT) is referenced by the delay import
+ /// descriptor through the pIAT field. The delay-load helper updates these
+ /// pointers with the real entry points so that the thunks are no longer in
+ /// the calling loop. The function pointers are accessed by using the expression
+ /// pINT->u1.Function.
+ ///
+ public uint DelayImportAddressTable;
+
+ ///
+ /// The RVA of the delay-load name table, which contains the names of the imports
+ /// that might need to be loaded. This matches the layout of the import name table.
+ ///
+ ///
+ /// The delay import name table (INT) contains the names of the imports that might
+ /// require loading. They are ordered in the same fashion as the function pointers
+ /// in the IAT. They consist of the same structures as the standard INT and are
+ /// accessed by using the expression pINT->u1.AddressOfData->Name[0].
+ ///
+ public uint DelayImportNameTable;
+
+ ///
+ /// The RVA of the bound delay-load address table, if it exists.
+ ///
+ ///
+ /// The delay bound import address table (BIAT) is an optional table of
+ /// IMAGE_THUNK_DATA items that is used along with the timestamp field of the
+ /// delay-load directory table by a post-process binding phase.
+ ///
+ public uint BoundDelayImportTable;
+
+ ///
+ /// The RVA of the unload delay-load address table, if it exists. This is an exact
+ /// copy of the delay import address table. If the caller unloads the DLL, this
+ /// table should be copied back over the delay import address table so that
+ /// subsequent calls to the DLL continue to use the thunking mechanism correctly.
+ ///
+ ///
+ /// The delay unload import address table (UIAT) is an optional table of
+ /// IMAGE_THUNK_DATA items that the unload code uses to handle an explicit unload
+ /// request. It consists of initialized data in the read-only section that is an
+ /// exact copy of the original IAT that referred the code to the delay-load thunks.
+ /// On the unload request, the library can be freed, the *phmod cleared, and the
+ /// UIAT written over the IAT to restore everything to its preload state.
+ ///
+ public uint UnloadDelayImportTable;
+
+ ///
+ /// The timestamp of the DLL to which this image has been bound.
+ ///
+ ///
+ /// The delay bound import address table (BIAT) is an optional table of
+ /// IMAGE_THUNK_DATA items that is used along with the timestamp field of the
+ /// delay-load directory table by a post-process binding phase.
+ ///
+ public uint TimeStamp;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Enums.cs b/SabreTools.Serialization/Models/PortableExecutable/Enums.cs
new file mode 100644
index 00000000..3a0f5639
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Enums.cs
@@ -0,0 +1,1678 @@
+using System;
+
+namespace SabreTools.Serialization.Models.PortableExecutable
+{
+ [Flags]
+ public enum AcceleratorTableFlags : ushort
+ {
+ ///
+ /// The accelerator key is a virtual-key code. If this flag is not specified,
+ /// the accelerator key is assumed to specify an ASCII character code.
+ ///
+ FVIRTKEY = 0x01,
+
+ ///
+ /// A menu item on the menu bar is not highlighted when an accelerator is used.
+ /// This attribute is obsolete and retained only for backward compatibility with
+ /// resource files designed for 16-bit Windows.
+ ///
+ FNOINVERT = 0x02,
+
+ ///
+ /// The accelerator is activated only if the user presses the SHIFT key. This flag
+ /// applies only to virtual keys.
+ ///
+ FSHIFT = 0x04,
+
+ ///
+ /// The accelerator is activated only if the user presses the CTRL key. This flag
+ /// applies only to virtual keys.
+ ///
+ FCONTROL = 0x08,
+
+ ///
+ /// The accelerator is activated only if the user presses the ALT key. This flag
+ /// applies only to virtual keys.
+ ///
+ FALT = 0x10,
+
+ ///
+ /// The entry is last in an accelerator table.
+ ///
+ LastEntry = 0x80,
+ }
+
+ public enum BaseRelocationTypes : ushort
+ {
+ ///
+ /// The base relocation is skipped. This type can be used to pad a block.
+ ///
+ IMAGE_REL_BASED_ABSOLUTE = 0,
+
+ ///
+ /// The base relocation adds the high 16 bits of the difference to the 16-bit
+ /// field at offset. The 16-bit field represents the high value of a 32-bit word.
+ ///
+ IMAGE_REL_BASED_HIGH = 1,
+
+ ///
+ /// The base relocation adds the low 16 bits of the difference to the 16-bit
+ /// field at offset. The 16-bit field represents the low half of a 32-bit word.
+ ///
+ IMAGE_REL_BASED_LOW = 2,
+
+ ///
+ /// The base relocation applies all 32 bits of the difference to the 32-bit
+ /// field at offset.
+ ///
+ IMAGE_REL_BASED_HIGHLOW = 3,
+
+ ///
+ /// The base relocation adds the high 16 bits of the difference to the 16-bit
+ /// field at offset. The 16-bit field represents the high value of a 32-bit word.
+ /// The low 16 bits of the 32-bit value are stored in the 16-bit word that follows
+ /// this base relocation. This means that this base relocation occupies two slots.
+ ///
+ IMAGE_REL_BASED_HIGHADJ = 4,
+
+ ///
+ /// The relocation interpretation is dependent on the machine type.
+ /// When the machine type is MIPS, the base relocation applies to a MIPS jump
+ /// instruction.
+ ///
+ IMAGE_REL_BASED_MIPS_JMPADDR = 5,
+
+ ///
+ /// This relocation is meaningful only when the machine type is ARM or Thumb.
+ /// The base relocation applies the 32-bit address of a symbol across a consecutive
+ /// MOVW/MOVT instruction pair.
+ ///
+ IMAGE_REL_BASED_ARM_MOV32 = 5,
+
+ ///
+ /// This relocation is only meaningful when the machine type is RISC-V. The base
+ /// relocation applies to the high 20 bits of a 32-bit absolute address.
+ ///
+ IMAGE_REL_BASED_RISCV_HIGH20 = 5,
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ RESERVED6 = 6,
+
+ ///
+ /// This relocation is meaningful only when the machine type is Thumb. The base
+ /// relocation applies the 32-bit address of a symbol to a consecutive MOVW/MOVT
+ /// instruction pair.
+ ///
+ IMAGE_REL_BASED_THUMB_MOV32 = 7,
+
+ ///
+ /// This relocation is only meaningful when the machine type is RISC-V. The base
+ /// relocation applies to the low 12 bits of a 32-bit absolute address formed in
+ /// RISC-V I-type instruction format.
+ ///
+ IMAGE_REL_BASED_RISCV_LOW12I = 7,
+
+ ///
+ /// This relocation is only meaningful when the machine type is RISC-V. The base
+ /// relocation applies to the low 12 bits of a 32-bit absolute address formed in
+ /// RISC-V S-type instruction format.
+ ///
+ IMAGE_REL_BASED_RISCV_LOW12S = 8,
+
+ ///
+ /// This relocation is only meaningful when the machine type is LoongArch 32-bit.
+ /// The base relocation applies to a 32-bit absolute address formed in two
+ /// consecutive instructions.
+ ///
+ IMAGE_REL_BASED_LOONGARCH32_MARK_LA = 8,
+
+ ///
+ /// This relocation is only meaningful when the machine type is LoongArch 64-bit.
+ /// The base relocation applies to a 64-bit absolute address formed in four
+ /// consecutive instructions.
+ ///
+ IMAGE_REL_BASED_LOONGARCH64_MARK_LA = 8,
+
+ ///
+ /// The relocation is only meaningful when the machine type is MIPS. The base
+ /// relocation applies to a MIPS16 jump instruction.
+ ///
+ IMAGE_REL_BASED_MIPS_JMPADDR16 = 9,
+
+ ///
+ /// The base relocation applies the difference to the 64-bit field at offset.
+ ///
+ IMAGE_REL_BASED_DIR64 = 10,
+ }
+
+ public enum CallbackReason : ushort
+ {
+ ///
+ /// A new process has started, including the first thread.
+ ///
+ DLL_PROCESS_ATTACH = 1,
+
+ ///
+ /// A new thread has been created. This notification sent for
+ /// all but the first thread.
+ ///
+ DLL_THREAD_ATTACH = 2,
+
+ ///
+ /// A thread is about to be terminated. This notification sent
+ /// for all but the first thread.
+ ///
+ DLL_THREAD_DETACH = 3,
+
+ ///
+ /// A process is about to terminate, including the original thread.
+ ///
+ DLL_PROCESS_DETACH = 0,
+ }
+
+ public enum COMDATSelect : byte
+ {
+ ///
+ /// If this symbol is already defined, the linker issues a "multiply
+ /// defined symbol" error.
+ ///
+ IMAGE_COMDAT_SELECT_NODUPLICATES = 0x01,
+
+ ///
+ /// Any section that defines the same COMDAT symbol can be linked;
+ /// the rest are removed.
+ ///
+ IMAGE_COMDAT_SELECT_ANY = 0x02,
+
+ ///
+ /// The linker chooses an arbitrary section among the definitions
+ /// for this symbol. If all definitions are not the same size, a
+ /// "multiply defined symbol" error is issued.
+ ///
+ IMAGE_COMDAT_SELECT_SAME_SIZE = 0x03,
+
+ ///
+ /// The linker chooses an arbitrary section among the definitions
+ /// for this symbol. If all definitions do not match exactly, a
+ /// "multiply defined symbol" error is issued.
+ ///
+ IMAGE_COMDAT_SELECT_EXACT_MATCH = 0x04,
+
+ ///
+ /// The section is linked if a certain other COMDAT section is linked.
+ /// This other section is indicated by the Number field of the
+ /// auxiliary symbol record for the section definition. This setting
+ /// is useful for definitions that have components in multiple sections
+ /// (for example, code in one and data in another), but where all must
+ /// be linked or discarded as a set. The other section this section is
+ /// associated with must be a COMDAT section, which can be another
+ /// associative COMDAT section. An associative COMDAT section's section
+ /// association chain can't form a loop. The section association chain
+ /// must eventually come to a COMDAT section that doesn't have
+ /// IMAGE_COMDAT_SELECT_ASSOCIATIVE set.
+ ///
+ IMAGE_COMDAT_SELECT_ASSOCIATIVE = 0x05,
+
+ ///
+ /// The linker chooses the largest definition from among all of the
+ /// definitions for this symbol. If multiple definitions have this size,
+ /// the choice between them is arbitrary.
+ ///
+ IMAGE_COMDAT_SELECT_LARGEST = 0x06,
+ }
+
+ public enum DebugType : uint
+ {
+ ///
+ /// An unknown value that is ignored by all tools.
+ ///
+ IMAGE_DEBUG_TYPE_UNKNOWN = 0,
+
+ ///
+ /// The COFF debug information (line numbers, symbol table, and string table).
+ /// This type of debug information is also pointed to by fields in the file
+ /// headers.
+ ///
+ IMAGE_DEBUG_TYPE_COFF = 1,
+
+ ///
+ /// The Visual C++ debug information.
+ ///
+ IMAGE_DEBUG_TYPE_CODEVIEW = 2,
+
+ ///
+ /// The frame pointer omission (FPO) information. This information tells the
+ /// debugger how to interpret nonstandard stack frames, which use the EBP
+ /// register for a purpose other than as a frame pointer.
+ ///
+ IMAGE_DEBUG_TYPE_FPO = 3,
+
+ ///
+ /// The location of DBG file.
+ ///
+ IMAGE_DEBUG_TYPE_MISC = 4,
+
+ ///
+ /// A copy of .pdata section.
+ ///
+ IMAGE_DEBUG_TYPE_EXCEPTION = 5,
+
+ ///
+ /// Reserved.
+ ///
+ IMAGE_DEBUG_TYPE_FIXUP = 6,
+
+ ///
+ /// The mapping from an RVA in image to an RVA in source image.
+ ///
+ IMAGE_DEBUG_TYPE_OMAP_TO_SRC = 7,
+
+ ///
+ /// The mapping from an RVA in source image to an RVA in image.
+ ///
+ IMAGE_DEBUG_TYPE_OMAP_FROM_SRC = 8,
+
+ ///
+ /// Reserved for Borland.
+ ///
+ IMAGE_DEBUG_TYPE_BORLAND = 9,
+
+ ///
+ /// Reserved.
+ ///
+ IMAGE_DEBUG_TYPE_RESERVED10 = 10,
+
+ ///
+ /// Reserved.
+ ///
+ IMAGE_DEBUG_TYPE_CLSID = 11,
+
+ ///
+ /// PE determinism or reproducibility.
+ ///
+ IMAGE_DEBUG_TYPE_REPRO = 16,
+
+ ///
+ /// Extended DLL characteristics bits.
+ ///
+ IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS = 20,
+ }
+
+ public enum DialogItemTemplateOrdinal : ushort
+ {
+ Button = 0x0080,
+ Edit = 0x0081,
+ Static = 0x0082,
+ ListBox = 0x0083,
+ ScrollBar = 0x0084,
+ ComboBox = 0x0085,
+ }
+
+ [Flags]
+ public enum DllCharacteristics : ushort
+ {
+ ///
+ /// Reserved, must be zero.
+ ///
+ RESERVED0 = 0x0001,
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ RESERVED1 = 0x0002,
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ RESERVED2 = 0x0004,
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ RESERVED3 = 0x0008,
+
+ ///
+ /// Image can handle a high entropy 64-bit virtual address space.
+ ///
+ IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020,
+
+ ///
+ /// DLL can be relocated at load time.
+ ///
+ IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040,
+
+ ///
+ /// Code Integrity checks are enforced.
+ ///
+ IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080,
+
+ ///
+ /// Image is NX compatible.
+ ///
+ IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100,
+
+ ///
+ /// Isolation aware, but do not isolate the image.
+ ///
+ IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200,
+
+ ///
+ /// Does not use structured exception (SE) handling.
+ /// No SE handler may be called in this image.
+ ///
+ IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400,
+
+ ///
+ /// Do not bind the image.
+ ///
+ IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800,
+
+ ///
+ /// Image must execute in an AppContainer.
+ ///
+ IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000,
+
+ ///
+ /// A WDM driver.
+ ///
+ IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000,
+
+ ///
+ /// Image supports Control Flow Guard.
+ ///
+ IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000,
+
+ ///
+ /// Terminal Server aware.
+ ///
+ IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000,
+ }
+
+ [Flags]
+ public enum ExtendedDllCharacteristics : ushort
+ {
+ ///
+ /// Image is Control-flow Enforcement Technology (CET) Shadow Stack compatible
+ ///
+ IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT = 0x0001,
+
+ ///
+ /// All branch targets in all image code sections are annotated with forward-edge
+ /// control flow integrity guard instructions such as x86 CET-Indirect Branch
+ /// Tracking (IBT) or ARM Branch Target Identification (BTI) instructions.
+ /// This bit is not used by Windows.
+ ///
+ IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT = 0x0040,
+ }
+
+ [Flags]
+ public enum ExtendedWindowStyles : uint
+ {
+ ///
+ /// The window has generic left-aligned properties. This is the default.
+ ///
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// The window text is displayed using left-to-right reading-order properties.
+ /// This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// The vertical scroll bar (if present) is to the right of the client area.
+ /// This is the default.
+ ///
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// The window has a double border; the window can, optionally, be created with
+ /// a title bar by specifying the WS_CAPTION style in the dwStyle parameter.
+ ///
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// The child window created with this style does not send the WM_PARENTNOTIFY
+ /// message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window should be placed above all non-topmost windows and should stay above them,
+ /// even when the window is deactivated. To add or remove this style, use the
+ /// SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// The window accepts drag-drop files.
+ ///
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ ///
+ /// The window should not be painted until siblings beneath the window (that were created
+ /// by the same thread) have been painted. The window appears transparent because the bits
+ /// of underlying sibling windows have already been painted.
+ ///
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ ///
+ /// The window is a MDI child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// The window is intended to be used as a floating toolbar. A tool window has a title
+ /// bar that is shorter than a normal title bar, and the window title is drawn using a
+ /// smaller font. A tool window does not appear in the taskbar or in the dialog that
+ /// appears when the user presses ALT+TAB. If a tool window has a system menu, its icon
+ /// is not displayed on the title bar. However, you can display the system menu by
+ /// right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// The window has a border with a raised edge.
+ ///
+ WS_EX_WINDOWEDGE = 0x00000100,
+
+ ///
+ /// The window has a border with a sunken edge.
+ ///
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// The title bar of the window includes a question mark. When the user clicks
+ /// the question mark, the cursor changes to a question mark with a pointer. If
+ /// the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure,
+ /// which should call the WinHelp function using the HELP_WM_HELP command. The
+ /// Help application displays a pop-up window that typically contains help for
+ /// the child window.
+ ///
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX
+ /// styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// The window has generic "right-aligned" properties. This depends on the window class.
+ /// This style has an effect only if the shell language is Hebrew, Arabic, or another
+ /// language that supports reading-order alignment; otherwise, the style is ignored.
+ ///
+ /// Using the WS_EX_RIGHT style for static or edit controls has the same effect as using
+ /// the SS_RIGHT or ES_RIGHT style, respectively. Using this style with button controls
+ /// has the same effect as using BS_RIGHT and BS_RIGHTBUTTON styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ ///
+ /// If the shell language is Hebrew, Arabic, or another language that supports reading-order
+ /// alignment, the window text is displayed using right-to-left reading-order properties.
+ /// For other languages, the style is ignored.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ ///
+ /// If the shell language is Hebrew, Arabic, or another language that supports
+ /// reading order alignment, the vertical scroll bar (if present) is to the left
+ /// of the client area. For other languages, the style is ignored.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// The window itself contains child windows that should take part in dialog box
+ /// navigation. If this style is specified, the dialog manager recurses into
+ /// children of this window when performing navigation operations such as handling
+ /// the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ ///
+ /// The window has a three-dimensional border style intended to be used for items that do
+ /// not accept user input.
+ ///
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ ///
+ WS_EX_APPWINDOW = 0x00040000,
+
+ ///
+ /// The window is a layered window. This style cannot be used if the window has a
+ /// class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ /// Windows 8: The WS_EX_LAYERED style is supported for top-level windows and child
+ /// windows. Previous Windows versions support WS_EX_LAYERED only for top-level windows.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// The window does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// The window does not render to a redirection surface. This is for windows that do not
+ /// have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ ///
+ /// If the shell language is Hebrew, Arabic, or another language that supports reading
+ /// order alignment, the horizontal origin of the window is on the right edge.
+ /// Increasing horizontal values advance to the left.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ ///
+ /// Paints all descendants of a window in bottom-to-top painting order using
+ /// double-buffering. Bottom-to-top painting order allows a descendent window
+ /// to have translucency (alpha) and transparency (color-key) effects, but only
+ /// if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without
+ /// flicker. This cannot be used if the window has a class style of either
+ /// CS_OWNDC or CS_CLASSDC.
+ ///
+ /// Windows 2000: This style is not supported.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// A top-level window created with this style does not become the foreground window when
+ /// the user clicks it. The system does not bring this window to the foreground when the
+ /// user minimizes or closes the foreground window.
+ ///
+ /// The window should not be activated through programmatic access or via keyboard
+ /// navigation by accessible technology, such as Narrator.
+ ///
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ /// The window does not appear on the taskbar by default. To force the window to appear on
+ /// the taskbar, use the WS_EX_APPWINDOW style.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// The window is an overlapped window.
+ ///
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ ///
+ /// The window is palette window, which is a modeless dialog box that presents an array of
+ /// commands.
+ ///
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+ }
+
+ public enum FixedFileInfoFileSubtype : uint
+ {
+ ///
+ /// The driver type is unknown by the system.
+ /// The font type is unknown by the system.
+ ///
+ VFT2_UNKNOWN = 0x00000000,
+
+ #region VFT_DRV
+
+ ///
+ /// The file contains a printer driver.
+ ///
+ VFT2_DRV_PRINTER = 0x00000001,
+
+ ///
+ /// The file contains a keyboard driver.
+ ///
+ VFT2_DRV_KEYBOARD = 0x00000002,
+
+ ///
+ /// The file contains a language driver.
+ ///
+ VFT2_DRV_LANGUAGE = 0x00000003,
+
+ ///
+ /// The file contains a display driver.
+ ///
+ VFT2_DRV_DISPLAY = 0x00000004,
+
+ ///
+ /// The file contains a mouse driver.
+ ///
+ VFT2_DRV_MOUSE = 0x00000005,
+
+ ///
+ /// The file contains a network driver.
+ ///
+ VFT2_DRV_NETWORK = 0x00000006,
+
+ ///
+ /// The file contains a system driver.
+ ///
+ VFT2_DRV_SYSTEM = 0x00000007,
+
+ ///
+ /// The file contains an installable driver.
+ ///
+ VFT2_DRV_INSTALLABLE = 0x00000008,
+
+ ///
+ /// The file contains a sound driver.
+ ///
+ VFT2_DRV_SOUND = 0x00000009,
+
+ ///
+ /// The file contains a communications driver.
+ ///
+ VFT2_DRV_COMM = 0x0000000A,
+
+ ///
+ /// The file contains a versioned printer driver.
+ ///
+ VFT2_DRV_VERSIONED_PRINTER = 0x0000000C,
+
+ #endregion
+
+ #region VFT_FONT
+
+ ///
+ /// The file contains a raster font.
+ ///
+ VFT2_FONT_RASTER = 0x00000001,
+
+ ///
+ /// The file contains a vector font.
+ ///
+ VFT2_FONT_VECTOR = 0x00000002,
+
+ ///
+ /// The file contains a TrueType font.
+ ///
+ VFT2_FONT_TRUETYPE = 0x00000003,
+
+ #endregion
+ }
+
+ public enum FixedFileInfoFileType : uint
+ {
+ ///
+ /// The file type is unknown to the system.
+ ///
+ VFT_UNKNOWN = 0x00000000,
+
+ ///
+ /// The file contains an application.
+ ///
+ VFT_APP = 0x00000001,
+
+ ///
+ /// The file contains a DLL.
+ ///
+ VFT_DLL = 0x00000002,
+
+ ///
+ /// The file contains a device driver. If FileType is VFT_DRV, FileSubtype
+ /// contains a more specific description of the driver.
+ ///
+ VFT_DRV = 0x00000003,
+
+ ///
+ /// The file contains a font. If FileType is VFT_FONT, FileSubtype contains
+ /// a more specific description of the font file.
+ ///
+ VFT_FONT = 0x00000004,
+
+ ///
+ /// The file contains a virtual device.
+ ///
+ VFT_VXD = 0x00000005,
+
+ ///
+ /// The file contains a static-link library.
+ ///
+ VFT_STATIC_LIB = 0x00000007,
+ }
+
+ [Flags]
+ public enum FixedFileInfoFlags : uint
+ {
+ ///
+ /// The file contains debugging information or is compiled with debugging
+ /// features enabled.
+ ///
+ VS_FF_DEBUG = 0x00000001,
+
+ ///
+ /// The file is a development version, not a commercially released product.
+ ///
+ VS_FF_PRERELEASE = 0x00000002,
+
+ ///
+ /// The file has been modified and is not identical to the original shipping
+ /// file of the same version number.
+ ///
+ VS_FF_PATCHED = 0x00000004,
+
+ ///
+ /// The file was not built using standard release procedures. If this flag is
+ /// set, the StringFileInfo structure should contain a PrivateBuild entry.
+ ///
+ VS_FF_PRIVATEBUILD = 0x00000008,
+
+ ///
+ /// The file's version structure was created dynamically; therefore, some
+ /// of the members in this structure may be empty or incorrect. This flag
+ /// should never be set in a file's VS_VERSIONINFO data.
+ ///
+ VS_FF_INFOINFERRED = 0x00000010,
+
+ ///
+ /// The file was built by the original company using standard release
+ /// procedures but is a variation of the normal file of the same version number.
+ /// If this flag is set, the StringFileInfo structure should contain a SpecialBuild
+ /// entry.
+ ///
+ VS_FF_SPECIALBUILD = 0x00000020,
+ }
+
+ [Flags]
+ public enum FixedFileInfoOS : uint
+ {
+ ///
+ /// The operating system for which the file was designed is
+ /// unknown to the system.
+ ///
+ VOS_UNKNOWN = 0x00000000,
+
+ ///
+ /// The file was designed for 16-bit Windows.
+ ///
+ VOS__WINDOWS16 = 0x00000001,
+
+ ///
+ /// The file was designed for 16-bit Presentation Manager.
+ ///
+ VOS__PM16 = 0x00000002,
+
+ ///
+ /// The file was designed for 32-bit Presentation Manager.
+ ///
+ VOS__PM32 = 0x00000003,
+
+ ///
+ /// The file was designed for 32-bit Windows.
+ ///
+ VOS__WINDOWS32 = 0x00000004,
+
+ ///
+ /// The file was designed for MS-DOS.
+ ///
+ VOS_DOS = 0x00010000,
+
+ ///
+ /// The file was designed for 16-bit OS/2.
+ ///
+ VOS_OS216 = 0x00020000,
+
+ ///
+ /// The file was designed for 32-bit OS/2.
+ ///
+ VOS_OS232 = 0x00030000,
+
+ ///
+ /// The file was designed for Windows NT.
+ ///
+ VOS_NT = 0x00040000,
+ }
+
+ [Flags]
+ public enum GuardFlags : uint
+ {
+ ///
+ /// Module performs control flow integrity checks using
+ /// system-supplied support.
+ ///
+ IMAGE_GUARD_CF_INSTRUMENTED = 0x00000100,
+
+ ///
+ /// Module performs control flow and write integrity checks.
+ ///
+ IMAGE_GUARD_CFW_INSTRUMENTED = 0x00000200,
+
+ ///
+ /// Module contains valid control flow target metadata.
+ ///
+ IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT = 0x00000400,
+
+ ///
+ /// Module does not make use of the /GS security cookie.
+ ///
+ IMAGE_GUARD_SECURITY_COOKIE_UNUSED = 0x00000800,
+
+ ///
+ /// Module supports read only delay load IAT.
+ ///
+ IMAGE_GUARD_PROTECT_DELAYLOAD_IAT = 0x00001000,
+
+ ///
+ /// Delayload import table in its own .didat section (with
+ /// nothing else in it) that can be freely reprotected.
+ ///
+ IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION = 0x00002000,
+
+ ///
+ /// Module contains suppressed export information. This also
+ /// infers that the address taken IAT table is also present
+ /// in the load config.
+ ///
+ IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT = 0x00004000,
+
+ ///
+ /// Module enables suppression of exports.
+ ///
+ IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION = 0x00008000,
+
+ ///
+ /// Module contains longjmp target information.
+ ///
+ IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT = 0x00010000,
+
+ ///
+ /// Mask for the subfield that contains the stride of Control
+ /// Flow Guard function table entries (that is, the additional
+ /// count of bytes per table entry).
+ ///
+ IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK = 0xF0000000,
+
+ ///
+ /// Additionally, the Windows SDK winnt.h header defines this
+ /// macro for the amount of bits to right-shift the GuardFlags
+ /// value to right-justify the Control Flow Guard function table
+ /// stride:
+ ///
+ IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT = 28,
+ }
+
+ public enum ImportType : ushort
+ {
+ ///
+ /// Executable code.
+ ///
+ IMPORT_CODE = 0,
+
+ ///
+ /// Data.
+ ///
+ IMPORT_DATA = 1,
+
+ ///
+ /// Specified as CONST in the .def file.
+ ///
+ IMPORT_CONST = 2,
+ }
+
+ // Actually 3 bits
+ public enum ImportNameType : ushort
+ {
+ ///
+ /// The import is by ordinal. This indicates that the value in the
+ /// Ordinal/Hint field of the import header is the import's ordinal.
+ /// If this constant is not specified, then the Ordinal/Hint field
+ /// should always be interpreted as the import's hint.
+ ///
+ IMPORT_ORDINAL = 0,
+
+ ///
+ /// The import name is identical to the public symbol name.
+ ///
+ IMPORT_NAME = 1,
+
+ ///
+ /// The import name is the public symbol name, but skipping the leading
+ /// ?, @, or optionally _.
+ ///
+ IMPORT_NAME_NOPREFIX = 2,
+
+ ///
+ /// The import name is the public symbol name, but skipping the leading
+ /// ?, @, or optionally _, and truncating at the first @.
+ ///
+ IMPORT_NAME_UNDECORATE = 3,
+ }
+
+ [Flags]
+ public enum MemoryFlags : ushort
+ {
+ // TODO: Validate the ~ statements
+ MOVEABLE = 0x0010,
+ FIXED = 0xFFEF, // ~MOVEABLE
+
+ PURE = 0x0020,
+ IMPURE = 0xFFDF, // ~PURE
+
+ PRELOAD = 0x0040,
+ LOADONCALL = 0xFFBF, // ~PRELOAD
+
+ DISCARDABLE = 0x1000,
+ }
+
+ [Flags]
+ public enum MenuFlags : uint
+ {
+ MF_INSERT = 0x00000000,
+ MF_CHANGE = 0x00000080,
+ MF_APPEND = 0x00000100,
+ MF_DELETE = 0x00000200,
+ MF_REMOVE = 0x00001000,
+
+ MF_BYCOMMAND = 0x00000000,
+ MF_BYPOSITION = 0x00000400,
+
+ MF_SEPARATOR = 0x00000800,
+
+ MF_ENABLED = 0x00000000,
+ MF_GRAYED = 0x00000001,
+ MF_DISABLED = 0x00000002,
+
+ MF_UNCHECKED = 0x00000000,
+ MF_CHECKED = 0x00000008,
+ MF_USECHECKBITMAPS = 0x00000200,
+
+ MF_STRING = 0x00000000,
+ MF_BITMAP = 0x00000004,
+ MF_OWNERDRAW = 0x00000100,
+
+ MF_POPUP = 0x00000010,
+ MF_MENUBARBREAK = 0x00000020,
+ MF_MENUBREAK = 0x00000040,
+
+ MF_UNHILITE = 0x00000000,
+ MF_HILITE = 0x00000080,
+
+ MF_DEFAULT = 0x00001000,
+ MF_SYSMENU = 0x00002000,
+ MF_HELP = 0x00004000,
+ MF_RIGHTJUSTIFY = 0x00004000,
+
+ MF_MOUSESELECT = 0x00008000,
+ MF_END = 0x00000080,
+
+ MFT_STRING = MF_STRING,
+ MFT_BITMAP = MF_BITMAP,
+ MFT_MENUBARBREAK = MF_MENUBARBREAK,
+ MFT_MENUBREAK = MF_MENUBREAK,
+ MFT_OWNERDRAW = MF_OWNERDRAW,
+ MFT_RADIOCHECK = 0x00000200,
+ MFT_SEPARATOR = MF_SEPARATOR,
+ MFT_RIGHTORDER = 0x00002000,
+ MFT_RIGHTJUSTIFY = MF_RIGHTJUSTIFY,
+
+ MFS_GRAYED = 0x00000003,
+ MFS_DISABLED = MFS_GRAYED,
+ MFS_CHECKED = MF_CHECKED,
+ MFS_HILITE = MF_HILITE,
+ MFS_ENABLED = MF_ENABLED,
+ MFS_UNCHECKED = MF_UNCHECKED,
+ MFS_UNHILITE = MF_UNHILITE,
+ MFS_DEFAULT = MF_DEFAULT,
+ }
+
+ public enum ResourceType : uint
+ {
+ RT_NEWRESOURCE = 0x2000,
+ RT_ERROR = 0x7FFF,
+
+ ///
+ /// Hardware-dependent cursor resource.
+ ///
+ RT_CURSOR = 1,
+
+ ///
+ /// Bitmap resource.
+ ///
+ RT_BITMAP = 2,
+
+ ///
+ /// Hardware-dependent icon resource.
+ ///
+ RT_ICON = 3,
+
+ ///
+ /// Menu resource.
+ ///
+ RT_MENU = 4,
+
+ ///
+ /// Dialog box.
+ ///
+ RT_DIALOG = 5,
+
+ ///
+ /// String-table entry.
+ ///
+ RT_STRING = 6,
+
+ ///
+ /// Font directory resource.
+ ///
+ RT_FONTDIR = 7,
+
+ ///
+ /// Font resource.
+ ///
+ RT_FONT = 8,
+
+ ///
+ /// Accelerator table.
+ ///
+ RT_ACCELERATOR = 9,
+
+ ///
+ /// Application-defined resource (raw data).
+ ///
+ RT_RCDATA = 10,
+
+ ///
+ /// Message-table entry.
+ ///
+ RT_MESSAGETABLE = 11,
+
+ ///
+ /// Hardware-independent cursor resource.
+ ///
+ RT_GROUP_CURSOR = RT_CURSOR + 11,
+
+ ///
+ /// Hardware-independent icon resource.
+ ///
+ RT_GROUP_ICON = RT_ICON + 11,
+
+ ///
+ /// Version resource.
+ ///
+ RT_VERSION = 16,
+
+ ///
+ /// Allows a resource editing tool to associate a string with an .rc file.
+ /// Typically, the string is the name of the header file that provides symbolic
+ /// names. The resource compiler parses the string but otherwise ignores the
+ /// value. For example, `1 DLGINCLUDE "MyFile.h"`
+ ///
+ RT_DLGINCLUDE = 17,
+
+ ///
+ /// Plug and Play resource.
+ ///
+ RT_PLUGPLAY = 19,
+
+ ///
+ /// VXD.
+ ///
+ RT_VXD = 20,
+
+ ///
+ /// Animated cursor.
+ ///
+ RT_ANICURSOR = 21,
+
+ ///
+ /// Animated icon.
+ ///
+ RT_ANIICON = 22,
+
+ ///
+ /// HTML resource.
+ ///
+ RT_HTML = 23,
+
+ ///
+ /// Side-by-Side Assembly Manifest.
+ ///
+ RT_MANIFEST = 24,
+
+ RT_NEWBITMAP = (RT_BITMAP | RT_NEWRESOURCE),
+ RT_NEWMENU = (RT_MENU | RT_NEWRESOURCE),
+ RT_NEWDIALOG = (RT_DIALOG | RT_NEWRESOURCE),
+ }
+
+ public enum SymbolDerivedType : byte
+ {
+ ///
+ /// No derived type; the symbol is a simple scalar variable.
+ ///
+ IMAGE_SYM_DTYPE_NULL = 0x00,
+
+ ///
+ /// The symbol is a pointer to base type.
+ ///
+ IMAGE_SYM_DTYPE_POINTER = 0x01,
+
+ ///
+ /// The symbol is a function that returns a base type.
+ ///
+ IMAGE_SYM_DTYPE_FUNCTION = 0x02,
+
+ ///
+ /// The symbol is an array of base type.
+ ///
+ IMAGE_SYM_DTYPE_ARRAY = 0x03,
+ }
+
+ public enum VersionResourceType : ushort
+ {
+ BinaryData = 0,
+ TextData = 1,
+ }
+
+ [Flags]
+ public enum WindowStyles : uint
+ {
+ #region Standard Styles
+
+ ///
+ /// The window is an overlapped window. An overlapped window has a title
+ /// bar and a border. Same as the WS_TILED style.
+ ///
+ WS_OVERLAPPED = 0x00000000,
+
+ ///
+ /// The window is an overlapped window. An overlapped window has a title bar
+ /// and a border. Same as the WS_OVERLAPPED style.
+ ///
+ WS_TILED = 0x00000000,
+
+ ///
+ /// The window has a maximize button. Cannot be combined with the
+ /// WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified.
+ ///
+ WS_MAXIMIZEBOX = 0x00010000,
+
+ ///
+ /// The window is a control that can receive the keyboard focus when the user
+ /// presses the TAB key. Pressing the TAB key changes the keyboard focus to
+ /// the next control with the WS_TABSTOP style.
+ ///
+ /// You can turn this style on and off to change dialog box navigation. To
+ /// change this style after a window has been created, use the SetWindowLong
+ /// function. For user-created windows and modeless dialogs to work with tab
+ /// stops, alter the message loop to call the IsDialogMessage function.
+ ///
+ WS_TABSTOP = 0x00010000,
+
+ ///
+ /// The window has a minimize button. Cannot be combined with the
+ /// WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified.
+ ///
+ WS_MINIMIZEBOX = 0x00020000,
+
+ ///
+ /// The window is the first control of a group of controls. The group consists
+ /// of this first control and all controls defined after it, up to the next
+ /// control with the WS_GROUP style. The first control in each group usually
+ /// has the WS_TABSTOP style so that the user can move from group to group.
+ /// The user can subsequently change the keyboard focus from one control in
+ /// the group to the next control in the group by using the direction keys.
+ ///
+ /// You can turn this style on and off to change dialog box navigation. To
+ /// change this style after a window has been created, use the SetWindowLong
+ /// function.
+ ///
+ WS_GROUP = 0x00020000,
+
+ ///
+ /// The window has a sizing border. Same as the WS_THICKFRAME style.
+ ///
+ WS_SIZEBOX = 0x00040000,
+
+ ///
+ /// The window has a sizing border. Same as the WS_SIZEBOX style.
+ ///
+ WS_THICKFRAME = 0x00040000,
+
+ ///
+ /// The window has a window menu on its title bar. The WS_CAPTION style must
+ /// also be specified.
+ ///
+ WS_SYSMENU = 0x00080000,
+
+ ///
+ /// The window has a horizontal scroll bar.
+ ///
+ WS_HSCROLL = 0x00100000,
+
+ ///
+ /// The window has a vertical scroll bar.
+ ///
+ WS_VSCROLL = 0x00200000,
+
+ ///
+ /// The window has a border of a style typically used with dialog boxes. A
+ /// window with this style cannot have a title bar.
+ ///
+ WS_DLGFRAME = 0x00400000,
+
+ ///
+ /// The window has a thin-line border
+ ///
+ WS_BORDER = 0x00800000,
+
+ ///
+ /// The window has a title bar
+ ///
+ WS_CAPTION = 0x00C00000,
+
+ ///
+ /// The window is initially maximized.
+ ///
+ WS_MAXIMIZE = 0x01000000,
+
+ ///
+ /// Excludes the area occupied by child windows when drawing occurs within the
+ /// parent window. This style is used when creating the parent window.
+ ///
+ WS_CLIPCHILDREN = 0x02000000,
+
+ ///
+ /// Clips child windows relative to each other; that is, when a particular child
+ /// window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other
+ /// overlapping child windows out of the region of the child window to be updated.
+ /// If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible,
+ /// when drawing within the client area of a child window, to draw within the
+ /// client area of a neighboring child window.
+ ///
+ WS_CLIPSIBLINGS = 0x04000000,
+
+ ///
+ /// The window is initially disabled. A disabled window cannot receive input from
+ /// the user. To change this after a window has been created, use the EnableWindow
+ /// function.
+ ///
+ WS_DISABLED = 0x08000000,
+
+ ///
+ /// The window is initially visible.
+ /// This style can be turned on and off by using the ShowWindow or SetWindowPos
+ /// function.
+ ///
+ WS_VISIBLE = 0x10000000,
+
+ ///
+ /// The window is initially minimized. Same as the WS_MINIMIZE style.
+ ///
+ WS_ICONIC = 0x20000000,
+
+ ///
+ /// The window is initially minimized. Same as the WS_ICONIC style.
+ ///
+ WS_MINIMIZE = 0x20000000,
+
+ ///
+ /// The window is a child window. A window with this style cannot have a menu
+ /// bar. This style cannot be used with the WS_POPUP style.
+ ///
+ WS_CHILD = 0x40000000,
+
+ ///
+ /// Same as the WS_CHILD style.
+ ///
+ WS_CHILDWINDOW = 0x40000000,
+
+ ///
+ /// The window is a pop-up window. This style cannot be used with the WS_CHILD style.
+ ///
+ WS_POPUP = 0x80000000,
+
+ ///
+ /// The window is an overlapped window. Same as the WS_TILEDWINDOW style.
+ ///
+ WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
+
+ ///
+ /// The window is a pop-up window. The WS_CAPTION and WS_POPUPWINDOW styles must be
+ /// combined to make the window menu visible.
+ ///
+ WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
+
+ ///
+ /// The window is an overlapped window. Same as the WS_OVERLAPPEDWINDOW style.
+ ///
+ WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
+
+ #endregion
+
+ #region Common Control Styles
+
+ ///
+ /// Causes the control to position itself at the top of the parent window's
+ /// client area and sets the width to be the same as the parent window's width.
+ /// Toolbars have this style by default.
+ ///
+ CCS_TOP = 0x00000001,
+
+ ///
+ /// Causes the control to resize and move itself horizontally, but not vertically,
+ /// in response to a WM_SIZE message. If CCS_NORESIZE is used, this style does not
+ /// apply. Header windows have this style by default.
+ ///
+ CCS_NOMOVEY = 0x00000002,
+
+ ///
+ /// Causes the control to position itself at the bottom of the parent window's
+ /// client area and sets the width to be the same as the parent window's width.
+ /// Status windows have this style by default.
+ ///
+ CCS_BOTTOM = 0x00000003,
+
+ ///
+ /// Prevents the control from using the default width and height when setting its
+ /// initial size or a new size. Instead, the control uses the width and height
+ /// specified in the request for creation or sizing.
+ ///
+ CCS_NORESIZE = 0x00000004,
+
+ ///
+ /// Prevents the control from automatically moving to the top or bottom of the parent
+ /// window. Instead, the control keeps its position within the parent window despite
+ /// changes to the size of the parent. If CCS_TOP or CCS_BOTTOM is also used, the
+ /// height is adjusted to the default, but the position and width remain unchanged.
+ ///
+ CCS_NOPARENTALIGN = 0x00000008,
+
+ ///
+ /// Enables a toolbar's built-in customization features, which let the user to drag a
+ /// button to a new position or to remove a button by dragging it off the toolbar.
+ /// In addition, the user can double-click the toolbar to display the Customize Toolbar
+ /// dialog box, which enables the user to add, delete, and rearrange toolbar buttons.
+ ///
+ CCS_ADJUSTABLE = 0x00000020,
+
+ ///
+ /// Prevents a two-pixel highlight from being drawn at the top of the control.
+ ///
+ CCS_NODIVIDER = 0x00000040,
+
+ ///
+ /// Version 4.70. Causes the control to be displayed vertically.
+ ///
+ CCS_VERT = 0x00000080,
+
+ ///
+ /// Version 4.70. Causes the control to be displayed vertically on the left side of the
+ /// parent window.
+ ///
+ CCS_LEFT = CCS_VERT | CCS_TOP,
+
+ ///
+ /// Version 4.70. Causes the control to be displayed vertically on the right side of the
+ /// parent window.
+ ///
+ CCS_RIGHT = CCS_VERT | CCS_BOTTOM,
+
+ ///
+ /// Version 4.70. Causes the control to resize and move itself vertically, but not
+ /// horizontally, in response to a WM_SIZE message. If CCS_NORESIZE is used, this style
+ /// does not apply.
+ ///
+ CCS_NOMOVEX = CCS_VERT | CCS_NOMOVEY,
+
+ #endregion
+
+ #region Dialog Box Styles
+
+ ///
+ /// Indicates that the coordinates of the dialog box are screen coordinates.
+ /// If this style is not specified, the coordinates are client coordinates.
+ ///
+ DS_ABSALIGN = 0x00000001,
+
+ ///
+ /// This style is obsolete and is included for compatibility with 16-bit versions
+ /// of Windows. If you specify this style, the system creates the dialog box with
+ /// the WS_EX_TOPMOST style. This style does not prevent the user from accessing
+ /// other windows on the desktop.
+ ///
+ /// Do not combine this style with the DS_CONTROL style.
+ ///
+ DS_SYSMODAL = 0x00000002,
+
+ ///
+ /// Obsolete. The system automatically applies the three-dimensional look to dialog
+ /// boxes created by applications.
+ ///
+ DS_3DLOOK = 0x00000004,
+
+ ///
+ /// Causes the dialog box to use the SYSTEM_FIXED_FONT instead of the default
+ /// SYSTEM_FONT. This is a monospace font compatible with the System font in 16-bit
+ /// versions of Windows earlier than 3.0.
+ ///
+ DS_FIXEDSYS = 0x00000008,
+
+ ///
+ /// Creates the dialog box even if errors occur for example, if a child window cannot
+ /// be created or if the system cannot create a special data segment for an edit control.
+ ///
+ DS_NOFAILCREATE = 0x00000010,
+
+ ///
+ /// Applies to 16-bit applications only. This style directs edit controls in the
+ /// dialog box to allocate memory from the application's data segment. Otherwise,
+ /// edit controls allocate storage from a global memory object.
+ ///
+ DS_LOCALEDIT = 0x00000020,
+
+ ///
+ /// Indicates that the header of the dialog box template (either standard or extended)
+ /// contains additional data specifying the font to use for text in the client area
+ /// and controls of the dialog box. If possible, the system selects a font according
+ /// to the specified font data. The system passes a handle to the font to the dialog
+ /// box and to each control by sending them the WM_SETFONT message. For descriptions
+ /// of the format of this font data, see DLGTEMPLATE and DLGTEMPLATEEX.
+ ///
+ /// If neither DS_SETFONT nor DS_SHELLFONT is specified, the dialog box template does
+ /// not include the font data.
+ ///
+ DS_SETFONT = 0x00000040,
+
+ ///
+ /// Creates a dialog box with a modal dialog-box frame that can be combined with a
+ /// title bar and window menu by specifying the WS_CAPTION and WS_SYSMENU styles.
+ ///
+ DS_MODALFRAME = 0x00000080,
+
+ ///
+ /// Suppresses WM_ENTERIDLE messages that the system would otherwise send to the owner
+ /// of the dialog box while the dialog box is displayed.
+ ///
+ DS_NOIDLEMSG = 0x00000100,
+
+ ///
+ /// Causes the system to use the SetForegroundWindow function to bring the dialog box
+ /// to the foreground. This style is useful for modal dialog boxes that require immediate
+ /// attention from the user regardless of whether the owner window is the foreground
+ /// window.
+ ///
+ /// The system restricts which processes can set the foreground window. For more
+ /// information, see Foreground and Background Windows.
+ ///
+ DS_SETFOREGROUND = 0x00000200,
+
+ ///
+ /// Creates a dialog box that works well as a child window of another dialog box, much like
+ /// a page in a property sheet. This style allows the user to tab among the control windows
+ /// of a child dialog box, use its accelerator keys, and so on.
+ ///
+ DS_CONTROL = 0x00000400,
+
+ ///
+ /// Centers the dialog box in the working area of the monitor that contains the owner window.
+ /// If no owner window is specified, the dialog box is centered in the working area of a
+ /// monitor determined by the system. The working area is the area not obscured by the taskbar
+ /// or any appbars.
+ ///
+ DS_CENTER = 0x00000800,
+
+ ///
+ /// Centers the dialog box on the mouse cursor.
+ ///
+ DS_CENTERMOUSE = 0x00001000,
+
+ ///
+ /// Includes a question mark in the title bar of the dialog box. When the user clicks the
+ /// question mark, the cursor changes to a question mark with a pointer. If the user then clicks
+ /// a control in the dialog box, the control receives a WM_HELP message. The control should pass
+ /// the message to the dialog box procedure, which should call the function using the
+ /// HELP_WM_HELP command. The help application displays a pop-up window that typically contains
+ /// help for the control.
+ ///
+ /// Note that DS_CONTEXTHELP is only a placeholder. When the dialog box is created, the system
+ /// checks for DS_CONTEXTHELP and, if it is there, adds WS_EX_CONTEXTHELP to the extended style
+ /// of the dialog box. WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX
+ /// styles.
+ ///
+ DS_CONTEXTHELP = 0x00002000,
+
+ ///
+ /// Windows CE Version 5.0 and later
+ ///
+ DS_USEPIXELS = 0x00008000,
+
+ ///
+ /// Indicates that the dialog box should use the system font. The typeface member of the extended
+ /// dialog box template must be set to MS Shell Dlg. Otherwise, this style has no effect. It is
+ /// also recommended that you use the DIALOGEX Resource, rather than the DIALOG Resource. For
+ /// more information, see Dialog Box Fonts.
+ ///
+ /// The system selects a font using the font data specified in the pointsize, weight, and italic
+ /// members. The system passes a handle to the font to the dialog box and to each control by
+ /// sending them the WM_SETFONT message. For descriptions of the format of this font data, see
+ /// DLGTEMPLATEEX.
+ ///
+ /// If neither DS_SHELLFONT nor DS_SETFONT is specified, the extended dialog box template does
+ /// not include the font data.
+ ///
+ DS_SHELLFONT = DS_SETFONT | DS_FIXEDSYS,
+
+ #endregion
+ }
+
+ public enum WindowsCertificateRevision : ushort
+ {
+ ///
+ /// Version 1, legacy version of the Win_Certificate structure. It is supported
+ /// only for purposes of verifying legacy Authenticode signatures
+ ///
+ WIN_CERT_REVISION_1_0 = 0x0100,
+
+ ///
+ /// Version 2 is the current version of the Win_Certificate structure.
+ ///
+ WIN_CERT_REVISION_2_0 = 0x0200,
+ }
+
+ public enum WindowsCertificateType : ushort
+ {
+ ///
+ /// bCertificate contains an X.509 Certificate
+ ///
+ ///
+ /// Not Supported
+ ///
+ WIN_CERT_TYPE_X509 = 0x0001,
+
+ ///
+ /// bCertificate contains a PKCS#7 SignedData structure
+ ///
+ WIN_CERT_TYPE_PKCS_SIGNED_DATA = 0x0002,
+
+ ///
+ /// Reserved
+ ///
+ WIN_CERT_TYPE_RESERVED_1 = 0x0003,
+
+ ///
+ /// Terminal Server Protocol Stack Certificate signing
+ ///
+ ///
+ /// Not Supported
+ ///
+ WIN_CERT_TYPE_TS_STACK_SIGNED = 0x0004,
+ }
+
+ public enum WindowsSubsystem : ushort
+ {
+ ///
+ /// An unknown subsystem
+ ///
+ IMAGE_SUBSYSTEM_UNKNOWN = 0x0000,
+
+ ///
+ /// Device drivers and native Windows processes
+ ///
+ IMAGE_SUBSYSTEM_NATIVE = 0x0001,
+
+ ///
+ /// The Windows graphical user interface (GUI) subsystem
+ ///
+ IMAGE_SUBSYSTEM_WINDOWS_GUI = 0x0002,
+
+ ///
+ /// The Windows character subsystem
+ ///
+ IMAGE_SUBSYSTEM_WINDOWS_CUI = 0x0003,
+
+ ///
+ /// The OS/2 character subsystem
+ ///
+ IMAGE_SUBSYSTEM_OS2_CUI = 0x0005,
+
+ ///
+ /// The Posix character subsystem
+ ///
+ IMAGE_SUBSYSTEM_POSIX_CUI = 0x0007,
+
+ ///
+ /// Native Win9x driver
+ ///
+ IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 0x0008,
+
+ ///
+ /// Windows CE
+ ///
+ IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 0x0009,
+
+ ///
+ /// An Extensible Firmware Interface (EFI) application
+ ///
+ IMAGE_SUBSYSTEM_EFI_APPLICATION = 0x000A,
+
+ ///
+ /// An EFI driver with boot services
+ ///
+ IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 0x000B,
+
+ ///
+ /// An EFI driver with run-time services
+ ///
+ IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 0x000C,
+
+ ///
+ /// An EFI ROM image
+ ///
+ IMAGE_SUBSYSTEM_EFI_ROM = 0x000D,
+
+ ///
+ /// XBOX
+ ///
+ IMAGE_SUBSYSTEM_XBOX = 0x000E,
+
+ ///
+ /// Windows boot application.
+ ///
+ IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 0x0010,
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Executable.cs b/SabreTools.Serialization/Models/PortableExecutable/Executable.cs
new file mode 100644
index 00000000..5cc08440
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Executable.cs
@@ -0,0 +1,250 @@
+using System.Collections.Generic;
+
+namespace SabreTools.Serialization.Models.PortableExecutable
+{
+ ///
+ /// The following list describes the Microsoft PE executable format, with the
+ /// base of the image header at the top. The section from the MS-DOS 2.0
+ /// Compatible EXE Header through to the unused section just before the PE header
+ /// is the MS-DOS 2.0 Section, and is used for MS-DOS compatibility only.
+ ///
+ ///
+ public sealed class Executable
+ {
+ ///
+ /// MS-DOS executable stub
+ ///
+ public MSDOS.Executable? Stub { get; set; }
+
+ ///
+ /// After the MS-DOS stub, at the file offset specified at offset 0x3c, is a 4-byte
+ /// signature that identifies the file as a PE format image file. This signature is "PE\0\0"
+ /// (the letters "P" and "E" followed by two null bytes).
+ ///
+ public string? Signature { get; set; }
+
+ ///
+ /// File header
+ ///
+ public COFF.FileHeader? FileHeader { get; set; }
+
+ ///
+ /// Microsoft extended optional header
+ ///
+ public OptionalHeader? OptionalHeader { get; set; }
+
+ ///
+ /// Section table
+ ///
+ public COFF.SectionHeader[]? SectionTable { get; set; }
+
+ ///
+ /// Symbol table
+ ///
+ public COFF.SymbolTableEntries.BaseEntry[]? SymbolTable { get; set; }
+
+ ///
+ /// String table
+ ///
+ public COFF.StringTable? StringTable { get; set; }
+
+ #region Data Directories
+
+ ///
+ /// The export data section, named .edata, contains information about symbols that other images
+ /// can access through dynamic linking. Exported symbols are generally found in DLLs, but DLLs
+ /// can also import symbols.
+ ///
+ /// An overview of the general structure of the export section is described below. The tables
+ /// described are usually contiguous in the file in the order shown (though this is not
+ /// required). Only the export directory table and export address table are required to export
+ /// symbols as ordinals. (An ordinal is an export that is accessed directly by its export
+ /// address table index.) The name pointer table, ordinal table, and export name table all
+ /// exist to support use of export names.
+ ///
+ ///
+ #region Export Table (.edata)
+
+ ///
+ /// A table with just one row (unlike the debug directory). This table indicates the
+ /// locations and sizes of the other export tables.
+ ///
+ public Export.DirectoryTable? ExportDirectoryTable { get; set; }
+
+ ///
+ /// An array of RVAs of exported symbols. These are the actual addresses of the exported
+ /// functions and data within the executable code and data sections. Other image files
+ /// can import a symbol by using an index to this table (an ordinal) or, optionally, by
+ /// using the public name that corresponds to the ordinal if a public name is defined.
+ ///
+ public Export.AddressTableEntry[]? ExportAddressTable { get; set; }
+
+ ///
+ /// An array of pointers to the public export names, sorted in ascending order.
+ ///
+ public Export.NamePointerTable? NamePointerTable { get; set; }
+
+ ///
+ /// An array of the ordinals that correspond to members of the name pointer table. The
+ /// correspondence is by position; therefore, the name pointer table and the ordinal table
+ /// must have the same number of members. Each ordinal is an index into the export address
+ /// table.
+ ///
+ public Export.OrdinalTable? OrdinalTable { get; set; }
+
+ ///
+ /// A series of null-terminated ASCII strings. Members of the name pointer table point into
+ /// this area. These names are the public names through which the symbols are imported and
+ /// exported; they are not necessarily the same as the private names that are used within
+ /// the image file.
+ ///
+ public Export.NameTable? ExportNameTable { get; set; }
+
+ #endregion
+
+ ///
+ /// All image files that import symbols, including virtually all executable (EXE) files,
+ /// have an .idata section. A typical file layout for the import information follows:
+ ///
+ /// - Directory Table
+ /// Null Directory Entry
+ /// - DLL1 Import Lookup Table
+ /// Null
+ /// - DLL2 Import Lookup Table
+ /// Null
+ /// - DLL3 Import Lookup Table
+ /// Null
+ /// - Hint-Name Table
+ ///
+ ///
+ #region Import Table (.idata) and Import Address Table
+
+ ///
+ /// The import information begins with the import directory table, which describes the
+ /// remainder of the import information.
+ ///
+ public Import.DirectoryTableEntry[]? ImportDirectoryTable { get; set; }
+
+ ///
+ /// An import lookup table is an array of 32-bit numbers for PE32 or an array of 64-bit
+ /// numbers for PE32+.
+ ///
+ public Dictionary? ImportLookupTables { get; set; }
+
+ ///
+ /// These addresses are the actual memory addresses of the symbols, although technically
+ /// they are still called "virtual addresses".
+ ///
+ public Dictionary? ImportAddressTables { get; set; }
+
+ ///
+ /// One hint/name table suffices for the entire import section.
+ ///
+ public Import.HintNameTableEntry[]? HintNameTable { get; set; }
+
+ #endregion
+
+ #region Resource Table (.rsrc)
+
+ ///
+ /// Resource directory table (.rsrc)
+ ///
+ public Resource.DirectoryTable? ResourceDirectoryTable { get; set; }
+
+ #endregion
+
+ // TODO: Handle Exception Table
+
+ #region Certificate Table
+
+ ///
+ /// Attribute certificate table
+ ///
+ public AttributeCertificate.Entry[]? AttributeCertificateTable { get; set; }
+
+ #endregion
+
+ #region Base Relocation Table (.reloc)
+
+ ///
+ /// Base relocation table
+ ///
+ public BaseRelocation.Block[]? BaseRelocationTable { get; set; }
+
+ #endregion
+
+ #region Debug Data (.debug*)
+
+ ///
+ /// Debug table
+ ///
+ public DebugData.Table? DebugTable { get; set; }
+
+ #endregion
+
+ // TODO: Handle Architecture
+ // TODO: Handle Global Ptr
+ // TODO: Thread Local Storage (.tls)
+ // TODO: Load Configuration Table
+ // TODO: Bound Import Table
+
+ #region Delay Load Table
+
+ ///
+ /// Delay-load directory table
+ ///
+ public DelayLoad.DirectoryTable? DelayLoadDirectoryTable { get; set; }
+
+ #endregion
+
+ // TODO: CLR Runtime Header (.cormeta)
+ // TODO: Reserved
+
+ #endregion
+
+ #region Named Sections
+
+ // TODO: Support grouped sections in section reading and parsing
+ // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#grouped-sections-object-only
+ // Grouped sections are ordered and mean that the data in the sections contributes
+ // to the "base" section (the one without the "$X" suffix). This may negatively impact
+ // the use of some of the different types of executables.
+
+ // .cormeta - CLR metadata is stored in this section. It is used to indicate that
+ // the object file contains managed code. The format of the metadata is not
+ // documented, but can be handed to the CLR interfaces for handling metadata.
+
+ // .drectve - A section is a directive section if it has the IMAGE_SCN_LNK_INFO
+ // flag set in the section header and has the .drectve section name. The linker
+ // removes a .drectve section after processing the information, so the section
+ // does not appear in the image file that is being linked.
+ //
+ // A .drectve section consists of a string of text that can be encoded as ANSI
+ // or UTF-8. If the UTF-8 byte order marker (BOM, a three-byte prefix that
+ // consists of 0xEF, 0xBB, and 0xBF) is not present, the directive string is
+ // interpreted as ANSI. The directive string is a series of linker options that
+ // are separated by spaces. Each option contains a hyphen, the option name, and
+ // any appropriate attribute. If an option contains spaces, the option must be
+ // enclosed in quotes. The .drectve section must not have relocations or line
+ // numbers.
+ //
+ // TODO: Can we implement reading/parsing the .drectve section?
+
+ // .pdata Section - Multiple formats per entry
+
+ // .sxdata - The valid exception handlers of an object are listed in the .sxdata
+ // section of that object. The section is marked IMAGE_SCN_LNK_INFO. It contains
+ // the COFF symbol index of each valid handler, using 4 bytes per index.
+ //
+ // Additionally, the compiler marks a COFF object as registered SEH by emitting
+ // the absolute symbol "@feat.00" with the LSB of the value field set to 1. A
+ // COFF object with no registered SEH handlers would have the "@feat.00" symbol,
+ // but no .sxdata section.
+ //
+ // TODO: Can we implement reading/parsing the .sxdata section?
+
+ #endregion
+
+ // TODO: Determine if "Archive (Library) File Format" is worth modelling
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Export/AddressTableEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Export/AddressTableEntry.cs
new file mode 100644
index 00000000..733f2d4e
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Export/AddressTableEntry.cs
@@ -0,0 +1,37 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Export
+{
+ ///
+ /// The export address table contains the address of exported entry points
+ /// and exported data and absolutes. An ordinal number is used as an index
+ /// into the export address table.
+ ///
+ /// Each entry in the export address table is a field that uses one of two
+ /// formats in the following table. If the address specified is not within
+ /// the export section (as defined by the address and length that are
+ /// indicated in the optional header), the field is an export RVA, which is
+ /// an actual address in code or data. Otherwise, the field is a forwarder RVA,
+ /// which names a symbol in another DLL.
+ ///
+ ///
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class AddressTableEntry
+ {
+ ///
+ /// The address of the exported symbol when loaded into memory, relative to
+ /// the image base. For example, the address of an exported function.
+ ///
+ [FieldOffset(0)] public uint ExportRVA;
+
+ ///
+ /// The pointer to a null-terminated ASCII string in the export section. This
+ /// string must be within the range that is given by the export table data
+ /// directory entry. See Optional Header Data Directories (Image Only). This
+ /// string gives the DLL name and the name of the export (for example,
+ /// "MYDLL.expfunc") or the DLL name and the ordinal number of the export
+ /// (for example, "MYDLL.#27").
+ ///
+ [FieldOffset(0)] public uint ForwarderRVA;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Export/DirectoryTable.cs b/SabreTools.Serialization/Models/PortableExecutable/Export/DirectoryTable.cs
new file mode 100644
index 00000000..a4dbe79d
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Export/DirectoryTable.cs
@@ -0,0 +1,78 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Export
+{
+ ///
+ /// The export symbol information begins with the export directory table,
+ /// which describes the remainder of the export symbol information. The
+ /// export directory table contains address information that is used to resolve
+ /// imports to the entry points within this image.
+ ///
+ ///
+ public sealed class DirectoryTable
+ {
+ ///
+ /// Reserved, must be 0.
+ ///
+ public uint ExportFlags { get; set; }
+
+ ///
+ /// The time and date that the export data was created.
+ ///
+ public uint TimeDateStamp { get; set; }
+
+ ///
+ /// The major version number. The major and minor version numbers can be set
+ /// by the user.
+ ///
+ public ushort MajorVersion { get; set; }
+
+ ///
+ /// The minor version number.
+ ///
+ public ushort MinorVersion { get; set; }
+
+ ///
+ /// The address of the ASCII string that contains the name of the DLL. This
+ /// address is relative to the image base.
+ ///
+ public uint NameRVA { get; set; }
+
+ ///
+ /// ASCII string that contains the name of the DLL.
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// The starting ordinal number for exports in this image. This field specifies
+ /// the starting ordinal number for the export address table. It is usually set
+ /// to 1.
+ ///
+ public uint OrdinalBase { get; set; }
+
+ ///
+ /// The number of entries in the export address table.
+ ///
+ public uint AddressTableEntries { get; set; }
+
+ ///
+ /// The number of entries in the name pointer table. This is also the number of
+ /// entries in the ordinal table.
+ ///
+ public uint NumberOfNamePointers { get; set; }
+
+ ///
+ /// The address of the export address table, relative to the image base.
+ ///
+ public uint ExportAddressTableRVA { get; set; }
+
+ ///
+ /// The address of the export name pointer table, relative to the image base.
+ /// The table size is given by the Number of Name Pointers field.
+ ///
+ public uint NamePointerRVA { get; set; }
+
+ ///
+ /// The address of the ordinal table, relative to the image base.
+ ///
+ public uint OrdinalTableRVA { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Export/NamePointerTable.cs b/SabreTools.Serialization/Models/PortableExecutable/Export/NamePointerTable.cs
new file mode 100644
index 00000000..108b4768
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Export/NamePointerTable.cs
@@ -0,0 +1,18 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Export
+{
+ ///
+ /// The export name pointer table is an array of addresses (RVAs) into the export name table.
+ /// The pointers are 32 bits each and are relative to the image base. The pointers are ordered
+ /// lexically to allow binary searches.
+ ///
+ /// An export name is defined only if the export name pointer table contains a pointer to it.
+ ///
+ ///
+ public sealed class NamePointerTable
+ {
+ ///
+ /// The pointers are 32 bits each and are relative to the image base.
+ ///
+ public uint[]? Pointers { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Export/NameTable.cs b/SabreTools.Serialization/Models/PortableExecutable/Export/NameTable.cs
new file mode 100644
index 00000000..cf8dc35c
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Export/NameTable.cs
@@ -0,0 +1,27 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Export
+{
+ ///
+ /// The export name table contains the actual string data that was pointed to by the export
+ /// name pointer table. The strings in this table are public names that other images can use
+ /// to import the symbols. These public export names are not necessarily the same as the
+ /// private symbol names that the symbols have in their own image file and source code,
+ /// although they can be.
+ ///
+ /// Every exported symbol has an ordinal value, which is just the index into the export
+ /// address table. Use of export names, however, is optional. Some, all, or none of the
+ /// exported symbols can have export names. For exported symbols that do have export names,
+ /// corresponding entries in the export name pointer table and export ordinal table work
+ /// together to associate each name with an ordinal.
+ ///
+ /// The structure of the export name table is a series of null-terminated ASCII strings
+ /// of variable length.
+ ///
+ ///
+ public sealed class NameTable
+ {
+ ///
+ /// A series of null-terminated ASCII strings of variable length.
+ ///
+ public string[]? Strings { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Export/OrdinalTable.cs b/SabreTools.Serialization/Models/PortableExecutable/Export/OrdinalTable.cs
new file mode 100644
index 00000000..1e189490
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Export/OrdinalTable.cs
@@ -0,0 +1,42 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Export
+{
+ ///
+ /// The export ordinal table is an array of 16-bit unbiased indexes into the export address table.
+ /// Ordinals are biased by the Ordinal Base field of the export directory table. In other words,
+ /// the ordinal base must be subtracted from the ordinals to obtain true indexes into the export
+ /// address table.
+ ///
+ /// The export name pointer table and the export ordinal table form two parallel arrays that are
+ /// separated to allow natural field alignment. These two tables, in effect, operate as one table,
+ /// in which the Export Name Pointer column points to a public (exported) name and the Export
+ /// Ordinal column gives the corresponding ordinal for that public name. A member of the export
+ /// name pointer table and a member of the export ordinal table are associated by having the same
+ /// position (index) in their respective arrays.
+ ///
+ /// Thus, when the export name pointer table is searched and a matching string is found at position
+ /// i, the algorithm for finding the symbol's RVA and biased ordinal is:
+ ///
+ /// i = Search_ExportNamePointerTable(name);
+ /// ordinal = ExportOrdinalTable[i];
+ ///
+ /// rva = ExportAddressTable[ordinal];
+ /// biased_ordinal = ordinal + OrdinalBase;
+ ///
+ /// When searching for a symbol by(biased) ordinal, the algorithm for finding the symbol's RVA
+ /// and name is:
+ ///
+ /// ordinal = biased_ordinal - OrdinalBase;
+ /// i = Search_ExportOrdinalTable(ordinal);
+ ///
+ /// rva = ExportAddressTable[ordinal];
+ /// name = ExportNameTable[i];
+ ///
+ ///
+ public sealed class OrdinalTable
+ {
+ ///
+ /// An array of 16-bit unbiased indexes into the export address table
+ ///
+ public ushort[]? Indexes { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Import/AddressTableEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Import/AddressTableEntry.cs
new file mode 100644
index 00000000..5d51c0b4
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Import/AddressTableEntry.cs
@@ -0,0 +1,36 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Import
+{
+ ///
+ /// The structure and content of the import address table are identical to those of
+ /// the import lookup table, until the file is bound. During binding, the entries in
+ /// the import address table are overwritten with the 32-bit (for PE32) or 64-bit
+ /// (for PE32+) addresses of the symbols that are being imported. These addresses are
+ /// the actual memory addresses of the symbols, although technically they are still
+ /// called "virtual addresses." The loader typically processes the binding.
+ ///
+ ///
+ public sealed class AddressTableEntry
+ {
+ ///
+ /// If this bit is set, import by ordinal. Otherwise, import by name. Bit is
+ /// masked as 0x80000000 for PE32, 0x8000000000000000 for PE32+.
+ ///
+ /// Bit 31/63
+ public bool OrdinalNameFlag { get; set; }
+
+ ///
+ /// A 16-bit ordinal number. This field is used only if the Ordinal/Name Flag
+ /// bit field is 1 (import by ordinal). Bits 30-15 or 62-15 must be 0.
+ ///
+ /// Bits 15-0
+ public ushort OrdinalNumber { get; set; }
+
+ ///
+ /// A 31-bit RVA of a hint/name table entry. This field is used only if the
+ /// Ordinal/Name Flag bit field is 0 (import by name). For PE32+ bits 62-31
+ /// must be zero.
+ ///
+ /// Bits 30-0
+ public uint HintNameTableRVA { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Import/DirectoryTableEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Import/DirectoryTableEntry.cs
new file mode 100644
index 00000000..ae26b6ea
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Import/DirectoryTableEntry.cs
@@ -0,0 +1,50 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Import
+{
+ ///
+ /// The import information begins with the import directory table, which
+ /// describes the remainder of the import information. The import directory
+ /// table contains address information that is used to resolve fixup references
+ /// to the entry points within a DLL image. The import directory table consists
+ /// of an array of import directory entries, one entry for each DLL to which
+ /// the image refers. The last directory entry is empty (filled with null values),
+ /// which indicates the end of the directory table.
+ ///
+ ///
+ public sealed class DirectoryTableEntry
+ {
+ ///
+ /// The RVA of the import lookup table. This table contains a name or ordinal
+ /// for each import. (The name "Characteristics" is used in Winnt.h, but no
+ /// longer describes this field.)
+ ///
+ public uint ImportLookupTableRVA { get; set; }
+
+ ///
+ /// The stamp that is set to zero until the image is bound. After the image is
+ /// bound, this field is set to the time/data stamp of the DLL.
+ ///
+ public uint TimeDateStamp { get; set; }
+
+ ///
+ /// The index of the first forwarder reference.
+ ///
+ public uint ForwarderChain { get; set; }
+
+ ///
+ /// The address of an ASCII string that contains the name of the DLL. This address
+ /// is relative to the image base.
+ ///
+ public uint NameRVA { get; set; }
+
+ ///
+ /// ASCII string that contains the name of the DLL.
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// The RVA of the import address table. The contents of this table are identical
+ /// to the contents of the import lookup table until the image is bound.
+ ///
+ public uint ImportAddressTableRVA { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Import/HintNameTableEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Import/HintNameTableEntry.cs
new file mode 100644
index 00000000..50958e9e
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Import/HintNameTableEntry.cs
@@ -0,0 +1,27 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Import
+{
+ ///
+ /// One hint/name table suffices for the entire import section.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class HintNameTableEntry
+ {
+ ///
+ /// An index into the export name pointer table. A match is attempted first
+ /// with this value. If it fails, a binary search is performed on the DLL's
+ /// export name pointer table.
+ ///
+ public ushort Hint;
+
+ ///
+ /// An ASCII string that contains the name to import. This is the string that
+ /// must be matched to the public name in the DLL. This string is case sensitive
+ /// and terminated by a null byte.
+ ///
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string? Name;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Import/LookupTableEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Import/LookupTableEntry.cs
new file mode 100644
index 00000000..2179e071
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Import/LookupTableEntry.cs
@@ -0,0 +1,36 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Import
+{
+ ///
+ /// An import lookup table is an array of 32-bit numbers for PE32 or an array of
+ /// 64-bit numbers for PE32+. Each entry uses the bit-field format that is described
+ /// in the following table. In this format, bit 31 is the most significant bit for
+ /// PE32 and bit 63 is the most significant bit for PE32+. The collection of these
+ /// entries describes all imports from a given DLL. The last entry is set to zero
+ /// (NULL) to indicate the end of the table.
+ ///
+ ///
+ public sealed class LookupTableEntry
+ {
+ ///
+ /// If this bit is set, import by ordinal. Otherwise, import by name. Bit is
+ /// masked as 0x80000000 for PE32, 0x8000000000000000 for PE32+.
+ ///
+ /// Bit 31/63
+ public bool OrdinalNameFlag { get; set; }
+
+ ///
+ /// A 16-bit ordinal number. This field is used only if the Ordinal/Name Flag
+ /// bit field is 1 (import by ordinal). Bits 30-15 or 62-15 must be 0.
+ ///
+ /// Bits 15-0
+ public ushort OrdinalNumber { get; set; }
+
+ ///
+ /// A 31-bit RVA of a hint/name table entry. This field is used only if the
+ /// Ordinal/Name Flag bit field is 0 (import by name). For PE32+ bits 62-31
+ /// must be zero.
+ ///
+ /// Bits 30-0
+ public uint HintNameTableRVA { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/LoadConfiguration/Directory.cs b/SabreTools.Serialization/Models/PortableExecutable/LoadConfiguration/Directory.cs
new file mode 100644
index 00000000..f1af9a8d
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/LoadConfiguration/Directory.cs
@@ -0,0 +1,189 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.LoadConfiguration
+{
+ ///
+ /// The data directory entry for a pre-reserved SEH load configuration
+ /// structure must specify a particular size of the load configuration
+ /// structure because the operating system loader always expects it to
+ /// be a certain value. In that regard, the size is really only a
+ /// version check. For compatibility with Windows XP and earlier versions
+ /// of Windows, the size must be 64 for x86 images.
+ ///
+ ///
+ public sealed class Directory
+ {
+ ///
+ /// Flags that indicate attributes of the file, currently unused.
+ ///
+ public uint Characteristics { get; set; }
+
+ ///
+ /// Date and time stamp value. The value is represented in the number of
+ /// seconds that have elapsed since midnight (00:00:00), January 1, 1970,
+ /// Universal Coordinated Time, according to the system clock. The time
+ /// stamp can be printed by using the C runtime (CRT) time function.
+ ///
+ public uint TimeDateStamp { get; set; }
+
+ ///
+ /// Major version number.
+ ///
+ public ushort MajorVersion { get; set; }
+
+ ///
+ /// Minor version number.
+ ///
+ public ushort MinorVersion { get; set; }
+
+ ///
+ /// The global loader flags to clear for this process as the loader starts
+ /// the process.
+ ///
+ public uint GlobalFlagsClear { get; set; }
+
+ ///
+ /// The global loader flags to set for this process as the loader starts
+ /// the process.
+ ///
+ public uint GlobalFlagsSet { get; set; }
+
+ ///
+ /// Memory that must be freed before it is returned to the system, in bytes.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong DeCommitFreeBlockThreshold { get; set; }
+
+ ///
+ /// Total amount of free memory, in bytes.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong DeCommitTotalFreeThreshold { get; set; }
+
+ ///
+ /// [x86 only] The VA of a list of addresses where the LOCK prefix is used so
+ /// that they can be replaced with NOP on single processor machines.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong LockPrefixTable { get; set; }
+
+ ///
+ /// Maximum allocation size, in bytes.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong MaximumAllocationSize { get; set; }
+
+ ///
+ /// Maximum virtual memory size, in bytes.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong VirtualMemoryThreshold { get; set; }
+
+ ///
+ /// Setting this field to a non-zero value is equivalent to calling
+ /// SetProcessAffinityMask with this value during process startup (.exe only)
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong ProcessAffinityMask { get; set; }
+
+ ///
+ /// Process heap flags that correspond to the first argument of the
+ /// HeapCreate function. These flags apply to the process heap that
+ /// is created during process startup.
+ ///
+ public uint ProcessHeapFlags { get; set; }
+
+ ///
+ /// The service pack version identifier.
+ ///
+ public ushort CSDVersion { get; set; }
+
+ ///
+ /// Must be zero.
+ ///
+ public ushort Reserved { get; set; }
+
+ ///
+ /// Reserved for use by the system.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong EditList { get; set; }
+
+ //
+ /// A pointer to a cookie that is used by Visual C++ or GS implementation.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong SecurityCookie { get; set; }
+
+ ///
+ /// [x86 only] The VA of the sorted table of RVAs of each valid, unique
+ /// SE handler in the image.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong SEHandlerTable { get; set; }
+
+ ///
+ /// [x86 only] The count of unique handlers in the table.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong SEHandlerCount { get; set; }
+
+ ///
+ /// The VA where Control Flow Guard check-function pointer is stored.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong GuardCFCheckFunctionPointer { get; set; }
+
+ ///
+ /// The VA where Control Flow Guard dispatch-function pointer is stored.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong GuardCFDispatchFunctionPointer { get; set; }
+
+ ///
+ /// The VA of the sorted table of RVAs of each Control Flow Guard
+ /// function in the image.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong GuardCFFunctionTable { get; set; }
+
+ ///
+ /// The count of unique RVAs in the above table.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong GuardCFFunctionCount { get; set; }
+
+ ///
+ /// Control Flow Guard related flags.
+ ///
+ public GuardFlags GuardFlags { get; set; }
+
+ ///
+ /// Code integrity information.
+ ///
+ /// 12 bytes
+ public byte[]? CodeIntegrity { get; set; }
+
+ ///
+ /// The VA where Control Flow Guard address taken IAT table is stored.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong GuardAddressTakenIatEntryTable { get; set; }
+
+ ///
+ /// The count of unique RVAs in the above table.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong GuardAddressTakenIatEntryCount { get; set; }
+
+ ///
+ /// The VA where Control Flow Guard long jump target table is stored.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong GuardLongJumpTargetTable { get; set; }
+
+ ///
+ /// The count of unique RVAs in the above table.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong GuardLongJumpTargetCount { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/OptionalHeader.cs b/SabreTools.Serialization/Models/PortableExecutable/OptionalHeader.cs
new file mode 100644
index 00000000..f947f436
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/OptionalHeader.cs
@@ -0,0 +1,245 @@
+namespace SabreTools.Serialization.Models.PortableExecutable
+{
+ ///
+ /// Every image file has an optional header that provides information to the loader.
+ /// This header is optional in the sense that some files (specifically, object files)
+ /// do not have it. For image files, this header is required. An object file can have
+ /// an optional header, but generally this header has no function in an object file
+ /// except to increase its size.
+ ///
+ /// Note that the size of the optional header is not fixed. The SizeOfOptionalHeader
+ /// field in the COFF header must be used to validate that a probe into the file for
+ /// a particular data directory does not go beyond SizeOfOptionalHeader.
+ ///
+ /// The NumberOfRvaAndSizes field of the optional header should also be used to ensure
+ /// that no probe for a particular data directory entry goes beyond the optional header.
+ /// In addition, it is important to validate the optional header magic number for format
+ /// compatibility.
+ ///
+ /// The optional header magic number determines whether an image is a PE32 or
+ /// PE32+ executable.
+ ///
+ /// PE32+ images allow for a 64-bit address space while limiting the image size to
+ /// 2 gigabytes. Other PE32+ modifications are addressed in their respective sections.
+ ///
+ /// The first eight fields of the optional header are standard fields that are defined
+ /// for every implementation of COFF. These fields contain general information that is
+ /// useful for loading and running an executable file. They are unchanged for the
+ /// PE32+ format.
+ ///
+ ///
+ public sealed class OptionalHeader : COFF.OptionalHeader
+ {
+ ///
+ /// The preferred address of the first byte of image when loaded into memory { get; set; }
+ /// must be a multiple of 64 K. The default for DLLs is 0x10000000. The default
+ /// for Windows CE EXEs is 0x00010000. The default for Windows NT, Windows 2000,
+ /// Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong ImageBase { get; set; }
+
+ ///
+ /// The alignment (in bytes) of sections when they are loaded into memory. It must
+ /// be greater than or equal to FileAlignment. The default is the page size for
+ /// the architecture.
+ ///
+ public uint SectionAlignment { get; set; }
+
+ ///
+ /// The alignment factor (in bytes) that is used to align the raw data of sections
+ /// in the image file. The value should be a power of 2 between 512 and 64 K,
+ /// inclusive. The default is 512. If the SectionAlignment is less than the
+ /// architecture's page size, then FileAlignment must match SectionAlignment.
+ ///
+ public uint FileAlignment { get; set; }
+
+ ///
+ /// The major version number of the required operating system.
+ ///
+ public ushort MajorOperatingSystemVersion { get; set; }
+
+ ///
+ /// The minor version number of the required operating system.
+ ///
+ public ushort MinorOperatingSystemVersion { get; set; }
+
+ ///
+ /// The major version number of the image.
+ ///
+ public ushort MajorImageVersion { get; set; }
+
+ ///
+ /// The minor version number of the image.
+ ///
+ public ushort MinorImageVersion { get; set; }
+
+ ///
+ /// The major version number of the subsystem.
+ ///
+ public ushort MajorSubsystemVersion { get; set; }
+
+ ///
+ /// The minor version number of the subsystem.
+ ///
+ public ushort MinorSubsystemVersion { get; set; }
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ public uint Win32VersionValue { get; set; }
+
+ ///
+ /// The size (in bytes) of the image, including all headers, as the image
+ /// is loaded in memory. It must be a multiple of SectionAlignment.
+ ///
+ public uint SizeOfImage { get; set; }
+
+ ///
+ /// The combined size of an MS-DOS stub, PE header, and section headers rounded
+ /// up to a multiple of FileAlignment.
+ ///
+ public uint SizeOfHeaders { get; set; }
+
+ ///
+ /// The image file checksum. The algorithm for computing the checksum is
+ /// incorporated into IMAGHELP.DLL. The following are checked for validation at
+ /// load time: all drivers, any DLL loaded at boot time, and any DLL that is
+ /// loaded into a critical Windows process.
+ ///
+ public uint CheckSum { get; set; }
+
+ ///
+ /// The subsystem that is required to run this image.
+ ///
+ public WindowsSubsystem Subsystem { get; set; }
+
+ ///
+ /// DLL characteristics
+ ///
+ public DllCharacteristics DllCharacteristics { get; set; }
+
+ ///
+ /// The size of the stack to reserve. Only SizeOfStackCommit is committed; the rest
+ /// is made available one page at a time until the reserve size is reached.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong SizeOfStackReserve { get; set; }
+
+ ///
+ /// The size of the stack to commit.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong SizeOfStackCommit { get; set; }
+
+ ///
+ /// The size of the local heap space to reserve. Only SizeOfHeapCommit is
+ /// committed; the rest is made available one page at a time until the reserve
+ /// size is reached.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong SizeOfHeapReserve { get; set; }
+
+ ///
+ /// The size of the local heap space to commit.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong SizeOfHeapCommit { get; set; }
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ public uint LoaderFlags { get; set; }
+
+ ///
+ /// The number of data-directory entries in the remainder of the optional header.
+ /// Each describes a location and size.
+ ///
+ public uint NumberOfRvaAndSizes { get; set; }
+
+ #region Data Directories (Image Only)
+
+ ///
+ /// The export table address and size.
+ ///
+ public DataDirectory? ExportTable { get; set; }
+
+ ///
+ /// The import table address and size.
+ ///
+ public DataDirectory? ImportTable { get; set; }
+
+ ///
+ /// The resource table address and size.
+ ///
+ public DataDirectory? ResourceTable { get; set; }
+
+ ///
+ /// The exception table address and size.
+ ///
+ public DataDirectory? ExceptionTable { get; set; }
+
+ ///
+ /// The attribute certificate table address and size.
+ ///
+ public DataDirectory? CertificateTable { get; set; }
+
+ ///
+ /// The base relocation table address and size.
+ ///
+ public DataDirectory? BaseRelocationTable { get; set; }
+
+ ///
+ /// The debug data starting address and size.
+ ///
+ public DataDirectory? Debug { get; set; }
+
+ ///
+ /// Reserved, must be 0
+ ///
+ public ulong Architecture { get; set; }
+
+ ///
+ /// The RVA of the value to be stored in the global pointer register.
+ /// The size member of this structure must be set to zero.
+ ///
+ public DataDirectory? GlobalPtr { get; set; }
+
+ ///
+ /// The thread local storage (TLS) table address and size.
+ ///
+ public DataDirectory? ThreadLocalStorageTable { get; set; }
+
+ ///
+ /// The load configuration table address and size.
+ ///
+ public DataDirectory? LoadConfigTable { get; set; }
+
+ ///
+ /// The bound import table address and size.
+ ///
+ public DataDirectory? BoundImport { get; set; }
+
+ ///
+ /// The import address table address and size
+ ///
+ public DataDirectory? ImportAddressTable { get; set; }
+
+ ///
+ /// The delay import descriptor address and size.
+ ///
+ public DataDirectory? DelayImportDescriptor { get; set; }
+
+ ///
+ /// The CLR runtime header address and size.
+ ///
+ public DataDirectory? CLRRuntimeHeader { get; set; }
+
+ ///
+ /// Reserved, must be zero
+ ///
+ public ulong Reserved { get; set; }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/DataEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/DataEntry.cs
new file mode 100644
index 00000000..b0b6c8ce
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/DataEntry.cs
@@ -0,0 +1,40 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource
+{
+ ///
+ /// The resource directory string area consists of Unicode strings, which
+ /// are word-aligned. These strings are stored together after the last
+ /// Resource Directory entry and before the first Resource Data entry.
+ /// This minimizes the impact of these variable-length strings on the
+ /// alignment of the fixed-size directory entries.
+ ///
+ ///
+ public sealed class DataEntry
+ {
+ ///
+ /// The address of a unit of resource data in the Resource Data area.
+ ///
+ public uint DataRVA { get; set; }
+
+ ///
+ /// The size, in bytes, of the resource data that is pointed to by the
+ /// Data RVA field.
+ ///
+ public uint Size { get; set; }
+
+ ///
+ /// The resource data that is pointed to by the Data RVA field.
+ ///
+ public byte[]? Data { get; set; }
+
+ ///
+ /// The code page that is used to decode code point values within the
+ /// resource data. Typically, the code page would be the Unicode code page.
+ ///
+ public uint Codepage { get; set; }
+
+ ///
+ /// Reserved, must be 0.
+ ///
+ public uint Reserved { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryEntry.cs
new file mode 100644
index 00000000..47f7cd0b
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryEntry.cs
@@ -0,0 +1,68 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource
+{
+ ///
+ /// A leaf's Type, Name, and Language IDs are determined by the path that is
+ /// taken through directory tables to reach the leaf. The first table
+ /// determines Type ID, the second table (pointed to by the directory entry
+ /// in the first table) determines Name ID, and the third table determines
+ /// Language ID.
+ ///
+ /// The directory entries make up the rows of a table. Each resource directory
+ /// entry has the following format. Whether the entry is a Name or ID entry
+ /// is indicated by the resource directory table, which indicates how many
+ /// Name and ID entries follow it (remember that all the Name entries precede
+ /// all the ID entries for the table). All entries for the table are sorted
+ /// in ascending order: the Name entries by case-sensitive string and the ID
+ /// entries by numeric value. Offsets are relative to the address in the
+ /// IMAGE_DIRECTORY_ENTRY_RESOURCE DataDirectory.
+ ///
+ ///
+ public sealed class DirectoryEntry
+ {
+ #region Offset 0x00
+
+ ///
+ /// The offset of a string that gives the Type, Name, or Language ID entry,
+ /// depending on level of table.
+ ///
+ public uint NameOffset { get; set; }
+
+ ///
+ /// A string that gives the Type, Name, or Language ID entry, depending on
+ /// level of table.
+ ///
+ public DirectoryString? Name { get; set; }
+
+ ///
+ /// A 32-bit integer that identifies the Type, Name, or Language ID entry.
+ ///
+ public uint IntegerID { get; set; }
+
+ #endregion
+
+ #region Offset 0x04
+
+ ///
+ /// High bit 0. Address of a Resource Data entry (a leaf).
+ ///
+ public uint DataEntryOffset { get; set; }
+
+ ///
+ /// Resource data entry (a leaf).
+ ///
+ public DataEntry? DataEntry { get; set; }
+
+ ///
+ /// High bit 1. The lower 31 bits are the address of another resource
+ /// directory table (the next level down).
+ ///
+ public uint SubdirectoryOffset { get; set; }
+
+ ///
+ /// Another resource directory table (the next level down).
+ ///
+ public DirectoryTable? Subdirectory { get; set; }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryString.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryString.cs
new file mode 100644
index 00000000..4ea26f4b
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryString.cs
@@ -0,0 +1,23 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource
+{
+ ///
+ /// The resource directory string area consists of Unicode strings, which
+ /// are word-aligned. These strings are stored together after the last
+ /// Resource Directory entry and before the first Resource Data entry.
+ /// This minimizes the impact of these variable-length strings on the
+ /// alignment of the fixed-size directory entries.
+ ///
+ ///
+ public sealed class DirectoryString
+ {
+ ///
+ /// The size of the string, not including length field itself.
+ ///
+ public ushort Length { get; set; } // TODO: Remove in lieu of BStr
+
+ ///
+ /// The variable-length Unicode string data, word-aligned.
+ ///
+ public byte[]? UnicodeString { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryTable.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryTable.cs
new file mode 100644
index 00000000..8b9da20e
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/DirectoryTable.cs
@@ -0,0 +1,59 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource
+{
+ ///
+ /// Each directory table is followed by a series of directory entries that
+ /// give the name or identifier (ID) for that level (Type, Name, or Language
+ /// level) and an address of either a data description or another directory
+ /// table. If the address points to a data description, then the data is a
+ /// leaf in the tree. If the address points to another directory table,
+ /// then that table lists directory entries at the next level down.
+ ///
+ /// Each resource directory table has the following format. This data
+ /// structure should be considered the heading of a table because the table
+ /// actually consists of directory entries.
+ ///
+ ///
+ public sealed class DirectoryTable
+ {
+ ///
+ /// Resource flags. This field is reserved for future use. It is currently
+ /// set to zero.
+ ///
+ public uint Characteristics { get; set; }
+
+ ///
+ /// The time that the resource data was created by the resource compiler.
+ ///
+ public uint TimeDateStamp { get; set; }
+
+ ///
+ /// The major version number, set by the user.
+ ///
+ public ushort MajorVersion { get; set; }
+
+ ///
+ /// The minor version number, set by the user.
+ ///
+ public ushort MinorVersion { get; set; }
+
+ ///
+ /// The number of directory entries immediately following the table that use
+ /// strings to identify Type, Name, or Language entries (depending on the
+ /// level of the table).
+ ///
+ public ushort NumberOfNameEntries { get; set; }
+
+ ///
+ /// The number of directory entries immediately following the Name entries that
+ /// use numeric IDs for Type, Name, or Language entries.
+ ///
+ public ushort NumberOfIDEntries { get; set; }
+
+ ///
+ /// Directory entries immediately following the table that use
+ /// strings to identify Type, Name, or Language entries (depending on the
+ /// level of the table).
+ ///
+ public DirectoryEntry[]? Entries { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AcceleratorTable.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AcceleratorTable.cs
new file mode 100644
index 00000000..b6e592e3
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AcceleratorTable.cs
@@ -0,0 +1,19 @@
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// The ACCELTABLEENTRY structure is repeated for all accelerator table entries in the resource.
+ /// The last entry in the table is flagged with the value 0x0080.
+ ///
+ /// You can compute the number of elements in the table if you divide the length of the resource
+ /// by eight. Then your application can randomly access the individual fixed-length entries.
+ ///
+ ///
+ public sealed class AcceleratorTable
+ {
+ ///
+ /// Accelerator table entries
+ ///
+ public AcceleratorTableEntry[]? Entries { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AcceleratorTableEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AcceleratorTableEntry.cs
new file mode 100644
index 00000000..30f8fc50
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AcceleratorTableEntry.cs
@@ -0,0 +1,35 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Describes the data in an individual accelerator table resource. The structure definition
+ /// provided here is for explanation only; it is not present in any standard header file.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class AcceleratorTableEntry
+ {
+ ///
+ /// Describes keyboard accelerator characteristics.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public AcceleratorTableFlags Flags;
+
+ ///
+ /// An ANSI character value or a virtual-key code that identifies the accelerator key.
+ ///
+ public ushort Ansi;
+
+ ///
+ /// An identifier for the keyboard accelerator. This is the value passed to the window
+ /// procedure when the user presses the specified key.
+ ///
+ public ushort Id;
+
+ ///
+ /// The number of bytes inserted to ensure that the structure is aligned on a DWORD boundary.
+ ///
+ public ushort Padding;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AssemblyManifest.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AssemblyManifest.cs
new file mode 100644
index 00000000..f7c35c3d
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/AssemblyManifest.cs
@@ -0,0 +1,390 @@
+using System.Xml.Serialization;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ [XmlRoot(ElementName = "assembly", Namespace = "urn:schemas-microsoft-com:asm.v1")]
+ public sealed class AssemblyManifest
+ {
+ [XmlAttribute("manifestVersion")]
+ public string? ManifestVersion { get; set; }
+
+ #region Group
+
+ [XmlElement("assemblyIdentity")]
+ public AssemblyIdentity[]? AssemblyIdentities { get; set; }
+
+ [XmlElement("noInheritable")]
+ public AssemblyNoInheritable[]? NoInheritables { get; set; }
+
+ #endregion
+
+ #region Group
+
+ [XmlElement("description")]
+ public AssemblyDescription? Description { get; set; }
+
+ [XmlElement("noInherit")]
+ public AssemblyNoInherit? NoInherit { get; set; }
+
+ //[XmlElement("noInheritable")]
+ //public AssemblyNoInheritable NoInheritable { get; set; }
+
+ [XmlElement("comInterfaceExternalProxyStub")]
+ public AssemblyCOMInterfaceExternalProxyStub[]? COMInterfaceExternalProxyStub { get; set; }
+
+ [XmlElement("dependency")]
+ public AssemblyDependency[]? Dependency { get; set; }
+
+ [XmlElement("file")]
+ public AssemblyFile[]? File { get; set; }
+
+ [XmlElement("clrClass")]
+ public AssemblyCommonLanguageRuntimeClass[]? CLRClass { get; set; }
+
+ [XmlElement("clrSurrogate")]
+ public AssemblyCommonLanguageSurrogateClass[]? CLRSurrogate { get; set; }
+
+ #endregion
+
+ [XmlAnyElement]
+ public object[]? EverythingElse { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyActiveCodePage
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyAutoElevate
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyBindingRedirect
+ {
+ [XmlAttribute("oldVersion")]
+ public string? OldVersion { get; set; }
+
+ [XmlAttribute("newVersion")]
+ public string? NewVersion { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyCOMClass
+ {
+ [XmlAttribute("clsid")]
+ public string? CLSID { get; set; }
+
+ [XmlAttribute("threadingModel")]
+ public string? ThreadingModel { get; set; }
+
+ [XmlAttribute("progid")]
+ public string? ProgID { get; set; }
+
+ [XmlAttribute("tlbid")]
+ public string? TLBID { get; set; }
+
+ [XmlAttribute("description")]
+ public string? Description { get; set; }
+
+ [XmlElement("progid")]
+ public AssemblyProgID[]? ProgIDs { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyCOMInterfaceExternalProxyStub
+ {
+ [XmlAttribute("iid")]
+ public string? IID { get; set; }
+
+ [XmlAttribute("name")]
+ public string? Name { get; set; }
+
+ [XmlAttribute("tlbid")]
+ public string? TLBID { get; set; }
+
+ [XmlAttribute("numMethods")]
+ public string? NumMethods { get; set; }
+
+ [XmlAttribute("proxyStubClsid32")]
+ public string? ProxyStubClsid32 { get; set; }
+
+ [XmlAttribute("baseInterface")]
+ public string? BaseInterface { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyCOMInterfaceProxyStub
+ {
+ [XmlAttribute("iid")]
+ public string? IID { get; set; }
+
+ [XmlAttribute("name")]
+ public string? Name { get; set; }
+
+ [XmlAttribute("tlbid")]
+ public string? TLBID { get; set; }
+
+ [XmlAttribute("numMethods")]
+ public string? NumMethods { get; set; }
+
+ [XmlAttribute("proxyStubClsid32")]
+ public string? ProxyStubClsid32 { get; set; }
+
+ [XmlAttribute("baseInterface")]
+ public string? BaseInterface { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyCommonLanguageRuntimeClass
+ {
+ [XmlAttribute("name")]
+ public string? Name { get; set; }
+
+ [XmlAttribute("clsid")]
+ public string? CLSID { get; set; }
+
+ [XmlAttribute("progid")]
+ public string? ProgID { get; set; }
+
+ [XmlAttribute("tlbid")]
+ public string? TLBID { get; set; }
+
+ [XmlAttribute("description")]
+ public string? Description { get; set; }
+
+ [XmlAttribute("runtimeVersion")]
+ public string? RuntimeVersion { get; set; }
+
+ [XmlAttribute("threadingModel")]
+ public string? ThreadingModel { get; set; }
+
+ [XmlElement("progid")]
+ public AssemblyProgID[]? ProgIDs { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyCommonLanguageSurrogateClass
+ {
+ [XmlAttribute("clsid")]
+ public string? CLSID { get; set; }
+
+ [XmlAttribute("name")]
+ public string? Name { get; set; }
+
+ [XmlAttribute("runtimeVersion")]
+ public string? RuntimeVersion { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyDependency
+ {
+ [XmlElement("dependentAssembly")]
+ public AssemblyDependentAssembly? DependentAssembly { get; set; }
+
+ [XmlAttribute("optional")]
+ public string? Optional { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyDependentAssembly
+ {
+ [XmlElement("assemblyIdentity")]
+ public AssemblyIdentity? AssemblyIdentity { get; set; }
+
+ [XmlElement("bindingRedirect")]
+ public AssemblyBindingRedirect[]? BindingRedirect { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyDescription
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyDisableTheming
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyDisableWindowFiltering
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyDPIAware
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyDPIAwareness
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyFile
+ {
+ [XmlAttribute("name")]
+ public string? Name { get; set; }
+
+ [XmlAttribute("hash")]
+ public string? Hash { get; set; }
+
+ [XmlAttribute("hashalg")]
+ public string? HashAlgorithm { get; set; }
+
+ [XmlAttribute("size")]
+ public string? Size { get; set; }
+
+ #region Group
+
+ [XmlElement("comClass")]
+ public AssemblyCOMClass[]? COMClass { get; set; }
+
+ [XmlElement("comInterfaceProxyStub")]
+ public AssemblyCOMInterfaceProxyStub[]? COMInterfaceProxyStub { get; set; }
+
+ [XmlElement("typelib")]
+ public AssemblyTypeLib[]? Typelib { get; set; }
+
+ [XmlElement("windowClass")]
+ public AssemblyWindowClass[]? WindowClass { get; set; }
+
+ #endregion
+ }
+
+ ///
+ public sealed class AssemblyGDIScaling
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyHeapType
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyHighResolutionScrollingAware
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyIdentity
+ {
+ [XmlAttribute("name")]
+ public string? Name { get; set; }
+
+ [XmlAttribute("version")]
+ public string? Version { get; set; }
+
+ [XmlAttribute("type")]
+ public string? Type { get; set; }
+
+ [XmlAttribute("processorArchitecture")]
+ public string? ProcessorArchitecture { get; set; }
+
+ [XmlAttribute("publicKeyToken")]
+ public string? PublicKeyToken { get; set; }
+
+ [XmlAttribute("language")]
+ public string? Language { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyLongPathAware
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyNoInherit
+ {
+ }
+
+ ///
+ public sealed class AssemblyNoInheritable
+ {
+ }
+
+ ///
+ public sealed class AssemblyPrinterDriverIsolation
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyProgID
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblySupportedOS
+ {
+ [XmlAttribute("Id")]
+ public string? Id { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyTypeLib
+ {
+ [XmlElement("tlbid")]
+ public string? TLBID { get; set; }
+
+ [XmlElement("version")]
+ public string? Version { get; set; }
+
+ [XmlElement("helpdir")]
+ public string? HelpDir { get; set; }
+
+ [XmlElement("resourceid")]
+ public string? ResourceID { get; set; }
+
+ [XmlElement("flags")]
+ public string? Flags { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyUltraHighResolutionScrollingAware
+ {
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ ///
+ public sealed class AssemblyWindowClass
+ {
+ [XmlAttribute("versioned")]
+ public string? Versioned { get; set; }
+
+ [XmlText]
+ public string? Value { get; set; }
+ }
+
+ // TODO: Left off at
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/CursorAndIconResource.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/CursorAndIconResource.cs
new file mode 100644
index 00000000..8c94d538
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/CursorAndIconResource.cs
@@ -0,0 +1,40 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// The system handles each icon and cursor as a single file. However, these are stored in
+ /// .res files and in executable files as a group of icon resources or a group of cursor
+ /// resources. The file formats of icon and cursor resources are similar. In the .res file
+ /// a resource group header follows all of the individual icon or cursor group components.
+ ///
+ /// The format of each icon component closely resembles the format of the .ico file. Each
+ /// icon image is stored in a BITMAPINFO structure followed by the color device-independent
+ /// bitmap (DIB) bits of the icon's XOR mask. The monochrome DIB bits of the icon's AND
+ /// mask follow the color DIB bits.
+ ///
+ /// The format of each cursor component resembles the format of the .cur file. Each cursor
+ /// image is stored in a BITMAPINFO structure followed by the monochrome DIB bits of the
+ /// cursor's XOR mask, and then by the monochrome DIB bits of the cursor's AND mask. Note
+ /// that there is a difference in the bitmaps of the two resources: Unlike icons, cursor
+ /// XOR masks do not have color DIB bits. Although the bitmaps of the cursor masks are
+ /// monochrome and do not have DIB headers or color tables, the bits are still in DIB
+ /// format with respect to alignment and direction. Another significant difference
+ /// between cursors and icons is that cursors have a hotspot and icons do not.
+ ///
+ /// The group header for both icon and cursor resources consists of a NEWHEADER structure
+ /// plus one or more RESDIR structures. There is one RESDIR structure for each icon or
+ /// cursor. The group header contains the information an application needs to select the
+ /// correct icon or cursor to display. Both the group header and the data that repeats for
+ /// each icon or cursor in the group have a fixed length. This allows the application to
+ /// randomly access the information.
+ ///
+ ///
+ public sealed class CursorAndIconResource
+ {
+ ///
+ /// Describes keyboard accelerator characteristics.
+ ///
+ public NewHeader? NEWHEADER { get; set; }
+
+ // TODO: Add array of entries in the resource
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogBoxResource.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogBoxResource.cs
new file mode 100644
index 00000000..48e16e9b
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogBoxResource.cs
@@ -0,0 +1,46 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// A dialog box is also one resource entry in the resource file. It consists of one
+ /// DLGTEMPLATE dialog box header structure plus one DLGITEMTEMPLATE structure for each
+ /// control in the dialog box. The DLGTEMPLATEEX and the DLGITEMTEMPLATEEX structures
+ /// describe the format of extended dialog box resources.
+ ///
+ ///
+ public sealed class DialogBoxResource
+ {
+ #region Dialog template
+
+ ///
+ /// Dialog box header structure
+ ///
+ public DialogTemplate? DialogTemplate { get; set; }
+
+ ///
+ /// Dialog box extended header structure
+ ///
+ public DialogTemplateExtended? ExtendedDialogTemplate { get; set; }
+
+ #endregion
+
+ #region Dialog item templates
+
+ ///
+ /// Following the DLGTEMPLATE header in a standard dialog box template are one or more
+ /// DLGITEMTEMPLATE structures that define the dimensions and style of the controls in the dialog
+ /// box. The cdit member specifies the number of DLGITEMTEMPLATE structures in the template.
+ /// These DLGITEMTEMPLATE structures must be aligned on DWORD boundaries.
+ ///
+ public DialogItemTemplate[]? DialogItemTemplates { get; set; }
+
+ ///
+ /// Following the DLGTEMPLATEEX header in an extended dialog box template is one or more
+ /// DLGITEMTEMPLATEEX structures that describe the controls of the dialog box. The cDlgItems
+ /// member of the DLGITEMTEMPLATEEX structure specifies the number of DLGITEMTEMPLATEEX
+ /// structures that follow in the template.
+ ///
+ public DialogItemTemplateExtended[]? ExtendedDialogItemTemplates { get; set; }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogItemTemplate.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogItemTemplate.cs
new file mode 100644
index 00000000..2fbce08e
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogItemTemplate.cs
@@ -0,0 +1,130 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Defines the dimensions and style of a control in a dialog box. One or more of these
+ /// structures are combined with a DLGTEMPLATE structure to form a standard template
+ /// for a dialog box.
+ ///
+ ///
+ public sealed class DialogItemTemplate
+ {
+ ///
+ /// The style of the control. This member can be a combination of window style values
+ /// (such as WS_BORDER) and one or more of the control style values (such as
+ /// BS_PUSHBUTTON and ES_LEFT).
+ ///
+ public WindowStyles Style { get; set; }
+
+ ///
+ /// The extended styles for a window. This member is not used to create dialog boxes,
+ /// but applications that use dialog box templates can use it to create other types
+ /// of windows.
+ ///
+ public ExtendedWindowStyles ExtendedStyle { get; set; }
+
+ ///
+ /// The x-coordinate, in dialog box units, of the upper-left corner of the control.
+ /// This coordinate is always relative to the upper-left corner of the dialog box's
+ /// client area.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen
+ /// units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionX { get; set; }
+
+ ///
+ /// The y-coordinate, in dialog box units, of the upper-left corner of the control.
+ /// This coordinate is always relative to the upper-left corner of the dialog box's
+ /// client area.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen
+ /// units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionY { get; set; }
+
+ ///
+ /// The width, in dialog box units, of the control.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen
+ /// units (pixels) by using the MapDialogRect function.
+ ///
+ public short WidthX { get; set; }
+
+ ///
+ /// The height, in dialog box units, of the control.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen
+ /// units (pixels) by using the MapDialogRect function.
+ ///
+ public short HeightY { get; set; }
+
+ ///
+ /// The control identifier.
+ ///
+ public ushort ID { get; set; }
+
+ // In a standard template for a dialog box, the DLGITEMTEMPLATE structure is always immediately
+ // followed by three variable-length arrays specifying the class, title, and creation data for
+ // the control. Each array consists of one or more 16-bit elements.
+ //
+ // Each DLGITEMTEMPLATE structure in the template must be aligned on a DWORD boundary. The class
+ // and title arrays must be aligned on WORD boundaries. The creation data array must be aligned
+ // on a WORD boundary.
+
+ ///
+ /// Immediately following each DLGITEMTEMPLATE structure is a class array that specifies the window
+ /// class of the control. If the first element of this array is any value other than 0xFFFF, the
+ /// system treats the array as a null-terminated Unicode string that specifies the name of a
+ /// registered window class. If the first element is 0xFFFF, the array has one additional element
+ /// that specifies the ordinal value of a predefined system class.
+ ///
+ ///
+ /// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
+ /// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
+ ///
+ public string? ClassResource { get; set; }
+
+ ///
+ /// The ordinal value of a predefined system class.
+ ///
+ public DialogItemTemplateOrdinal ClassResourceOrdinal { get; set; }
+
+ ///
+ /// Following the class array is a title array that contains the initial text or resource identifier
+ /// of the control. If the first element of this array is 0xFFFF, the array has one additional element
+ /// that specifies an ordinal value of a resource, such as an icon, in an executable file. You can use
+ /// a resource identifier for controls, such as static icon controls, that load and display an icon
+ /// or other resource rather than text. If the first element is any value other than 0xFFFF, the system
+ /// treats the array as a null-terminated Unicode string that specifies the initial text.
+ ///
+ ///
+ /// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
+ /// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
+ ///
+ public string? TitleResource { get; set; }
+
+ ///
+ /// An ordinal value of a resource, such as an icon, in an executable file
+ ///
+ public ushort TitleResourceOrdinal { get; set; }
+
+ ///
+ /// The creation data array begins at the next WORD boundary after the title array. This creation data
+ /// can be of any size and format. If the first word of the creation data array is nonzero, it indicates
+ /// the size, in bytes, of the creation data (including the size word).
+ ///
+ public ushort CreationDataSize { get; set; }
+
+ ///
+ /// The creation data array begins at the next WORD boundary after the title array. This creation data
+ /// can be of any size and format. The control's window procedure must be able to interpret the data.
+ /// When the system creates the control, it passes a pointer to this data in the lParam parameter of the
+ /// WM_CREATE message that it sends to the control.
+ ///
+ public byte[]? CreationData { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogItemTemplateExtended.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogItemTemplateExtended.cs
new file mode 100644
index 00000000..85e10a6e
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogItemTemplateExtended.cs
@@ -0,0 +1,128 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// A block of text used by an extended dialog box template to describe the extended dialog box.
+ /// For a description of the format of an extended dialog box template, see DLGTEMPLATEEX.
+ ///
+ ///
+ public sealed class DialogItemTemplateExtended
+ {
+ ///
+ /// The help context identifier for the control. When the system sends a WM_HELP message,
+ /// it passes the helpID value in the dwContextId member of the HELPINFO structure.
+ ///
+ public uint HelpID { get; set; }
+
+ ///
+ /// The extended styles for a window. This member is not used to create controls in dialog
+ /// boxes, but applications that use dialog box templates can use it to create other types
+ /// of windows.
+ ///
+ public ExtendedWindowStyles ExtendedStyle { get; set; }
+
+ ///
+ /// The style of the control. This member can be a combination of window style values
+ /// (such as WS_BORDER) and one or more of the control style values (such as
+ /// BS_PUSHBUTTON and ES_LEFT).
+ ///
+ public WindowStyles Style { get; set; }
+
+ ///
+ /// The x-coordinate, in dialog box units, of the upper-left corner of the control.
+ /// This coordinate is always relative to the upper-left corner of the dialog box's
+ /// client area.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen
+ /// units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionX { get; set; }
+
+ ///
+ /// The y-coordinate, in dialog box units, of the upper-left corner of the control.
+ /// This coordinate is always relative to the upper-left corner of the dialog box's
+ /// client area.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen
+ /// units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionY { get; set; }
+
+ ///
+ /// The width, in dialog box units, of the control.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen
+ /// units (pixels) by using the MapDialogRect function.
+ ///
+ public short WidthX { get; set; }
+
+ ///
+ /// The height, in dialog box units, of the control.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen
+ /// units (pixels) by using the MapDialogRect function.
+ ///
+ public short HeightY { get; set; }
+
+ ///
+ /// The control identifier.
+ ///
+ public uint ID { get; set; }
+
+ ///
+ /// A variable-length array of 16-bit elements that specifies the window class of the control. If
+ /// the first element of this array is any value other than 0xFFFF, the system treats the array as
+ /// a null-terminated Unicode string that specifies the name of a registered window class.
+ ///
+ /// If the first element is 0xFFFF, the array has one additional element that specifies the ordinal
+ /// value of a predefined system class.
+ ///
+ ///
+ /// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
+ /// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
+ ///
+ public string? ClassResource { get; set; }
+
+ ///
+ /// The ordinal value of a predefined system class.
+ ///
+ public DialogItemTemplateOrdinal ClassResourceOrdinal { get; set; }
+
+ ///
+ /// A variable-length array of 16-bit elements that contains the initial text or resource identifier of the
+ /// control. If the first element of this array is 0xFFFF, the array has one additional element that
+ /// specifies the ordinal value of a resource, such as an icon, in an executable file. You can use a
+ /// resource identifier for controls, such as static icon controls, that load and display an icon or other
+ /// resource rather than text. If the first element is any value other than 0xFFFF, the system treats the
+ /// array as a null-terminated Unicode string that specifies the initial text.
+ ///
+ ///
+ /// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
+ /// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
+ ///
+ public string? TitleResource { get; set; }
+
+ ///
+ /// An ordinal value of a resource, such as an icon, in an executable file
+ ///
+ public ushort TitleResourceOrdinal { get; set; }
+
+ ///
+ /// The creation data array begins at the next WORD boundary after the title array. This creation data
+ /// can be of any size and format. If the first word of the creation data array is nonzero, it indicates
+ /// the size, in bytes, of the creation data (including the size word).
+ ///
+ public ushort CreationDataSize { get; set; }
+
+ ///
+ /// The creation data array begins at the next WORD boundary after the title array. This creation data
+ /// can be of any size and format. The control's window procedure must be able to interpret the data.
+ /// When the system creates the control, it passes a pointer to this data in the lParam parameter of the
+ /// WM_CREATE message that it sends to the control.
+ ///
+ public byte[]? CreationData { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogTemplate.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogTemplate.cs
new file mode 100644
index 00000000..20a83ad9
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogTemplate.cs
@@ -0,0 +1,160 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Defines the dimensions and style of a dialog box. This structure, always the first
+ /// in a standard template for a dialog box, also specifies the number of controls in
+ /// the dialog box and therefore specifies the number of subsequent DLGITEMTEMPLATE
+ /// structures in the template.
+ ///
+ ///
+ public sealed class DialogTemplate
+ {
+ ///
+ /// The style of the dialog box. This member can be a combination of window style
+ /// values (such as WS_CAPTION and WS_SYSMENU) and dialog box style values (such
+ /// as DS_CENTER).
+ ///
+ /// If the style member includes the DS_SETFONT style, the header of the dialog box
+ /// template contains additional data specifying the font to use for text in the
+ /// client area and controls of the dialog box. The font data begins on the WORD
+ /// boundary that follows the title array. The font data specifies a 16-bit point
+ /// size value and a Unicode font name string. If possible, the system creates a
+ /// font according to the specified values. Then the system sends a WM_SETFONT
+ /// message to the dialog box and to each control to provide a handle to the font.
+ /// If DS_SETFONT is not specified, the dialog box template does not include the
+ /// font data.
+ ///
+ /// The DS_SHELLFONT style is not supported in the DLGTEMPLATE header.
+ ///
+ public WindowStyles Style { get; set; }
+
+ ///
+ /// The extended styles for a window. This member is not used to create dialog boxes,
+ /// but applications that use dialog box templates can use it to create other types
+ /// of windows.
+ ///
+ public ExtendedWindowStyles ExtendedStyle { get; set; }
+
+ ///
+ /// The number of items in the dialog box.
+ ///
+ public ushort ItemCount { get; set; }
+
+ ///
+ /// The x-coordinate, in dialog box units, of the upper-left corner of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionX { get; set; }
+
+ ///
+ /// The y-coordinate, in dialog box units, of the upper-left corner of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionY { get; set; }
+
+ ///
+ /// The width, in dialog box units, of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short WidthX { get; set; }
+
+ ///
+ /// The height, in dialog box units, of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short HeightY { get; set; }
+
+ // In a standard template for a dialog box, the DLGTEMPLATE structure is always immediately
+ // followed by three variable-length arrays that specify the menu, class, and title for the
+ // dialog box. When the DS_SETFONT style is specified, these arrays are also followed by a
+ // 16-bit value specifying point size and another variable-length array specifying a
+ // typeface name. Each array consists of one or more 16-bit elements. The menu, class, title,
+ // and font arrays must be aligned on WORD boundaries.
+
+ ///
+ /// Immediately following the DLGTEMPLATE structure is a menu array that identifies a menu
+ /// resource for the dialog box. If the first element of this array is 0x0000, the dialog box
+ /// has no menu and the array has no other elements. If the first element is 0xFFFF, the array
+ /// has one additional element that specifies the ordinal value of a menu resource in an
+ /// executable file. If the first element has any other value, the system treats the array as
+ /// a null-terminated Unicode string that specifies the name of a menu resource in an executable
+ /// file.
+ ///
+ ///
+ /// If you specify character strings in the menu, class, title, or typeface arrays, you must use
+ /// Unicode strings.
+ ///
+ public string? MenuResource { get; set; }
+
+ ///
+ /// The ordinal value of a menu resource in an executable file.
+ ///
+ public ushort MenuResourceOrdinal { get; set; }
+
+ ///
+ /// Following the menu array is a class array that identifies the window class of the dialog box.
+ /// If the first element of the array is 0x0000, the system uses the predefined dialog box class
+ /// for the dialog box and the array has no other elements. If the first element is 0xFFFF,
+ /// the array has one additional element that specifies the ordinal value of a predefined system
+ /// window class. If the first element has any other value, the system treats the array as a
+ /// null-terminated Unicode string that specifies the name of a registered window class.
+ ///
+ ///
+ /// If you specify character strings in the menu, class, title, or typeface arrays, you must use
+ /// Unicode strings.
+ ///
+ public string? ClassResource { get; set; }
+
+ ///
+ /// The ordinal value of a predefined system class.
+ ///
+ public ushort ClassResourceOrdinal { get; set; }
+
+ ///
+ /// Following the class array is a title array that specifies a null-terminated Unicode string
+ /// that contains the title of the dialog box. If the first element of this array is 0x0000,
+ /// the dialog box has no title and the array has no other elements.
+ ///
+ ///
+ /// If you specify character strings in the menu, class, title, or typeface arrays, you must use
+ /// Unicode strings.
+ ///
+ public string? TitleResource { get; set; }
+
+ ///
+ /// The 16-bit point size value and the typeface array follow the title array, but only if the
+ /// style member specifies the DS_SETFONT style. The point size value specifies the point size
+ /// of the font to use for the text in the dialog box and its controls. When these values are
+ /// specified, the system creates a font having the specified size and typeface (if possible)
+ /// and sends a WM_SETFONT message to the dialog box procedure and the control window
+ /// procedures as it creates the dialog box and controls.
+ ///
+ public ushort PointSizeValue { get; set; }
+
+ ///
+ /// The 16-bit point size value and the typeface array follow the title array, but only if the
+ /// style member specifies the DS_SETFONT style. The typeface array is a null-terminated Unicode
+ /// string specifying the name of the typeface for the font. When these values are specified,
+ /// the system creates a font having the specified size and typeface (if possible) and sends a
+ /// WM_SETFONT message to the dialog box procedure and the control window procedures as it
+ /// creates the dialog box and controls.
+ ///
+ ///
+ /// If you specify character strings in the menu, class, title, or typeface arrays, you must use
+ /// Unicode strings.
+ ///
+ public string? Typeface { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogTemplateExtended.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogTemplateExtended.cs
new file mode 100644
index 00000000..ebef4ca9
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DialogTemplateExtended.cs
@@ -0,0 +1,185 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// An extended dialog box template begins with a DLGTEMPLATEEX header that describes
+ /// the dialog box and specifies the number of controls in the dialog box. For each
+ /// control in a dialog box, an extended dialog box template has a block of data that
+ /// uses the DLGITEMTEMPLATEEX format to describe the control.
+ ///
+ /// The DLGTEMPLATEEX structure is not defined in any standard header file. The
+ /// structure definition is provided here to explain the format of an extended template
+ /// for a dialog box.
+ ///
+ ///
+ public sealed class DialogTemplateExtended
+ {
+ ///
+ /// The version number of the extended dialog box template. This member must be
+ /// set to 1.
+ ///
+ public ushort Version { get; set; }
+
+ ///
+ /// Indicates whether a template is an extended dialog box template. If signature
+ /// is 0xFFFF, this is an extended dialog box template. In this case, the dlgVer
+ /// member specifies the template version number. If signature is any value other
+ /// than 0xFFFF, this is a standard dialog box template that uses the DLGTEMPLATE
+ /// and DLGITEMTEMPLATE structures.
+ ///
+ public ushort Signature { get; set; }
+
+ ///
+ /// The help context identifier for the dialog box window. When the system sends a
+ /// WM_HELP message, it passes this value in the wContextId member of the HELPINFO
+ /// structure.
+ ///
+ public uint HelpID { get; set; }
+
+ ///
+ /// The extended windows styles. This member is not used when creating dialog boxes,
+ /// but applications that use dialog box templates can use it to create other types
+ /// of windows.
+ ///
+ public ExtendedWindowStyles ExtendedStyle { get; set; }
+
+ ///
+ /// The style of the dialog box.
+ ///
+ /// If style includes the DS_SETFONT or DS_SHELLFONT dialog box style, the DLGTEMPLATEEX
+ /// header of the extended dialog box template contains four additional members (pointsize,
+ /// weight, italic, and typeface) that describe the font to use for the text in the client
+ /// area and controls of the dialog box. If possible, the system creates a font according
+ /// to the values specified in these members. Then the system sends a WM_SETFONT message
+ /// to the dialog box and to each control to provide a handle to the font.
+ ///
+ public WindowStyles Style { get; set; }
+
+ ///
+ /// The number of controls in the dialog box.
+ ///
+ public ushort DialogItems { get; set; }
+
+ ///
+ /// The x-coordinate, in dialog box units, of the upper-left corner of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionX { get; set; }
+
+ ///
+ /// The y-coordinate, in dialog box units, of the upper-left corner of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionY { get; set; }
+
+ ///
+ /// The width, in dialog box units, of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short WidthX { get; set; }
+
+ ///
+ /// The height, in dialog box units, of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short HeightY { get; set; }
+
+ ///
+ /// A variable-length array of 16-bit elements that identifies a menu resource for the dialog box.
+ /// If the first element of this array is 0x0000, the dialog box has no menu and the array has no
+ /// other elements. If the first element is 0xFFFF, the array has one additional element that
+ /// specifies the ordinal value of a menu resource in an executable file. If the first element has
+ /// any other value, the system treats the array as a null-terminated Unicode string that specifies
+ /// the name of a menu resource in an executable file.
+ ///
+ ///
+ /// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
+ /// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
+ ///
+ public string? MenuResource { get; set; }
+
+ ///
+ /// The ordinal value of a menu resource in an executable file.
+ ///
+ public ushort MenuResourceOrdinal { get; set; }
+
+ /// A variable-length array of 16-bit elements that identifies the window class of the
+ /// dialog box. If the first element of the array is 0x0000, the system uses the predefined dialog
+ /// box class for the dialog box and the array has no other elements. If the first element is 0xFFFF,
+ /// the array has one additional element that specifies the ordinal value of a predefined system
+ /// window class. If the first element has any other value, the system treats the array as a
+ /// null-terminated Unicode string that specifies the name of a registered window class.
+ ///
+ ///
+ /// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
+ /// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
+ ///
+ public string? ClassResource { get; set; }
+
+ ///
+ /// The ordinal value of a predefined system window class.
+ ///
+ public ushort ClassResourceOrdinal { get; set; }
+
+ ///
+ /// The title of the dialog box. If the first element of this array is 0x0000, the dialog box has no
+ /// title and the array has no other elements.
+ ///
+ ///
+ /// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
+ /// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
+ ///
+ public string? TitleResource { get; set; }
+
+ ///
+ /// The point size of the font to use for the text in the dialog box and its controls.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public ushort PointSize { get; set; }
+
+ ///
+ /// The weight of the font. Note that, although this can be any of the values listed for the lfWeight
+ /// member of the LOGFONT structure, any value that is used will be automatically changed to FW_NORMAL.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public ushort Weight { get; set; }
+
+ ///
+ /// Indicates whether the font is italic. If this value is TRUE, the font is italic.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public byte Italic { get; set; }
+
+ ///
+ /// The character set to be used. For more information, see the lfcharset member of LOGFONT.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public byte CharSet { get; set; }
+
+ ///
+ /// The name of the typeface for the font.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ ///
+ /// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
+ /// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
+ ///
+ public string? Typeface { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DirEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DirEntry.cs
new file mode 100644
index 00000000..185d7f4b
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/DirEntry.cs
@@ -0,0 +1,21 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains the information necessary for an application to access a specific font. The structure
+ /// definition provided here is for explanation only; it is not present in any standard header file.
+ ///
+ ///
+ public sealed class DirEntry
+ {
+ ///
+ /// A unique ordinal identifier for an individual font in a font resource group.
+ ///
+ public ushort FontOrdinal { get; set; }
+
+ ///
+ /// The FONTDIRENTRY structure for the specified font directly follows the DIRENTRY structure
+ /// for that font.
+ ///
+ public FontDirEntry? Entry { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FixedFileInfo.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FixedFileInfo.cs
new file mode 100644
index 00000000..e6f75f56
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FixedFileInfo.cs
@@ -0,0 +1,92 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains version information for a file. This information is language and
+ /// code page independent.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class FixedFileInfo
+ {
+ ///
+ /// Contains the value 0xFEEF04BD. This is used with the szKey member of the VS_VERSIONINFO
+ /// structure when searching a file for the FixedFileInfo structure.
+ ///
+ public uint Signature;
+
+ ///
+ /// The binary version number of this structure. The high-order word of this member contains
+ /// the major version number, and the low-order word contains the minor version number.
+ ///
+ public uint StrucVersion;
+
+ ///
+ /// The most significant 32 bits of the file's binary version number. This member is used with
+ /// FileVersionLS to form a 64-bit value used for numeric comparisons.
+ ///
+ public uint FileVersionMS;
+
+ ///
+ /// The least significant 32 bits of the file's binary version number. This member is used with
+ /// FileVersionMS to form a 64-bit value used for numeric comparisons.
+ ///
+ public uint FileVersionLS;
+
+ ///
+ /// The most significant 32 bits of the binary version number of the product with which this file
+ /// was distributed. This member is used with ProductVersionLS to form a 64-bit value used for
+ /// numeric comparisons.
+ ///
+ public uint ProductVersionMS;
+
+ ///
+ /// The least significant 32 bits of the binary version number of the product with which this file
+ /// was distributed. This member is used with ProductVersionMS to form a 64-bit value used for
+ /// numeric comparisons.
+ ///
+ public uint ProductVersionLS;
+
+ ///
+ /// Contains a bitmask that specifies the valid bits in FileFlags. A bit is valid only if it was
+ /// defined when the file was created.
+ ///
+ public uint FileFlagsMask;
+
+ ///
+ /// Contains a bitmask that specifies the Boolean attributes of the file.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public FixedFileInfoFlags FileFlags;
+
+ ///
+ /// The operating system for which this file was designed.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public FixedFileInfoOS FileOS;
+
+ ///
+ /// The general type of file.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public FixedFileInfoFileType FileType;
+
+ ///
+ /// The function of the file. The possible values depend on the value of FileType. For all values
+ /// of FileType not described in the following list, FileSubtype is zero.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public FixedFileInfoFileSubtype FileSubtype;
+
+ ///
+ /// The most significant 32 bits of the file's 64-bit binary creation date and time stamp.
+ ///
+ public uint FileDateMS;
+
+ ///
+ /// The least significant 32 bits of the file's 64-bit binary creation date and time stamp.
+ ///
+ public uint FileDateLS;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FontDirEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FontDirEntry.cs
new file mode 100644
index 00000000..9c3189d8
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FontDirEntry.cs
@@ -0,0 +1,174 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains information about an individual font in a font resource group. The structure definition
+ /// provided here is for explanation only; it is not present in any standard header file.
+ ///
+ ///
+ public sealed class FontDirEntry
+ {
+ ///
+ /// A user-defined version number for the resource data that tools can use to read and write
+ /// resource files.
+ ///
+ public ushort Version { get; set; }
+
+ ///
+ /// The size of the file, in bytes.
+ ///
+ public uint Size { get; set; }
+
+ ///
+ /// The font supplier's copyright information.
+ ///
+ /// 60 characters
+ public byte[]? Copyright { get; set; }
+
+ ///
+ /// The type of font file.
+ ///
+ public ushort Type { get; set; }
+
+ ///
+ /// The point size at which this character set looks best.
+ ///
+ public ushort Points { get; set; }
+
+ ///
+ /// The vertical resolution, in dots per inch, at which this character set was digitized.
+ ///
+ public ushort VertRes { get; set; }
+
+ ///
+ /// The horizontal resolution, in dots per inch, at which this character set was digitized.
+ ///
+ public ushort HorizRes { get; set; }
+
+ ///
+ /// The distance from the top of a character definition cell to the baseline of the typographical
+ /// font.
+ ///
+ public ushort Ascent { get; set; }
+
+ ///
+ /// The amount of leading inside the bounds set by the PixHeight member. Accent marks and other
+ /// diacritical characters can occur in this area.
+ ///
+ public ushort InternalLeading { get; set; }
+
+ ///
+ /// The amount of extra leading that the application adds between rows.
+ ///
+ public ushort ExternalLeading { get; set; }
+
+ ///
+ /// An italic font if not equal to zero.
+ ///
+ public byte Italic { get; set; }
+
+ ///
+ /// An underlined font if not equal to zero.
+ ///
+ public byte Underline { get; set; }
+
+ ///
+ /// A strikeout font if not equal to zero.
+ ///
+ public byte StrikeOut { get; set; }
+
+ ///
+ /// The weight of the font in the range 0 through 1000. For example, 400 is roman and 700 is bold.
+ /// If this value is zero, a default weight is used. For additional defined values, see the
+ /// description of the LOGFONT structure.
+ ///
+ public ushort Weight { get; set; }
+
+ ///
+ /// The character set of the font. For predefined values, see the description of the LOGFONT
+ /// structure.
+ ///
+ public byte CharSet { get; set; }
+
+ ///
+ /// The width of the grid on which a vector font was digitized. For raster fonts, if the member
+ /// is not equal to zero, it represents the width for all the characters in the bitmap. If the
+ /// member is equal to zero, the font has variable-width characters.
+ ///
+ public ushort PixWidth { get; set; }
+
+ ///
+ /// The height of the character bitmap for raster fonts or the height of the grid on which a
+ /// vector font was digitized.
+ ///
+ public ushort PixHeight { get; set; }
+
+ ///
+ /// The pitch and the family of the font. For additional information, see the description of
+ /// the LOGFONT structure.
+ ///
+ public byte PitchAndFamily { get; set; }
+
+ ///
+ /// The average width of characters in the font (generally defined as the width of the letter x).
+ /// This value does not include the overhang required for bold or italic characters.
+ ///
+ public ushort AvgWidth { get; set; }
+
+ ///
+ /// The width of the widest character in the font.
+ ///
+ public ushort MaxWidth { get; set; }
+
+ ///
+ /// The first character code defined in the font.
+ ///
+ public byte FirstChar { get; set; }
+
+ ///
+ /// The last character code defined in the font.
+ ///
+ public byte LastChar { get; set; }
+
+ ///
+ /// The character to substitute for characters not in the font.
+ ///
+ public byte DefaultChar { get; set; }
+
+ ///
+ /// The character that will be used to define word breaks for text justification.
+ ///
+ public byte BreakChar { get; set; }
+
+ ///
+ /// The number of bytes in each row of the bitmap. This value is always even so that the rows
+ /// start on word boundaries. For vector fonts, this member has no meaning.
+ ///
+ public ushort WidthBytes { get; set; }
+
+ ///
+ /// The offset in the file to a null-terminated string that specifies a device name. For a
+ /// generic font, this value is zero.
+ ///
+ public uint Device { get; set; }
+
+ ///
+ /// The offset in the file to a null-terminated string that names the typeface.
+ ///
+ public uint Face { get; set; }
+
+ ///
+ /// This member is reserved.
+ ///
+ public uint Reserved { get; set; }
+
+ ///
+ /// The name of the device if this font file is designated for a specific device.
+ ///
+ public string? DeviceName { get; set; }
+
+ ///
+ /// The typeface name of the font.
+ ///
+ public string? FaceName { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FontGroupHeader.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FontGroupHeader.cs
new file mode 100644
index 00000000..b95e9632
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/FontGroupHeader.cs
@@ -0,0 +1,21 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains the information necessary for an application to access a specific font. The structure
+ /// definition provided here is for explanation only; it is not present in any standard header file.
+ ///
+ ///
+ public sealed class FontGroupHeader
+ {
+ ///
+ /// The number of individual fonts associated with this resource.
+ ///
+ public ushort NumberOfFonts { get; set; }
+
+ ///
+ /// A structure that contains a unique ordinal identifier for each font in the resource. The DE
+ /// member is a placeholder for the variable-length array of DIRENTRY structures.
+ ///
+ public DirEntry[]? DE { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuHeader.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuHeader.cs
new file mode 100644
index 00000000..da9d7de8
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuHeader.cs
@@ -0,0 +1,12 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Common base class for menu item types
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public abstract class MenuHeader { }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuHeaderExtended.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuHeaderExtended.cs
new file mode 100644
index 00000000..a64cd245
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuHeaderExtended.cs
@@ -0,0 +1,30 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Defines the header for an extended menu template. This structure definition is for
+ /// explanation only; it is not present in any standard header file.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class MenuHeaderExtended : MenuHeader
+ {
+ ///
+ /// The template version number. This member must be 1 for extended menu templates.
+ ///
+ public ushort Version;
+
+ ///
+ /// The offset to the first MENUEX_TEMPLATE_ITEM structure, relative to the end of
+ /// this structure member. If the first item definition immediately follows the
+ /// dwHelpId member, this member should be 4.
+ ///
+ public ushort Offset;
+
+ ///
+ /// The help identifier of menu bar.
+ ///
+ public uint HelpID;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuItem.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuItem.cs
new file mode 100644
index 00000000..9870fb91
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuItem.cs
@@ -0,0 +1,12 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Common base class for menu item types
+ ///
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public abstract class MenuItem { }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuItemExtended.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuItemExtended.cs
new file mode 100644
index 00000000..61e057d2
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuItemExtended.cs
@@ -0,0 +1,44 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Defines a menu item in an extended menu template. This structure definition is for
+ /// explanation only; it is not present in any standard header file.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class MenuItemExtended : MenuItem
+ {
+ ///
+ /// Describes the menu item.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public MenuFlags ItemType;
+
+ ///
+ /// Describes the menu item.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public MenuFlags State;
+
+ ///
+ /// A numeric expression that identifies the menu item that is passed in the
+ /// WM_COMMAND message.
+ ///
+ public uint ID;
+
+ ///
+ /// A set of bit flags that specify the type of menu item.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public MenuFlags Flags;
+
+ ///
+ /// A null-terminated Unicode string that contains the text for this menu item.
+ /// There is no fixed limit on the size of this string.
+ ///
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string? MenuText;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuResource.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuResource.cs
new file mode 100644
index 00000000..f1782150
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MenuResource.cs
@@ -0,0 +1,22 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// A menu resource consists of a MENUHEADER structure followed by one or more
+ /// NORMALMENUITEM or POPUPMENUITEM structures, one for each menu item in the menu
+ /// template. The MENUEX_TEMPLATE_HEADER and the MENUEX_TEMPLATE_ITEM structures
+ /// describe the format of extended menu resources.
+ ///
+ ///
+ public sealed class MenuResource
+ {
+ ///
+ /// Menu header structure
+ ///
+ public MenuHeader? MenuHeader { get; set; }
+
+ ///
+ /// Menu items
+ ///
+ public MenuItem[]? MenuItems { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceBlock.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceBlock.cs
new file mode 100644
index 00000000..facacb7e
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceBlock.cs
@@ -0,0 +1,30 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains information about message strings with identifiers in the range indicated
+ /// by the LowId and HighId members.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class MessageResourceBlock
+ {
+ ///
+ /// The lowest message identifier contained within this structure.
+ ///
+ public uint LowId;
+
+ ///
+ /// The highest message identifier contained within this structure.
+ ///
+ public uint HighId;
+
+ ///
+ /// The offset, in bytes, from the beginning of the MESSAGE_RESOURCE_DATA structure to the
+ /// MESSAGE_RESOURCE_ENTRY structures in this MESSAGE_RESOURCE_BLOCK. The MESSAGE_RESOURCE_ENTRY
+ /// structures contain the message strings.
+ ///
+ public uint OffsetToEntries;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceData.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceData.cs
new file mode 100644
index 00000000..a009f25d
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceData.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains information about formatted text for display as an error message or in a message
+ /// box in a message table resource.
+ ///
+ ///
+ public sealed class MessageResourceData
+ {
+ ///
+ /// The number of MESSAGE_RESOURCE_BLOCK structures.
+ ///
+ public uint NumberOfBlocks { get; set; }
+
+ ///
+ /// An array of structures. The array is the size indicated by the NumberOfBlocks member.
+ ///
+ public MessageResourceBlock[]? Blocks { get; set; }
+
+ ///
+ /// Message resource entries
+ ///
+ public Dictionary? Entries { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceEntry.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceEntry.cs
new file mode 100644
index 00000000..26a34068
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/MessageResourceEntry.cs
@@ -0,0 +1,25 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains the error message or message box display text for a message table resource.
+ ///
+ ///
+ public sealed class MessageResourceEntry
+ {
+ ///
+ /// The length, in bytes, of the MESSAGE_RESOURCE_ENTRY structure.
+ ///
+ public ushort Length { get; set; }
+
+ ///
+ /// Indicates that the string is encoded in Unicode, if equal to the value 0x0001.
+ /// Indicates that the string is encoded in ANSI, if equal to the value 0x0000.
+ ///
+ public ushort Flags { get; set; }
+
+ ///
+ /// Pointer to an array that contains the error message or message box display text.
+ ///
+ public string? Text { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NewHeader.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NewHeader.cs
new file mode 100644
index 00000000..d105f43d
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NewHeader.cs
@@ -0,0 +1,31 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains the number of icon or cursor components in a resource group. The
+ /// structure definition provided here is for explanation only; it is not present
+ /// in any standard header file.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class NewHeader
+ {
+ ///
+ /// Reserved; must be zero.
+ ///
+ public ushort Reserved;
+
+ ///
+ /// The resource type. This member must have one of the following values.
+ /// - RES_ICON (1): Icon resource type.
+ /// - RES_CURSOR (2): Cursor resource type.
+ ///
+ public ushort ResType;
+
+ ///
+ /// The number of icon or cursor components in the resource group.
+ ///
+ public ushort ResCount;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NormalMenuHeader.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NormalMenuHeader.cs
new file mode 100644
index 00000000..6505ab6b
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NormalMenuHeader.cs
@@ -0,0 +1,25 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains version information for the menu resource. The structure definition provided
+ /// here is for explanation only; it is not present in any standard header file.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class NormalMenuHeader: MenuHeader
+ {
+ ///
+ /// The version number of the menu template. This member must be equal to zero to indicate
+ /// that this is an RT_MENU created with a standard menu template.
+ ///
+ public ushort Version;
+
+ ///
+ /// The size of the menu template header. This value is zero for menus you create with a
+ /// standard menu template.
+ ///
+ public ushort HeaderSize;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NormalMenuItem.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NormalMenuItem.cs
new file mode 100644
index 00000000..4a5d4c21
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/NormalMenuItem.cs
@@ -0,0 +1,27 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains information about each item in a menu resource that does not open a menu
+ /// or a submenu. The structure definition provided here is for explanation only; it
+ /// is not present in any standard header file.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class NormalMenuItem : MenuItem
+ {
+ ///
+ /// The type of menu item.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public MenuFlags NormalResInfo;
+
+ ///
+ /// A null-terminated Unicode string that contains the text for this menu item.
+ /// There is no fixed limit on the size of this string.
+ ///
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string? NormalMenuText;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/PopupMenuItem.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/PopupMenuItem.cs
new file mode 100644
index 00000000..d6507ff8
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/PopupMenuItem.cs
@@ -0,0 +1,45 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Contains information about the menu items in a menu resource that open a menu
+ /// or a submenu. The structure definition provided here is for explanation only;
+ /// it is not present in any standard header file.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class PopupMenuItem : MenuItem
+ {
+ ///
+ /// Describes the menu item.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public MenuFlags PopupItemType;
+
+ ///
+ /// Describes the menu item.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public MenuFlags PopupState;
+
+ ///
+ /// A numeric expression that identifies the menu item that is passed in the
+ /// WM_COMMAND message.
+ ///
+ public uint PopupID;
+
+ ///
+ /// A set of bit flags that specify the type of menu item.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public MenuFlags PopupResInfo;
+
+ ///
+ /// A null-terminated Unicode string that contains the text for this menu item.
+ /// There is no fixed limit on the size of this string.
+ ///
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string? PopupMenuText;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringData.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringData.cs
new file mode 100644
index 00000000..8c1d2853
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringData.cs
@@ -0,0 +1,79 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Represents the organization of data in a file-version resource. It contains a string
+ /// that describes a specific aspect of a file, for example, a file's version, its
+ /// copyright notices, or its trademarks.
+ ///
+ ///
+ public sealed class StringData
+ {
+ ///
+ /// The length, in bytes, of this String structure.
+ ///
+ public ushort Length { get; set; }
+
+ ///
+ /// The size, in words, of the Value member.
+ ///
+ public ushort ValueLength { get; set; }
+
+ ///
+ /// The type of data in the version resource.
+ ///
+ public VersionResourceType ResourceType { get; set; }
+
+ ///
+ /// An arbitrary Unicode string. The Key member can be one or more of the following
+ /// values. These values are guidelines only.
+ /// - Comments: The Value member contains any additional information that should be
+ /// displayed for diagnostic purposes. This string can be an arbitrary length.
+ /// - CompanyName: The Value member identifies the company that produced the file.
+ /// For example, "Microsoft Corporation" or "Standard Microsystems Corporation, Inc."
+ /// - FileDescription: The Value member describes the file in such a way that it can be
+ /// presented to users. This string may be presented in a list box when the user is
+ /// choosing files to install. For example, "Keyboard driver for AT-style keyboards"
+ /// or "Microsoft Word for Windows".
+ /// - FileVersion: The Value member identifies the version of this file. For example,
+ /// Value could be "3.00A" or "5.00.RC2".
+ /// - InternalName: The Value member identifies the file's internal name, if one exists.
+ /// For example, this string could contain the module name for a DLL, a virtual device
+ /// name for a Windows virtual device, or a device name for a MS-DOS device driver.
+ /// - LegalCopyright: The Value member describes all copyright notices, trademarks, and
+ /// registered trademarks that apply to the file. This should include the full text of
+ /// all notices, legal symbols, copyright dates, trademark numbers, and so on. In
+ /// English, this string should be in the format "Copyright Microsoft Corp. 1990 1994".
+ /// - LegalTrademarks: The Value member describes all trademarks and registered trademarks
+ /// that apply to the file. This should include the full text of all notices, legal
+ /// symbols, trademark numbers, and so on. In English, this string should be in the
+ /// format "Windows is a trademark of Microsoft Corporation".
+ /// - OriginalFilename: The Value member identifies the original name of the file, not
+ /// including a path. This enables an application to determine whether a file has been
+ /// renamed by a user. This name may not be MS-DOS 8.3-format if the file is specific
+ /// to a non-FAT file system.
+ /// - PrivateBuild: The Value member describes by whom, where, and why this private version
+ /// of the file was built. This string should only be present if the VS_FF_PRIVATEBUILD
+ /// flag is set in the dwFileFlags member of the VS_FIXEDFILEINFO structure. For example,
+ /// Value could be "Built by OSCAR on \OSCAR2".
+ /// - ProductName: The Value member identifies the name of the product with which this file is
+ /// distributed. For example, this string could be "Microsoft Windows".
+ /// - ProductVersion: The Value member identifies the version of the product with which this
+ /// file is distributed. For example, Value could be "3.00A" or "5.00.RC2".
+ /// - SpecialBuild: The Value member describes how this version of the file differs from the
+ /// normal version. This entry should only be present if the VS_FF_SPECIALBUILD flag is
+ /// set in the dwFileFlags member of the VS_FIXEDFILEINFO structure. For example, Value
+ /// could be "Private build for Olivetti solving mouse problems on M250 and M250E computers".
+ ///
+ public string? Key { get; set; }
+
+ ///
+ /// As many zero words as necessary to align the Value member on a 32-bit boundary.
+ ///
+ public ushort Padding { get; set; }
+
+ ///
+ /// A zero-terminated string. See the szKey member description for more information.
+ ///
+ public string? Value { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringFileInfo.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringFileInfo.cs
new file mode 100644
index 00000000..f7098f02
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringFileInfo.cs
@@ -0,0 +1,43 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Represents the organization of data in a file-version resource. It contains version
+ /// information that can be displayed for a particular language and code page.
+ ///
+ ///
+ public sealed class StringFileInfo
+ {
+ ///
+ /// The length, in bytes, of the entire StringFileInfo block, including all
+ /// structures indicated by the Children member.
+ ///
+ public ushort Length { get; set; }
+
+ ///
+ /// This member is always equal to zero.
+ ///
+ public ushort ValueLength { get; set; }
+
+ ///
+ /// The type of data in the version resource.
+ ///
+ public VersionResourceType ResourceType { get; set; }
+
+ ///
+ /// The Unicode string L"StringFileInfo".
+ ///
+ public string? Key { get; set; }
+
+ ///
+ /// As many zero words as necessary to align the Children member on a 32-bit boundary.
+ ///
+ public ushort Padding { get; set; }
+
+ ///
+ /// An array of one or more StringTable structures. Each StringTable structure's Key
+ /// member indicates the appropriate language and code page for displaying the text in
+ /// that StringTable structure.
+ ///
+ public StringTable[]? Children { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringTable.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringTable.cs
new file mode 100644
index 00000000..287c126c
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringTable.cs
@@ -0,0 +1,46 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Represents the organization of data in a file-version resource. It contains language
+ /// and code page formatting information for the strings specified by the Children member.
+ /// A code page is an ordered character set.
+ ///
+ ///
+ public sealed class StringTable
+ {
+ ///
+ /// The length, in bytes, of this StringTable structure, including all structures
+ /// indicated by the Children member.
+ ///
+ public ushort Length { get; set; }
+
+ ///
+ /// This member is always equal to zero.
+ ///
+ public ushort ValueLength { get; set; }
+
+ ///
+ /// The type of data in the version resource.
+ ///
+ public VersionResourceType ResourceType { get; set; }
+
+ ///
+ /// An 8-digit hexadecimal number stored as a Unicode string. The four most significant
+ /// digits represent the language identifier. The four least significant digits represent
+ /// the code page for which the data is formatted. Each Microsoft Standard Language
+ /// identifier contains two parts: the low-order 10 bits specify the major language,
+ /// and the high-order 6 bits specify the sublanguage.
+ ///
+ public string? Key { get; set; }
+
+ ///
+ /// As many zero words as necessary to align the Children member on a 32-bit boundary.
+ ///
+ public ushort Padding { get; set; }
+
+ ///
+ /// An array of one or more StringData structures.
+ ///
+ public StringData[]? Children { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VarData.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VarData.cs
new file mode 100644
index 00000000..48796951
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VarData.cs
@@ -0,0 +1,50 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Represents the organization of data in a file-version resource. It typically contains a
+ /// list of language and code page identifier pairs that the version of the application or
+ /// DLL supports.
+ ///
+ ///
+ public sealed class VarData
+ {
+ ///
+ /// The length, in bytes, of the Var structure.
+ ///
+ public ushort Length { get; set; }
+
+ ///
+ /// The size, in words, of the Value member.
+ ///
+ public ushort ValueLength { get; set; }
+
+ ///
+ /// The type of data in the version resource.
+ ///
+ public VersionResourceType ResourceType { get; set; }
+
+ ///
+ /// The Unicode string L"Translation".
+ ///
+ public string? Key { get; set; }
+
+ ///
+ /// As many zero words as necessary to align the Value member on a 32-bit boundary.
+ ///
+ public ushort Padding { get; set; }
+
+ ///
+ /// An array of one or more values that are language and code page identifier pairs.
+ ///
+ /// If you use the Var structure to list the languages your application or DLL supports
+ /// instead of using multiple version resources, use the Value member to contain an array
+ /// of DWORD values indicating the language and code page combinations supported by this
+ /// file. The low-order word of each DWORD must contain a Microsoft language identifier,
+ /// and the high-order word must contain the IBM code page number. Either high-order or
+ /// low-order word can be zero, indicating that the file is language or code page
+ /// independent. If the Var structure is omitted, the file will be interpreted as both
+ /// language and code page independent.
+ ///
+ public uint[]? Value { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VarFileInfo.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VarFileInfo.cs
new file mode 100644
index 00000000..e9fc0976
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VarFileInfo.cs
@@ -0,0 +1,41 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Represents the organization of data in a file-version resource. It contains version
+ /// information not dependent on a particular language and code page combination.
+ ///
+ ///
+ public sealed class VarFileInfo
+ {
+ ///
+ /// The length, in bytes, of the entire VarFileInfo block, including all structures
+ /// indicated by the Children member.
+ ///
+ public ushort Length { get; set; }
+
+ ///
+ /// This member is always equal to zero.
+ ///
+ public ushort ValueLength { get; set; }
+
+ ///
+ /// The type of data in the version resource.
+ ///
+ public VersionResourceType ResourceType { get; set; }
+
+ ///
+ /// The Unicode string L"VarFileInfo".
+ ///
+ public string? Key { get; set; }
+
+ ///
+ /// As many zero words as necessary to align the Children member on a 32-bit boundary.
+ ///
+ public ushort Padding { get; set; }
+
+ ///
+ /// Typically contains a list of languages that the application or DLL supports.
+ ///
+ public VarData[]? Children { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VersionInfo.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VersionInfo.cs
new file mode 100644
index 00000000..7262e9c7
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/VersionInfo.cs
@@ -0,0 +1,61 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource.Entries
+{
+ ///
+ /// Represents the organization of data in a file-version resource. It is the root
+ /// structure that contains all other file-version information structures.
+ ///
+ ///
+ public sealed class VersionInfo
+ {
+ ///
+ /// The length, in bytes, of the VS_VERSIONINFO structure. This length does not
+ /// include any padding that aligns any subsequent version resource data on a
+ /// 32-bit boundary.
+ ///
+ public ushort Length { get; set; }
+
+ ///
+ /// The length, in bytes, of the Value member. This value is zero if there is no
+ /// Value member associated with the current version structure.
+ ///
+ public ushort ValueLength { get; set; }
+
+ ///
+ /// The type of data in the version resource. This member is 1 if the version resource
+ /// contains text data and 0 if the version resource contains binary data.
+ ///
+ public VersionResourceType ResourceType { get; set; }
+
+ ///
+ /// The Unicode string L"VS_VERSION_INFO".
+ ///
+ public string? Key { get; set; }
+
+ ///
+ /// Contains as many zero words as necessary to align the Value member on a 32-bit boundary.
+ ///
+ public ushort Padding1 { get; set; }
+
+ ///
+ /// Arbitrary data associated with this VS_VERSIONINFO structure. The ValueLength member
+ /// specifies the length of this member; if ValueLength is zero, this member does not exist.
+ ///
+ public FixedFileInfo? Value { get; set; }
+
+ ///
+ /// As many zero words as necessary to align the Children member on a 32-bit boundary.
+ /// These bytes are not included in wValueLength. This member is optional.
+ ///
+ public ushort Padding2 { get; set; }
+
+ ///
+ /// The StringFileInfo structure to store user-defined string information data.
+ ///
+ public StringFileInfo? StringFileInfo { get; set; }
+
+ ///
+ /// The VarFileInfo structure to store language information data.
+ ///
+ public VarFileInfo? VarFileInfo { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/ResourceHeader.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/ResourceHeader.cs
new file mode 100644
index 00000000..00fcb9c1
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/ResourceHeader.cs
@@ -0,0 +1,99 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.PortableExecutable.Resource
+{
+ ///
+ /// Contains information about the resource header itself and the data specific to
+ /// this resource. This structure is not a true C-language structure, because it
+ /// contains variable-length members. The structure definition provided here is for
+ /// explanation only; it is not present in any standard header file.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public sealed class ResourceHeader
+ {
+ ///
+ /// The size, in bytes, of the data that follows the resource header for this
+ /// particular resource. It does not include any file padding between this
+ /// resource and any resource that follows it in the resource file.
+ ///
+ public uint DataSize;
+
+ ///
+ /// The size, in bytes, of the resource header data that follows.
+ ///
+ public uint HeaderSize;
+
+ ///
+ /// The resource type. The TYPE member can either be a numeric value or a
+ /// null-terminated Unicode string that specifies the name of the type. See the
+ /// following Remarks section for a description of Name or Ordinal type members.
+ ///
+ /// If the TYPE member is a numeric value, it can specify either a standard or a
+ /// user-defined resource type. If the member is a string, then it is a
+ /// user-defined resource type.
+ ///
+ /// Values less than 256 are reserved for system use.
+ ///
+ [MarshalAs(UnmanagedType.U4)]
+ public ResourceType ResourceType;
+
+ ///
+ /// A name that identifies the particular resource. The NAME member, like the TYPE
+ /// member, can either be a numeric value or a null-terminated Unicode string.
+ /// See the following Remarks section for a description of Name or Ordinal type
+ /// members.
+ ///
+ /// You do not need to add padding for DWORD alignment between the TYPE and NAME
+ /// members because they contain WORD data. However, you may need to add a WORD of
+ /// padding after the NAME member to align the rest of the header on DWORD boundaries.
+ ///
+ public uint Name;
+
+ ///
+ /// A predefined resource data version. This will determine which version of the
+ /// resource data the application should use.
+ ///
+ public uint DataVersion;
+
+ ///
+ /// A set of attribute flags that can describe the state of the resource. Modifiers
+ /// in the .RC script file assign these attributes to the resource. The script
+ /// identifiers can assign the following flag values.
+ ///
+ /// Applications do not use any of these attributes. The attributes are permitted
+ /// in the script for backward compatibility with existing scripts, but they are
+ /// ignored. Resources are loaded when the corresponding module is loaded, and are
+ /// freed when the module is unloaded.
+ ///
+ [MarshalAs(UnmanagedType.U2)]
+ public MemoryFlags MemoryFlags;
+
+ ///
+ /// The language for the resource or set of resources. Set the value for this member
+ /// with the optional LANGUAGE resource definition statement. The parameters are
+ /// constants from the Winnt.h file.
+ ///
+ /// Each resource includes a language identifier so the system or application can
+ /// select a language appropriate for the current locale of the system. If there are
+ /// multiple resources of the same type and name that differ only in the language of
+ /// the strings within the resources, you will need to specify a LanguageId for each
+ /// one.
+ ///
+ public ushort LanguageId;
+
+ ///
+ /// A user-defined version number for the resource data that tools can use to read and
+ /// write resource files. Set this value with the optional VERSION resource definition
+ /// statement.
+ ///
+ public uint Version;
+
+ ///
+ /// Specifies user-defined information about the resource that tools can use to read and
+ /// write resource files. Set this value with the optional CHARACTERISTICS resource
+ /// definition statement.
+ ///
+ public uint Characteristics;
+ }
+}
diff --git a/SabreTools.Serialization/Models/PortableExecutable/TLS/Directory.cs b/SabreTools.Serialization/Models/PortableExecutable/TLS/Directory.cs
new file mode 100644
index 00000000..ccded4e6
--- /dev/null
+++ b/SabreTools.Serialization/Models/PortableExecutable/TLS/Directory.cs
@@ -0,0 +1,55 @@
+namespace SabreTools.Serialization.Models.PortableExecutable.TLS
+{
+ ///
+ public sealed class Directory
+ {
+ ///
+ /// The starting address of the TLS template. The template is a block of data
+ /// that is used to initialize TLS data. The system copies all of this data
+ /// each time a thread is created, so it must not be corrupted. Note that this
+ /// address is not an RVA; it is an address for which there should be a base
+ /// relocation in the .reloc section.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong RawDataStartVA { get; set; }
+
+ ///
+ /// The address of the last byte of the TLS, except for the zero fill. As
+ /// with the Raw Data Start VA field, this is a VA, not an RVA.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong RawDataEndVA { get; set; }
+
+ ///
+ /// The location to receive the TLS index, which the loader assigns. This
+ /// location is in an ordinary data section, so it can be given a symbolic
+ /// name that is accessible to the program.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong AddressOfIndex { get; set; }
+
+ ///
+ /// The pointer to an array of TLS callback functions. The array is
+ /// null-terminated, so if no callback function is supported, this field
+ /// points to 4 bytes set to zero.
+ ///
+ /// This value is 32-bit if PE32 and 64-bit if PE32+
+ public ulong AddressOfCallbacks { get; set; }
+
+ ///
+ /// The size in bytes of the template, beyond the initialized data delimited
+ /// by the Raw Data Start VA and Raw Data End VA fields. The total template
+ /// size should be the same as the total size of TLS data in the image file.
+ /// The zero fill is the amount of data that comes after the initialized
+ /// nonzero data.
+ ///
+ public uint SizeOfZeroFill { get; set; }
+
+ ///
+ /// The four bits [23:20] describe alignment info. Possible values are those
+ /// defined as IMAGE_SCN_ALIGN_*, which are also used to describe alignment
+ /// of section in object files. The other 28 bits are reserved for future use.
+ ///
+ public uint Characteristics { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/SafeDisc/Constants.cs b/SabreTools.Serialization/Models/SafeDisc/Constants.cs
new file mode 100644
index 00000000..1fa2bb6e
--- /dev/null
+++ b/SabreTools.Serialization/Models/SafeDisc/Constants.cs
@@ -0,0 +1,9 @@
+namespace SabreTools.Serialization.Models.SafeDisc
+{
+ public static class Constants
+ {
+ public const uint EncryptedFileEntrySignature1 = 0xA8726B03;
+
+ public const uint EncryptedFileEntrySignature2 = 0xEF01996C;
+ }
+}
diff --git a/SabreTools.Serialization/Models/SafeDisc/EncryptedFileEntry.cs b/SabreTools.Serialization/Models/SafeDisc/EncryptedFileEntry.cs
new file mode 100644
index 00000000..e8fba1e2
--- /dev/null
+++ b/SabreTools.Serialization/Models/SafeDisc/EncryptedFileEntry.cs
@@ -0,0 +1,33 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.SafeDisc
+{
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public class EncryptedFileEntry
+ {
+ ///
+ /// 0xA8726B03
+ ///
+ public uint Signature1;
+
+ ///
+ /// 0xEF01996C
+ ///
+ public uint Signature2;
+
+ public uint FileNumber;
+
+ public uint Offset1;
+
+ public uint Offset2;
+
+ public uint Unknown1;
+
+ public uint Unknown2;
+
+ /// 0x0D bytes
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x0D)]
+ public byte[]? Name;
+ }
+}
diff --git a/SabreTools.Serialization/Models/SecuROM/AddD.cs b/SabreTools.Serialization/Models/SecuROM/AddD.cs
new file mode 100644
index 00000000..9723b921
--- /dev/null
+++ b/SabreTools.Serialization/Models/SecuROM/AddD.cs
@@ -0,0 +1,61 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.SecuROM
+{
+ ///
+ /// Overlay data associated with SecuROM executables
+ ///
+ ///
+ /// All information in this file has been researched in a clean room
+ /// environment by using sample from legally obtained software that
+ /// is protected by SecuROM.
+ ///
+ public sealed class AddD
+ {
+ ///
+ /// "AddD", Identifier?
+ ///
+ public uint Signature { get; set; }
+
+ /// s
+ /// Unknown (Entry count?)
+ ///
+ ///
+ /// 3 in EXPUNGED, 3.17.00.0017, 3.17.00.0019
+ /// 3 in 4.47.00.0039, 4.84.00.0054, 4.84.69.0037, 4.84.76.7966, 4.84.76.7968, 4.85.07.0009
+ ///
+ public uint EntryCount { get; set; }
+
+ ///
+ /// Version, always 8 bytes?
+ ///
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string? Version;
+
+ ///
+ /// Unknown (Build? Formatted as a string)
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public char[]? Build;
+
+ ///
+ /// Unknown (0x14h), Variable number of bytes before entry table
+ ///
+ ///
+ /// 44 bytes in EXPUNGED, 3.17.00.0017, 3.17.00.0019, 4.47.00.0039
+ /// 112 bytes in 4.84.00.0054, 4.84.69.0037, 4.84.76.7966, 4.84.76.7968, 4.85.07.0009
+ /// 112 byte range contains a fixed-length string at 0x2C, possibly a product ID?
+ /// "801400-001" in 4.84.00.0054
+ /// "594130-001" in 4.84.69.0037
+ /// "554900-001" in 4.84.76.7966
+ /// "554900-001" in 4.84.76.7968
+ /// "548520-001" in 4.85.07.0009
+ ///
+ public byte[]? Unknown14h { get; set; }
+
+ ///
+ /// Entry table
+ ///
+ public AddDEntry[]? Entries { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/SecuROM/AddDEntry.cs b/SabreTools.Serialization/Models/SecuROM/AddDEntry.cs
new file mode 100644
index 00000000..8d497419
--- /dev/null
+++ b/SabreTools.Serialization/Models/SecuROM/AddDEntry.cs
@@ -0,0 +1,79 @@
+using System.Runtime.InteropServices;
+
+namespace SabreTools.Serialization.Models.SecuROM
+{
+ ///
+ /// Overlay data associated with SecuROM executables
+ ///
+ ///
+ /// All information in this file has been researched in a clean room
+ /// environment by using sample from legally obtained software that
+ /// is protected by SecuROM.
+ ///
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public sealed class AddDEntry
+ {
+ ///
+ /// Physical offset of the embedded file
+ ///
+ public uint PhysicalOffset;
+
+ ///
+ /// Length of the embedded file
+ ///
+ /// The last entry seems to be 4 bytes short in 4.47.00.0039
+ public uint Length;
+
+ ///
+ /// Unknown (0x08)
+ ///
+ /// 3149224 [3496, 48] in the sample (all 3 entries) in 4.47.00.0039
+ public uint Unknown08h;
+
+ ///
+ /// Unknown (0x0C)
+ ///
+ /// 3147176 [1448, 48] in the sample (all 3 entries) in 4.47.00.0039
+ public uint Unknown0Ch;
+
+ ///
+ /// Unknown (0x10)
+ ///
+ /// 3149224 [3496, 48] in the sample (all 3 entries) in 4.47.00.0039
+ public uint Unknown10h;
+
+ ///
+ /// Unknown (0x14)
+ ///
+ /// 1245044 [65396, 18] in the sample (all 3 entries) in 4.47.00.0039
+ public uint Unknown14h;
+
+ ///
+ /// Unknown (0x18)
+ ///
+ /// 4214725 [20421, 64] in the sample (all 3 entries) in 4.47.00.0039
+ public uint Unknown18h;
+
+ ///
+ /// Unknown (0x1C)
+ ///
+ /// 2 [2, 0] in the sample (all 3 entries) in 4.47.00.0039
+ public uint Unknown1Ch;
+
+ ///
+ /// Entry file name (null-terminated)
+ ///
+ /// 12 bytes long in the sample (all 3 entries) in 4.47.00.0039
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string? FileName;
+
+ ///
+ /// Unknown (0x2C)
+ ///
+ ///
+ /// Offset based on consistent-sized filenames (12 bytes) in 4.47.00.0039
+ /// 132 [132, 0] in the sample (all 3 entries) in 4.47.00.0039
+ ///
+ public uint Unknown2Ch;
+ }
+}
diff --git a/SabreTools.Serialization/Models/SecuROM/Constants.cs b/SabreTools.Serialization/Models/SecuROM/Constants.cs
new file mode 100644
index 00000000..fc2a941a
--- /dev/null
+++ b/SabreTools.Serialization/Models/SecuROM/Constants.cs
@@ -0,0 +1,130 @@
+
+namespace SabreTools.Serialization.Models.SecuROM
+{
+ public static class Constants
+ {
+ #region AddD
+
+ public const string AddDMagicString = "AddD";
+
+ public static readonly byte[] AddDMagicBytes = [0x41, 0x64, 0x64, 0x44];
+
+ #endregion
+
+ #region DFA
+
+ public static readonly string DFAMagicString = "SDFA" + (char)0x04 + (char)0x00 + (char)0x00 + (char)0x00;
+
+ public static readonly byte[] DFAMagicBytes = [0x53, 0x44, 0x46, 0x41, 0x04, 0x00, 0x00, 0x00];
+
+ #region Keys
+
+ ///
+ /// 128-bit value, possibly a GUID
+ ///
+ public const string COID = "COID";
+
+ ///
+ /// 128-bit value, possibly a GUID
+ ///
+ /// Only a value of D0 A2 25 C7 16 20 B7 43 99 74 2A BB 39 6B C3 57 has been found
+ public const string CUID = "CUID";
+
+ ///
+ /// Encrypted data section
+ ///
+ public const string DATA = "DATA";
+
+ ///
+ /// Header version (?)
+ ///
+ /// Only a value of 0C 00 00 00 has been found
+ public const string HVER = "HVER";
+
+ ///
+ /// Unknown value
+ ///
+ public const string INVE = "INVE";
+
+ ///
+ /// Unknown key value
+ ///
+ public const string KEYB = "KEYB";
+
+ ///
+ /// Unknown key value
+ ///
+ public const string KEYL = "KEYL";
+
+ ///
+ /// MAC address (?)
+ ///
+ public const string MAC1 = "MAC1";
+
+ ///
+ /// MAC address (?)
+ ///
+ public const string MAC2 = "MAC2";
+
+ ///
+ /// Padding section
+ ///
+ /// Only a length of 832 has been found
+ public const string PAD1 = "PAD1";
+
+ ///
+ /// Private key ID (?)
+ ///
+ public const string PKID = "PKID";
+
+ ///
+ /// Private key name (?)
+ ///
+ /// Seemingly a UTF-16 string
+ public const string PKNA = "PKNA";
+
+ ///
+ /// Size of the decrypted executable
+ ///
+ public const string RAWS = "RAWS";
+
+ ///
+ /// 128-bit value, possibly a GUID
+ ///
+ /// Only a value of all zeroes has been found
+ public const string SCID = "SCID";
+
+ ///
+ /// Time stored in NTFS filetime
+ ///
+ ///
+ public const string TIME = "TIME";
+
+ ///
+ /// First URL to connect to
+ ///
+ public const string UR01 = "UR01";
+
+ ///
+ /// Second URL to connect to
+ ///
+ public const string UR02 = "UR02";
+
+ ///
+ /// Unknown value
+ ///
+ public const string XSPF = "XSPF";
+
+ #endregion
+
+ #endregion
+
+ #region Matroshka
+
+ public const string MatroshkaMagicString = "MatR";
+
+ public static readonly byte[] MatroshkaMagicBytes = [0x4D, 0x61, 0x74, 0x52];
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/SecuROM/DFAEntry.cs b/SabreTools.Serialization/Models/SecuROM/DFAEntry.cs
new file mode 100644
index 00000000..bb49b585
--- /dev/null
+++ b/SabreTools.Serialization/Models/SecuROM/DFAEntry.cs
@@ -0,0 +1,24 @@
+namespace SabreTools.Serialization.Models.SecuROM
+{
+ ///
+ /// Represents a single key-length-value tuple in a
+ /// SecuROM DFA file
+ ///
+ public class DFAEntry
+ {
+ ///
+ /// Entry name, always 4 ASCII characters
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// Length of the value in bytes
+ ///
+ public uint Length { get; set; }
+
+ ///
+ /// Value of the entry whose length is given by
+ ///
+ public byte[]? Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/SecuROM/DFAFile.cs b/SabreTools.Serialization/Models/SecuROM/DFAFile.cs
new file mode 100644
index 00000000..089ac4b9
--- /dev/null
+++ b/SabreTools.Serialization/Models/SecuROM/DFAFile.cs
@@ -0,0 +1,27 @@
+namespace SabreTools.Serialization.Models.SecuROM
+{
+ ///
+ /// Most DFA-protected files seem to also have additional encryption,
+ /// possibly SecuROM DFE. Only early RC-encrypted executables can be
+ /// parsed beyond the initial header.
+ ///
+ public class DFAFile
+ {
+ ///
+ /// "SDFA" 0x04 0x00 0x00 0x00
+ ///
+ /// 8 bytes
+ public byte[]? Signature { get; set; }
+
+ ///
+ /// Unknown value, possibly a block or header size
+ ///
+ /// Only a value of 0x400 has been found
+ public uint BlockOrHeaderSize { get; set; }
+
+ ///
+ /// All entries in the file
+ ///
+ public DFAEntry[]? Entries { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/SecuROM/Enums.cs b/SabreTools.Serialization/Models/SecuROM/Enums.cs
new file mode 100644
index 00000000..638b77a0
--- /dev/null
+++ b/SabreTools.Serialization/Models/SecuROM/Enums.cs
@@ -0,0 +1,36 @@
+namespace SabreTools.Serialization.Models.SecuROM
+{
+ public enum MatroshkaEntryType : uint
+ {
+ ///
+ /// Helper or activation executable
+ ///
+ Helper = 0x01,
+
+ ///
+ /// Main executable, usually one of the following:
+ /// - RC-encrypted executable to be decrypted later
+ /// - Main game program executable
+ /// - Revoker executable
+ ///
+ /// Usually the second entry
+ Main = 0x02,
+
+ ///
+ /// Required libraries for the main executable
+ ///
+ ///
+ /// Examples include:
+ /// - DFA.dll for RC-encrypted executables
+ /// - paul.dll for PA-protected games
+ /// - remover.exe for revocation
+ /// executables.
+ ///
+ Dependency = 0x04,
+
+ ///
+ /// Similar use to
+ ///
+ Unknown0x08 = 0x08,
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/SecuROM/MatroshkaEntry.cs b/SabreTools.Serialization/Models/SecuROM/MatroshkaEntry.cs
new file mode 100644
index 00000000..f1513f2b
--- /dev/null
+++ b/SabreTools.Serialization/Models/SecuROM/MatroshkaEntry.cs
@@ -0,0 +1,65 @@
+namespace SabreTools.Serialization.Models.SecuROM
+{
+ public class MatroshkaEntry
+ {
+ ///
+ /// File entry path, either 256 or 512 bytes
+ ///
+ ///
+ /// Versions without a key prefix are 256 bytes.
+ /// Versions with key values either are 256 or 512 bytes.
+ /// Stored as a string as the rest of the 256/512 bytes are just padding.
+ ///
+ public string? Path { get; set; }
+
+ ///
+ /// Type of the entry data
+ ///
+ public MatroshkaEntryType EntryType { get; set; }
+
+ ///
+ /// Data size
+ ///
+ public uint Size { get; set; }
+
+ ///
+ /// Data offset within the package
+ ///
+ public uint Offset { get; set; }
+
+ ///
+ /// Unknown value only seen in later versions
+ ///
+ /// Does not indicate that the offset is or isn't a 64-bit value
+ public uint? Unknown { get; set; }
+
+ ///
+ /// File modification time, stored in NTFS filetime.
+ ///
+ ///
+ public ulong ModifiedTime { get; set; }
+
+ ///
+ /// File creation time, stored in NTFS filetime.
+ ///
+ ///
+ public ulong CreatedTime { get; set; }
+
+ ///
+ /// File access time, stored in NTFS filetime.
+ ///
+ ///
+ public ulong AccessedTime { get; set; }
+
+ ///
+ /// MD5 hash of the data
+ ///
+ /// 16 bytes
+ public byte[]? MD5 { get; set; }
+
+ ///
+ /// The file data, stored as a byte array
+ ///
+ public byte[]? FileData { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/SecuROM/MatroshkaPackage.cs b/SabreTools.Serialization/Models/SecuROM/MatroshkaPackage.cs
new file mode 100644
index 00000000..19eb3458
--- /dev/null
+++ b/SabreTools.Serialization/Models/SecuROM/MatroshkaPackage.cs
@@ -0,0 +1,86 @@
+namespace SabreTools.Serialization.Models.SecuROM
+{
+ ///
+ /// Securom Matroschka Package PE section
+ ///
+ ///
+ /// Offered by SecuROM, its main purpose seems to be managing some sort
+ /// of SecuROM-related operation involving multiple temporary files
+ /// contained within the package. Observed in Release Control executables,
+ /// Product Activation Revocation executables, and in some regular
+ /// Product-Activation-protected releases (such as the digital download
+ /// releases of Neverwinter Nights 2 and Test Drive Unlimited) where the
+ /// game executable, paul.dll and other PA-related files are stored in
+ /// the matroschka package.
+ ///
+ public class MatroshkaPackage
+ {
+ ///
+ /// "MatR"
+ ///
+ /// 4 bytes
+ public string? Signature { get; set; }
+
+ ///
+ /// Number of internal entries
+ ///
+ public uint EntryCount { get; set; }
+
+ #region Longer Header only
+
+ // The combination of the 4 following values have only been seen in
+ // one of 4 distinct patterns. The meaning of these patterns is unknown.
+ // - 0 0 0
+ // - 0 0 1
+ // - 0 1 1
+ // - 1 1 1
+ // These values do not seem to have a link to whether the paths included
+ // in entries are 256- or 512-byte. There also do not seem to be any links
+ // between these values and the hex string values.
+ // There is one example of "0 0 0" which contains a key hex string of all
+ // 0x00 values and 256-byte paths.
+
+ ///
+ /// One of four unknown values only observed on longer header matroschka sections
+ ///
+ /// Only values of 0 or 1 have been found
+ public uint? UnknownRCValue1 { get; set; }
+
+ ///
+ /// One of four unknown values only observed on longer header matroschka sections
+ ///
+ /// Only values of 0 or 1 have been found
+ public uint? UnknownRCValue2 { get; set; }
+
+ ///
+ /// One of four unknown values only observed on longer header matroschka sections
+ ///
+ /// Only values of 0 or 1 have been found
+ public uint? UnknownRCValue3 { get; set; }
+
+ ///
+ /// 32-character hex string
+ ///
+ ///
+ /// This is all zeroes for all observed longer header non-RC matroschka sections. For RC sections, this is
+ /// always 630A411277DE8A4B9BB8DF2A14AC4C28, except for the executables for Crysis Wars and Crysis
+ /// Warhead, which are 9D2593B31A01E041AF6EDC15AEF5B969. Those two are noteworthy as they appear to be the
+ /// earliest known RC games, have a strange key in the encrypted executable, and are the only games that cannot
+ /// currently be manually unlocked (and thus, cannot be unlocked at all at the moment). So, this may indicate
+ /// something about version, functionality, or otherwise?
+ ///
+ public string? KeyHexString { get; set; }
+
+ ///
+ /// Padding for alignment, always 0x00000000
+ ///
+ public uint? Padding { get; set; }
+
+ #endregion
+
+ ///
+ /// Entries array whose length is given by
+ ///
+ public MatroshkaEntry[]? Entries { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/AddDirectoryToPath.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddDirectoryToPath.cs
new file mode 100644
index 00000000..5d98776a
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddDirectoryToPath.cs
@@ -0,0 +1,36 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Add Directory to PATH
+ ///
+ /// This action adds a directory to the PATH environment variable, as set in Autoexec.bat.
+ /// The directory is appended to every occurrence of the SET PATH statement that does not
+ /// already contain it. A SET PATH statement is added if none exists. The system restarts at
+ /// the end of installation so that the new PATH takes effect.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f0".
+ ///
+ ///
+ public class AddDirectoryToPath : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Location to add [start of PATH or end of PATH] (unknown)
+ /// + No indication that this flag is respected, if it exists
+ /// - Add to all PATH variables (unknown)
+ /// + Only seems to apply to AUTOEXEC.BAT-based paths?
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Directory name to add to path
+ ///
+ /// May contain a variable name
+ public string? Directory { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/AddTextToInstallLog.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddTextToInstallLog.cs
new file mode 100644
index 00000000..186160c4
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddTextToInstallLog.cs
@@ -0,0 +1,28 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Add Text to INSTALL.LOG
+ ///
+ /// This action adds commands to the installation log (Install.log).
+ ///
+ /// Use the Open/Close Install.log action to create the installation log.
+ ///
+ /// As the installation runs on the destination computer, each action it performs is logged in
+ /// the installation log (installation of files, additions or changes to registry, and so on).
+ /// Failures are listed also, with the reason for failure. The uninstall reverses each action
+ /// recorded in the Install.log, starting at the bottom of the log and going up. Typically, you
+ /// add commands to the Install.log to customize the uninstall process for an application.
+ ///
+ /// Because the log is written continuously during installation, the location of the text in the
+ /// log depends on where in the script you place the Add Text to Install.log script line.
+ ///
+ ///
+ ///
+ public class AddTextToInstallLog : MachineStateData
+ {
+ ///
+ /// Text
+ ///
+ public string? Text { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToAutoexecBat.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToAutoexecBat.cs
new file mode 100644
index 00000000..3f03f9c4
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToAutoexecBat.cs
@@ -0,0 +1,62 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Add to AUTOEXEC.BAT
+ ///
+ /// This action edits Autoexec.bat, which is executed during startup, allowing you to add
+ /// commands that are executed before Windows loads.
+ ///
+ /// Insert commands at a particular line number, or search the file for specific text and
+ /// insert the new line before, after, or in place of the existing line. The destination
+ /// computer is restarted after installation to force the new commands to take effect.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f1".
+ ///
+ ///
+ public class AddToAutoexecBat : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Case Sensitive (0x01)
+ /// - Insert Action (unknown)
+ /// - Match Criteria (unknown)
+ /// - Ignore White Space (unknown)
+ /// - Make Backup File (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Full path to the text file to edit
+ ///
+ ///
+ /// Ignored because structure is shared with both
+ /// and
+ ///
+ public string? FileToEdit { get; set; }
+
+ ///
+ /// Text to insert into the file
+ ///
+ public string? TextToInsert { get; set; }
+
+ ///
+ /// Search for Text
+ ///
+ public string? SearchForText { get; set; }
+
+ ///
+ /// Comment Text
+ ///
+ public string? CommentText { get; set; }
+
+ ///
+ /// Line number to insert text at, 0 for append to end
+ ///
+ public int LineNumber { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToConfigSys.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToConfigSys.cs
new file mode 100644
index 00000000..d216adc0
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToConfigSys.cs
@@ -0,0 +1,60 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Add to CONFIG.SYS
+ ///
+ /// This action edits the Config.sys file to add new commands. Insert commands at a
+ /// particular line number, or search the file for specific text and insert the new line before,
+ /// after, or in place of the existing line. The destination computer is restarted automatically
+ /// to force the new commands to take effect.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f2".
+ ///
+ ///
+ public class AddToConfigSys : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Case Sensitive (0x01)
+ /// - Insert Action (unknown)
+ /// - Match Criteria (unknown)
+ /// - Ignore White Space (unknown)
+ /// - Make Backup File (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Full path to the text file to edit
+ ///
+ ///
+ /// Ignored because structure is shared with both
+ /// and
+ ///
+ public string? FileToEdit { get; set; }
+
+ ///
+ /// Text to insert into the file
+ ///
+ public string? TextToInsert { get; set; }
+
+ ///
+ /// Search for Text
+ ///
+ public string? SearchForText { get; set; }
+
+ ///
+ /// Comment Text
+ ///
+ public string? CommentText { get; set; }
+
+ ///
+ /// Line number to insert text at, 0 for append to end
+ ///
+ public int LineNumber { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToSystemIni.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToSystemIni.cs
new file mode 100644
index 00000000..36d41f06
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/AddToSystemIni.cs
@@ -0,0 +1,24 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Add to SYSTEM.INI
+ ///
+ /// (Windows 3.1x or Windows 9x only) This action adds a device entry to the 386Enh
+ /// section of the System.ini file. The destination computer is restarted automatically to
+ /// force the new device driver to be loaded.
+ ///
+ /// Do not use this action to modify the display driver (display=xxx) or any other non-
+ /// device entry. Instead, use the Edit INI action.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f3".
+ ///
+ ///
+ public class AddToSystemIni : FunctionData
+ {
+ ///
+ /// Full commandline for the device
+ ///
+ public string? DeviceName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/CallDllFunction.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/CallDllFunction.cs
new file mode 100644
index 00000000..f74f34cf
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/CallDllFunction.cs
@@ -0,0 +1,61 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Call DLL Function
+ ///
+ /// This action calls a .DLL function from a .DLL on the destination computer. They can be
+ /// be .DLLs you have written, .DLLs developed for WiseScript, or Windows .DLLs. You can
+ /// branch the script based on the returned results of a .DLL by setting the Action to Start
+ /// Block if Return Value True or Start While Loop.
+ ///
+ ///
+ /// This acts like the start of a block if a flag is set.
+ ///
+ ///
+ ///
+ public class CallDllFunction : MachineStateData
+ {
+ ///
+ /// Flags, unknown mapping
+ ///
+ ///
+ /// Expected Values:
+ /// - Start block if function returns true (0x02 or 0x03)
+ /// - Loop while function returns true (0x02 or 0x03)
+ /// - Hide progress bar before calling function (0x04)
+ /// - Unknown (0x08) - Internal library call?
+ /// - Unknown (0x10) - Results in the flag being (^ 0x30)
+ /// - Unknown (0x20) - Checked for existence along with 0x08
+ /// not existing to run a function. It also results
+ /// in the flag value being (^ 0x30)
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// DLL path/name or NULL for Wise internal
+ ///
+ public string? DllPath { get; set; }
+
+ ///
+ /// Function name
+ ///
+ public string? FunctionName { get; set; }
+
+ ///
+ /// Args?
+ ///
+ /// In older/trimmed scripts, this seems to be missing?
+ public string? Operand_4 { get; set; }
+
+ ///
+ /// Return variable from an external call
+ ///
+ /// In older/trimmed scripts, this seems to be missing?
+ public string? ReturnVariable { get; set; }
+
+ ///
+ /// One entry per language count
+ ///
+ public FunctionData[]? Entries { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckConfiguration.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckConfiguration.cs
new file mode 100644
index 00000000..2096ccb7
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckConfiguration.cs
@@ -0,0 +1,42 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Check Configuration
+ ///
+ /// This action tests the hardware configuration, operating system, and other characteristics
+ /// of the destination computer. As a result of this check, the action can display a message,
+ /// halt the installation after displaying a message, or start a conditional block.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f12".
+ /// This acts like the start of a block if a flag is set.
+ ///
+ ///
+ public class CheckConfiguration : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - System (unknown)
+ /// - Display Message Only (unknown)
+ /// - Abort Installation (unknown)
+ /// - Start Block (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Appears in the body of the message dialog box. Leave this blank to prevent the
+ /// message from appearing.
+ ///
+ /// If fully numeric, it was probably called Flags2 in the source
+ public string? Message { get; set; }
+
+ ///
+ /// Dialog box title
+ ///
+ public string? Title { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckDiskSpace.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckDiskSpace.cs
new file mode 100644
index 00000000..e7b868d6
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckDiskSpace.cs
@@ -0,0 +1,44 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Check Disk Space
+ ///
+ /// This action determines if enough disk space is available for the installation, based on
+ /// files that are always installed. You would use this action only if the WiseScript contains
+ /// Install File(s) actions that install files permanently on the destination computer.
+ ///
+ /// You can leave all fields blank and the action checks disk space for all files. This action
+ /// takes the cluster size of the disk into account.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f23".
+ ///
+ ///
+ public class CheckDiskSpace : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Do not cancel during silent installation (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Required disk space for up to 3 additional disks
+ ///
+ public string? ReserveSpace { get; set; }
+
+ ///
+ /// Variable to store the result of the space check
+ ///
+ public string? StatusVariable { get; set; }
+
+ ///
+ /// Component variables
+ ///
+ public string? ComponentVariables { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckHttpConnection.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckHttpConnection.cs
new file mode 100644
index 00000000..3ba4ade6
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckHttpConnection.cs
@@ -0,0 +1,45 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Check HTTP Connection
+ ///
+ /// This action determines whether a given URL is valid by using WinSock.dll to try to
+ /// download the HTML page.
+ ///
+ /// If the installation is not true 32-bit, specify both Win16 and Win32 error variables. Then,
+ /// the Win32 WinSock.dll is used, followed by the Win16 WinSock.dll. Otherwise, only the
+ /// 32-bit version is used.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f38".
+ ///
+ ///
+ public class CheckHttpConnection : FunctionData
+ {
+ ///
+ /// URL to check
+ ///
+ /// Includes http://
+ public string? UrlToCheck { get; set; }
+
+ ///
+ /// 32-bit windosck.dll error text return
+ ///
+ public string? Win32ErrorTextVariable { get; set; }
+
+ ///
+ /// 32-bit winsock.dll error code return
+ ///
+ public string? Win32ErrorNumberVariable { get; set; }
+
+ ///
+ /// 16-bit windosck.dll error text return
+ ///
+ public string? Win16ErrorTextVariable { get; set; }
+
+ ///
+ /// 16-bit winsock.dll error code return
+ ///
+ public string? Win16ErrorNumberVariable { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckIfFileDirExists.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckIfFileDirExists.cs
new file mode 100644
index 00000000..d049f650
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/CheckIfFileDirExists.cs
@@ -0,0 +1,47 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Check If File/Dir Exists
+ ///
+ /// This action determines if a file or directory exists, whether a directory is writable, or if a
+ /// .DLL is loaded into memory. It can perform different actions based on the result of the
+ /// check.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f19".
+ /// This acts like the start of a block if a flag is set.
+ ///
+ ///
+ public class CheckIfFileDirExists : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Display Message Only (unknown)
+ /// - Abort Installation (unknown)
+ /// - Start Block (unknown)
+ /// - Start While Loop (unknown)
+ /// - Perform loop at least once (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Pathname
+ ///
+ public string? Pathname { get; set; }
+
+ ///
+ /// Appears in the body of the message dialog box. Leave this blank to prevent the
+ /// message from appearing.
+ ///
+ public string? Message { get; set; }
+
+ ///
+ /// Dialog box title
+ ///
+ public string? Title { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ConfigODBCDataSource.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ConfigODBCDataSource.cs
new file mode 100644
index 00000000..92df3dc9
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ConfigODBCDataSource.cs
@@ -0,0 +1,46 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Config ODBC Data Source
+ ///
+ /// This action configures an ODBC data source for use with an existing ODBC (Open
+ /// Database Connectivity) driver.
+ ///
+ ///
+ ///
+ public class ConfigODBCDataSource : MachineStateData
+ {
+ ///
+ /// Flags
+ ///
+ ///
+ /// Expected flags:
+ /// - System (unknown)
+ /// - Display Message Only (unknown)
+ /// - Abort Installation (unknown)
+ /// - Start Block (unknown)
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// File format string
+ ///
+ ///
+ /// Formatted like "File Description (*.ext)"
+ ///
+ public string? FileFormat { get; set; }
+
+ ///
+ /// Connection string for the data source
+ ///
+ ///
+ /// Contains the following fields in order, separated
+ /// by 0x7F characters, similar to function calls:
+ /// - DSN=: Driver Name
+ /// - DSN=: Data Source Name
+ /// - DESCRIPTION=: Description of the data source
+ /// - DBQ=: Path to the database
+ ///
+ public string? ConnectionString { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/CopyLocalFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/CopyLocalFile.cs
new file mode 100644
index 00000000..98624428
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/CopyLocalFile.cs
@@ -0,0 +1,42 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Copy Local File
+ ///
+ /// This action copies uncompressed files from a floppy disk, CD, the destination computer,
+ /// or a network drive.
+ ///
+ ///
+ ///
+ public class CopyLocalFile : MachineStateData
+ {
+ ///
+ /// Unknown, 0x0C
+ ///
+ public ushort Flags { get; set; } // 0x00 - 0x01
+
+ ///
+ /// Padding
+ ///
+ ///
+ /// 40 bytes, padding because structure is internally
+ /// shared with
+ ///
+ public byte[]? Padding { get; set; } // 0x02 - 0x2A
+
+ ///
+ /// Destination path
+ ///
+ public string? Destination { get; set; } // 0x2B - ?
+
+ ///
+ /// Description, one per language + 1
+ ///
+ public string[]? Description { get; set; }
+
+ ///
+ /// Source file
+ ///
+ public string? Source { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/CreateDirectory.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/CreateDirectory.cs
new file mode 100644
index 00000000..65efa21d
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/CreateDirectory.cs
@@ -0,0 +1,23 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Create Directory
+ ///
+ /// Directories are created when files are installed to them. Use this action only to create an
+ /// empty directory on the destination computer.
+ ///
+ /// When a WiseScript is called by a Windows Installer installation, you also can create a
+ /// directory on the Features or Components tabs of Setup Editor in Windows Installer
+ /// Editor.
+ ///
+ ///
+ ///
+ public class CreateDirectory : MachineStateData
+ {
+ ///
+ /// Pathname of the directory to create
+ ///
+ /// Should start with a variable
+ public string? Pathname { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/CustomDialogSet.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/CustomDialogSet.cs
new file mode 100644
index 00000000..1f84e9ac
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/CustomDialogSet.cs
@@ -0,0 +1,38 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Custom Dialog
+ ///
+ /// Use this action to create your own dialog box or dialog box set.
+ ///
+ ///
+ ///
+ /// TODO: Document the decompressed file format
+ public class CustomDialogSet : MachineStateData
+ {
+ ///
+ /// Start of the deflated data
+ ///
+ public uint DeflateStart { get; set; }
+
+ ///
+ /// End of the deflated data
+ ///
+ public uint DeflateEnd { get; set; }
+
+ ///
+ /// Inflated data size
+ ///
+ public uint InflatedSize { get; set; }
+
+ ///
+ /// Display variable name
+ ///
+ public string? DisplayVariable { get; set; }
+
+ ///
+ /// Name
+ ///
+ public string? Name { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/DeflateEntry.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/DeflateEntry.cs
new file mode 100644
index 00000000..6c00c6fe
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/DeflateEntry.cs
@@ -0,0 +1,24 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Represents deflated file parameters
+ ///
+ ///
+ public class DeflateEntry
+ {
+ ///
+ /// Start of the deflated data
+ ///
+ public uint DeflateStart { get; set; }
+
+ ///
+ /// End of the deflated data
+ ///
+ public uint DeflateEnd { get; set; }
+
+ ///
+ /// Inflated data size
+ ///
+ public uint InflatedSize { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/DeleteFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/DeleteFile.cs
new file mode 100644
index 00000000..47dc6693
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/DeleteFile.cs
@@ -0,0 +1,30 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Delete File
+ ///
+ /// This action removes files from the destination computer.
+ ///
+ /// You do not need to delete temp files if you use the Get Temporary Filename action to
+ /// create them because they are deleted automatically.
+ ///
+ ///
+ ///
+ public class DeleteFile : MachineStateData
+ {
+ ///
+ /// Flags, unknown values
+ ///
+ ///
+ /// Expected flags:
+ /// - Include Sub-Directories (unknown)
+ /// - Remove Directory Containing Files (unknown)
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// Path name
+ ///
+ public string? Pathname { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/DisplayBillboard.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/DisplayBillboard.cs
new file mode 100644
index 00000000..38cb5aa9
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/DisplayBillboard.cs
@@ -0,0 +1,57 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Display Billboard
+ ///
+ /// This action displays a bitmap or .GRF file during installation if you have set the
+ /// background to display a gradient on the Screen page. Create .GRF files (scalable
+ /// bitmaps) with the Custom Billboard Editor.
+ ///
+ /// You can use up to 16 Display Billboard actions in the script.
+ ///
+ ///
+ ///
+ public class DisplayBillboard : MachineStateData
+ {
+ ///
+ /// Flags
+ ///
+ ///
+ /// Expected values:
+ /// - 0x3805 - Erase num?; Erase all?
+ /// - 0x4000 - Hide progress bar
+ ///
+ public ushort Flags { get; set; } // 0x01 - 0x02
+
+ ///
+ /// Flags(?)
+ ///
+ ///
+ /// Values from WISE0001.DLL
+ /// - >> 0x0F -> piVar3[10]
+ /// - & 0x4000 -> uVar8 = Operand_2 & 0x3FFF
+ /// - Unknown (0x8000)
+ ///
+ public ushort Operand_2 { get; set; } // 0x03 - 0x04
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Values from WISE0001.DLL
+ /// - & 0x4000 -> uVar8 = Operand_3 & 0x3FFF
+ ///
+ public ushort Operand_3 { get; set; } // 0x05 - 0x06
+
+ ///
+ /// Deflate information
+ ///
+ /// One per language
+ public DeflateEntry[]? DeflateInfo { get; set; } // 0x07 -
+
+ ///
+ /// Terminator?
+ ///
+ public byte Terminator { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/DisplayMessage.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/DisplayMessage.cs
new file mode 100644
index 00000000..ea9c3fa2
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/DisplayMessage.cs
@@ -0,0 +1,30 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Display Message
+ ///
+ /// This action displays a message dialog box and can optionally branch the script based on
+ /// the end user response. Without the branching option, this dialog box has an OK button,
+ /// which continues, and a Cancel button, which halts installation.
+ ///
+ ///
+ ///
+ public class DisplayMessage : MachineStateData
+ {
+ ///
+ /// Flags, unknown mapping
+ ///
+ ///
+ /// Expected flags:
+ /// - Message icon(?)
+ /// - Start If Block (0x01)
+ /// - No Cancel (unknown)
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// Strings, two per language (1 title and 1 message)
+ ///
+ public string[]? TitleText { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/EditIniFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/EditIniFile.cs
new file mode 100644
index 00000000..4120e3a8
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/EditIniFile.cs
@@ -0,0 +1,31 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Edit INI File
+ ///
+ /// This action edits an .INI file on the destination computer. To edit SYSTEM.INI, use the
+ /// Add to SYSTEM.INI action instead.
+ ///
+ ///
+ ///
+ public class EditIniFile : MachineStateData
+ {
+ ///
+ /// Path name to INI file
+ ///
+ /// Open for writing in append mode
+ public string? Pathname { get; set; }
+
+ ///
+ /// INI section, represented by a Settings line
+ /// in the original script
+ ///
+ public string? Section { get; set; }
+
+ ///
+ /// Multiline string containing values, each representing
+ /// a new Settings line in the original script
+ ///
+ public string? Values { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/EditRegistry.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/EditRegistry.cs
new file mode 100644
index 00000000..6938eaf8
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/EditRegistry.cs
@@ -0,0 +1,63 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Edit Registry
+ ///
+ /// This action adds, edits, or deletes registry keys or values. You can create registry entries
+ /// manually or import a registry file (.REG).
+ ///
+ ///
+ /// The documentation mentions that there are multiple options, including
+ /// deleting keys and values, updating values, and adding new key-value
+ /// pairs. As far as research has taken, this set of options does not
+ /// appear to be immediately mappable to the data below.
+ ///
+ ///
+ ///
+ public class EditRegistry : MachineStateData
+ {
+ ///
+ /// Flags and Root
+ ///
+ ///
+ /// To get the root value, do (FlagsAndRoot & 0x1F)
+ /// Flag values:
+ /// - 0x10 - Force backup of registry value (if 0x80 == 0)
+ /// + It overrides the values set by 0x24 and 0x25
+ /// and then disables the flag after
+ /// - 0x40 - Delete? (If root is not 0?)
+ /// - 0x80 - Unknown
+ ///
+ public byte FlagsAndRoot { get; set; }
+
+ ///
+ /// Data type, defaults to 0 if not defined
+ /// in source scripts
+ ///
+ public byte DataType { get; set; }
+
+ ///
+ /// An unknown value that appears in some versions.
+ /// Its presence indicates to load an external DLL
+ /// for performing registry actions. Investigation
+ /// is needed on how to determine the script is the
+ /// version that uses this string or not.
+ ///
+ public string? UnknownFsllib { get; set; }
+
+ ///
+ /// Key path
+ ///
+ public string? Key { get; set; }
+
+ ///
+ /// New value
+ ///
+ public string? NewValue { get; set; }
+
+ ///
+ /// Value name
+ ///
+ public string? ValueName { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ElseIfStatement.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ElseIfStatement.cs
new file mode 100644
index 00000000..4fb6c896
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ElseIfStatement.cs
@@ -0,0 +1,30 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// ElseIf Statement
+ ///
+ /// This action is put inside an If block to check for another condition. It marks the
+ /// beginning of a block of code that is executed only if the condition checked by the If
+ /// Statement is false, all previous ElseIfs are false, and this ElseIf is true. You can use one
+ /// If Statement with multiple ElseIf Statements to check for multiple conditions.
+ ///
+ ///
+ ///
+ public class ElseIfStatement : MachineStateData
+ {
+ ///
+ /// Operator, values need to be mapped
+ ///
+ public byte Operator { get; set; }
+
+ ///
+ /// Variable name
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Value
+ ///
+ public string? Value { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ElseStatement.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ElseStatement.cs
new file mode 100644
index 00000000..d0b6737b
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ElseStatement.cs
@@ -0,0 +1,20 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Else Statement
+ ///
+ /// This action marks the beginning of a section of instructions to be executed when the
+ /// condition specified in the matching If action is false. It takes no parameters, and
+ /// selecting it from the Actions list inserts it directly into the script with no further dialog
+ /// boxes or prompts.
+ ///
+ ///
+ /// This acts like the start of a block.
+ ///
+ ///
+ ///
+ public class ElseStatement : MachineStateData
+ {
+ // There is no data
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/EndBlockStatement.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/EndBlockStatement.cs
new file mode 100644
index 00000000..fa617f9a
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/EndBlockStatement.cs
@@ -0,0 +1,28 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// End Block / End Statement
+ ///
+ /// This action marks the end of an If block or a While loop. It takes no parameters, and
+ /// selecting it from the Action list inserts it directly into the script with no further dialog
+ /// boxes or prompts.
+ ///
+ ///
+ /// The documentation mentions that this statement should contain no data
+ /// but there is still an operand that is apparently present. It is unknown what
+ /// this value could map to.
+ ///
+ ///
+ ///
+ public class EndBlockStatement : MachineStateData
+ {
+ ///
+ /// Unknown, maybe flags?
+ ///
+ ///
+ /// 0x00 - ???
+ /// 0x01 - ???
+ ///
+ public byte Operand_1 { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/EndUserDefinedAction.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/EndUserDefinedAction.cs
new file mode 100644
index 00000000..f97df616
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/EndUserDefinedAction.cs
@@ -0,0 +1,19 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// End User-Defined Action
+ ///
+ /// You create a user-defined action by creating a separate WiseScript and saving it in the
+ /// Actions subdirectory of this product’s installation directory, or in the shared directory
+ /// that is specified in Preferences.
+ ///
+ ///
+ /// This acts like the end of a block.
+ ///
+ ///
+ ///
+ public class EndUserDefinedAction : MachineStateData
+ {
+ // There is no data
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ExecuteProgram.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ExecuteProgram.cs
new file mode 100644
index 00000000..88e619c2
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ExecuteProgram.cs
@@ -0,0 +1,38 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Execute Program
+ ///
+ /// This action runs another .EXE. The .EXE can be a file that is already installed on the
+ /// destination computer, a file you installed as part of the installation, or a file you provide
+ /// on a separate disk.
+ ///
+ /// If the .EXE you plan to execute is coded to pass back a return value, the resulting return
+ /// value is put into the variables %INSTALL_RESULT% and %PROCEXITCODE%. If the
+ /// EXE passes back a return value, mark the Wait for Program to Exit check box.
+ ///
+ ///
+ ///
+ public class ExecuteProgram : MachineStateData
+ {
+ ///
+ /// Flags, unknown values
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// Path to the program to execute
+ ///
+ public string? Pathname { get; set; }
+
+ ///
+ /// Command Line
+ ///
+ public string? CommandLine { get; set; }
+
+ ///
+ /// Default directory name
+ ///
+ public string? DefaultDirectory { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ExitInstallation.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ExitInstallation.cs
new file mode 100644
index 00000000..57d9b1da
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ExitInstallation.cs
@@ -0,0 +1,18 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Exit Installation
+ ///
+ /// This action exits the installation.
+ ///
+ /// No message appears unless you also set the RESTART variable.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f28".
+ ///
+ ///
+ public class ExitInstallation : FunctionData
+ {
+ // There is no data
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ExternalDllCall.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ExternalDllCall.cs
new file mode 100644
index 00000000..d42945da
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ExternalDllCall.cs
@@ -0,0 +1,20 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// External DLL Call
+ ///
+ /// This represents a call to an external DLL.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is invoked when
+ /// the external DLL path is provided.
+ ///
+ ///
+ public class ExternalDllCall : FunctionData
+ {
+ ///
+ /// Arguments passed in from the Call DLL Function
+ ///
+ public string[]? Args { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/FindFileInPath.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/FindFileInPath.cs
new file mode 100644
index 00000000..7ac82310
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/FindFileInPath.cs
@@ -0,0 +1,55 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Find File in Path
+ ///
+ /// This action searches for a file on the destination computer. If more than one match
+ /// exists, only the first match is returned.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f22".
+ /// This acts like the start of a block if the default value is omitted(?)
+ ///
+ ///
+ public class FindFileInPath : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Remove File Name (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Variable to store the path if it is found
+ ///
+ public string? VariableName { get; set; }
+
+ ///
+ /// File name, not a full path
+ ///
+ /// Wildcard characters are not allowed
+ public string? FileName { get; set; }
+
+ ///
+ /// Value to put in the variable if the file is not found
+ ///
+ /// Leave blank to evaluage to false for an if
+ public string? DefaultValue { get; set; }
+
+ ///
+ /// Semicolon-delimited list of directories to search
+ ///
+ /// Variables are allowed. If blank, PATH is used.
+ public string? SearchDirectories { get; set; }
+
+ ///
+ /// Optional description to display if the search takes longer than
+ /// 1.5 seconds to complete.
+ ///
+ public string? Description { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/FunctionData.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/FunctionData.cs
new file mode 100644
index 00000000..92494c55
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/FunctionData.cs
@@ -0,0 +1,7 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Base class for all function call data types
+ ///
+ public abstract class FunctionData { }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/GetEnvironmentVariable.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/GetEnvironmentVariable.cs
new file mode 100644
index 00000000..d8f39cb3
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/GetEnvironmentVariable.cs
@@ -0,0 +1,40 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Get Environment Variable
+ ///
+ /// This action puts the value of a Windows environment variable into a WiseScript variable.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f17".
+ ///
+ ///
+ public class GetEnvironmentVariable : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Remove File Name (non-zero value)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Variable name
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Environment variable name
+ ///
+ public string? Environment { get; set; }
+
+ ///
+ /// Optional default value used if environment variable
+ /// is not found
+ ///
+ public string? DefaultValue { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/GetRegistryKeyValue.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/GetRegistryKeyValue.cs
new file mode 100644
index 00000000..a1a4b3b6
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/GetRegistryKeyValue.cs
@@ -0,0 +1,51 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Get Registry Key Value
+ ///
+ /// This action puts the value of a registry key into a variable. Multi-line (MULTI_SZ)
+ /// registry values are read into a list format.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f9".
+ ///
+ ///
+ public class GetRegistryKeyValue : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Remove File Name (unknown)
+ /// - Expand Environment Variables (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Variable name
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Registry key
+ ///
+ public string? Key { get; set; }
+
+ ///
+ /// Default value if not found
+ ///
+ public string? Default { get; set; }
+
+ ///
+ /// Value name, blank for Win16
+ ///
+ public string? ValueName { get; set; }
+
+ ///
+ /// The root that contains the registry key.
+ ///
+ public string? Root { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/GetSystemInformation.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/GetSystemInformation.cs
new file mode 100644
index 00000000..4e926aa5
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/GetSystemInformation.cs
@@ -0,0 +1,57 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Get System Information
+ ///
+ /// This action retrieves information about the destination computer and puts it into a
+ /// variable.
+ ///
+ ///
+ ///
+ public class GetSystemInformation : MachineStateData
+ {
+ ///
+ /// Flags, values unknown
+ ///
+ ///
+ /// Expected flags:
+ /// - Retrieve Current Date/Time (unknown)
+ /// - Windows Version (unknown)
+ /// - DOS Version (unknown)
+ /// - K Bytes Physical Memory (unknown)
+ /// - File Date/Time Modified (unknown)
+ /// - File Version Number (unknown)
+ /// - Registered Owner Name (unknown)
+ /// - Registered Company Name (unknown)
+ /// - Drive Type for Pathname (unknown)
+ /// - First Network Drive (unknown)
+ /// - First CD-ROM Drive (unknown)
+ /// - Win32s Version (unknown)
+ /// - Full UNC Pathname
+ /// - Installer EXE Pathname
+ /// - File Size (Bytes)
+ /// - Volume Serial Number
+ /// - Volume Label
+ /// - Windows Logon Name
+ /// - Service Pack Number
+ /// - Current Date/Time (four-digit year)
+ /// - File Date/Time Modified (four-digit year)
+ /// - Disk Free Space (KBytes)
+ /// - Current Date/Time (Regional settings)
+ /// - UTC File Date/Time Modified
+ /// - Is OS 64 Bit
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// Variable name
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Used only for operations that retrieve information
+ /// on files or directories
+ ///
+ public string? Pathname { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/GetTemporaryFilename.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/GetTemporaryFilename.cs
new file mode 100644
index 00000000..1c4ec19b
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/GetTemporaryFilename.cs
@@ -0,0 +1,21 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Get Temporary Filename
+ ///
+ /// This action generates a unique, temporary file name and stores it in a variable. Use the
+ /// temporary name when you need to install a file to the Windows Temp directory
+ /// (%TEMP%). Files that you create using this file name are deleted when the installation
+ /// finishes. Example: Use this to install a .DLL that is called during installation, and is then
+ /// no longer needed.
+ ///
+ ///
+ ///
+ public class GetTemporaryFilename : MachineStateData
+ {
+ ///
+ /// Variable to store the temporary file name
+ ///
+ public string? Variable { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/IfWhileStatement.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/IfWhileStatement.cs
new file mode 100644
index 00000000..a63dfc6c
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/IfWhileStatement.cs
@@ -0,0 +1,70 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// If Statement / While Statement
+ ///
+ /// This action marks the beginning of a conditional block of script, an If block. If the
+ /// condition specified in the If Statement is true, the lines inside the If block are executed.
+ /// The If block can also contain an Else or several ElseIf actions.
+ ///
+ /// This action begins a While loop. An End Statement must end the loop. As long as the
+ /// condition specified in the While Statement Settings dialog box is true, the script lines
+ /// inside the loop execute repeatedly. If the condition is not true, then the While loop is
+ /// exited, and the next script line is executed.
+ ///
+ ///
+ ///
+ public class IfWhileStatement : MachineStateData
+ {
+ ///
+ /// Flags, unknown values
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - If or While loop (Possibly 0x10 == While, 0x20 == If)
+ /// - Perform While loop at least once (Possibly 0x40)
+ /// - Operation (Between 0x00 and 0x0F)
+ /// + Addition (unknown)
+ /// + Subtraction (unknown)
+ /// + Multiplication (unknown)
+ /// + Division (unknown)
+ /// + Left (unknown)
+ /// + Right (unknown)
+ /// + Mid (unknown)
+ /// + Concat (unknown)
+ /// + Instr (unknown)
+ /// + Before (unknown)
+ /// + After (unknown)
+ /// + Len (Possibly 0x0D)
+ /// + Lcase (unknown)
+ /// + Ucase (unknown)
+ /// + Ltrim (unknown)
+ /// + Rtrim (unknown)
+ /// + And (unknown)
+ /// + Or (unknown)
+ /// + Not (unknown)
+ /// + > (unknown)
+ /// + < (unknown)
+ /// + >= (unknown)
+ /// + <= (unknown)
+ /// + = (unknown)
+ /// + <> (unknown)
+ ///
+ /// If the Flags & 0x20 == 0 and Flags & 0x10 == 0,
+ /// the flag value in the stack is set back to
+ /// Flags ^ 0x60.
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// Variable name
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Value
+ ///
+ public string? Value { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/IncludeScript.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/IncludeScript.cs
new file mode 100644
index 00000000..5047abf5
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/IncludeScript.cs
@@ -0,0 +1,25 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Include Script
+ ///
+ /// This action adds an additional script to the current installation script. During compile,
+ /// the include script is copied into the calling script at the location of the Include Script
+ /// action, resulting in a combination of the scripts.
+ ///
+ /// Include scripts can save time because you can develop a library of WiseScripts that
+ /// perform specific functions, like subroutines. You can re-use include scripts and share
+ /// them with colleagues. They typically contain just a few lines of code, such as calling an
+ /// .EXE or displaying a particular dialog box. Include scripts can be any size with the
+ /// limitation that the calling script plus include scripts cannot be more than 32,000 lines.
+ ///
+ ///
+ ///
+ public class IncludeScript : MachineStateData
+ {
+ ///
+ /// Count of sequential 0x1B bytes, excluding the original opcode
+ ///
+ public int Count { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/InsertLineIntoTextFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/InsertLineIntoTextFile.cs
new file mode 100644
index 00000000..db8e9337
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/InsertLineIntoTextFile.cs
@@ -0,0 +1,55 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Insert Line Into Text File
+ ///
+ /// This action edits a text file on the destination computer. Use it to edit configuration files
+ /// that cannot be edited by Edit INI File, Add Device to System.ini, Add Command to
+ /// Config.sys, or Add Command to Autoexec.bat.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f25".
+ ///
+ ///
+ public class InsertLineIntoTextFile : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Case Sensitive (0x01)
+ /// - Insert Action (unknown)
+ /// - Match Criteria (unknown)
+ /// - Ignore White Space (unknown)
+ /// - Make Backup File (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Full path to the text file to edit
+ ///
+ public string? FileToEdit { get; set; }
+
+ ///
+ /// Text to insert into the file
+ ///
+ public string? TextToInsert { get; set; }
+
+ ///
+ /// Search for Text
+ ///
+ public string? SearchForText { get; set; }
+
+ ///
+ /// Comment Text
+ ///
+ public string? CommentText { get; set; }
+
+ ///
+ /// Line number to insert text at, 0 for append to end
+ ///
+ public int LineNumber { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/InstallDirectXComponents.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/InstallDirectXComponents.cs
new file mode 100644
index 00000000..8dc0bb18
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/InstallDirectXComponents.cs
@@ -0,0 +1,43 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Install DirectX Components
+ ///
+ /// Little is known about this function other than it seems to install any
+ /// local DirectX components, if necessary. No official documentation
+ /// is publicly available that contains a reference to this.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f30".
+ ///
+ ///
+ public class InstallDirectXComponents : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - 0x40 - Unsets itself and sets 0x200 if not already
+ /// - If final value & 0x3fffff7f == 0, return failure
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Root path containing all DirectX components
+ ///
+ public string? RootPath { get; set; }
+
+ ///
+ /// Path to the DSETUP.DLL to be used
+ ///
+ public string? LibraryPath { get; set; }
+
+ ///
+ /// Unknown numeric value
+ ///
+ /// Not fully identified; replaces the flags if not 0?
+ public int SizeOrOffsetOrFlag { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/InstallFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/InstallFile.cs
new file mode 100644
index 00000000..78d86da0
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/InstallFile.cs
@@ -0,0 +1,102 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Install File
+ ///
+ /// This action installs files on the destination computer. Each file or directory to be installed
+ /// must have a separate Install File(s) action.
+ ///
+ ///
+ /// Multiple files can be included in the installer from
+ /// a single source Install File statement in the script.
+ /// Wildcards have been observed in a few examples to denote
+ /// entire directories or subdirectories being copied.
+ ///
+ ///
+ public class InstallFile : MachineStateData
+ {
+ ///
+ /// Values of 0x8000, 0x8100, 0x0000, 0x9800 0xA100 have been observed
+ ///
+ ///
+ /// Expected flags:
+ /// - Include Sub-Directories (unknown)
+ /// - Shared DLL Counter (unknown)
+ /// - No Progress Bar (unknown)
+ /// - Self-Register OCX/DLL/EXE/TLB (unknown)
+ /// - Replace Existing File [Always, Never, Check File [Doesn't Matter, Same or Older, Older]] (unknown)
+ /// - Retain Duplicates in Path (unknown)
+ ///
+ /// This is two separate fields in WISE0001.DLL (bVar1 and bVar2)
+ ///
+ /// if (bVar2 & 0x48) == 0 && (bVar1 & 0x40) == 0
+ /// Checksum set? Verify the file if possible
+ /// if (bVar1 & 1) != 0 && action[0x13] != 0
+ /// See Operand_7
+ ///
+ public ushort Flags { get; set; } // 0x01 - 0x02
+
+ ///
+ /// Start of the deflated data
+ ///
+ public uint DeflateStart { get; set; } // 0x03 - 0x06
+
+ ///
+ /// End of the deflated data
+ ///
+ public uint DeflateEnd { get; set; } // 0x07 - 0x0A
+
+ ///
+ /// MS-DOS date
+ ///
+ public ushort Date { get; set; } // 0x0B - 0x0C
+
+ ///
+ /// MS-DOS time
+ ///
+ public ushort Time { get; set; } // 0x0D - 0x0E
+
+ ///
+ /// Inflated data size
+ ///
+ public uint InflatedSize { get; set; } // 0x0F - 0x12
+
+ ///
+ /// Unknown, 20 * \0? Not seen in hl15of16.exe and hl1316.exe
+ ///
+ ///
+ /// 20 bytes
+ /// 0x13 (4 bytes) - if (bVar1 & 1) != 0 && [0x13] != 0 [BLOCK]
+ /// 0x13 (4 bytes) = local_70
+ /// 0x17 (4 bytes) - local_6c
+ /// 0x1B (4 bytes) - local_68.PrivilegeCount
+ /// 0x1F (4 bytes) - local_68.Control
+ /// 0x23 (4 bytes) - local_68.Privilege[0].Luid.LowPart
+ ///
+ public byte[]? Operand_7 { get; set; } // 0x13 - 0x26
+
+ ///
+ /// CRC-32 checksum of the data
+ ///
+ /// Do not check when it is 0
+ public uint Crc32 { get; set; } // 0x27 - 0x2A
+
+ ///
+ /// Destination pathname
+ ///
+ public string? DestinationPathname { get; set; } // 0x2B - ?
+
+ ///
+ /// One file text per language
+ ///
+ public string[]? Description { get; set; }
+
+ ///
+ /// Source file
+ ///
+ ///
+ /// Unused because structure is internally shared with
+ ///
+ public string? Source { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/InvalidOperation.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/InvalidOperation.cs
new file mode 100644
index 00000000..aa252d62
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/InvalidOperation.cs
@@ -0,0 +1,15 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Invalid Operation
+ ///
+ /// This operation was found in WISE0001.DLL and appears to
+ /// abort installation with a return code of 0xfffffffe.
+ ///
+ ///
+ ///
+ public class InvalidOperation : MachineStateData
+ {
+ // There is no data
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/MachineStateData.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/MachineStateData.cs
new file mode 100644
index 00000000..75730a7a
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/MachineStateData.cs
@@ -0,0 +1,7 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Base class for all machine state data types
+ ///
+ public abstract class MachineStateData { }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/NewEvent.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/NewEvent.cs
new file mode 100644
index 00000000..a59084b1
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/NewEvent.cs
@@ -0,0 +1,38 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// New Event
+ ///
+ /// Event scripts handle events. (Example: The end user cancels the installation.)
+ ///
+ /// Mainline
+ ///
+ /// The primary script that’s executed during the normal installation process. It
+ /// contains placeholders for Cancel and Exit scripts. When you open a script, that script
+ /// is considered the “main installation script,” and is on the first tab below the
+ /// installation script.
+ ///
+ /// Exit
+ ///
+ /// The script that’s executed when the installation is complete, or when an Exit
+ /// Installation script command is executed. If you create a user-defined action, you
+ /// store its custom dialog box here.
+ ///
+ /// Cancel
+ ///
+ /// The script that’s executed when the end user cancels the installation. Because some
+ /// files might already be installed when the end user cancels, the Cancel script
+ /// contains the include script, rollback.wse, which returns the destination computer to
+ /// its pre-installation state.
+ ///
+ ///
+ ///
+ public class NewEvent : MachineStateData
+ {
+ ///
+ /// Padding bytes
+ ///
+ /// Either 0 or 6 bytes from samples
+ public byte[]? Padding { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/NoOp.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/NoOp.cs
new file mode 100644
index 00000000..e9598d4a
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/NoOp.cs
@@ -0,0 +1,15 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// No-op
+ ///
+ /// This operation was found in WISE0001.DLL and appears to
+ /// do nothing except move to the next operation.
+ ///
+ ///
+ ///
+ public class NoOp : MachineStateData
+ {
+ // There is no data
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/OpenCloseInstallLog.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/OpenCloseInstallLog.cs
new file mode 100644
index 00000000..d040e116
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/OpenCloseInstallLog.cs
@@ -0,0 +1,35 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Open/Close Install.log
+ ///
+ /// Use this action to create an installation log.
+ /// Normally, every file that is installed is recorded in the install.log. The uninstall works by
+ /// reading Install.log from bottom to top and reversing each recorded action.
+ ///
+ /// The Open/Close Install.log action lets you customize the uninstall, by turning logging off
+ /// and on at key points to prevent some actions from being recorded in the log. If you use
+ /// this action to stop logging, you must also use it to resume logging or no log file is
+ /// created.
+ ///
+ ///
+ ///
+ public class OpenCloseInstallLog : MachineStateData
+ {
+ ///
+ /// Flags, unknown values
+ ///
+ ///
+ /// Expected flags:
+ /// - Resume/Start writing entries into installation log (0x01/0x02?)
+ /// - Pause writing entries into installation log (0x00)
+ /// - Open new installation log (0x01/0x02?)
+ ///
+ public ushort Flags { get; set; }
+
+ ///
+ /// Log name used when opening a new log
+ ///
+ public string? LogName { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ParseString.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ParseString.cs
new file mode 100644
index 00000000..4f870d33
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ParseString.cs
@@ -0,0 +1,69 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Parse String
+ ///
+ /// This action splits a text string and places the results in two variables.
+ ///
+ /// You can split the string at a character or substring that you specify, which discards the
+ /// character or substring you specified. Example: If you split the string “ONE,TWO” at the
+ /// first occurrence of a comma, “ONE” is put into destination variable 1 and “TWO” is put
+ /// into the destination variable 2. If the character or substring is not found, the entire
+ /// string is put into destination variable 1, and nothing is put into destination variable 2.
+ /// The find is case-sensitive.
+ ///
+ /// You can also split a string at any arbitrary character position, which discards no
+ /// characters. Example: If you split the string “ONE,TWO” at character position four from
+ /// left, then “ONE,” is put into the destination variable 1 and “TWO” is put into the
+ /// destination variable 2.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f27".
+ ///
+ ///
+ public class ParseString : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Operation (unknown)
+ /// - Trim Spaces (unknown)
+ /// - Ignore Case (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Source Value
+ ///
+ ///
+ /// You enter text and variables (examples: %MAINDIR% or %MAINDIR%\%PICTDIR%).
+ /// To include a literal percent (%) symbol, use %%.
+ ///
+ public string? Source { get; set; }
+
+ ///
+ /// Pattern/Position at which to split
+ ///
+ ///
+ /// Character patterns are case-sensitive unless you mark Ignore Case.
+ /// To split at a pattern, enter any number of characters, including numbers,
+ /// and select one of the pattern options in Operation. To split a string
+ /// based on character position, enter the character position, where 1 is
+ /// the first character, and select one of the position options in Operation.
+ ///
+ public string? PatternPosition { get; set; }
+
+ ///
+ /// Variable to store the first half of the string
+ ///
+ public string? DestinationVariable1 { get; set; }
+
+ ///
+ /// Variable to store the second half of the string
+ ///
+ public string? DestinationVariable2 { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/PlayMultimediaFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/PlayMultimediaFile.cs
new file mode 100644
index 00000000..828c200d
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/PlayMultimediaFile.cs
@@ -0,0 +1,41 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Play Multimedia File
+ ///
+ /// This action plays an audio (.WAV) or video (.AVI) file during installation. Playback is
+ /// asynchronous, which means the sound or movie can play while the installation
+ /// continues. The multimedia file must be installed on the destination computer before this
+ /// action is called. It must be small enough to fit into the destination computer’s RAM for it
+ /// to play correctly, because the disk is heavily accessed by the installation process. To
+ /// produce sound, the destination computer must be properly equipped and configured.
+ ///
+ ///
+ ///
+ public class PlayMultimediaFile : MachineStateData
+ {
+ ///
+ /// Flags
+ ///
+ /// Values:
+ /// - Loop Continuously (0x01)
+ /// - File Type (WAV or AVI) (0x02 == AVI)
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// X Position on a 640 x 480 screen for AVI to play
+ ///
+ public ushort XPosition { get; set; }
+
+ ///
+ /// Y Position on a 640 x 480 screen for AVI to play
+ ///
+ public ushort YPosition { get; set; }
+
+ ///
+ /// Path to the .WAV or .AVI file
+ ///
+ public string? Pathname { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/PostToHttpServer.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/PostToHttpServer.cs
new file mode 100644
index 00000000..c8872eed
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/PostToHttpServer.cs
@@ -0,0 +1,45 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Post to HTTP Server
+ ///
+ /// This action posts information over the Internet to a Web server. (Example: Use it to
+ /// record user registration information or other data.) You must set up a CGI program or
+ /// Active Server Page (.ASP) on the server that accepts data sent by an HTTP POST
+ /// operation and deciphers encoded characters.
+ ///
+ /// The destination computer must have a valid Internet connection. If end users might not
+ /// have this capability, you can add a prompt on a dialog box asking the end user if they
+ /// have Internet connectivity. Then use the results from the prompt to run this action or
+ /// not.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f34".
+ /// This acts like the start of a block if a flag is set.
+ ///
+ ///
+ public class PostToHttpServer : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Ignore Errors (unknown)
+ /// - Abort Installation (unknown)
+ /// - Start Block (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// URL
+ ///
+ public string? URL { get; set; }
+
+ ///
+ /// Text to post in "field=data" format
+ ///
+ public string? PostData { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/PromptForFilename.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/PromptForFilename.cs
new file mode 100644
index 00000000..c5cce2a7
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/PromptForFilename.cs
@@ -0,0 +1,61 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Prompt for Filename
+ ///
+ /// This action prompts the end user to select a file using a standard Open or Save dialog
+ /// box. The complete path of the file or directory is returned in a variable. (Example: Use
+ /// the returned directory to set the installation directory for a subset of files.) No file is
+ /// actually opened or saved by this action. This action is included to provide backward
+ /// compatibility for older WiseScripts. In new scripts, use custom dialog boxes or dialog
+ /// box controls to perform the same function. This action requires an End Statement,
+ /// because it begins a block of statements, similar to an If Statement.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f35".
+ /// This acts like the start of a block.
+ ///
+ ///
+ public class PromptForFilename : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Dialog Type (unknown)
+ /// - Allow selection of multiple files (unknown)
+ /// - Prompt if file does not exist (unknown)
+ /// - File must exist (unknown)
+ /// - Pathname must exist (unknown)
+ /// - Skip write permissions test (unknown)
+ /// - Do not validate the pathname (unknown)
+ /// - Display prompt if overwriting existing file (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Destination variable for the selection
+ ///
+ public string? DestinationVariable { get; set; }
+
+ ///
+ /// Default extension if one is not entered
+ ///
+ public string? DefaultExtension { get; set; }
+
+ ///
+ /// Title for the dialog box
+ ///
+ public string? DialogTitle { get; set; }
+
+ ///
+ /// File types to appear in the selction list
+ ///
+ ///
+ /// Formatted like "File Description (*.ext);*.ext"
+ ///
+ public string? FilterList { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadIniValue.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadIniValue.cs
new file mode 100644
index 00000000..b6a9712f
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadIniValue.cs
@@ -0,0 +1,50 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Read INI Value
+ ///
+ /// This action reads an entry from an existing .INI file into a variable. Example: Obtain a
+ /// path to a file.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f8".
+ ///
+ ///
+ public class ReadIniValue : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Remove File Name (nonzero value)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Variable name
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Path to INI
+ ///
+ public string? Pathname { get; set; }
+
+ ///
+ /// INI section
+ ///
+ public string? Section { get; set; }
+
+ ///
+ /// Item key
+ ///
+ public string? Item { get; set; }
+
+ ///
+ /// Default value
+ ///
+ public string? DefaultValue { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadUpdateTextFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadUpdateTextFile.cs
new file mode 100644
index 00000000..7fc8e146
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadUpdateTextFile.cs
@@ -0,0 +1,46 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Read/Update Text File
+ ///
+ /// This action begins a loop that reads and, optionally, updates text in a text file. Each loop
+ /// puts the next line of text into a variable. You can put actions in the loop that change the
+ /// contents of the variable (example: Parse String). Optionally, the changed variable can
+ /// be written back to the file. The loop repeats for each line of the file. This action requires
+ /// an End Statement.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f33".
+ /// This acts like the start of a block.
+ ///
+ ///
+ public class ReadUpdateTextFile : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Read lines of file into variable (unknown)
+ /// - Update file with new contents of variable (unknown)
+ /// - Make Backup File (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Variable to store each line of the text file
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Full path to the text file to be edited
+ ///
+ public string? Pathname { get; set; }
+
+ ///
+ /// Language Strings
+ ///
+ public string? LanguageStrings { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadWriteBinaryFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadWriteBinaryFile.cs
new file mode 100644
index 00000000..f8d07d05
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/ReadWriteBinaryFile.cs
@@ -0,0 +1,52 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Read/Write Binary File
+ ///
+ /// This action reads from a binary file to a variable, or writes from a variable to a binary
+ /// file. If you write to the file, the existing information in the file is not moved, it is
+ /// overwritten.
+ ///
+ /// This action does not support reading or writing non-ASCII characters (characters with
+ /// codes above 127).
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f15".
+ ///
+ ///
+ public class ReadWriteBinaryFile : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Transfer Direction [0x00 == Read, 0x01 == Write]
+ /// - Null Terminated (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Full path to the binary file
+ ///
+ public string? FilePathname { get; set; }
+
+ ///
+ /// Name of the variable
+ ///
+ public string? VariableName { get; set; }
+
+ ///
+ /// Offset in the file to start from
+ ///
+ /// Encoded as a string
+ public int FileOffset { get; set; }
+
+ ///
+ /// Maximum number of bytes to process
+ ///
+ /// Encoded as a string
+ public int MaxLength { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/RegisterFont.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/RegisterFont.cs
new file mode 100644
index 00000000..b3ad6147
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/RegisterFont.cs
@@ -0,0 +1,25 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Register Font
+ ///
+ /// This action registers a new TrueType font (.TTF file) that has been copied into the
+ /// Windows font directory.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f10".
+ ///
+ ///
+ public class RegisterFont : FunctionData
+ {
+ ///
+ /// TrueType font filename, not path
+ ///
+ public string? FontFileName { get; set; }
+
+ ///
+ /// Full name of the font
+ ///
+ public string? FontName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/RenameFileDirectory.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/RenameFileDirectory.cs
new file mode 100644
index 00000000..5327feb5
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/RenameFileDirectory.cs
@@ -0,0 +1,24 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Rename File/Directory
+ ///
+ /// This action renames a file or directory on the destination computer. This can be an
+ /// existing file or directory, or a file or directory that your installation installed. The file
+ /// must not be busy.
+ ///
+ ///
+ ///
+ public class RenameFileDirectory : MachineStateData
+ {
+ ///
+ /// Full path to the existing file or directory
+ ///
+ public string? OldPathname { get; set; }
+
+ ///
+ /// New file or directory name
+ ///
+ public string? NewFileName { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/SearchForFile.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/SearchForFile.cs
new file mode 100644
index 00000000..03b3928c
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/SearchForFile.cs
@@ -0,0 +1,48 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Search for File
+ ///
+ /// This action searches for a file on local drives, network drives, or all drives, and returns
+ /// the full path to the file.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f13".
+ ///
+ ///
+ public class SearchForFile : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Return Type (unknown)
+ /// - Drives to Search (local, network, both) (unknown)
+ /// - Search Depth (unknown)
+ /// - Remove File Name (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Variable to store the file path
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Filename to search for
+ ///
+ public string? FileName { get; set; }
+
+ ///
+ /// Default value if the file is not found
+ ///
+ public string? DefaultValue { get; set; }
+
+ ///
+ /// Message to display during the search operation
+ ///
+ public string? MessageText { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/SelfRegisterOCXsDLLs.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/SelfRegisterOCXsDLLs.cs
new file mode 100644
index 00000000..3178732d
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/SelfRegisterOCXsDLLs.cs
@@ -0,0 +1,31 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Self-Register OCXs/DLLs
+ ///
+ /// Use this action to self-register all queued .OCX, .DLL, and .EXE files or to add an existing
+ /// file to the queue.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f29".
+ ///
+ ///
+ public class SelfRegisterOCXsDLLs : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Register all pending OCXs/DLLs/EXEs (unknown)
+ /// - Queue existing file for self-registration
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Description/Pathname
+ ///
+ public string? Description { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/SetFileAttributes.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/SetFileAttributes.cs
new file mode 100644
index 00000000..f865c297
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/SetFileAttributes.cs
@@ -0,0 +1,35 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Set File Attributes
+ ///
+ /// This action sets the attributes of one file or a group of files.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f12".
+ /// This acts like the start of a block if a flag is set.
+ ///
+ ///
+ public class SetFileAttributes : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Read Only (Maybe 0x01)
+ /// - Hidden (Maybe 0x02)
+ /// - System (Maybe 0x04)
+ /// - Scan Directory Tree (unknown)
+ /// - Archive (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// File to change
+ ///
+ /// Wildcards are allowed
+ public string? FilePathname { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/SetFilesBuffers.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/SetFilesBuffers.cs
new file mode 100644
index 00000000..25d30a2a
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/SetFilesBuffers.cs
@@ -0,0 +1,28 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Set Files/Buffers
+ ///
+ /// This action sets the FILES= and BUFFERS= lines in Config.sys. If either is currently
+ /// lower than the minimum specified in this action, it is increased to the specified value. If
+ /// either is already greater than the minimum specified in this action, it is not changed.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f21".
+ ///
+ ///
+ public class SetFilesBuffers : FunctionData
+ {
+ ///
+ /// Minimum files to be specfied in FILES= in CONFIG.SYS
+ ///
+ /// Blank means leave unchanged
+ public string? MinimumFiles { get; set; }
+
+ ///
+ /// Minimum buffers to be specfied in BUFFERS= in CONFIG.SYS
+ ///
+ /// Blank means leave unchanged
+ public string? MinimumBuffers { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/SetVariable.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/SetVariable.cs
new file mode 100644
index 00000000..cd87aff3
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/SetVariable.cs
@@ -0,0 +1,49 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Set Variable
+ ///
+ /// This action sets the value of a variable by providing a literal value, by modifying the
+ /// variable’s existing value, or by evaluating an expression.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f16".
+ ///
+ ///
+ public class SetVariable : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// (flags >> 2 & 0x0F)
+ /// - Nothing (0x00)
+ /// - Increment (0x04)
+ /// - Decrement (0x08)
+ /// - Remove trailing backslashes (0x0C)
+ /// - Convert to long filename (0x10)
+ /// - Convert to short filename (0x14)
+ /// - Convert to uppercase (0x18)
+ /// - Convert to lowercase (0x1C)
+ ///
+ /// One of the following is case 0x20:
+ /// - Evaluate Expression (unknown)
+ /// - Append to Existing Value (unknown)
+ /// - Remove File Name (unknown)
+ /// - Read Variable From Values File (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ ///
+ /// Variable name
+ ///
+ public string? Variable { get; set; }
+
+ ///
+ /// Value, optional
+ ///
+ public string? Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/StartStopService.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/StartStopService.cs
new file mode 100644
index 00000000..5bfab8a8
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/StartStopService.cs
@@ -0,0 +1,35 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Start/Stop Service
+ ///
+ /// This action lets you start or stop a service on the destination computer. It only applies to
+ /// operating systems that support services.
+ ///
+ /// When a WiseScript is called by a Windows Installer installation, you can also start and
+ /// stop services by using the Services page in Windows Installer Editor.
+ ///
+ /// After you try to stop a service, the script pauses to give the service time to stop. The
+ /// currently logged-in end user must have the appropriate privileges to start and stop
+ /// services.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f36".
+ ///
+ ///
+ public class StartStopService : FunctionData
+ {
+ ///
+ /// Operation
+ ///
+ ///
+ /// Stop = 0, Start = 1
+ ///
+ public byte Operation { get; set; }
+
+ ///
+ /// Internal name of the service to start or stop
+ ///
+ public string? ServiceName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/StartUserDefinedAction.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/StartUserDefinedAction.cs
new file mode 100644
index 00000000..070cf2a8
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/StartUserDefinedAction.cs
@@ -0,0 +1,19 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Start User-Defined Action
+ ///
+ /// You create a user-defined action by creating a separate WiseScript and saving it in the
+ /// Actions subdirectory of this product’s installation directory, or in the shared directory
+ /// that is specified in Preferences.
+ ///
+ ///
+ /// This acts like the start of a block.
+ ///
+ ///
+ ///
+ public class StartUserDefinedAction : MachineStateData
+ {
+ // There is no data
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x19.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x19.cs
new file mode 100644
index 00000000..ec4e575b
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x19.cs
@@ -0,0 +1,26 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ public class Unknown0x19 : MachineStateData
+ {
+ ///
+ /// Unknown
+ ///
+ public byte Operand_1 { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ public string? Operand_2 { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ public string? Operand_3 { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ public string? Operand_4 { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x24.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x24.cs
new file mode 100644
index 00000000..83ee9eb9
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x24.cs
@@ -0,0 +1,17 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Unknown
+ ///
+ ///
+ /// This action enables a flag that is used by this and .
+ /// It seems to only be referenced in contexts where there are registry
+ /// keys read and written, specifically about repair.
+ ///
+ ///
+ ///
+ public class Unknown0x24 : MachineStateData
+ {
+ // There is no data
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x25.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x25.cs
new file mode 100644
index 00000000..112df7e8
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/Unknown0x25.cs
@@ -0,0 +1,17 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Unknown
+ ///
+ ///
+ /// This action enables a flag that is used by this and .
+ /// It seems to only be referenced in contexts where there are registry
+ /// keys read and written, specifically about repair.
+ ///
+ ///
+ ///
+ public class Unknown0x25 : MachineStateData
+ {
+ // There is no data
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/UserDefinedActionStep.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/UserDefinedActionStep.cs
new file mode 100644
index 00000000..17013c17
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/UserDefinedActionStep.cs
@@ -0,0 +1,29 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// User-Defined Action Step
+ ///
+ /// You create a user-defined action by creating a separate WiseScript and saving it in the
+ /// Actions subdirectory of this product’s installation directory, or in the shared directory
+ /// that is specified in Preferences.
+ ///
+ ///
+ ///
+ public class UserDefinedActionStep : MachineStateData
+ {
+ ///
+ /// Flags for writing out
+ ///
+ ///
+ /// Values:
+ /// - 0x01 - Used as value appended to the end of the selected line
+ /// - 0x02 - Indicates if the string should be formatted(?)
+ ///
+ public byte Flags { get; set; }
+
+ ///
+ /// Script lines
+ ///
+ public string[]? ScriptLines { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/Win32SystemDirectory.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/Win32SystemDirectory.cs
new file mode 100644
index 00000000..ed5ae265
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/Win32SystemDirectory.cs
@@ -0,0 +1,22 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Win32 System Directory
+ ///
+ /// This action puts the path to the operating system directory (%WIN%\System32) into a
+ /// variable. Alternatively, use the predefined variables %SYS% or %SYS32% to access the
+ /// system directory. This action is included to provide backward compatibility for older
+ /// WiseScripts.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f11".
+ ///
+ ///
+ public class Win32SystemDirectory : FunctionData
+ {
+ ///
+ /// Variable name to store the value in
+ ///
+ public string? VariableName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Actions/WizardBlockLoop.cs b/SabreTools.Serialization/Models/WiseInstaller/Actions/WizardBlockLoop.cs
new file mode 100644
index 00000000..accd8a99
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Actions/WizardBlockLoop.cs
@@ -0,0 +1,81 @@
+namespace SabreTools.Serialization.Models.WiseInstaller.Actions
+{
+ ///
+ /// Wizard Block / Wizard Loop
+ ///
+ /// This action precedes dialog boxes that make up the majority of the installation’s end
+ /// user interface. End users can move forward and backward through these dialog boxes.
+ /// The script continues executing inside the wizard loop until the last dialog box has been
+ /// completed and accepted.
+ ///
+ ///
+ /// This action is called through Call DLL Function and is mapped to "f31".
+ /// This acts like the start of a block if a flag is set(?).
+ ///
+ ///
+ public class WizardBlockLoop : FunctionData
+ {
+ ///
+ /// Flags from the argument data
+ ///
+ ///
+ /// Encoded as a string, binary representation in script file.
+ /// Expected flags:
+ /// - Skip Dialog (unknown)
+ ///
+ public byte DataFlags { get; set; }
+
+ // TODO: Below is actually a list of dialog boxes
+ // TODO: Below should move to create dialog box
+
+ ///
+ /// Direction variable name
+ ///
+ /// "B" == Previous, "N" == Next
+ public string? DirectionVariable { get; set; }
+
+ ///
+ /// Display variable name
+ ///
+ public string? DisplayVariable { get; set; }
+
+ ///
+ /// X Position
+ ///
+ public int? XPosition { get; set; }
+
+ ///
+ /// Y Position, numeric
+ ///
+ public int? YPosition { get; set; }
+
+ ///
+ /// Filler Color, numeric
+ ///
+ public int? FillerColor { get; set; }
+
+ ///
+ /// Unknown, numeric
+ ///
+ public string? Operand_6 { get; set; }
+
+ ///
+ /// Unknown, numeric
+ ///
+ public string? Operand_7 { get; set; }
+
+ ///
+ /// Unknown, numeric
+ ///
+ public string? Operand_8 { get; set; }
+
+ ///
+ /// Either just a dialog name or a combination of
+ /// Dialog, Variable, Value, and Compare values
+ /// that are `\t` separated. Dialog and Variable
+ /// are both strings, Value and Compare both seem
+ /// to be numeric
+ ///
+ public string? DialogVariableValueCompare { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Constants.cs b/SabreTools.Serialization/Models/WiseInstaller/Constants.cs
new file mode 100644
index 00000000..7c678e0c
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Constants.cs
@@ -0,0 +1,106 @@
+using System.Collections.Generic;
+
+namespace SabreTools.Serialization.Models.WiseInstaller
+{
+ public static class Constants
+ {
+ ///
+ /// Count of per-language strings for an Action
+ ///
+ /// Derived from WISE0001.DLL
+ public static readonly byte[] CountOfLanguageActionStrings =
+ [
+ 0x01, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ ///
+ /// Count of non-language strings for an Action
+ ///
+ ///
+ /// Derived from WISE0001.DLL
+ /// One variant of the DLL has action 0x06 have a
+ /// value of `0x01` instead of `0x00`.
+ /// One variant of the DLL has action 0x18 have a
+ /// value of `0x01` instead of `0x00`.
+ ///
+ public static readonly byte[] CountOfStaticActionStrings =
+ [
+ 0x02, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x03,
+ 0x00, 0x04, 0x03, 0x01, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x03, 0x00, 0x02, 0x02, 0x01, 0x01,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x02, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ ///
+ /// Size of the invariant data for an Action
+ ///
+ ///
+ /// One variant of the DLL has action 0x18 have a
+ /// value of `0x06` instead of `0x01`.
+ ///
+ public static readonly byte[] SizeOfStaticActionData =
+ [
+ 0x2B, 0x00, 0x02, 0x02, 0x02, 0x01, 0x13, 0x02,
+ 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x00, 0x01,
+ 0x01, 0x01, 0x2B, 0x00, 0x0D, 0x02, 0x01, 0x06,
+ 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00,
+ ];
+
+ ///
+ /// "WIS" string for WiseSection 57, 49, 53
+ ///
+ public static readonly byte[] WisString =
+ [0x57, 0x49, 0x53];
+
+ ///
+ /// List of currently observed offsets for the "WIS" string in WiseSection
+ ///
+ public static readonly int[] WisOffsets =
+ [32, 33, 41, 77, 78, 82];
+
+ ///
+ /// Size of the header for a WiseSection
+ ///
+ public static readonly Dictionary WiseSectionHeaderLengthDictionary = new Dictionary()
+ {
+ {32, 6},
+ {33, 6},
+ {41, 8},
+ {77, 17},
+ {78, 17},
+ {82, 18},
+ };
+
+ ///
+ /// Offset from "WIS" string to be used as length of version field.
+ ///
+ public static readonly Dictionary WiseSectionVersionOffsetDictionary = new Dictionary()
+ {
+ {32, 4},
+ {33, 5},
+ {41, 5},
+ {77, 5},
+ {78, 6},
+ {82, 6},
+ };
+
+ ///
+ /// Size of pre-string byte array, guessed to be correlated with "WIS" string offset.
+ ///
+ public static readonly Dictionary WiseSectionPreStringBytesSize = new Dictionary()
+ {
+ {32, 8},
+ {33, 16},
+ {41, 18},
+ {77, 19},
+ {78, 19},
+ {82, 19},
+ };
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/Enums.cs b/SabreTools.Serialization/Models/WiseInstaller/Enums.cs
new file mode 100644
index 00000000..0f3074c0
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/Enums.cs
@@ -0,0 +1,418 @@
+namespace SabreTools.Serialization.Models.WiseInstaller
+{
+ ///
+ /// The CharacterSet Enumeration defines the possible sets of
+ /// character glyphs that are defined in fonts for graphics output.
+ ///
+ ///
+ public enum CharacterSet : uint
+ {
+ ANSI_CHARSET = 0x00000000,
+ DEFAULT_CHARSET = 0x00000001,
+ SYMBOL_CHARSET = 0x00000002,
+ MAC_CHARSET = 0x0000004D,
+ SHIFTJIS_CHARSET = 0x00000080,
+ HANGUL_CHARSET = 0x00000081,
+ JOHAB_CHARSET = 0x00000082,
+ GB2312_CHARSET = 0x00000086,
+ CHINESEBIG5_CHARSET = 0x00000088,
+ GREEK_CHARSET = 0x000000A1,
+ TURKISH_CHARSET = 0x000000A2,
+ VIETNAMESE_CHARSET = 0x000000A3,
+ HEBREW_CHARSET = 0x000000B1,
+ ARABIC_CHARSET = 0x000000B2,
+ BALTIC_CHARSET = 0x000000BA,
+ RUSSIAN_CHARSET = 0x000000CC,
+ THAI_CHARSET = 0x000000DE,
+ EASTEUROPE_CHARSET = 0x000000EE,
+ OEM_CHARSET = 0x000000FF
+ }
+
+ ///
+ /// Endianness of the file(?)
+ ///
+ ///
+ public enum Endianness : ushort
+ {
+ BigEndian = 0x0008,
+ LittleEndian = 0x0800,
+ }
+
+ ///
+ /// Opcodes for the state machine
+ ///
+ ///
+ public enum OperationCode : byte
+ {
+ ///
+ /// Install a file
+ ///
+ InstallFile = 0x00,
+
+ ///
+ /// Invalid case
+ ///
+ Invalid0x01 = 0x01,
+
+ ///
+ /// No-op
+ ///
+ /// Empty case in WISE0001.DLL
+ NoOp = 0x02,
+
+ ///
+ /// Display Message
+ ///
+ DisplayMessage = 0x03,
+
+ ///
+ /// User-Defined Action Step
+ ///
+ UserDefinedActionStep = 0x04,
+
+ ///
+ /// Edit INI File
+ ///
+ EditIniFile = 0x05,
+
+ ///
+ /// Display billboard
+ ///
+ DisplayBillboard = 0x06,
+
+ ///
+ /// Execute Program
+ ///
+ ExecuteProgram = 0x07,
+
+ ///
+ /// End block
+ ///
+ EndBlock = 0x08,
+
+ ///
+ /// Call DLL Function
+ ///
+ CallDllFunction = 0x09,
+
+ ///
+ /// Edit Registry
+ ///
+ EditRegistry = 0x0A,
+
+ ///
+ /// Delete File
+ ///
+ DeleteFile = 0x0B,
+
+ ///
+ /// If/While Statement
+ ///
+ IfWhileStatement = 0x0C,
+
+ ///
+ /// Else Statement
+ ///
+ ElseStatement = 0x0D,
+
+ ///
+ /// Invalid case
+ ///
+ Invalid0x0E = 0x0E,
+
+ ///
+ /// Start User-Defined Action
+ ///
+ StartUserDefinedAction = 0x0F,
+
+ ///
+ /// End User-Defined Action
+ ///
+ EndUserDefinedAction = 0x10,
+
+ ///
+ /// Create Directory
+ ///
+ CreateDirectory = 0x11,
+
+ ///
+ /// Copy Local File
+ ///
+ CopyLocalFile = 0x12,
+
+ ///
+ /// Invalid case
+ ///
+ Invalid0x13 = 0x13,
+
+ ///
+ /// Custom Dialog Set
+ ///
+ CustomDialogSet = 0x14,
+
+ ///
+ /// Get System Information
+ ///
+ GetSystemInformation = 0x15,
+
+ ///
+ /// Get Temporary Filename
+ ///
+ GetTemporaryFilename = 0x16,
+
+ ///
+ /// Play Multimedia File
+ ///
+ PlayMultimediaFile = 0x17,
+
+ ///
+ /// New Event
+ ///
+ /// Returns 0xffffffff in WISE0001.DLL
+ NewEvent = 0x18,
+
+ ///
+ /// Install ODBC Driver
+ ///
+ ///
+ /// Available documentation does not mention this action,
+ /// instead saying that the driver needs to be installed
+ /// before configuration. This may be a holdover from
+ /// older versions that required driver installation.
+ ///
+ InstallODBCDriver = 0x19,
+
+ ///
+ /// Config ODBC Data Source
+ ///
+ ConfigODBCDataSource = 0x1A,
+
+ ///
+ /// Include Script(?)
+ ///
+ ///
+ /// Acts like a no-op in the parsed script. Includes a
+ /// "Pathname" to the file to be included.
+ ///
+ /// In WISE0001.DLL, it seeks forward until it doesn't
+ /// find another 0x1B value again. Indicates that this
+ /// may not be "Include Script" as previously expected.
+ ///
+ IncludeScript = 0x1B,
+
+ ///
+ /// Add Text to INSTALL.LOG
+ ///
+ AddTextToInstallLog = 0x1C,
+
+ ///
+ /// Rename File/Directory
+ ///
+ RenameFileDirectory = 0x1D,
+
+ ///
+ /// Open/Close Install.log
+ ///
+ OpenCloseInstallLog = 0x1E,
+
+ ///
+ /// Invalid case
+ ///
+ Invalid0x1F = 0x1F,
+
+ ///
+ /// Invalid case
+ ///
+ Invalid0x20 = 0x20,
+
+ ///
+ /// Invalid case
+ ///
+ Invalid0x21 = 0x21,
+
+ ///
+ /// Invalid case
+ ///
+ Invalid0x22 = 0x22,
+
+ ///
+ /// ElseIf Statement
+ ///
+ ElseIfStatement = 0x23,
+
+ ///
+ /// Enable repair?
+ ///
+ ///
+ /// The flag used by this and seems
+ /// to only be referenced in contexts where there are registry
+ /// keys read and written, specifically about repair.
+ ///
+ Unknown0x24 = 0x24,
+
+ ///
+ /// Disable repair?
+ ///
+ ///
+ /// The flag used by this and seems
+ /// to only be referenced in contexts where there are registry
+ /// keys read and written, specifically about repair.
+ ///
+ Unknown0x25 = 0x25,
+
+ // Check in WISE0001.DLL suggests that there could be up
+ // to opcode 0x3F. If the opcode is greater than 0x3F,
+ // then the installation aborts with 0xfffffffe.
+ //
+ // Opcode 0x3F returns a value of 0xffffffff.
+ }
+
+ ///
+ /// Wise installer overlay header flags
+ ///
+ ///
+ public enum OverlayHeaderFlags : uint
+ {
+ ///
+ /// This value is checked for explicitly. If this value
+ /// and are both not
+ /// set, then it shows the commandline when silent mode
+ /// is disabled.
+ ///
+ /// If just this value is set, the bottom of the window
+ /// is adjusted by (MainWindowBottom * 3) / 4 and then
+ /// displays the window with the current size.
+ ///
+ WISE_FLAG_UNKNOWN_0 = 0x00000001,
+
+ ///
+ /// This value is checked for explicitly. If this value
+ /// and not is set
+ /// and is set and
+ /// the silent mode flag is not enabled, it runs a
+ /// function. Maybe debug window?
+ ///
+ /// If this value and
+ /// are both not set, then it displays the window
+ /// maximized.
+ ///
+ /// If just this value is set and silent mode is enabled,
+ /// the position of the window is set to full screen
+ /// but the window is not shown.
+ ///
+ WISE_FLAG_UNKNOWN_1 = 0x00000002,
+
+ WISE_FLAG_UNKNOWN_2 = 0x00000004,
+
+ ///
+ /// Enable fullscreen installer
+ ///
+ ///
+ /// If this flag is enabled, it sets the following window flags:
+ /// WS_BORDER | WS_DLGFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_TILED
+ ///
+ /// If this flag is disabled, it sets the following window flags:
+ /// WS_POPUP | WS_SIZEBOX
+ ///
+ WISE_FLAG_FULLSCREEN = 0x00000008,
+
+ ///
+ /// Seen in hluplink.exe, Swat 3 and glsetup.exe
+ ///
+ WISE_FLAG_UNKNOWN_4 = 0x00000010,
+
+ WISE_FLAG_UNKNOWN_5 = 0x00000020,
+
+ WISE_FLAG_UNKNOWN_6 = 0x00000040,
+
+ ///
+ /// This value is checked for explicitly. If this value is
+ /// set and the commandline doesn't specify silent mode
+ /// and the first byte of the flags (f & 3 != 2), it runs
+ /// a function. Maybe debug window?
+ ///
+ WISE_FLAG_UNKNOWN_7 = 0x00000080,
+
+ ///
+ /// Indicates that PKZIP containers are used
+ ///
+ WISE_FLAG_PK_ZIP = 0x00000100,
+
+ WISE_FLAG_UNKNOWN_9 = 0x00000200,
+
+ WISE_FLAG_UNKNOWN_10 = 0x00000400,
+
+ ///
+ /// May be related to requireAdministrator
+ ///
+ WISE_FLAG_UNKNOWN_11 = 0x00000800,
+
+ ///
+ /// This value is checked for explicitly
+ ///
+ WISE_FLAG_UNKNOWN_12 = 0x00001000,
+
+ WISE_FLAG_UNKNOWN_13 = 0x00002000,
+
+ WISE_FLAG_UNKNOWN_14 = 0x00004000,
+
+ WISE_FLAG_UNKNOWN_15 = 0x00008000,
+
+ ///
+ /// May be related to requireAdministrator
+ ///
+ WISE_FLAG_UNKNOWN_16 = 0x00010000,
+
+ WISE_FLAG_UNKNOWN_17 = 0x00020000,
+
+ WISE_FLAG_UNKNOWN_18 = 0x00040000,
+
+ ///
+ /// Only seen set in Wild Wheels
+ ///
+ WISE_FLAG_UNKNOWN_19 = 0x00080000,
+
+ WISE_FLAG_UNKNOWN_20 = 0x00100000,
+
+ WISE_FLAG_UNKNOWN_21 = 0x00200000,
+
+ ///
+ /// Only seen in glsetup.exe
+ ///
+ WISE_FLAG_UNKNOWN_22 = 0x00400000,
+
+ WISE_FLAG_UNKNOWN_23 = 0x00800000,
+
+ WISE_FLAG_UNKNOWN_24 = 0x01000000,
+
+ WISE_FLAG_UNKNOWN_25 = 0x02000000,
+
+ WISE_FLAG_UNKNOWN_26 = 0x04000000,
+
+ WISE_FLAG_UNKNOWN_27 = 0x08000000,
+
+ WISE_FLAG_UNKNOWN_28 = 0x10000000,
+
+ WISE_FLAG_UNKNOWN_29 = 0x20000000,
+
+ ///
+ /// If enabled, sets the same flag as /M4 commandline
+ ///
+ ///
+ /// The /M4 commandline parameter, this flag, and then
+ /// some value (DAT_00404270) being 0 all lead to the
+ /// same outcome. The set of installers that include
+ /// this flag need to be further analyzed to see what
+ /// possible files are omitted if this flag is set.
+ ///
+ /// Preliminary inspection of output files does not
+ /// show any notable missing files. It is very possible
+ /// that this represents a file that is not currently
+ /// extracted.
+ ///
+ WISE_FLAG_FORCE_M4 = 0x40000000,
+
+ WISE_FLAG_UNKNOWN_31 = 0x80000000,
+
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/MachineState.cs b/SabreTools.Serialization/Models/WiseInstaller/MachineState.cs
new file mode 100644
index 00000000..296330d0
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/MachineState.cs
@@ -0,0 +1,22 @@
+using SabreTools.Serialization.Models.WiseInstaller.Actions;
+
+namespace SabreTools.Serialization.Models.WiseInstaller
+{
+ ///
+ /// Represents a single step in the state machine defined
+ /// in a Wise script file.
+ ///
+ public class MachineState
+ {
+ ///
+ /// Opcode
+ ///
+ public OperationCode Op { get; set; }
+
+ ///
+ /// Data specific to the operation, may be null
+ ///
+
+ public MachineStateData? Data { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/OverlayHeader.cs b/SabreTools.Serialization/Models/WiseInstaller/OverlayHeader.cs
new file mode 100644
index 00000000..38376fc8
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/OverlayHeader.cs
@@ -0,0 +1,182 @@
+namespace SabreTools.Serialization.Models.WiseInstaller
+{
+ ///
+ /// Wise installer overlay data header
+ ///
+ ///
+ public class OverlayHeader
+ {
+ ///
+ /// DLL name length, if it exists
+ ///
+ public byte DllNameLen { get; set; } // 0x00
+
+ ///
+ /// DLL name, missing if is 0
+ ///
+ public string? DllName { get; set; } //
+
+ ///
+ /// DLL size, missing if is 0
+ ///
+ public uint? DllSize { get; set; } //
+
+ ///
+ /// Packing flags
+ ///
+ public OverlayHeaderFlags Flags { get; set; } // 0x01 - 0x04
+
+ ///
+ /// Graphics data
+ ///
+ ///
+ /// 12 bytes
+ ///
+ /// When the data is processed, it does the following:
+ ///
+ /// ushort[] colors = new ushort[3];
+ /// int colorsPtr = 0;
+ ///
+ /// for (int i = 0; i < 3; i++)
+ /// {
+ /// uint color = (GraphicsData[i + 3] * ) / 0x5F + GraphicsData[i];
+ /// colors[colorsPtr] = color;
+ /// if (color < 0)
+ /// colors[colorsPtr] = 0;
+ /// if (colors[colorsPtr] > 0xFF)
+ /// colors[colorsPtr] = 0xFF
+ ///
+ /// colorsPtr++;
+ /// }
+ ///
+ public byte[]? GraphicsData { get; set; } // 0x05 - 0x10
+
+ ///
+ /// Points to the Exit event in the script, if it exists
+ ///
+ public uint WiseScriptExitEventOffset { get; set; } // 0x11 - 0x14
+
+ ///
+ /// Points to the Cancel event in the script, if it exists
+ ///
+ public uint WiseScriptCancelEventOffset { get; set; } // 0x15 - 0x18
+
+ ///
+ /// Inflated size of the Wise installer script
+ ///
+ public uint WiseScriptInflatedSize { get; set; } // 0x19 - 0x1C
+
+ ///
+ /// Deflated size of the Wise installer script
+ ///
+ public uint WiseScriptDeflatedSize { get; set; } // 0x1D - 0x20
+
+ ///
+ /// Deflated size of WISE0001.DLL
+ ///
+ public uint WiseDllDeflatedSize { get; set; } // 0x21 - 0x24
+
+ ///
+ /// Deflated size of CTL3D32.DLL
+ ///
+ public uint Ctl3d32DeflatedSize { get; set; } // 0x25 - 0x28
+
+ ///
+ /// Deflated size of unknown data
+ ///
+ public uint SomeData4DeflatedSize { get; set; } // 0x29 - 0x2C
+
+ ///
+ /// Deflated size of Ocxreg32.EXE,
+ ///
+ public uint RegToolDeflatedSize { get; set; } // 0x2D - 0x30
+
+ ///
+ /// Deflated size of PROGRESS.DLL
+ ///
+ public uint ProgressDllDeflatedSize { get; set; } // 0x31 - 0x34
+
+ ///
+ /// Deflated size of unknown data
+ ///
+ public uint SomeData7DeflatedSize { get; set; } // 0x35 - 0x38
+
+ ///
+ /// Deflated size of unknown data
+ ///
+ public uint SomeData8DeflatedSize { get; set; } // 0x39 - 0x3C
+
+ ///
+ /// Deflated size of unknown data
+ ///
+ /// Samples were MS-DOS executables
+ public uint SomeData9DeflatedSize { get; set; } // 0x3D - 0x40
+
+ ///
+ /// Deflated size of unknown data
+ ///
+ public uint SomeData10DeflatedSize { get; set; } // 0x41 - 0x44
+
+ ///
+ /// Deflated size of FILE000{n}.DAT
+ ///
+ public uint FinalFileDeflatedSize { get; set; } // 0x45 - 0x48
+
+ ///
+ /// Inflated size of FILE000{n}.DAT
+ ///
+ public uint FinalFileInflatedSize { get; set; } // 0x49 - 0x4C
+
+ ///
+ /// On multi-disc installers this is set to 0x00000000, so it may
+ /// represent EOF instead of filesize? At least for now. Only compared
+ /// the two multi-disc installers listed in the README.md, need more
+ /// multi-disc installers to properly compare. On single file
+ /// installers this is this installer it's filesize.
+ ///
+ public uint EOF { get; set; } // 0x4D - 0x50
+
+ ///
+ /// Deflated size of the DIB
+ ///
+ /// First file
+ public uint DibDeflatedSize { get; set; } // 0x51 - 0x54
+
+ ///
+ /// Inflated size of the DIB
+ ///
+ /// First file
+ public uint DibInflatedSize { get; set; } // 0x55 - 0x58
+
+ ///
+ /// Deflated size of the install script
+ ///
+ /// Only present in later versions
+ public uint? InstallScriptDeflatedSize { get; set; } // 0x59 - 0x5C
+
+ ///
+ /// Character set for the font
+ ///
+ ///
+ /// Only present in later versions. In the overlay reading code
+ /// present in those later versions, it is lumped in with the
+ /// rest of the sizes above.
+ ///
+ public CharacterSet? CharacterSet { get; set; } // 0x5D - 0x60
+
+ ///
+ /// Endianness of the file(?)
+ ///
+ public Endianness Endianness { get; set; } // 0x61 - 0x62
+
+ ///
+ /// Init text length
+ ///
+ public byte InitTextLen { get; set; } // 0x63
+
+ ///
+ /// Init text whose length is given by
+ ///
+ public string? InitText { get; set; } // 0x64 -
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/ScriptFile.cs b/SabreTools.Serialization/Models/WiseInstaller/ScriptFile.cs
new file mode 100644
index 00000000..31a96dac
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/ScriptFile.cs
@@ -0,0 +1,19 @@
+namespace SabreTools.Serialization.Models.WiseInstaller
+{
+ ///
+ /// Wise script file
+ ///
+ ///
+ public class ScriptFile
+ {
+ ///
+ /// Script header
+ ///
+ public ScriptHeader? Header { get; set; }
+
+ ///
+ /// States representing the state machine in order
+ ///
+ public MachineState[]? States { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Serialization/Models/WiseInstaller/ScriptHeader.cs b/SabreTools.Serialization/Models/WiseInstaller/ScriptHeader.cs
new file mode 100644
index 00000000..5884c3a1
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/ScriptHeader.cs
@@ -0,0 +1,171 @@
+namespace SabreTools.Serialization.Models.WiseInstaller
+{
+ ///
+ /// Header for the Wise script
+ ///
+ ///
+ public class ScriptHeader
+ {
+ ///
+ /// Flags, unknown mapping
+ ///
+ ///
+ /// The high byte (0x01) being any value but 0x00 indicates
+ /// that a 32-bit library will be used.
+ ///
+ public ushort Flags { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Read in a loop with , possibly
+ /// an offset? It's read into an array.
+ ///
+ /// Both values are then used to build variable names if they're
+ /// non-zero. The variable names use "SYS" as the template.
+ /// The values are then seemingly read over?
+ ///
+ public ushort UnknownU16_1 { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Read in a loop with , possibly
+ /// an offset? It's read into an array.
+ ///
+ /// Both values are then used to build variable names if they're
+ /// non-zero. The variable names use "SYS" as the template.
+ /// The values are then seemingly read over?
+ ///
+ public ushort UnknownU16_2 { get; set; }
+
+ ///
+ /// Total deflated size of OP 0x00 files?
+ ///
+ ///
+ /// This seems to match the offset we can do filesize - SomeOffset1
+ /// to get to the script file deflate offset, but not on all
+ /// installers..
+ ///
+ /// Values from WISE0001.DLL
+ /// - < 0 - Display abort installation message and return 1?
+ /// - 0x400 - Breaks a loop?
+ /// - 0x800 - Returns 0?
+ ///
+ public uint SomeOffset1 { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// Used as a size to allocate memory in WISE0001.DLL
+ ///
+ public uint SomeOffset2 { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// 4 bytes
+ ///
+ /// In WISE0001.DLL, the first byte of this array is checked
+ /// to be 0x00. If it's not 0x00, then it skips a string, ending
+ /// at the next null terminator. The string at that offset is
+ /// then comapred to ...
+ ///
+ public byte[]? UnknownBytes_2 { get; set; }
+
+ ///
+ /// Creation of this WiseScript.bin since UNIX epoch
+ ///
+ public uint DateTime { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ ///
+ /// This is a variable-length area of data that hasn't been
+ /// properly mapped yet. There are currently 4 documented
+ /// lengths of data:
+ /// - 9 - Short header data, missing some fields
+ /// - 17 - Middle header data, missing some fields
+ /// - 22 - Normal header data, all fields present
+ /// - 31 - Long header data, all fields present
+ ///
+ public byte[]? VariableLengthData { get; set; }
+
+ ///
+ /// FTP URL for online downloading
+ ///
+ public string? FTPURL { get; set; }
+
+ ///
+ /// Log pathname
+ ///
+ public string? LogPathname { get; set; }
+
+ ///
+ /// Message font
+ ///
+ public string? MessageFont { get; set; }
+
+ ///
+ /// Font size for message fonts
+ ///
+ public uint FontSize { get; set; }
+
+ ///
+ /// Unknown
+ ///
+ /// 2 bytes
+ public byte[]? Unknown_2 { get; set; }
+
+ ///
+ /// if languageCount > 1: the total string count is larger, there
+ /// will be the language selection strings at top and the normal
+ /// strings (56) minus 1 (55) will be times the languageCount, plus 2.
+ ///
+ ///
+ /// Language selection strings example when there are 6 languages:
+ ///
+ /// "Select Language" ;; selection string 1
+ /// "Please Select a Language" ;; selection string 2
+ /// "U.S. English" ;; language name
+ /// "ENU" ;; language short
+ /// "Fran.ias"
+ /// "FRA"
+ /// "Deutsch"
+ /// "DEU"
+ /// "Portugu.s"
+ /// "PTG"
+ /// "Espa.ol"
+ /// "ESN"
+ /// "Italiano"
+ /// "ITA"
+ ///
+ /// The total string count seen with 6 languages is 434 and the
+ /// total string count seen with 1 language has been always 56, for a
+ /// languageCount of 5 the string count should be 287. As seen for now.
+ ///
+ /// if (languageCount > 1) {
+ /// stringCount = (55 * languageCount) + (languageCount * 2) + 2;
+ /// }
+ /// else {
+ /// stringCount = 56 = (55 * languageCount) + languageCount
+ /// }
+ ///
+ /// The container size (uint8_t) is a guess, because the neightbour
+ /// bytes are almost all 0x00 (as seen for now). So did you find a
+ /// installer with more then 255 languages? then FIXME :')
+ ///
+ public byte LanguageCount { get; set; }
+
+ ///
+ /// All strings in the aheader
+ ///
+ /// See the remarks in
+ public string[]? HeaderStrings { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Models/WiseInstaller/SectionHeader.cs b/SabreTools.Serialization/Models/WiseInstaller/SectionHeader.cs
new file mode 100644
index 00000000..75627887
--- /dev/null
+++ b/SabreTools.Serialization/Models/WiseInstaller/SectionHeader.cs
@@ -0,0 +1,180 @@
+namespace SabreTools.Serialization.Models.WiseInstaller
+{
+ ///
+ /// .WISE sections seem to be present in what virustotal calls "Self Extracting Wise Installer"s. These sections
+ /// contain a header with anywhere from seven to nineteen 4-byte little-endian values, followed by what's possibly
+ /// a version number, then string data, and then the file entries.
+ ///
+ /// At some point in the header, there will be the characters "WIS" prepended by what seems to be a version number.
+ /// This possible version number will be referred to from here on as just "version number", as it would be overly
+ /// verbose to continue using "what is possibly a version number".
+ ///
+ /// The WIS characters do not always align with a specific offset if the header is broken up by 4-byte blocks, and
+ /// the version number seems to maintain this offset. It is currently unknown if the version number is 4 bytes long
+ /// or five bytes long, it seems to vary.
+ ///
+ /// Offsets of the "W" in the "WIS" string currently observed are 32, 33, 41, 77, 78, and 82. This seems to point to
+ /// 4-6 known header lengths, depending on the deal with the version number/WIS offset.
+ ///
+ /// Before the version number, there are anywhere from seven to nineteen 4-byte little-endian values depending on
+ /// the length of the pre-string part of the header. These values will be described indexed from zero (0-18). The
+ /// only one of these values that's ever guaranteed not to be all 0x00 is value 6. This is the size of the "main"
+ /// file in the file entry part of the section, which is the size of the file, plus 4 bytes for its following crc32.
+ /// This file seems to always be an msi installer that's extracted to the TEMP directory and ran to perform the
+ /// actual install. This file has been observed to be nameless (a randomly generated alphanumeric string
+ /// followed by .msi, with some examples including 2fbcb.msi and ddec.msi, serve as the filename. Name is random
+ /// even when re-running the same installer) thus far. In many installers, all other pre-version values are 0x00,
+ /// so this is the only guaranteed value.
+ ///
+ /// All values not explicitly mentioned to never have been observed have been observed in at least one installer
+ /// thus far.
+ ///
+ public class SectionHeader
+ {
+ ///
+ /// Unknown Data Size.
+ ///
+ public uint UnknownDataSize { get; set; }
+
+ ///
+ /// Value 1, (possibly?) the size of the second file entry. This has thus far always been observed
+ /// with non-0x00 values for values 3 and 4, and usually, but not always, value 5 as well. Thus far always been
+ /// observed to be an executable, filename unknown. Likely assists with extraction. A few samples with a
+ /// non-0x00 value 1 seem to have value 5 as 0x00, meaning that it being observed as the second file may just be
+ /// coincidence, and values 1 and 5 may refer to files with a specific purpose/meaning.
+ ///
+ public uint SecondExecutableFileEntryLength { get; set; }
+
+ ///
+ /// Unknown value 2. Currently unobserved in any samples.
+ ///
+ public uint UnknownValue2 { get; set; }
+
+ ///
+ /// Unknown value 3. This has thus far always been observed with a non-0x00 value for value 4.
+ ///
+ public uint UnknownValue3 { get; set; }
+
+ ///
+ /// Unknown value 4. This has thus far always been observed with a non-0x00 value for value 3.
+ ///
+ public uint UnknownValue4 { get; set; }
+
+ ///
+ /// Value 5, the size of the first entry. This has thus far always been observed with
+ /// non-0x00 values for values 3 and 4, and guarantees the presence of one file before the main msi installer
+ /// file. Thus far always been observed to be an executable, filename unknown. Likely assists with extraction.
+ ///
+ public uint FirstExecutableFileEntryLength { get; set; }
+
+ ///
+ /// Value 6, the size of the "main" msi installer file entry. Always at the end of the file entries.
+ ///
+ public uint MsiFileEntryLength { get; set; }
+
+ ///
+ /// Unknown value 7. Currently unobserved in any samples.
+ ///
+ /// TODO: From this entry onward the values are not guaranteed
+ public uint UnknownValue7 { get; set; }
+
+ ///
+ /// Unknown value 8. Currently unobserved in any samples.
+ ///
+ public uint UnknownValue8 { get; set; }
+
+ ///
+ /// Value 9, the size of the third entry.
+ ///
+ public uint ThirdExecutableFileEntryLength { get; set; }
+
+ ///
+ /// Unknown value 10.
+ ///
+ public uint UnknownValue10 { get; set; }
+
+ ///
+ /// Unknown value 11. Currently unobserved in any samples.
+ ///
+ public uint UnknownValue11 { get; set; }
+
+ ///
+ /// Unknown value 12. Currently unobserved in any samples.
+ ///
+ public uint UnknownValue12 { get; set; }
+
+ ///
+ /// Unknown value 13. Currently unobserved in any samples.
+ ///
+ public uint UnknownValue13 { get; set; }
+
+ ///
+ /// Unknown value 14. Currently unobserved in any samples.
+ ///
+ public uint UnknownValue14 { get; set; }
+
+ ///
+ /// Unknown value 15. Currently unobserved in any samples.
+ ///
+ public uint UnknownValue15 { get; set; }
+
+ ///
+ /// Unknown value 16.
+ ///
+ public uint UnknownValue16 { get; set; }
+
+ ///
+ /// Unknown value 17.
+ ///
+ public uint UnknownValue17 { get; set; }
+
+ ///
+ /// Unknown value 18. Currently unobserved in any samples.
+ ///
+ public uint UnknownValue18 { get; set; }
+
+ ///
+ /// Byte array representing version. Byte array used due to unknown size and type for version.
+ ///
+ public byte[]? Version { get; set; }
+
+ ///
+ /// String representing the WIS[etc].TMP string
+ ///
+ public string? TmpString { get; set; }
+
+ ///
+ /// String representing the GUID string.
+ ///
+ public string? GuidString { get; set; }
+
+ ///
+ /// String representing a version number. This isn't the version of the .WISE installer itself, as it is
+ /// entirely inconsistent even within the same week. Likely refers to a version for what's being installed
+ /// rather than the installer itself
+ ///
+ public string? NonWiseVersion { get; set; }
+
+ ///
+ /// Unknown. May also refer to a non-value for pre-78-offset executables and only a value for 78-offset-onwards
+ /// ones.
+ ///
+ public byte[]? PreFontValue {get; set;}
+
+ ///
+ /// Font size
+ ///
+ public int FontSize { get; set; }
+
+ ///
+ /// Byte array representing string lengths and info. Individual strings not predefined since number of strings
+ /// will likely vary between many installers.
+ ///
+ public byte[]? PreStringValues { get; set; }
+
+ ///
+ /// Strings for the section. Size and any breakup of strings currently unknown.
+ ///
+ public byte[][]? Strings { get; set; }
+ }
+}
diff --git a/SabreTools.Serialization/Printers/LinearExecutable.cs b/SabreTools.Serialization/Printers/LinearExecutable.cs
index e2957127..8d44d221 100644
--- a/SabreTools.Serialization/Printers/LinearExecutable.cs
+++ b/SabreTools.Serialization/Printers/LinearExecutable.cs
@@ -1,6 +1,6 @@
using System.Text;
-using SabreTools.Models.LinearExecutable;
using SabreTools.Serialization.Interfaces;
+using SabreTools.Serialization.Models.LinearExecutable;
namespace SabreTools.Serialization.Printers
{
@@ -41,7 +41,7 @@ namespace SabreTools.Serialization.Printers
Print(builder, executable.DebugInformation);
}
- private static void Print(StringBuilder builder, SabreTools.Models.MSDOS.ExecutableHeader? header)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.MSDOS.ExecutableHeader? header)
{
builder.AppendLine(" MS-DOS Stub Header Information:");
builder.AppendLine(" -------------------------");
diff --git a/SabreTools.Serialization/Printers/MSDOS.cs b/SabreTools.Serialization/Printers/MSDOS.cs
index 2f393fbf..5acb8d98 100644
--- a/SabreTools.Serialization/Printers/MSDOS.cs
+++ b/SabreTools.Serialization/Printers/MSDOS.cs
@@ -1,6 +1,6 @@
using System.Text;
-using SabreTools.Models.MSDOS;
using SabreTools.Serialization.Interfaces;
+using SabreTools.Serialization.Models.MSDOS;
namespace SabreTools.Serialization.Printers
{
diff --git a/SabreTools.Serialization/Printers/NewExecutable.cs b/SabreTools.Serialization/Printers/NewExecutable.cs
index f534636d..b702f9e8 100644
--- a/SabreTools.Serialization/Printers/NewExecutable.cs
+++ b/SabreTools.Serialization/Printers/NewExecutable.cs
@@ -1,8 +1,8 @@
using System.Collections.Generic;
using System.Text;
-using SabreTools.Models.NewExecutable;
using SabreTools.Serialization.Extensions;
using SabreTools.Serialization.Interfaces;
+using SabreTools.Serialization.Models.NewExecutable;
namespace SabreTools.Serialization.Printers
{
@@ -34,7 +34,7 @@ namespace SabreTools.Serialization.Printers
Print(builder, executable.NonResidentNameTable);
}
- private static void Print(StringBuilder builder, SabreTools.Models.MSDOS.ExecutableHeader? header)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.MSDOS.ExecutableHeader? header)
{
builder.AppendLine(" MS-DOS Stub Header Information:");
builder.AppendLine(" -------------------------");
@@ -243,7 +243,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, ModuleReferenceTableEntry[]? entries, SabreTools.Models.MSDOS.ExecutableHeader? stub, ExecutableHeader? header)
+ private static void Print(StringBuilder builder, ModuleReferenceTableEntry[]? entries, SabreTools.Serialization.Models.MSDOS.ExecutableHeader? stub, ExecutableHeader? header)
{
builder.AppendLine(" Module-Reference Table Information:");
builder.AppendLine(" -------------------------");
diff --git a/SabreTools.Serialization/Printers/PortableExecutable.cs b/SabreTools.Serialization/Printers/PortableExecutable.cs
index 6364b8b0..ba6f1728 100644
--- a/SabreTools.Serialization/Printers/PortableExecutable.cs
+++ b/SabreTools.Serialization/Printers/PortableExecutable.cs
@@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.Text;
using System.Xml;
using SabreTools.IO.Extensions;
-using SabreTools.Models.COFF;
-using SabreTools.Models.COFF.SymbolTableEntries;
-using SabreTools.Models.PortableExecutable;
-using SabreTools.Models.PortableExecutable.Resource.Entries;
using SabreTools.Serialization.Extensions;
using SabreTools.Serialization.Interfaces;
+using SabreTools.Serialization.Models.COFF;
+using SabreTools.Serialization.Models.COFF.SymbolTableEntries;
+using SabreTools.Serialization.Models.PortableExecutable;
+using SabreTools.Serialization.Models.PortableExecutable.Resource.Entries;
namespace SabreTools.Serialization.Printers
{
@@ -60,7 +60,7 @@ namespace SabreTools.Serialization.Printers
Print(builder, executable.DebugTable);
}
- private static void Print(StringBuilder builder, SabreTools.Models.MSDOS.ExecutableHeader? header)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.MSDOS.ExecutableHeader? header)
{
builder.AppendLine(" MS-DOS Stub Header Information:");
builder.AppendLine(" -------------------------");
@@ -119,7 +119,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.OptionalHeader? header, SectionHeader[]? table)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.OptionalHeader? header, SectionHeader[]? table)
{
builder.AppendLine(" Optional Header Information:");
builder.AppendLine(" -------------------------");
@@ -417,7 +417,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine(entry.Reserved2, " Reserved");
}
- private static void Print(StringBuilder builder, SabreTools.Models.COFF.StringTable? stringTable)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.COFF.StringTable? stringTable)
{
builder.AppendLine(" String Table Information:");
builder.AppendLine(" -------------------------");
@@ -439,7 +439,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.AttributeCertificate.Entry[]? entries)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate.Entry[]? entries)
{
builder.AppendLine(" Attribute Certificate Table Information:");
builder.AppendLine(" -------------------------");
@@ -506,7 +506,7 @@ namespace SabreTools.Serialization.Printers
}
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.DelayLoad.DirectoryTable? table, SectionHeader[]? sections)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.DelayLoad.DirectoryTable? table, SectionHeader[]? sections)
{
builder.AppendLine(" Delay-Load Directory Table Information:");
builder.AppendLine(" -------------------------");
@@ -533,7 +533,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.BaseRelocation.Block[]? entries, SectionHeader[]? sections)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.Block[]? entries, SectionHeader[]? sections)
{
builder.AppendLine(" Base Relocation Table Information:");
builder.AppendLine(" -------------------------");
@@ -576,7 +576,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.DebugData.Table? table)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.DebugData.Table? table)
{
builder.AppendLine(" Debug Table Information:");
builder.AppendLine(" -------------------------");
@@ -605,7 +605,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Export.DirectoryTable? table, SectionHeader[]? sections)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.Export.DirectoryTable? table, SectionHeader[]? sections)
{
builder.AppendLine(value: " Export Directory Table Information:");
builder.AppendLine(" -------------------------");
@@ -635,7 +635,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Export.AddressTableEntry[]? table, SectionHeader[]? sections)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry[]? table, SectionHeader[]? sections)
{
builder.AppendLine(" Export Address Table Information:");
builder.AppendLine(" -------------------------");
@@ -658,7 +658,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Export.NamePointerTable? table)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.Export.NamePointerTable? table)
{
builder.AppendLine(" Export Name Pointer Table Information:");
builder.AppendLine(" -------------------------");
@@ -680,7 +680,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Export.OrdinalTable? table)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.Export.OrdinalTable? table)
{
builder.AppendLine(" Export Ordinal Table Information:");
builder.AppendLine(" -------------------------");
@@ -702,7 +702,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Export.NameTable? table)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.Export.NameTable? table)
{
builder.AppendLine(" Export Name Table Information:");
builder.AppendLine(" -------------------------");
@@ -724,7 +724,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry[]? table, SectionHeader[]? sections)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry[]? table, SectionHeader[]? sections)
{
builder.AppendLine(" Import Directory Table Information:");
builder.AppendLine(" -------------------------");
@@ -754,7 +754,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, Dictionary? tables, SectionHeader[]? sections)
+ private static void Print(StringBuilder builder, Dictionary? tables, SectionHeader[]? sections)
{
builder.AppendLine(" Import Lookup Tables Information:");
builder.AppendLine(" -------------------------");
@@ -800,7 +800,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, Dictionary? tables, SectionHeader[]? sections)
+ private static void Print(StringBuilder builder, Dictionary? tables, SectionHeader[]? sections)
{
builder.AppendLine(" Import Address Tables Information:");
builder.AppendLine(" -------------------------");
@@ -846,7 +846,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Import.HintNameTableEntry[]? table)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.Import.HintNameTableEntry[]? table)
{
builder.AppendLine(" Import Hint/Name Table Information:");
builder.AppendLine(" -------------------------");
@@ -869,7 +869,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Resource.DirectoryTable? table, SectionHeader[]? sections)
+ private static void Print(StringBuilder builder, SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryTable? table, SectionHeader[]? sections)
{
builder.AppendLine(" Resource Directory Table Information:");
builder.AppendLine(" -------------------------");
@@ -884,7 +884,7 @@ namespace SabreTools.Serialization.Printers
builder.AppendLine();
}
- private static void Print(StringBuilder builder, SabreTools.Models.PortableExecutable.Resource.DirectoryTable table, int level, List