117 lines
3.0 KiB
Rust
117 lines
3.0 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
|