use std::borrow::Cow;
use crate::constants;
use crate::error::Error;
use crate::packet::Packet;
pub(crate) struct ReadBuffer {
buf: Vec<u8>,
pos: usize,
}
impl ReadBuffer {
fn get_integer_buf_and_sign(
&mut self,
max_size: usize,
) -> Result<(&[u8], bool), Error> {
let length_byte = self.read_u8()?;
let is_negative = length_byte & 0x80 != 0;
let length = if is_negative {
length_byte & 0x7f
} else {
length_byte
};
let buf = self.read_bytes(length as usize)?;
if buf.len() > max_size {
Err(Error::integer_too_large(max_size, buf.len()))
} else {
Ok((buf, is_negative))
}
}
fn get_unsigned_integer_buf(
&mut self,
max_size: usize,
) -> Result<&[u8], Error> {
let (buf, is_negative) = self.get_integer_buf_and_sign(max_size)?;
if is_negative {
Err(Error::unexpected_negative_integer())
} else {
Ok(buf)
}
}
fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub(crate) fn from_bytes(bytes: &[u8]) -> ReadBuffer {
ReadBuffer {
buf: bytes.to_vec(),
pos: 0,
}
}
pub(crate) fn from_packets(packets: &[Packet]) -> ReadBuffer {
let mut buf = Vec::<u8>::new();
for packet in packets {
buf.extend_from_slice(&packet.buf);
}
ReadBuffer { buf, pos: 0 }
}
pub(crate) fn get_pos(&self) -> usize {
self.pos
}
pub(crate) fn read_bytes(
&mut self,
num_bytes: usize,
) -> Result<&[u8], Error> {
if self.pos + num_bytes > self.buf.len() {
Err(Error::out_of_data())
} else {
let buf = &self.buf[self.pos..self.pos + num_bytes];
self.pos += num_bytes;
Ok(buf)
}
}
pub(crate) fn read_bytes_with_double_length(
&mut self,
) -> Result<Cow<'_, [u8]>, Error> {
let num_bytes = self.read_ub4()?;
if num_bytes > 0 {
self.read_bytes_with_length()
} else {
Ok(Cow::from(&[]))
}
}
pub(crate) fn read_bytes_with_length(
&mut self,
) -> Result<Cow<'_, [u8]>, Error> {
let len = self.read_short_length()?;
if len != constants::TTC_LONG_LENGTH_INDICATOR {
Ok(Cow::from(self.read_bytes(len as usize)?))
} else {
let mut output = Vec::<u8>::new();
loop {
let num_bytes = self.read_ub4()?;
if num_bytes == 0 {
break;
}
let bytes = self.read_bytes(num_bytes as usize)?;
output.extend_from_slice(bytes);
}
Ok(Cow::from(output))
}
}
pub(crate) fn read_i8(&mut self) -> Result<i8, Error> {
let buf = self.read_bytes(1)?;
Ok(buf[0] as i8)
}
pub fn read_sb4(&mut self) -> Result<i32, Error> {
let (buf, is_negative) = self.get_integer_buf_and_sign(4)?;
let value = u32::from_buf(buf);
if is_negative {
Ok((0_i32) - (value as i32))
} else {
Ok(value as i32)
}
}
pub fn read_sb8(&mut self) -> Result<i64, Error> {
let (buf, is_negative) = self.get_integer_buf_and_sign(8)?;
let value = u64::from_buf(buf);
if is_negative {
Ok((0_i64) - (value as i64))
} else {
Ok(value as i64)
}
}
pub(crate) fn read_short_length(&mut self) -> Result<u8, Error> {
let mut short_len = self.read_u8()?;
if short_len == constants::TTC_NULL_LENGTH_INDICATOR {
short_len = 0;
}
Ok(short_len)
}
pub(crate) fn read_str_with_length(&mut self) -> Result<String, Error> {
let bytes = self.read_bytes_with_length()?.into_owned();
Ok(String::from_utf8(bytes).unwrap())
}
pub(crate) fn read_str_with_double_length(
&mut self,
) -> Result<String, Error> {
let bytes = self.read_bytes_with_double_length()?.into_owned();
Ok(String::from_utf8(bytes).unwrap())
}
pub(crate) fn read_ub2(&mut self) -> Result<u16, Error> {
let buf = self.get_unsigned_integer_buf(2)?;
Ok(u16::from_buf(buf))
}
pub(crate) fn read_ub4(&mut self) -> Result<u32, Error> {
let buf = self.get_unsigned_integer_buf(4)?;
Ok(u32::from_buf(buf))
}
pub(crate) fn read_ub8(&mut self) -> Result<u64, Error> {
let buf = self.get_unsigned_integer_buf(8)?;
Ok(u64::from_buf(buf))
}
pub(crate) fn read_u8(&mut self) -> Result<u8, Error> {
let buf = self.read_bytes(1)?;
Ok(buf[0])
}
pub(crate) fn read_u16be(&mut self) -> Result<u16, Error> {
let buf = self.read_bytes(2)?;
Ok(u16::from_be_bytes(buf.try_into().unwrap()))
}
pub(crate) fn read_u16le(&mut self) -> Result<u16, Error> {
let buf = self.read_bytes(2)?;
Ok(u16::from_le_bytes(buf.try_into().unwrap()))
}
pub(crate) fn read_u32be(&mut self) -> Result<u32, Error> {
let buf = self.read_bytes(4)?;
Ok(u32::from_be_bytes(buf.try_into().unwrap()))
}
pub(crate) fn read_value<T>(&mut self) -> Result<Option<T>, Error>
where
T: FromBuf,
{
let bytes = self.read_bytes_with_length()?;
if bytes.is_empty() {
Ok(None)
} else {
Ok(Some(<T>::from_buf(&bytes)))
}
}
pub(crate) fn read_value_lob<T>(&mut self) -> Result<Option<T>, Error>
where
T: FromBufFallible,
{
let num_bytes = self.read_ub4()?;
if num_bytes == 0 {
Ok(None)
} else {
let _size = self.read_ub8()?;
let _chunk_size = self.read_ub4()?;
let mut buf =
ReadBuffer::from_bytes(&self.read_bytes_with_length()?);
let _locator = self.read_bytes_with_length()?;
if buf.is_empty() {
Ok(None)
} else {
Ok(Some(<T>::from_buf_fallible(&mut buf)?))
}
}
}
pub(crate) fn set_pos(&mut self, pos: usize) {
self.pos = pos;
}
}
pub(crate) trait FromBuf {
fn from_buf(buf: &[u8]) -> Self;
}
impl FromBuf for bool {
fn from_buf(buf: &[u8]) -> bool {
buf[buf.len() - 1] == 1
}
}
impl FromBuf for f32 {
fn from_buf(buf: &[u8]) -> f32 {
let mut raw_bytes: [u8; 4] = [0; 4];
raw_bytes.copy_from_slice(buf);
if raw_bytes[0] & 0x80 != 0 {
raw_bytes[0] &= 0x7f;
} else {
raw_bytes[0] = !raw_bytes[0];
raw_bytes[1] = !raw_bytes[1];
raw_bytes[2] = !raw_bytes[2];
raw_bytes[3] = !raw_bytes[3];
}
f32::from_be_bytes(raw_bytes)
}
}
impl FromBuf for f64 {
fn from_buf(buf: &[u8]) -> f64 {
let mut raw_bytes: [u8; 8] = [0; 8];
raw_bytes.copy_from_slice(buf);
if raw_bytes[0] & 0x80 != 0 {
raw_bytes[0] &= 0x7f;
} else {
raw_bytes[0] = !raw_bytes[0];
raw_bytes[1] = !raw_bytes[1];
raw_bytes[2] = !raw_bytes[2];
raw_bytes[3] = !raw_bytes[3];
raw_bytes[4] = !raw_bytes[4];
raw_bytes[5] = !raw_bytes[5];
raw_bytes[6] = !raw_bytes[6];
raw_bytes[7] = !raw_bytes[7];
}
f64::from_be_bytes(raw_bytes)
}
}
impl FromBuf for u16 {
fn from_buf(buf: &[u8]) -> u16 {
match buf.len() {
0 => 0,
1 => buf[0] as u16,
_ => u16::from_be_bytes(buf.try_into().unwrap()),
}
}
}
impl FromBuf for u32 {
fn from_buf(buf: &[u8]) -> u32 {
match buf.len() {
3 => {
let first = u16::from_buf(&buf[..2]);
(first as u32) << 8 | (buf[2] as u32)
}
4 => u32::from_be_bytes(buf.try_into().unwrap()),
_ => u16::from_buf(buf) as u32,
}
}
}
impl FromBuf for u64 {
fn from_buf(buf: &[u8]) -> u64 {
match buf.len() {
5 => {
let first = u32::from_buf(&buf[..4]);
(first as u64) << 8 | (buf[4] as u64)
}
6 => {
let first = u32::from_buf(&buf[..4]);
let second = u16::from_buf(&buf[4..]);
(first as u64) << 16 | (second as u64)
}
7 => {
let first = u32::from_buf(&buf[..4]);
let second = u32::from_buf(&buf[4..]);
(first as u64) << 24 | (second as u64)
}
8 => u64::from_be_bytes(buf.try_into().unwrap()),
_ => u32::from_buf(buf) as u64,
}
}
}
pub(crate) trait FromBufFallible {
fn from_buf_fallible(buf: &mut ReadBuffer) -> Result<Self, Error>
where
Self: Sized;
}