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