#![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: &mut R) -> Result where R: Read, { r.read_u8().wrap_err("failed to read u8") } fn read_u32_le_impl(r: &mut R) -> Result where R: Read, { r.read_u32::().wrap_err("failed to read u32") } fn read_u64_le_impl(r: &mut R) -> Result where R: Read, { r.read_u64::().wrap_err("failed to read u64") } macro_rules! make_read { ($func:ident, $op:ident, $type:ty) => { pub(crate) fn $func(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: &mut W, val: u32) -> Result<()> where W: Write, { w.write_u32::(val) .wrap_err("failed to write u32") } macro_rules! make_write { ($func:ident, $op:ident, $type:ty) => { pub(crate) fn $func(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: &mut R, buf: &mut Vec) -> Result 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: &mut W, offset: u64) -> Result 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) } }