Generic resource entry is now used

This commit is contained in:
Matt Nadareski
2026-02-12 18:25:24 -05:00
parent c99f86ee95
commit e9eb3eb4be
6 changed files with 59 additions and 44 deletions

View File

@@ -3,7 +3,7 @@ namespace SabreTools.Data.Models.PortableExecutable.Resource.Entries
/// <summary>
/// Generic or unparsed resource data
/// </summary>
public abstract class GenericResourceEntry : ResourceDataType
public class GenericResourceEntry : ResourceDataType
{
/// <summary>
/// Unparsed byte data from the resource

View File

@@ -10,6 +10,6 @@ namespace SabreTools.Data.Models.PortableExecutable.Resource.Entries
/// <summary>
/// Set of integer-keyed values
/// </summary>
public Dictionary<int, string?> Values { get; set; } = [];
public Dictionary<int, string?> Data { get; set; } = [];
}
}

View File

@@ -1606,6 +1606,21 @@ namespace SabreTools.Serialization.Readers
return obj;
}
/// <summary>
/// Parse a byte array into a GenericResourceEntry
/// </summary>
/// <param name="data">Data to parse</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled GenericResourceEntry on success, null on error</returns>
public static Data.Models.PortableExecutable.Resource.Entries.GenericResourceEntry ParseGenericResourceEntry(byte[] data)
{
var obj = new Data.Models.PortableExecutable.Resource.Entries.GenericResourceEntry();
obj.Data = data;
return obj;
}
/// <summary>
/// Parse a Stream into a HintNameTable
/// </summary>
@@ -2930,7 +2945,7 @@ namespace SabreTools.Serialization.Readers
if (stringValue is not null)
{
stringValue = stringValue.Replace("\n", "\\n").Replace("\r", newValue: "\\r");
obj.Values[stringIndex++] = stringValue;
obj.Data[stringIndex++] = stringValue;
}
}

View File

