mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
refactor(godot): share PCK header facts across inspections
This commit is contained in:
1 parent
d7d9457661
commit
8982f40d00
4 files changed
+56
-18
No files matched your search
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
hasGodotPckHeader,
|
||||
readGodotPckHeaderFacts,
|
||||
} from "../domain/godotPckFormat.js";
|
||||
import type { FileHandle } from "node:fs/promises";
|
||||
import { createHash } from "node:crypto";
|
||||
import { setImmediate } from "node:timers/promises";
|
||||
@@ -108,20 +112,22 @@ export const inspectDesktopFile = async (
|
||||
raw_version: metadataPrefix.rawVersion,
|
||||
},
|
||||
});
|
||||
if (prefix.length >= 20 && prefix.toString("latin1", 0, 4) === "GDPC")
|
||||
if (prefix.length >= 20 && hasGodotPckHeader(prefix)) {
|
||||
const pckHeader = readGodotPckHeaderFacts(prefix);
|
||||
fact({
|
||||
kind: "godot-pck-header",
|
||||
offset: 0,
|
||||
value: {
|
||||
pack_version: prefix.readUInt32LE(4),
|
||||
pack_version: pckHeader.formatVersion,
|
||||
engine_version: [
|
||||
prefix.readUInt32LE(8),
|
||||
prefix.readUInt32LE(12),
|
||||
prefix.readUInt32LE(16),
|
||||
pckHeader.engineMajor,
|
||||
pckHeader.engineMinor,
|
||||
pckHeader.enginePatch,
|
||||
],
|
||||
placement: "standalone",
|
||||
},
|
||||
});
|
||||
}
|
||||
if (
|
||||
prefix.length >= 16 &&
|
||||
prefix.toString("latin1", 0, 4) === "FORM" &&
|
||||
@@ -320,21 +326,22 @@ const inspectPckTrailer = async (
|
||||
"Embedded PCK trailer declares an invalid pack extent",
|
||||
);
|
||||
const offset = size - 12 - Number(packSize);
|
||||
const header = await read(offset, 20);
|
||||
if (header.toString("latin1", 0, 4) !== "GDPC")
|
||||
const bytes = await read(offset, 20);
|
||||
if (!hasGodotPckHeader(bytes))
|
||||
throw new ArtifactReaderFailure(
|
||||
"format",
|
||||
"Embedded PCK trailer does not locate a pack header",
|
||||
);
|
||||
const header = readGodotPckHeaderFacts(bytes);
|
||||
fact({
|
||||
kind: "godot-pck-header",
|
||||
offset,
|
||||
value: {
|
||||
pack_version: header.readUInt32LE(4),
|
||||
pack_version: header.formatVersion,
|
||||
engine_version: [
|
||||
header.readUInt32LE(8),
|
||||
header.readUInt32LE(12),
|
||||
header.readUInt32LE(16),
|
||||
header.engineMajor,
|
||||
header.engineMinor,
|
||||
header.enginePatch,
|
||||
],
|
||||
placement: "embedded-trailer",
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { readGodotPckHeaderFacts } from "../domain/godotPckFormat.js";
|
||||
import { artifactExpansionBudgetBytes } from "../domain/artifactExpansionBudget.js";
|
||||
import type { FileHandle } from "node:fs/promises";
|
||||
import { setImmediate } from "node:timers/promises";
|
||||
@@ -301,7 +302,8 @@ const readGodotPckHeader = async (
|
||||
throw formatFailure("no standalone header or executable trailer");
|
||||
const { start, end, embedded } = location;
|
||||
const fixed = await readPckBytes(handle, start, 40, end, signal);
|
||||
const version = fixed.readUInt32LE(4);
|
||||
const header = readGodotPckHeaderFacts(fixed);
|
||||
const version = header.formatVersion;
|
||||
if (![2, 3, 4].includes(version))
|
||||
throw new ArtifactReaderFailure(
|
||||
"unavailable",
|
||||
@@ -343,9 +345,9 @@ const readGodotPckHeader = async (
|
||||
return {
|
||||
kind: "godot-pck",
|
||||
format_version: version,
|
||||
engine_major: fixed.readUInt32LE(8),
|
||||
engine_minor: fixed.readUInt32LE(12),
|
||||
engine_patch: fixed.readUInt32LE(16),
|
||||
engine_major: header.engineMajor,
|
||||
engine_minor: header.engineMinor,
|
||||
engine_patch: header.enginePatch,
|
||||
pack_start: start,
|
||||
pack_end: end,
|
||||
embedded,
|
||||
|
||||
@@ -8,3 +8,24 @@ export const hasGodotPckHeader = (bytes: Uint8Array): boolean =>
|
||||
bytes[1] === 0x44 &&
|
||||
bytes[2] === 0x50 &&
|
||||
bytes[3] === 0x43;
|
||||
|
||||
/** Common declared fields; support and pack extent admission belong to callers. */
|
||||
export interface GodotPckHeaderFacts {
|
||||
readonly formatVersion: number;
|
||||
readonly engineMajor: number;
|
||||
readonly engineMinor: number;
|
||||
readonly enginePatch: number;
|
||||
}
|
||||
|
||||
/** Decode declared fields after the caller admits a complete 20-byte header. */
|
||||
export const readGodotPckHeaderFacts = (
|
||||
bytes: Uint8Array,
|
||||
): GodotPckHeaderFacts => {
|
||||
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
||||
return {
|
||||
formatVersion: view.getUint32(4, true),
|
||||
engineMajor: view.getUint32(8, true),
|
||||
engineMinor: view.getUint32(12, true),
|
||||
enginePatch: view.getUint32(16, true),
|
||||
};
|
||||
};
|
||||
@@ -192,6 +192,8 @@ it("reads sparse embedded PCK ranges without hashing or retaining a large execut
|
||||
pck.write("GDPC");
|
||||
pck.writeUInt32LE(3, 4);
|
||||
pck.writeUInt32LE(4, 8);
|
||||
pck.writeUInt32LE(0x80000001, 12);
|
||||
pck.writeUInt32LE(0xffffffff, 16);
|
||||
const trailer = Buffer.alloc(12);
|
||||
trailer.writeBigUInt64LE(BigInt(pck.length));
|
||||
trailer.write("GDPC", 8);
|
||||
@@ -203,9 +205,15 @@ it("reads sparse embedded PCK ranges without hashing or retaining a large execut
|
||||
expect(report.candidates.map((row) => row.family)).toContain("godot");
|
||||
expect(report.coverage.bytes_read).toBeLessThan(4096);
|
||||
expect(report.files[0]?.bytes).toBe(size);
|
||||
expect(report.files[0]?.facts).toContainEqual(
|
||||
expect.objectContaining({ kind: "godot-pck-header", offset: size - 32 }),
|
||||
);
|
||||
expect(report.files[0]?.facts).toContainEqual({
|
||||
kind: "godot-pck-header",
|
||||
offset: size - 32,
|
||||
value: {
|
||||
pack_version: 3,
|
||||
engine_version: [4, 0x80000001, 0xffffffff],
|
||||
placement: "embedded-trailer",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("does not promote filenames, arbitrary pak files or symlink targets into byte facts", async () => {
|
||||
|
||||
Reference in new issue
Block a user