read_data_track/
read_data_track.rs1use cd_da_reader::{CdReader, ReadOptions, SectorReadFormat};
13
14const PVD_SECTOR_OFFSET: u32 = 16;
16
17fn main() -> Result<(), Box<dyn std::error::Error>> {
18 let reader = CdReader::open_default()?;
19 let toc = reader.read_toc()?;
20
21 let data_track = toc
22 .tracks
23 .iter()
24 .find(|t| !t.is_audio)
25 .ok_or("no data track on this disc (need a mixed-mode / enhanced CD)")?;
26
27 let pvd_lba = data_track.start_lba + PVD_SECTOR_OFFSET;
28 println!(
29 "Data track #{} starts at LBA {}; reading PVD at LBA {}\n",
30 data_track.number, data_track.start_lba, pvd_lba
31 );
32
33 let mut options = ReadOptions::default().with_format(SectorReadFormat::Mode1Raw);
34
35 let raw = reader.read_sector_range(pvd_lba, 1, &options)?;
37 if raw.len() != 2352 {
38 return Err(format!("raw read returned {} bytes, expected 2352", raw.len()).into());
39 }
40
41 let sync_ok = raw[0] == 0x00 && raw[1..11].iter().all(|&b| b == 0xFF) && raw[11] == 0x00;
42 let mode = raw[15];
43 println!("raw sync pattern : {}", pass(sync_ok));
44 println!("raw sector mode : Mode {mode}");
45
46 let user_offset = match mode {
49 1 => 16,
50 2 => 24,
51 other => return Err(format!("unexpected sector mode {other}").into()),
52 };
53 let raw_user = &raw[user_offset..user_offset + 2048];
54
55 let iso_ok = raw_user[0] == 0x01 && &raw_user[1..6] == b"CD001";
56 println!("ISO 9660 'CD001' : {}", pass(iso_ok));
57
58 if mode == 1 {
61 options = options.with_format(SectorReadFormat::Mode1Cooked);
62 let cooked = reader.read_sector_range(pvd_lba, 1, &options)?;
63 if cooked.len() != 2048 {
64 return Err(
65 format!("cooked read returned {} bytes, expected 2048", cooked.len()).into(),
66 );
67 }
68 let matches_raw = cooked == raw_user;
69 println!("cooked == raw[16..]: {}", pass(matches_raw));
70
71 if sync_ok && iso_ok && matches_raw {
72 println!("\nALL CHECKS PASSED — cooked and raw data reads are correct.");
73 return Ok(());
74 }
75 } else {
76 println!(
77 "\nData track is Mode {mode} (e.g. CD-Extra / Mode 2 Form 1). The cooked path \
78 targets Mode 1, so only the raw checks apply here."
79 );
80 if sync_ok && iso_ok {
81 println!("Raw read verified against on-disc ISO structure.");
82 return Ok(());
83 }
84 }
85
86 Err("one or more verification checks FAILED — see output above".into())
87}
88
89fn pass(ok: bool) -> &'static str {
90 if ok { "PASS" } else { "FAIL" }
91}