//! The IPS(24/16) patchfile format is one of the simplest possible patchfile formats. //! It contains no way to identify the correct target file, and cannot insert or remove bytes. //! //! An IPS file starts with the magic number "PATCH" //! ```console //! 0000: 50 41 54 43 48 |PATCH| //! ``` //! //! Patches are encoded linearly with no padding or alignment, and //! all numeric values are encoded big-endian. Patches cannot have //! a length of b"EOF", as "EOF" marks the end of the patchfile. //! ```console //! xxxx: 45 4f 46 |EOF| //! ``` //! //! The patchfile matches the following pseudo-grammar //! ```console //! IPS = "PATCH" Patch* "EOF" //! Patch = { offset: u24 != "EOF", kind: PatchKind } //! PatchData = { len: u16 != 0, data: [u8; len] } // Plain ol' data //! | { _: u16 == 0, len: u16, byte: u8 } // Run-length-encoded data //! ``` use crate::{parse_helpers::*, Apply}; use std::io::{self, Read, Seek, SeekFrom, Write}; pub struct IPS { pub magic: [u8; 5], pub patches: Vec, } pub struct Patch { pub offset: u32, pub data: Data, } pub enum Data { /// Run-length-encoded (repeated) data RLEnc(u16, u8), /// Verbatim data Plain(Vec), } impl Apply for IPS { fn apply(&self, writer: &mut W) -> io::Result<()> { for patch in &self.patches { patch.apply(writer)?; } Ok(()) } } impl Apply for Patch { fn apply(&self, writer: &mut W) -> io::Result<()> { let Self { offset, data } = self; writer.seek(SeekFrom::Start(*offset as _))?; data.apply(writer) } } impl Apply for Data { fn apply(&self, writer: &mut W) -> io::Result<()> { match self { &Data::RLEnc(len, value) => { io::copy(&mut io::repeat(value).take(len as _), writer)?; Ok(()) } Data::Plain(buf) => writer.write_all(buf), } } } impl IPS { const MAGIC24: &[u8] = b"PATCH"; const MAGIC32: &[u8] = b"IPS32"; /// Reads an IPS file out of the provided reader. /// /// Consumes 5 bytes and returns Ok(None) if the reader doesn't yield an IPS file. pub fn parse(reader: &mut impl Read) -> io::Result> { let magic = read_bytes(reader)?; let parse = match magic.as_slice() { Self::MAGIC24 => Patch::parse::<3>, Self::MAGIC32 => Patch::parse::<4>, _ => return Ok(None), }; let mut patches = vec![]; while let Some(patch) = parse(reader)? { patches.push(patch) } Ok(Some(Self { magic, patches })) } } impl Patch { pub fn parse(reader: &mut impl Read) -> io::Result> { const EOF: [&[u8]; 2] = [b"EOF", b"EEOF"]; let buf: [u8; WIDTH] = read_bytes(reader)?; if const {EOF[WIDTH - 3]} == buf { return Ok(None); } let mut offset = 0; for byte in buf { offset = offset << 8 | byte as u32; } let data = Data::parse(reader)?; Ok(Some(Self { offset, data })) } } impl Data { pub fn parse(reader: &mut impl Read) -> io::Result { match read16(reader)? { 0 => { let len = read16(reader)?; let value = read_bytes::<1>(reader)?[0]; Ok(Data::RLEnc(len, value)) } len => { let mut data = vec![0u8; len as _]; reader.read_exact(&mut data)?; Ok(Data::Plain(data)) } } } }