use std::path::Path;
use crate::{FormatPlugin, PhysicalMemoryProvider, PhysicalRange, Result};
#[derive(Debug)]
pub struct RawProvider {
data: Vec<u8>,
ranges: Vec<PhysicalRange>,
}
impl RawProvider {
pub fn from_bytes(bytes: &[u8]) -> Self {
let data = bytes.to_vec();
let ranges = if data.is_empty() {
vec![]
} else {
vec![PhysicalRange {
start: 0,
end: data.len() as u64,
}]
};
Self { data, ranges }
}
pub fn from_path(path: &Path) -> Result<Self> {
let data = std::fs::read(path)?;
Ok(Self::from_bytes(&data))
}
}
impl PhysicalMemoryProvider for RawProvider {
fn read_phys(&self, addr: u64, buf: &mut [u8]) -> Result<usize> {
if buf.is_empty() {
return Ok(0);
}
let data_len = self.data.len() as u64;
if addr >= data_len {
return Ok(0);
}
let src_start = addr as usize;
let available = self.data.len() - src_start;
let to_read = buf.len().min(available);
buf[..to_read].copy_from_slice(&self.data[src_start..src_start + to_read]);
Ok(to_read)
}
fn ranges(&self) -> &[PhysicalRange] {
&self.ranges
}
fn format_name(&self) -> &str {
"Raw"
}
}
pub struct RawPlugin;
impl FormatPlugin for RawPlugin {
fn name(&self) -> &str {
"Raw"
}
fn probe(&self, header: &[u8]) -> u8 {
if header.is_empty() {
0
} else {
5
}
}
fn open(&self, path: &Path) -> Result<Box<dyn PhysicalMemoryProvider>> {
Ok(Box::new(RawProvider::from_path(path)?))
}
}
inventory::submit!(&RawPlugin as &dyn FormatPlugin);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn probe_confidence() {
let plugin = RawPlugin;
assert_eq!(plugin.probe(&[0u8; 64]), 5);
assert_eq!(plugin.probe(&[]), 0);
}
#[test]
fn read_from_start() {
let data: Vec<u8> = (0u8..=255).collect();
let provider = RawProvider::from_bytes(&data);
assert_eq!(provider.ranges().len(), 1);
assert_eq!(provider.ranges()[0].start, 0);
assert_eq!(provider.ranges()[0].end, 256);
assert_eq!(provider.total_size(), 256);
let mut buf = [0u8; 4];
let n = provider.read_phys(0, &mut buf).unwrap();
assert_eq!(n, 4);
assert_eq!(&buf, &[0, 1, 2, 3]);
}
#[test]
fn read_past_end() {
let data = vec![0xFFu8; 64];
let provider = RawProvider::from_bytes(&data);
let mut buf = [0u8; 4];
let n = provider.read_phys(64, &mut buf).unwrap();
assert_eq!(n, 0);
let n2 = provider.read_phys(1000, &mut buf).unwrap();
assert_eq!(n2, 0);
}
#[test]
fn read_partial() {
let data = vec![0xABu8; 10];
let provider = RawProvider::from_bytes(&data);
let mut buf = [0u8; 8];
let n = provider.read_phys(6, &mut buf).unwrap();
assert_eq!(n, 4); assert_eq!(&buf[..4], &[0xABu8; 4]);
}
#[test]
fn empty_dump() {
let provider = RawProvider::from_bytes(&[]);
assert_eq!(provider.ranges().len(), 0);
assert_eq!(provider.total_size(), 0);
}
#[test]
fn from_path_roundtrip() {
let data: Vec<u8> = (0u8..=127).collect();
let path = std::env::temp_dir().join("memf_test_raw_from_path.raw");
std::fs::write(&path, &data).unwrap();
let provider = RawProvider::from_path(&path).unwrap();
assert_eq!(provider.ranges().len(), 1);
assert_eq!(provider.total_size(), 128);
assert_eq!(provider.format_name(), "Raw");
let mut buf = [0u8; 4];
let n = provider.read_phys(0, &mut buf).unwrap();
assert_eq!(n, 4);
assert_eq!(&buf, &[0, 1, 2, 3]);
std::fs::remove_file(&path).ok();
}
#[test]
fn plugin_name() {
let plugin = RawPlugin;
assert_eq!(plugin.name(), "Raw");
}
#[test]
fn read_phys_empty_buffer() {
let data = vec![0xFFu8; 64];
let provider = RawProvider::from_bytes(&data);
let mut buf = [];
let n = provider.read_phys(0, &mut buf).unwrap();
assert_eq!(n, 0);
}
}