use opticaldiscs::browse::open_disc_filesystem;
use opticaldiscs::detect::DiscImageInfo;
use opticaldiscs::formats::FilesystemType;
const SECTOR: usize = 2048;
const NSR_LSN: usize = 17; const VDS_LSN: usize = 32; const PHYS_START: u32 = 100; const META_FILE_PHYS_LBN: u32 = 0; const META_AREA_PHYS_LBN: u32 = 10; const FILE_DATA_PHYS_LBN: u32 = 20; const AVDP_LSN: usize = 256;
fn p16(b: &mut [u8], o: usize, v: u16) {
b[o..o + 2].copy_from_slice(&v.to_le_bytes());
}
fn p32(b: &mut [u8], o: usize, v: u32) {
b[o..o + 4].copy_from_slice(&v.to_le_bytes());
}
fn tag(b: &mut [u8], id: u16) {
p16(b, 0, id);
}
fn short_ad(b: &mut [u8], o: usize, len_bytes: u32, lbn: u32) {
p32(b, o, len_bytes); p32(b, o + 4, lbn);
}
fn long_ad(b: &mut [u8], o: usize, len_bytes: u32, lbn: u32, partref: u16) {
p32(b, o, len_bytes);
p32(b, o + 4, lbn);
p16(b, o + 8, partref);
}
fn file_entry(file_type: u8, adtype: u16, size: u64, l_ad: u32) -> Vec<u8> {
let mut fe = vec![0u8; SECTOR];
tag(&mut fe, 261);
fe[16 + 11] = file_type; p16(&mut fe, 16 + 18, adtype); fe[56..64].copy_from_slice(&size.to_le_bytes()); p32(&mut fe, 168, 0); p32(&mut fe, 172, l_ad); fe
}
fn fid(name: &[u8], is_dir: bool, is_parent: bool, icb_lbn: u32, icb_partref: u16) -> Vec<u8> {
let l_fi = if is_parent { 0 } else { name.len() };
let total = (38 + l_fi + 3) & !3;
let mut f = vec![0u8; total];
tag(&mut f, 257);
let mut ch = 0u8;
if is_dir {
ch |= 0x02;
}
if is_parent {
ch |= 0x08;
}
f[18] = ch;
f[19] = l_fi as u8;
long_ad(&mut f, 20, SECTOR as u32, icb_lbn, icb_partref);
p16(&mut f, 36, 0); if !is_parent {
f[38..38 + name.len()].copy_from_slice(name);
}
f
}
fn write_lsn(img: &mut [u8], lsn: usize, bytes: &[u8]) {
img[lsn * SECTOR..lsn * SECTOR + bytes.len()].copy_from_slice(bytes);
}
fn build_image() -> Vec<u8> {
let mut img = vec![0u8; 260 * SECTOR];
let mut nsr = vec![0u8; SECTOR];
nsr[1..6].copy_from_slice(b"NSR03");
write_lsn(&mut img, NSR_LSN, &nsr);
let mut avdp = vec![0u8; SECTOR];
tag(&mut avdp, 2);
p32(&mut avdp, 16, (3 * SECTOR) as u32); p32(&mut avdp, 20, VDS_LSN as u32); write_lsn(&mut img, AVDP_LSN, &avdp);
let mut pd = vec![0u8; SECTOR];
tag(&mut pd, 5);
p16(&mut pd, 22, 0); p32(&mut pd, 188, PHYS_START); p32(&mut pd, 192, 160); write_lsn(&mut img, VDS_LSN, &pd);
let mut lvd = vec![0u8; SECTOR];
tag(&mut lvd, 6);
lvd[84] = 8;
lvd[85..90].copy_from_slice(b"UDF25");
lvd[84 + 127] = 6; p32(&mut lvd, 212, SECTOR as u32); long_ad(&mut lvd, 248, SECTOR as u32, 0, 1);
p32(&mut lvd, 268, 2); lvd[440] = 1;
lvd[441] = 6;
p16(&mut lvd, 442, 1); p16(&mut lvd, 444, 0); let m = 446;
lvd[m] = 2;
lvd[m + 1] = 64;
lvd[m + 5..m + 5 + 23].copy_from_slice(b"*UDF Metadata Partition");
p16(&mut lvd, m + 38, 0); p32(&mut lvd, m + 40, META_FILE_PHYS_LBN); write_lsn(&mut img, VDS_LSN + 1, &lvd);
let mut term = vec![0u8; SECTOR];
tag(&mut term, 8);
write_lsn(&mut img, VDS_LSN + 2, &term);
let mut meta_fe = file_entry(250, 0, (8 * SECTOR) as u64, 8);
short_ad(&mut meta_fe, 176, (8 * SECTOR) as u32, META_AREA_PHYS_LBN);
write_lsn(
&mut img,
(PHYS_START + META_FILE_PHYS_LBN) as usize,
&meta_fe,
);
let meta_lsn = |n: u32| (PHYS_START + META_AREA_PHYS_LBN + n) as usize;
let mut fsd = vec![0u8; SECTOR];
tag(&mut fsd, 256);
long_ad(&mut fsd, 400, SECTOR as u32, 1, 1);
write_lsn(&mut img, meta_lsn(0), &fsd);
let mut parent = fid(&[], true, true, 1, 1);
let hello_fid = fid(&[8, b'H', b'E', b'L', b'L', b'O'], false, false, 3, 1);
let mut root_data = Vec::new();
root_data.append(&mut parent);
root_data.extend_from_slice(&hello_fid);
let mut root_fe = file_entry(4, 0, root_data.len() as u64, 8);
short_ad(&mut root_fe, 176, root_data.len() as u32, 2); write_lsn(&mut img, meta_lsn(1), &root_fe);
write_lsn(&mut img, meta_lsn(2), &root_data);
let body = b"hello udf25";
let mut hello_fe = file_entry(5, 1, body.len() as u64, 16);
long_ad(&mut hello_fe, 176, body.len() as u32, FILE_DATA_PHYS_LBN, 0);
write_lsn(&mut img, meta_lsn(3), &hello_fe);
write_lsn(&mut img, (PHYS_START + FILE_DATA_PHYS_LBN) as usize, body);
img
}
#[test]
fn udf_metadata_partition_browse() {
let img = build_image();
use std::io::Write;
let mut f = tempfile::Builder::new().suffix(".iso").tempfile().unwrap();
f.write_all(&img).unwrap();
f.flush().unwrap();
let info = DiscImageInfo::open(f.path()).expect("open");
assert_eq!(info.filesystem, FilesystemType::Udf);
let mut fs = open_disc_filesystem(&info).expect("open fs");
assert_eq!(fs.volume_name(), Some("UDF25"));
let root = fs.root().unwrap();
let entries = fs.list_directory(&root).unwrap();
let hello = entries
.iter()
.find(|e| e.name == "HELLO")
.expect("HELLO present");
assert!(!hello.is_directory());
assert_eq!(hello.size, 11);
assert_eq!(fs.read_file(hello).unwrap(), b"hello udf25");
assert_eq!(fs.read_file_range(hello, 6, 5).unwrap(), b"udf25");
}