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