1use std::ops::Range;
19use std::io::Cursor;
20use std::fs::File;
21use std::sync::Arc;
22use std::path::{Path, PathBuf};
23
24use byteorder::{
25 ReadBytesExt,
26 BigEndian,
27 LittleEndian
28};
29use memmap::Mmap;
30use ron_uuid::UUID;
31
32use {
33 Result,
34 Str,
35 Endianess,
36};
37
38#[derive(Clone, Debug)]
39pub enum Region {
42 Undefined{
44 address_bits: usize,
47 name: Str,
50 uuid: UUID,
53 },
54 Buffer{
56 address_bits: usize,
59 name: Str,
62 uuid: UUID,
65 offset: u64,
67 buffer: Arc<[u8]>,
69 },
70 File{
72 address_bits: usize,
75 name: Str,
78 uuid: UUID,
81 offset: u64,
83 file: Arc<Mmap>,
85 path: Option<PathBuf>,
87 file_offset: u64,
89 },
90}
91
92impl Region {
93 pub fn undefined<S, U>(name: S, address_bits: usize, uuid: U) -> Region where S: Into<Str>, U: Into<Option<UUID>> {
95 Region::Undefined{
96 address_bits: address_bits,
97 name: name.into(),
98 uuid: uuid.into().unwrap_or_default(),
99 }
100 }
101
102 pub fn from_mmap<S, O, P, U>(name: S, address_bits: usize, mmap: Mmap, path: P, file_offset: O, offset: O, uuid: U) -> Region where S: Into<Str>, O: Into<Option<u64>>, P: Into<Option<PathBuf>>, U: Into<Option<UUID>> {
104 Region::File{
105 offset: offset.into().unwrap_or(0),
106 name: name.into(),
107 file: Arc::new(mmap),
108 address_bits: address_bits,
109 uuid: uuid.into().unwrap_or_default(),
110 path: path.into(),
111 file_offset: file_offset.into().unwrap_or(0),
112 }
113 }
114
115 pub fn from_file<S, O, P, U>(name: S, address_bits: usize, fd: File, path: P, offset: O, uuid: U) -> Result<Region> where S: Into<Str>, O: Into<Option<u64>>, P: Into<Option<PathBuf>>, U: Into<Option<UUID>> {
117 Ok(Region::File{
118 offset: offset.into().unwrap_or(0),
119 name: name.into(),
120 file: Arc::new(unsafe { Mmap::map(&fd)? }),
121 address_bits: address_bits,
122 uuid: uuid.into().unwrap_or_default(),
123 path: path.into(),
124 file_offset: 0,
125 })
126 }
127
128 pub fn from_buf<S, O, B, U>(name: S, address_bits: usize, buf: B, offset: O, uuid: U) -> Region where S: Into<Str>, O: Into<Option<u64>>, B: Into<Arc<[u8]>>, U: Into<Option<UUID>> {
130 Region::Buffer{
131 offset: offset.into().unwrap_or(0),
132 name: name.into(),
133 buffer: buf.into(),
134 address_bits: address_bits,
135 uuid: uuid.into().unwrap_or_default(),
136 }
137 }
138
139 pub fn file<'a>(&'a self) -> Option<(&'a Path, u64)> {
141 match self {
142 &Region::Undefined{ .. } => None,
143 &Region::File{ ref path, file_offset, .. } =>
144 path.as_ref().map(|x| (PathBuf::as_path(x), file_offset)),
145 &Region::Buffer{ .. } => None,
146 }
147 }
148
149 pub fn name<'a>(&'a self) -> &'a Str {
151 match self {
152 &Region::Undefined{ ref name,.. } => name,
153 &Region::File{ ref name,.. } => name,
154 &Region::Buffer{ ref name,.. } => name,
155 }
156 }
157
158 pub fn rename(&mut self, new: Str) {
160 match self {
161 &mut Region::Undefined{ ref mut name,.. } => { *name = new }
162 &mut Region::File{ ref mut name,.. } => { *name = new }
163 &mut Region::Buffer{ ref mut name,.. } => { *name = new }
164 }
165 }
166
167 pub fn uuid<'a>(&'a self) -> &'a UUID {
169 match self {
170 &Region::Undefined{ ref uuid,.. } => uuid,
171 &Region::File{ ref uuid,.. } => uuid,
172 &Region::Buffer{ ref uuid,.. } => uuid,
173 }
174 }
175
176 pub fn address_bits(&self) -> usize {
178 match self {
179 &Region::Undefined{ address_bits,.. } => address_bits,
180 &Region::File{ address_bits,.. } => address_bits,
181 &Region::Buffer{ address_bits,.. } => address_bits,
182 }
183 }
184
185 pub fn defined(&self) -> Range<u64> {
187 match self {
188 &Region::Undefined{ .. } => 0..0,
189 &Region::File{ offset, ref file,.. } =>
190 offset..offset + file.len() as u64,
191 &Region::Buffer{ offset, ref buffer,.. } =>
192 offset..offset + buffer.len() as u64,
193 }
194 }
195
196 pub fn read<'a>(&'a self, start: u64, len: usize) -> Result<&'a[u8]> {
199 if !self.in_range(start..start + len as u64) { return Err("Out of range".into()); }
200 if len == 0 || !self.is_defined(start..start + len as u64) {
201 return Err("Undefined".into());
202 }
203
204 match self {
205 &Region::Undefined{ .. } => unreachable!(),
206 &Region::File{ ref file, offset,.. } => {
207 let a = ((start - offset) as usize)..((start - offset) as usize + len);
208 Ok(&file[a])
209 }
210 &Region::Buffer{ ref buffer, offset,.. } => {
211 let a = ((start - offset) as usize)..((start - offset) as usize + len);
212 Ok(&buffer[a])
213 }
214 }
215 }
216
217 pub fn try_read(&self, address: u64, buf: &mut [u8]) -> Result<usize> {
220 use std::cmp;
221
222 if !self.in_range(address..address + 1) { return Err("Out of range".into()); }
223 if !self.is_defined(address..address + 1) { return Ok(0); }
224
225 match self {
226 &Region::Undefined{ .. } if buf.len() == 0 => Ok(0),
227 &Region::Undefined{ .. } => unreachable!(),
228 &Region::File{ ref file, offset,.. } => {
229 let o = offset as usize;
230 let l = cmp::min(buf.len(), file.len());
231 let a = (address as usize - o)..(address as usize + l - o);
232
233 buf[0..l].clone_from_slice(&file[a]);
234 Ok(l)
235 }
236
237 &Region::Buffer{ ref buffer, offset,.. } => {
238 let o = offset as usize;
239 let address = address as usize - o;
240 let l = cmp::min(buf.len(), buffer.len() - address);
241 let a = (address as usize)..(address as usize + l);
242
243 buf[0..l].clone_from_slice(&buffer[a]);
244 Ok(l)
245 }
246 }
247 }
248
249 pub fn read_integer(&self, address: u64, endianess: Endianess, bytes: usize) -> Result<u64> {
252 match bytes {
253 1 => {
254 Ok(self.read(address, 1)?[0] as u64)
255 }
256 2 => {
257 let buf = self.read(address, 2)?;
258 let mut cur = Cursor::new(buf);
259
260 match endianess {
261 Endianess::Little => Ok(cur.read_u16::<LittleEndian>()? as u64),
262 Endianess::Big => Ok(cur.read_u16::<BigEndian>()? as u64),
263 }
264 }
265 4 => {
266 let buf = self.read(address, 4)?;
267 let mut cur = Cursor::new(buf);
268
269 match endianess {
270 Endianess::Little => Ok(cur.read_u32::<LittleEndian>()? as u64),
271 Endianess::Big => Ok(cur.read_u32::<BigEndian>()? as u64),
272 }
273 }
274 8 => {
275 let buf = self.read(address, 8)?;
276 let mut cur = Cursor::new(buf);
277
278 match endianess {
279 Endianess::Little => cur.read_u64::<LittleEndian>().map_err(|e| e.into()),
280 Endianess::Big => cur.read_u64::<BigEndian>().map_err(|e| e.into()),
281 }
282 }
283 _ => Err(format!("reaidng a {} byte integer is unimplemented",bytes).into()),
284 }
285 }
286
287 pub fn in_range(&self, range: Range<u64>) -> bool {
290 match self {
291 &Region::Undefined{ address_bits,.. } => {
292 64 - range.start.leading_zeros() as usize <= address_bits &&
293 64 - range.end.saturating_sub(1).leading_zeros() as usize <= address_bits
294 }
295 &Region::Buffer{ address_bits,.. } => {
296 64 - range.start.leading_zeros() as usize <= address_bits &&
297 64 - range.end.saturating_sub(1).leading_zeros() as usize <= address_bits
298 }
299 &Region::File{ address_bits,.. } => {
300 64 - range.start.leading_zeros() as usize <= address_bits &&
301 64 - range.end.saturating_sub(1).leading_zeros() as usize <= address_bits
302 }
303 }
304 }
305
306 pub fn is_defined(&self, range: Range<u64>) -> bool {
309 match self {
310 &Region::Undefined{ .. } => false,
311 &Region::Buffer{ ref buffer, offset, address_bits,.. } => {
312 let end = if address_bits < 64 { 1 << address_bits } else { 0xFFFFFFFFFFFFFFFF };
313 let head = 0..offset;
314 let tail = offset + (buffer.len() as u64)..end;
315 let outside = head.end > range.start || tail.start < range.end;
316
317 !outside
318 }
319 &Region::File{ ref file, offset, address_bits,.. } => {
320 let end = if address_bits < 64 { 1 << address_bits } else { 0xFFFFFFFFFFFFFFFF };
321 let head = 0..offset;
322 let tail = offset + (file.len() as u64)..end;
323 let outside = head.end > range.start || tail.start < range.end;
324
325 !outside
326 }
327 }
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334
335 #[test]
336 fn construct() {
337 let b: Box<[u8]> = vec![1, 2, 3].into();
338 let l1 = Region::undefined("l1",6,None);
339 let l2 = Region::from_buf("l2",3,b,None,None);
340
341 assert_eq!(l1.defined(), 0..0);
342 assert_eq!(l2.defined(), 0..3);
343 assert_eq!(l1.address_bits(), 6);
344 assert_eq!(l1.name(), "l1");
345 assert_eq!(l2.address_bits(), 3);
346 assert_eq!(l2.name(), "l2");
347 }
348
349 #[test]
350 fn is_defined() {
351 let b: Box<[u8]> = vec![1, 2, 3].into();
352 let l1 = Region::from_buf("l2",16,b,5,None);
353
354 assert_eq!(l1.defined(), 5..8);
355 assert_eq!(l1.is_defined(0..1), false);
356 assert!(l1.try_read(0, &mut vec![0u8; 1]).is_ok());
357 assert_eq!(l1.is_defined(0..5), false);
358 assert!(l1.try_read(0, &mut vec![0u8; 4]).is_ok());
359 assert_eq!(l1.is_defined(3..7), false);
360 assert!(l1.try_read(3, &mut vec![0u8; 4]).is_ok());
361 assert_eq!(l1.is_defined(5..6), true);
362 assert!(l1.try_read(5, &mut vec![0u8; 1]).is_ok());
363 assert_eq!(l1.is_defined(5..8), true);
364 assert!(l1.try_read(5, &mut vec![0u8; 3]).is_ok());
365 assert_eq!(l1.is_defined(9..20), false);
366 assert!(l1.try_read(9, &mut vec![0u8; 10]).is_ok());
367 }
368
369 #[test]
370 fn in_range() {
371 let b: Box<[u8]> = vec![1, 2, 3].into();
372 let l1 = Region::from_buf("l2",16,b,0,None);
373
374 assert_eq!(l1.defined(), 0..3);
375 assert_eq!(l1.in_range(0..1), true);
376 assert!(l1.try_read(0, &mut vec![0u8; 1]).is_ok());
377 assert_eq!(l1.in_range(0x10000..0x10001), false);
378 assert_eq!(l1.in_range(3..0x1_00_00), true);
379 assert_eq!(l1.in_range(5..0x10001), false);
380 }
381
382 #[test]
383 fn read() {
384 let b: Box<[u8]> = vec![1, 2, 3].into();
385 let l1 = Region::from_buf("l2",3,b,None,None);
386
387 {
388 let buf = l1.read(0, 1).unwrap();
389 assert_eq!(buf, [1]);
390 }
391
392 {
393 let buf = l1.read(2, 1).unwrap();
394 assert_eq!(buf, [3]);
395 }
396
397 {
398 let buf = l1.read(1, 2).unwrap();
399 assert_eq!(buf, [2,3]);
400 }
401 }
402
403 #[test]
404 fn try_read() {
405 let b: Box<[u8]> = vec![1, 2, 3].into();
406 let l1 = Region::from_buf("l2",3,b,None,None);
407
408 {
409 let mut buf = [0u8; 3];
410 assert_eq!(l1.try_read(0, &mut buf).ok(), Some(3));
411 assert_eq!(buf, [1, 2, 3]);
412 }
413
414 {
415 let mut buf = [0u8; 3];
416 assert_eq!(l1.try_read(2, &mut buf).ok(), Some(1));
417 assert_eq!(buf, [3, 0, 0]);
418 }
419
420 {
421 let mut buf = [0u8; 3];
422 assert_eq!(l1.try_read(1, &mut buf).ok(), Some(2));
423 assert_eq!(buf, [2, 3, 0]);
424 }
425 }
426}