use std::{
convert::TryInto,
error::Error,
io::{self, Cursor, Read},
};
pub struct ByteBuffer {
buffer: Cursor<Vec<u8>>,
}
impl ByteBuffer {
pub fn new(data: Vec<u8>) -> Self {
ByteBuffer {
buffer: Cursor::new(data),
}
}
pub fn byte_offset(&self) -> u64 {
self.buffer.position()
}
pub fn bytes_remaining(&self) -> u32 {
(self.buffer.get_ref().len() as u64 - self.buffer.position()) as u32
}
pub fn read_string(&mut self, length: usize) -> io::Result<String> {
let mut buffer = vec![0; length];
self.buffer.read_exact(&mut buffer)?;
Ok(String::from_utf8_lossy(&buffer).to_string())
}
pub fn read_string_ascii(&mut self, length: usize) -> io::Result<String> {
let mut buffer = vec![0; length];
self.buffer.read_exact(&mut buffer)?;
Ok(String::from_utf8_lossy(&buffer).to_string())
}
pub fn read_string_utf16_be(&mut self, length: usize) -> Result<String, Box<dyn Error>> {
if length % 2 != 0 {
return Err("Length must be even, as UTF-16 characters are 2 bytes".into());
}
let mut buf = vec![0; length];
self.buffer.read_exact(&mut buf)?;
let u16_buffer: Vec<u16> = buf
.chunks(2)
.map(|chunk| u16::from_be_bytes(chunk.try_into().expect("Chunk should be of length 2")))
.collect();
let s = String::from_utf16(&u16_buffer)?;
Ok(s)
}
pub fn read_uint32(&mut self) -> io::Result<u32> {
let mut buffer = [0; 4];
self.buffer.read_exact(&mut buffer)?;
Ok(u32::from_be_bytes(buffer))
}
pub fn read_uint64(&mut self) -> io::Result<u64> {
let mut buffer = [0; 8];
self.buffer.read_exact(&mut buffer)?;
Ok(u64::from_be_bytes(buffer))
}
pub fn read_uint8(&mut self) -> io::Result<u8> {
let mut buffer = [0; 1];
self.buffer.read_exact(&mut buffer)?;
Ok(buffer[0])
}
pub fn read_uint8_array(&mut self, data_length: usize) -> io::Result<Vec<u8>> {
let mut buffer = vec![0; data_length];
self.buffer.read_exact(&mut buffer)?;
Ok(buffer)
}
pub fn reset(&mut self) {
self.buffer.set_position(0);
}
pub fn skip(&mut self, next_cursor: u64) {
let new_position = self.buffer.position() + next_cursor;
self.buffer.set_position(new_position);
}
}