1use byteorder::{LittleEndian, ReadBytesExt};
2
3#[derive(Debug, thiserror::Error)]
4pub enum StringParseError {
5 #[error("Buffer read error: {}", 0)]
7 Read(std::io::Error),
8 #[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
30pub 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]; let data_slice = &mut &data[..];
43
44 assert_eq!(read_nt_utf16_string(data_slice)?, "abc");
46
47 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]; 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}