//! Simple IPS file parsing and application pub use ips::IPS; use std::io::{Result as IoResult, Seek, Write}; pub mod ips; /// Patches a [seekable](Seek) [writer](Write) with the provided [patch](Apply) pub trait Patchable: Write + Seek { fn patch(&mut self, with: P) -> IoResult<&mut Self>; } impl Patchable for W { /// Applies the provided patch to this [seekable](Seek) [writer](Write) fn patch(&mut self, with: P) -> IoResult<&mut Self> { with.apply(self)?; Ok(self) } } /// Applies a patch to a [seekable](Seek) [writer](Write) pub trait Apply { /// Applies this patch to the provided [seekable](Seek) [writer](Write) fn apply(&self, writer: &mut W) -> IoResult<()>; } mod parse_utils { use std::io; pub fn read_bytes(reader: &mut impl io::Read) -> io::Result<[u8; N]> { let mut buf = [0; N]; reader.read_exact(&mut buf).map(|_| buf) } /// Parses a 24-bit big-endian "offset" and ensures it isn't `0x454f46` (`b"EOF"`) pub fn offset(reader: &mut impl io::Read) -> io::Result> { let buf = read_bytes(reader)?; if buf == *b"EOF" { return Ok(None); } let mut offset = 0; for byte in buf { offset = offset << 8 | byte as u32; } Ok(Some(offset)) } pub fn read16(reader: &mut impl io::Read) -> io::Result { Ok(u16::from_be_bytes(read_bytes(reader)?)) } }