From 53af618fe4fd73dd22984bed6c2db780fa383d02 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 18 Sep 2025 09:40:15 -0400 Subject: [PATCH] Proof-of-concept Wise section caching --- .../Wrappers/PortableExecutable.Extraction.cs | 24 +--- .../Wrappers/PortableExecutable.cs | 104 ++++++++++++++---- 2 files changed, 85 insertions(+), 43 deletions(-) diff --git a/SabreTools.Serialization/Wrappers/PortableExecutable.Extraction.cs b/SabreTools.Serialization/Wrappers/PortableExecutable.Extraction.cs index 8dda12e9..fb642ead 100644 --- a/SabreTools.Serialization/Wrappers/PortableExecutable.Extraction.cs +++ b/SabreTools.Serialization/Wrappers/PortableExecutable.Extraction.cs @@ -397,9 +397,8 @@ namespace SabreTools.Serialization.Wrappers return ExtractWiseOverlay(outputDirectory, includeDebug, source, offset); // Try to find the section header - var section = FindWiseSection(); - if (section != null) - return ExtractWiseSection(outputDirectory, includeDebug, source, section); + if (WiseSection != null) + return ExtractWiseSection(outputDirectory, includeDebug, source); // Everything else could not extract return false; @@ -527,23 +526,10 @@ namespace SabreTools.Serialization.Wrappers /// Potentially multi-part stream to read /// Wise section information /// True if extraction succeeded, false otherwise - private bool ExtractWiseSection(string outputDirectory, bool includeDebug, Stream source, Models.PortableExecutable.SectionHeader section) + private bool ExtractWiseSection(string outputDirectory, bool includeDebug, Stream source) { - // Get the offset - long offset = section.VirtualAddress.ConvertVirtualAddress(SectionTable); - if (offset < 0 || offset >= source.Length) - return false; - - // Read the section into a local array - int sectionLength = (int)section.VirtualSize; - byte[]? sectionData; - lock (source) - { - sectionData = source.ReadFrom(offset, sectionLength, retainPosition: true); - } - - // Parse the section header - var header = WiseSectionHeader.Create(sectionData, 0); + // Get the section header + var header = WiseSection; if (header == null) { if (includeDebug) Console.Error.WriteLine("Could not parse the section header"); diff --git a/SabreTools.Serialization/Wrappers/PortableExecutable.cs b/SabreTools.Serialization/Wrappers/PortableExecutable.cs index 6d88d434..709decd6 100644 --- a/SabreTools.Serialization/Wrappers/PortableExecutable.cs +++ b/SabreTools.Serialization/Wrappers/PortableExecutable.cs @@ -491,6 +491,71 @@ namespace SabreTools.Serialization.Wrappers } } + /// + /// Wise section wrapper, if it exists + /// + public WiseSectionHeader? WiseSection + { + get + { + lock (_wiseSectionHeaderLock) + { + // If we already have cached data, just use that immediately + if (_wiseSectionHeader != null) + return _wiseSectionHeader; + + // If the header will not be found due to missing section data + if (_wiseSectionHeaderMissing) + return null; + + // If the section table is invalid + if (SectionTable == null) + { + _wiseSectionHeaderMissing = true; + return null; + } + + // Find the .WISE section + SectionHeader? wiseSection = null; + foreach (var section in SectionTable) + { + string sectionName = Encoding.ASCII.GetString(section.Name ?? []).TrimEnd('\0'); + if (sectionName != ".WISE") + continue; + + wiseSection = section; + break; + } + + // If the section cannot be found + if (wiseSection == null) + { + _wiseSectionHeaderMissing = true; + return null; + } + + // Get the physical offset of the section + long offset = wiseSection.VirtualAddress.ConvertVirtualAddress(SectionTable); + if (offset < 0 || offset >= Length) + { + _wiseSectionHeaderMissing = true; + return null; + } + + // Read the section into a local array + int sectionLength = (int)wiseSection.VirtualSize; + byte[]? sectionData = ReadRangeFromSource(offset, sectionLength); + + // Parse the section header + _wiseSectionHeader = WiseSectionHeader.Create(sectionData, 0); + if (_wiseSectionHeader == null) + _wiseSectionHeaderMissing = true; + + return _wiseSectionHeader; + } + } + } + #region Version Information /// @@ -815,6 +880,21 @@ namespace SabreTools.Serialization.Wrappers /// private readonly List?[] _tableStringData = new List?[16]; + /// + /// Wise section wrapper, if it exists + /// + private WiseSectionHeader? _wiseSectionHeader = null; + + /// + /// Lock object for + /// + private readonly object _wiseSectionHeaderLock = new(); + + /// + /// Indicates if cannot be found + /// + private bool _wiseSectionHeaderMissing = false; + #region Version Information /// @@ -1446,30 +1526,6 @@ namespace SabreTools.Serialization.Wrappers } } - /// - /// Find the location of a Wise section, if it exists - /// - /// Wise section on success, null otherwise - public SectionHeader? FindWiseSection() - { - // If the section table is invalid - if (SectionTable == null) - return null; - - // Find the .WISE section - foreach (var section in SectionTable) - { - string sectionName = Encoding.ASCII.GetString(section.Name ?? []).TrimEnd('\0'); - if (sectionName != ".WISE") - continue; - - return section; - } - - // Otherwise, it could not be found - return null; - } - #endregion #region Resource Parsing