Diagnostics that localise the decrypted-DVD title loss

Two opt-in dumps, driven by FMKV_IMAGE, that narrow where a decrypted DVD
image loses titles:

dump_title_sets_for_an_image reports what survives parse_vmg. On one disc
the CSS image yields 13 title sets and 38 titles; its decrypted copy
yields 8 and 10. Sets 8, 9, 10, 12 and 13 are dropped outright, set 11
parses but returns no titles at all, and set 7 returns 3 of 5.

dump_vts_ifo_reads_for_an_image reads every VTS IFO and hashes the
CONTENT. All thirteen are byte-identical across the two images, so
parse_vts is handed the same bytes and the same TT_SRPT info and still
fails on one of them — the divergence is in what it reads from the READER
afterwards, which is file_start_lba and the PGCIT.

An earlier version of the second dump compared only length and magic and
so wrongly reported the images as identical; it hashes the bytes now.
This commit is contained in:
Matthew Jackson
2026-08-05 20:14:46 -07:00
parent 5c64662213
commit 77ad147563
+31 -2
View File
@@ -843,10 +843,39 @@ fn dump_vts_ifo_reads_for_an_image() {
let p = format!("/VIDEO_TS/VTS_{n:02}_0.IFO");
match fs.read_file(&mut img, &p) {
Ok(b) => {
let magic = String::from_utf8_lossy(&b[..12.min(b.len())]).to_string();
println!("VTS {n:02}: read ok, {} bytes, magic={magic:?}", b.len());
// Hash the CONTENT, not just the length: two IFOs of equal
// size and magic can still differ, and comparing only length
// and magic is what made an earlier pass of this diagnostic
// wrongly report the images as identical.
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
for byte in &b {
h ^= *byte as u64;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
}
println!("VTS {n:02}: {} bytes fnv={h:016x}", b.len());
}
Err(e) => println!("VTS {n:02}: READ FAILED: {e}"),
}
}
}
/// Diagnostic (opt-in): how many title sets survive `parse_vmg`, and how many
/// titles does each carry? Splits "the set was dropped" from "the set parsed
/// but yielded fewer titles".
#[test]
#[ignore = "diagnostic: needs FMKV_IMAGE"]
fn dump_title_sets_for_an_image() {
let Ok(path) = std::env::var("FMKV_IMAGE") else {
return;
};
let mut img =
crate::io::file_sector_source::FileSectorSource::open(std::path::Path::new(&path))
.expect("open");
let fs = udf::read_filesystem(&mut img).expect("udf");
let info = crate::ifo::parse_vmg(&mut img, &fs).expect("parse_vmg");
let total: usize = info.title_sets.iter().map(|ts| ts.titles.len()).sum();
println!("title_sets={} total_titles={total}", info.title_sets.len());
for ts in &info.title_sets {
println!(" vts={} titles={}", ts.vts_number, ts.titles.len());
}
}