Add (untested!!!) support for IPS32
This commit is contained in:
parent
d47dbaa866
commit
349eb14a9c
38
src/ips.rs
38
src/ips.rs
@ -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,15 +97,22 @@ 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)?;
|
||||||
|
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)?;
|
let data = Data::parse(reader)?;
|
||||||
Ok(Some(Self { offset, data }))
|
Ok(Some(Self { offset, data }))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Data {
|
impl 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<()>;
|
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)?))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user