Add (untested!!!) support for IPS32
This commit is contained in:
parent
d47dbaa866
commit
349eb14a9c
40
src/ips.rs
40
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<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 }))
|
||||
}
|
||||
}
|
||||
|
||||
|
17
src/lib.rs
17
src/lib.rs
@ -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)?))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user