use crate::error::{EwfError, Result};
pub const EVF_SIGNATURE: [u8; 8] = [0x45, 0x56, 0x46, 0x09, 0x0d, 0x0a, 0xff, 0x00];
pub(crate) const FILE_HEADER_SIZE: usize = 13;
pub(crate) const SECTION_DESCRIPTOR_SIZE: usize = 76;
pub(crate) const DEFAULT_LRU_SIZE: usize = 100;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EwfFileHeader {
pub segment_number: u16,
}
impl EwfFileHeader {
pub fn parse(buf: &[u8]) -> Result<Self> {
if buf.len() < FILE_HEADER_SIZE {
return Err(EwfError::BufferTooShort {
expected: FILE_HEADER_SIZE,
got: buf.len(),
});
}
if buf[0..8] != EVF_SIGNATURE {
return Err(EwfError::InvalidSignature);
}
let segment_number = u16::from_le_bytes([buf[9], buf[10]]);
Ok(Self { segment_number })
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SectionDescriptor {
pub section_type: String,
pub next: u64,
pub section_size: u64,
pub offset: u64,
}
impl SectionDescriptor {
pub fn parse(buf: &[u8], offset: u64) -> Result<Self> {
if buf.len() < SECTION_DESCRIPTOR_SIZE {
return Err(EwfError::BufferTooShort {
expected: SECTION_DESCRIPTOR_SIZE,
got: buf.len(),
});
}
let type_end = buf[..16].iter().position(|&b| b == 0).unwrap_or(16);
let section_type = String::from_utf8_lossy(&buf[..type_end]).into_owned();
let next = u64::from_le_bytes(buf[16..24].try_into().unwrap());
let section_size = u64::from_le_bytes(buf[24..32].try_into().unwrap());
Ok(Self {
section_type,
next,
section_size,
offset,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EwfVolume {
pub chunk_count: u32,
pub sectors_per_chunk: u32,
pub bytes_per_sector: u32,
pub sector_count: u64,
}
impl EwfVolume {
pub fn parse(buf: &[u8]) -> Result<Self> {
if buf.len() < 24 {
return Err(EwfError::BufferTooShort {
expected: 24,
got: buf.len(),
});
}
let chunk_count = u32::from_le_bytes(buf[4..8].try_into().unwrap());
let sectors_per_chunk = u32::from_le_bytes(buf[8..12].try_into().unwrap());
let bytes_per_sector = u32::from_le_bytes(buf[12..16].try_into().unwrap());
let sector_count = u64::from_le_bytes(buf[16..24].try_into().unwrap());
Ok(Self {
chunk_count,
sectors_per_chunk,
bytes_per_sector,
sector_count,
})
}
pub fn chunk_size(&self) -> u64 {
self.sectors_per_chunk as u64 * self.bytes_per_sector as u64
}
pub fn total_size(&self) -> u64 {
self.bytes_per_sector as u64 * self.sector_count
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TableEntry {
pub compressed: bool,
pub chunk_offset: u32,
}
impl TableEntry {
pub fn parse(buf: &[u8]) -> Result<Self> {
if buf.len() < 4 {
return Err(EwfError::BufferTooShort {
expected: 4,
got: buf.len(),
});
}
let raw = u32::from_le_bytes(buf[..4].try_into().unwrap());
let compressed = (raw >> 31) != 0;
let chunk_offset = raw & 0x7FFF_FFFF;
Ok(Self {
compressed,
chunk_offset,
})
}
}
#[derive(Debug, Clone)]
pub(crate) struct Chunk {
pub(crate) segment_idx: usize,
pub(crate) compressed: bool,
pub(crate) offset: u64,
pub(crate) size: u64,
}