This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/tools/re-capture/archive_naming.py
Sylpheed RE agent 27602a3032 re: BLOCKED -- the 2D / READY_ROOM TOC names, three routes closed with controls
1. A different hash family.  The corpus knows three (idxd-tag-hash.md):
name_hash, tag_hash, ixud_hash.  Scoring all 5977 harvested names x 6
prefixes: GP_TITLE 8/16 and GP_PAUSE_MENU 6/11 under name_hash (the
positive controls), and tag_hash and ixud_hash explain NOTHING anywhere
-- including the paks name_hash does explain.  So they are not the TOC
function, and the unnameable pair is not keyed by a different one.
GP_MAIN_GAME_E2D stays at 0/711 under all three.

2. The executable.  sylpheed.db's strings table holds 7140 rows, of
which exactly two look like asset paths -- Data\gmicon002_2.t32 and
Data\gmicon006_2.t32, in a Data\ directory nothing else on the disc
uses -- and neither resolves in any archive.  The binary is not the name
source; it holds two strays and no table.

3. Name transformations -- 13 of them on the 419 config paths, all 0.

The container runs out here.  Those TOC keys hash names that exist on
neither the disc nor the executable in readable form.  The only lever
left is a dictionary attack using name_hash's shape (top byte = the
character-sum checksum), and that needs a plausible name corpus this
disc does not contain.  Noted as blocked rather than improvised around.

The port does not need these names: sprites and bundles are readable by
content (T8aD, RATC), and the config records already say which asset
each HUD element uses.  Only the archive-key to name mapping is missing.

Artefact +22 lines / 0 deletions; the other eight regenerate
byte-identical.
2026-08-27 15:22:13 +00:00

67 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""How much of each pak's TOC can be named from the asset strings on the disc.
Harvests every plausible asset-name string from every archive, hashes each under
the known path prefixes, and reports per archive how many of its entries are
explained. Regenerates docs/re/data/archive-naming.txt.
"""
import sys, os, glob, re, collections
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import unitgroup as U
from unit_substructures import pak_entries
EXT = r'(prt|t32|rat|tbl|xpr|ttc|ttf|TTC|TTF|bin|col|rgn|prm)'
PRE = ['', '2d\\', 'ui\\', 'hud\\', 'Stage\\', 'stage\\', 'message\\', 'language\\',
'prt\\', 'view\\'] + [l + '\\' for l in ('eng', 'jpn', 'fra', 'deu', 'ita', 'esp')]
def main():
paks = sorted(glob.glob('/work/sylph_extract/**/*.pak', recursive=True))
names = set()
toc = {}
for pk in paks:
ents = pak_entries(pk)
toc[os.path.basename(pk)] = [h for h, b in ents]
for h, b in ents:
for m in re.finditer((r'[A-Za-z0-9_\\.\-]{4,60}\.' + EXT).encode(), b):
names.add(m.group(0).decode('latin-1'))
H = set()
for n in names:
for p in PRE:
H.add(U.name_hash(p + n))
print("# How much of each pak's TOC can be named from the disc's own strings")
print("# Regenerate: python3 tools/re-capture/archive_naming.py")
print("# See docs/re/structures/archive-naming.md")
print("\n candidate asset-name strings harvested: %d" % len(names))
print(" path prefixes tried: %d" % len(PRE))
print("\n archive entries named pct")
rows = sorted(((k, v) for k, v in toc.items()), key=lambda r: -len(r[1]))
for nm, ent in rows:
nd = sum(1 for h in ent if h in H)
print(" %-30s %6d %6d %5.1f%%" % (nm, len(ent), nd, 100.0 * nd / len(ent) if ent else 0))
def _ix(t): return U.ixud_hash([ord(c) for c in t])
FN = [('name_hash', U.name_hash), ('tag_hash', U.tag_hash), ('ixud_hash', _ix)]
SUB = ['', '2d\\', 'eng\\', 'Data\\', 'ArmsSt\\', 'Marker\\']
print("\n## CONTROL is the unnameable pair keyed by a DIFFERENT hash?")
print(" (6 prefixes x 3 hash families; the menu paks are the positive control)")
for nm in ['GP_MAIN_GAME_E2D.pak', 'GP_READY_ROOM.pak', 'GP_TITLE.pak', 'GP_PAUSE_MENU.pak']:
S = set(toc[nm])
for fname, f in FN:
best = (0, '')
for p in SUB:
n = sum(1 for v in names if f(p + v) in S)
if n > best[0]: best = (n, p or '<bare>')
print(" %-22s %-10s %4d / %-5d %s" % (nm, fname, best[0], len(S), best[1]))
print("\n## CONTROL the executable holds almost no asset names")
print(" sylpheed.db `strings`: 7140 rows, of which 2 look like asset paths")
print(" Data\\gmicon002_2.t32 and Data\\gmicon006_2.t32")
for n in ['Data\\gmicon002_2.t32', 'Data\\gmicon006_2.t32', 'gmicon002_2.t32']:
print(" %-28s resolves anywhere: %s" % (n, U.name_hash(n) in H))
if __name__ == "__main__":
main()