1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use byteorder::{NativeEndian, ReadBytesExt};
use failure::Error;
use std::io::Cursor;

// UEFI Spec 2.8, 3.1.3.
// TODO: add file_path_list.
#[derive(Debug, PartialEq)]
pub struct EFILoadOpt {
    pub attributes: u32,
    pub description: String,
    pub optional_data: Vec<u8>,
}

impl EFILoadOpt {
    pub fn decode(buf: &[u8]) -> Result<Self, Error> {
        let mut cursor = Cursor::new(buf);
        let attributes = cursor.read_u32::<NativeEndian>()?;
        let file_path_list_length = cursor.read_u16::<NativeEndian>()?;
        let description_start = cursor.position() as usize;

        let vec_capacity = (buf.len() - description_start + 1) >> 1;
        let mut description_buf: Vec<u16> = Vec::with_capacity(vec_capacity);
        loop {
            let c = cursor.read_u16::<NativeEndian>()?;
            if c == 0 {
                break;
            }
            description_buf.push(c);
        }

        let description = String::from_utf16(&description_buf)?;

        let optional_data_start = cursor.position() as usize + file_path_list_length as usize;
        let optional_data: Vec<u8> = Vec::from(&buf[optional_data_start..]);

        Ok(EFILoadOpt {
            attributes: attributes,
            description: description,
            optional_data: optional_data,
        })
    }
}

#[test]
fn decode_test() {
    let buf: Vec<u8> = vec![
        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,
        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,
        76, 149, 26, 169, 112, 74, 106, 62, 66, 2, 2, 4, 4, 52, 0, 92, 0, 69, 0, 70, 0, 73, 0, 92,
        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,
        0, 52, 0, 46, 0, 69, 0, 70, 0, 73, 0, 0, 0, 127, 255, 4, 0, 0, 0, 66, 79,
    ];
    assert_eq!(
        EFILoadOpt::decode(&buf).unwrap(),
        EFILoadOpt {
            attributes: 1,
            description: "ubuntu".to_owned(),
            optional_data: vec![0, 0, 66, 79],
        }
    );
}