Do the same for string table resource

This commit is contained in:
Matt Nadareski
2026-02-12 16:02:09 -05:00
parent 3e0a6dbf32
commit c5f732584b
5 changed files with 53 additions and 43 deletions

View File

@@ -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
/// <summary>
/// Read resource data as a string table resource
/// </summary>
/// <param name="entry">Resource data entry to parse into a string table resource</param>
/// <returns>A filled string table resource on success, null on error</returns>
/// TODO: Create concrete type for this and inherit from ResourceDataType
public static Dictionary<int, string?>? 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<int, string?>();
// 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;
}
/// <summary>
/// Parse a byte array into a ResourceHeader
/// </summary>

View File

@@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace SabreTools.Data.Models.PortableExecutable.Resource.Entries
{
/// <summary>
/// Represents a string table resource
/// </summary>
public sealed class StringTableResource : ResourceDataType
{
/// <summary>
/// Set of integer-keyed values
/// </summary>
public Dictionary<int, string?> Values { get; set; } = [];
}
}

View File

@@ -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<Data.Models.PortableExecutable.Resource.Entries.StringTable>();
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
}
/// <summary>
/// Parse a Stream into a StringTable
/// Parse a Stream into a COFF StringTable
/// </summary>
/// <param name="data">Stream to parse</param>
/// <returns>Filled StringTable on success, null on error</returns>
public static StringTable ParseStringTable(Stream data)
public static StringTable ParseCOFFStringTable(Stream data)
{
var obj = new StringTable();
@@ -2810,12 +2810,12 @@ namespace SabreTools.Serialization.Readers
}
/// <summary>
/// Read byte data as a StringTable resource
/// Read byte data as a FileInfo StringTable
/// </summary>
/// <param name="data">Byte array to parse</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled StringTable resource on success, null on error</returns>
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;
}
/// <summary>
/// Read byte data as a StringTableResource
/// </summary>
/// <param name="data">Byte array to parse</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled StringTableResource resource on success, null on error</returns>
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;
}
/// <summary>
/// Parse a Stream into a symbol table
/// </summary>

View File

@@ -1284,8 +1284,8 @@ namespace SabreTools.Serialization.Wrappers
{
string padding = new(' ', (level + 1) * 2);
Dictionary<int, string?>? 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;

View File

@@ -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;