macho_core/format/
container.rs1use crate::error::{Error, Result};
2use crate::format::constants::*;
3use crate::format::fat::parse_fat_binary_with_limits;
4use crate::format::macho::parse_macho_file_with_limits;
5use crate::format::{ParseMode, ParseOptions, ParseOutcome};
6use crate::model::container::MachoContainer;
7use crate::model::validate::{self, Severity};
8
9pub fn parse(data: &[u8]) -> Result<MachoContainer<'_>> {
11 parse_with_options(data, &ParseOptions::default()).map(|outcome| outcome.container)
12}
13
14pub fn parse_with_options<'data>(
16 data: &'data [u8],
17 options: &ParseOptions,
18) -> Result<ParseOutcome<'data>> {
19 if data.len() < 4 {
20 return Err(Error::format("file too small to identify"));
21 }
22
23 let magic = u32::from_ne_bytes(data[0..4].try_into().unwrap());
24
25 let container = match magic {
26 FAT_MAGIC | FAT_CIGAM | FAT_MAGIC_64 | FAT_CIGAM_64 => {
27 parse_fat_binary_with_limits(data, &options.limits).map(MachoContainer::Fat)
28 }
29 MH_MAGIC | MH_CIGAM | MH_MAGIC_64 | MH_CIGAM_64 => {
30 parse_macho_file_with_limits(data, &options.limits).map(MachoContainer::Thin)
31 }
32 _ => Err(Error::format(format!(
33 "unrecognized file magic: {magic:#010x}"
34 ))),
35 }?;
36
37 let diagnostics = container
38 .macho_files()
39 .flat_map(validate::validate)
40 .collect::<Vec<_>>();
41 if options.mode == ParseMode::Strict
42 && let Some(diagnostic) = diagnostics
43 .iter()
44 .find(|diagnostic| diagnostic.severity == Severity::Error)
45 {
46 return Err(Error::validation(format!(
47 "{}: {}",
48 diagnostic.code.0, diagnostic.message
49 )));
50 }
51
52 Ok(ParseOutcome {
53 container,
54 diagnostics,
55 })
56}