use adler2::adler32_slice;
use super::constants::{DIGEST_DATA_SIZE, HASH_DATA_SIZE};
use crate::{Error, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EwfHashSection {
pub md5: [u8; 16],
}
impl EwfHashSection {
pub fn parse(data: &[u8]) -> Result<Self> {
if data.len() != HASH_DATA_SIZE {
return Err(Error::invalid_format(format!(
"ewf hash section must be {HASH_DATA_SIZE} bytes, got {}",
data.len()
)));
}
let stored_checksum = u32::from_le_bytes([data[32], data[33], data[34], data[35]]);
let calculated_checksum = adler32_slice(&data[..32]);
if stored_checksum != calculated_checksum {
return Err(Error::invalid_format(format!(
"ewf hash checksum mismatch: stored 0x{stored_checksum:08x}, calculated 0x{calculated_checksum:08x}"
)));
}
Ok(Self {
md5: copy_array::<16>(&data[..16])?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EwfDigestSection {
pub md5: [u8; 16],
pub sha1: [u8; 20],
}
impl EwfDigestSection {
pub fn parse(data: &[u8]) -> Result<Self> {
if data.len() < DIGEST_DATA_SIZE {
return Err(Error::invalid_format(format!(
"ewf digest section must be at least {DIGEST_DATA_SIZE} bytes, got {}",
data.len()
)));
}
let data = &data[..DIGEST_DATA_SIZE];
let stored_checksum = u32::from_le_bytes([data[76], data[77], data[78], data[79]]);
let calculated_checksum = adler32_slice(&data[..76]);
if stored_checksum != calculated_checksum {
return Err(Error::invalid_format(format!(
"ewf digest checksum mismatch: stored 0x{stored_checksum:08x}, calculated 0x{calculated_checksum:08x}"
)));
}
Ok(Self {
md5: copy_array::<16>(&data[..16])?,
sha1: copy_array::<20>(&data[16..36])?,
})
}
}
fn copy_array<const N: usize>(data: &[u8]) -> Result<[u8; N]> {
data.try_into().map_err(|_| {
Error::invalid_format(format!(
"ewf fixed-size array conversion failed: expected {N} bytes, got {}",
data.len()
))
})
}
#[cfg(test)]
mod tests {
use adler2::adler32_slice;
use super::*;
#[test]
fn parses_digest_prefix_with_trailing_bytes() {
let mut data = vec![0u8; DIGEST_DATA_SIZE + 16];
data[..16].copy_from_slice(&[0x11; 16]);
data[16..36].copy_from_slice(&[0x22; 20]);
let checksum = adler32_slice(&data[..76]);
data[76..80].copy_from_slice(&checksum.to_le_bytes());
let digest = EwfDigestSection::parse(&data).unwrap();
assert_eq!(digest.md5, [0x11; 16]);
assert_eq!(digest.sha1, [0x22; 20]);
}
}