1use crate::read::{Architecture, Error, ReadError, ReadRef, Result};
2use crate::{macho, BigEndian, Pod};
3
4pub use macho::{FatArch32, FatArch64, FatHeader};
5
6impl FatHeader {
7 /// Attempt to parse a fat header.
8 ///
9 /// Does not validate the magic value.
10 pub fn parse<'data, R: ReadRef<'data>>(file: R) -> Result<&'data FatHeader> {
11 file.read_at::<FatHeader>(0)
12 .read_error("Invalid fat header size or alignment")
13 }
14
15 /// Attempt to parse a fat header and 32-bit fat arches.
16 pub fn parse_arch32<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch32]> {
17 let mut offset = 0;
18 let header = file
19 .read::<FatHeader>(&mut offset)
20 .read_error("Invalid fat header size or alignment")?;
21 if header.magic.get(BigEndian) != macho::FAT_MAGIC {
22 return Err(Error("Invalid 32-bit fat magic"));
23 }
24 file.read_slice::<FatArch32>(&mut offset, header.nfat_arch.get(BigEndian) as usize)
25 .read_error("Invalid nfat_arch")
26 }
27
28 /// Attempt to parse a fat header and 64-bit fat arches.
29 pub fn parse_arch64<'data, R: ReadRef<'data>>(file: R) -> Result<&'data [FatArch64]> {
30 let mut offset = 0;
31 let header = file
32 .read::<FatHeader>(&mut offset)
33 .read_error("Invalid fat header size or alignment")?;
34 if header.magic.get(BigEndian) != macho::FAT_MAGIC_64 {
35 return Err(Error("Invalid 64-bit fat magic"));
36 }
37 file.read_slice::<FatArch64>(&mut offset, header.nfat_arch.get(BigEndian) as usize)
38 .read_error("Invalid nfat_arch")
39 }
40}
41
42/// A trait for generic access to [`macho::FatArch32`] and [`macho::FatArch64`].
43#[allow(missing_docs)]
44pub trait FatArch: Pod {
45 type Word: Into<u64>;
46
47 fn cputype(&self) -> u32;
48 fn cpusubtype(&self) -> u32;
49 fn offset(&self) -> Self::Word;
50 fn size(&self) -> Self::Word;
51 fn align(&self) -> u32;
52
53 fn architecture(&self) -> Architecture {
54 match self.cputype() {
55 macho::CPU_TYPE_ARM => Architecture::Arm,
56 macho::CPU_TYPE_ARM64 => Architecture::Aarch64,
57 macho::CPU_TYPE_X86 => Architecture::I386,
58 macho::CPU_TYPE_X86_64 => Architecture::X86_64,
59 macho::CPU_TYPE_MIPS => Architecture::Mips,
60 macho::CPU_TYPE_POWERPC => Architecture::PowerPc,
61 macho::CPU_TYPE_POWERPC64 => Architecture::PowerPc64,
62 _ => Architecture::Unknown,
63 }
64 }
65
66 fn file_range(&self) -> (u64, u64) {
67 (self.offset().into(), self.size().into())
68 }
69
70 fn data<'data, R: ReadRef<'data>>(&self, file: R) -> Result<&'data [u8]> {
71 file.read_bytes_at(self.offset().into(), self.size().into())
72 .read_error("Invalid fat arch offset or size")
73 }
74}
75
76impl FatArch for FatArch32 {
77 type Word = u32;
78
79 fn cputype(&self) -> u32 {
80 self.cputype.get(BigEndian)
81 }
82
83 fn cpusubtype(&self) -> u32 {
84 self.cpusubtype.get(BigEndian)
85 }
86
87 fn offset(&self) -> Self::Word {
88 self.offset.get(BigEndian)
89 }
90
91 fn size(&self) -> Self::Word {
92 self.size.get(BigEndian)
93 }
94
95 fn align(&self) -> u32 {
96 self.align.get(BigEndian)
97 }
98}
99
100impl FatArch for FatArch64 {
101 type Word = u64;
102
103 fn cputype(&self) -> u32 {
104 self.cputype.get(BigEndian)
105 }
106
107 fn cpusubtype(&self) -> u32 {
108 self.cpusubtype.get(BigEndian)
109 }
110
111 fn offset(&self) -> Self::Word {
112 self.offset.get(BigEndian)
113 }
114
115 fn size(&self) -> Self::Word {
116 self.size.get(BigEndian)
117 }
118
119 fn align(&self) -> u32 {
120 self.align.get(BigEndian)
121 }
122}
123