mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 07:16:13 +00:00
feat(il2cpp): read member names, string literals and metadata versions 24 and 27 (#5326)
* feat(il2cpp): read member names, string literals and metadata versions 24 and 27 Adds field, property, event and parameter names with their owners, managed string literals, and the version 24 and 27 header layouts to inspect_il2cpp_metadata, with filtered pages for the new collections. Member decoding yields between row batches like the other row readers. * fix(il2cpp): bound metadata expansion and query parameter owners * test(il2cpp): cover nonempty property and event tables --------- Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
This commit is contained in:
1 parent
052956af34
commit
21e0c580e7
24 files changed
+1707
-315
No files matched your search
@@ -1,11 +1,12 @@
|
||||
import { afterEach, expect, it, vi } from "vitest";
|
||||
import {
|
||||
IL2CPP_METADATA_SECTION_NAMES,
|
||||
il2cppMetadataSchema,
|
||||
il2cppMetadataParentSchema,
|
||||
type Il2cppMetadata,
|
||||
} from "../il2cpp/il2cppMetadata.js";
|
||||
import { createEvidence } from "../evidence.js";
|
||||
import { freezeJsonSnapshot } from "../immutableJson.js";
|
||||
import { jsonObjectSchema } from "../jsonValue.js";
|
||||
import { projectIl2cppMetadataView } from "./il2cppMetadataView.js";
|
||||
|
||||
afterEach(() => {
|
||||
@@ -55,6 +56,11 @@ const report: Il2cppMetadata = {
|
||||
},
|
||||
],
|
||||
methods: [{ name: "Run", declaring_type: 0 }],
|
||||
fields: [{ name: "value", declaring_type: 0 }],
|
||||
properties: [],
|
||||
events: [],
|
||||
parameters: [{ name: "times", method: 0 }],
|
||||
string_literals: [{ value: "Go", value_base64: null }],
|
||||
limitations: [],
|
||||
};
|
||||
|
||||
@@ -74,27 +80,139 @@ const page = {
|
||||
} as const;
|
||||
|
||||
it("validates a sealed parent once across pages and keeps counts exact", () => {
|
||||
const parse = vi.spyOn(il2cppMetadataSchema, "safeParse");
|
||||
const parse = vi.spyOn(il2cppMetadataParentSchema, "safeParse");
|
||||
const sealed = parent(freezeJsonSnapshot(structuredClone(report)), true);
|
||||
for (const offset of [0, 1]) {
|
||||
const view = projectIl2cppMetadataView(sealed, { ...page, offset });
|
||||
if (!view.ok) throw view.error;
|
||||
expect(view.value).toMatchObject({
|
||||
items: [{ index: offset, ...report.types[offset] }],
|
||||
counts: { images: 1, types: 2, methods: 1, nested_types: 1 },
|
||||
counts: {
|
||||
sections: report.sections.length,
|
||||
images: 1,
|
||||
types: 2,
|
||||
methods: 1,
|
||||
nested_types: 1,
|
||||
fields: 1,
|
||||
properties: 0,
|
||||
events: 0,
|
||||
parameters: 1,
|
||||
string_literals: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
expect(parse).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("revalidates unsealed inline input on every page", () => {
|
||||
const parse = vi.spyOn(il2cppMetadataSchema, "safeParse");
|
||||
const parse = vi.spyOn(il2cppMetadataParentSchema, "safeParse");
|
||||
const inline = parent(structuredClone(report), false);
|
||||
projectIl2cppMetadataView(inline, page);
|
||||
projectIl2cppMetadataView(inline, page);
|
||||
expect(parse).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("preserves historical omission as unknown while keeping existing metadata queries usable", () => {
|
||||
const historical = jsonObjectSchema.parse(report);
|
||||
for (const key of [
|
||||
"fields",
|
||||
"properties",
|
||||
"events",
|
||||
"parameters",
|
||||
"string_literals",
|
||||
])
|
||||
delete historical[key];
|
||||
const source = parent(freezeJsonSnapshot(historical), true);
|
||||
const summary = projectIl2cppMetadataView(source, { kind: "summary" });
|
||||
if (!summary.ok) throw summary.error;
|
||||
expect(summary.value).toMatchObject({
|
||||
summary: {
|
||||
counts: { types: 2, methods: 1, fields: null, parameters: null },
|
||||
},
|
||||
unknowns: expect.arrayContaining([
|
||||
expect.stringContaining("did not collect fields"),
|
||||
]),
|
||||
});
|
||||
const existing = projectIl2cppMetadataView(source, page);
|
||||
if (!existing.ok) throw existing.error;
|
||||
expect(existing.value).toMatchObject({
|
||||
items: [{ index: 0, name: "Outer" }],
|
||||
});
|
||||
const unavailable = projectIl2cppMetadataView(source, {
|
||||
kind: "il2cpp-metadata",
|
||||
collection: "parameters",
|
||||
offset: 0,
|
||||
limit: 1,
|
||||
});
|
||||
expect(unavailable.ok).toBe(false);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ fields: [{ name: "bad", declaring_type: 2 }] },
|
||||
{ parameters: [{ name: "bad", method: 1 }] },
|
||||
{ string_literals: [{ value: null, value_base64: null }] },
|
||||
{ string_literals: [{ value: "Go", value_base64: "R28=" }] },
|
||||
])(
|
||||
"rejects inconsistent member ownership or literal representation in authenticated parent facts: %j",
|
||||
(changed) => {
|
||||
const result = projectIl2cppMetadataView(
|
||||
parent({ ...report, ...changed }, false),
|
||||
{ kind: "summary" },
|
||||
);
|
||||
expect(result.ok).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
it("selects a batch of parameter owners before paging and intersects exact identities and names", () => {
|
||||
const source = parent(
|
||||
freezeJsonSnapshot({
|
||||
...report,
|
||||
parameters: [
|
||||
{ name: "first", method: 0 },
|
||||
{ name: "unclaimed", method: -1 },
|
||||
{ name: "last", method: 0 },
|
||||
],
|
||||
}),
|
||||
true,
|
||||
);
|
||||
const query = {
|
||||
kind: "il2cpp-metadata",
|
||||
collection: "parameters",
|
||||
method_indices: [0, 0, 99],
|
||||
fields: ["name", "method"],
|
||||
offset: 1,
|
||||
limit: 1,
|
||||
} as const;
|
||||
const result = projectIl2cppMetadataView(source, {
|
||||
...query,
|
||||
method_indices: [...query.method_indices],
|
||||
fields: [...query.fields],
|
||||
});
|
||||
if (!result.ok) throw result.error;
|
||||
expect(result.value).toMatchObject({
|
||||
items: [{ index: 2, name: "last", method: 0 }],
|
||||
coverage: { total: 2, exhausted: true, next_offset: null },
|
||||
});
|
||||
for (const selection of [
|
||||
{ method_indices: [] },
|
||||
{ method_indices: [99] },
|
||||
{ method_indices: [0], indices: [1] },
|
||||
{ method_indices: [0], names: ["unclaimed"] },
|
||||
]) {
|
||||
const empty = projectIl2cppMetadataView(source, {
|
||||
...query,
|
||||
...selection,
|
||||
offset: 0,
|
||||
fields: [...query.fields],
|
||||
});
|
||||
if (!empty.ok) throw empty.error;
|
||||
expect(empty.value).toMatchObject({
|
||||
items: [],
|
||||
coverage: { total: 0, exhausted: true },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("intersects batch identities, fields, image ranges and exact names in source order", () => {
|
||||
const source = parent(freezeJsonSnapshot(structuredClone(report)), true);
|
||||
const result = projectIl2cppMetadataView(source, {
|
||||
|
||||
Reference in new issue
Block a user