1use super::header::{Handle, Header};
2use super::strings::*;
3use crate::structs::{DefinedStruct, SMBiosEndOfTable, SMBiosStruct};
4use serde::{Serialize, Serializer};
5use std::fmt;
6use std::{
7 convert::TryInto,
8 fs::File,
9 io::{prelude::*, Error, ErrorKind, SeekFrom},
10 slice::Iter,
11};
12#[derive(Serialize)]
27pub struct UndefinedStruct {
28 pub header: Header,
30
31 pub fields: Vec<u8>,
49
50 #[serde(serialize_with = "ser_strings")]
52 pub strings: SMBiosStringSet,
53}
54
55fn ser_strings<S>(data: &SMBiosStringSet, serializer: S) -> Result<S::Ok, S::Error>
56where
57 S: Serializer,
58{
59 serializer.serialize_str(format!("{:?}", data).as_str())
60}
61
62impl<'a> UndefinedStruct {
63 pub fn new(raw: &Vec<u8>) -> Self {
65 match raw.get(Header::LENGTH_OFFSET) {
66 Some(&header_length) => UndefinedStruct {
67 header: Header::new(raw[..Header::SIZE].try_into().expect("4 bytes")),
68 fields: raw.get(..(header_length as usize)).unwrap_or(&[]).to_vec(),
69 strings: {
70 SMBiosStringSet::new(
71 raw.get((header_length as usize)..raw.len() - 2)
72 .unwrap_or(&[])
73 .to_vec(),
74 )
75 },
76 },
77 None => UndefinedStruct {
78 ..Default::default()
79 },
80 }
81 }
82
83 pub fn get_field_byte(&self, offset: usize) -> Option<u8> {
85 match self.fields.get(offset..offset + 1) {
86 Some(val) => Some(val[0]),
87 None => None,
88 }
89 }
90
91 pub fn get_field_word(&self, offset: usize) -> Option<u16> {
93 match self.fields.get(offset..offset + 2) {
94 Some(val) => Some(u16::from_le_bytes(val.try_into().expect("u16 is 2 bytes"))),
95 None => None,
96 }
97 }
98
99 pub fn get_field_handle(&self, offset: usize) -> Option<Handle> {
101 match self.fields.get(offset..offset + Handle::SIZE) {
102 Some(val) => Some(Handle(u16::from_le_bytes(
103 val.try_into().expect("u16 is 2 bytes"),
104 ))),
105 None => None,
106 }
107 }
108
109 pub fn get_field_dword(&self, offset: usize) -> Option<u32> {
111 match self.fields.get(offset..offset + 4) {
112 Some(val) => Some(u32::from_le_bytes(val.try_into().expect("u32 is 4 bytes"))),
113 None => None,
114 }
115 }
116
117 pub fn get_field_qword(&self, offset: usize) -> Option<u64> {
119 match self.fields.get(offset..offset + 8) {
120 Some(val) => Some(u64::from_le_bytes(val.try_into().expect("u64 is 8 bytes"))),
121 None => None,
122 }
123 }
124
125 pub fn get_field_string(&self, offset: usize) -> SMBiosString {
132 match self.get_field_byte(offset) {
133 Some(val) => self.strings.get_string(val),
134 None => Err(SMBiosStringError::FieldOutOfBounds).into(),
135 }
136 }
137
138 pub fn get_field_data(&self, start_index: usize, end_index: usize) -> Option<&[u8]> {
143 return self.fields.get(start_index..end_index);
144 }
145
146 pub fn as_type<T: SMBiosStruct<'a>>(&'a self) -> Option<T> {
158 if T::STRUCT_TYPE == self.header.struct_type() {
159 Some(T::new(self))
160 } else {
161 None
162 }
163 }
164
165 pub fn defined_struct(&self) -> DefinedStruct<'_> {
167 self.into()
168 }
169}
170
171impl fmt::Debug for UndefinedStruct {
172 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
173 let fields = &self.fields[Header::SIZE..];
174 fmt.debug_struct(std::any::type_name::<UndefinedStruct>())
175 .field("header", &self.header)
176 .field("fields", &fields)
177 .field("strings", &self.strings)
178 .finish()
179 }
180}
181
182impl Default for UndefinedStruct {
183 fn default() -> Self {
184 let v: [u8; 4] = [0; 4];
185 UndefinedStruct {
186 header: Header::new(v),
187 fields: (&[]).to_vec(),
188 strings: { SMBiosStringSet::new((&[]).to_vec()) },
189 }
190 }
191}
192
193#[derive(Debug, Serialize)]
197pub struct UndefinedStructTable(Vec<UndefinedStruct>);
198
199impl<'a> UndefinedStructTable {
200 fn new() -> UndefinedStructTable {
201 UndefinedStructTable(Vec::new())
202 }
203
204 fn add(&mut self, elem: UndefinedStruct) {
205 self.0.push(elem);
206 }
207
208 pub fn iter(&self) -> Iter<'_, UndefinedStruct> {
210 self.0.iter()
211 }
212
213 pub fn defined_struct_iter<T>(&'a self) -> impl Iterator<Item = T> + 'a
215 where
216 T: SMBiosStruct<'a>,
217 {
218 self.iter()
219 .take_while(|undefined_struct| {
220 undefined_struct.header.struct_type() != SMBiosEndOfTable::STRUCT_TYPE
221 })
222 .filter_map(|undefined_struct| {
223 if undefined_struct.header.struct_type() == T::STRUCT_TYPE {
224 Some(T::new(undefined_struct))
225 } else {
226 None
227 }
228 })
229 }
230
231 pub fn all<T, F>(&'a self, f: F) -> bool
233 where
234 T: SMBiosStruct<'a>,
235 F: FnMut(T) -> bool,
236 {
237 self.defined_struct_iter().all(f)
238 }
239
240 pub fn any<T, F>(&'a self, f: F) -> bool
242 where
243 T: SMBiosStruct<'a>,
244 F: FnMut(T) -> bool,
245 {
246 self.defined_struct_iter().any(f)
247 }
248
249 pub fn first<T>(&'a self) -> Option<T>
251 where
252 T: SMBiosStruct<'a>,
253 {
254 self.defined_struct_iter().next()
255 }
256
257 pub fn find<T, P>(&'a self, predicate: P) -> Option<T>
259 where
260 T: SMBiosStruct<'a>,
261 P: FnMut(&T) -> bool,
262 {
263 self.defined_struct_iter().find(predicate)
264 }
265
266 pub fn find_map<A, B, F>(&'a self, f: F) -> Option<B>
268 where
269 A: SMBiosStruct<'a>,
270 F: FnMut(A) -> Option<B>,
271 {
272 self.defined_struct_iter().find_map(f)
273 }
274
275 pub fn filter<T: 'a, P: 'a>(&'a self, predicate: P) -> impl Iterator<Item = T> + 'a
277 where
278 T: SMBiosStruct<'a>,
279 P: FnMut(&T) -> bool,
280 {
281 self.defined_struct_iter().filter(predicate)
282 }
283
284 pub fn map<A: 'a, B, F: 'a>(&'a self, f: F) -> impl Iterator<Item = B> + 'a
286 where
287 A: SMBiosStruct<'a>,
288 F: FnMut(A) -> B,
289 {
290 self.defined_struct_iter().map(f)
291 }
292
293 pub fn filter_map<A: 'a, B, F: 'a>(&'a self, f: F) -> impl Iterator<Item = B> + 'a
295 where
296 A: SMBiosStruct<'a>,
297 F: FnMut(A) -> Option<B>,
298 {
299 self.defined_struct_iter().filter_map(f)
300 }
301
302 pub fn find_by_handle(&'a self, handle: &Handle) -> Option<&'a UndefinedStruct> {
306 self.iter()
307 .find(|smbios_struct| smbios_struct.header.handle() == *handle)
308 .and_then(|undefined_struct| Some(undefined_struct))
309 }
310
311 pub fn collect<T>(&'a self) -> Vec<T>
313 where
314 T: SMBiosStruct<'a>,
315 {
316 self.defined_struct_iter().collect()
317 }
318
319 pub fn try_load_from_file_offset(
321 file: &mut File,
322 table_offset: u64,
323 table_len: usize,
324 ) -> Result<Self, Error> {
325 if table_len < Header::SIZE + 2 {
326 return Err(Error::new(
327 ErrorKind::InvalidData,
328 format!("The table has an invalid size: {}", table_len),
329 ));
330 }
331
332 file.seek(SeekFrom::Start(table_offset))?;
333 let mut table = Vec::with_capacity(table_len);
334 table.resize(table_len, 0);
335 file.read_exact(&mut table)?;
336 Ok(table.into())
337 }
338}
339
340impl From<Vec<u8>> for UndefinedStructTable {
341 fn from(data: Vec<u8>) -> Self {
342 const DOUBLE_ZERO_SIZE: usize = 2usize;
343 const MIN_STRUCT_SIZE: usize = Header::SIZE + DOUBLE_ZERO_SIZE;
344 let mut result = Self::new();
345 let mut current_index = 0usize;
346
347 loop {
348 match data.get(current_index..current_index + MIN_STRUCT_SIZE) {
350 Some(min_struct) => {
351 let struct_len = min_struct[Header::LENGTH_OFFSET] as usize;
353
354 if struct_len < Header::SIZE {
356 break;
357 }
358
359 match data.get(current_index + struct_len..) {
363 Some(strings_etc) => {
364 match strings_etc
365 .windows(DOUBLE_ZERO_SIZE)
366 .position(|x| x[0] == x[1] && x[1] == 0)
367 {
368 Some(double_zero_position) => {
369 let next_index = current_index
371 + struct_len
372 + double_zero_position
373 + DOUBLE_ZERO_SIZE;
374
375 result.add(UndefinedStruct::new(
377 &data[current_index..next_index].to_vec(),
378 ));
379 current_index = next_index;
380 }
381 None => break,
382 }
383 }
384 None => break,
385 };
386 }
387 None => break,
388 }
389 }
390
391 result
392 }
393}
394
395impl IntoIterator for UndefinedStructTable {
396 type Item = UndefinedStruct;
397 type IntoIter = std::vec::IntoIter<Self::Item>;
398
399 fn into_iter(self) -> Self::IntoIter {
400 self.0.into_iter()
401 }
402}