diff --git a/SabreTools.Serialization/Wrappers/LinearExecutable.cs b/SabreTools.Serialization/Wrappers/LinearExecutable.cs index 5a7affba..c6931da3 100644 --- a/SabreTools.Serialization/Wrappers/LinearExecutable.cs +++ b/SabreTools.Serialization/Wrappers/LinearExecutable.cs @@ -1,9 +1,11 @@ using System; using System.IO; +using SabreTools.IO.Extensions; +using SabreTools.Models.LinearExecutable; namespace SabreTools.Serialization.Wrappers { - public class LinearExecutable : WrapperBase + public class LinearExecutable : WrapperBase { #region Descriptive Properties @@ -14,7 +16,16 @@ namespace SabreTools.Serialization.Wrappers #region Extension Properties - /// + /// + public InformationBlock? InformationBlock => Model.InformationBlock; + + /// + public ObjectPageMapEntry[]? ObjectPageMap => Model.ObjectPageMap; + + /// + public ResourceTableEntry[]? ResourceTable => Model.ResourceTable; + + /// public Models.MSDOS.Executable? Stub => Model.Stub; #endregion @@ -22,14 +33,14 @@ namespace SabreTools.Serialization.Wrappers #region Constructors /// - public LinearExecutable(Models.LinearExecutable.Executable? model, byte[]? data, int offset) + public LinearExecutable(Executable? model, byte[]? data, int offset) : base(model, data, offset) { // All logic is handled by the base class } /// - public LinearExecutable(Models.LinearExecutable.Executable? model, Stream? data) + public LinearExecutable(Executable? model, Stream? data) : base(model, data) { // All logic is handled by the base class @@ -83,6 +94,204 @@ namespace SabreTools.Serialization.Wrappers #endregion + #region Object Page Map + + /// + /// Get a single object page map entry + /// + /// Object page map index to retrieve + /// Entry on success, null otherwise + public ObjectPageMapEntry? GetObjectPageMapEntry(int index) + { + // If the object page map table is invalid + if (ObjectPageMap == null || ObjectPageMap.Length == 0) + return null; + + // If the index is invalid + if (index < 0 || index >= ObjectPageMap.Length) + return null; + + // Return the entry + return ObjectPageMap[index]; + } + + /// + /// Get the data for a single object page map entry + /// + /// Object page map index to retrieve + /// Entry data on success, null otherwise + public byte[]? GetObjectPageMapEntryData(int index) + { + // Get the entry offset + int offset = GetObjectPageMapEntryOffset(index); + if (offset < 0) + return null; + + // Get the entry length + int length = GetObjectPageMapEntryLength(index); + if (length < 0) + return null; + else if (length == 0) + return []; + + // Read the entry data and return + return ReadFromDataSource(offset, length); + } + + /// + /// Get the data length for a object page map entry + /// + /// Object page map index to retrieve + /// Entry length on success, -1 otherwise + public int GetObjectPageMapEntryLength(int index) + { + // Get the matching entry + var entry = GetObjectPageMapEntry(index); + if (entry == null) + return -1; + + // Return the reported length + return entry.DataSize; + } + + /// + /// Get the data offset for a single object page map entry + /// + /// Object page map index to retrieve + /// Entry offset on success, -1 otherwise + public int GetObjectPageMapEntryOffset(int index) + { + // If the information block is invalid + if (InformationBlock == null) + return -1; + + // Get the end of the file, if possible + int endOfFile = GetEndOfFile(); + if (endOfFile == -1) + return -1; + + // Get the matching entry + var entry = GetObjectPageMapEntry(index); + if (entry == null) + return -1; + + // Verify the entry offset + int offset = (int)(entry.PageDataOffset << (int)InformationBlock.BytesOnLastPage); + if (offset < 0 || offset + entry.DataSize >= endOfFile) + return -1; + + // Return the verified offset + return offset; + } + + #endregion + + #region Resource Table + + /// + /// Get a single resource table entry + /// + /// Resource table index to retrieve + /// Entry on success, null otherwise + public ResourceTableEntry? GetResourceTableEntry(int index) + { + // If the resource table table is invalid + if (ResourceTable == null || ResourceTable.Length == 0) + return null; + + // If the index is invalid + if (index < 0 || index >= ResourceTable.Length) + return null; + + // Return the entry + return ResourceTable[index]; + } + + /// + /// Get the data for a single resource table entry + /// + /// Resource table index to retrieve + /// Entry data on success, null otherwise + public byte[]? GetResourceTableEntryData(int index) + { + // Get the entry + var entry = GetResourceTableEntry(index); + if (entry == null) + return null; + + // Get the entry offset + int offset = GetResourceTableEntryOffset(index); + if (offset < 0) + return null; + + // Get the entry length + int length = GetResourceTableEntryLength(index); + if (length < 0) + return null; + else if (length == 0) + return []; + + // Get the matching object data + var objectData = GetObjectPageMapEntryData(entry.ObjectNumber); + if (objectData == null) + return null; + + // Read the entry data and return + return objectData.ReadBytes(ref offset, length); + } + + /// + /// Get the data length for a resource table entry + /// + /// Resource table index to retrieve + /// Entry length on success, -1 otherwise + public int GetResourceTableEntryLength(int index) + { + // Get the matching entry + var entry = GetResourceTableEntry(index); + if (entry == null) + return -1; + + // Return the reported length + return (int)entry.ResourceSize; + } + + /// + /// Get the data offset for a single resource table entry + /// + /// Resource table index to retrieve + /// Entry offset on success, -1 otherwise + public int GetResourceTableEntryOffset(int index) + { + // If the information block is invalid + if (InformationBlock == null) + return -1; + + // Get the end of the file, if possible + int endOfFile = GetEndOfFile(); + if (endOfFile == -1) + return -1; + + // Get the matching entry + var entry = GetResourceTableEntry(index); + if (entry == null) + return -1; + + // Get the matching object length + int objectLength = GetObjectPageMapEntryLength(entry.ObjectNumber); + if (objectLength == -1) + return -1; + + // Verify the entry offset + if (entry.Offset < 0 || entry.Offset + entry.ResourceSize >= objectLength) + return -1; + + // Return the verified offset + return (int)entry.Offset; + } + + #endregion + #region REMOVE -- DO NOT USE ///