Maraiah/maraiah/machdr.rs

117 lines
2.7 KiB
Rust

//! Macintosh archived format header utilities.
use crate::file::SeekBackToStart;
use std::io::{SeekFrom, prelude::*};
/// Skips over an Apple Single header. Returns true if one was found.
pub fn skip_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 magic != [0, 5, 22, 0, 0, 2, 0, 0] {
return false;
}
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 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 _ 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 {
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
false
}
/// Skips over a Mac Binary II header. Returns true if one was found.
pub fn skip_macbin<R>(fp: &mut R) -> bool
where R: Read + Seek
{
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 head.iter().take(124) {
for j in 8..16 {
let d = u16::from(byte) << j;
if (d ^ crc) & 0x8000 == 0 {
crc <<= 1;
} else {
crc = crc << 1 ^ 0x1021;
}
}
}
// if ok, resource fork follows
if crc == u16::from_be_bytes([head[124], head[125]]) {
fp.set_seek(false);
true
} else {
false
}
}
/// Reads a `MacBin` or `AppleSingle` header if there is one and skips past it
/// from the start of the header to the resource fork (if one is found.) Returns
/// true if either one was found.
pub fn skip_mac_header<R>(fp: &mut R) -> bool
where R: Read + Seek
{
if skip_macbin(fp) {
return true;
}
let _ = fp.seek(SeekFrom::Start(0));
if skip_apple_single(fp) {
return true;
}
let _ = fp.seek(SeekFrom::Start(0));
false
}
// EOF