Skip to main content

efivar_fix/
utils.rs

1use byteorder::{LittleEndian, ReadBytesExt};
2
3#[derive(Debug, thiserror::Error)]
4pub enum StringParseError {
5    /// occurs when you get an error while reading the data
6    #[error("Buffer read error: {}", 0)]
7    Read(std::io::Error),
8    /// occurs when the bytes are not a valid UTF-16 string
9    #[error("Buffer parse error: {}", 0)]
10    Parse(std::string::FromUtf16Error),
11}
12
13pub fn read_nt_utf16_string(cursor: &mut &[u8]) -> Result<String, StringParseError> {
14    let mut vec: Vec<u16> = vec![];
15    loop {
16        match cursor
17            .read_u16::<LittleEndian>()
18            .map_err(StringParseError::Read)?
19        {
20            0x0000 => {
21                return String::from_utf16(&vec).map_err(StringParseError::Parse);
22            }
23            chr => {
24                vec.push(chr);
25            }
26        }
27    }
28}
29
30/// convert a u16 list to a u8 list (one u16 -> two u8)
31pub fn u16_to_u8(input: &[u16]) -> Vec<u8> {
32    input.iter().flat_map(|v| v.to_le_bytes()).collect()
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    #[test]
40    fn read_string() -> Result<(), StringParseError> {
41        let data: Vec<u8> = vec![b'a', 0x00, b'b', 0x00, b'c', 0x00, 0x00, 0x00, 0xFF]; // abc + null termination + a byte
42        let data_slice = &mut &data[..];
43
44        // verify extracted string is right
45        assert_eq!(read_nt_utf16_string(data_slice)?, "abc");
46
47        // verify the byte is left
48        assert_eq!(data_slice, &vec![0xFF]);
49        Ok(())
50    }
51
52    #[test]
53    fn read_string_without_nt() {
54        let data: Vec<u8> = vec![b'a', 0x00, b'b', 0x00, b'c', 0x00]; // abc
55        let data_slice = &mut &data[..];
56
57        let err = read_nt_utf16_string(data_slice).expect_err("Invalid string should return error");
58
59        if let StringParseError::Read(io_err) = err {
60            assert_eq!(io_err.kind(), std::io::ErrorKind::UnexpectedEof);
61        } else {
62            panic!("Error was not read error");
63        };
64    }
65
66    #[test]
67    fn read_string_invalid_utf16() {
68        let data: Vec<u8> = vec![0x00, 0xD8, 0x69, 0x00, 0x00, 0x00];
69        let data_slice = &mut &data[..];
70
71        let err = read_nt_utf16_string(data_slice).expect_err("Invalid string should return error");
72
73        if let StringParseError::Parse(_) = err {
74        } else {
75            panic!("Error was not parse error");
76        };
77    }
78}