maraiah: rewrite machdr.rs to use Read/Seek
parent
daebfd2da6
commit
2095e9d58a
|
@ -2,6 +2,7 @@
|
|||
|
||||
use crate::err::*;
|
||||
use std::fs;
|
||||
use std::io::{SeekFrom, prelude::*};
|
||||
|
||||
/// Confirms that the path `p` is a folder.
|
||||
pub fn validate_folder_path(p: &str) -> ResultS<()>
|
||||
|
@ -14,4 +15,40 @@ pub fn validate_folder_path(p: &str) -> ResultS<()>
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for SeekBackToStart<T>
|
||||
where T: Seek
|
||||
{
|
||||
fn drop(&mut self) {if self.fl {let _ = self.seek(SeekFrom::Start(0));}}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for SeekBackToStart<T>
|
||||
where T: Seek
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {&self.sc}
|
||||
}
|
||||
|
||||
impl<T> std::ops::DerefMut for SeekBackToStart<T>
|
||||
where T: Seek
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {&mut self.sc}
|
||||
}
|
||||
|
||||
impl<T> SeekBackToStart<T>
|
||||
where T: Seek
|
||||
{
|
||||
pub fn new(sc: T) -> Self {SeekBackToStart{sc, fl: true}}
|
||||
|
||||
pub fn set_seek(&mut self, fl: bool) {self.fl = fl;}
|
||||
pub fn get_seek(&self) -> bool {self.fl}
|
||||
}
|
||||
|
||||
/// Seeks back to the starting position of the inner object when losing scope,
|
||||
/// unless a flag is set.
|
||||
pub struct SeekBackToStart<T: Seek> {
|
||||
sc: T,
|
||||
fl: bool,
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
@ -1,50 +1,77 @@
|
|||
//! Macintosh archived format header utilities.
|
||||
|
||||
use crate::bin::*;
|
||||
use crate::file::SeekBackToStart;
|
||||
use std::io::{SeekFrom, prelude::*};
|
||||
|
||||
/// Checks for an `AppleSingle` header. Returns offset to the resource fork.
|
||||
pub fn check_apple_single(b: &[u8]) -> Option<usize>
|
||||
/// Checks for an Apple Single header. Returns offset to the resource fork.
|
||||
pub fn check_apple_single<R>(fp: &mut R) -> bool
|
||||
where R: Read + Seek
|
||||
{
|
||||
let mut fp = SeekBackToStart::new(fp);
|
||||
|
||||
let mut magic = [0; 8];
|
||||
let magic = if fp.read(&mut magic).is_ok() {magic} else {return false;};
|
||||
|
||||
// check magic numbers
|
||||
if b.len() < 26 || *b.get(0..8)? != [0, 5, 22, 0, 0, 2, 0, 0] {
|
||||
return None;
|
||||
if magic != [0, 5, 22, 0, 0, 2, 0, 0] {
|
||||
return false;
|
||||
}
|
||||
|
||||
let num = usize::from(u16b(&b[24..]));
|
||||
let mut num = [0; 2];
|
||||
let num = if fp.read(&mut num).is_ok() {num} else {return false;};
|
||||
let num = u64::from(u16::from_be_bytes(num));
|
||||
|
||||
if b.len() < 26 + 12 * num {
|
||||
return None;
|
||||
if fp.seek(SeekFrom::Start(26 + 12 * num)).is_err() |
|
||||
fp.seek(SeekFrom::Start(26)).is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the resource fork (entity 1)
|
||||
for i in 0..num {
|
||||
let p = 26 + 12 * i;
|
||||
let ent = u32b(&b[p..]);
|
||||
let ofs = usize_from_u32(u32b(&b[p + 4..]));
|
||||
let len = usize_from_u32(u32b(&b[p + 8..]));
|
||||
for _ in 0..num {
|
||||
let mut ent = [0; 4];
|
||||
let mut ofs = [0; 4];
|
||||
let mut len = [0; 4];
|
||||
let ent = if fp.read(&mut ent).is_ok() {ent} else {return false;};
|
||||
let ofs = if fp.read(&mut ofs).is_ok() {ofs} else {return false;};
|
||||
let len = if fp.read(&mut len).is_ok() {len} else {return false;};
|
||||
let ent = u32::from_be_bytes(ent);
|
||||
let ofs = u64::from(u32::from_be_bytes(ofs));
|
||||
let len = u64::from(u32::from_be_bytes(len));
|
||||
|
||||
if ent == 1 {
|
||||
return if ofs + len > b.len() {None} else {Some(ofs)};
|
||||
if fp.seek(SeekFrom::Start(ofs + len)).is_ok() &
|
||||
fp.seek(SeekFrom::Start(ofs)).is_ok() {
|
||||
fp.set_seek(false);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no resource fork
|
||||
None
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks for a `MacBinary II` header. Returns offset to the resource fork.
|
||||
pub fn check_macbin(b: &[u8]) -> Option<usize>
|
||||
/// Checks for a Mac Binary II header. Returns offset to the resource fork.
|
||||
pub fn check_macbin<R>(fp: &mut R) -> bool
|
||||
where R: Read + Seek
|
||||
{
|
||||
// check legacy version, length, zero fill, and macbin2 version
|
||||
// I swear this isn't *completely* magic
|
||||
if b.len() < 128 || b[0] != 0 || b[1] > 63 || b[74] != 0 || b[123] > 129 {
|
||||
return None;
|
||||
let mut fp = SeekBackToStart::new(fp);
|
||||
|
||||
let mut head = [0; 128];
|
||||
let head = if fp.read(&mut head).is_ok() {head} else {return false;};
|
||||
|
||||
// check legacy version, length, zero fill, and macbin2 version. I swear,
|
||||
// this isn't *completely* magic
|
||||
if head[0] != 0 || head[1] > 63 || head[74] != 0 || head[123] > 129 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut crc = 0;
|
||||
|
||||
// check header crc
|
||||
for &byte in b.iter().take(124) {
|
||||
for &byte in head.iter().take(124) {
|
||||
for j in 8..16 {
|
||||
let d = u16::from(byte) << j;
|
||||
|
||||
|
@ -57,22 +84,32 @@ pub fn check_macbin(b: &[u8]) -> Option<usize>
|
|||
}
|
||||
|
||||
// if ok, resource fork follows
|
||||
if crc == u16b(&b[124..]) {
|
||||
Some(128)
|
||||
if crc == u16::from_be_bytes([head[124], head[125]]) {
|
||||
fp.set_seek(false);
|
||||
true
|
||||
} else {
|
||||
None
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a `MacBin` or `AppleSingle` header if there is one and returns the
|
||||
/// offset from the start of the header to the resource fork (if one is found.)
|
||||
pub fn try_mac_header(b: &[u8]) -> usize
|
||||
pub fn try_mac_header<R>(fp: &mut R) -> bool
|
||||
where R: Read + Seek
|
||||
{
|
||||
if let Some(ofs) = check_macbin(b) {
|
||||
ofs
|
||||
} else {
|
||||
check_apple_single(b).unwrap_or(0)
|
||||
if check_macbin(fp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let _ = fp.seek(SeekFrom::Start(0));
|
||||
|
||||
if check_apple_single(fp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let _ = fp.seek(SeekFrom::Start(0));
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
@ -7,8 +7,10 @@ fn machdr_must_process()
|
|||
{
|
||||
const INPUT: &[u8] = include_bytes!("data/misc/macbin.in");
|
||||
|
||||
assert_eq!(machdr::check_macbin(INPUT), Some(128));
|
||||
assert_eq!(machdr::try_mac_header(INPUT), 128);
|
||||
let mut inp = std::io::Cursor::new(INPUT);
|
||||
|
||||
assert_eq!(machdr::check_macbin(&mut inp), true);
|
||||
assert_eq!(machdr::try_mac_header(&mut inp), true);
|
||||
|
||||
// FIXME: missing test data for applesingle
|
||||
}
|
||||
|
@ -16,10 +18,11 @@ fn machdr_must_process()
|
|||
#[test]
|
||||
fn machdr_must_not_process()
|
||||
{
|
||||
for inp in &RANDOM {
|
||||
assert_eq!(machdr::check_macbin(inp), None);
|
||||
assert_eq!(machdr::check_apple_single(inp), None);
|
||||
assert_eq!(machdr::try_mac_header(inp), 0);
|
||||
for rinp in &RANDOM {
|
||||
let mut inp = std::io::Cursor::new(rinp);
|
||||
assert_eq!(machdr::check_macbin(&mut inp), false);
|
||||
assert_eq!(machdr::check_apple_single(&mut inp), false);
|
||||
assert_eq!(machdr::try_mac_header(&mut inp), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue