113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
"""Compare forensic snapshots and print diff tables."""
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
def load(p):
|
|
return json.loads(Path(p).read_text(encoding="utf-8-sig"))
|
|
|
|
def diff_table(a, b, keys):
|
|
rows = []
|
|
for k in keys:
|
|
va, vb = a.get(k), b.get(k)
|
|
changed = va != vb
|
|
rows.append((k, va, vb, "CHANGED" if changed else "same"))
|
|
return rows
|
|
|
|
def print_table(title, rows):
|
|
print(f"\n=== {title} ===")
|
|
print(f"{'Property':<22} {'Before':<40} {'After':<40} {'Status'}")
|
|
for k, va, vb, st in rows:
|
|
sa = json.dumps(va) if not isinstance(va, str) else va
|
|
sb = json.dumps(vb) if not isinstance(vb, str) else vb
|
|
if len(sa) > 38: sa = sa[:35] + "..."
|
|
if len(sb) > 38: sb = sb[:35] + "..."
|
|
print(f"{k:<22} {sa:<40} {sb:<40} {st}")
|
|
|
|
def compare_advances(orig, new):
|
|
oa, na = orig or [], new or []
|
|
diffs = []
|
|
for i in range(max(len(oa), len(na))):
|
|
ov = oa[i] if i < len(oa) else None
|
|
nv = na[i] if i < len(na) else None
|
|
if ov != nv:
|
|
diffs.append((i, ov, nv))
|
|
return diffs
|
|
|
|
def main():
|
|
extract_path = Path(sys.argv[1] if len(sys.argv) > 1 else "forensic_extract_out.json")
|
|
wasm_path = Path(sys.argv[2] if len(sys.argv) > 2 else "forensic_wasm_out.json")
|
|
ex = load(extract_path)
|
|
wasm = load(wasm_path)
|
|
|
|
keys = [
|
|
"text", "fontId", "fontName", "fontSize", "color",
|
|
"glyphCount", "advanceCount", "paragraphWidth", "baseline", "lineHeight",
|
|
"origLinesProvided",
|
|
]
|
|
|
|
orig = ex["original"]
|
|
entry_payload = ex["editEntry"]
|
|
one_payload = ex["editOne"]
|
|
|
|
# WASM layout snapshots
|
|
from forensic_extract import snapshot_from_wasm_layout, para_signature # type: ignore
|
|
seed_fn = orig.get("fontName", "")
|
|
entry_wasm = snapshot_from_wasm_layout("ENTRY_WASM", wasm["editEntryWasm"]["layout"], seed_fn)
|
|
one_wasm = snapshot_from_wasm_layout("ONE_WASM", wasm["editOneWasm"]["layout"], seed_fn)
|
|
|
|
print_table("ORIGINAL vs EDIT_MODE_ENTRY (payload)", diff_table(orig, entry_payload, keys))
|
|
print_table("ORIGINAL vs EDIT_MODE_ENTRY (WASM layout)", diff_table(orig, entry_wasm, keys))
|
|
|
|
adv_diff_entry = compare_advances(orig.get("advances"), entry_wasm.get("advances"))
|
|
if adv_diff_entry:
|
|
print(f"\nAdvance diffs ORIGINAL vs ENTRY_WASM: {len(adv_diff_entry)} positions")
|
|
for i, ov, nv in adv_diff_entry[:20]:
|
|
print(f" [{i}] {ov} -> {nv}")
|
|
else:
|
|
print("\nAdvance arrays IDENTICAL: ORIGINAL vs ENTRY_WASM")
|
|
|
|
print_table("EDIT_ENTRY vs AFTER_ONE_CHAR (payload)", diff_table(entry_payload, one_payload, keys))
|
|
print_table("ENTRY_WASM vs ONE_WASM", diff_table(entry_wasm, one_wasm, keys))
|
|
|
|
adv_diff_one = compare_advances(entry_wasm.get("advances"), one_wasm.get("advances"))
|
|
if adv_diff_one:
|
|
print(f"\nAdvance diffs ENTRY_WASM vs ONE_WASM: {len(adv_diff_one)} positions")
|
|
for i, ov, nv in adv_diff_one[:20]:
|
|
print(f" [{i}] {ov} -> {nv}")
|
|
|
|
# Line widths
|
|
print("\n=== LINE WIDTHS ===")
|
|
print(f"Original lineWidths: {orig.get('lineWidths')}")
|
|
print(f"Entry WASM lineWidths: {entry_wasm.get('lineWidths')}")
|
|
print(f"One WASM lineWidths: {one_wasm.get('lineWidths')}")
|
|
|
|
# Signatures chain
|
|
sigs = {
|
|
"original": para_signature(orig),
|
|
"entry_payload": para_signature(entry_payload),
|
|
"entry_wasm": para_signature(entry_wasm),
|
|
"one_payload": para_signature(one_payload),
|
|
"one_wasm": para_signature(one_wasm),
|
|
}
|
|
print("\n=== SIGNATURE CHAIN ===")
|
|
prev = None
|
|
for name, sig in sigs.items():
|
|
changed = prev and sig != prev
|
|
print(f" {name}: {sig}" + (" <-- FIRST CHANGE from " + prev_name if changed else ""))
|
|
if changed and prev:
|
|
pass
|
|
prev_name = name
|
|
prev = sig
|
|
|
|
# First mutation
|
|
chain = list(sigs.items())
|
|
base = chain[0][1]
|
|
for i in range(1, len(chain)):
|
|
if chain[i][1] != base:
|
|
print(f"\nFIRST SIGNATURE CHANGE: {chain[i][0]} (vs original)")
|
|
break
|
|
|
|
if __name__ == "__main__":
|
|
main()
|