1use byteorder::{NativeEndian, ReadBytesExt};
2use std::io::Cursor;
3
4#[derive(Debug, PartialEq)]
7pub struct EFILoadOpt {
8 pub attributes: u32,
9 pub description: String,
10 pub optional_data: Vec<u8>,
11}
12
13#[derive(Debug, thiserror::Error)]
14pub enum DecodeError {
15 #[error("attributes: {0}")]
16 Attributes(std::io::Error),
17 #[error("file path list length: {0}")]
18 FilePathListLength(std::io::Error),
19 #[error("description reading: {0}")]
20 DescriptionReading(std::io::Error),
21 #[error("description parsing: {0}")]
22 DescriptionParsing(std::string::FromUtf16Error),
23}
24
25impl EFILoadOpt {
26 pub fn decode(buf: &[u8]) -> Result<Self, DecodeError> {
27 let mut cursor = Cursor::new(buf);
28 let attributes = cursor
29 .read_u32::<NativeEndian>()
30 .map_err(DecodeError::Attributes)?;
31 let file_path_list_length = cursor
32 .read_u16::<NativeEndian>()
33 .map_err(DecodeError::FilePathListLength)?;
34 let description_start = cursor.position() as usize;
35
36 let vec_capacity = (buf.len() - description_start + 1) >> 1;
37 let mut description_buf: Vec<u16> = Vec::with_capacity(vec_capacity);
38 loop {
39 let c = cursor
40 .read_u16::<NativeEndian>()
41 .map_err(DecodeError::DescriptionReading)?;
42 if c == 0 {
43 break;
44 }
45 description_buf.push(c);
46 }
47
48 let description =
49 String::from_utf16(&description_buf).map_err(DecodeError::DescriptionParsing)?;
50
51 let optional_data_start = cursor.position() as usize + file_path_list_length as usize;
52 let optional_data: Vec<u8> = Vec::from(&buf[optional_data_start..]);
53
54 Ok(EFILoadOpt {
55 attributes: attributes,
56 description: description,
57 optional_data: optional_data,
58 })
59 }
60}
61
62#[test]
63fn decode_test() {
64 let buf: Vec<u8> = vec![
65 1, 0, 0, 0, 98, 0, 117, 0, 98, 0, 117, 0, 110, 0, 116, 0, 117, 0, 0, 0, 4, 1, 42, 0, 6, 0,
66 0, 0, 0, 8, 132, 56, 1, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 17, 231, 186, 229, 231, 20, 31,
67 76, 149, 26, 169, 112, 74, 106, 62, 66, 2, 2, 4, 4, 52, 0, 92, 0, 69, 0, 70, 0, 73, 0, 92,
68 0, 85, 0, 66, 0, 85, 0, 78, 0, 84, 0, 85, 0, 92, 0, 83, 0, 72, 0, 73, 0, 77, 0, 88, 0, 54,
69 0, 52, 0, 46, 0, 69, 0, 70, 0, 73, 0, 0, 0, 127, 255, 4, 0, 0, 0, 66, 79,
70 ];
71 assert_eq!(
72 EFILoadOpt::decode(&buf).unwrap(),
73 EFILoadOpt {
74 attributes: 1,
75 description: "ubuntu".to_owned(),
76 optional_data: vec![0, 0, 66, 79],
77 }
78 );
79}