Files
Sylpheed/crates/sylpheed-formats/examples/caption_coverage.rs
Sylpheed RE agent 1b295e3cd2 re: read all eight caption families — 15x more text, and the same lesson twice
build_caption_text generalises the key parser from MSG_DEMO_* to all eight
families. The shapes are uniform and each family is 100% consistent with its
own: seven use MSG_<FAM>_<id>_<page>_<line>, and VOICE alone inserts a family
letter before the id.

                       ids    lines
  build_demo_text      134      537
  build_caption_text  3721     8074

The DEMO family comes out identical through both readers -- 537 lines either
way -- which is the control that generalising changed nothing that already
worked. Pinned by tests/caption_families_disc.rs, along with VOICE ids keeping
their family letter.

But this does NOT close the gap, and the write-up says so: 8074 against the
44579 text-bearing fields the record-level scan counts is about 18%.

The reason is the same lesson this session already learned once.
build_caption_text pairs a value with the key that happens to follow it in the
raw UTF-16 token stream -- the adjacency heuristic that was wrong for IDXD and
is wrong here for the same reason. ixud.rs has no record/field reader at all.
The IXUD record table IS decoded and verified disc-wide (1104/1104 objects,
628165/628165 fields reproducing their key) and was simply never wired into
the crate.

Next step recorded: give ixud.rs an IdxdObject-shaped reader and read captions
as fields rather than adjacent tokens. The decode exists; only the plumbing is
missing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-26 02:47:13 +00:00

39 lines
1.4 KiB
Rust

//! How many caption lines does `build_caption_text` actually recover?
use std::collections::BTreeMap;
use sylpheed_formats::{movie_subtitle, PakArchive};
fn main() {
let disc = std::env::var("SYLPHEED_DISC").expect("set SYLPHEED_DISC");
let pak = PakArchive::open(format!("{disc}/dat/GP_MAIN_GAME_E.pak")).expect("pak");
let all = movie_subtitle::build_caption_text(&pak);
let demo = movie_subtitle::build_demo_text(&pak);
let mut per: BTreeMap<&str, (usize, usize)> = BTreeMap::new();
for (id, lines) in &all {
let fam = id.split('_').next().unwrap();
let e = per.entry(fam).or_default();
e.0 += 1;
e.1 += lines.len();
}
println!("{:<8} {:>8} {:>9}", "family", "ids", "lines");
let (mut ids, mut lines) = (0, 0);
for (fam, (i, l)) in &per {
println!("{fam:<8} {i:>8} {l:>9}");
ids += i;
lines += l;
}
println!("{:<8} {:>8} {:>9}", "TOTAL", ids, lines);
println!(
"\nbuild_demo_text alone: {} ids, {} lines",
demo.len(),
demo.values().map(|v| v.len()).sum::<usize>()
);
// The DEMO family must come out identical either way — that is the control.
let demo_via_all: usize = all
.iter()
.filter(|(k, _)| k.starts_with("DEMO_"))
.map(|(_, v)| v.len())
.sum();
println!("DEMO via build_caption_text: {demo_via_all} lines");
}