use crate::util::read_u32_le_at;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ImageInfo {
pub version: u32,
pub flags: u32,
}
pub const OBJC_IMAGE_DYLD_CATEGORIES_OPTIMIZED: u32 = 1 << 0;
pub const OBJC_IMAGE_SUPPORTS_GC: u32 = 1 << 1;
pub const OBJC_IMAGE_REQUIRES_GC: u32 = 1 << 2;
pub const OBJC_IMAGE_OPTIMIZED_BY_DYLD: u32 = 1 << 3;
pub const OBJC_IMAGE_SIGNED_CLASS_RO: u32 = 1 << 4;
pub const OBJC_IMAGE_IS_SIMULATED: u32 = 1 << 5;
pub const OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES: u32 = 1 << 6;
pub const OBJC_IMAGE_OPTIMIZED_BY_DYLD_CLOSURE: u32 = 1 << 7;
pub const OBJC_IMAGE_SWIFT_UNSTABLE_VERSION_MASK: u32 = 0x0000_ff00;
pub const OBJC_IMAGE_SWIFT_STABLE_VERSION_MASK: u32 = 0xffff_0000;
impl ImageInfo {
pub(crate) fn parse(body: &[u8]) -> Option<Self> {
let version = read_u32_le_at(body, 0)?;
let flags = read_u32_le_at(body, 4)?;
Some(Self { version, flags })
}
pub fn dyld_categories_optimized(&self) -> bool {
self.flags & OBJC_IMAGE_DYLD_CATEGORIES_OPTIMIZED != 0
}
pub fn supports_gc(&self) -> bool {
self.flags & OBJC_IMAGE_SUPPORTS_GC != 0
}
pub fn requires_gc(&self) -> bool {
self.flags & OBJC_IMAGE_REQUIRES_GC != 0
}
pub fn optimized_by_dyld(&self) -> bool {
self.flags & OBJC_IMAGE_OPTIMIZED_BY_DYLD != 0
}
pub fn signed_class_ro(&self) -> bool {
self.flags & OBJC_IMAGE_SIGNED_CLASS_RO != 0
}
pub fn is_simulated(&self) -> bool {
self.flags & OBJC_IMAGE_IS_SIMULATED != 0
}
pub fn has_category_class_properties(&self) -> bool {
self.flags & OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES != 0
}
pub fn optimized_by_dyld_closure(&self) -> bool {
self.flags & OBJC_IMAGE_OPTIMIZED_BY_DYLD_CLOSURE != 0
}
pub fn swift_unstable_version(&self) -> u8 {
((self.flags & OBJC_IMAGE_SWIFT_UNSTABLE_VERSION_MASK) >> 8) as u8
}
pub fn swift_stable_version(&self) -> u16 {
((self.flags & OBJC_IMAGE_SWIFT_STABLE_VERSION_MASK) >> 16) as u16
}
pub fn contains_swift(&self) -> bool {
self.flags & OBJC_IMAGE_SWIFT_UNSTABLE_VERSION_MASK != 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_basic() {
let body = [
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, ];
let info = ImageInfo::parse(&body).unwrap();
assert_eq!(info.version, 0);
assert_eq!(info.flags, 0x40);
assert!(info.has_category_class_properties());
assert!(!info.signed_class_ro());
assert!(!info.contains_swift());
}
#[test]
fn truncated_returns_none() {
assert_eq!(ImageInfo::parse(&[0; 7]), None);
}
#[test]
fn swift_version_decode() {
let info = ImageInfo {
version: 0,
flags: (0x0001 << 16) | (7 << 8),
};
assert!(info.contains_swift());
assert_eq!(info.swift_unstable_version(), 7);
assert_eq!(info.swift_stable_version(), 1);
}
}