@@ -362,7 +362,7 @@ namespace SabreTools.Serialization.Wrappers
string resourceKey = kvp.Key;
var value = kvp.Value;
if (value is null || value is not byte[] ba || ba.Length == 0)
if (value is null || value is not Data.Models.PortableExecutable.Resource.Entries.GenericResourceEntry ba || ba.Data.Length == 0)
continue;
// Set the output variables
@@ -370,10 +370,10 @@ namespace SabreTools.Serialization.Wrappers
string extension = string.Empty;
// Only process the resource if it a recognized signature
for (; resourceOffset < 0x400 && resourceOffset < ba.Length - 0x10; resourceOffset++)
for (; resourceOffset < 0x400 && resourceOffset < ba.Data.Length - 0x10; resourceOffset++)
{
int temp = resourceOffset;
byte[] resourceSample = ba.ReadBytes(ref temp, 0x10);
byte[] resourceSample = ba.Data.ReadBytes(ref temp, 0x10);
if (resourceSample.StartsWith(Data.Models.SevenZip.Constants.SignatureBytes))
{
@@ -506,7 +506,7 @@ namespace SabreTools.Serialization.Wrappers
// Write the resource data to a temp file
using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream.Write(ba, resourceOffset, ba.Length - resourceOffset);
tempStream.Write(ba.Data, resourceOffset, ba.Data.Length - resourceOffset);
tempStream.Flush();
}
catch (Exception ex)

View File

@@ -1293,7 +1293,7 @@ namespace SabreTools.Serialization.Wrappers
return;
}
foreach (var kvp in stringTable.Values)
foreach (var kvp in stringTable.Data)
{
int index = kvp.Key;
string? stringValue = kvp.Value;

View File

@@ -595,7 +595,7 @@ namespace SabreTools.Serialization.Wrappers
/// <summary>
/// Dictionary of resource data
/// </summary>
public Dictionary<string, object?> ResourceData
public Dictionary<string, ResourceDataType?> ResourceData
{
get
{
@@ -1122,7 +1122,7 @@ namespace SabreTools.Serialization.Wrappers
/// <summary>
/// Cached resource data
/// </summary>
private readonly Dictionary<string, object?> _resourceData = [];
private readonly Dictionary<string, ResourceDataType?> _resourceData = [];
/// <summary>
/// Lock object for <see cref="_resourceData"/>
@@ -1588,22 +1588,22 @@ namespace SabreTools.Serialization.Wrappers
/// </summary>
/// <param name="entry">String entry to check for</param>
/// <returns>List of matching resources</returns>
public List<Dictionary<int, string?>?> FindStringTableByEntry(string entry)
public List<StringTableResource?> FindStringTableByEntry(string entry)
{
// Cache the resource data for easier reading
var resourceData = ResourceData;
if (resourceData.Count == 0)
return [];
var stringTables = new List<Dictionary<int, string?>?>();
var stringTables = new List<StringTableResource?>();
foreach (var resource in resourceData.Values)
{
if (resource is null)
continue;
if (resource is not Dictionary<int, string?> st || st is null)
if (resource is not StringTableResource st || st is null)
continue;
foreach (string? s in st.Values)
foreach (string? s in st.Data.Values)
{
#if NETFRAMEWORK || NETSTANDARD
if (s is null || !s.Contains(entry))
@@ -1637,10 +1637,10 @@ namespace SabreTools.Serialization.Wrappers
{
if (!kvp.Key.Contains(typeName))
continue;
if (kvp.Value is null || kvp.Value is not byte[] b || b is null)
if (kvp.Value is null || kvp.Value is not GenericResourceEntry b || b is null)
continue;
resources.Add(b);
resources.Add(b.Data);
}
return resources;
@@ -1663,15 +1663,15 @@ namespace SabreTools.Serialization.Wrappers
{
if (resource is null)
continue;
if (resource is not byte[] b || b is null)
if (resource is not GenericResourceEntry b || b is null)
continue;
try
{
string? arrayAsASCII = Encoding.ASCII.GetString(b!);
string? arrayAsASCII = Encoding.ASCII.GetString(b!.Data);
if (arrayAsASCII.Contains(value))
{
resources.Add(b);
resources.Add(b.Data);
continue;
}
}
@@ -1679,10 +1679,10 @@ namespace SabreTools.Serialization.Wrappers
try
{
string? arrayAsUTF8 = Encoding.UTF8.GetString(b!);
string? arrayAsUTF8 = Encoding.UTF8.GetString(b!.Data);
if (arrayAsUTF8.Contains(value))
{
resources.Add(b);
resources.Add(b.Data);
continue;
}
}
@@ -1690,10 +1690,10 @@ namespace SabreTools.Serialization.Wrappers
try
{
string? arrayAsUnicode = Encoding.Unicode.GetString(b!);
string? arrayAsUnicode = Encoding.Unicode.GetString(b!.Data);
if (arrayAsUnicode.Contains(value))
{
resources.Add(b);
resources.Add(b.Data);
continue;
}
}
@@ -1770,9 +1770,9 @@ namespace SabreTools.Serialization.Wrappers
bool exeResources = false;
foreach (var kvp in resourceData)
{
if (kvp.Value is null || kvp.Value is not byte[] ba)
if (kvp.Value is null || kvp.Value is not GenericResourceEntry ba)
continue;
if (!ba.StartsWith(Data.Models.MSDOS.Constants.SignatureBytes))
if (!ba.Data.StartsWith(Data.Models.MSDOS.Constants.SignatureBytes))
continue;
exeResources = true;
@@ -1866,7 +1866,7 @@ namespace SabreTools.Serialization.Wrappers
// Create the key and value objects
string key = string.Join(", ", Array.ConvertAll([.. types], t => t.ToString()));
object? value = entry.Data;
ResourceDataType? value = Readers.PortableExecutable.ParseGenericResourceEntry(entry.Data);
// If we have a known resource type
if (types.Count > 0 && types[0] is uint resourceType)
@@ -1876,14 +1876,14 @@ namespace SabreTools.Serialization.Wrappers
switch ((ResourceType)resourceType)
{
case ResourceType.RT_CURSOR:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_BITMAP:
case ResourceType.RT_NEWBITMAP:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_ICON:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_MENU:
case ResourceType.RT_NEWMENU:
@@ -1897,47 +1897,47 @@ namespace SabreTools.Serialization.Wrappers
value = Readers.PortableExecutable.ParseStringTableResource(entry.Data);
break;
case ResourceType.RT_FONTDIR:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_FONT:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_ACCELERATOR:
value = Readers.PortableExecutable.ParseAcceleratorTable(entry.Data);
break;
case ResourceType.RT_RCDATA:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_MESSAGETABLE:
value = Readers.PortableExecutable.ParseMessageResourceData(entry.Data);
break;
case ResourceType.RT_GROUP_CURSOR:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_GROUP_ICON:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_VERSION:
_versionInfo = Readers.PortableExecutable.ParseVersionInfo(entry.Data);
value = _versionInfo;
break;
case ResourceType.RT_DLGINCLUDE:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_PLUGPLAY:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_VXD:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_ANICURSOR:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_ANIICON:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_HTML:
value = entry.Data;
// TODO: Implement specific parsing
break;
case ResourceType.RT_MANIFEST:
_assemblyManifest = Readers.PortableExecutable.ParseAssemblyManifest(entry.Data);
@@ -1950,25 +1950,25 @@ namespace SabreTools.Serialization.Wrappers
// Error state, ignore
case ResourceType.RT_ERROR:
value = entry.Data;
// TODO: Implement specific parsing
break;
default:
value = entry.Data;
// TODO: Implement specific parsing
break;
}
}
catch
{
// Fall back on byte array data for malformed items
value = entry.Data;
value = Readers.PortableExecutable.ParseGenericResourceEntry(entry.Data);
}
}
// If we have a custom resource type
else if (types.Count > 0 && types[0] is string)
{
value = entry.Data;
value = Readers.PortableExecutable.ParseGenericResourceEntry(entry.Data);
}
// Add the key and value to the cache