cd_da_reader/data_reader/
detect.rs1use super::raw_sector::{RawSectorMode, RawSectorParseError, parse_raw_sector};
2use crate::{CdReader, CdReaderError, ReadOptions, SectorReadFormat, Track};
3
4impl CdReader {
5 pub fn detect_track_format(&self, track: &Track) -> Result<SectorReadFormat, CdReaderError> {
18 if track.is_audio {
19 return Ok(SectorReadFormat::Audio);
20 }
21
22 let information = self.drive.read_track_information(track.number)?;
23 if let Some(format) = format_from_data_mode(information.data_mode) {
24 return Ok(format);
25 }
26
27 let options = ReadOptions::default().with_format(SectorReadFormat::Mode2Raw);
28 let raw_sector = self.read_sector_range(track.start_lba, 1, &options)?;
29 format_from_raw_sector(&raw_sector).map_err(|_| CdReaderError::CannotDetectTrackFormat {
30 track_number: track.number,
31 data_mode: Some(information.data_mode),
32 })
33 }
34}
35
36fn format_from_data_mode(data_mode: u8) -> Option<SectorReadFormat> {
43 match data_mode {
44 0x01 => Some(SectorReadFormat::Mode1Cooked),
45 0x02 => Some(SectorReadFormat::Mode2Raw),
46 _ => None,
47 }
48}
49
50fn format_from_raw_sector(sector: &[u8]) -> Result<SectorReadFormat, RawSectorParseError> {
51 match parse_raw_sector(sector)?.mode {
52 RawSectorMode::Mode1 => Ok(SectorReadFormat::Mode1Cooked),
53 RawSectorMode::Mode2 => Ok(SectorReadFormat::Mode2Raw),
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 fn raw_sector(mode: u8) -> [u8; 2352] {
62 let mut sector = [0u8; 2352];
63 sector[0] = 0x00;
64 sector[1..11].fill(0xFF);
65 sector[11] = 0x00;
66 sector[15] = mode;
67 sector
68 }
69
70 #[test]
71 fn audio_tracks_do_not_require_drive_detection() {
72 let reader = CdReader::test_reader();
73 let track = Track {
74 number: 1,
75 start_lba: 0,
76 start_msf: (0, 2, 0),
77 is_audio: true,
78 };
79
80 assert_eq!(
81 reader.detect_track_format(&track).unwrap(),
82 SectorReadFormat::Audio
83 );
84 }
85
86 #[test]
87 fn maps_mode1_to_its_cooked_format() {
88 assert_eq!(
89 format_from_data_mode(0x01),
90 Some(SectorReadFormat::Mode1Cooked)
91 );
92 }
93
94 #[test]
95 fn maps_mode2_to_raw_sectors() {
96 assert_eq!(
97 format_from_data_mode(0x02),
98 Some(SectorReadFormat::Mode2Raw)
99 );
100 }
101
102 #[test]
103 fn maps_raw_sector_modes_to_supported_formats() {
104 assert_eq!(
105 format_from_raw_sector(&raw_sector(1)).unwrap(),
106 SectorReadFormat::Mode1Cooked
107 );
108 assert_eq!(
109 format_from_raw_sector(&raw_sector(2)).unwrap(),
110 SectorReadFormat::Mode2Raw
111 );
112 }
113
114 #[test]
115 fn rejects_unknown_or_reserved_mmc_data_modes() {
116 assert_eq!(format_from_data_mode(0x00), None);
117 for data_mode in 0x03..=0x0F {
118 assert_eq!(format_from_data_mode(data_mode), None);
119 }
120 }
121}