From 79b3f4694dab266ca40de308e360fa5fac04be81 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:15:08 +0800 Subject: [PATCH] fix(desktop): probe GameMaker data filenames Select conventional Linux and macOS game data files for the existing bounded FORM/GEN8 probe. Add service-boundary regressions and document the selected names. Fixes #6659 --- docs/desktop-applications.md | 2 +- src/artifacts/DesktopApplicationReader.ts | 2 +- .../filesystem/desktopApplication.test.ts | 32 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/docs/desktop-applications.md b/docs/desktop-applications.md index c9473cf3a3..1161d51055 100644 --- a/docs/desktop-applications.md +++ b/docs/desktop-applications.md @@ -97,7 +97,7 @@ same bundle. Export writes only the caller-selected output file. | Unity Mono | A managed assembly below `*_Data/Managed` or `Contents/Resources/Data/Managed` has an exact UnityEngine assembly reference. | | Unity IL2CPP | A recognized IL2CPP metadata magic (with the raw version when complete) coexists with a conventionally named native `GameAssembly.dll`, `GameAssembly.so`, `GameAssembly.dylib` or `libil2cpp.so` image. Build correspondence remains unknown. | | Godot | A `GDPC` header at file start or a validated executable trailer offset. | -| GameMaker | A bounded `FORM` container starts with a `GEN8` chunk. | +| GameMaker | A bounded `FORM` container starts with a `GEN8` chunk. The scan probes conventional `data.win`, `game.unx`, and `game.ios` data files for that header. | | Unreal | `Content/Paks` path conventions or an IoStore TOC signature; arbitrary `.pak` filenames are insufficient. | | Electron | A `resources/app.asar` or `resources/default_app.asar` path convention; archive validity is unverified. | diff --git a/src/artifacts/DesktopApplicationReader.ts b/src/artifacts/DesktopApplicationReader.ts index 02d8fcbfa5..a0a5cce4eb 100644 --- a/src/artifacts/DesktopApplicationReader.ts +++ b/src/artifacts/DesktopApplicationReader.ts @@ -476,6 +476,6 @@ const addPathFacts = (row: DesktopFile): string | null => { const probeSelected = (entry: DirectoryArtifactEntry): boolean => entry.executable || - /(?:\.(?:exe|dll|so|dylib|pck|utoc)|(?:^|\/)global-metadata\.dat|(?:^|\/)data\.win)$/iu.test( + /(?:\.(?:exe|dll|so|dylib|pck|utoc)|(?:^|\/)(?:global-metadata\.dat|data\.win|game\.(?:unx|ios)))$/iu.test( entry.path, ); diff --git a/tests/boundary/filesystem/desktopApplication.test.ts b/tests/boundary/filesystem/desktopApplication.test.ts index 00bfdce792..0541118c36 100644 --- a/tests/boundary/filesystem/desktopApplication.test.ts +++ b/tests/boundary/filesystem/desktopApplication.test.ts @@ -787,6 +787,38 @@ it.each([ }, ); +it.each([ + "assets/game.unx", + "Example.app/Contents/Resources/game.ios", +])("probes the GameMaker data file at %s", async (path) => { + const root = await createTestTempDirectory("rea-desktop-gamemaker-data-"); + const form = Buffer.alloc(16); + form.write("FORM"); + form.writeUInt32LE(8, 4); + form.write("GEN8", 8); + form.writeUInt32LE(0, 12); + await put(root, path, form); + + const { report } = await inspect(root); + expect(report.candidates.map((candidate) => candidate.family)).toContain( + "gamemaker", + ); + expect(report.files).toContainEqual( + expect.objectContaining({ + path, + read_status: "examined", + facts: [ + expect.objectContaining({ + kind: "gamemaker-form-header", + offset: 0, + value: { container: "FORM", first_chunk: "GEN8" }, + }), + ], + }), + ); + expect(report.coverage.status).toBe("complete-within-scan"); +}); + it("compares exact signature bytes without masking high bits in engine headers or trailers", async () => { const root = await createTestTempDirectory("rea-desktop-exact-signatures-"); const pck = Buffer.alloc(20);