1use std::path::Path;
7
8use crate::{FormatPlugin, PhysicalMemoryProvider, PhysicalRange, Result};
9
10#[derive(Debug)]
14pub struct RawProvider {
15 data: Vec<u8>,
16 ranges: Vec<PhysicalRange>,
18}
19
20impl RawProvider {
21 pub fn from_bytes(bytes: &[u8]) -> Self {
23 let data = bytes.to_vec();
24 let ranges = if data.is_empty() {
25 vec![]
26 } else {
27 vec![PhysicalRange {
28 start: 0,
29 end: data.len() as u64,
30 }]
31 };
32 Self { data, ranges }
33 }
34
35 pub fn from_path(path: &Path) -> Result<Self> {
37 let data = std::fs::read(path)?;
38 Ok(Self::from_bytes(&data))
39 }
40}
41
42impl PhysicalMemoryProvider for RawProvider {
43 fn read_phys(&self, addr: u64, buf: &mut [u8]) -> Result<usize> {
44 if buf.is_empty() {
45 return Ok(0);
46 }
47
48 let data_len = self.data.len() as u64;
49 if addr >= data_len {
50 return Ok(0);
51 }
52
53 let src_start = addr as usize;
54 let available = self.data.len() - src_start;
55 let to_read = buf.len().min(available);
56 buf[..to_read].copy_from_slice(&self.data[src_start..src_start + to_read]);
57 Ok(to_read)
58 }
59
60 fn ranges(&self) -> &[PhysicalRange] {
61 &self.ranges
62 }
63
64 fn format_name(&self) -> &str {
65 "Raw"
66 }
67}
68
69pub struct RawPlugin;
74
75impl FormatPlugin for RawPlugin {
76 fn name(&self) -> &str {
77 "Raw"
78 }
79
80 fn probe(&self, header: &[u8]) -> u8 {
81 if header.is_empty() {
82 0
83 } else {
84 5
85 }
86 }
87
88 fn open(&self, path: &Path) -> Result<Box<dyn PhysicalMemoryProvider>> {
89 Ok(Box::new(RawProvider::from_path(path)?))
90 }
91}
92
93inventory::submit!(&RawPlugin as &dyn FormatPlugin);
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
101 fn probe_confidence() {
102 let plugin = RawPlugin;
103 assert_eq!(plugin.probe(&[0u8; 64]), 5);
104 assert_eq!(plugin.probe(&[]), 0);
105 }
106
107 #[test]
109 fn read_from_start() {
110 let data: Vec<u8> = (0u8..=255).collect();
111 let provider = RawProvider::from_bytes(&data);
112
113 assert_eq!(provider.ranges().len(), 1);
114 assert_eq!(provider.ranges()[0].start, 0);
115 assert_eq!(provider.ranges()[0].end, 256);
116 assert_eq!(provider.total_size(), 256);
117
118 let mut buf = [0u8; 4];
119 let n = provider.read_phys(0, &mut buf).unwrap();
120 assert_eq!(n, 4);
121 assert_eq!(&buf, &[0, 1, 2, 3]);
122 }
123
124 #[test]
126 fn read_past_end() {
127 let data = vec![0xFFu8; 64];
128 let provider = RawProvider::from_bytes(&data);
129
130 let mut buf = [0u8; 4];
131 let n = provider.read_phys(64, &mut buf).unwrap();
132 assert_eq!(n, 0);
133
134 let n2 = provider.read_phys(1000, &mut buf).unwrap();
135 assert_eq!(n2, 0);
136 }
137
138 #[test]
140 fn read_partial() {
141 let data = vec![0xABu8; 10];
142 let provider = RawProvider::from_bytes(&data);
143
144 let mut buf = [0u8; 8];
145 let n = provider.read_phys(6, &mut buf).unwrap();
146 assert_eq!(n, 4); assert_eq!(&buf[..4], &[0xABu8; 4]);
148 }
149
150 #[test]
152 fn empty_dump() {
153 let provider = RawProvider::from_bytes(&[]);
154 assert_eq!(provider.ranges().len(), 0);
155 assert_eq!(provider.total_size(), 0);
156 }
157
158 #[test]
159 fn from_path_roundtrip() {
160 let data: Vec<u8> = (0u8..=127).collect();
161 let path = std::env::temp_dir().join("memf_test_raw_from_path.raw");
162 std::fs::write(&path, &data).unwrap();
163 let provider = RawProvider::from_path(&path).unwrap();
164 assert_eq!(provider.ranges().len(), 1);
165 assert_eq!(provider.total_size(), 128);
166 assert_eq!(provider.format_name(), "Raw");
167 let mut buf = [0u8; 4];
168 let n = provider.read_phys(0, &mut buf).unwrap();
169 assert_eq!(n, 4);
170 assert_eq!(&buf, &[0, 1, 2, 3]);
171 std::fs::remove_file(&path).ok();
172 }
173
174 #[test]
175 fn plugin_name() {
176 let plugin = RawPlugin;
177 assert_eq!(plugin.name(), "Raw");
178 }
179
180 #[test]
181 fn read_phys_empty_buffer() {
182 let data = vec![0xFFu8; 64];
183 let provider = RawProvider::from_bytes(&data);
184 let mut buf = [];
185 let n = provider.read_phys(0, &mut buf).unwrap();
186 assert_eq!(n, 0);
187 }
188}