diff --git a/src/ips.rs b/src/ips.rs index 3cd2cdf..2ac18e8 100644 --- a/src/ips.rs +++ b/src/ips.rs @@ -21,7 +21,7 @@ //! | { _: u16 == 0, len: u16, byte: u8 } // Run-length-encoded data //! ``` -use crate::{parse_utils::*, Apply}; +use crate::{parse_helpers::*, Apply}; use std::io::{self, Read, Seek, SeekFrom, Write}; pub struct IPS { @@ -29,13 +29,11 @@ pub struct IPS { 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), @@ -74,20 +72,23 @@ impl Apply for Data { } impl IPS { - /// The expected magic number - pub const MAGIC: &[u8] = b"PATCH"; + 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)?; - if Self::MAGIC != magic { - return Ok(None); - } + + 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) = Patch::parse(reader)? { + while let Some(patch) = parse(reader)? { patches.push(patch) } @@ -96,14 +97,21 @@ impl IPS { } 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 })) - } + 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 })) } } diff --git a/src/lib.rs b/src/lib.rs index e3f3427..752a3f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ pub trait Apply { fn apply(&self, writer: &mut W) -> IoResult<()>; } -mod parse_utils { +mod parse_helpers { use std::io; pub fn read_bytes(reader: &mut impl io::Read) -> io::Result<[u8; N]> { @@ -32,21 +32,6 @@ mod parse_utils { 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)?)) }