127 lines
3.1 KiB
Rust
127 lines
3.1 KiB
Rust
#![allow(dead_code)]
|
|
use std::io::{Read, Seek, SeekFrom, Write};
|
|
|
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
use color_eyre::eyre::WrapErr;
|
|
use color_eyre::{Help, Result, SectionExt};
|
|
|
|
fn read_u8_impl<R>(r: &mut R) -> Result<u8>
|
|
where
|
|
R: Read,
|
|
{
|
|
r.read_u8().wrap_err("failed to read u8")
|
|
}
|
|
|
|
fn read_u32_le_impl<R>(r: &mut R) -> Result<u32>
|
|
where
|
|
R: Read,
|
|
{
|
|
r.read_u32::<LittleEndian>().wrap_err("failed to read u32")
|
|
}
|
|
|
|
fn read_u64_le_impl<R>(r: &mut R) -> Result<u64>
|
|
where
|
|
R: Read,
|
|
{
|
|
r.read_u64::<LittleEndian>().wrap_err("failed to read u64")
|
|
}
|
|
|
|
macro_rules! make_read {
|
|
($func:ident, $op:ident, $type:ty) => {
|
|
pub(crate) fn $func<R>(r: &mut R) -> Result<$type>
|
|
where
|
|
R: Read + Seek,
|
|
{
|
|
let res = $op(r);
|
|
|
|
if res.is_err() {
|
|
let pos = r.stream_position();
|
|
if pos.is_ok() {
|
|
res.with_section(|| {
|
|
format!("{pos:#X} ({pos})", pos = pos.unwrap()).header("Position: ")
|
|
})
|
|
} else {
|
|
res
|
|
}
|
|
} else {
|
|
res
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
fn write_u32_le_impl<W>(w: &mut W, val: u32) -> Result<()>
|
|
where
|
|
W: Write,
|
|
{
|
|
w.write_u32::<LittleEndian>(val)
|
|
.wrap_err("failed to write u32")
|
|
}
|
|
|
|
macro_rules! make_write {
|
|
($func:ident, $op:ident, $type:ty) => {
|
|
pub(crate) fn $func<W>(w: &mut W, val: $type) -> Result<()>
|
|
where
|
|
W: Write + Seek,
|
|
{
|
|
let res = $op(w, val);
|
|
|
|
if res.is_err() {
|
|
let pos = w.stream_position();
|
|
if pos.is_ok() {
|
|
res.with_section(|| {
|
|
format!("{pos:#X} ({pos})", pos = pos.unwrap()).header("Position: ")
|
|
})
|
|
} else {
|
|
res
|
|
}
|
|
} else {
|
|
res
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
make_read!(read_u8, read_u8_impl, u8);
|
|
make_read!(read_u32, read_u32_le_impl, u32);
|
|
make_read!(read_u64, read_u64_le_impl, u64);
|
|
|
|
make_write!(write_u32, write_u32_le_impl, u32);
|
|
|
|
pub(crate) fn read_up_to<R>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
|
|
where
|
|
R: Read + Seek,
|
|
{
|
|
let pos = r.stream_position()?;
|
|
|
|
let err = {
|
|
match r.read_exact(buf) {
|
|
Ok(_) => return Ok(buf.len()),
|
|
Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => {
|
|
r.seek(SeekFrom::Start(pos))?;
|
|
match r.read_to_end(buf) {
|
|
Ok(read) => return Ok(read),
|
|
Err(err) => err,
|
|
}
|
|
}
|
|
Err(err) => err,
|
|
}
|
|
};
|
|
|
|
Err(err).with_section(|| format!("{pos:#X} ({pos})", pos = pos).header("Position: "))
|
|
}
|
|
|
|
pub fn write_padding<W>(w: &mut W, offset: u64) -> Result<usize>
|
|
where
|
|
W: Write + Seek,
|
|
{
|
|
let pos = w.stream_position()? + offset;
|
|
let size = 16 - (pos % 16) as usize;
|
|
|
|
if size > 0 && size < 16 {
|
|
w.seek(SeekFrom::Current(size as i64))?;
|
|
Ok(size)
|
|
} else {
|
|
Ok(0)
|
|
}
|
|
}
|