1use binrw::binread;
2use bitflags::bitflags;
3use macintosh_utils::{
4 FourCC, Point,
5 chrono::{DateTime, Utc},
6 decode_string,
7};
8use std::cmp::min;
9
10bitflags! {
11 #[derive(Debug, Clone)]
12 pub struct Flags: u8 {
13 const LOCKED = 1<<0;
14 }
15}
16
17#[binread]
19#[derive(Debug)]
20#[br(big)]
21pub struct Header {
22 pub version: u8,
24 #[br(temp,assert(name_len > 0 && name_len < 63))]
25 name_len: u8,
26 #[br(map(|r: [u8; 63]| decode_string(r[0..min(name_len as usize, 63)].to_vec())))]
28 pub name: String,
29 pub type_code: FourCC,
31 pub creator_code: FourCC,
33 pub finder_flags_upper: u8,
35 #[br(temp, assert(zero==0))]
36 zero: u8,
37 pub position: Point,
39 pub window_id: u16,
41 #[br(map(Flags::from_bits_retain))]
42 pub flags: Flags,
43 #[br(temp, assert(zero_again==0))]
44 zero_again: u8,
45 pub data_fork_len: u32,
47 pub resource_fork_len: u32,
49 #[br(map(macintosh_utils::date))]
50 pub created_at: DateTime<Utc>,
51 #[br(map(macintosh_utils::date))]
52 pub modified_at: DateTime<Utc>,
53
54 pub comment_len: u16,
56 pub finder_flags_lower: u8,
58 pub magic: FourCC,
60 pub file_name_script: u8,
61 pub extended_finder_flags: u8,
62 #[br(temp)]
63 _reserved_2: [u8; 8],
64 pub unpacked_total_len: u32,
65 pub extended_header_len: u16,
66 pub uploader_version: u8,
67 pub downloader_min_version: u8,
68 pub checksum: u16,
70
71 #[br(temp)]
72 _reserved_3: u16,
73}
74
75impl Header {
76 pub const FIXED_SIZE: usize = 128;
77
78 fn extended_header_location(&self) -> u64 {
79 Header::FIXED_SIZE as u64
80 }
81
82 pub fn data_fork_location(&self) -> u64 {
83 self.extended_header_location() + align_128(self.extended_header_len as u64)
84 }
85
86 pub fn resource_fork_location(&self) -> u64 {
87 self.data_fork_location() + align_128(self.data_fork_len as u64)
88 }
89
90 pub fn file_comment_location(&self) -> u64 {
91 self.resource_fork_location() + align_128(self.resource_fork_len as u64)
92 }
93}
94
95fn align_128(input: u64) -> u64 {
96 if (0x80 - 1) & input != 0 {
97 (input + 0x80) & !(0x80 - 1)
98 } else {
99 input
100 }
101}
102
103#[cfg(test)]
104mod test {
105 use super::align_128;
106
107 #[test]
108 fn align_int() {
109 assert_eq!(align_128(0), 0);
110 assert_eq!(align_128(1), 128);
111 assert_eq!(align_128(127), 128);
112 assert_eq!(align_128(128), 128);
113 assert_eq!(align_128(129), 256);
114 }
115}