use std::io::{Read, Seek, SeekFrom};
use crate::error::{Error, Result};
pub struct HdfReader<R: Read + Seek> {
inner: R,
sizeof_addr: u8,
sizeof_size: u8,
}
impl<R: Read + Seek> HdfReader<R> {
pub fn new(inner: R) -> Self {
Self {
inner,
sizeof_addr: 8,
sizeof_size: 8,
}
}
pub fn set_sizeof_addr(&mut self, size: u8) {
self.sizeof_addr = size;
}
pub fn set_sizeof_size(&mut self, size: u8) {
self.sizeof_size = size;
}
pub fn sizeof_addr(&self) -> u8 {
self.sizeof_addr
}
pub fn sizeof_size(&self) -> u8 {
self.sizeof_size
}
pub fn position(&mut self) -> Result<u64> {
Ok(self.inner.stream_position()?)
}
pub fn len(&mut self) -> Result<u64> {
let pos = self.inner.stream_position()?;
let len = self.inner.seek(SeekFrom::End(0))?;
self.inner.seek(SeekFrom::Start(pos))?;
Ok(len)
}
pub fn seek(&mut self, pos: u64) -> Result<u64> {
Ok(self.inner.seek(SeekFrom::Start(pos))?)
}
pub fn seek_relative(&mut self, offset: i64) -> Result<u64> {
Ok(self.inner.seek(SeekFrom::Current(offset))?)
}
pub fn read_bytes(&mut self, n: usize) -> Result<Vec<u8>> {
let mut buf = vec![0u8; n];
self.inner.read_exact(&mut buf)?;
Ok(buf)
}
pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
self.inner.read_exact(buf)?;
Ok(())
}
pub fn read_u8(&mut self) -> Result<u8> {
let mut buf = [0u8; 1];
self.inner.read_exact(&mut buf)?;
Ok(buf[0])
}
pub fn read_u16(&mut self) -> Result<u16> {
let mut buf = [0u8; 2];
self.inner.read_exact(&mut buf)?;
Ok(u16::from_le_bytes(buf))
}
pub fn read_u32(&mut self) -> Result<u32> {
let mut buf = [0u8; 4];
self.inner.read_exact(&mut buf)?;
Ok(u32::from_le_bytes(buf))
}
pub fn read_u64(&mut self) -> Result<u64> {
let mut buf = [0u8; 8];
self.inner.read_exact(&mut buf)?;
Ok(u64::from_le_bytes(buf))
}
pub fn read_i32(&mut self) -> Result<i32> {
let mut buf = [0u8; 4];
self.inner.read_exact(&mut buf)?;
Ok(i32::from_le_bytes(buf))
}
pub fn read_uint(&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::InvalidFormat(format!(
"unsupported integer size: {size}"
))),
}
}
pub fn read_addr(&mut self) -> Result<u64> {
self.read_uint(self.sizeof_addr)
}
pub fn read_length(&mut self) -> Result<u64> {
self.read_uint(self.sizeof_size)
}
pub fn read_var_uint(&mut self, nbytes: u8) -> Result<u64> {
if nbytes == 0 || nbytes > 8 {
return Err(Error::InvalidFormat(format!(
"invalid variable uint size: {nbytes}"
)));
}
let mut val: u64 = 0;
for i in 0..nbytes {
let byte = self.read_u8()? as u64;
val |= byte << (i * 8);
}
Ok(val)
}
pub fn skip(&mut self, n: u64) -> Result<()> {
self.inner.seek(SeekFrom::Current(n as i64))?;
Ok(())
}
pub fn read_checksum(&mut self) -> Result<u32> {
self.read_u32()
}
pub fn inner_mut(&mut self) -> &mut R {
&mut self.inner
}
pub fn inner(&self) -> &R {
&self.inner
}
}
pub const UNDEF_ADDR: u64 = u64::MAX;
pub fn is_undef_addr(addr: u64) -> bool {
addr == UNDEF_ADDR
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_read_integers() {
let data: Vec<u8> = vec![
0x42, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12, ];
let mut r = HdfReader::new(Cursor::new(data));
assert_eq!(r.read_u8().unwrap(), 0x42);
assert_eq!(r.read_u16().unwrap(), 0x1234);
assert_eq!(r.read_u32().unwrap(), 0x12345678);
assert_eq!(r.read_u64().unwrap(), 0x1234567890ABCDEF);
}
#[test]
fn test_read_var_uint() {
let data = vec![0x03, 0x02, 0x01];
let mut r = HdfReader::new(Cursor::new(data));
assert_eq!(r.read_var_uint(3).unwrap(), 0x010203);
}
#[test]
fn test_read_addr_4byte() {
let data = vec![0x78, 0x56, 0x34, 0x12];
let mut r = HdfReader::new(Cursor::new(data));
r.set_sizeof_addr(4);
assert_eq!(r.read_addr().unwrap(), 0x12345678);
}
}