use alloc::borrow::Cow;
use core::fmt::Debug;
use crate::endianity::Endianity;
use crate::leb128;
use crate::read::{Error, Result};
#[allow(clippy::len_without_is_empty)]
pub trait Reader: Debug + Clone {
type Endian: Endianity;
fn endian(&self) -> Self::Endian;
fn len(&self) -> usize;
fn empty(&mut self);
fn truncate(&mut self, len: usize) -> Result<()>;
fn offset_from(&self, base: &Self) -> usize;
fn skip(&mut self, len: usize) -> Result<()>;
fn split(&mut self, len: usize) -> Result<Self>;
fn to_slice(&self) -> Result<Cow<'_, [u8]>>;
fn read_slice(&mut self, buf: &mut [u8]) -> Result<()>;
#[inline]
fn read_relocatable(&mut self, size: u8) -> Result<u64> {
self.read_sized(size)
}
#[inline]
fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
fn read_u8(&mut self) -> Result<u8> {
let mut buf = [0; 1];
self.read_slice(&mut buf)?;
Ok(buf[0])
}
#[inline]
fn read_u16(&mut self) -> Result<u16> {
let mut buf = [0; 2];
self.read_slice(&mut buf)?;
Ok(self.endian().read_u16(&buf))
}
#[inline]
fn read_u32(&mut self) -> Result<u32> {
let mut buf = [0; 4];
self.read_slice(&mut buf)?;
Ok(self.endian().read_u32(&buf))
}
#[inline]
fn read_u64(&mut self) -> Result<u64> {
let mut buf = [0; 8];
self.read_slice(&mut buf)?;
Ok(self.endian().read_u64(&buf))
}
fn read_sized(&mut self, size: u8) -> Result<u64> {
match size {
1 => self.read_u8().map(u64::from),
2 => self.read_u16().map(u64::from),
4 => self.read_u32().map(u64::from),
8 => self.read_u64(),
_ => Err(Error::UnsupportedSize(size)),
}
}
fn read_uleb128(&mut self) -> Result<u64> {
read_leb128(
self,
|bytes| leb128::read_unsigned(bytes),
Error::BadUnsignedLeb128,
)
}
fn read_sleb128(&mut self) -> Result<i64> {
read_leb128(
self,
|bytes| leb128::read_signed(bytes),
Error::BadSignedLeb128,
)
}
#[inline]
fn range_from(&self, offset: usize) -> Result<Self> {
let mut reader = self.clone();
reader.skip(offset)?;
Ok(reader)
}
}
fn read_leb128<R: Reader, T>(
reader: &mut R,
decode: impl FnOnce(&mut dyn Iterator<Item = u8>) -> Option<T>,
overflow: Error,
) -> Result<T> {
let mut eof = false;
let mut bytes = core::iter::from_fn(|| {
let byte = reader.read_u8().ok();
eof = byte.is_none();
byte
});
match decode(&mut bytes) {
Some(value) => Ok(value),
None if eof => Err(Error::UnexpectedEof),
None => Err(overflow),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::endianity::{BigEndian, LittleEndian};
use crate::read::EndianSlice;
#[test]
fn test_leb128() {
let buf = [0xe5, 0x8e, 0x26, 0x7f, 0x80, 0x7f, 0x80];
let mut r = EndianSlice::new(&buf, LittleEndian);
assert_eq!(r.read_uleb128(), Ok(624_485));
assert_eq!(r.read_sleb128(), Ok(-1));
assert_eq!(r.read_sleb128(), Ok(-128));
assert_eq!(r.read_uleb128(), Err(Error::UnexpectedEof));
}
#[test]
fn test_sized() {
let buf = [1, 2, 3, 4, 5, 6, 7, 8];
let mut r = EndianSlice::new(&buf, BigEndian);
assert_eq!(r.read_sized(2), Ok(0x0102));
assert_eq!(r.read_sized(3), Err(Error::UnsupportedSize(3)));
assert_eq!(r.range_from(0).unwrap().read_sized(8).ok(), None);
assert_eq!(
EndianSlice::new(&buf, BigEndian).read_u64(),
Ok(0x0102_0304_0506_0708)
);
}
}