diff --git a/SabreTools.Serialization.Test/SabreTools.Serialization.Test.csproj b/SabreTools.Serialization.Test/SabreTools.Serialization.Test.csproj index 6c0798cc..f2175cfb 100644 --- a/SabreTools.Serialization.Test/SabreTools.Serialization.Test.csproj +++ b/SabreTools.Serialization.Test/SabreTools.Serialization.Test.csproj @@ -27,7 +27,7 @@ all - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/SabreTools.Serialization/Extensions.PortableExecutable.cs b/SabreTools.Serialization/Extensions.PortableExecutable.cs index 2c243dfa..3036667a 100644 --- a/SabreTools.Serialization/Extensions.PortableExecutable.cs +++ b/SabreTools.Serialization/Extensions.PortableExecutable.cs @@ -604,7 +604,11 @@ namespace SabreTools.Serialization #region Class resource currentOffset = offset; - ushort classResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort classResourceIdentifier; + if (offset >= entry.Data.Length) + classResourceIdentifier = 0x0000; + else + classResourceIdentifier = entry.Data.ReadUInt16(ref offset); offset = currentOffset; // 0x0000 means no elements @@ -640,7 +644,11 @@ namespace SabreTools.Serialization #region Title resource currentOffset = offset; - ushort titleResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort titleResourceIdentifier; + if (offset >= entry.Data.Length) + titleResourceIdentifier = 0x0000; + else + titleResourceIdentifier = entry.Data.ReadUInt16(ref offset); offset = currentOffset; // 0x0000 means no elements @@ -900,7 +908,7 @@ namespace SabreTools.Serialization if (menuHeaderExtended == null) return null; - menuResource.ExtendedMenuHeader = menuHeaderExtended; + menuResource.MenuHeader = menuHeaderExtended; #endregion @@ -929,7 +937,7 @@ namespace SabreTools.Serialization } } - menuResource.ExtendedMenuItems = [.. extendedMenuItems]; + menuResource.MenuItems = [.. extendedMenuItems]; #endregion } @@ -937,7 +945,7 @@ namespace SabreTools.Serialization { #region Menu header - var menuHeader = entry.Data.ReadType(ref offset); + var menuHeader = entry.Data.ReadType(ref offset); if (menuHeader == null) return null; @@ -1076,21 +1084,9 @@ namespace SabreTools.Serialization // Loop through and add while (offset < entry.Data.Length) { - ushort stringLength = entry.Data.ReadUInt16(ref offset); - if (stringLength == 0) + string? stringValue = entry.Data.ReadPrefixedUnicodeString(ref offset); + if (stringValue != null) { - stringTable[stringIndex++] = "[EMPTY]"; - } - else - { - if (stringLength * 2 > entry.Data.Length - offset) - { - Console.WriteLine($"{stringLength * 2} requested but {entry.Data.Length - offset} remains"); - stringLength = (ushort)((entry.Data.Length - offset) / 2); - } - - string stringValue = Encoding.Unicode.GetString(entry.Data, offset, stringLength * 2); - offset += stringLength * 2; stringValue = stringValue.Replace("\n", "\\n").Replace("\r", newValue: "\\r"); stringTable[stringIndex++] = stringValue; } diff --git a/SabreTools.Serialization/Printers/PortableExecutable.cs b/SabreTools.Serialization/Printers/PortableExecutable.cs index 25145cff..3ea201c6 100644 --- a/SabreTools.Serialization/Printers/PortableExecutable.cs +++ b/SabreTools.Serialization/Printers/PortableExecutable.cs @@ -1120,79 +1120,67 @@ namespace SabreTools.Serialization.Printers if (menu.MenuHeader != null) { - builder.AppendLine(menu.MenuHeader.Version, $"{padding}Version"); - builder.AppendLine(menu.MenuHeader.HeaderSize, $"{padding}Header size"); + if (menu.MenuHeader is NormalMenuHeader normalMenuHeader) + { + builder.AppendLine(normalMenuHeader.Version, $"{padding}Version"); + builder.AppendLine(normalMenuHeader.HeaderSize, $"{padding}Header size"); + } + else if (menu.MenuHeader is MenuHeaderExtended menuHeaderExtended) + { + builder.AppendLine(menuHeaderExtended.Version, $"{padding}Version"); + builder.AppendLine(menuHeaderExtended.Offset, $"{padding}Offset"); + builder.AppendLine(menuHeaderExtended.HelpID, $"{padding}Help ID"); + } + else + { + builder.AppendLine($"{padding}Menu header found, but malformed"); + } builder.AppendLine(); - builder.AppendLine($"{padding}Menu items"); - builder.AppendLine($"{padding}-------------------------"); - if (menu.MenuItems == null || menu.MenuItems.Length == 0) - { - builder.AppendLine($"{padding}No menu items"); - return; - } - - for (int i = 0; i < menu.MenuItems.Length; i++) - { - var menuItem = menu.MenuItems[i]; - builder.AppendLine($"{padding}Menu item {i}"); - if (menuItem == null) - { - builder.AppendLine($"{padding} [NULL]"); - continue; - } - - if (menuItem is NormalMenuItem normalMenuItem) - { - builder.AppendLine($"{padding} Resource info: {normalMenuItem.NormalResInfo} (0x{normalMenuItem.NormalResInfo:X})"); - builder.AppendLine(normalMenuItem.NormalMenuText, $"{padding} Menu text"); - } - else if (menuItem is PopupMenuItem popupMenuItem) - { - builder.AppendLine($"{padding} Item type: {popupMenuItem.PopupItemType} (0x{popupMenuItem.PopupItemType:X})"); - builder.AppendLine($"{padding} State: {popupMenuItem.PopupState} (0x{popupMenuItem.PopupState:X})"); - builder.AppendLine(popupMenuItem.PopupID, $"{padding} ID"); - builder.AppendLine($"{padding} Resource info: {popupMenuItem.PopupResInfo} (0x{popupMenuItem.PopupResInfo:X})"); - builder.AppendLine(popupMenuItem.PopupMenuText, $"{padding} Menu text"); - } - } } - else if (menu.ExtendedMenuHeader != null) + + builder.AppendLine($"{padding}Menu items"); + builder.AppendLine($"{padding}-------------------------"); + if (menu.MenuItems == null || menu.MenuItems.Length == 0) { - builder.AppendLine(menu.ExtendedMenuHeader.Version, $"{padding}Version"); - builder.AppendLine(menu.ExtendedMenuHeader.Offset, $"{padding}Offset"); - builder.AppendLine(menu.ExtendedMenuHeader.HelpID, $"{padding}Help ID"); - builder.AppendLine(); - builder.AppendLine($"{padding}Menu items"); - builder.AppendLine($"{padding}-------------------------"); - if (menu.ExtendedMenuHeader.Offset == 0 - || menu.ExtendedMenuItems == null - || menu.ExtendedMenuItems.Length == 0) - { - builder.AppendLine($"{padding}No menu items"); - return; - } - - for (int i = 0; i < menu.ExtendedMenuItems.Length; i++) - { - var menuItem = menu.ExtendedMenuItems[i]; - - builder.AppendLine($"{padding}Menu item {i}"); - if (menuItem == null) - { - builder.AppendLine($"{padding} [NULL]"); - continue; - } - - builder.AppendLine($"{padding} Item type: {menuItem.ItemType} (0x{menuItem.ItemType:X})"); - builder.AppendLine($"{padding} State: {menuItem.State} (0x{menuItem.State:X})"); - builder.AppendLine(menuItem.ID, $"{padding} ID"); - builder.AppendLine($"{padding} Flags: {menuItem.Flags} (0x{menuItem.Flags:X})"); - builder.AppendLine(menuItem.MenuText, $"{padding} Menu text"); - } + builder.AppendLine($"{padding}No menu items"); + return; } - else + + for (int i = 0; i < menu.MenuItems.Length; i++) { - builder.AppendLine($"{padding}Menu resource found, but malformed"); + var menuItem = menu.MenuItems[i]; + builder.AppendLine($"{padding}Menu item {i}"); + if (menuItem == null) + { + builder.AppendLine($"{padding} [NULL]"); + continue; + } + + if (menuItem is NormalMenuItem normalMenuItem) + { + builder.AppendLine($"{padding} Resource info: {normalMenuItem.NormalResInfo} (0x{normalMenuItem.NormalResInfo:X})"); + builder.AppendLine(normalMenuItem.NormalMenuText, $"{padding} Menu text"); + } + else if (menuItem is PopupMenuItem popupMenuItem) + { + builder.AppendLine($"{padding} Item type: {popupMenuItem.PopupItemType} (0x{popupMenuItem.PopupItemType:X})"); + builder.AppendLine($"{padding} State: {popupMenuItem.PopupState} (0x{popupMenuItem.PopupState:X})"); + builder.AppendLine(popupMenuItem.PopupID, $"{padding} ID"); + builder.AppendLine($"{padding} Resource info: {popupMenuItem.PopupResInfo} (0x{popupMenuItem.PopupResInfo:X})"); + builder.AppendLine(popupMenuItem.PopupMenuText, $"{padding} Menu text"); + } + else if (menuItem is MenuItemExtended menuItemExtended) + { + builder.AppendLine($"{padding} Item type: {menuItemExtended.ItemType} (0x{menuItemExtended.ItemType:X})"); + builder.AppendLine($"{padding} State: {menuItemExtended.State} (0x{menuItemExtended.State:X})"); + builder.AppendLine(menuItemExtended.ID, $"{padding} ID"); + builder.AppendLine($"{padding} Flags: {menuItemExtended.Flags} (0x{menuItemExtended.Flags:X})"); + builder.AppendLine(menuItemExtended.MenuText, $"{padding} Menu text"); + } + else + { + builder.AppendLine($"{padding} Menu item found, but malformed"); + } } } diff --git a/SabreTools.Serialization/SabreTools.Serialization.csproj b/SabreTools.Serialization/SabreTools.Serialization.csproj index 507aa832..a3d14218 100644 --- a/SabreTools.Serialization/SabreTools.Serialization.csproj +++ b/SabreTools.Serialization/SabreTools.Serialization.csproj @@ -31,7 +31,7 @@ - + diff --git a/SabreTools.Serialization/Wrappers/PortableExecutable.cs b/SabreTools.Serialization/Wrappers/PortableExecutable.cs index 955a5b78..fb82a1f3 100644 --- a/SabreTools.Serialization/Wrappers/PortableExecutable.cs +++ b/SabreTools.Serialization/Wrappers/PortableExecutable.cs @@ -1188,68 +1188,68 @@ namespace SabreTools.Serialization.Wrappers { switch ((Models.PortableExecutable.ResourceType)resourceType) { - case SabreTools.Models.PortableExecutable.ResourceType.RT_CURSOR: + case Models.PortableExecutable.ResourceType.RT_CURSOR: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_BITMAP: + case Models.PortableExecutable.ResourceType.RT_BITMAP: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_ICON: + case Models.PortableExecutable.ResourceType.RT_ICON: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_MENU: + case Models.PortableExecutable.ResourceType.RT_MENU: value = entry.AsMenu(); break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_DIALOG: + case Models.PortableExecutable.ResourceType.RT_DIALOG: value = entry.AsDialogBox(); break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_STRING: + case Models.PortableExecutable.ResourceType.RT_STRING: value = entry.AsStringTable(); break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_FONTDIR: + case Models.PortableExecutable.ResourceType.RT_FONTDIR: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_FONT: + case Models.PortableExecutable.ResourceType.RT_FONT: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_ACCELERATOR: + case Models.PortableExecutable.ResourceType.RT_ACCELERATOR: value = entry.AsAcceleratorTableResource(); break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_RCDATA: + case Models.PortableExecutable.ResourceType.RT_RCDATA: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_MESSAGETABLE: + case Models.PortableExecutable.ResourceType.RT_MESSAGETABLE: value = entry.AsMessageResourceData(); break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_GROUP_CURSOR: + case Models.PortableExecutable.ResourceType.RT_GROUP_CURSOR: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_GROUP_ICON: + case Models.PortableExecutable.ResourceType.RT_GROUP_ICON: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_VERSION: + case Models.PortableExecutable.ResourceType.RT_VERSION: _versionInfo = entry.AsVersionInfo(); value = _versionInfo; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_DLGINCLUDE: + case Models.PortableExecutable.ResourceType.RT_DLGINCLUDE: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_PLUGPLAY: + case Models.PortableExecutable.ResourceType.RT_PLUGPLAY: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_VXD: + case Models.PortableExecutable.ResourceType.RT_VXD: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_ANICURSOR: + case Models.PortableExecutable.ResourceType.RT_ANICURSOR: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_ANIICON: + case Models.PortableExecutable.ResourceType.RT_ANIICON: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_HTML: + case Models.PortableExecutable.ResourceType.RT_HTML: value = entry.Data; break; - case SabreTools.Models.PortableExecutable.ResourceType.RT_MANIFEST: + case Models.PortableExecutable.ResourceType.RT_MANIFEST: _assemblyManifest = entry.AsAssemblyManifest(); value = _versionInfo; break; @@ -1335,7 +1335,7 @@ namespace SabreTools.Serialization.Wrappers /// Name of the section to check for /// True to enable exact matching of names, false for starts-with /// Section data on success, null on error - public SabreTools.Models.PortableExecutable.SectionHeader? GetFirstSection(string? name, bool exact = false) + public Models.PortableExecutable.SectionHeader? GetFirstSection(string? name, bool exact = false) { // If we have no sections if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any()) @@ -1360,7 +1360,7 @@ namespace SabreTools.Serialization.Wrappers /// Name of the section to check for /// True to enable exact matching of names, false for starts-with /// Section data on success, null on error - public SabreTools.Models.PortableExecutable.SectionHeader? GetLastSection(string? name, bool exact = false) + public Models.PortableExecutable.SectionHeader? GetLastSection(string? name, bool exact = false) { // If we have no sections if (SectionNames == null || !SectionNames.Any() || this.Model.SectionTable == null || !this.Model.SectionTable.Any()) @@ -1384,7 +1384,7 @@ namespace SabreTools.Serialization.Wrappers /// /// Index of the section to check for /// Section data on success, null on error - public SabreTools.Models.PortableExecutable.SectionHeader? GetSection(int index) + public Models.PortableExecutable.SectionHeader? GetSection(int index) { // If we have no sections if (this.Model.SectionTable == null || !this.Model.SectionTable.Any())