use crate::{
error::typedstream::TypedStreamError,
util::typedstream::models::{Archivable, Class, ClassResult, OutputData, Type},
};
const I_16: u8 = 0x81;
const I_32: u8 = 0x82;
const DECIMAL: u8 = 0x83;
const START: u8 = 0x84;
const EMPTY: u8 = 0x85;
const END: u8 = 0x86;
const REFERENCE_TAG: u64 = 0x92;
#[derive(Debug)]
pub struct TypedStreamReader<'a> {
stream: &'a [u8],
idx: usize,
types_table: Vec<Vec<Type>>,
object_table: Vec<Archivable>,
placeholder: Option<usize>,
}
impl<'a> TypedStreamReader<'a> {
pub fn from(stream: &'a [u8]) -> Self {
Self {
stream,
idx: 0,
types_table: vec![],
object_table: vec![],
placeholder: None,
}
}
fn read_signed_int(&mut self) -> Result<i64, TypedStreamError> {
match self.get_current_byte()? {
I_16 => {
let size = 2;
self.idx += 1;
let value = i16::from_le_bytes(
self.read_exact_bytes(size)?
.try_into()
.map_err(TypedStreamError::SliceError)?,
);
Ok(value as i64)
}
I_32 => {
let size = 4;
self.idx += 1;
let value = i32::from_le_bytes(
self.read_exact_bytes(size)?
.try_into()
.map_err(TypedStreamError::SliceError)?,
);
Ok(value as i64)
}
_ => {
if self.get_current_byte()? > REFERENCE_TAG as u8 && self.get_next_byte()? != END {
self.idx += 1;
return self.read_signed_int();
}
let value = i8::from_le_bytes([self.get_current_byte()?]);
self.idx += 1;
Ok(value as i64)
}
}
}
fn read_unsigned_int(&mut self) -> Result<u64, TypedStreamError> {
match self.get_current_byte()? {
I_16 => {
let size = 2;
self.idx += 1;
let value = u16::from_le_bytes(
self.read_exact_bytes(size)?
.try_into()
.map_err(TypedStreamError::SliceError)?,
);
Ok(value as u64)
}
I_32 => {
let size = 4;
self.idx += 1;
let value = u32::from_le_bytes(
self.read_exact_bytes(size)?
.try_into()
.map_err(TypedStreamError::SliceError)?,
);
Ok(value as u64)
}
_ => {
let value = u8::from_le_bytes([self.get_current_byte()?]);
self.idx += 1;
Ok(value as u64)
}
}
}
fn read_float(&mut self) -> Result<f32, TypedStreamError> {
match self.get_current_byte()? {
DECIMAL => {
let size = 4;
self.idx += 1;
let value = f32::from_le_bytes(
self.read_exact_bytes(size)?
.try_into()
.map_err(TypedStreamError::SliceError)?,
);
Ok(value)
}
I_16 | I_32 => Ok(self.read_signed_int()? as f32),
_ => {
self.idx += 1;
Ok(self.read_signed_int()? as f32)
}
}
}
fn read_double(&mut self) -> Result<f64, TypedStreamError> {
match self.get_current_byte()? {
DECIMAL => {
let size = 8;
self.idx += 1;
let value = f64::from_le_bytes(
self.read_exact_bytes(size)?
.try_into()
.map_err(TypedStreamError::SliceError)?,
);
Ok(value)
}
I_16 | I_32 => Ok(self.read_signed_int()? as f64),
_ => {
self.idx += 1;
Ok(self.read_signed_int()? as f64)
}
}
}
fn read_exact_bytes(&mut self, n: usize) -> Result<&[u8], TypedStreamError> {
let range =
self.stream
.get(self.idx..self.idx + n)
.ok_or(TypedStreamError::OutOfBounds(
self.idx + n,
self.stream.len(),
))?;
self.idx += n;
Ok(range)
}
fn read_exact_as_string(
&mut self,
n: usize,
string: &mut String,
) -> Result<(), TypedStreamError> {
let str = std::str::from_utf8(self.read_exact_bytes(n)?)
.map_err(TypedStreamError::StringParseError)?;
string.push_str(str);
Ok(())
}
fn get_byte(&self, byte_idx: usize) -> Result<u8, TypedStreamError> {
if byte_idx < self.stream.len() {
return Ok(self.stream[byte_idx]);
}
Err(TypedStreamError::OutOfBounds(byte_idx, self.stream.len()))
}
fn get_current_byte(&self) -> Result<u8, TypedStreamError> {
self.get_byte(self.idx)
}
fn get_next_byte(&self) -> Result<u8, TypedStreamError> {
self.get_byte(self.idx + 1)
}
fn read_array(&mut self, size: usize) -> Result<Vec<u8>, TypedStreamError> {
Ok(self.read_exact_bytes(size)?.to_vec())
}
fn read_type(&mut self) -> Result<Vec<Type>, TypedStreamError> {
let length = self.read_unsigned_int()?;
let types = self.read_exact_bytes(length as usize)?;
if types.first() == Some(&0x5b) {
return Type::get_array_length(types).ok_or(TypedStreamError::InvalidArray);
}
Ok(types.iter().map(Type::from_byte).collect())
}
fn read_pointer(&mut self) -> Result<u32, TypedStreamError> {
let pointer = self.get_current_byte()?;
let result = (pointer as u32)
.checked_sub(REFERENCE_TAG as u32)
.ok_or(TypedStreamError::InvalidPointer(pointer));
self.idx += 1;
result
}
fn read_class(&mut self) -> Result<ClassResult, TypedStreamError> {
let mut out_v: Vec<Archivable> = vec![];
match self.get_current_byte()? {
START => {
while self.get_current_byte()? == START {
self.idx += 1;
}
let length = self.read_unsigned_int()?;
if length >= REFERENCE_TAG {
let index = length - REFERENCE_TAG;
return Ok(ClassResult::Index(index as usize));
}
let mut class_name = String::with_capacity(length as usize);
self.read_exact_as_string(length as usize, &mut class_name)?;
let version = self.read_unsigned_int()?;
self.types_table
.push(vec![Type::new_string(class_name.clone())]);
out_v.push(Archivable::Class(Class::new(class_name, version)));
if let ClassResult::ClassHierarchy(parent) = self.read_class()? {
out_v.extend(parent);
}
}
EMPTY => {
self.idx += 1;
}
_ => {
let index = self.read_pointer()?;
return Ok(ClassResult::Index(index as usize));
}
}
Ok(ClassResult::ClassHierarchy(out_v))
}
fn read_object(&mut self) -> Result<Option<&Archivable>, TypedStreamError> {
match self.get_current_byte()? {
START => {
match self.read_class()? {
ClassResult::Index(idx) => {
return Ok(self.object_table.get(idx));
}
ClassResult::ClassHierarchy(classes) => {
for class in classes.iter() {
self.object_table.push(class.clone())
}
}
}
Ok(None)
}
EMPTY => {
self.idx += 1;
Ok(None)
}
_ => {
let index = self.read_pointer()?;
Ok(self.object_table.get(index as usize))
}
}
}
fn read_string(&mut self) -> Result<String, TypedStreamError> {
let length = self.read_unsigned_int()?;
let mut string = String::with_capacity(length as usize);
self.read_exact_as_string(length as usize, &mut string)?;
Ok(string)
}
fn read_embedded_data(&mut self) -> Result<Option<Archivable>, TypedStreamError> {
self.idx += 1;
match self.get_type(true)? {
Some(types) => self.read_types(types),
None => Ok(None),
}
}
fn get_type(&mut self, embedded: bool) -> Result<Option<Vec<Type>>, TypedStreamError> {
match self.get_current_byte()? {
START => {
self.idx += 1;
let object_types = self.read_type()?;
if embedded {
self.object_table
.push(Archivable::Type(object_types.clone()));
}
self.types_table.push(object_types);
Ok(self.types_table.last().cloned())
}
END => {
Ok(None)
}
_ => {
while self.get_current_byte()? == self.get_next_byte()? {
self.idx += 1;
}
let ref_tag = self.read_pointer()?;
Ok(self.types_table.get(ref_tag as usize).cloned())
}
}
}
fn read_types(
&mut self,
found_types: Vec<Type>,
) -> Result<Option<Archivable>, TypedStreamError> {
let mut out_v = vec![];
let mut is_obj: bool = false;
for found_type in found_types {
match found_type {
Type::Utf8String => out_v.push(OutputData::String(self.read_string()?)),
Type::EmbeddedData => {
return self.read_embedded_data();
}
Type::Object => {
is_obj = true;
let length = self.object_table.len();
self.placeholder = Some(length);
self.object_table.push(Archivable::Placeholder);
if let Some(object) = self.read_object()? {
match object.clone() {
Archivable::Object(cls, data) => {
if !data.is_empty() {
self.object_table[length] =
Archivable::Object(cls.clone(), vec![]);
}
out_v.extend(data)
}
Archivable::Class(cls) => out_v.push(OutputData::Class(cls)),
Archivable::Data(data) => out_v.extend(data),
Archivable::Placeholder | Archivable::Type(_) => {}
}
}
}
Type::SignedInt => out_v.push(OutputData::SignedInteger(self.read_signed_int()?)),
Type::UnsignedInt => {
out_v.push(OutputData::UnsignedInteger(self.read_unsigned_int()?))
}
Type::Float => out_v.push(OutputData::Float(self.read_float()?)),
Type::Double => out_v.push(OutputData::Double(self.read_double()?)),
Type::Unknown(byte) => out_v.push(OutputData::Byte(byte)),
Type::String(s) => out_v.push(OutputData::String(s)),
Type::Array(size) => out_v.push(OutputData::Array(self.read_array(size)?)),
};
}
if let Some(spot) = self.placeholder {
if !out_v.is_empty() {
if let Some(OutputData::Class(class)) = out_v.last() {
self.object_table[spot] = Archivable::Object(class.clone(), vec![]);
} else if let Some(Archivable::Class(class)) = self.object_table.get(spot + 1) {
self.object_table[spot] = Archivable::Object(class.clone(), out_v.clone());
self.placeholder = None;
return Ok(self.object_table.get(spot).cloned());
} else if let Some(Archivable::Object(_, data)) = self.object_table.get_mut(spot) {
data.extend(out_v.clone());
self.placeholder = None;
return Ok(self.object_table.get(spot).cloned());
} else {
self.object_table[spot] = Archivable::Data(out_v.clone());
self.placeholder = None;
return Ok(self.object_table.get(spot).cloned());
}
}
}
if !out_v.is_empty() && !is_obj {
return Ok(Some(Archivable::Data(out_v.clone())));
}
Ok(None)
}
pub(crate) fn validate_header(&mut self) -> Result<(), TypedStreamError> {
let typedstream_version = self.read_unsigned_int()?;
let signature = self.read_string()?;
let system_version = self.read_signed_int()?;
if typedstream_version != 4 || signature != "streamtyped" || system_version != 1000 {
return Err(TypedStreamError::InvalidHeader);
}
Ok(())
}
pub fn parse(&mut self) -> Result<Vec<Archivable>, TypedStreamError> {
let mut out_v = vec![];
self.validate_header()?;
while self.idx < self.stream.len() {
if self.get_current_byte()? == END {
self.idx += 1;
continue;
}
if let Some(found_types) = self.get_type(false)? {
let result = self.read_types(found_types);
if let Ok(Some(res)) = result {
out_v.push(res);
}
}
}
Ok(out_v)
}
}