mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-09-22 06:45:11 +00:00
Move some extension parsers to more common location
This commit is contained in:
@@ -163,23 +163,7 @@ namespace SabreTools.Data.Extensions
|
||||
if (entry?.Data is null || entry.Data.Length % 8 != 0)
|
||||
return null;
|
||||
|
||||
// Get the number of entries
|
||||
int count = entry.Data.Length / 8;
|
||||
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var table = new AcceleratorTable();
|
||||
table.Entries = new AcceleratorTableEntry[count];
|
||||
|
||||
// Read in the table
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
table.Entries[i] = ParseAcceleratorTableEntry(entry.Data, ref offset);
|
||||
}
|
||||
|
||||
return table;
|
||||
return Serialization.Readers.PortableExecutable.ParseAcceleratorTable(entry.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -215,470 +199,7 @@ namespace SabreTools.Data.Extensions
|
||||
if (entry?.Data is null)
|
||||
return null;
|
||||
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var dialogBoxResource = new DialogBoxResource();
|
||||
|
||||
// Try to read the signature for an extended dialog box template
|
||||
int signatureOffset = sizeof(ushort);
|
||||
int possibleSignature = entry.Data.ReadUInt16LittleEndian(ref signatureOffset);
|
||||
if (possibleSignature == 0xFFFF)
|
||||
{
|
||||
#region Extended dialog template
|
||||
|
||||
var dialogTemplateExtended = new DialogTemplateExtended();
|
||||
|
||||
dialogTemplateExtended.Version = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
dialogTemplateExtended.Signature = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
dialogTemplateExtended.HelpID = entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogTemplateExtended.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogTemplateExtended.Style = (WindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogTemplateExtended.DialogItems = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
dialogTemplateExtended.PositionX = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogTemplateExtended.PositionY = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogTemplateExtended.WidthX = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogTemplateExtended.HeightY = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
|
||||
#region Menu resource
|
||||
|
||||
int currentOffset = offset;
|
||||
ushort menuResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (menuResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool menuResourceHasOrdinal = menuResourceIdentifier == 0xFFFF;
|
||||
if (menuResourceHasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the menu resource as a string
|
||||
dialogTemplateExtended.MenuResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
|
||||
// Read the ordinal if we have the flag set
|
||||
if (menuResourceHasOrdinal)
|
||||
dialogTemplateExtended.MenuResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Class resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort classResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (classResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool classResourcehasOrdinal = classResourceIdentifier == 0xFFFF;
|
||||
if (classResourcehasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the class resource as a string
|
||||
dialogTemplateExtended.ClassResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
|
||||
// Read the ordinal if we have the flag set
|
||||
if (classResourcehasOrdinal)
|
||||
dialogTemplateExtended.ClassResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Title resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort titleResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (titleResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the title resource as a string
|
||||
dialogTemplateExtended.TitleResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Point size and typeface
|
||||
|
||||
// Only if DS_SETFONT is set are the values here used
|
||||
#if NET20 || NET35
|
||||
if ((dialogTemplateExtended.Style & WindowStyles.DS_SETFONT) != 0)
|
||||
#else
|
||||
if (dialogTemplateExtended.Style.HasFlag(WindowStyles.DS_SETFONT))
|
||||
#endif
|
||||
{
|
||||
dialogTemplateExtended.PointSize = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
dialogTemplateExtended.Weight = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
dialogTemplateExtended.Italic = entry.Data.ReadByte(ref offset);
|
||||
dialogTemplateExtended.CharSet = entry.Data.ReadByte(ref offset);
|
||||
dialogTemplateExtended.Typeface = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
#endregion
|
||||
|
||||
dialogBoxResource.ExtendedDialogTemplate = dialogTemplateExtended;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extended dialog item templates
|
||||
|
||||
var dialogItemExtendedTemplates = new List<DialogItemTemplateExtended>();
|
||||
|
||||
for (int i = 0; i < dialogTemplateExtended.DialogItems; i++)
|
||||
{
|
||||
var dialogItemTemplate = new DialogItemTemplateExtended();
|
||||
|
||||
dialogItemTemplate.HelpID = entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogItemTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogItemTemplate.Style = (WindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogItemTemplate.PositionX = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogItemTemplate.PositionY = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogItemTemplate.WidthX = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogItemTemplate.HeightY = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogItemTemplate.ID = entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
#region Class resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort itemClassResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0xFFFF means ordinal only
|
||||
if (itemClassResourceIdentifier == 0xFFFF)
|
||||
{
|
||||
// Increment the pointer
|
||||
_ = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the ordinal
|
||||
dialogItemTemplate.ClassResourceOrdinal = (DialogItemTemplateOrdinal)entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool classResourcehasOrdinal = itemClassResourceIdentifier == 0xFFFF;
|
||||
if (classResourcehasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the class resource as a string
|
||||
dialogItemTemplate.ClassResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Title resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort itemTitleResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0xFFFF means ordinal only
|
||||
if (itemTitleResourceIdentifier == 0xFFFF)
|
||||
{
|
||||
// Increment the pointer
|
||||
_ = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the ordinal
|
||||
dialogItemTemplate.TitleResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the title resource as a string
|
||||
dialogItemTemplate.TitleResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Creation data
|
||||
|
||||
dialogItemTemplate.CreationDataSize = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
if (dialogItemTemplate.CreationDataSize != 0)
|
||||
dialogItemTemplate.CreationData = entry.Data.ReadBytes(ref offset, dialogItemTemplate.CreationDataSize);
|
||||
|
||||
#endregion
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
dialogItemExtendedTemplates.Add(dialogItemTemplate);
|
||||
|
||||
// If we have an invalid item count
|
||||
if (offset >= entry.Data.Length)
|
||||
break;
|
||||
}
|
||||
|
||||
dialogBoxResource.ExtendedDialogItemTemplates = [.. dialogItemExtendedTemplates];
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Dialog template
|
||||
|
||||
var dialogTemplate = new DialogTemplate();
|
||||
|
||||
dialogTemplate.Style = (WindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogTemplate.ItemCount = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
dialogTemplate.PositionX = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogTemplate.PositionY = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogTemplate.WidthX = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogTemplate.HeightY = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
|
||||
#region Menu resource
|
||||
|
||||
int currentOffset = offset;
|
||||
ushort menuResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (menuResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool menuResourceHasOrdinal = menuResourceIdentifier == 0xFFFF;
|
||||
if (menuResourceHasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the menu resource as a string
|
||||
dialogTemplate.MenuResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
|
||||
// Read the ordinal if we have the flag set
|
||||
if (menuResourceHasOrdinal)
|
||||
dialogTemplate.MenuResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Class resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort classResourceIdentifier;
|
||||
if (offset >= entry.Data.Length)
|
||||
classResourceIdentifier = 0x0000;
|
||||
else
|
||||
classResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (classResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool classResourcehasOrdinal = classResourceIdentifier == 0xFFFF;
|
||||
if (classResourcehasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the class resource as a string
|
||||
dialogTemplate.ClassResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
|
||||
// Read the ordinal if we have the flag set
|
||||
if (classResourcehasOrdinal)
|
||||
dialogTemplate.ClassResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Title resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort titleResourceIdentifier;
|
||||
if (offset >= entry.Data.Length)
|
||||
titleResourceIdentifier = 0x0000;
|
||||
else
|
||||
titleResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (titleResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the title resource as a string
|
||||
dialogTemplate.TitleResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Point size and typeface
|
||||
|
||||
// Only if DS_SETFONT is set are the values here used
|
||||
#if NET20 || NET35
|
||||
if ((dialogTemplate.Style & WindowStyles.DS_SETFONT) != 0)
|
||||
#else
|
||||
if (dialogTemplate.Style.HasFlag(WindowStyles.DS_SETFONT))
|
||||
#endif
|
||||
{
|
||||
dialogTemplate.PointSizeValue = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the font name as a string
|
||||
dialogTemplate.Typeface = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
#endregion
|
||||
|
||||
dialogBoxResource.DialogTemplate = dialogTemplate;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dialog item templates
|
||||
|
||||
var dialogItemTemplates = new List<DialogItemTemplate>();
|
||||
|
||||
for (int i = 0; i < dialogTemplate.ItemCount; i++)
|
||||
{
|
||||
var dialogItemTemplate = new DialogItemTemplate();
|
||||
|
||||
dialogItemTemplate.Style = (WindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogItemTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
dialogItemTemplate.PositionX = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogItemTemplate.PositionY = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogItemTemplate.WidthX = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogItemTemplate.HeightY = entry.Data.ReadInt16LittleEndian(ref offset);
|
||||
dialogItemTemplate.ID = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
#region Class resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort itemClassResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0xFFFF means ordinal only
|
||||
if (itemClassResourceIdentifier == 0xFFFF)
|
||||
{
|
||||
// Increment the pointer
|
||||
_ = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the ordinal
|
||||
dialogItemTemplate.ClassResourceOrdinal = (DialogItemTemplateOrdinal)entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool classResourcehasOrdinal = itemClassResourceIdentifier == 0xFFFF;
|
||||
if (classResourcehasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the class resource as a string
|
||||
dialogItemTemplate.ClassResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Title resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort itemTitleResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0xFFFF means ordinal only
|
||||
if (itemTitleResourceIdentifier == 0xFFFF)
|
||||
{
|
||||
// Increment the pointer
|
||||
_ = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the ordinal
|
||||
dialogItemTemplate.TitleResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the title resource as a string
|
||||
dialogItemTemplate.TitleResource = entry.Data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Creation data
|
||||
|
||||
dialogItemTemplate.CreationDataSize = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
if (dialogItemTemplate.CreationDataSize != 0 && dialogItemTemplate.CreationDataSize + offset < entry.Data.Length)
|
||||
dialogItemTemplate.CreationData = entry.Data.ReadBytes(ref offset, dialogItemTemplate.CreationDataSize);
|
||||
|
||||
#endregion
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
dialogItemTemplates.Add(dialogItemTemplate);
|
||||
|
||||
// If we have an invalid item count
|
||||
if (offset >= entry.Data.Length)
|
||||
break;
|
||||
}
|
||||
|
||||
dialogBoxResource.DialogItemTemplates = [.. dialogItemTemplates];
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
return dialogBoxResource;
|
||||
return Serialization.Readers.PortableExecutable.ParseDialogBoxResource(entry.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -761,89 +282,7 @@ namespace SabreTools.Data.Extensions
|
||||
if (entry?.Data is null)
|
||||
return null;
|
||||
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var menuResource = new MenuResource();
|
||||
|
||||
// Try to read the version for an extended header
|
||||
int versionOffset = 0;
|
||||
int possibleVersion = entry.Data.ReadUInt16LittleEndian(ref versionOffset);
|
||||
if (possibleVersion == 0x0001)
|
||||
{
|
||||
#region Extended menu header
|
||||
|
||||
var menuHeaderExtended = ParseMenuHeaderExtended(entry.Data, ref offset);
|
||||
menuResource.MenuHeader = menuHeaderExtended;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extended dialog item templates
|
||||
|
||||
var extendedMenuItems = new List<MenuItemExtended>();
|
||||
|
||||
if (offset != 0)
|
||||
{
|
||||
offset = menuHeaderExtended.Offset;
|
||||
|
||||
while (offset < entry.Data.Length)
|
||||
{
|
||||
var extendedMenuItem = ParseMenuItemExtended(entry.Data, ref offset);
|
||||
extendedMenuItems.Add(extendedMenuItem);
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 4);
|
||||
}
|
||||
}
|
||||
|
||||
menuResource.MenuItems = [.. extendedMenuItems];
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Menu header
|
||||
|
||||
menuResource.MenuHeader = ParseNormalMenuHeader(entry.Data, ref offset);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Menu items
|
||||
|
||||
var menuItems = new List<MenuItem>();
|
||||
|
||||
while (offset < entry.Data.Length)
|
||||
{
|
||||
// Determine if this is a popup
|
||||
int flagsOffset = offset;
|
||||
var initialFlags = (MenuFlags)entry.Data.ReadUInt16LittleEndian(ref flagsOffset);
|
||||
|
||||
MenuItem? menuItem;
|
||||
#if NET20 || NET35
|
||||
if ((initialFlags & MenuFlags.MF_POPUP) != 0)
|
||||
#else
|
||||
if (initialFlags.HasFlag(MenuFlags.MF_POPUP))
|
||||
#endif
|
||||
menuItem = ParsePopupMenuItem(entry.Data, ref offset);
|
||||
else
|
||||
menuItem = ParseNormalMenuItem(entry.Data, ref offset);
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
entry.Data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
if (menuItem is null)
|
||||
return null;
|
||||
|
||||
menuItems.Add(menuItem);
|
||||
}
|
||||
|
||||
menuResource.MenuItems = [.. menuItems];
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
return menuResource;
|
||||
return Serialization.Readers.PortableExecutable.ParseMenuResource(entry.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -857,59 +296,7 @@ namespace SabreTools.Data.Extensions
|
||||
if (entry?.Data is null)
|
||||
return null;
|
||||
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var messageResourceData = new MessageResourceData();
|
||||
|
||||
// Message resource blocks
|
||||
messageResourceData.NumberOfBlocks = entry.Data.ReadUInt32LittleEndian(ref offset);
|
||||
if (messageResourceData.NumberOfBlocks > 0)
|
||||
{
|
||||
var messageResourceBlocks = new List<MessageResourceBlock>();
|
||||
|
||||
for (int i = 0; i < messageResourceData.NumberOfBlocks; i++)
|
||||
{
|
||||
var messageResourceBlock = ParseMessageResourceBlock(entry.Data, ref offset);
|
||||
messageResourceBlocks.Add(messageResourceBlock);
|
||||
}
|
||||
|
||||
messageResourceData.Blocks = [.. messageResourceBlocks];
|
||||
}
|
||||
|
||||
// Message resource entries
|
||||
if (messageResourceData.Blocks.Length != 0)
|
||||
{
|
||||
var messageResourceEntries = new Dictionary<uint, MessageResourceEntry?>();
|
||||
|
||||
for (int i = 0; i < messageResourceData.Blocks.Length; i++)
|
||||
{
|
||||
var messageResourceBlock = messageResourceData.Blocks[i];
|
||||
if (messageResourceBlock is null)
|
||||
continue;
|
||||
|
||||
offset = (int)messageResourceBlock.OffsetToEntries;
|
||||
|
||||
for (uint j = messageResourceBlock.LowId; j <= messageResourceBlock.HighId; j++)
|
||||
{
|
||||
var messageResourceEntry = new MessageResourceEntry();
|
||||
|
||||
messageResourceEntry.Length = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
messageResourceEntry.Flags = entry.Data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
Encoding textEncoding = messageResourceEntry.Flags == 0x0001 ? Encoding.Unicode : Encoding.ASCII;
|
||||
byte[] textArray = entry.Data.ReadBytes(ref offset, messageResourceEntry.Length - 4);
|
||||
messageResourceEntry.Text = textEncoding.GetString(textArray);
|
||||
|
||||
messageResourceEntries[j] = messageResourceEntry;
|
||||
}
|
||||
}
|
||||
|
||||
messageResourceData.Entries = messageResourceEntries;
|
||||
}
|
||||
|
||||
return messageResourceData;
|
||||
return Serialization.Readers.PortableExecutable.ParseMessageResourceData(entry.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1130,24 +517,6 @@ namespace SabreTools.Data.Extensions
|
||||
return versionInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a AcceleratorTableEntry
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled AcceleratorTableEntry on success, null on error</returns>
|
||||
public static AcceleratorTableEntry ParseAcceleratorTableEntry(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new AcceleratorTableEntry();
|
||||
|
||||
obj.Flags = (AcceleratorTableFlags)data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Ansi = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Id = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Padding = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a FixedFileInfo
|
||||
/// </summary>
|
||||
@@ -1175,110 +544,6 @@ namespace SabreTools.Data.Extensions
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a MenuHeaderExtended
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled MenuHeaderExtended on success, null on error</returns>
|
||||
public static MenuHeaderExtended ParseMenuHeaderExtended(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new MenuHeaderExtended();
|
||||
|
||||
obj.Version = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Offset = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.HelpID = data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a MenuItemExtended
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled MenuItemExtended on success, null on error</returns>
|
||||
public static MenuItemExtended ParseMenuItemExtended(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new MenuItemExtended();
|
||||
|
||||
obj.ItemType = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.State = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ID = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.Flags = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.MenuText = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a MessageResourceBlock
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled MessageResourceBlock on success, null on error</returns>
|
||||
public static MessageResourceBlock ParseMessageResourceBlock(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new MessageResourceBlock();
|
||||
|
||||
obj.LowId = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.HighId = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.OffsetToEntries = data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a NormalMenuHeader
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled NormalMenuHeader on success, null on error</returns>
|
||||
public static NormalMenuHeader ParseNormalMenuHeader(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new NormalMenuHeader();
|
||||
|
||||
obj.Version = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.HeaderSize = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a NormalMenuItem
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled NormalMenuItem on success, null on error</returns>
|
||||
public static NormalMenuItem ParseNormalMenuItem(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new NormalMenuItem();
|
||||
|
||||
obj.NormalResInfo = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.NormalMenuText = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a PopupMenuItem
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled PopupMenuItem on success, null on error</returns>
|
||||
public static PopupMenuItem ParsePopupMenuItem(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new PopupMenuItem();
|
||||
|
||||
obj.PopupItemType = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PopupState = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PopupID = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PopupResInfo = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PopupMenuText = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a ResourceHeader
|
||||
/// </summary>
|
||||
@@ -1346,7 +611,7 @@ namespace SabreTools.Data.Extensions
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <param name="alignment">Number of bytes to align on</param>
|
||||
/// <returns>True if the array could be aligned, false otherwise</returns>
|
||||
private static bool AlignToBoundary(this byte[]? input, ref int offset, byte alignment)
|
||||
internal static bool AlignToBoundary(this byte[]? input, ref int offset, byte alignment)
|
||||
{
|
||||
// If the array is invalid
|
||||
if (input is null || input.Length == 0)
|
||||
|
||||
@@ -475,6 +475,52 @@ namespace SabreTools.Serialization.Readers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into an AcceleratorTable
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>Filled AcceleratorTable on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.AcceleratorTable? ParseAcceleratorTable(byte[] data)
|
||||
{
|
||||
// If we have data that's invalid for this resource type, we can't do anything
|
||||
if (data.Length % 8 != 0)
|
||||
return null;
|
||||
|
||||
// Get the number of entries
|
||||
int count = data.Length / 8;
|
||||
|
||||
// Create the output object
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.AcceleratorTable();
|
||||
obj.Entries = new Data.Models.PortableExecutable.Resource.Entries.AcceleratorTableEntry[count];
|
||||
|
||||
// Read in the table
|
||||
int offset = 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
obj.Entries[i] = ParseAcceleratorTableEntry(data, ref offset);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a AcceleratorTableEntry
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled AcceleratorTableEntry on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.AcceleratorTableEntry ParseAcceleratorTableEntry(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.AcceleratorTableEntry();
|
||||
|
||||
obj.Flags = (AcceleratorTableFlags)data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Ansi = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Id = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Padding = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into an attribute certificate table
|
||||
/// </summary>
|
||||
@@ -740,6 +786,507 @@ namespace SabreTools.Serialization.Readers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a DialogBoxResource
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>A filled DialogBoxResource on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.DialogBoxResource? ParseDialogBoxResource(byte[] data)
|
||||
{
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.DialogBoxResource();
|
||||
|
||||
// Try to read the signature for an extended dialog box template
|
||||
int signatureOffset = sizeof(ushort);
|
||||
int possibleSignature = data.ReadUInt16LittleEndian(ref signatureOffset);
|
||||
if (possibleSignature == 0xFFFF)
|
||||
{
|
||||
obj.ExtendedDialogTemplate = ParseDialogTemplateExtended(data, ref offset);
|
||||
|
||||
var dialogItemExtendedTemplates = new List<Data.Models.PortableExecutable.Resource.Entries.DialogItemTemplateExtended>();
|
||||
for (int i = 0; i < obj.ExtendedDialogTemplate.DialogItems; i++)
|
||||
{
|
||||
var dialogItemTemplate = ParseDialogItemTemplateExtended(data, ref offset);
|
||||
dialogItemExtendedTemplates.Add(dialogItemTemplate);
|
||||
|
||||
// If we have an invalid item count
|
||||
if (offset >= data.Length)
|
||||
break;
|
||||
}
|
||||
|
||||
obj.ExtendedDialogItemTemplates = [.. dialogItemExtendedTemplates];
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.DialogTemplate = ParseDialogTemplate(data, ref offset);
|
||||
|
||||
var dialogItemTemplates = new List<Data.Models.PortableExecutable.Resource.Entries.DialogItemTemplate>();
|
||||
for (int i = 0; i < obj.DialogTemplate.ItemCount; i++)
|
||||
{
|
||||
var dialogItemTemplate = ParseDialogItemTemplate(data, ref offset);
|
||||
dialogItemTemplates.Add(dialogItemTemplate);
|
||||
|
||||
// If we have an invalid item count
|
||||
if (offset >= data.Length)
|
||||
break;
|
||||
}
|
||||
|
||||
obj.DialogItemTemplates = [.. dialogItemTemplates];
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a DialogItemTemplate
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled DialogItemTemplate on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.DialogItemTemplate ParseDialogItemTemplate(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.DialogItemTemplate();
|
||||
|
||||
obj.Style = (WindowStyles)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ExtendedStyle = (ExtendedWindowStyles)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PositionX = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.PositionY = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.WidthX = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.HeightY = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.ID = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
#region Class resource
|
||||
|
||||
int currentOffset = offset;
|
||||
ushort itemClassResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0xFFFF means ordinal only
|
||||
if (itemClassResourceIdentifier == 0xFFFF)
|
||||
{
|
||||
// Increment the pointer
|
||||
_ = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the ordinal
|
||||
obj.ClassResourceOrdinal = (DialogItemTemplateOrdinal)data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool classResourcehasOrdinal = itemClassResourceIdentifier == 0xFFFF;
|
||||
if (classResourcehasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the class resource as a string
|
||||
obj.ClassResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Title resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort itemTitleResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0xFFFF means ordinal only
|
||||
if (itemTitleResourceIdentifier == 0xFFFF)
|
||||
{
|
||||
// Increment the pointer
|
||||
_ = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the ordinal
|
||||
obj.TitleResourceOrdinal = data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the title resource as a string
|
||||
obj.TitleResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Creation data
|
||||
|
||||
obj.CreationDataSize = data.ReadUInt16LittleEndian(ref offset);
|
||||
if (obj.CreationDataSize != 0 && obj.CreationDataSize + offset < data.Length)
|
||||
obj.CreationData = data.ReadBytes(ref offset, obj.CreationDataSize);
|
||||
|
||||
#endregion
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a DialogItemTemplateExtended
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled DialogItemTemplateExtended on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.DialogItemTemplateExtended ParseDialogItemTemplateExtended(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.DialogItemTemplateExtended();
|
||||
|
||||
obj.HelpID = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ExtendedStyle = (ExtendedWindowStyles)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.Style = (WindowStyles)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PositionX = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.PositionY = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.WidthX = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.HeightY = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.ID = data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
#region Class resource
|
||||
|
||||
int currentOffset = offset;
|
||||
ushort itemClassResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0xFFFF means ordinal only
|
||||
if (itemClassResourceIdentifier == 0xFFFF)
|
||||
{
|
||||
// Increment the pointer
|
||||
_ = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the ordinal
|
||||
obj.ClassResourceOrdinal = (DialogItemTemplateOrdinal)data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool classResourcehasOrdinal = itemClassResourceIdentifier == 0xFFFF;
|
||||
if (classResourcehasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the class resource as a string
|
||||
obj.ClassResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Title resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort itemTitleResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0xFFFF means ordinal only
|
||||
if (itemTitleResourceIdentifier == 0xFFFF)
|
||||
{
|
||||
// Increment the pointer
|
||||
_ = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the ordinal
|
||||
obj.TitleResourceOrdinal = data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the title resource as a string
|
||||
obj.TitleResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Creation data
|
||||
|
||||
obj.CreationDataSize = data.ReadUInt16LittleEndian(ref offset);
|
||||
if (obj.CreationDataSize != 0)
|
||||
obj.CreationData = data.ReadBytes(ref offset, obj.CreationDataSize);
|
||||
|
||||
#endregion
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a DialogTemplate
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled DialogTemplate on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.DialogTemplate ParseDialogTemplate(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.DialogTemplate();
|
||||
|
||||
obj.Style = (WindowStyles)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ExtendedStyle = (ExtendedWindowStyles)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ItemCount = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.PositionX = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.PositionY = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.WidthX = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.HeightY = data.ReadInt16LittleEndian(ref offset);
|
||||
|
||||
#region Menu resource
|
||||
|
||||
int currentOffset = offset;
|
||||
ushort menuResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (menuResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool menuResourceHasOrdinal = menuResourceIdentifier == 0xFFFF;
|
||||
if (menuResourceHasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the menu resource as a string
|
||||
obj.MenuResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
|
||||
// Read the ordinal if we have the flag set
|
||||
if (menuResourceHasOrdinal)
|
||||
obj.MenuResourceOrdinal = data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Class resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort classResourceIdentifier;
|
||||
if (offset >= data.Length)
|
||||
classResourceIdentifier = 0x0000;
|
||||
else
|
||||
classResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (classResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool classResourcehasOrdinal = classResourceIdentifier == 0xFFFF;
|
||||
if (classResourcehasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the class resource as a string
|
||||
obj.ClassResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
|
||||
// Read the ordinal if we have the flag set
|
||||
if (classResourcehasOrdinal)
|
||||
obj.ClassResourceOrdinal = data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Title resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort titleResourceIdentifier;
|
||||
if (offset >= data.Length)
|
||||
titleResourceIdentifier = 0x0000;
|
||||
else
|
||||
titleResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (titleResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the title resource as a string
|
||||
obj.TitleResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Point size and typeface
|
||||
|
||||
// Only if DS_SETFONT is set are the values here used
|
||||
#if NET20 || NET35
|
||||
if ((obj.Style & WindowStyles.DS_SETFONT) != 0)
|
||||
#else
|
||||
if (obj.Style.HasFlag(WindowStyles.DS_SETFONT))
|
||||
#endif
|
||||
{
|
||||
obj.PointSizeValue = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
// Read the font name as a string
|
||||
obj.Typeface = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
#endregion
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a DialogTemplateExtended
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled DialogTemplateExtended on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.DialogTemplateExtended ParseDialogTemplateExtended(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.DialogTemplateExtended();
|
||||
|
||||
obj.Version = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Signature = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.HelpID = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ExtendedStyle = (ExtendedWindowStyles)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.Style = (WindowStyles)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.DialogItems = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.PositionX = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.PositionY = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.WidthX = data.ReadInt16LittleEndian(ref offset);
|
||||
obj.HeightY = data.ReadInt16LittleEndian(ref offset);
|
||||
|
||||
#region Menu resource
|
||||
|
||||
int currentOffset = offset;
|
||||
ushort menuResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (menuResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool menuResourceHasOrdinal = menuResourceIdentifier == 0xFFFF;
|
||||
if (menuResourceHasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the menu resource as a string
|
||||
obj.MenuResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
|
||||
// Read the ordinal if we have the flag set
|
||||
if (menuResourceHasOrdinal)
|
||||
obj.MenuResourceOrdinal = data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Class resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort classResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (classResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flag if there's an ordinal at the end
|
||||
bool classResourcehasOrdinal = classResourceIdentifier == 0xFFFF;
|
||||
if (classResourcehasOrdinal)
|
||||
offset += sizeof(ushort);
|
||||
|
||||
// Read the class resource as a string
|
||||
obj.ClassResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
|
||||
// Read the ordinal if we have the flag set
|
||||
if (classResourcehasOrdinal)
|
||||
obj.ClassResourceOrdinal = data.ReadUInt16LittleEndian(ref offset);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Title resource
|
||||
|
||||
currentOffset = offset;
|
||||
ushort titleResourceIdentifier = data.ReadUInt16LittleEndian(ref offset);
|
||||
offset = currentOffset;
|
||||
|
||||
// 0x0000 means no elements
|
||||
if (titleResourceIdentifier == 0x0000)
|
||||
{
|
||||
// Increment the pointer if it was empty
|
||||
offset += sizeof(ushort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the title resource as a string
|
||||
obj.TitleResource = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
// Align to the WORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Point size and typeface
|
||||
|
||||
// Only if DS_SETFONT is set are the values here used
|
||||
#if NET20 || NET35
|
||||
if ((obj.Style & WindowStyles.DS_SETFONT) != 0)
|
||||
#else
|
||||
if (obj.Style.HasFlag(WindowStyles.DS_SETFONT))
|
||||
#endif
|
||||
{
|
||||
obj.PointSize = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Weight = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Italic = data.ReadByte(ref offset);
|
||||
obj.CharSet = data.ReadByte(ref offset);
|
||||
obj.Typeface = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
}
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
#endregion
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a ExportAddressTable
|
||||
/// </summary>
|
||||
@@ -1280,6 +1827,243 @@ namespace SabreTools.Serialization.Readers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a MenuHeaderExtended
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled MenuHeaderExtended on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.MenuHeaderExtended ParseMenuHeaderExtended(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.MenuHeaderExtended();
|
||||
|
||||
obj.Version = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Offset = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.HelpID = data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a MenuItemExtended
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled MenuItemExtended on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.MenuItemExtended ParseMenuItemExtended(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.MenuItemExtended();
|
||||
|
||||
obj.ItemType = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.State = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.ID = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.Flags = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.MenuText = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a MenuResource
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>Filled MenuResource on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.MenuResource? ParseMenuResource(byte[] data)
|
||||
{
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.MenuResource();
|
||||
|
||||
// Try to read the version for an extended header
|
||||
int versionOffset = 0;
|
||||
int possibleVersion = data.ReadUInt16LittleEndian(ref versionOffset);
|
||||
if (possibleVersion == 0x0001)
|
||||
{
|
||||
var menuHeaderExtended = ParseMenuHeaderExtended(data, ref offset);
|
||||
obj.MenuHeader = menuHeaderExtended;
|
||||
|
||||
var extendedMenuItems = new List<Data.Models.PortableExecutable.Resource.Entries.MenuItemExtended>();
|
||||
if (offset != 0)
|
||||
{
|
||||
offset = menuHeaderExtended.Offset;
|
||||
|
||||
while (offset < data.Length)
|
||||
{
|
||||
var extendedMenuItem = ParseMenuItemExtended(data, ref offset);
|
||||
extendedMenuItems.Add(extendedMenuItem);
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
}
|
||||
}
|
||||
|
||||
obj.MenuItems = [.. extendedMenuItems];
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.MenuHeader = ParseNormalMenuHeader(data, ref offset);
|
||||
|
||||
#region Menu items
|
||||
|
||||
var menuItems = new List<Data.Models.PortableExecutable.Resource.Entries.MenuItem>();
|
||||
|
||||
while (offset < data.Length)
|
||||
{
|
||||
// Determine if this is a popup
|
||||
int flagsOffset = offset;
|
||||
var initialFlags = (MenuFlags)data.ReadUInt16LittleEndian(ref flagsOffset);
|
||||
|
||||
Data.Models.PortableExecutable.Resource.Entries.MenuItem? menuItem;
|
||||
#if NET20 || NET35
|
||||
if ((initialFlags & MenuFlags.MF_POPUP) != 0)
|
||||
#else
|
||||
if (initialFlags.HasFlag(MenuFlags.MF_POPUP))
|
||||
#endif
|
||||
menuItem = ParsePopupMenuItem(data, ref offset);
|
||||
else
|
||||
menuItem = ParseNormalMenuItem(data, ref offset);
|
||||
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
if (menuItem is null)
|
||||
return null;
|
||||
|
||||
menuItems.Add(menuItem);
|
||||
}
|
||||
|
||||
obj.MenuItems = [.. menuItems];
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a MessageResourceBlock
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled MessageResourceBlock on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.MessageResourceBlock ParseMessageResourceBlock(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.MessageResourceBlock();
|
||||
|
||||
obj.LowId = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.HighId = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.OffsetToEntries = data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read resource data as a MessageResourceData
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>A filled MessageResourceData on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.MessageResourceData? ParseMessageResourceData(byte[] data)
|
||||
{
|
||||
// Initialize the iterator
|
||||
int offset = 0;
|
||||
|
||||
// Create the output object
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.MessageResourceData();
|
||||
|
||||
// Message resource blocks
|
||||
obj.NumberOfBlocks = data.ReadUInt32LittleEndian(ref offset);
|
||||
if (obj.NumberOfBlocks > 0)
|
||||
{
|
||||
var messageResourceBlocks = new List<Data.Models.PortableExecutable.Resource.Entries.MessageResourceBlock>();
|
||||
|
||||
for (int i = 0; i < obj.NumberOfBlocks; i++)
|
||||
{
|
||||
var messageResourceBlock = ParseMessageResourceBlock(data, ref offset);
|
||||
messageResourceBlocks.Add(messageResourceBlock);
|
||||
}
|
||||
|
||||
obj.Blocks = [.. messageResourceBlocks];
|
||||
}
|
||||
|
||||
// Message resource entries
|
||||
if (obj.Blocks.Length != 0)
|
||||
{
|
||||
var messageResourceEntries = new Dictionary<uint, Data.Models.PortableExecutable.Resource.Entries.MessageResourceEntry?>();
|
||||
|
||||
for (int i = 0; i < obj.Blocks.Length; i++)
|
||||
{
|
||||
var messageResourceBlock = obj.Blocks[i];
|
||||
if (messageResourceBlock is null)
|
||||
continue;
|
||||
|
||||
offset = (int)messageResourceBlock.OffsetToEntries;
|
||||
|
||||
for (uint j = messageResourceBlock.LowId; j <= messageResourceBlock.HighId; j++)
|
||||
{
|
||||
messageResourceEntries[j] = ParseMessageResourceEntry(data, ref offset);
|
||||
}
|
||||
}
|
||||
|
||||
obj.Entries = messageResourceEntries;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a MessageResourceEntry
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled MessageResourceEntry on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.MessageResourceEntry ParseMessageResourceEntry(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.MessageResourceEntry();
|
||||
|
||||
obj.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.Flags = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
Encoding textEncoding = obj.Flags == 0x0001 ? Encoding.Unicode : Encoding.ASCII;
|
||||
byte[] textArray = data.ReadBytes(ref offset, obj.Length - 4);
|
||||
obj.Text = textEncoding.GetString(textArray);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a NormalMenuHeader
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled NormalMenuHeader on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.NormalMenuHeader ParseNormalMenuHeader(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.NormalMenuHeader();
|
||||
|
||||
obj.Version = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.HeaderSize = data.ReadUInt16LittleEndian(ref offset);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a NormalMenuItem
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled NormalMenuItem on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.NormalMenuItem ParseNormalMenuItem(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.NormalMenuItem();
|
||||
|
||||
obj.NormalResInfo = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.NormalMenuText = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an OptionalHeader
|
||||
/// </summary>
|
||||
@@ -1408,6 +2192,25 @@ namespace SabreTools.Serialization.Readers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a PopupMenuItem
|
||||
/// </summary>
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled PopupMenuItem on success, null on error</returns>
|
||||
public static Data.Models.PortableExecutable.Resource.Entries.PopupMenuItem ParsePopupMenuItem(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new Data.Models.PortableExecutable.Resource.Entries.PopupMenuItem();
|
||||
|
||||
obj.PopupItemType = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PopupState = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PopupID = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PopupResInfo = (MenuFlags)data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.PopupMenuText = data.ReadNullTerminatedUnicodeString(ref offset) ?? string.Empty;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a Relocation
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user