decomp-toolkit/src/util/reader.rs

256 lines
6.4 KiB
Rust

use std::{
io,
io::{Error, ErrorKind, Read, Seek, SeekFrom},
};
use io::Write;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Endian {
Big,
Little,
}
pub const DYNAMIC_SIZE: usize = 0;
pub const fn struct_size<const N: usize>(fields: [usize; N]) -> usize {
let mut result = 0;
let mut i = 0;
while i < N {
let size = fields[i];
if size == DYNAMIC_SIZE {
// Dynamically sized
return DYNAMIC_SIZE;
}
result += size;
i += 1;
}
result
}
#[inline]
pub fn skip_bytes<const N: usize, R>(reader: &mut R) -> io::Result<()>
where R: Read + Seek + ?Sized {
reader.seek(SeekFrom::Current(N as i64))?;
Ok(())
}
pub trait FromReader: Sized {
type Args;
const STATIC_SIZE: usize;
fn from_reader_args<R>(reader: &mut R, e: Endian, args: Self::Args) -> io::Result<Self>
where R: Read + Seek + ?Sized;
fn from_reader<R>(reader: &mut R, e: Endian) -> io::Result<Self>
where
R: Read + Seek + ?Sized,
Self::Args: Default,
{
Self::from_reader_args(reader, e, Default::default())
}
}
macro_rules! impl_from_reader {
($($t:ty),*) => {
$(
impl FromReader for $t {
const STATIC_SIZE: usize = std::mem::size_of::<Self>();
type Args = ();
#[inline]
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
where R: Read + Seek + ?Sized {
let mut buf = [0u8; Self::STATIC_SIZE];
reader.read_exact(&mut buf)?;
Ok(match e {
Endian::Big => Self::from_be_bytes(buf),
Endian::Little => Self::from_le_bytes(buf),
})
}
}
)*
};
}
impl_from_reader!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
impl<const N: usize> FromReader for [u8; N] {
type Args = ();
const STATIC_SIZE: usize = N;
#[inline]
fn from_reader_args<R>(reader: &mut R, _e: Endian, _args: Self::Args) -> io::Result<Self>
where R: Read + Seek + ?Sized {
let mut buf = [0u8; N];
reader.read_exact(&mut buf)?;
Ok(buf)
}
}
impl<const N: usize> FromReader for [u32; N] {
type Args = ();
const STATIC_SIZE: usize = N * u32::STATIC_SIZE;
#[inline]
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
where R: Read + Seek + ?Sized {
let mut buf = [0u32; N];
reader.read_exact(unsafe {
std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, Self::STATIC_SIZE)
})?;
if e == Endian::Big {
for x in buf.iter_mut() {
*x = u32::from_be(*x);
}
}
Ok(buf)
}
}
#[inline]
pub fn read_bytes<R>(reader: &mut R, count: usize) -> io::Result<Vec<u8>>
where R: Read + Seek + ?Sized {
let mut buf = vec![0u8; count];
reader.read_exact(&mut buf)?;
Ok(buf)
}
#[inline]
pub fn read_vec<T, R>(reader: &mut R, count: usize, e: Endian) -> io::Result<Vec<T>>
where
T: FromReader,
T::Args: Default,
R: Read + Seek + ?Sized,
{
let mut vec = Vec::with_capacity(count);
for _ in 0..count {
vec.push(T::from_reader(reader, e)?);
}
Ok(vec)
}
#[inline]
pub fn read_vec_args<T, R>(
reader: &mut R,
count: usize,
e: Endian,
args: T::Args,
) -> io::Result<Vec<T>>
where
T: FromReader,
T::Args: Clone,
R: Read + Seek + ?Sized,
{
let mut vec = Vec::with_capacity(count);
for _ in 0..count {
vec.push(T::from_reader_args(reader, e, args.clone())?);
}
Ok(vec)
}
#[inline]
pub fn read_string<T, R>(reader: &mut R, e: Endian) -> io::Result<String>
where
T: FromReader + TryInto<usize>,
T::Args: Default,
R: Read + Seek + ?Sized,
{
let len = <T>::from_reader(reader, e)?
.try_into()
.map_err(|_| Error::new(ErrorKind::InvalidData, "invalid string length"))?;
let mut buf = vec![0u8; len];
reader.read_exact(&mut buf)?;
String::from_utf8(buf).map_err(|e| Error::new(ErrorKind::InvalidData, e))
}
pub trait ToWriter: Sized {
fn to_writer<W>(&self, writer: &mut W, e: Endian) -> io::Result<()>
where W: Write + ?Sized;
#[inline]
fn to_writer_static<W>(&self, writer: &mut W, e: Endian) -> io::Result<()>
where W: Write + ?Sized {
writer.write_all(&self.to_bytes(e)?)
}
fn to_bytes(&self, e: Endian) -> io::Result<Vec<u8>> {
let mut buf = vec![0u8; self.write_size()];
self.to_writer(&mut buf.as_mut_slice(), e)?;
Ok(buf)
}
fn write_size(&self) -> usize;
}
macro_rules! impl_to_writer {
($($t:ty),*) => {
$(
impl ToWriter for $t {
fn to_writer<W>(&self, writer: &mut W, e: Endian) -> io::Result<()>
where W: Write + ?Sized {
writer.write_all(&match e {
Endian::Big => self.to_be_bytes(),
Endian::Little => self.to_le_bytes(),
})
}
fn to_bytes(&self, e: Endian) -> io::Result<Vec<u8>> {
Ok(match e {
Endian::Big => self.to_be_bytes(),
Endian::Little => self.to_le_bytes(),
}.to_vec())
}
fn write_size(&self) -> usize {
std::mem::size_of::<Self>()
}
}
)*
};
}
impl_to_writer!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
impl<const N: usize> ToWriter for [u8; N] {
fn to_writer<W>(&self, writer: &mut W, _e: Endian) -> io::Result<()>
where W: Write + ?Sized {
writer.write_all(self)
}
fn write_size(&self) -> usize { N }
}
impl ToWriter for &[u8] {
fn to_writer<W>(&self, writer: &mut W, _e: Endian) -> io::Result<()>
where W: Write + ?Sized {
writer.write_all(self)
}
fn write_size(&self) -> usize { self.len() }
}
impl ToWriter for Vec<u8> {
fn to_writer<W>(&self, writer: &mut W, _e: Endian) -> io::Result<()>
where W: Write + ?Sized {
writer.write_all(self)
}
fn write_size(&self) -> usize { self.len() }
}
pub fn write_vec<T, W>(writer: &mut W, vec: &[T], e: Endian) -> io::Result<()>
where
T: ToWriter,
W: Write + ?Sized,
{
for item in vec {
item.to_writer(writer, e)?;
}
Ok(())
}