use crate::error::{UnityError, UnityResult};
use crate::math::{Matrix4x4, RectF32, Vector2, Vector3, Vector4};
#[derive(Clone, Copy)]
pub enum ByteOrder {
Big,
Little,
}
#[derive(Clone)]
pub struct Reader<'a> {
buf: &'a [u8],
offset: usize,
order: ByteOrder,
}
impl<'a> Reader<'a> {
pub fn new(buf: &'a [u8], order: ByteOrder) -> Self {
Self { buf, offset: 0, order }
}
pub fn get_offset(&self) -> usize {
self.offset
}
pub fn set_offset(&mut self, offset: usize) -> UnityResult<usize> {
if self.buf.len() < offset {
return Err(UnityError::Eof);
}
let result = self.offset;
self.offset = offset;
Ok(result)
}
pub fn set_little_order(&mut self) {
self.order = ByteOrder::Little
}
pub fn set_big_order(&mut self) {
self.order = ByteOrder::Big
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn get_order(&self) -> ByteOrder {
self.order
}
pub fn has_space(&self, length: usize) -> UnityResult<usize> {
let end = length + self.get_offset();
if self.buf.len() < end {
Err(UnityError::Eof)
} else {
Ok(end)
}
}
pub fn align(&mut self, num: usize) -> UnityResult<usize> {
let offset_before_align = self.get_offset();
let remain = offset_before_align % num;
let offset_after_align = match remain {
0 => offset_before_align,
_ => offset_before_align - remain + num,
};
if offset_after_align > self.buf.len() {
return Err(UnityError::Eof);
}
self.set_offset(offset_after_align)?;
Ok(offset_after_align)
}
pub fn read_u8_slice(&mut self, length: usize) -> UnityResult<&[u8]> {
let end = self.has_space(length)?;
let result = &self.buf[self.offset..end];
self.offset = end;
Ok(result)
}
pub fn read_u8_array<const N: usize>(&mut self) -> UnityResult<[u8; N]> {
let mut result = [0; N];
let end = self.has_space(N)?;
let slice = &self.buf[self.get_offset()..end];
result.copy_from_slice(slice);
self.offset = end;
Ok(result)
}
pub fn read_f32_array<const N: usize>(&mut self) -> UnityResult<[f32; N]> {
let mut result = [0.0; N];
let end = self.has_space(N * std::mem::size_of::<f32>())?;
for i in 0..N {
result[i] = self.read_f32()?;
}
self.offset = end;
Ok(result)
}
pub fn read_i32_array<const N: usize>(&mut self) -> UnityResult<[i32; N]> {
let mut result = [0; N];
let end = self.has_space(N * std::mem::size_of::<i32>())?;
for i in 0..N {
result[i] = self.read_i32()?;
}
self.offset = end;
Ok(result)
}
pub fn read_u8_list(&mut self, length: usize) -> UnityResult<Vec<u8>> {
Ok(self.read_u8_slice(length)?.to_vec())
}
pub fn read_u8(&mut self) -> UnityResult<u8> {
let end = self.has_space(1)?;
let result = self.buf[self.offset];
self.offset = end;
Ok(result)
}
pub fn read_bool(&mut self) -> UnityResult<bool> {
Ok(self.read_u8()? != 0)
}
pub fn read_u16(&mut self) -> UnityResult<u16> {
let a = self.read_u8_array::<2>()?;
match self.order {
ByteOrder::Big => Ok(u16::from_be_bytes(a)),
ByteOrder::Little => Ok(u16::from_le_bytes(a)),
}
}
pub fn read_u32(&mut self) -> UnityResult<u32> {
let a = self.read_u8_array::<4>()?;
match self.order {
ByteOrder::Big => Ok(u32::from_be_bytes(a)),
ByteOrder::Little => Ok(u32::from_le_bytes(a)),
}
}
pub fn read_u64(&mut self) -> UnityResult<u64> {
let a = self.read_u8_array::<8>()?;
match self.order {
ByteOrder::Big => Ok(u64::from_be_bytes(a)),
ByteOrder::Little => Ok(u64::from_le_bytes(a)),
}
}
pub fn read_i8(&mut self) -> UnityResult<i8> {
let a = self.read_u8_array::<1>()?;
Ok(i8::from_be_bytes(a))
}
pub fn read_i16(&mut self) -> UnityResult<i16> {
let a = self.read_u8_array::<2>()?;
match self.order {
ByteOrder::Big => Ok(i16::from_be_bytes(a)),
ByteOrder::Little => Ok(i16::from_le_bytes(a)),
}
}
pub fn read_i32(&mut self) -> UnityResult<i32> {
let a = self.read_u8_array::<4>()?;
match self.order {
ByteOrder::Big => Ok(i32::from_be_bytes(a)),
ByteOrder::Little => Ok(i32::from_le_bytes(a)),
}
}
pub fn read_i64(&mut self) -> UnityResult<i64> {
let a = self.read_u8_array::<8>()?;
match self.order {
ByteOrder::Big => Ok(i64::from_be_bytes(a)),
ByteOrder::Little => Ok(i64::from_le_bytes(a)),
}
}
pub fn read_f32(&mut self) -> UnityResult<f32> {
let a = self.read_u8_array::<4>()?;
match self.order {
ByteOrder::Big => Ok(f32::from_be_bytes(a)),
ByteOrder::Little => Ok(f32::from_le_bytes(a)),
}
}
pub fn read_f64(&mut self) -> UnityResult<f64> {
let a = self.read_u8_array::<8>()?;
match self.order {
ByteOrder::Big => Ok(f64::from_be_bytes(a)),
ByteOrder::Little => Ok(f64::from_le_bytes(a)),
}
}
pub fn read_7bit_u32(&mut self) -> UnityResult<u32> {
let mut out = 0u32;
let mut shift = 0u32;
loop {
let b = self.read_u8()?;
out |= ((b & 0x7f) as u32) << shift;
shift += 7;
if b & 0x80 == 0 {
break;
}
}
Ok(out)
}
pub fn read_string_util_null(&mut self) -> UnityResult<String> {
let mut ret = String::new();
loop {
let b = self.read_u8()?;
if b == 0 {
break;
} else {
ret.push(b as char);
}
}
Ok(ret)
}
pub fn read_string_util_null_with_limit(&mut self, limit: usize) -> UnityResult<String> {
let mut ret = String::new();
for _ in 0..limit {
let b = self.read_u8()?;
if b == 0 {
break;
} else {
ret.push(b as char);
}
}
Ok(ret)
}
pub fn read_string_with_length(&mut self, length: usize) -> UnityResult<String> {
let mut ret = String::with_capacity(length);
for _ in 0..length {
let b = self.read_u8()?;
ret.push(b as char);
}
Ok(ret)
}
pub fn read_string_with_7bit_length(&mut self) -> UnityResult<String> {
let length = self.read_7bit_u32()?;
self.read_string_with_length(length as usize)
}
pub fn read_aligned_string(&mut self) -> UnityResult<String> {
let this = self as *mut Self;
let length = self.read_i32()?;
let result = self.read_string_with_length(length as usize);
unsafe {
this.as_mut().unwrap().align(4)?;
}
result
}
pub fn read_i32_list(&mut self, length: usize) -> UnityResult<Vec<i32>> {
self.has_space(length)?;
let mut ret = Vec::with_capacity(length);
for _ in 0..length {
ret.push(self.read_i32()?)
}
Ok(ret)
}
pub fn read_rect_f32(&mut self) -> UnityResult<RectF32> {
Ok(RectF32 { x: self.read_f32()?, y: self.read_f32()?, w: self.read_f32()?, h: self.read_f32()? })
}
pub fn read_vector2(&mut self) -> UnityResult<Vector2> {
Ok(Vector2 { x: self.read_f32()?, y: self.read_f32()? })
}
pub fn read_vector3(&mut self) -> UnityResult<Vector3> {
Ok(Vector3 { x: self.read_f32()?, y: self.read_f32()?, z: self.read_f32()? })
}
pub fn read_vector4(&mut self) -> UnityResult<Vector4> {
Ok(Vector4 { x: self.read_f32()?, y: self.read_f32()?, z: self.read_f32()?, w: self.read_f32()? })
}
pub fn read_matrix4x4(&mut self) -> UnityResult<Matrix4x4> {
Ok(Matrix4x4 { m00: self.read_f32()?, m10: self.read_f32()?, m20: self.read_f32()?, m30: self.read_f32()?, m01: self.read_f32()?, m11: self.read_f32()?, m21: self.read_f32()?, m31: self.read_f32()?, m02: self.read_f32()?, m12: self.read_f32()?, m22: self.read_f32()?, m32: self.read_f32()?, m03: self.read_f32()?, m13: self.read_f32()?, m23: self.read_f32()?, m33: self.read_f32()? })
}
pub fn read_u16_list(&mut self, size: usize) -> UnityResult<Vec<u16>> {
let _end = self.has_space(size)?;
let mut ret = Vec::with_capacity(size);
for _ in 0..size {
ret.push(self.read_u16()?)
}
Ok(ret)
}
pub fn read_string_list(&mut self) -> UnityResult<Vec<String>> {
let length = self.read_i32()?;
let mut result = Vec::with_capacity(length as usize);
for _ in 0..length {
result.push(self.read_aligned_string()?);
}
Ok(result)
}
pub fn read_f32_list(&mut self, size: usize) -> UnityResult<Vec<f32>> {
let _end = self.has_space(size)?;
let mut ret = Vec::with_capacity(size);
for _ in 0..size {
ret.push(self.read_f32()?)
}
Ok(ret)
}
pub fn read_matrix4x4_list(&mut self, size: usize) -> UnityResult<Vec<Matrix4x4>> {
let _end = self.has_space(size)?;
let mut ret = Vec::with_capacity(size);
for _ in 0..size {
ret.push(self.read_matrix4x4()?)
}
Ok(ret)
}
}