//! 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_utils::*, Apply}; use std::io::{self, Read, Seek, SeekFrom, Write}; pub struct IPS { pub magic: [u8; 5], pub patches: Vec, } // A single IPS patch pub struct Patch { pub offset: u32, pub data: Data, } /// The 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 { /// The expected magic number pub const MAGIC: &[u8] = b"PATCH"; /// 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)?; if Self::MAGIC != magic { return Ok(None); } let mut patches = vec![]; while let Some(patch) = Patch::parse(reader)? { patches.push(patch) } Ok(Some(Self { magic, patches })) } } impl Patch { pub fn parse(reader: &mut impl Read) -> io::Result> { match offset(reader)? { None => Ok(None), Some(offset) => { 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)) } } } }