hexspell 0.0.5

A open source lib to parse executables in Rust
Documentation
//! Types and parsers for Mach-O load commands.
//!
//! Load commands describe the layout of the rest of the file, including
//! segment mappings and metadata such as symbol tables. This module offers
//! an iterator over the command stream that yields typed [`LoadCommand`]
//! values, performing bounds checks and handling both little- and
//! big-endian variants.

use super::header::Endianness;
use crate::errors;
use crate::field::Field;

#[derive(Debug)]
pub struct LoadCommand {
    pub cmd: Field<u32>,
    pub cmdsize: Field<u32>,
}

impl LoadCommand {
    pub fn parse_load_commands(
        buffer: &[u8],
        offset: usize,
        ncmds: u32,
        endianness: Endianness,
    ) -> Result<Vec<Self>, errors::FileParseError> {
        let mut commands = Vec::new();
        let mut current_offset = offset;

        for _ in 0..ncmds {
            if buffer.len() < current_offset + 8 {
                return Err(errors::FileParseError::BufferOverflow);
            }

            let read_u32 = |offset: usize| -> Result<u32, errors::FileParseError> {
                let bytes: [u8; 4] = buffer
                    .get(offset..offset + 4)
                    .ok_or(errors::FileParseError::BufferOverflow)?
                    .try_into()
                    .map_err(|_| errors::FileParseError::BufferOverflow)?;
                Ok(match endianness {
                    Endianness::Little => u32::from_le_bytes(bytes),
                    Endianness::Big => u32::from_be_bytes(bytes),
                })
            };

            let cmd = Field::new(read_u32(current_offset)?, current_offset, 4);
            let cmdsize = Field::new(read_u32(current_offset + 4)?, current_offset + 4, 4);

            commands.push(LoadCommand { cmd, cmdsize });
            current_offset += cmdsize.value as usize;
        }

        Ok(commands)
    }
}