Files
morluto bd4f5e9c19 fix(parsers): preserve format evidence and caller input identity
Retain bounded FAT and offset-tagged PE observations through archive hashing,
classification, and content nodes. Preserve PyInstaller member paths according
to the observed carrier dialect and share APK v1 signing-name semantics.

Read SQLite's implicit sqlite_schema table without inventing a stored schema
declaration. Distinguish unsupported ELF numbering and decoded-name admission
from malformed data and fixed scan allowances. Preserve Sigrok basenames and
classify matching explicit input-format refusals at their owning boundary.

Validation: 554 distinct tests passed, 3 skipped across serial focused runs;
build, typecheck/lint, docs, formatting, and discovery (2141 files) passed.
Sigrok command-boundary simulators do not establish real-tool decoding.
Small repeated public PyInstaller CLI runs had equivalent inventory facts;
warm median elapsed 0.5431s before / 0.5426s after, with no speed claim.

Fixes #6733
Fixes #6741
Fixes #6722
Fixes #6732
Fixes #6736
Fixes #6734
Fixes #6764
Fixes #6766
Refs #6739
2026-10-23 22:54:28 +08:00

111 lines
3.2 KiB
TypeScript

import { createHash } from "node:crypto";
export interface GodotPckMember {
readonly path: string;
readonly data: string | Uint8Array;
readonly flags?: number;
readonly md5?: Buffer;
readonly size?: bigint;
readonly offset?: bigint;
}
export const pckU32 = (value: number): Buffer => {
const bytes = Buffer.alloc(4);
bytes.writeUInt32LE(value);
return bytes;
};
export const pckU64 = (value: bigint | number): Buffer => {
const bytes = Buffer.alloc(8);
bytes.writeBigUInt64LE(BigInt(value));
return bytes;
};
const pad4 = (bytes: Buffer): Buffer =>
Buffer.concat([bytes, Buffer.alloc((4 - (bytes.length % 4)) % 4)]);
/**
* Build a pack with the layout Godot's exporter writes (and GDRE Tools
* reproduces): format 2 places the directory after a 96-byte header and
* members after it; format 3 stores members first and a pack-relative
* directory offset.
*/
export const buildGodotPck = (
version: 2 | 3 | 4,
members: readonly GodotPckMember[],
options: { packFlags?: number; fileCount?: number } = {},
): Buffer => {
const data: Buffer[] = [];
const offsets: number[] = [];
const memberBytes: Buffer[] = [];
let dataBytes = 0;
for (const member of members) {
offsets.push(dataBytes);
const bytes = pad4(Buffer.from(member.data));
memberBytes.push(Buffer.from(member.data));
data.push(bytes);
dataBytes += bytes.length;
}
const directory = Buffer.concat([
pckU32(options.fileCount ?? members.length),
...members.flatMap((member, index) => {
const path = pad4(Buffer.from(member.path));
return [
pckU32(path.length),
path,
pckU64(member.offset ?? BigInt(offsets[index] ?? 0)),
pckU64(member.size ?? BigInt(memberBytes[index]?.length ?? 0)),
member.md5 ??
createHash("md5")
.update(memberBytes[index] ?? "")
.digest(),
pckU32(member.flags ?? 0),
];
}),
]);
const headerBytes = 96;
const fileBase = version === 2 ? headerBytes + directory.length : headerBytes;
const header = Buffer.concat([
Buffer.from("GDPC"),
pckU32(version),
pckU32(4),
pckU32(6),
pckU32(1),
pckU32(options.packFlags ?? (version >= 3 ? 2 : 0)),
pckU64(fileBase),
pckU64(version >= 3 ? headerBytes + dataBytes : 0),
]);
const paddedHeader = Buffer.concat([
header,
Buffer.alloc(headerBytes - header.length),
]);
return version === 2
? Buffer.concat([paddedHeader, directory, ...data])
: Buffer.concat([paddedHeader, ...data, directory]);
};
export const embedGodotPck = (pack: Buffer): Buffer =>
Buffer.concat([
Buffer.from("\x7fELF fake engine bytes"),
pack,
pckU64(pack.length),
Buffer.from("GDPC"),
]);
/** Repeated physical ranges are valid aliases but multiply plaintext I/O per path. */
export const buildAliasedGodotPck = (
version: 2 | 3 | 4,
count: number,
entryBytes = 256 * 1024,
flags = 0,
): Buffer =>
buildGodotPck(
version,
Array.from({ length: count }, (_, index) => ({
path: `res://aliases/${String(index)}.bin`,
data: index === 0 ? "x".repeat(entryBytes) : "",
offset: 0n,
size: BigInt(entryBytes),
md5: Buffer.alloc(16),
flags,
})),
);