Maraiah/src/durandal/bin.rs

208 lines
5.3 KiB
Rust

//! Binary data conversion utilities.
use crate::durandal::err::*;
use serde::Serialize;
use std::{fmt, num::NonZeroU16};
#[doc(hidden)]
macro_rules! rd_1 {
// big endian
(BE $b:ident $nam:ident u16 $n:expr) => {
rd_1!($b u16::from_be_bytes, $nam 2 $n);
};
(BE $b:ident $nam:ident i16 $n:expr) => {
rd_1!($b i16::from_be_bytes, $nam 2 $n);
};
(BE $b:ident $nam:ident u32 $n:expr) => {
rd_1!($b u32::from_be_bytes, $nam 4 $n);
};
(BE $b:ident $nam:ident i32 $n:expr) => {
rd_1!($b i32::from_be_bytes, $nam 4 $n);
};
(BE $b:ident $nam:ident as usize u16 $n:expr) => {
rd_1!($b u16::from_be_bytes, $nam 2 $n);
let $nam = $nam as usize;
};
(BE $b:ident $nam:ident as usize u32 $n:expr) => {
rd_1!($b u32::from_be_bytes, $nam 4 $n);
let $nam = $nam as usize;
};
(BE $b:ident $nam:ident Angle $n:expr) => {
rd_1!($b u16::from_be_bytes, $nam 2 $n);
let $nam = Angle::from_bits($nam);
};
(BE $b:ident $nam:ident Fixed $n:expr) => {
rd_1!($b u32::from_be_bytes, $nam 4 $n);
let $nam = Fixed::from_bits($nam);
};
(BE $b:ident $nam:ident Unit $n:expr) => {
rd_1!($b u16::from_be_bytes, $nam 2 $n);
let $nam = Unit::from_bits($nam);
};
(BE $b:ident $nam:ident OptU16 $n:expr) => {
rd_1!($b u16::from_be_bytes, $nam 2 $n);
let $nam = OptU16::from_repr($nam);
};
// little endian
(LE $b:ident $nam:ident u16 $n:expr) => {
rd_1!($b u16::from_le_bytes $nam 2 $n);
};
(LE $b:ident $nam:ident i16 $n:expr) => {
rd_1!($b i16::from_le_bytes $nam 2 $n);
};
(LE $b:ident $nam:ident u32 $n:expr) => {
rd_1!($b u32::from_le_bytes $nam 4 $n);
};
(LE $b:ident $nam:ident i32 $n:expr) => {
rd_1!($b i32::from_le_bytes $nam 4 $n);
};
(LE $b:ident $nam:ident as usize u16 $n:expr) => {
rd_1!($b u16::from_le_bytes $nam 2 $n);
let $nam = $nam as usize;
};
(LE $b:ident $nam:ident as usize u32 $n:expr) => {
rd_1!($b u32::from_le_bytes $nam 4 $n);
let $nam = $nam as usize;
};
// generic endianness
($_:ident $b:ident $nam:ident u8 $n:expr) => {
let $nam = $b[$n];
};
($_:ident $b:ident $nam:ident array u8 $n:expr) => {
let $nam = &$b[$n];
};
($_:ident $b:ident $nam:ident i8 $n:expr) => {
let $nam = $b[$n] as i8;
};
($_:ident $b:ident $nam:ident iden $n:expr) => {
let $nam = [$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]];
};
($_:ident $b:ident $nam:ident $f:ident $n:expr) => {
let $nam = $f(&$b[$n])?;
};
($_:ident $b:ident $nam:ident nt $f:ident $n:expr) => {
let $nam = $f(&$b[$n]);
};
// worker - creates let statement
($b:ident $pth:path , $nam:ident 2 $n:expr) => {
let $nam = $pth([$b[$n], $b[$n + 1]]);
};
($b:ident $pth:path , $nam:ident 4 $n:expr) => {
let $nam = $pth([$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]]);
};
}
macro_rules! read_data {
(
$sz:expr , $ty:ident in $b:ident =>
$( $nam:ident = $t:ident [ $n:expr ] $( $ex:ident )* ; )*
) => {
if $b.len() < $sz {
bail!("not enough data");
}
$(rd_1!($ty $b $nam $($ex)* $t $n);)*
};
}
pub fn ident(b: &[u8]) -> Ident {[b[0], b[1], b[2], b[3]]}
pub fn u32b(b: &[u8]) -> u32 {u32::from_be_bytes([b[0], b[1], b[2], b[3]])}
pub fn u16b(b: &[u8]) -> u16 {u16::from_be_bytes([b[0], b[1]])}
pub fn i32b(b: &[u8]) -> i32 {i32::from_be_bytes([b[0], b[1], b[2], b[3]])}
pub fn i16b(b: &[u8]) -> i16 {i16::from_be_bytes([b[0], b[1]])}
pub fn rd_array<T, F>(b: &[u8], read: F) -> ResultS<Vec<T>>
where T: Sized,
F: Fn(&[u8]) -> ResultS<(T, usize)>
{
let mut v = Vec::new();
let mut p = 0;
while p < b.len() {
let (r, s) = read(&b[p..])?;
v.push(r);
p += s;
}
Ok(v)
}
pub fn rd_ofstable<T, F>(b: &[u8],
mut p: usize,
num: usize,
read: F)
-> ResultS<Vec<T>>
where T: Sized,
F: Fn(&[u8]) -> ResultS<T>
{
let mut v = Vec::with_capacity(num);
for _ in 0..num {
let ofs = u32b(&b[p..]) as usize;
if ofs >= b.len() {
bail!("not enough data");
}
v.push(read(&b[ofs..])?);
p += 4;
}
Ok(v)
}
impl OptU16
{
/// Creates an `OptU16` from a `u16`.
pub fn from_repr(n: u16) -> Self
{
if n == u16::max_value() {
Self(None)
} else {
Self(NonZeroU16::new(n + 1))
}
}
/// Returns the `u16` representation of an `OptU16`.
pub fn get_repr(&self) -> u16
{
match self.0 {
None => u16::max_value(),
Some(n) => n.get() - 1,
}
}
/// Returns the `Option` representation of an `OptU16`.
pub fn get(&self) -> Option<u16>
{
match self.0 {
None => None,
Some(n) => Some(n.get() - 1),
}
}
}
impl fmt::Debug for OptU16
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self.get() {
None => write!(f, "None"),
Some(n) => write!(f, "Some({})", n),
}
}
}
/// A four-character-code identifier.
pub type Ident = [u8; 4];
/// An object identified by a `u16` which may be `u16::max_value()` to
/// represent None.
#[derive(Serialize)]
pub struct OptU16(Option<NonZeroU16>);
// EOF