efi_loadopt/
lib.rs

1use byteorder::{NativeEndian, ReadBytesExt};
2use std::io::Cursor;
3
4// UEFI Spec 2.8, 3.1.3.
5// TODO: add file_path_list.
6#[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}