Add (untested!!!) support for IPS32

This commit is contained in:
John 2024-07-07 04:34:32 -05:00
parent d47dbaa866
commit 349eb14a9c
2 changed files with 25 additions and 32 deletions

View File

@ -21,7 +21,7 @@
//! | { _: u16 == 0, len: u16, byte: u8 } // Run-length-encoded data //! | { _: 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}; use std::io::{self, Read, Seek, SeekFrom, Write};
pub struct IPS { pub struct IPS {
@ -29,13 +29,11 @@ pub struct IPS {
pub patches: Vec<Patch>, pub patches: Vec<Patch>,
} }
// A single IPS patch
pub struct Patch { pub struct Patch {
pub offset: u32, pub offset: u32,
pub data: Data, pub data: Data,
} }
/// The data
pub enum Data { pub enum Data {
/// Run-length-encoded (repeated) data /// Run-length-encoded (repeated) data
RLEnc(u16, u8), RLEnc(u16, u8),
@ -74,20 +72,23 @@ impl Apply for Data {
} }
impl IPS { impl IPS {
/// The expected magic number const MAGIC24: &[u8] = b"PATCH";
pub const MAGIC: &[u8] = b"PATCH"; const MAGIC32: &[u8] = b"IPS32";
/// Reads an IPS file out of the provided reader. /// 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. /// 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<Option<Self>> { pub fn parse(reader: &mut impl Read) -> io::Result<Option<Self>> {
let magic = read_bytes(reader)?; 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![]; let mut patches = vec![];
while let Some(patch) = Patch::parse(reader)? { while let Some(patch) = parse(reader)? {
patches.push(patch) patches.push(patch)
} }
@ -96,14 +97,21 @@ impl IPS {
} }
impl Patch { impl Patch {
pub fn parse(reader: &mut impl Read) -> io::Result<Option<Self>> { pub fn parse<const WIDTH: usize>(reader: &mut impl Read) -> io::Result<Option<Self>> {
match offset(reader)? { const EOF: [&[u8]; 2] = [b"EOF", b"EEOF"];
None => Ok(None),
Some(offset) => { let buf: [u8; WIDTH] = read_bytes(reader)?;
let data = Data::parse(reader)?; if const {EOF[WIDTH - 3]} == buf {
Ok(Some(Self { offset, data })) 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 }))
} }
} }

View File

@ -24,7 +24,7 @@ pub trait Apply {
fn apply<W: Write + Seek>(&self, writer: &mut W) -> IoResult<()>; fn apply<W: Write + Seek>(&self, writer: &mut W) -> IoResult<()>;
} }
mod parse_utils { mod parse_helpers {
use std::io; use std::io;
pub fn read_bytes<const N: usize>(reader: &mut impl io::Read) -> io::Result<[u8; N]> { pub fn read_bytes<const N: usize>(reader: &mut impl io::Read) -> io::Result<[u8; N]> {
@ -32,21 +32,6 @@ mod parse_utils {
reader.read_exact(&mut buf).map(|_| buf) 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<Option<u32>> {
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<u16> { pub fn read16(reader: &mut impl io::Read) -> io::Result<u16> {
Ok(u16::from_be_bytes(read_bytes(reader)?)) Ok(u16::from_be_bytes(read_bytes(reader)?))
} }