1use crate::error::Result;
2use crate::model::addr::Va;
3use crate::objc::class::{resolve_class_name_from_va, resolve_class_ref_name};
4use crate::objc::method::parse_method_list;
5use crate::objc::property::{parse_property_list, parse_property_list_with_kind};
6use crate::objc::protocol::parse_protocol_name_list;
7use crate::objc::resolve::ObjCResolver;
8use crate::objc::types::ObjCCategory;
9
10pub fn parse_category(resolver: &ObjCResolver<'_>, cat_va: Va) -> Result<ObjCCategory> {
12 let offset = resolver.va_to_offset(cat_va)?;
13
14 let name_ptr_offset = offset.as_usize() as u64;
15 let name = match resolver.read_pointer_at_offset(name_ptr_offset)? {
16 Some(va) => resolver.read_cstring(va).unwrap_or("<invalid>").to_string(),
17 None => "<null>".to_string(),
18 };
19
20 let cls_offset = offset.as_usize() as u64 + 8;
22 let class_name = resolve_class_ref_name(resolver, cls_offset).unwrap_or_else(|| {
23 if let Ok(Some(cls_va)) = resolver.read_pointer_at_offset(cls_offset) {
24 resolve_class_name_from_va(resolver, cls_va).unwrap_or_else(|| "<class>".to_string())
25 } else {
26 "<null>".to_string()
27 }
28 });
29
30 let inst_methods_offset = offset.as_usize() as u64 + 16;
31 let instance_methods = match resolver.read_pointer_at_offset(inst_methods_offset)? {
32 Some(va) if va.0 != 0 => parse_method_list(resolver, va).unwrap_or_default(),
33 _ => Vec::new(),
34 };
35
36 let cls_methods_offset = offset.as_usize() as u64 + 24;
37 let class_methods = match resolver.read_pointer_at_offset(cls_methods_offset)? {
38 Some(va) if va.0 != 0 => parse_method_list(resolver, va).unwrap_or_default(),
39 _ => Vec::new(),
40 };
41
42 let protos_offset = offset.as_usize() as u64 + 32;
43 let protocols = match resolver.read_pointer_at_offset(protos_offset)? {
44 Some(va) if va.0 != 0 => parse_protocol_name_list(resolver, va).unwrap_or_default(),
45 _ => Vec::new(),
46 };
47
48 let props_offset = offset.as_usize() as u64 + 40;
50 let properties = match resolver.read_pointer_at_offset(props_offset) {
51 Ok(Some(va)) if va.0 != 0 => parse_property_list(resolver, va).unwrap_or_default(),
52 _ => Vec::new(),
53 };
54
55 let class_props_offset = offset.as_usize() as u64 + 48;
56 let class_properties = match resolver.read_pointer_at_offset(class_props_offset) {
57 Ok(Some(va)) if va.0 != 0 => {
58 parse_property_list_with_kind(resolver, va, true).unwrap_or_default()
59 }
60 _ => Vec::new(),
61 };
62
63 let mut properties = properties;
64 properties.extend(class_properties);
65
66 Ok(ObjCCategory {
67 name,
68 class_name,
69 instance_methods,
70 class_methods,
71 properties,
72 protocols,
73 })
74}