//! 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(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(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(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