use crate::IsoError;
pub const PVD_TYPE: u8 = 0x01;
pub const SVD_TYPE: u8 = 0x02; pub const TERMINATOR_TYPE: u8 = 0xFF;
pub const BOOT_RECORD_TYPE: u8 = 0x00;
#[derive(Debug, Clone)]
pub struct PrimaryVolumeDescriptor {
pub volume_label: String,
pub root_dir_lba: u32,
pub root_dir_size: u32,
pub volume_space_size: u32,
}
impl PrimaryVolumeDescriptor {
pub fn parse(sector: &[u8]) -> Result<Self, IsoError> {
if sector.len() < 156 + 34 {
return Err(IsoError::BadDescriptor("sector too short".into()));
}
if §or[1..6] != b"CD001" {
return Err(IsoError::BadDescriptor("missing CD001 signature".into()));
}
if sector[0] != PVD_TYPE {
return Err(IsoError::BadDescriptor(format!(
"expected type 0x01, got 0x{:02x}",
sector[0]
)));
}
if sector[6] != 0x01 {
return Err(IsoError::BadDescriptor(format!(
"expected version 0x01, got 0x{:02x}",
sector[6]
)));
}
let volume_label = std::str::from_utf8(§or[40..72])
.unwrap_or("")
.trim_end()
.to_string();
let volume_space_size = u32::from_le_bytes(sector[80..84].try_into().unwrap());
let root = §or[156..190];
let root_dir_lba = u32::from_le_bytes(root[2..6].try_into().unwrap());
let root_dir_size = u32::from_le_bytes(root[10..14].try_into().unwrap());
Ok(Self {
volume_label,
root_dir_lba,
root_dir_size,
volume_space_size,
})
}
}
#[derive(Debug, Clone)]
pub struct SupplementaryVolumeDescriptor {
pub is_joliet: bool,
pub volume_label: String,
pub root_dir_lba: u32,
pub root_dir_size: u32,
}
impl SupplementaryVolumeDescriptor {
pub fn parse(sector: &[u8]) -> Result<Self, IsoError> {
if sector.len() < 190 {
return Err(IsoError::BadDescriptor("SVD sector too short".into()));
}
if §or[1..6] != b"CD001" || sector[0] != SVD_TYPE {
return Err(IsoError::BadDescriptor("not a Supplementary VD".into()));
}
let esc = §or[88..120];
let is_joliet = esc
.windows(3)
.any(|w| w == b"%/@" || w == b"%/B" || w == b"%/C" || w == b"%/E");
let volume_label = if is_joliet {
decode_ucs2be(§or[40..72])
} else {
std::str::from_utf8(§or[40..72])
.unwrap_or("")
.trim_end()
.to_string()
};
let root = §or[156..190];
let root_dir_lba = u32::from_le_bytes(root[2..6].try_into().unwrap());
let root_dir_size = u32::from_le_bytes(root[10..14].try_into().unwrap());
Ok(Self {
is_joliet,
volume_label,
root_dir_lba,
root_dir_size,
})
}
}
pub(crate) fn decode_ucs2be(bytes: &[u8]) -> String {
bytes
.chunks_exact(2)
.map_while(|w| {
let cp = u16::from_be_bytes([w[0], w[1]]);
if cp == 0 {
None
} else {
char::from_u32(u32::from(cp))
}
})
.collect::<String>()
.trim_end()
.to_string()
}