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