mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-22 14:55:11 +00:00
Do the same for version info
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using SabreTools.Data.Models.COFF;
|
||||
using SabreTools.Data.Models.PortableExecutable;
|
||||
@@ -243,84 +242,6 @@ namespace SabreTools.Data.Extensions
|
||||
return fontGroupHeader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read byte data as a string file info resource
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse into a string file info</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled string file info resource on success, null on error</returns>
|
||||
public static StringFileInfo? AsStringFileInfo(byte[] data, ref int offset)
|
||||
{
|
||||
var stringFileInfo = new StringFileInfo();
|
||||
|
||||
// Cache the initial offset
|
||||
int currentOffset = offset;
|
||||
|
||||
stringFileInfo.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
stringFileInfo.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
stringFileInfo.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
stringFileInfo.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
if (stringFileInfo.Key != "StringFileInfo")
|
||||
{
|
||||
offset -= 6 + (((stringFileInfo.Key?.Length ?? 0) + 1) * 2);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
var stringFileInfoChildren = new List<Models.PortableExecutable.Resource.Entries.StringTable>();
|
||||
while ((offset - currentOffset) < stringFileInfo.Length)
|
||||
{
|
||||
var stringTable = new Models.PortableExecutable.Resource.Entries.StringTable();
|
||||
|
||||
stringTable.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
stringTable.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
stringTable.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
stringTable.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
var stringTableChildren = new List<StringData>();
|
||||
while ((offset - currentOffset) < stringTable.Length)
|
||||
{
|
||||
var stringData = new StringData();
|
||||
|
||||
int dataStartOffset = offset;
|
||||
stringData.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
stringData.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
stringData.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
stringData.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
if (stringData.ValueLength > 0)
|
||||
{
|
||||
int bytesReadable = Math.Min(stringData.ValueLength * sizeof(ushort), stringData.Length - (offset - dataStartOffset));
|
||||
byte[] valueBytes = data.ReadBytes(ref offset, bytesReadable);
|
||||
stringData.Value = Encoding.Unicode.GetString(valueBytes);
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
stringTableChildren.Add(stringData);
|
||||
if (stringData.Length == 0 && stringData.ValueLength == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
stringTable.Children = [.. stringTableChildren];
|
||||
|
||||
stringFileInfoChildren.Add(stringTable);
|
||||
}
|
||||
|
||||
stringFileInfo.Children = [.. stringFileInfoChildren];
|
||||
|
||||
return stringFileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read resource data as a string table resource
|
||||
/// </summary>
|
||||
@@ -353,67 +274,6 @@ namespace SabreTools.Data.Extensions
|
||||
return stringTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read byte data as a var file info resource
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse into a var file info</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled var file info resource on success, null on error</returns>
|
||||
public static VarFileInfo? AsVarFileInfo(byte[] data, ref int offset)
|
||||
{
|
||||
var varFileInfo = new VarFileInfo();
|
||||
|
||||
// Cache the initial offset
|
||||
int initialOffset = offset;
|
||||
|
||||
varFileInfo.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
varFileInfo.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
varFileInfo.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
varFileInfo.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
if (varFileInfo.Key != "VarFileInfo")
|
||||
return null;
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
var varFileInfoChildren = new List<VarData>();
|
||||
while ((offset - initialOffset) < varFileInfo.Length)
|
||||
{
|
||||
var varData = new VarData();
|
||||
|
||||
varData.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
varData.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
varData.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
varData.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
if (varData.Key != "Translation")
|
||||
{
|
||||
offset -= 6 + (((varData.Key?.Length ?? 0) + 1) * 2);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
// Cache the current offset
|
||||
int currentOffset = offset;
|
||||
|
||||
var varDataValue = new List<uint>();
|
||||
while ((offset - currentOffset) < varData.ValueLength)
|
||||
{
|
||||
uint languageAndCodeIdentifierPair = data.ReadUInt32LittleEndian(ref offset);
|
||||
varDataValue.Add(languageAndCodeIdentifierPair);
|
||||
}
|
||||
|
||||
varData.Value = [.. varDataValue];
|
||||
|
||||
varFileInfoChildren.Add(varData);
|
||||
}
|
||||
|
||||
varFileInfo.Children = [.. varFileInfoChildren];
|
||||
|
||||
return varFileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read resource data as a version info resource
|
||||
/// </summary>
|
||||
@@ -425,67 +285,7 @@ namespace SabreTools.Data.Extensions
|
||||
if (entry?.Data is null)
|
||||
return null;
|
||||
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var versionInfo = new VersionInfo();
|
||||
|
||||
versionInfo.Length = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
versionInfo.ValueLength = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
versionInfo.ResourceType = (VersionResourceType)entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
versionInfo.Key = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
if (versionInfo.Key != "VS_VERSION_INFO")
|
||||
return null;
|
||||
|
||||
while (offset < entry.Data.Length && (offset % 4) != 0)
|
||||
versionInfo.Padding1 = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read fixed file info
|
||||
if (versionInfo.ValueLength > 0 && offset + versionInfo.ValueLength <= entry.Data.Length)
|
||||
{
|
||||
var fixedFileInfo = ParseFixedFileInfo(entry.Data, ref offset);
|
||||
if (fixedFileInfo?.Signature != 0xFEEF04BD)
|
||||
return null;
|
||||
|
||||
versionInfo.Value = fixedFileInfo;
|
||||
}
|
||||
|
||||
while (offset < entry.Data.Length && (offset % 4) != 0)
|
||||
versionInfo.Padding2 = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Determine if we have a StringFileInfo or VarFileInfo twice
|
||||
ReadInfoSection(entry.Data, ref offset, versionInfo);
|
||||
ReadInfoSection(entry.Data, ref offset, versionInfo);
|
||||
|
||||
return versionInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a FixedFileInfo
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled FixedFileInfo on success, null on error</returns>
|
||||
public static FixedFileInfo ParseFixedFileInfo(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new FixedFileInfo();
|
||||
|
||||
obj.Signature = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.StrucVersion = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileVersionMS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileVersionLS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ProductVersionMS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ProductVersionLS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileFlagsMask = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileFlags = (FixedFileInfoFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileOS = (FixedFileInfoOS)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileType = (FixedFileInfoFileType)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileSubtype = (FixedFileInfoFileSubtype)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileDateMS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileDateLS = data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
return Serialization.Readers.PortableExecutable.ParseVersionInfo(entry.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -512,38 +312,6 @@ namespace SabreTools.Data.Extensions
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read either a `StringFileInfo` or `VarFileInfo` based on the key
|
||||
/// </summary>
|
||||
/// <param name="entry"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="versionInfo"></param>
|
||||
/// <returns></returns>
|
||||
private static void ReadInfoSection(byte[] data, ref int offset, VersionInfo versionInfo)
|
||||
{
|
||||
// If the offset is invalid, don't move the pointer
|
||||
if (offset < 0 || offset >= versionInfo.Length)
|
||||
return;
|
||||
|
||||
// Cache the current offset for reading
|
||||
int currentOffset = offset;
|
||||
|
||||
offset += 6;
|
||||
string? nextKey = data.ReadNullTerminatedUnicodeString(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
if (nextKey == "StringFileInfo")
|
||||
{
|
||||
var stringFileInfo = AsStringFileInfo(data, ref offset);
|
||||
versionInfo.StringFileInfo = stringFileInfo;
|
||||
}
|
||||
else if (nextKey == "VarFileInfo")
|
||||
{
|
||||
var varFileInfo = AsVarFileInfo(data, ref offset);
|
||||
versionInfo.VarFileInfo = varFileInfo;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
@@ -1450,6 +1450,33 @@ namespace SabreTools.Serialization.Readers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a FixedFileInfo
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled FixedFileInfo on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.FixedFileInfo ParseFixedFileInfo(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.FixedFileInfo();
|
||||
|
||||
obj.Signature = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.StrucVersion = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileVersionMS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileVersionLS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ProductVersionMS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ProductVersionLS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileFlagsMask = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileFlags = (FixedFileInfoFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileOS = (FixedFileInfoOS)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileType = (FixedFileInfoFileType)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileSubtype = (FixedFileInfoFileSubtype)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileDateMS = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.FileDateLS = data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a FunctionDefinition
|
||||
/// </summary>
|
||||
@@ -1811,6 +1838,37 @@ namespace SabreTools.Serialization.Readers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read either a `StringFileInfo` or `VarFileInfo` based on the key
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <param name="versionInfo"></param>
|
||||
public static void ReadInfoSection(byte[] data, ref int offset, Data.Models.PortableExecutable.Resource.Entries.VersionInfo versionInfo)
|
||||
{
|
||||
// If the offset is invalid, don't move the pointer
|
||||
if (offset < 0 || offset >= versionInfo.Length)
|
||||
return;
|
||||
|
||||
// Cache the current offset for reading
|
||||
int currentOffset = offset;
|
||||
|
||||
offset += 6;
|
||||
string? nextKey = data.ReadNullTerminatedUnicodeString(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
if (nextKey == "StringFileInfo")
|
||||
{
|
||||
var stringFileInfo = ParseStringFileInfo(data, ref offset);
|
||||
versionInfo.StringFileInfo = stringFileInfo;
|
||||
}
|
||||
else if (nextKey == "VarFileInfo")
|
||||
{
|
||||
var varFileInfo = ParseVarFileInfo(data, ref offset);
|
||||
versionInfo.VarFileInfo = varFileInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a LineNumber
|
||||
/// </summary>
|
||||
@@ -2542,6 +2600,76 @@ namespace SabreTools.Serialization.Readers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read byte data as a string file info resource
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled string file info resource on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.StringFileInfo? ParseStringFileInfo(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.StringFileInfo();
|
||||
|
||||
// Cache the initial offset
|
||||
int currentOffset = offset;
|
||||
|
||||
obj.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
if (obj.Key != "StringFileInfo")
|
||||
{
|
||||
offset -= 6 + (((obj.Key?.Length ?? 0) + 1) * 2);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
var stringFileInfoChildren = new List<Data.Models.PortableExecutable.Resource.Entries.StringTable>();
|
||||
while ((offset - currentOffset) < obj.Length)
|
||||
{
|
||||
var stringTable = ParseStringTableResource(data, ref offset, currentOffset);
|
||||
stringFileInfoChildren.Add(stringTable);
|
||||
}
|
||||
|
||||
obj.Children = [.. stringFileInfoChildren];
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read byte data as a StringData
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled StringData on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.StringData ParseStringData(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.StringData();
|
||||
|
||||
int dataStartOffset = offset;
|
||||
obj.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
if (obj.ValueLength > 0)
|
||||
{
|
||||
int bytesReadable = Math.Min(obj.ValueLength * sizeof(ushort), obj.Length - (offset - dataStartOffset));
|
||||
byte[] valueBytes = data.ReadBytes(ref offset, bytesReadable);
|
||||
obj.Value = Encoding.Unicode.GetString(valueBytes);
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a StringTable
|
||||
/// </summary>
|
||||
@@ -2571,6 +2699,38 @@ namespace SabreTools.Serialization.Readers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read byte data as a StringTable resource
|
||||
/// </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)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.StringTable();
|
||||
|
||||
obj.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
var stringTableChildren = new List<Data.Models.PortableExecutable.Resource.Entries.StringData>();
|
||||
while ((offset - initialOffset) < obj.Length)
|
||||
{
|
||||
var stringData = ParseStringData(data, ref offset);
|
||||
stringTableChildren.Add(stringData);
|
||||
if (stringData.Length == 0 && stringData.ValueLength == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
obj.Children = [.. stringTableChildren];
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a symbol table
|
||||
/// </summary>
|
||||
@@ -2651,6 +2811,111 @@ namespace SabreTools.Serialization.Readers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read byte data as a VarFileInfo
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled VarFileInfo on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.VarFileInfo? ParseVarFileInfo(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.VarFileInfo();
|
||||
|
||||
// Cache the initial offset
|
||||
int initialOffset = offset;
|
||||
|
||||
obj.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
if (obj.Key != "VarFileInfo")
|
||||
return null;
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
var varFileInfoChildren = new List<Data.Models.PortableExecutable.Resource.Entries.VarData>();
|
||||
while ((offset - initialOffset) < obj.Length)
|
||||
{
|
||||
var varData = new Data.Models.PortableExecutable.Resource.Entries.VarData();
|
||||
|
||||
varData.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
varData.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
varData.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
varData.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
if (varData.Key != "Translation")
|
||||
{
|
||||
offset -= 6 + (((varData.Key?.Length ?? 0) + 1) * 2);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
// Cache the current offset
|
||||
int currentOffset = offset;
|
||||
|
||||
var varDataValue = new List<uint>();
|
||||
while ((offset - currentOffset) < varData.ValueLength)
|
||||
{
|
||||
uint languageAndCodeIdentifierPair = data.ReadUInt32LittleEndian(ref offset);
|
||||
varDataValue.Add(languageAndCodeIdentifierPair);
|
||||
}
|
||||
|
||||
varData.Value = [.. varDataValue];
|
||||
|
||||
varFileInfoChildren.Add(varData);
|
||||
}
|
||||
|
||||
obj.Children = [.. varFileInfoChildren];
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a VersionInfo
|
||||
/// </summary>
|
||||
/// <param name="tableData">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled VersionInfo on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.VersionInfo? ParseVersionInfo(byte[] data)
|
||||
{
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.VersionInfo();
|
||||
|
||||
obj.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.ResourceType = (VersionResourceType)data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Key = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
if (obj.Key != "VS_VERSION_INFO")
|
||||
return null;
|
||||
|
||||
while (offset < data.Length && (offset % 4) != 0)
|
||||
obj.Padding1 = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read fixed file info
|
||||
if (obj.ValueLength > 0 && offset + obj.ValueLength <= data.Length)
|
||||
{
|
||||
var fixedFileInfo = ParseFixedFileInfo(data, ref offset);
|
||||
if (fixedFileInfo?.Signature != 0xFEEF04BD)
|
||||
return null;
|
||||
|
||||
obj.Value = fixedFileInfo;
|
||||
}
|
||||
|
||||
while (offset < data.Length && (offset % 4) != 0)
|
||||
obj.Padding2 = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Determine if we have a StringFileInfo or VarFileInfo twice
|
||||
ReadInfoSection(data, ref offset, obj);
|
||||
ReadInfoSection(data, ref offset, obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a WeakExternal
|
||||
/// </summary>
|
||||
|
||||
@@ -1072,7 +1072,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
string padding = new(' ', (level + 1) * 2);
|
||||
|
||||
MenuResource? menu = null;
|
||||
try { menu = entry.AsMenu(); } catch { }
|
||||
try { menu = Readers.PortableExecutable.ParseMenuResource(entry.Data); } catch { }
|
||||
|
||||
if (menu is null)
|
||||
{
|
||||
@@ -1149,7 +1149,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
string padding = new(' ', (level + 1) * 2);
|
||||
|
||||
DialogBoxResource? dialogBox = null;
|
||||
try { dialogBox = entry.AsDialogBox(); } catch { }
|
||||
try { dialogBox = Readers.PortableExecutable.ParseDialogBoxResource(entry.Data); } catch { }
|
||||
|
||||
if (dialogBox is null)
|
||||
{
|
||||
@@ -1318,7 +1318,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
string padding = new(' ', (level + 1) * 2);
|
||||
|
||||
AcceleratorTable? acceleratorTable = null;
|
||||
try { acceleratorTable = entry.AsAcceleratorTableResource(); } catch { }
|
||||
try { acceleratorTable = Readers.PortableExecutable.ParseAcceleratorTable(entry.Data); } catch { }
|
||||
|
||||
if (acceleratorTable?.Entries is null)
|
||||
{
|
||||
@@ -1401,7 +1401,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
string padding = new(' ', (level + 1) * 2);
|
||||
|
||||
MessageResourceData? messageTable = null;
|
||||
try { messageTable = entry.AsMessageResourceData(); } catch { }
|
||||
try { messageTable = Readers.PortableExecutable.ParseMessageResourceData(entry.Data); } catch { }
|
||||
|
||||
if (messageTable is null)
|
||||
{
|
||||
@@ -1480,7 +1480,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
string padding = new(' ', (level + 1) * 2);
|
||||
|
||||
VersionInfo? versionInfo = null;
|
||||
try { versionInfo = entry.AsVersionInfo(); } catch { }
|
||||
try { versionInfo = Readers.PortableExecutable.ParseVersionInfo(entry.Data); } catch { }
|
||||
|
||||
if (versionInfo is null)
|
||||
{
|
||||
|
||||
@@ -1887,11 +1887,11 @@ namespace SabreTools.Serialization.Wrappers
|
||||
break;
|
||||
case ResourceType.RT_MENU:
|
||||
case ResourceType.RT_NEWMENU:
|
||||
value = entry.AsMenu();
|
||||
value = Readers.PortableExecutable.ParseMenuResource(entry.Data);
|
||||
break;
|
||||
case ResourceType.RT_DIALOG:
|
||||
case ResourceType.RT_NEWDIALOG:
|
||||
value = entry.AsDialogBox();
|
||||
value = Readers.PortableExecutable.ParseDialogBoxResource(entry.Data);
|
||||
break;
|
||||
case ResourceType.RT_STRING:
|
||||
value = entry.AsStringTable();
|
||||
@@ -1903,13 +1903,13 @@ namespace SabreTools.Serialization.Wrappers
|
||||
value = entry.Data;
|
||||
break;
|
||||
case ResourceType.RT_ACCELERATOR:
|
||||
value = entry.AsAcceleratorTableResource();
|
||||
value = Readers.PortableExecutable.ParseAcceleratorTable(entry.Data);
|
||||
break;
|
||||
case ResourceType.RT_RCDATA:
|
||||
value = entry.Data;
|
||||
break;
|
||||
case ResourceType.RT_MESSAGETABLE:
|
||||
value = entry.AsMessageResourceData();
|
||||
value = Readers.PortableExecutable.ParseMessageResourceData(entry.Data);
|
||||
break;
|
||||
case ResourceType.RT_GROUP_CURSOR:
|
||||
value = entry.Data;
|
||||
@@ -1918,7 +1918,7 @@ namespace SabreTools.Serialization.Wrappers
|
||||
value = entry.Data;
|
||||
break;
|
||||
case ResourceType.RT_VERSION:
|
||||
_versionInfo = entry.AsVersionInfo();
|
||||
_versionInfo = Readers.PortableExecutable.ParseVersionInfo(entry.Data);
|
||||
value = _versionInfo;
|
||||
break;
|
||||
case ResourceType.RT_DLGINCLUDE:
|
||||
|
||||
Reference in New Issue
Block a user