• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::io::Read;
6 use std::mem::size_of;
7 
8 #[derive(Debug)]
9 pub enum Error {
10     ReadStruct,
11 }
12 pub type Result<T> = std::result::Result<T, Error>;
13 
14 /// Reads a struct from an input buffer.
15 ///
16 /// # Arguments
17 ///
18 /// * `f` - The input to read from.  Often this is a file.
19 /// * `out` - The struct to fill with data read from `f`.
20 ///
21 /// # Safety
22 ///
23 /// This is unsafe because the struct is initialized to unverified data read from the input.
24 /// `read_struct` should only be called to fill plain old data structs.  It is not endian safe.
read_struct<T: Copy, F: Read>(f: &mut F, out: &mut T) -> Result<()>25 pub unsafe fn read_struct<T: Copy, F: Read>(f: &mut F, out: &mut T) -> Result<()> {
26     let out_slice = std::slice::from_raw_parts_mut(out as *mut T as *mut u8, size_of::<T>());
27     f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?;
28     Ok(())
29 }
30 
31 /// Reads an array of structs from an input buffer.  Returns a Vec of structs initialized with data
32 /// from the specified input.
33 ///
34 /// # Arguments
35 ///
36 /// * `f` - The input to read from.  Often this is a file.
37 /// * `len` - The number of structs to fill with data read from `f`.
38 ///
39 /// # Safety
40 ///
41 /// This is unsafe because the structs are initialized to unverified data read from the input.
42 /// `read_struct_slice` should only be called for plain old data structs.  It is not endian safe.
read_struct_slice<T: Copy, F: Read>(f: &mut F, len: usize) -> Result<Vec<T>>43 pub unsafe fn read_struct_slice<T: Copy, F: Read>(f: &mut F, len: usize) -> Result<Vec<T>> {
44     let mut out: Vec<T> = Vec::with_capacity(len);
45     out.set_len(len);
46     let out_slice =
47         std::slice::from_raw_parts_mut(out.as_ptr() as *mut T as *mut u8, size_of::<T>() * len);
48     f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?;
49     Ok(out)
50 }
51 
52 #[cfg(test)]
53 mod test {
54     use super::*;
55     use std::io::Cursor;
56     use std::mem;
57 
58     #[derive(Clone, Copy, Debug, Default, PartialEq)]
59     struct TestRead {
60         a: u64,
61         b: u8,
62         c: u8,
63         d: u8,
64         e: u8,
65     }
66 
67     #[test]
struct_basic_read()68     fn struct_basic_read() {
69         let orig = TestRead {
70             a: 0x7766554433221100,
71             b: 0x88,
72             c: 0x99,
73             d: 0xaa,
74             e: 0xbb,
75         };
76         let source = unsafe {
77             // Don't worry it's a test
78             std::slice::from_raw_parts(
79                 &orig as *const _ as *const u8,
80                 std::mem::size_of::<TestRead>(),
81             )
82         };
83         assert_eq!(mem::size_of::<TestRead>(), mem::size_of_val(&source));
84         let mut tr: TestRead = Default::default();
85         unsafe {
86             read_struct(&mut Cursor::new(source), &mut tr).unwrap();
87         }
88         assert_eq!(orig, tr);
89     }
90 
91     #[test]
struct_read_past_end()92     fn struct_read_past_end() {
93         let orig = TestRead {
94             a: 0x7766554433221100,
95             b: 0x88,
96             c: 0x99,
97             d: 0xaa,
98             e: 0xbb,
99         };
100         let source = unsafe {
101             // Don't worry it's a test
102             std::slice::from_raw_parts(
103                 &orig as *const _ as *const u8,
104                 std::mem::size_of::<TestRead>() - 1,
105             )
106         };
107         let mut tr: TestRead = Default::default();
108         unsafe {
109             assert!(read_struct(&mut Cursor::new(source), &mut tr).is_err());
110         }
111     }
112 
113     #[test]
struct_slice_read()114     fn struct_slice_read() {
115         let orig = vec![
116             TestRead {
117                 a: 0x7766554433221100,
118                 b: 0x88,
119                 c: 0x99,
120                 d: 0xaa,
121                 e: 0xbb,
122             },
123             TestRead {
124                 a: 0x7867564534231201,
125                 b: 0x02,
126                 c: 0x13,
127                 d: 0x24,
128                 e: 0x35,
129             },
130             TestRead {
131                 a: 0x7a69584736251403,
132                 b: 0x04,
133                 c: 0x15,
134                 d: 0x26,
135                 e: 0x37,
136             },
137         ];
138         let source = unsafe {
139             // Don't worry it's a test
140             std::slice::from_raw_parts(
141                 orig.as_ptr() as *const u8,
142                 std::mem::size_of::<TestRead>() * 3,
143             )
144         };
145 
146         let tr: Vec<TestRead> = unsafe { read_struct_slice(&mut Cursor::new(source), 3).unwrap() };
147         assert_eq!(orig, tr);
148     }
149 }
150