1pub const PVD_LBA: u32 = 16;
10
11pub fn root_directory(pvd: &[u8]) -> Option<(u32, u32)> {
13 if pvd.len() < 190 || pvd[0] != 1 || &pvd[1..6] != b"CD001" {
14 return None;
15 }
16 let rec = &pvd[156..190];
17 Some((le32(&rec[2..6]), le32(&rec[10..14])))
18}
19
20pub fn find_in_directory(sector: &[u8], name: &str) -> Option<(u32, u32)> {
23 let mut at = 0;
24 while at + 33 <= sector.len() {
25 let len = sector[at] as usize;
26 if len == 0 {
27 break;
28 }
29 if at + len > sector.len() {
30 break;
31 }
32 let rec = §or[at..at + len];
33 let name_len = rec[32] as usize;
34 if 33 + name_len <= len {
35 let raw = &rec[33..33 + name_len];
36 let base = match raw.iter().position(|&b| b == b';') {
37 Some(p) => &raw[..p],
38 None => raw,
39 };
40 if base.eq_ignore_ascii_case(name.as_bytes()) {
41 return Some((le32(&rec[2..6]), le32(&rec[10..14])));
42 }
43 }
44 at += len;
45 }
46 None
47}
48
49fn le32(b: &[u8]) -> u32 {
50 u32::from_le_bytes([b[0], b[1], b[2], b[3]])
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 fn record(name: &[u8], lba: u32, size: u32) -> [u8; 48] {
58 let mut r = [0u8; 48];
59 let len = 33 + name.len() + (name.len() + 1) % 2;
60 r[0] = len as u8;
61 r[2..6].copy_from_slice(&lba.to_le_bytes());
62 r[10..14].copy_from_slice(&size.to_le_bytes());
63 r[32] = name.len() as u8;
64 r[33..33 + name.len()].copy_from_slice(name);
65 r
66 }
67
68 #[test]
69 fn finds_file_by_name() {
70 let mut dir = [0u8; 2048];
71 let mut at = 0;
72 for (name, lba, size) in [
73 (&b"\0"[..], 20, 2048),
74 (b"PSX.EXE;1", 22, 90000),
75 (b"MOVIE.STR;1", 70, 81920),
76 ] {
77 let r = record(name, lba, size);
78 let len = r[0] as usize;
79 dir[at..at + len].copy_from_slice(&r[..len]);
80 at += len;
81 }
82 assert_eq!(find_in_directory(&dir, "movie.str"), Some((70, 81920)));
83 assert_eq!(find_in_directory(&dir, "NOPE.STR"), None);
84 }
85
86 #[test]
87 fn reads_root_from_pvd() {
88 let mut pvd = [0u8; 2048];
89 pvd[0] = 1;
90 pvd[1..6].copy_from_slice(b"CD001");
91 pvd[156 + 2..156 + 6].copy_from_slice(&20u32.to_le_bytes());
92 pvd[156 + 10..156 + 14].copy_from_slice(&2048u32.to_le_bytes());
93 assert_eq!(root_directory(&pvd), Some((20, 2048)));
94 }
95}