use encoding::{all::UTF_16LE, DecoderTrap, Encoding};
use crate::evtx_parser::ReadSeek;
use crate::utils::print_hexdump;
use byteorder::{LittleEndian, ReadBytesExt};
use log::{error, trace};
use std::{
cmp::min,
io::{self, Cursor, Error, ErrorKind},
};
pub fn read_len_prefixed_utf16_string<T: ReadSeek>(
stream: &mut T,
is_null_terminated: bool,
) -> io::Result<Option<String>> {
let expected_number_of_characters = stream.read_u16::<LittleEndian>()?;
let needed_bytes = (expected_number_of_characters * 2) as usize;
trace!(
"Going to read a{}string of len {} from stream",
if is_null_terminated {
" null terminated "
} else {
" "
},
expected_number_of_characters
);
read_utf16_by_size(stream, needed_bytes as u64)
.and_then(|s| {
if let Some(string) = s {
if string.len() == expected_number_of_characters as usize {
return Ok(Some(string));
} else {
error!(
"Expected string of length {}, found string of length {} - {}",
expected_number_of_characters,
string.len(),
string
);
return Err(Error::from(ErrorKind::InvalidData));
}
}
Ok(Some("".to_string()))
})
.and_then(|s| {
if is_null_terminated {
stream.read_u16::<LittleEndian>()?;
};
Ok(s)
})
}
pub fn read_utf16_by_size<T: ReadSeek>(stream: &mut T, size: u64) -> io::Result<Option<String>> {
let _p = stream.tell()? as usize;
let mut buffer = vec![0; size as usize];
let _ref_to_utf16_bytes = stream.read_exact(&mut buffer);
match size {
0 => Ok(None),
_ => match UTF_16LE.decode(&mut buffer, DecoderTrap::Strict) {
Ok(s) => Ok(Some(s)),
Err(_s) => Err(Error::from(ErrorKind::InvalidData)),
},
}
}
pub fn dump_cursor(cursor: &Cursor<&[u8]>, lookbehind: i32) {
let offset = cursor.position();
let data = cursor.get_ref();
println!("-------------------------------");
println!("Current Value {:2X}", data[offset as usize]);
let m = (offset as i32) - lookbehind;
let start = if m < 0 { 0 } else { m };
let end_of_buffer_or_default = min(100, data.len() - offset as usize);
let end = offset + end_of_buffer_or_default as u64;
print_hexdump(&data[start as usize..end as usize], 0, 'C');
println!("\n-------------------------------");
}