//! Macintosh archived format header utilities. use crate::bin::*; /// Checks for an `AppleSingle` header. Returns offset to the resource fork. pub fn check_apple_single(b: &[u8]) -> Option { // check magic numbers if b.len() < 26 || *b.get(0..8)? != [0, 5, 22, 0, 0, 2, 0, 0] { return None; } let num = usize::from(u16b(&b[24..])); if b.len() < 26 + 12 * num { return None; } // 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..])); if ent == 1 { return if ofs + len > b.len() {None} else {Some(ofs)}; } } // no resource fork None } /// Checks for a `MacBinary II` header. Returns offset to the resource fork. pub fn check_macbin(b: &[u8]) -> Option { // 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 crc = 0; // check header crc for &byte in b.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 == u16b(&b[124..]) { Some(128) } else { None } } /// 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 { if let Some(ofs) = check_macbin(b) { ofs } else { check_apple_single(b).unwrap_or(0) } } // EOF