diff --git a/SabreTools.Serialization/Extensions.PortableExecutable.cs b/SabreTools.Serialization/Extensions.PortableExecutable.cs index 696b843..c7ad7a7 100644 --- a/SabreTools.Serialization/Extensions.PortableExecutable.cs +++ b/SabreTools.Serialization/Extensions.PortableExecutable.cs @@ -6,7 +6,6 @@ using SabreTools.IO.Extensions; using SabreTools.Models.PortableExecutable; -// TODO: Finish replacing ReadType namespace SabreTools.Serialization { public static partial class Extensions @@ -95,42 +94,46 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Debug /// - /// Read debug data as an NB10 Program Database + /// Parse a byte array into a NB10ProgramDatabase /// - /// Data to parse into a database + /// Data to parse /// Offset into the byte array - /// A filled NB10 Program Database on success, null on error - public static NB10ProgramDatabase? AsNB10ProgramDatabase(this byte[] data, ref int offset) + /// A filled NB10ProgramDatabase on success, null on error + public static NB10ProgramDatabase? ParseNB10ProgramDatabase(this byte[] data, ref int offset) { - var nb10ProgramDatabase = data.ReadType(ref offset); - if (nb10ProgramDatabase?.Signature != 0x3031424E) + var obj = new NB10ProgramDatabase(); + + obj.Signature = data.ReadUInt32LittleEndian(ref offset); + if (obj.Signature != 0x3031424E) return null; - return nb10ProgramDatabase; + obj.Offset = data.ReadUInt32LittleEndian(ref offset); + obj.Timestamp = data.ReadUInt32LittleEndian(ref offset); + obj.Age = data.ReadUInt32LittleEndian(ref offset); + obj.PdbFileName = data.ReadNullTerminatedAnsiString(ref offset); + + return obj; } /// - /// Read debug data as an RSDS Program Database + /// Parse a byte array into a RSDSProgramDatabase /// - /// Data to parse into a database + /// Data to parse /// Offset into the byte array - /// A filled RSDS Program Database on success, null on error - public static RSDSProgramDatabase? AsRSDSProgramDatabase(this byte[] data, ref int offset) + /// A filled RSDSProgramDatabase on success, null on error + public static RSDSProgramDatabase? ParseRSDSProgramDatabase(this byte[] data, ref int offset) { - var rsdsProgramDatabase = data.ReadType(ref offset); - if (rsdsProgramDatabase?.Signature != 0x53445352) + var obj = new RSDSProgramDatabase(); + + obj.Signature = data.ReadUInt32LittleEndian(ref offset); + if (obj.Signature != 0x53445352) return null; -#if NET20 || NET35 || NET40 || NET452 || NET462 - // Convert ASCII string to UTF-8 - if (rsdsProgramDatabase.PathAndFileName != null) - { - byte[] bytes = Encoding.ASCII.GetBytes(rsdsProgramDatabase.PathAndFileName); - rsdsProgramDatabase.PathAndFileName = Encoding.UTF8.GetString(bytes); - } -#endif + obj.GUID = data.ReadGuid(ref offset); + obj.Age = data.ReadUInt32LittleEndian(ref offset); + obj.PathAndFileName = data.ReadNullTerminatedUTF8String(ref offset); - return rsdsProgramDatabase; + return obj; } #endregion @@ -138,88 +141,80 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Overlay /// - /// Read overlay data as a SecuROM AddD overlay data + /// Parse a byte array into a SecuROMAddD /// /// Data to parse into overlay data /// Offset into the byte array - /// A filled SecuROM AddD overlay data on success, null on error - public static SecuROMAddD? AsSecuROMAddD(this byte[] data, ref int offset) + /// A filled SecuROMAddD on success, null on error + public static SecuROMAddD? ParseSecuROMAddD(this byte[] data, ref int offset) { // Read in the table - var addD = new SecuROMAddD(); + var obj = new SecuROMAddD(); - addD.Signature = data.ReadUInt32(ref offset); - if (addD.Signature != 0x44646441) + obj.Signature = data.ReadUInt32LittleEndian(ref offset); + if (obj.Signature != 0x44646441) return null; int originalOffset = offset; - addD.EntryCount = data.ReadUInt32(ref offset); - addD.Version = data.ReadNullTerminatedAnsiString(ref offset); - if (string.IsNullOrEmpty(addD.Version)) + obj.EntryCount = data.ReadUInt32LittleEndian(ref offset); + obj.Version = data.ReadNullTerminatedAnsiString(ref offset); + if (string.IsNullOrEmpty(obj.Version)) offset = originalOffset + 0x10; var buildBytes = data.ReadBytes(ref offset, 4); var buildChars = Array.ConvertAll(buildBytes, b => (char)b); - addD.Build = buildChars; + obj.Build = buildChars; // Distinguish between v1 and v2 int bytesToRead = 112; // v2 - if (string.IsNullOrEmpty(addD.Version) - || addD.Version!.StartsWith("3") - || addD.Version.StartsWith("4.47")) + if (string.IsNullOrEmpty(obj.Version) + || obj.Version!.StartsWith("3") + || obj.Version.StartsWith("4.47")) { bytesToRead = 44; } - addD.Unknown14h = data.ReadBytes(ref offset, bytesToRead); + obj.Unknown14h = data.ReadBytes(ref offset, bytesToRead); - addD.Entries = new SecuROMAddDEntry[addD.EntryCount]; - for (int i = 0; i < addD.EntryCount; i++) + obj.Entries = new SecuROMAddDEntry[obj.EntryCount]; + for (int i = 0; i < obj.EntryCount; i++) { - var addDEntry = data.ReadType(ref offset); - if (addDEntry == null) - return null; - - addD.Entries[i] = addDEntry; + obj.Entries[i] = ParseSecuROMAddDEntry(data, ref offset); } - return addD; + return obj; } - #endregion - - // TODO: Implement other resource types from https://learn.microsoft.com/en-us/windows/win32/menurc/resource-file-formats - #region Resources - /// - /// Read resource data as a resource header + /// Parse a byte array into a SecuROMAddDEntry /// - /// Data to parse into a resource header + /// Data to parse /// Offset into the byte array - /// A filled resource header on success, null on error - public static ResourceHeader? AsResourceHeader(this byte[] data, ref int offset) + /// Filled SecuROMAddDEntry on success, null on error + public static SecuROMAddDEntry ParseSecuROMAddDEntry(this byte[] data, ref int offset) { - // If we have data that's invalid, we can't do anything - if (data == null) - return null; - - // Read in the table - var header = new ResourceHeader(); - - header.DataSize = data.ReadUInt32(ref offset); - header.HeaderSize = data.ReadUInt32(ref offset); - header.ResourceType = (ResourceType)data.ReadUInt32(ref offset); // TODO: Could be a string too - header.Name = data.ReadUInt32(ref offset); // TODO: Could be a string too - header.DataVersion = data.ReadUInt32(ref offset); - header.MemoryFlags = (MemoryFlags)data.ReadUInt16(ref offset); - header.LanguageId = data.ReadUInt16(ref offset); - header.Version = data.ReadUInt32(ref offset); - header.Characteristics = data.ReadUInt32(ref offset); - - return header; + var obj = new SecuROMAddDEntry(); + + obj.PhysicalOffset = data.ReadUInt32LittleEndian(ref offset); + obj.Length = data.ReadUInt32LittleEndian(ref offset); + obj.Unknown08h = data.ReadUInt32LittleEndian(ref offset); + obj.Unknown0Ch = data.ReadUInt32LittleEndian(ref offset); + obj.Unknown10h = data.ReadUInt32LittleEndian(ref offset); + obj.Unknown14h = data.ReadUInt32LittleEndian(ref offset); + obj.Unknown18h = data.ReadUInt32LittleEndian(ref offset); + obj.Unknown1Ch = data.ReadUInt32LittleEndian(ref offset); + obj.FileName = data.ReadNullTerminatedAnsiString(ref offset); + obj.Unknown2Ch = data.ReadUInt32LittleEndian(ref offset); + + return obj; } + #endregion + + // TODO: Implement other resource types from https://learn.microsoft.com/en-us/windows/win32/menurc/resource-file-formats + #region Resources + /// /// Read resource data as an accelerator table resource /// @@ -243,11 +238,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Read in the table for (int i = 0; i < count; i++) { - var acceleratorTableEntry = entry.Data.ReadType(ref offset); - if (acceleratorTableEntry == null) - return null; - - table[i] = acceleratorTableEntry; + table[i] = ParseAcceleratorTableEntry(entry.Data, ref offset); } return table; @@ -294,19 +285,19 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Try to read the signature for an extended dialog box template int signatureOffset = sizeof(ushort); - int possibleSignature = entry.Data.ReadUInt16(ref signatureOffset); + int possibleSignature = entry.Data.ReadUInt16LittleEndian(ref signatureOffset); if (possibleSignature == 0xFFFF) { #region Extended dialog template var dialogTemplateExtended = new DialogTemplateExtended(); - dialogTemplateExtended.Version = entry.Data.ReadUInt16(ref offset); - dialogTemplateExtended.Signature = entry.Data.ReadUInt16(ref offset); - dialogTemplateExtended.HelpID = entry.Data.ReadUInt32(ref offset); - dialogTemplateExtended.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset); - dialogTemplateExtended.Style = (WindowStyles)entry.Data.ReadUInt32(ref offset); - dialogTemplateExtended.DialogItems = entry.Data.ReadUInt16(ref offset); + 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.ReadInt16(ref offset); dialogTemplateExtended.PositionY = entry.Data.ReadInt16(ref offset); dialogTemplateExtended.WidthX = entry.Data.ReadInt16(ref offset); @@ -315,7 +306,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Menu resource int currentOffset = offset; - ushort menuResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort menuResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0x0000 means no elements @@ -343,7 +334,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Read the ordinal if we have the flag set if (menuResourceHasOrdinal) - dialogTemplateExtended.MenuResourceOrdinal = entry.Data.ReadUInt16(ref offset); + dialogTemplateExtended.MenuResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset); } #endregion @@ -351,7 +342,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Class resource currentOffset = offset; - ushort classResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort classResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0x0000 means no elements @@ -379,7 +370,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Read the ordinal if we have the flag set if (classResourcehasOrdinal) - dialogTemplateExtended.ClassResourceOrdinal = entry.Data.ReadUInt16(ref offset); + dialogTemplateExtended.ClassResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset); } #endregion @@ -387,7 +378,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Title resource currentOffset = offset; - ushort titleResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort titleResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0x0000 means no elements @@ -420,8 +411,8 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section if (dialogTemplateExtended.Style.HasFlag(WindowStyles.DS_SETFONT)) #endif { - dialogTemplateExtended.PointSize = entry.Data.ReadUInt16(ref offset); - dialogTemplateExtended.Weight = entry.Data.ReadUInt16(ref offset); + 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); @@ -448,29 +439,29 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section { var dialogItemTemplate = new DialogItemTemplateExtended(); - dialogItemTemplate.HelpID = entry.Data.ReadUInt32(ref offset); - dialogItemTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset); - dialogItemTemplate.Style = (WindowStyles)entry.Data.ReadUInt32(ref offset); + 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.ReadInt16(ref offset); dialogItemTemplate.PositionY = entry.Data.ReadInt16(ref offset); dialogItemTemplate.WidthX = entry.Data.ReadInt16(ref offset); dialogItemTemplate.HeightY = entry.Data.ReadInt16(ref offset); - dialogItemTemplate.ID = entry.Data.ReadUInt32(ref offset); + dialogItemTemplate.ID = entry.Data.ReadUInt32LittleEndian(ref offset); #region Class resource currentOffset = offset; - ushort itemClassResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort itemClassResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0xFFFF means ordinal only if (itemClassResourceIdentifier == 0xFFFF) { // Increment the pointer - _ = entry.Data.ReadUInt16(ref offset); + _ = entry.Data.ReadUInt16LittleEndian(ref offset); // Read the ordinal - dialogItemTemplate.ClassResourceOrdinal = (DialogItemTemplateOrdinal)entry.Data.ReadUInt16(ref offset); + dialogItemTemplate.ClassResourceOrdinal = (DialogItemTemplateOrdinal)entry.Data.ReadUInt16LittleEndian(ref offset); } else { @@ -495,17 +486,17 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Title resource currentOffset = offset; - ushort itemTitleResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort itemTitleResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0xFFFF means ordinal only if (itemTitleResourceIdentifier == 0xFFFF) { // Increment the pointer - _ = entry.Data.ReadUInt16(ref offset); + _ = entry.Data.ReadUInt16LittleEndian(ref offset); // Read the ordinal - dialogItemTemplate.TitleResourceOrdinal = entry.Data.ReadUInt16(ref offset); + dialogItemTemplate.TitleResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset); } else { @@ -524,7 +515,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Creation data - dialogItemTemplate.CreationDataSize = entry.Data.ReadUInt16(ref offset); + dialogItemTemplate.CreationDataSize = entry.Data.ReadUInt16LittleEndian(ref offset); if (dialogItemTemplate.CreationDataSize != 0) dialogItemTemplate.CreationData = entry.Data.ReadBytes(ref offset, dialogItemTemplate.CreationDataSize); @@ -554,9 +545,9 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section var dialogTemplate = new DialogTemplate(); - dialogTemplate.Style = (WindowStyles)entry.Data.ReadUInt32(ref offset); - dialogTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset); - dialogTemplate.ItemCount = entry.Data.ReadUInt16(ref offset); + 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.ReadInt16(ref offset); dialogTemplate.PositionY = entry.Data.ReadInt16(ref offset); dialogTemplate.WidthX = entry.Data.ReadInt16(ref offset); @@ -565,7 +556,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Menu resource int currentOffset = offset; - ushort menuResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort menuResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0x0000 means no elements @@ -593,7 +584,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Read the ordinal if we have the flag set if (menuResourceHasOrdinal) - dialogTemplate.MenuResourceOrdinal = entry.Data.ReadUInt16(ref offset); + dialogTemplate.MenuResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset); } #endregion @@ -605,7 +596,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section if (offset >= entry.Data.Length) classResourceIdentifier = 0x0000; else - classResourceIdentifier = entry.Data.ReadUInt16(ref offset); + classResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0x0000 means no elements @@ -633,7 +624,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Read the ordinal if we have the flag set if (classResourcehasOrdinal) - dialogTemplate.ClassResourceOrdinal = entry.Data.ReadUInt16(ref offset); + dialogTemplate.ClassResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset); } #endregion @@ -645,7 +636,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section if (offset >= entry.Data.Length) titleResourceIdentifier = 0x0000; else - titleResourceIdentifier = entry.Data.ReadUInt16(ref offset); + titleResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0x0000 means no elements @@ -678,7 +669,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section if (dialogTemplate.Style.HasFlag(WindowStyles.DS_SETFONT)) #endif { - dialogTemplate.PointSizeValue = entry.Data.ReadUInt16(ref offset); + dialogTemplate.PointSizeValue = entry.Data.ReadUInt16LittleEndian(ref offset); // Read the font name as a string dialogTemplate.Typeface = entry.Data.ReadNullTerminatedUnicodeString(ref offset); @@ -705,28 +696,28 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section { var dialogItemTemplate = new DialogItemTemplate(); - dialogItemTemplate.Style = (WindowStyles)entry.Data.ReadUInt32(ref offset); - dialogItemTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset); + dialogItemTemplate.Style = (WindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset); + dialogItemTemplate.ExtendedStyle = (ExtendedWindowStyles)entry.Data.ReadUInt32LittleEndian(ref offset); dialogItemTemplate.PositionX = entry.Data.ReadInt16(ref offset); dialogItemTemplate.PositionY = entry.Data.ReadInt16(ref offset); dialogItemTemplate.WidthX = entry.Data.ReadInt16(ref offset); dialogItemTemplate.HeightY = entry.Data.ReadInt16(ref offset); - dialogItemTemplate.ID = entry.Data.ReadUInt16(ref offset); + dialogItemTemplate.ID = entry.Data.ReadUInt16LittleEndian(ref offset); #region Class resource currentOffset = offset; - ushort itemClassResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort itemClassResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0xFFFF means ordinal only if (itemClassResourceIdentifier == 0xFFFF) { // Increment the pointer - _ = entry.Data.ReadUInt16(ref offset); + _ = entry.Data.ReadUInt16LittleEndian(ref offset); // Read the ordinal - dialogItemTemplate.ClassResourceOrdinal = (DialogItemTemplateOrdinal)entry.Data.ReadUInt16(ref offset); + dialogItemTemplate.ClassResourceOrdinal = (DialogItemTemplateOrdinal)entry.Data.ReadUInt16LittleEndian(ref offset); } else { @@ -751,17 +742,17 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Title resource currentOffset = offset; - ushort itemTitleResourceIdentifier = entry.Data.ReadUInt16(ref offset); + ushort itemTitleResourceIdentifier = entry.Data.ReadUInt16LittleEndian(ref offset); offset = currentOffset; // 0xFFFF means ordinal only if (itemTitleResourceIdentifier == 0xFFFF) { // Increment the pointer - _ = entry.Data.ReadUInt16(ref offset); + _ = entry.Data.ReadUInt16LittleEndian(ref offset); // Read the ordinal - dialogItemTemplate.TitleResourceOrdinal = entry.Data.ReadUInt16(ref offset); + dialogItemTemplate.TitleResourceOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset); } else { @@ -780,7 +771,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #region Creation data - dialogItemTemplate.CreationDataSize = entry.Data.ReadUInt16(ref offset); + dialogItemTemplate.CreationDataSize = entry.Data.ReadUInt16LittleEndian(ref offset); if (dialogItemTemplate.CreationDataSize != 0) dialogItemTemplate.CreationData = entry.Data.ReadBytes(ref offset, dialogItemTemplate.CreationDataSize); @@ -825,7 +816,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Create the output object var fontGroupHeader = new FontGroupHeader(); - fontGroupHeader.NumberOfFonts = entry.Data.ReadUInt16(ref offset); + fontGroupHeader.NumberOfFonts = entry.Data.ReadUInt16LittleEndian(ref offset); if (fontGroupHeader.NumberOfFonts > 0) { fontGroupHeader.DE = new DirEntry[fontGroupHeader.NumberOfFonts]; @@ -833,37 +824,37 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section { var dirEntry = new DirEntry(); - dirEntry.FontOrdinal = entry.Data.ReadUInt16(ref offset); + dirEntry.FontOrdinal = entry.Data.ReadUInt16LittleEndian(ref offset); dirEntry.Entry = new FontDirEntry(); - dirEntry.Entry.Version = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.Size = entry.Data.ReadUInt32(ref offset); + dirEntry.Entry.Version = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.Size = entry.Data.ReadUInt32LittleEndian(ref offset); dirEntry.Entry.Copyright = entry.Data.ReadBytes(ref offset, 60); - dirEntry.Entry.Type = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.Points = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.VertRes = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.HorizRes = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.Ascent = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.InternalLeading = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.ExternalLeading = entry.Data.ReadUInt16(ref offset); + dirEntry.Entry.Type = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.Points = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.VertRes = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.HorizRes = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.Ascent = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.InternalLeading = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.ExternalLeading = entry.Data.ReadUInt16LittleEndian(ref offset); dirEntry.Entry.Italic = entry.Data.ReadByte(ref offset); dirEntry.Entry.Underline = entry.Data.ReadByte(ref offset); dirEntry.Entry.StrikeOut = entry.Data.ReadByte(ref offset); - dirEntry.Entry.Weight = entry.Data.ReadUInt16(ref offset); + dirEntry.Entry.Weight = entry.Data.ReadUInt16LittleEndian(ref offset); dirEntry.Entry.CharSet = entry.Data.ReadByte(ref offset); - dirEntry.Entry.PixWidth = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.PixHeight = entry.Data.ReadUInt16(ref offset); + dirEntry.Entry.PixWidth = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.PixHeight = entry.Data.ReadUInt16LittleEndian(ref offset); dirEntry.Entry.PitchAndFamily = entry.Data.ReadByte(ref offset); - dirEntry.Entry.AvgWidth = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.MaxWidth = entry.Data.ReadUInt16(ref offset); + dirEntry.Entry.AvgWidth = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.MaxWidth = entry.Data.ReadUInt16LittleEndian(ref offset); dirEntry.Entry.FirstChar = entry.Data.ReadByte(ref offset); dirEntry.Entry.LastChar = entry.Data.ReadByte(ref offset); dirEntry.Entry.DefaultChar = entry.Data.ReadByte(ref offset); dirEntry.Entry.BreakChar = entry.Data.ReadByte(ref offset); - dirEntry.Entry.WidthBytes = entry.Data.ReadUInt16(ref offset); - dirEntry.Entry.Device = entry.Data.ReadUInt32(ref offset); - dirEntry.Entry.Face = entry.Data.ReadUInt32(ref offset); - dirEntry.Entry.Reserved = entry.Data.ReadUInt32(ref offset); + dirEntry.Entry.WidthBytes = entry.Data.ReadUInt16LittleEndian(ref offset); + dirEntry.Entry.Device = entry.Data.ReadUInt32LittleEndian(ref offset); + dirEntry.Entry.Face = entry.Data.ReadUInt32LittleEndian(ref offset); + dirEntry.Entry.Reserved = entry.Data.ReadUInt32LittleEndian(ref offset); // TODO: Determine how to read these two? Immediately after? dirEntry.Entry.DeviceName = entry.Data.ReadNullTerminatedAnsiString(ref offset); @@ -896,15 +887,12 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Try to read the version for an extended header int versionOffset = 0; - int possibleVersion = entry.Data.ReadUInt16(ref versionOffset); + int possibleVersion = entry.Data.ReadUInt16LittleEndian(ref versionOffset); if (possibleVersion == 0x0001) { #region Extended menu header - var menuHeaderExtended = entry.Data.ReadType(ref offset); - if (menuHeaderExtended == null) - return null; - + var menuHeaderExtended = ParseMenuHeaderExtended(entry.Data, ref offset); menuResource.MenuHeader = menuHeaderExtended; #endregion @@ -919,9 +907,8 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section while (offset < entry.Data.Length) { - var extendedMenuItem = entry.Data.ReadType(ref offset); - if (extendedMenuItem == null) - return null; + var extendedMenuItem = ParseMenuItemExtended(entry.Data, ref offset); + extendedMenuItems.Add(extendedMenuItem); // Align to the DWORD boundary if we're not at the end if (offset < entry.Data.Length) @@ -929,8 +916,6 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section while (offset < entry.Data.Length && (offset % 4) != 0) _ = entry.Data.ReadByte(ref offset); } - - extendedMenuItems.Add(extendedMenuItem); } } @@ -942,11 +927,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section { #region Menu header - var menuHeader = entry.Data.ReadType(ref offset); - if (menuHeader == null) - return null; - - menuResource.MenuHeader = menuHeader; + menuResource.MenuHeader = ParseNormalMenuHeader(entry.Data, ref offset); #endregion @@ -958,7 +939,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section { // Determine if this is a popup int flagsOffset = offset; - var initialFlags = (MenuFlags)entry.Data.ReadUInt16(ref flagsOffset); + var initialFlags = (MenuFlags)entry.Data.ReadUInt16LittleEndian(ref flagsOffset); MenuItem? menuItem; #if NET20 || NET35 @@ -966,9 +947,9 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section #else if (initialFlags.HasFlag(MenuFlags.MF_POPUP)) #endif - menuItem = entry.Data.ReadType(ref offset); + menuItem = ParsePopupMenuItem(entry.Data, ref offset); else - menuItem = entry.Data.ReadType(ref offset); + menuItem = ParseNormalMenuItem(entry.Data, ref offset); // Align to the DWORD boundary if we're not at the end if (offset < entry.Data.Length) @@ -1009,17 +990,14 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section var messageResourceData = new MessageResourceData(); // Message resource blocks - messageResourceData.NumberOfBlocks = entry.Data.ReadUInt32(ref offset); + messageResourceData.NumberOfBlocks = entry.Data.ReadUInt32LittleEndian(ref offset); if (messageResourceData.NumberOfBlocks > 0) { var messageResourceBlocks = new List(); for (int i = 0; i < messageResourceData.NumberOfBlocks; i++) { - var messageResourceBlock = entry.Data.ReadType(ref offset); - if (messageResourceBlock == null) - return null; - + var messageResourceBlock = ParseMessageResourceBlock(entry.Data, ref offset); messageResourceBlocks.Add(messageResourceBlock); } @@ -1043,8 +1021,8 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section { var messageResourceEntry = new MessageResourceEntry(); - messageResourceEntry.Length = entry.Data.ReadUInt16(ref offset); - messageResourceEntry.Flags = entry.Data.ReadUInt16(ref offset); + 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); @@ -1061,126 +1039,6 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section return messageResourceData; } - /// - /// Read resource data as a string table resource - /// - /// Resource data entry to parse into a string table resource - /// A filled string table resource on success, null on error - public static Dictionary? AsStringTable(this ResourceDataEntry? entry) - { - // If we have an invalid entry, just skip - if (entry?.Data == null) - return null; - - // Initialize the iterators - int offset = 0, stringIndex = 0; - - // Create the output table - var stringTable = new Dictionary(); - - // Loop through and add - while (offset < entry.Data.Length) - { - string? stringValue = entry.Data.ReadPrefixedUnicodeString(ref offset); - if (stringValue != null) - { - stringValue = stringValue.Replace("\n", "\\n").Replace("\r", newValue: "\\r"); - stringTable[stringIndex++] = stringValue; - } - } - - return stringTable; - } - - /// - /// Read resource data as a version info resource - /// - /// Resource data entry to parse into a version info resource - /// A filled version info resource on success, null on error - public static VersionInfo? AsVersionInfo(this ResourceDataEntry? entry) - { - // If we have an invalid entry, just skip - if (entry?.Data == null) - return null; - - // Initialize the iterator - int offset = 0; - - // Create the output object - var versionInfo = new VersionInfo(); - - versionInfo.Length = entry.Data.ReadUInt16(ref offset); - versionInfo.ValueLength = entry.Data.ReadUInt16(ref offset); - versionInfo.ResourceType = (VersionResourceType)entry.Data.ReadUInt16(ref offset); - versionInfo.Key = entry.Data.ReadNullTerminatedUnicodeString(ref offset); - if (versionInfo.Key != "VS_VERSION_INFO") - return null; - - while (offset < entry.Data.Length && (offset % 4) != 0) - versionInfo.Padding1 = entry.Data.ReadUInt16(ref offset); - - // Read fixed file info - if (versionInfo.ValueLength > 0 && offset + versionInfo.ValueLength <= entry.Data.Length) - { - var fixedFileInfo = entry.Data.ReadType(ref offset); - if (fixedFileInfo?.Signature != 0xFEEF04BD) - return null; - - versionInfo.Value = fixedFileInfo; - } - - while (offset < entry.Data.Length && (offset % 4) != 0) - versionInfo.Padding2 = entry.Data.ReadUInt16(ref offset); - - // TODO: Make the following block a private helper method - - // Determine if we have a StringFileInfo or VarFileInfo next - if (offset < versionInfo.Length) - { - // Cache the current offset for reading - int currentOffset = offset; - - offset += 6; - string? nextKey = entry.Data.ReadNullTerminatedUnicodeString(ref offset); - offset = currentOffset; - - if (nextKey == "StringFileInfo") - { - var stringFileInfo = AsStringFileInfo(entry.Data, ref offset); - versionInfo.StringFileInfo = stringFileInfo; - } - else if (nextKey == "VarFileInfo") - { - var varFileInfo = AsVarFileInfo(entry.Data, ref offset); - versionInfo.VarFileInfo = varFileInfo; - } - } - - // And again - if (offset < versionInfo.Length) - { - // Cache the current offset for reading - int currentOffset = offset; - - offset += 6; - string? nextKey = entry.Data.ReadNullTerminatedUnicodeString(ref offset); - offset = currentOffset; - - if (nextKey == "StringFileInfo") - { - var stringFileInfo = AsStringFileInfo(entry.Data, ref offset); - versionInfo.StringFileInfo = stringFileInfo; - } - else if (nextKey == "VarFileInfo") - { - var varFileInfo = AsVarFileInfo(entry.Data, ref offset); - versionInfo.VarFileInfo = varFileInfo; - } - } - - return versionInfo; - } - /// /// Read byte data as a string file info resource /// @@ -1194,9 +1052,9 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Cache the initial offset int currentOffset = offset; - stringFileInfo.Length = data.ReadUInt16(ref offset); - stringFileInfo.ValueLength = data.ReadUInt16(ref offset); - stringFileInfo.ResourceType = (VersionResourceType)data.ReadUInt16(ref 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); if (stringFileInfo.Key != "StringFileInfo") { @@ -1216,9 +1074,9 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section { var stringTable = new StringTable(); - stringTable.Length = data.ReadUInt16(ref offset); - stringTable.ValueLength = data.ReadUInt16(ref offset); - stringTable.ResourceType = (VersionResourceType)data.ReadUInt16(ref offset); + 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); // Align to the DWORD boundary if we're not at the end @@ -1234,9 +1092,9 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section var stringData = new StringData(); int dataStartOffset = offset; - stringData.Length = data.ReadUInt16(ref offset); - stringData.ValueLength = data.ReadUInt16(ref offset); - stringData.ResourceType = (VersionResourceType)data.ReadUInt16(ref 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); // Align to the DWORD boundary if we're not at the end @@ -1275,6 +1133,37 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section return stringFileInfo; } + /// + /// Read resource data as a string table resource + /// + /// Resource data entry to parse into a string table resource + /// A filled string table resource on success, null on error + public static Dictionary? AsStringTable(this ResourceDataEntry? entry) + { + // If we have an invalid entry, just skip + if (entry?.Data == null) + return null; + + // Initialize the iterators + int offset = 0, stringIndex = 0; + + // Create the output table + var stringTable = new Dictionary(); + + // Loop through and add + while (offset < entry.Data.Length) + { + string? stringValue = entry.Data.ReadPrefixedUnicodeString(ref offset); + if (stringValue != null) + { + stringValue = stringValue.Replace("\n", "\\n").Replace("\r", newValue: "\\r"); + stringTable[stringIndex++] = stringValue; + } + } + + return stringTable; + } + /// /// Read byte data as a var file info resource /// @@ -1288,9 +1177,9 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section // Cache the initial offset int initialOffset = offset; - varFileInfo.Length = data.ReadUInt16(ref offset); - varFileInfo.ValueLength = data.ReadUInt16(ref offset); - varFileInfo.ResourceType = (VersionResourceType)data.ReadUInt16(ref 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); if (varFileInfo.Key != "VarFileInfo") return null; @@ -1307,9 +1196,9 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section { var varData = new VarData(); - varData.Length = data.ReadUInt16(ref offset); - varData.ValueLength = data.ReadUInt16(ref offset); - varData.ResourceType = (VersionResourceType)data.ReadUInt16(ref offset); + 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); if (varData.Key != "Translation") { @@ -1330,7 +1219,7 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section var varDataValue = new List(); while ((offset - currentOffset) < varData.ValueLength) { - uint languageAndCodeIdentifierPair = data.ReadUInt32(ref offset); + uint languageAndCodeIdentifierPair = data.ReadUInt32LittleEndian(ref offset); varDataValue.Add(languageAndCodeIdentifierPair); } @@ -1344,6 +1233,268 @@ public static int ContainingSectionIndex(this uint rva, SectionHeader[]? section return varFileInfo; } + /// + /// Read resource data as a version info resource + /// + /// Resource data entry to parse into a version info resource + /// A filled version info resource on success, null on error + public static VersionInfo? AsVersionInfo(this ResourceDataEntry? entry) + { + // If we have an invalid entry, just skip + if (entry?.Data == 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); + 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); + + // TODO: Make the following block a private helper method + + // Determine if we have a StringFileInfo or VarFileInfo next + if (offset < versionInfo.Length) + { + // Cache the current offset for reading + int currentOffset = offset; + + offset += 6; + string? nextKey = entry.Data.ReadNullTerminatedUnicodeString(ref offset); + offset = currentOffset; + + if (nextKey == "StringFileInfo") + { + var stringFileInfo = AsStringFileInfo(entry.Data, ref offset); + versionInfo.StringFileInfo = stringFileInfo; + } + else if (nextKey == "VarFileInfo") + { + var varFileInfo = AsVarFileInfo(entry.Data, ref offset); + versionInfo.VarFileInfo = varFileInfo; + } + } + + // And again + if (offset < versionInfo.Length) + { + // Cache the current offset for reading + int currentOffset = offset; + + offset += 6; + string? nextKey = entry.Data.ReadNullTerminatedUnicodeString(ref offset); + offset = currentOffset; + + if (nextKey == "StringFileInfo") + { + var stringFileInfo = AsStringFileInfo(entry.Data, ref offset); + versionInfo.StringFileInfo = stringFileInfo; + } + else if (nextKey == "VarFileInfo") + { + var varFileInfo = AsVarFileInfo(entry.Data, ref offset); + versionInfo.VarFileInfo = varFileInfo; + } + } + + return versionInfo; + } + + /// + /// Parse a byte array into a AcceleratorTableEntry + /// + /// Data to parse + /// Offset into the byte array + /// A filled AcceleratorTableEntry on success, null on error + 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; + } + + /// + /// Parse a byte array into a FixedFileInfo + /// + /// Data to parse + /// Offset into the byte array + /// A filled FixedFileInfo on success, null on error + 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; + } + + /// + /// Parse a byte array into a MenuHeaderExtended + /// + /// Data to parse + /// Offset into the byte array + /// A filled MenuHeaderExtended on success, null on error + 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; + } + + /// + /// Parse a byte array into a MenuItemExtended + /// + /// Data to parse + /// Offset into the byte array + /// A filled MenuItemExtended on success, null on error + 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); + + return obj; + } + + /// + /// Parse a byte array into a MessageResourceBlock + /// + /// Data to parse + /// Offset into the byte array + /// A filled MessageResourceBlock on success, null on error + 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; + } + + /// + /// Parse a byte array into a NormalMenuHeader + /// + /// Data to parse + /// Offset into the byte array + /// A filled NormalMenuHeader on success, null on error + 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; + } + + /// + /// Parse a byte array into a NormalMenuItem + /// + /// Data to parse + /// Offset into the byte array + /// A filled NormalMenuItem on success, null on error + 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); + + return obj; + } + + /// + /// Parse a byte array into a PopupMenuItem + /// + /// Data to parse + /// Offset into the byte array + /// A filled PopupMenuItem on success, null on error + 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); + + return obj; + } + + /// + /// Parse a byte array into a ResourceHeader + /// + /// Data to parse + /// Offset into the byte array + /// A filled ResourceHeader on success, null on error + public static ResourceHeader ParseResourceHeader(this byte[] data, ref int offset) + { + // Read in the table + var obj = new ResourceHeader(); + + obj.DataSize = data.ReadUInt32LittleEndian(ref offset); + obj.HeaderSize = data.ReadUInt32LittleEndian(ref offset); + obj.ResourceType = (ResourceType)data.ReadUInt32LittleEndian(ref offset); // TODO: Could be a string too + obj.Name = data.ReadUInt32LittleEndian(ref offset); // TODO: Could be a string too + obj.DataVersion = data.ReadUInt32LittleEndian(ref offset); + obj.MemoryFlags = (MemoryFlags)data.ReadUInt16LittleEndian(ref offset); + obj.LanguageId = data.ReadUInt16LittleEndian(ref offset); + obj.Version = data.ReadUInt32LittleEndian(ref offset); + obj.Characteristics = data.ReadUInt32LittleEndian(ref offset); + + return obj; + } + #endregion } } \ No newline at end of file diff --git a/SabreTools.Serialization/Wrappers/PortableExecutable.cs b/SabreTools.Serialization/Wrappers/PortableExecutable.cs index aa4597a..534d5d0 100644 --- a/SabreTools.Serialization/Wrappers/PortableExecutable.cs +++ b/SabreTools.Serialization/Wrappers/PortableExecutable.cs @@ -1036,7 +1036,7 @@ private void ParseDebugTable() // NB10 if (signature == 0x3031424E) { - var nb10ProgramDatabase = entryData.AsNB10ProgramDatabase(ref offset); + var nb10ProgramDatabase = entryData.ParseNB10ProgramDatabase(ref offset); if (nb10ProgramDatabase != null) { _debugData[i] = nb10ProgramDatabase; @@ -1047,7 +1047,7 @@ private void ParseDebugTable() // RSDS else if (signature == 0x53445352) { - var rsdsProgramDatabase = entryData.AsRSDSProgramDatabase(ref offset); + var rsdsProgramDatabase = entryData.ParseRSDSProgramDatabase(ref offset); if (rsdsProgramDatabase != null) { _debugData[i] = rsdsProgramDatabase;