cd_da_reader/
parse_toc.rs1use crate::{Toc, Track};
2
3pub(crate) fn parse_toc(data: Vec<u8>) -> std::io::Result<Toc> {
4 if data.len() < 4 {
11 return Err(std::io::Error::new(
12 std::io::ErrorKind::InvalidData,
13 "TOC data too short",
14 ));
15 }
16
17 let toc_length = u16::from_be_bytes([data[0], data[1]]) as usize;
18 let first_track = data[2];
19 let last_track = data[3];
20
21 let mut tracks = vec![];
22 let mut offset = 4;
23
24 let mut lead_out_lba: Option<u32> = None;
25
26 while offset + 8 <= data.len() && offset < toc_length + 2 {
27 let track_num = data[offset + 2];
28 let control = data[offset + 1];
29
30 let lba = u32::from_be_bytes([
32 data[offset + 4],
33 data[offset + 5],
34 data[offset + 6],
35 data[offset + 7],
36 ]);
37
38 let msf = lba_to_msf(lba);
39
40 if track_num != 0xAA {
41 tracks.push(Track {
42 number: track_num,
43 start_lba: lba,
44 start_msf: msf,
45 is_audio: (control & 0x04) == 0,
46 });
47 } else {
48 lead_out_lba = Some(lba);
49 }
50
51 offset += 8;
52 }
53
54 if let Some(leadout) = lead_out_lba {
55 Ok(Toc {
56 first_track,
57 last_track,
58 tracks,
59 leadout_lba: leadout,
60 })
61 } else {
62 Err(std::io::Error::new(
63 std::io::ErrorKind::InvalidData,
64 "Didn't find 0xAA",
65 ))
66 }
67}
68
69pub fn lba_to_msf(lba: u32) -> (u8, u8, u8) {
76 let total_frames = lba + 150; let minutes = (total_frames / 75 / 60) as u8;
78 let seconds = ((total_frames / 75) % 60) as u8;
79 let frames = (total_frames % 75) as u8;
80 (minutes, seconds, frames)
81}