use std::{borrow::Borrow, io::Read, io::Write};
mod error;
mod memory;
pub use error::BinaryError;
pub use memory::memory::MemoryStream;
pub type Result<T> = std::result::Result<T, BinaryError>;
macro_rules! write_data {
($endian:expr, $value:expr, $stream:expr) => {
let data = match $endian {
Endian::Little => $value.to_le_bytes(),
Endian::Big => $value.to_be_bytes(),
};
return Ok($stream.write(&data)?);
};
}
macro_rules! read_data {
($endian:expr, $value:expr, $kind:ty) => {
let data = match $endian {
Endian::Little => <$kind>::from_le_bytes($value),
Endian::Big => <$kind>::from_be_bytes($value),
};
return Ok(data);
};
}
#[derive(PartialEq, Clone)]
pub enum Endian {
Big,
Little,
}
impl Default for Endian {
fn default() -> Self {
Self::Little
}
}
pub trait SeekStream {
fn seek(&mut self, to: usize) -> Result<usize>;
fn tell(&mut self) -> Result<usize>;
fn len(&self) -> Result<usize>;
}
pub struct BinaryReader<'a> {
pub stream: MemoryStream<'a>,
pub endian: Endian,
}
impl<'a> BinaryReader<'a> {
pub fn new_stream<'b>(stream: MemoryStream<'a>, endian: Endian) -> Self {
Self { endian, stream }
}
pub fn new_vec(buffer: &'a mut Vec<u8>, endian: Endian) -> Self {
Self {
endian,
stream: MemoryStream::new_vec(buffer),
}
}
pub fn read_string(&mut self) -> Result<String> {
let chars = if cfg!(feature = "wasm32") {
let str_len = self.read_u32()?;
let mut chars: Vec<u8> = vec![0; str_len as usize];
self.stream.read(&mut chars)?;
chars
} else {
let str_len = self.read_usize()?;
let mut chars: Vec<u8> = vec![0; str_len];
self.stream.read(&mut chars)?;
chars
};
Ok(String::from_utf8(chars)?)
}
pub fn swap_endianness(&mut self) {
if self.endian == Endian::Big {
self.endian = Endian::Little;
} else {
self.endian = Endian::Big;
}
}
pub fn read_char(&mut self) -> Result<char> {
Ok(std::char::from_u32(self.read_u32()?).ok_or_else(|| BinaryError::InvalidChar)?)
}
pub fn read_bool(&mut self) -> Result<bool> {
let value = self.read_u8()?;
Ok(value > 0)
}
pub fn read_f32(&mut self) -> Result<f32> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, f32);
}
pub fn read_f64(&mut self) -> Result<f64> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, f64);
}
#[cfg(target_arch = "wasm32")]
pub fn read_isize(&mut self) -> Result<isize> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, isize);
}
#[cfg(not(target_arch = "wasm32"))]
pub fn read_isize(&mut self) -> Result<isize> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, isize);
}
#[cfg(target_arch = "wasm32")]
pub fn read_usize(&mut self) -> Result<usize> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, usize);
}
#[cfg(not(target_arch = "wasm32"))]
pub fn read_usize(&mut self) -> Result<usize> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, usize);
}
pub fn read_u64(&mut self) -> Result<u64> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, u64);
}
pub fn read_i64(&mut self) -> Result<i64> {
let mut buffer: [u8; 8] = [0; 8];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, i64);
}
pub fn read_u32(&mut self) -> Result<u32> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, u32);
}
pub fn read_i32(&mut self) -> Result<i32> {
let mut buffer: [u8; 4] = [0; 4];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, i32);
}
pub fn read_u16(&mut self) -> Result<u16> {
let mut buffer: [u8; 2] = [0; 2];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, u16);
}
pub fn read_i16(&mut self) -> Result<i16> {
let mut buffer: [u8; 2] = [0; 2];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, i16);
}
pub fn read_u8(&mut self) -> Result<u8> {
let mut buffer: [u8; 1] = [0; 1];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, u8);
}
pub fn read_i8(&mut self) -> Result<i8> {
let mut buffer: [u8; 1] = [0; 1];
self.stream.read(&mut buffer)?;
read_data!(self.endian, buffer, i8);
}
pub fn read_bytes(&mut self, length: usize) -> Result<Vec<u8>> {
let mut buffer: Vec<u8> = vec![0; length];
self.stream.read(&mut buffer)?;
Ok(buffer)
}
pub fn read_bytes_at(&mut self, length: usize, position: usize) -> Result<Vec<u8>> {
let mut buffer: Vec<u8> = vec![0; length];
self.stream.seek(position)?;
self.stream.read(&mut buffer)?;
Ok(buffer)
}
pub fn read_big_string(&mut self) -> Result<String> {
let len = self.read_i32()? as usize;
let str = self.read_bytes(len)?;
Ok(String::from_utf8(str)?)
}
}
pub struct BinaryWriter<'a> {
pub stream: MemoryStream<'a>,
pub endian: Endian,
}
impl<'a> BinaryWriter<'a> {
pub fn new_stream<'b>(stream: MemoryStream<'b>, endian: Endian) -> Self
where
'b: 'a,
{
Self { endian, stream }
}
pub fn new_vec(stream: &'a mut Vec<u8>, endian: Endian) -> Self {
Self {
endian,
stream: MemoryStream::new_vec(stream),
}
}
pub fn write_string<S: AsRef<str>>(&mut self, value: S) -> Result<usize> {
let bytes = value.as_ref().as_bytes();
if cfg!(feature = "wasm32") {
self.write_u32(bytes.len() as u32)?;
} else {
self.write_usize(bytes.len())?;
}
Ok(self.stream.write(&bytes.to_vec())?)
}
pub fn write_char<V: Borrow<char>>(&mut self, v: V) -> Result<usize> {
self.write_u32(*v.borrow() as u32)
}
pub fn write_bool<V: Borrow<bool>>(&mut self, value: V) -> Result<usize> {
let written = self.write_u8(if *value.borrow() { 1 } else { 0 })?;
Ok(written)
}
pub fn write_f32<V: Borrow<f32>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_f64<V: Borrow<f64>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_isize<V: Borrow<isize>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_usize<V: Borrow<usize>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_u64<V: Borrow<u64>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_i64<V: Borrow<i64>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_u32<V: Borrow<u32>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_i32<V: Borrow<i32>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_u16<V: Borrow<u16>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_i16<V: Borrow<i16>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_u8<V: Borrow<u8>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_i8<V: Borrow<i8>>(&mut self, value: V) -> Result<usize> {
write_data!(self.endian, value.borrow(), self.stream);
}
pub fn write_bytes<B: AsRef<[u8]>>(&mut self, data: B) -> Result<usize> {
Ok(self.stream.write(data.as_ref())?)
}
pub fn write_bytes_at<B: AsRef<[u8]>>(&mut self, data: B, position: usize) -> Result<usize> {
self.stream.seek(position)?;
Ok(self.stream.write(data.as_ref())?)
}
pub fn write_big_string<B: AsRef<[u8]>>(
&mut self,
data: B,
position: Option<usize>,
) -> Result<usize> {
if let Some(pos) = position {
self.stream.seek(pos)?;
}
Ok(self.stream.write(data.as_ref())?)
}
pub fn write_bytes_with_value(&mut self, count: usize, fill_value: u8) -> Result<usize> {
let mut buff = Vec::with_capacity(count) as Vec<u8>;
buff.resize(count, fill_value);
Ok(self.write_bytes(buff)?)
}
pub fn swap_endianness(&mut self) {
if self.endian == Endian::Big {
self.endian = Endian::Little;
} else {
self.endian = Endian::Big;
}
}
}