mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
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
111 lines
3.2 KiB
TypeScript
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,
|
|
})),
|
|
);
|