Files
amacocian ef513e1230 Gwca bindings (#1462)
* Bump version to 0.9.10.1

* Bump Microsoft.Web.WebView2 from 1.0.3719.77 to 1.0.3800.47 (#1442)

---
updated-dependencies:
- dependency-name: Microsoft.Web.WebView2
  dependency-version: 1.0.3800.47
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Improve mod view responsiveness (#1443)

* Improve application launcher logging (Closes #1441) (#1444)

* Damage modifier 0x248 (Closes #1438) (#1445)

* Initial commit

* Setup generator

* Progress

* Update generator

* Initial commit

* Setup generator

* Progress

* Update generator

* Fix library loading

* Move code to gwca

* Fix leave party

* Disable console on Release

* Add more exports to gwca

* Upgrade gwca

* Fixes to character selector

* Fix GetWindowHandle

* Move character selector to frame based

* Fix config spamming

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexandru Macocian <amacocian@microsoft.com>
2026-02-24 06:37:10 -08:00

141 lines
5.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Immutable;
using System.Text;
namespace Daybreak.Generators;
/// <summary>
/// Minimal PE exportname reader. Zero external dependencies — reads the
/// PE export directory directly from the on-disk binary so we can use it
/// inside a Roslyn source generator (netstandard2.0).
/// </summary>
internal static class PeExportReader
{
public static ImmutableArray<string> ReadExportNames(byte[] data)
{
// Minimum size: DOS header (64 bytes)
if (data.Length < 64)
return [];
// ── DOS Header ─────────────────────────────────────────────
// e_magic == "MZ"
if (data[0] != 0x4D || data[1] != 0x5A)
return [];
// e_lfanew at offset 0x3C → offset of PE signature
int peOffset = BitConverter.ToInt32(data, 0x3C);
if (peOffset < 0 || peOffset + 4 > data.Length)
return [];
// ── PE Signature ───────────────────────────────────────────
if (data[peOffset] != 'P' || data[peOffset + 1] != 'E' ||
data[peOffset + 2] != 0 || data[peOffset + 3] != 0)
return [];
// ── COFF Header (20 bytes) ─────────────────────────────────
int coffOffset = peOffset + 4;
if (coffOffset + 20 > data.Length)
return [];
ushort numberOfSections = BitConverter.ToUInt16(data, coffOffset + 2);
ushort sizeOfOptionalHeader = BitConverter.ToUInt16(data, coffOffset + 16);
int optionalOffset = coffOffset + 20;
if (optionalOffset + sizeOfOptionalHeader > data.Length)
return [];
// ── Optional Header ────────────────────────────────────────
ushort magic = BitConverter.ToUInt16(data, optionalOffset);
bool isPE32Plus = magic == 0x20B;
// PE32 = 0x10B, PE32+ = 0x20B
// NumberOfRvaAndSizes
int numRvaOffset = optionalOffset + (isPE32Plus ? 108 : 92);
if (numRvaOffset + 4 > data.Length)
return [];
uint numberOfRvaAndSizes = BitConverter.ToUInt32(data, numRvaOffset);
if (numberOfRvaAndSizes == 0)
return [];
// Data directory [0] = Export Table (RVA, Size)
int dataDirOffset = optionalOffset + (isPE32Plus ? 112 : 96);
if (dataDirOffset + 8 > data.Length)
return [];
uint exportRva = BitConverter.ToUInt32(data, dataDirOffset);
uint exportSize = BitConverter.ToUInt32(data, dataDirOffset + 4);
if (exportRva == 0 || exportSize == 0)
return [];
// ── Section Headers ────────────────────────────────────────
int sectionsOffset = optionalOffset + sizeOfOptionalHeader;
var sections = new SectionInfo[numberOfSections];
for (int i = 0; i < numberOfSections; i++)
{
int off = sectionsOffset + (i * 40);
if (off + 40 > data.Length) break;
sections[i] = new SectionInfo(
BitConverter.ToUInt32(data, off + 12), // VirtualAddress
BitConverter.ToUInt32(data, off + 8), // VirtualSize
BitConverter.ToUInt32(data, off + 20), // PointerToRawData
BitConverter.ToUInt32(data, off + 16) // SizeOfRawData
);
}
// ── Export Directory Table ─────────────────────────────────
int exportDirFileOff = RvaToFileOffset(exportRva, sections);
if (exportDirFileOff < 0 || exportDirFileOff + 40 > data.Length)
return [];
uint numberOfNames = BitConverter.ToUInt32(data, exportDirFileOff + 24);
uint addressOfNamesRva = BitConverter.ToUInt32(data, exportDirFileOff + 32);
int namesTableOff = RvaToFileOffset(addressOfNamesRva, sections);
if (namesTableOff < 0)
return [];
// ── Read Name Strings ──────────────────────────────────────
var builder = ImmutableArray.CreateBuilder<string>((int)numberOfNames);
for (int i = 0; i < (int)numberOfNames; i++)
{
int entryOff = namesTableOff + (i * 4);
if (entryOff + 4 > data.Length) break;
uint nameRva = BitConverter.ToUInt32(data, entryOff);
int nameOff = RvaToFileOffset(nameRva, sections);
if (nameOff < 0) continue;
// Read null-terminated ASCII string
int end = nameOff;
while (end < data.Length && data[end] != 0) end++;
builder.Add(Encoding.ASCII.GetString(data, nameOff, end - nameOff));
}
return builder.ToImmutable();
}
// ────────────────────────────────────────────────────────────────
private static int RvaToFileOffset(uint rva, SectionInfo[] sections)
{
for (int i = 0; i < sections.Length; i++)
{
uint va = sections[i].VirtualAddress;
uint end = va + Math.Max(sections[i].VirtualSize, sections[i].SizeOfRawData);
if (rva >= va && rva < end)
return (int)(rva - va + sections[i].PointerToRawData);
}
return -1;
}
private readonly struct SectionInfo(uint va, uint vs, uint ptr, uint srd)
{
public readonly uint VirtualAddress = va;
public readonly uint VirtualSize = vs;
public readonly uint PointerToRawData = ptr;
public readonly uint SizeOfRawData = srd;
}
}