#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BootPlatform {
X86,
PowerPC,
Mac,
EFI,
Other(u8),
}
impl BootPlatform {
pub fn from_byte(b: u8) -> Self {
match b {
0x00 => Self::X86,
0x01 => Self::PowerPC,
0x02 => Self::Mac,
0xEF => Self::EFI,
v => Self::Other(v),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BootEntry {
pub bootable: bool,
pub media_type: u8,
pub lba: u32,
pub sector_count: u16,
pub platform: BootPlatform,
}
pub fn parse_boot_catalog(catalog: &[u8]) -> Vec<BootEntry> {
let mut entries = Vec::new();
if catalog.len() < 64 {
return entries;
}
if catalog[0] != 0x01 || catalog[30] != 0x55 || catalog[31] != 0xAA {
return entries;
}
let default_platform = BootPlatform::from_byte(catalog[1]);
let mut offset = 32;
if offset + 32 > catalog.len() {
return entries;
}
{
let e = &catalog[offset..offset + 32];
let boot_indicator = e[0];
if boot_indicator == 0x88 || boot_indicator == 0x00 {
entries.push(BootEntry {
bootable: boot_indicator == 0x88,
media_type: e[1] & 0x0F,
lba: u32::from_le_bytes(e[8..12].try_into().unwrap()),
sector_count: u16::from_le_bytes(e[6..8].try_into().unwrap()),
platform: default_platform,
});
}
}
offset += 32;
while offset + 32 <= catalog.len() {
let h = &catalog[offset..offset + 32];
let header_id = h[0];
if header_id != 0x90 && header_id != 0x91 {
break;
}
let section_platform = BootPlatform::from_byte(h[1]);
let count = u16::from_le_bytes(h[2..4].try_into().unwrap()) as usize;
offset += 32;
for _ in 0..count {
if offset + 32 > catalog.len() {
break;
}
let e = &catalog[offset..offset + 32];
let boot_indicator = e[0];
entries.push(BootEntry {
bootable: boot_indicator == 0x88,
media_type: e[1] & 0x0F,
lba: u32::from_le_bytes(e[8..12].try_into().unwrap()),
sector_count: u16::from_le_bytes(e[6..8].try_into().unwrap()),
platform: section_platform.clone(),
});
offset += 32;
}
if header_id == 0x91 {
break;
}
}
entries
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BootInfoTable {
pub pvd_lba: u32,
pub boot_file_lba: u32,
pub boot_file_len: u32,
pub checksum: u32,
}
impl BootInfoTable {
pub fn parse(sector: &[u8]) -> Option<Self> {
if sector.len() < 24 {
return None;
}
let le32 = |i: usize| u32::from_le_bytes(sector[i..i + 4].try_into().unwrap());
let pvd_lba = le32(8);
let boot_file_lba = le32(12);
let boot_file_len = le32(16);
let checksum = le32(20);
if pvd_lba == 0 && boot_file_lba == 0 && boot_file_len == 0 && checksum == 0 {
return None;
}
Some(Self { pvd_lba, boot_file_lba, boot_file_len, checksum })
}
}
pub fn boot_catalog_lba(sector: &[u8]) -> Option<u32> {
if sector.len() < 75 {
return None;
}
if sector[0] != 0x00 || §or[1..6] != b"CD001" || sector[6] != 0x01 {
return None;
}
if !sector[7..39].starts_with(b"EL TORITO SPECIFICATION") {
return None;
}
Some(u32::from_le_bytes(sector[71..75].try_into().unwrap()))
}