Skip to main content

macho_core/format/
container.rs

1use 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
9/// Performs parse.
10pub fn parse(data: &[u8]) -> Result<MachoContainer<'_>> {
11    parse_with_options(data, &ParseOptions::default()).map(|outcome| outcome.container)
12}
13
14/// Performs parse_with_options.
15pub 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}