diff --git a/SabreTools.Serialization/Extensions/PortableExecutable.cs b/SabreTools.Serialization/Extensions/PortableExecutable.cs index e2e6f34d..8f35f19e 100644 --- a/SabreTools.Serialization/Extensions/PortableExecutable.cs +++ b/SabreTools.Serialization/Extensions/PortableExecutable.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using SabreTools.Data.Models.COFF; using SabreTools.Data.Models.PortableExecutable; using SabreTools.IO.Extensions; @@ -148,38 +147,6 @@ namespace SabreTools.Data.Extensions // TODO: Implement other resource types from https://learn.microsoft.com/en-us/windows/win32/menurc/resource-file-formats #region Resources - /// - /// Read resource data as a string table resource - /// - /// Resource data entry to parse into a string table resource - /// A filled string table resource on success, null on error - /// TODO: Create concrete type for this and inherit from ResourceDataType - public static Dictionary? AsStringTable(this Models.PortableExecutable.Resource.DataEntry? entry) - { - // If we have an invalid entry, just skip - if (entry?.Data is null) - return null; - - // Initialize the iterators - int offset = 0, stringIndex = 0; - - // Create the output table - var stringTable = new Dictionary(); - - // Loop through and add - while (offset < entry.Data.Length) - { - string? stringValue = entry.Data.ReadPrefixedUnicodeString(ref offset); - if (stringValue is not null) - { - stringValue = stringValue.Replace("\n", "\\n").Replace("\r", newValue: "\\r"); - stringTable[stringIndex++] = stringValue; - } - } - - return stringTable; - } - /// /// Parse a byte array into a ResourceHeader /// diff --git a/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringTableResource.cs b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringTableResource.cs new file mode 100644 index 00000000..9765c6b8 --- /dev/null +++ b/SabreTools.Serialization/Models/PortableExecutable/Resource/Entries/StringTableResource.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace SabreTools.Data.Models.PortableExecutable.Resource.Entries +{ + /// + /// Represents a string table resource + /// + public sealed class StringTableResource : ResourceDataType + { + /// + /// Set of integer-keyed values + /// + public Dictionary Values { get; set; } = []; + } +} diff --git a/SabreTools.Serialization/Readers/PortableExecutable.cs b/SabreTools.Serialization/Readers/PortableExecutable.cs index bd60f3af..be24fcaa 100644 --- a/SabreTools.Serialization/Readers/PortableExecutable.cs +++ b/SabreTools.Serialization/Readers/PortableExecutable.cs @@ -122,7 +122,7 @@ namespace SabreTools.Serialization.Readers // Set the symbol and string tables pex.SymbolTable = ParseSymbolTable(data, fileHeader.NumberOfSymbols); - pex.StringTable = ParseStringTable(data); + pex.StringTable = ParseCOFFStringTable(data); } #endregion @@ -2739,7 +2739,7 @@ namespace SabreTools.Serialization.Readers var stringFileInfoChildren = new List(); while ((offset - currentOffset) < obj.Length) { - var stringTable = ParseStringTableResource(data, ref offset, currentOffset); + var stringTable = ParseFileInfoStringTable(data, ref offset, currentOffset); stringFileInfoChildren.Add(stringTable); } @@ -2781,11 +2781,11 @@ namespace SabreTools.Serialization.Readers } /// - /// Parse a Stream into a StringTable + /// Parse a Stream into a COFF StringTable /// /// Stream to parse /// Filled StringTable on success, null on error - public static StringTable ParseStringTable(Stream data) + public static StringTable ParseCOFFStringTable(Stream data) { var obj = new StringTable(); @@ -2810,12 +2810,12 @@ namespace SabreTools.Serialization.Readers } /// - /// Read byte data as a StringTable resource + /// Read byte data as a FileInfo StringTable /// /// Byte array to parse /// Offset into the byte array /// A filled StringTable resource on success, null on error - public static Data.Models.PortableExecutable.Resource.Entries.StringTable ParseStringTableResource(byte[] data, ref int offset, int initialOffset) + public static Data.Models.PortableExecutable.Resource.Entries.StringTable ParseFileInfoStringTable(byte[] data, ref int offset, int initialOffset) { var obj = new Data.Models.PortableExecutable.Resource.Entries.StringTable(); @@ -2841,6 +2841,34 @@ namespace SabreTools.Serialization.Readers return obj; } + /// + /// Read byte data as a StringTableResource + /// + /// Byte array to parse + /// Offset into the byte array + /// A filled StringTableResource resource on success, null on error + public static Data.Models.PortableExecutable.Resource.Entries.StringTableResource? ParseStringTableResource(byte[] data) + { + // Initialize the iterators + int offset = 0, stringIndex = 0; + + // Create the output table + var obj = new Data.Models.PortableExecutable.Resource.Entries.StringTableResource(); + + // Loop through and add + while (offset < data.Length) + { + string? stringValue = data.ReadPrefixedUnicodeString(ref offset); + if (stringValue is not null) + { + stringValue = stringValue.Replace("\n", "\\n").Replace("\r", newValue: "\\r"); + obj.Values[stringIndex++] = stringValue; + } + } + + return obj; + } + /// /// Parse a Stream into a symbol table /// diff --git a/SabreTools.Serialization/Wrappers/PortableExecutable.Printing.cs b/SabreTools.Serialization/Wrappers/PortableExecutable.Printing.cs index dd1e41b1..f5bf979f 100644 --- a/SabreTools.Serialization/Wrappers/PortableExecutable.Printing.cs +++ b/SabreTools.Serialization/Wrappers/PortableExecutable.Printing.cs @@ -1284,8 +1284,8 @@ namespace SabreTools.Serialization.Wrappers { string padding = new(' ', (level + 1) * 2); - Dictionary? stringTable = null; - try { stringTable = entry.AsStringTable(); } catch { } + StringTableResource? stringTable = null; + try { stringTable = Readers.PortableExecutable.ParseStringTableResource(entry.Data); } catch { } if (stringTable is null) { @@ -1293,7 +1293,7 @@ namespace SabreTools.Serialization.Wrappers return; } - foreach (var kvp in stringTable) + foreach (var kvp in stringTable.Values) { int index = kvp.Key; string? stringValue = kvp.Value; diff --git a/SabreTools.Serialization/Wrappers/PortableExecutable.cs b/SabreTools.Serialization/Wrappers/PortableExecutable.cs index 83b605c2..97d77549 100644 --- a/SabreTools.Serialization/Wrappers/PortableExecutable.cs +++ b/SabreTools.Serialization/Wrappers/PortableExecutable.cs @@ -1894,7 +1894,7 @@ namespace SabreTools.Serialization.Wrappers value = Readers.PortableExecutable.ParseDialogBoxResource(entry.Data); break; case ResourceType.RT_STRING: - value = entry.AsStringTable(); + value = Readers.PortableExecutable.ParseStringTableResource(entry.Data); break; case ResourceType.RT_FONTDIR: value = entry.Data;