Skip to main content

il2cpp_bridge_rs/structs/core/metadata/
image.rs

1//! Image metadata wrapper.
2use crate::api::{self, cache};
3use crate::structs::core::Class;
4use std::ffi::c_void;
5
6use super::assembly::Assembly;
7
8/// Represents a hydrated IL2CPP image.
9///
10/// In Unity terms this is roughly the image or module backing an assembly.
11#[derive(Debug, Clone)]
12pub struct Image {
13    /// Pointer to the internal IL2CPP image structure
14    pub address: *mut c_void,
15    /// Name of the image (e.g., "Assembly-CSharp")
16    pub name: String,
17    /// Filename of the image incl. extension (e.g., "Assembly-CSharp.dll")
18    pub filename: String,
19    /// Pointer to the assembly containing this image
20    pub assembly: *mut c_void,
21    /// Pointer to the entry point method (if any)
22    pub entry_point: *mut c_void,
23}
24
25unsafe impl Send for Image {}
26unsafe impl Sync for Image {}
27
28impl Image {
29    /// Returns the assembly associated with this image, if it is cached.
30    pub fn get_assembly(&self) -> Option<std::sync::Arc<Assembly>> {
31        unsafe {
32            let assembly_ptr = api::image_get_assembly(self.address);
33            if assembly_ptr.is_null() {
34                return None;
35            }
36
37            for entry in cache::CACHE.assemblies.iter() {
38                if entry.value().address == assembly_ptr {
39                    return Some(std::sync::Arc::clone(entry.value()));
40                }
41            }
42            None
43        }
44    }
45
46    /// Returns all classes defined in this image.
47    pub fn get_classes(&self) -> Vec<Class> {
48        let mut classes = Vec::new();
49        unsafe {
50            let class_count = api::image_get_class_count(self.address);
51            for i in 0..class_count {
52                let class_ptr = api::image_get_class(self.address, i);
53                if !class_ptr.is_null() {
54                    if let Some(class) = cache::class_from_ptr(class_ptr) {
55                        classes.push(class);
56                    }
57                }
58            }
59        }
60        classes
61    }
62
63    /// Finds a class by name within this image.
64    ///
65    /// Accepts either a fully qualified type name such as
66    /// `UnityEngine.GameObject` or an unqualified name for the global
67    /// namespace.
68    pub fn class(&self, name: &str) -> Option<Class> {
69        if let Some(class) = cache::CACHE.classes.get(name) {
70            return Some((**class).clone());
71        }
72
73        let (namespace, class_name) = if let Some(idx) = name.rfind('.') {
74            (&name[..idx], &name[idx + 1..])
75        } else {
76            ("", name)
77        };
78
79        unsafe {
80            let ns_cstr = std::ffi::CString::new(namespace).ok()?;
81            let name_cstr = std::ffi::CString::new(class_name).ok()?;
82
83            let class_ptr =
84                api::class_from_name(self.address, ns_cstr.as_ptr(), name_cstr.as_ptr());
85
86            if !class_ptr.is_null() {
87                cache::class_from_ptr(class_ptr)
88            } else {
89                None
90            }
91        }
92    }
93}