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
//! ```
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<Patch>,
}
// 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<Option<Self>> {
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<Option<Self>> {
match offset(reader)? {
None => Ok(None),
Some(offset) => {
let data = Data::parse(reader)?;
Ok(Some(Self { offset, data }))
}
pub fn parse<const WIDTH: usize>(reader: &mut impl Read) -> io::Result<Option<Self>> {
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 }))
}
}

View File

@ -24,7 +24,7 @@ pub trait Apply {
fn apply<W: Write + Seek>(&self, writer: &mut W) -> IoResult<()>;
}
mod parse_utils {
mod parse_helpers {
use std::io;
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)
}
/// 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> {
Ok(u16::from_be_bytes(read_bytes(reader)?))
}