use std::cell::RefCell;
use std::fmt;
use crate::io::BinaryStream;
use crate::error::Result;
use crate::read_versioned;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnityVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
pub build_type: UnityBuildType,
pub build_number: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum UnityBuildType {
Alpha = 0,
Beta = 1,
Final = 2,
Patch = 3,
}
impl UnityVersion {
pub fn new(major: u32, minor: u32, patch: u32, build_type: UnityBuildType, build_number: u32) -> Self {
Self { major, minor, patch, build_type, build_number }
}
pub fn parse(s: &str) -> Option<Self> {
let s = s.trim();
let major;
let minor;
let mut patch = 0u32;
let mut build_type = UnityBuildType::Final;
let mut build_number = 0u32;
let parts: Vec<&str> = s.splitn(3, '.').collect();
if parts.len() < 2 {
return None;
}
major = parts[0].parse().ok()?;
minor = parts[1].parse().ok()?;
if parts.len() == 3 {
let rest = parts[2];
let type_pos = rest.find(|c: char| c == 'f' || c == 'b' || c == 'a' || c == 'p');
if let Some(pos) = type_pos {
patch = rest[..pos].parse().ok()?;
let type_char = rest.as_bytes()[pos];
build_type = match type_char {
b'a' => UnityBuildType::Alpha,
b'b' => UnityBuildType::Beta,
b'f' => UnityBuildType::Final,
b'p' => UnityBuildType::Patch,
_ => UnityBuildType::Final,
};
build_number = rest[pos + 1..].parse().unwrap_or(1);
} else {
patch = rest.parse().unwrap_or(0);
}
}
Some(Self { major, minor, patch, build_type, build_number })
}
pub fn gte(&self, major: u32, minor: u32, patch: u32, bt: UnityBuildType, bn: u32) -> bool {
let lhs = (self.major, self.minor, self.patch, self.build_type as u32, self.build_number);
let rhs = (major, minor, patch, bt as u32, bn);
lhs >= rhs
}
pub fn gte_simple(&self, major: u32, minor: u32, patch: u32) -> bool {
(self.major, self.minor, self.patch) >= (major, minor, patch)
}
pub fn gte_major_minor(&self, major: u32, minor: u32) -> bool {
(self.major, self.minor) >= (major, minor)
}
pub fn gte_major(&self, major: u32) -> bool {
self.major >= major
}
pub fn resolve_sub_version(&self, raw_version: i32) -> f64 {
match raw_version {
24 => {
if self.gte_simple(2020, 1, 11) {
24.4
} else if self.gte_major(2020) {
24.3
} else if self.gte_simple(2019, 4, 21) {
24.5
} else if self.gte_simple(2019, 4, 15) {
24.4
} else if self.gte_simple(2019, 3, 7) {
24.3
} else if self.gte_major(2019) {
24.2
} else if self.gte_simple(2018, 4, 34) {
24.15
} else if self.gte_major_minor(2018, 3) {
24.1
} else {
24.0
}
}
27 => {
if self.gte_major_minor(2021, 1) {
27.2
} else if self.gte_simple(2020, 2, 4) {
27.1
} else {
27.0
}
}
29 => {
if self.gte(2022, 1, 0, UnityBuildType::Beta, 7) {
29.1
} else {
29.0
}
}
31 => {
if self.gte(2022, 3, 33, UnityBuildType::Final, 1) {
31.1
} else {
31.0
}
}
_ => raw_version as f64,
}
}
}
impl fmt::Display for UnityVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let t = match self.build_type {
UnityBuildType::Alpha => 'a',
UnityBuildType::Beta => 'b',
UnityBuildType::Final => 'f',
UnityBuildType::Patch => 'p',
};
write!(f, "{}.{}.{}{}{}", self.major, self.minor, self.patch, t, self.build_number)
}
}
fn decode_packing_size(encoded: u32) -> u32 {
match encoded {
0 => 0,
1 => 1,
2 => 2,
3 => 4,
4 => 8,
5 => 16,
6 => 32,
7 => 64,
8 => 128,
_ => 0,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum Il2CppPackingSizeEnum {
Zero = 0,
One = 1,
Two = 2,
Four = 3,
Eight = 4,
Sixteen = 5,
ThirtyTwo = 6,
SixtyFour = 7,
OneHundredTwentyEight = 8,
}
impl Il2CppPackingSizeEnum {
pub fn from_u32(value: u32) -> Option<Self> {
match value {
0 => Some(Self::Zero),
1 => Some(Self::One),
2 => Some(Self::Two),
3 => Some(Self::Four),
4 => Some(Self::Eight),
5 => Some(Self::Sixteen),
6 => Some(Self::ThirtyTwo),
7 => Some(Self::SixtyFour),
8 => Some(Self::OneHundredTwentyEight),
_ => None,
}
}
pub fn numerical_value(self) -> u32 {
decode_packing_size(self as u32)
}
}
#[derive(Debug, Clone, Copy)]
pub struct IndexWidths {
pub type_def: u8,
pub generic_container: u8,
pub type_index: u8,
pub parameter_def: u8,
pub interface_offset: u8,
pub event: u8,
pub property: u8,
pub nested_type: u8,
pub method: u8,
pub generic_param: u8,
pub field: u8,
pub default_value_data: u8,
}
impl Default for IndexWidths {
fn default() -> Self {
Self {
type_def: 4, generic_container: 4, type_index: 4,
parameter_def: 4, interface_offset: 4, event: 4,
property: 4, nested_type: 4, method: 4,
generic_param: 4, field: 4, default_value_data: 4,
}
}
}
impl IndexWidths {
pub fn from_header(h: &Il2CppGlobalMetadataHeader, version: f64) -> Self {
if version < 38.0 {
return Self::default();
}
fn w(count: i32) -> u8 {
if count <= 0 { 4 } else if count <= 255 { 1 } else if count <= 65535 { 2 } else { 4 }
}
let type_index = if h.interface_offsets_count > 0 && h.interface_offsets_size > 0 {
let bpe = h.interface_offsets_size / h.interface_offsets_count;
if bpe > 4 { (bpe - 4) as u8 } else { 4 }
} else { 4 };
Self {
type_def: w(h.type_definitions_count),
generic_container: w(h.generic_containers_count),
type_index,
parameter_def: if version >= 39.0 { w(h.parameters_count) } else { 4 },
interface_offset: if version >= 104.0 { w(h.interface_offsets_count) } else { 4 },
event: if version >= 104.0 { w(h.events_count) } else { 4 },
property: if version >= 104.0 { w(h.properties_count) } else { 4 },
nested_type: if version >= 104.0 { w(h.nested_types_count) } else { 4 },
method: if version >= 105.0 { w(h.methods_count) } else { 4 },
generic_param: if version >= 106.0 { w(h.generic_parameters_count) } else { 4 },
field: if version >= 106.0 { w(h.fields_count) } else { 4 },
default_value_data: if version >= 106.0 { w(h.field_and_parameter_default_value_data_count) } else { 4 },
}
}
pub fn get_type_index_size(h: &Il2CppGlobalMetadataHeader) -> usize {
if h.interface_offsets_count > 0 && h.interface_offsets_size > 0 {
let bpe = (h.interface_offsets_size / h.interface_offsets_count) as usize;
if bpe > 4 { bpe - 4 } else { 4 }
} else {
4
}
}
}
thread_local! {
static INDEX_WIDTHS: RefCell<IndexWidths> = RefCell::new(IndexWidths::default());
}
pub fn set_index_widths(widths: IndexWidths) {
INDEX_WIDTHS.with(|w| *w.borrow_mut() = widths);
}
#[inline(always)] fn read_type_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().type_index)) }
#[inline(always)] fn read_type_def_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().type_def)) }
#[inline(always)] fn read_gc_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().generic_container)) }
#[inline(always)] fn read_param_def_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().parameter_def)) }
#[inline(always)] fn read_ioffset_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().interface_offset)) }
#[inline(always)] fn read_event_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().event)) }
#[inline(always)] fn read_property_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().property)) }
#[inline(always)] fn read_nested_type_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().nested_type)) }
#[inline(always)] fn read_method_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().method)) }
#[inline(always)] fn read_gp_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().generic_param)) }
#[inline(always)] fn read_field_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().field)) }
#[inline(always)] fn read_dvdata_idx(s: &mut BinaryStream) -> Result<i32> { INDEX_WIDTHS.with(|iw| s.read_variable_index(iw.borrow().default_value_data)) }
#[derive(Debug, Clone, Default)]
pub struct Il2CppGlobalMetadataHeader {
pub sanity: u32,
pub version: i32,
pub string_literal_offset: i32,
pub string_literal_size: i32,
pub string_literal_data_offset: i32,
pub string_literal_data_size: i32,
pub string_offset: i32,
pub string_size: i32,
pub events_offset: i32,
pub events_size: i32,
pub properties_offset: i32,
pub properties_size: i32,
pub methods_offset: i32,
pub methods_size: i32,
pub parameter_default_values_offset: i32,
pub parameter_default_values_size: i32,
pub field_default_values_offset: i32,
pub field_default_values_size: i32,
pub field_and_parameter_default_value_data_offset: i32,
pub field_and_parameter_default_value_data_size: i32,
pub field_marshaled_sizes_offset: i32,
pub field_marshaled_sizes_size: i32,
pub parameters_offset: i32,
pub parameters_size: i32,
pub fields_offset: i32,
pub fields_size: i32,
pub generic_parameters_offset: i32,
pub generic_parameters_size: i32,
pub generic_parameter_constraints_offset: i32,
pub generic_parameter_constraints_size: i32,
pub generic_containers_offset: i32,
pub generic_containers_size: i32,
pub nested_types_offset: i32,
pub nested_types_size: i32,
pub interfaces_offset: i32,
pub interfaces_size: i32,
pub vtable_methods_offset: i32,
pub vtable_methods_size: i32,
pub interface_offsets_offset: i32,
pub interface_offsets_size: i32,
pub type_definitions_offset: i32,
pub type_definitions_size: i32,
pub rgctx_entries_offset: i32,
pub rgctx_entries_count: i32,
pub images_offset: i32,
pub images_size: i32,
pub assemblies_offset: i32,
pub assemblies_size: i32,
pub metadata_usage_lists_offset: i32,
pub metadata_usage_lists_count: i32,
pub metadata_usage_pairs_offset: i32,
pub metadata_usage_pairs_count: i32,
pub field_refs_offset: i32,
pub field_refs_size: i32,
pub referenced_assemblies_offset: i32,
pub referenced_assemblies_size: i32,
pub attributes_info_offset: i32,
pub attributes_info_count: i32,
pub attribute_types_offset: i32,
pub attribute_types_count: i32,
pub attribute_data_offset: i32,
pub attribute_data_size: i32,
pub attribute_data_range_offset: i32,
pub attribute_data_range_size: i32,
pub unresolved_virtual_call_parameter_types_offset: i32,
pub unresolved_virtual_call_parameter_types_size: i32,
pub unresolved_virtual_call_parameter_ranges_offset: i32,
pub unresolved_virtual_call_parameter_ranges_size: i32,
pub windows_runtime_type_names_offset: i32,
pub windows_runtime_type_names_size: i32,
pub windows_runtime_strings_offset: i32,
pub windows_runtime_strings_size: i32,
pub exported_type_definitions_offset: i32,
pub exported_type_definitions_size: i32,
pub type_definitions_count: i32,
pub generic_containers_count: i32,
pub interface_offsets_count: i32,
pub parameters_count: i32,
pub events_count: i32,
pub properties_count: i32,
pub nested_types_count: i32,
pub methods_count: i32,
pub generic_parameters_count: i32,
pub fields_count: i32,
pub field_and_parameter_default_value_data_count: i32,
pub type_inline_arrays_offset: i32,
pub type_inline_arrays_size: i32,
pub type_inline_arrays_count: i32,
}
impl Il2CppGlobalMetadataHeader {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let v38 = version >= 38.0;
macro_rules! sec {
() => {{
let o = stream.read_i32()?;
let s = stream.read_i32()?;
let c = if v38 { stream.read_i32()? } else { 0 };
(o, s, c)
}};
}
let sanity = stream.read_u32()?;
let version_field = stream.read_i32()?;
let (string_literal_offset, string_literal_size, _) = sec!();
let (string_literal_data_offset, string_literal_data_size, _) = sec!();
let (string_offset, string_size, _) = sec!();
let (events_offset, events_size, events_count) = sec!();
let (properties_offset, properties_size, properties_count) = sec!();
let (methods_offset, methods_size, methods_count) = sec!();
let (parameter_default_values_offset, parameter_default_values_size, _) = sec!();
let (field_default_values_offset, field_default_values_size, _) = sec!();
let (field_and_parameter_default_value_data_offset, field_and_parameter_default_value_data_size, field_and_parameter_default_value_data_count) = sec!();
let (field_marshaled_sizes_offset, field_marshaled_sizes_size, _) = sec!();
let (parameters_offset, parameters_size, parameters_count) = sec!();
let (fields_offset, fields_size, fields_count) = sec!();
let (generic_parameters_offset, generic_parameters_size, generic_parameters_count) = sec!();
let (generic_parameter_constraints_offset, generic_parameter_constraints_size, _) = sec!();
let (generic_containers_offset, generic_containers_size, generic_containers_count) = sec!();
let (nested_types_offset, nested_types_size, nested_types_count) = sec!();
let (interfaces_offset, interfaces_size, _) = sec!();
let (vtable_methods_offset, vtable_methods_size, _) = sec!();
let (interface_offsets_offset, interface_offsets_size, interface_offsets_count) = sec!();
let (type_definitions_offset, type_definitions_size, type_definitions_count) = sec!();
let (type_inline_arrays_offset, type_inline_arrays_size, type_inline_arrays_count) = if version >= 104.0 { sec!() } else { (0, 0, 0) };
let (rgctx_entries_offset, rgctx_entries_count) = if version <= 24.15 { let (o, s, _) = sec!(); (o, s) } else { (0, 0) };
let (images_offset, images_size, _) = sec!();
let (assemblies_offset, assemblies_size, _) = sec!();
let (metadata_usage_lists_offset, metadata_usage_lists_count) = if version < 27.0 { let (o, s, _) = sec!(); (o, s) } else { (0, 0) };
let (metadata_usage_pairs_offset, metadata_usage_pairs_count) = if version < 27.0 { let (o, s, _) = sec!(); (o, s) } else { (0, 0) };
let (field_refs_offset, field_refs_size, _) = sec!();
let (referenced_assemblies_offset, referenced_assemblies_size, _) = sec!();
let (attributes_info_offset, attributes_info_count, attribute_types_offset, attribute_types_count,
attribute_data_offset, attribute_data_size, attribute_data_range_offset, attribute_data_range_size) =
if version < 29.0 {
let (ao, ac, _) = sec!();
let (to, tc, _) = sec!();
(ao, ac, to, tc, 0, 0, 0, 0)
} else {
let (ddo, dds, _) = sec!();
let (dro, drs, _) = sec!();
(0, 0, 0, 0, ddo, dds, dro, drs)
};
let (unresolved_virtual_call_parameter_types_offset, unresolved_virtual_call_parameter_types_size, _) = sec!();
let (unresolved_virtual_call_parameter_ranges_offset, unresolved_virtual_call_parameter_ranges_size, _) = sec!();
let (windows_runtime_type_names_offset, windows_runtime_type_names_size, _) = sec!();
let (windows_runtime_strings_offset, windows_runtime_strings_size) = if version >= 27.0 { let (o, s, _) = sec!(); (o, s) } else { (0, 0) };
let (exported_type_definitions_offset, exported_type_definitions_size) = if version >= 24.0 { let (o, s, _) = sec!(); (o, s) } else { (0, 0) };
Ok(Self {
sanity, version: version_field,
string_literal_offset, string_literal_size,
string_literal_data_offset, string_literal_data_size,
string_offset, string_size,
events_offset, events_size,
properties_offset, properties_size,
methods_offset, methods_size,
parameter_default_values_offset, parameter_default_values_size,
field_default_values_offset, field_default_values_size,
field_and_parameter_default_value_data_offset, field_and_parameter_default_value_data_size,
field_marshaled_sizes_offset, field_marshaled_sizes_size,
parameters_offset, parameters_size,
fields_offset, fields_size,
generic_parameters_offset, generic_parameters_size,
generic_parameter_constraints_offset, generic_parameter_constraints_size,
generic_containers_offset, generic_containers_size,
nested_types_offset, nested_types_size,
interfaces_offset, interfaces_size,
vtable_methods_offset, vtable_methods_size,
interface_offsets_offset, interface_offsets_size,
type_definitions_offset, type_definitions_size,
rgctx_entries_offset, rgctx_entries_count,
images_offset, images_size,
assemblies_offset, assemblies_size,
metadata_usage_lists_offset, metadata_usage_lists_count,
metadata_usage_pairs_offset, metadata_usage_pairs_count,
field_refs_offset, field_refs_size,
referenced_assemblies_offset, referenced_assemblies_size,
attributes_info_offset, attributes_info_count,
attribute_types_offset, attribute_types_count,
attribute_data_offset, attribute_data_size,
attribute_data_range_offset, attribute_data_range_size,
unresolved_virtual_call_parameter_types_offset, unresolved_virtual_call_parameter_types_size,
unresolved_virtual_call_parameter_ranges_offset, unresolved_virtual_call_parameter_ranges_size,
windows_runtime_type_names_offset, windows_runtime_type_names_size,
windows_runtime_strings_offset, windows_runtime_strings_size,
exported_type_definitions_offset, exported_type_definitions_size,
type_definitions_count, generic_containers_count, interface_offsets_count,
parameters_count, events_count, properties_count, nested_types_count,
methods_count, generic_parameters_count, fields_count,
field_and_parameter_default_value_data_count,
type_inline_arrays_offset, type_inline_arrays_size, type_inline_arrays_count,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppImageDefinition {
pub name_index: i32,
pub assembly_index: i32,
pub type_start: i32,
pub type_count: i32,
pub exported_type_start: i32,
pub exported_type_count: i32,
pub entry_point_index: i32,
pub token: u32,
pub custom_attribute_start: i32,
pub custom_attribute_count: i32,
}
impl Il2CppImageDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let name_index = stream.read_i32()?;
let assembly_index = stream.read_i32()?;
let type_start = read_type_def_idx(stream)?;
let type_count = stream.read_u32()?;
let exported_type_start = if version >= 24.0 { read_type_def_idx(stream)? } else { 0 };
let exported_type_count = if version >= 24.0 { stream.read_u32()? } else { 0 };
let entry_point_index = read_method_idx(stream)?;
let token = read_versioned!(stream, version, 19.0, 999.0, read_u32, 0);
let custom_attribute_start = read_versioned!(stream, version, 24.1, 999.0, read_i32, 0);
let custom_attribute_count = read_versioned!(stream, version, 24.1, 999.0, read_i32, 0);
Ok(Self {
name_index, assembly_index, type_start, type_count: type_count as i32,
exported_type_start, exported_type_count: exported_type_count as i32,
entry_point_index, token, custom_attribute_start, custom_attribute_count,
})
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } let mut size = 4 * 4; if version >= 24.0 { size += 8; } if version >= 19.0 { size += 4; } if version >= 19.0 { size += 4; } if version >= 24.1 { size += 8; } size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppAssemblyNameDefinition {
pub name_index: i32,
pub culture_index: i32,
pub hash_value_index: i32,
pub public_key_index: i32,
pub hash_alg: i32,
pub hash_len: i32,
pub flags: u32,
pub major: i32,
pub minor: i32,
pub build: i32,
pub revision: i32,
pub public_key_token: [u8; 8],
}
impl Il2CppAssemblyNameDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let name_index = stream.read_i32()?;
let culture_index = stream.read_i32()?;
let hash_value_index = if version <= 24.3 && (version - 24.15).abs() > 0.001 {
stream.read_i32()?
} else {
0
};
let public_key_index = stream.read_i32()?;
let hash_alg = stream.read_i32()?;
let hash_len = stream.read_i32()?;
let flags = stream.read_u32()?;
let major = stream.read_i32()?;
let minor = stream.read_i32()?;
let build = stream.read_i32()?;
let revision = stream.read_i32()?;
let token_bytes = stream.read_bytes(8)?;
let mut public_key_token = [0u8; 8];
public_key_token.copy_from_slice(&token_bytes);
Ok(Self {
name_index,
culture_index,
hash_value_index,
public_key_index,
hash_alg,
hash_len,
flags,
major,
minor,
build,
revision,
public_key_token,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppAssemblyDefinition {
pub image_index: i32,
pub token: u32,
pub module_token: u32,
pub custom_attribute_index: i32,
pub referenced_assembly_start: i32,
pub referenced_assembly_count: i32,
pub aname: Il2CppAssemblyNameDefinition,
}
impl Il2CppAssemblyDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let image_index = stream.read_i32()?;
let token = read_versioned!(stream, version, 24.1, 999.0, read_u32, 0);
let module_token = read_versioned!(stream, version, 38.0, 999.0, read_u32, 0);
let custom_attribute_index = read_versioned!(stream, version, 0.0, 24.0, read_i32, 0);
let referenced_assembly_start = read_versioned!(stream, version, 20.0, 999.0, read_i32, 0);
let referenced_assembly_count = read_versioned!(stream, version, 20.0, 999.0, read_i32, 0);
let aname = Il2CppAssemblyNameDefinition::read(stream, version)?;
Ok(Self {
image_index, token, custom_attribute_index,
referenced_assembly_start, referenced_assembly_count, aname,
module_token,
})
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } let mut size = 4; if version >= 24.1 { size += 4; } if version <= 24.0 { size += 4; } if version >= 20.0 { size += 8; } size += 4 * 10 + 8; if version <= 24.3 { size += 4; } size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppTypeDefinition {
pub name_index: i32,
pub namespace_index: i32,
pub custom_attribute_index: i32,
pub byval_type_index: i32,
pub byref_type_index: i32,
pub declaring_type_index: i32,
pub parent_index: i32,
pub element_type_index: i32,
pub rgctx_start_index: i32,
pub rgctx_count: i32,
pub generic_container_index: i32,
pub delegate_wrapper_from_managed_to_native_index: i32,
pub marshaling_functions_index: i32,
pub ccw_function_index: i32,
pub guid_index: i32,
pub flags: u32,
pub field_start: i32,
pub method_start: i32,
pub event_start: i32,
pub property_start: i32,
pub nested_types_start: i32,
pub interfaces_start: i32,
pub vtable_start: i32,
pub interface_offsets_start: i32,
pub method_count: u16,
pub property_count: u16,
pub field_count: u16,
pub event_count: u16,
pub nested_type_count: u16,
pub vtable_count: u16,
pub interfaces_count: u16,
pub interface_offsets_count: u16,
pub bitfield: u32,
pub token: u32,
}
impl Il2CppTypeDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let name_index = stream.read_i32()?;
let namespace_index = stream.read_i32()?;
let custom_attribute_index = read_versioned!(stream, version, 0.0, 24.0, read_i32, 0);
let byval_type_index = read_type_idx(stream)?;
let byref_type_index = read_versioned!(stream, version, 0.0, 24.5, read_i32, 0);
let declaring_type_index = read_type_idx(stream)?;
let parent_index = read_type_idx(stream)?;
let element_type_index = if version < 35.0 { stream.read_i32()? } else { -1 };
let rgctx_start_index = read_versioned!(stream, version, 0.0, 24.15, read_i32, 0);
let rgctx_count = read_versioned!(stream, version, 0.0, 24.15, read_i32, 0);
let generic_container_index = read_gc_idx(stream)?;
let delegate_wrapper_from_managed_to_native_index = read_versioned!(stream, version, 0.0, 22.0, read_i32, 0);
let marshaling_functions_index = read_versioned!(stream, version, 0.0, 22.0, read_i32, 0);
let ccw_function_index = read_versioned!(stream, version, 21.0, 22.0, read_i32, 0);
let guid_index = read_versioned!(stream, version, 21.0, 22.0, read_i32, 0);
let flags = stream.read_u32()?;
let field_start = read_field_idx(stream)?;
let method_start = read_method_idx(stream)?;
let event_start = read_event_idx(stream)?;
let property_start = read_property_idx(stream)?;
let nested_types_start = read_nested_type_idx(stream)?;
let interfaces_start = read_ioffset_idx(stream)?;
let vtable_start = stream.read_i32()?;
let interface_offsets_start = read_ioffset_idx(stream)?;
let method_count = stream.read_u16()?;
let property_count = stream.read_u16()?;
let field_count = stream.read_u16()?;
let event_count = stream.read_u16()?;
let nested_type_count = stream.read_u16()?;
let vtable_count = stream.read_u16()?;
let interfaces_count = stream.read_u16()?;
let interface_offsets_count = stream.read_u16()?;
let bitfield = stream.read_u32()?;
let token = read_versioned!(stream, version, 19.0, 999.0, read_u32, 0);
Ok(Self {
name_index, namespace_index, custom_attribute_index,
byval_type_index, byref_type_index, declaring_type_index,
parent_index, element_type_index, rgctx_start_index, rgctx_count,
generic_container_index, delegate_wrapper_from_managed_to_native_index,
marshaling_functions_index, ccw_function_index, guid_index,
flags, field_start, method_start, event_start, property_start,
nested_types_start, interfaces_start, vtable_start, interface_offsets_start,
method_count, property_count, field_count, event_count,
nested_type_count, vtable_count, interfaces_count, interface_offsets_count,
bitfield, token,
})
}
pub fn is_value_type(&self) -> bool { (self.bitfield & 0x1) == 1 }
pub fn is_enum(&self) -> bool { ((self.bitfield >> 1) & 0x1) == 1 }
pub fn has_finalizer(&self) -> bool { ((self.bitfield >> 2) & 0x1) == 1 }
pub fn has_cctor(&self) -> bool { ((self.bitfield >> 3) & 0x1) == 1 }
pub fn is_blittable(&self) -> bool { ((self.bitfield >> 4) & 0x1) == 1 }
pub fn is_import_or_windows_runtime(&self) -> bool { ((self.bitfield >> 5) & 0x1) == 1 }
pub fn packing_size(&self) -> u32 { decode_packing_size((self.bitfield >> 6) & 0xF) }
pub fn packing_size_is_default(&self) -> bool { ((self.bitfield >> 10) & 0x1) == 1 }
pub fn class_size_is_default(&self) -> bool { ((self.bitfield >> 11) & 0x1) == 1 }
pub fn specified_packing_size(&self) -> u32 { decode_packing_size((self.bitfield >> 12) & 0xF) }
pub fn is_by_ref_like(&self) -> bool { ((self.bitfield >> 16) & 0x1) == 1 }
pub fn has_inline_array(&self) -> bool { ((self.bitfield >> 17) & 0x1) == 1 }
pub fn is_abstract(&self) -> bool { (self.flags & 0x80) != 0 }
pub fn is_interface(&self) -> bool { (self.flags & 0x20) != 0 }
pub fn is_sealed(&self) -> bool { (self.flags & 0x100) != 0 }
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } let mut size = 0usize;
size += 4 + 4; if version <= 24.0 { size += 4; } size += 4; if version <= 24.5 { size += 4; } size += 4; size += 4; if version < 35.0 { size += 4; } if version <= 24.15 { size += 8; } size += 4; if version <= 22.0 { size += 8; } if version >= 21.0 && version <= 22.0 { size += 8; } size += 4; size += 4 * 8; size += 2 * 8; size += 4; if version >= 19.0 { size += 4; } size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppMethodDefinition {
pub name_index: u32,
pub declaring_type: i32,
pub return_type: i32,
pub return_parameter_token: i32,
pub parameter_start: i32,
pub custom_attribute_index: i32,
pub generic_container_index: i32,
pub method_index: i32,
pub invoker_index: i32,
pub delegate_wrapper_index: i32,
pub rgctx_start_index: i32,
pub rgctx_count: i32,
pub token: u32,
pub flags: u16,
pub iflags: u16,
pub slot: u16,
pub parameter_count: u16,
}
impl Il2CppMethodDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let name_index = stream.read_u32()?;
let declaring_type = read_type_def_idx(stream)?;
let return_type = read_type_idx(stream)?;
let return_parameter_token = read_versioned!(stream, version, 31.0, 999.0, read_i32, 0);
let parameter_start = read_param_def_idx(stream)?;
let custom_attribute_index = read_versioned!(stream, version, 0.0, 24.0, read_i32, 0);
let generic_container_index = read_gc_idx(stream)?;
let method_index = read_versioned!(stream, version, 0.0, 24.15, read_i32, 0);
let invoker_index = read_versioned!(stream, version, 0.0, 24.15, read_i32, 0);
let delegate_wrapper_index = read_versioned!(stream, version, 0.0, 24.15, read_i32, 0);
let rgctx_start_index = read_versioned!(stream, version, 0.0, 24.15, read_i32, 0);
let rgctx_count = read_versioned!(stream, version, 0.0, 24.15, read_i32, 0);
let token = stream.read_u32()?;
let flags = stream.read_u16()?;
let iflags = stream.read_u16()?;
let slot = stream.read_u16()?;
let parameter_count = stream.read_u16()?;
Ok(Self {
name_index, declaring_type, return_type, return_parameter_token,
parameter_start, custom_attribute_index, generic_container_index,
method_index, invoker_index, delegate_wrapper_index,
rgctx_start_index, rgctx_count, token, flags, iflags, slot, parameter_count,
})
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } let mut size = 4 + 4 + 4; if version >= 31.0 { size += 4; } size += 4; if version <= 24.0 { size += 4; } size += 4; if version <= 24.15 { size += 4 * 5; } size += 4; size += 2 * 4; size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppParameterDefinition {
pub name_index: i32,
pub token: u32,
pub custom_attribute_index: i32,
pub type_index: i32,
}
impl Il2CppParameterDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let name_index = stream.read_i32()?;
let token = stream.read_u32()?;
let custom_attribute_index = read_versioned!(stream, version, 0.0, 24.0, read_i32, 0);
let type_index = read_type_idx(stream)?;
Ok(Self { name_index, token, custom_attribute_index, type_index })
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } let mut size = 4 + 4 + 4; if version <= 24.0 { size += 4; } size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppFieldDefinition {
pub name_index: i32,
pub type_index: i32,
pub custom_attribute_index: i32,
pub token: u32,
}
impl Il2CppFieldDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let name_index = stream.read_i32()?;
let type_index = read_type_idx(stream)?;
let custom_attribute_index = read_versioned!(stream, version, 0.0, 24.0, read_i32, 0);
let token = read_versioned!(stream, version, 19.0, 999.0, read_u32, 0);
Ok(Self { name_index, type_index, custom_attribute_index, token })
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } let mut size = 4 + 4; if version <= 24.0 { size += 4; }
if version >= 19.0 { size += 4; }
size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppFieldDefaultValue {
pub field_index: i32,
pub type_index: i32,
pub data_index: i32,
}
impl Il2CppFieldDefaultValue {
pub fn read(stream: &mut BinaryStream, _version: f64) -> Result<Self> {
let field_index = read_field_idx(stream)?;
let type_index = read_type_idx(stream)?;
let data_index = read_dvdata_idx(stream)?;
Ok(Self { field_index, type_index, data_index })
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } 12
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppParameterDefaultValue {
pub parameter_index: i32,
pub type_index: i32,
pub data_index: i32,
}
impl Il2CppParameterDefaultValue {
pub fn read(stream: &mut BinaryStream, _version: f64) -> Result<Self> {
let parameter_index = read_param_def_idx(stream)?;
let type_index = read_type_idx(stream)?;
let data_index = read_dvdata_idx(stream)?;
Ok(Self { parameter_index, type_index, data_index })
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } 12
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppPropertyDefinition {
pub name_index: i32,
pub get: i32,
pub set: i32,
pub attrs: u32,
pub custom_attribute_index: i32,
pub token: u32,
}
impl Il2CppPropertyDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let name_index = stream.read_i32()?;
let get = read_method_idx(stream)?;
let set = read_method_idx(stream)?;
let attrs = stream.read_u32()?;
let custom_attribute_index = read_versioned!(stream, version, 0.0, 24.0, read_i32, 0);
let token = read_versioned!(stream, version, 19.0, 999.0, read_u32, 0);
Ok(Self { name_index, get, set, attrs, custom_attribute_index, token })
}
pub fn byte_size(version: f64) -> usize {
if version >= 105.0 { return 0; } let mut size = 4 * 4; if version <= 24.0 { size += 4; }
if version >= 19.0 { size += 4; }
size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppEventDefinition {
pub name_index: i32,
pub type_index: i32,
pub add: i32,
pub remove: i32,
pub raise: i32,
pub custom_attribute_index: i32,
pub token: u32,
}
impl Il2CppEventDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let name_index = stream.read_i32()?;
let type_index = read_type_idx(stream)?;
let add = read_method_idx(stream)?;
let remove = read_method_idx(stream)?;
let raise = read_method_idx(stream)?;
let custom_attribute_index = read_versioned!(stream, version, 0.0, 24.0, read_i32, 0);
let token = read_versioned!(stream, version, 19.0, 999.0, read_u32, 0);
Ok(Self { name_index, type_index, add, remove, raise, custom_attribute_index, token })
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } let mut size = 4 * 5;
if version <= 24.0 { size += 4; }
if version >= 19.0 { size += 4; }
size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppGenericContainer {
pub owner_index: i32,
pub type_argc: i32,
pub is_method: i32,
pub generic_parameter_start: i32,
}
impl Il2CppGenericContainer {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let owner_index = stream.read_i32()?;
let (type_argc, is_method) = if version >= 106.0 {
(stream.read_u16()? as i32, stream.read_u8()? as i32)
} else {
(stream.read_i32()?, stream.read_i32()?)
};
let generic_parameter_start = read_gp_idx(stream)?;
Ok(Self { owner_index, type_argc, is_method, generic_parameter_start })
}
pub fn byte_size(version: f64) -> usize {
if version >= 106.0 { return 0; } 16 }
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppGenericParameter {
pub owner_index: i32,
pub name_index: u32,
pub constraints_start: i16,
pub constraints_count: i16,
pub num: u16,
pub flags: u16,
}
impl Il2CppGenericParameter {
pub fn read(stream: &mut BinaryStream, _version: f64) -> Result<Self> {
Ok(Self {
owner_index: read_gc_idx(stream)?,
name_index: stream.read_u32()?,
constraints_start: stream.read_i16()?,
constraints_count: stream.read_i16()?,
num: stream.read_u16()?,
flags: stream.read_u16()?,
})
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } 16 }
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppCustomAttributeTypeRange {
pub token: u32,
pub start: i32,
pub count: i32,
}
impl Il2CppCustomAttributeTypeRange {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
Ok(Self {
token: read_versioned!(stream, version, 24.1, 999.0, read_u32, 0),
start: stream.read_i32()?,
count: stream.read_i32()?,
})
}
pub fn byte_size(version: f64) -> usize {
let mut size = 8; if version >= 24.1 { size += 4; } size
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppCustomAttributeDataRange {
pub token: u32,
pub start_offset: u32,
}
impl Il2CppCustomAttributeDataRange {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
token: stream.read_u32()?,
start_offset: stream.read_u32()?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppMetadataUsageList {
pub start: u32,
pub count: u32,
}
impl Il2CppMetadataUsageList {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
start: stream.read_u32()?,
count: stream.read_u32()?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppMetadataUsagePair {
pub destination_index: u32,
pub encoded_source_index: u32,
}
impl Il2CppMetadataUsagePair {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
destination_index: stream.read_u32()?,
encoded_source_index: stream.read_u32()?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppStringLiteral {
pub length: u32, pub data_index: u32,
}
impl Il2CppStringLiteral {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let length = if version < 35.0 { stream.read_u32()? } else { 0 };
let data_index = stream.read_u32()?;
Ok(Self { length, data_index })
}
pub fn byte_size(version: f64) -> usize {
if version < 35.0 { 8 } else { 4 }
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppFieldRef {
pub type_index: i32,
pub field_index: i32,
}
impl Il2CppFieldRef {
pub fn read(stream: &mut BinaryStream, _version: f64) -> Result<Self> {
let type_index = read_type_idx(stream)?;
let field_index = read_field_idx(stream)?;
Ok(Self { type_index, field_index })
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } 8
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppInterfaceOffset {
pub type_index: i32,
pub offset: i32,
}
impl Il2CppInterfaceOffset {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
let type_index = read_type_idx(stream)?;
let offset = stream.read_i32()?;
Ok(Self { type_index, offset })
}
pub fn byte_size(type_index_size: usize) -> usize {
type_index_size + 4
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppInlineArrayLength {
pub type_index: i32,
pub length: i32,
}
impl Il2CppInlineArrayLength {
pub fn read(stream: &mut BinaryStream, _version: f64) -> Result<Self> {
let type_index = read_type_idx(stream)?;
let length = stream.read_i32()?;
Ok(Self { type_index, length })
}
pub fn byte_size(version: f64) -> usize {
if version >= 38.0 { return 0; } 8
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppRGCTXDefinitionData {
pub rgctx_data_dummy: i32,
}
impl Il2CppRGCTXDefinitionData {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
rgctx_data_dummy: stream.read_i32()?,
})
}
pub fn method_index(&self) -> i32 {
self.rgctx_data_dummy
}
pub fn type_index(&self) -> i32 {
self.rgctx_data_dummy
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppRGCTXConstrainedData {
pub type_index: i32,
pub encoded_method_index: i32,
}
impl Il2CppRGCTXConstrainedData {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
type_index: stream.read_i32()?,
encoded_method_index: stream.read_i32()?,
})
}
pub fn method_index(&self) -> i32 {
self.encoded_method_index
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppRGCTXDefinition {
pub rgctx_type: i64,
pub def_data: Option<Il2CppRGCTXDefinitionData>,
pub constrained_data: Option<Il2CppRGCTXConstrainedData>,
pub data_va: u64,
}
impl Il2CppRGCTXDefinition {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let rgctx_type = if version < 29.0 {
stream.read_i32()? as i64
} else {
stream.read_i64()?
};
let mut def_data = None;
let constrained_data = None;
let mut data_va = 0u64;
if version < 27.2 {
def_data = Some(Il2CppRGCTXDefinitionData::read(stream)?);
} else {
data_va = stream.read_ptr()?;
}
Ok(Self {
rgctx_type,
def_data,
constrained_data,
data_va,
})
}
pub fn resolve_data(&mut self, stream: &mut BinaryStream, map_vatr: &dyn Fn(u64) -> Result<u64>) -> Result<()> {
if self.data_va == 0 || self.def_data.is_some() || self.constrained_data.is_some() {
return Ok(());
}
let raw_offset = map_vatr(self.data_va)?;
let saved_pos = stream.position();
stream.set_position(raw_offset);
if self.rgctx_type == 5 {
self.constrained_data = Some(Il2CppRGCTXConstrainedData::read(stream)?);
} else {
self.def_data = Some(Il2CppRGCTXDefinitionData::read(stream)?);
}
stream.set_position(saved_pos);
Ok(())
}
pub fn method_index(&self) -> i32 {
if let Some(ref d) = self.def_data {
d.method_index()
} else if let Some(ref c) = self.constrained_data {
c.method_index()
} else {
-1
}
}
pub fn type_index(&self) -> i32 {
if let Some(ref d) = self.def_data {
d.type_index()
} else if let Some(ref c) = self.constrained_data {
c.type_index
} else {
-1
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppCodeRegistration {
pub method_pointers_count: u64,
pub method_pointers: u64,
pub delegate_wrappers_from_native_to_managed_count: u64,
pub delegate_wrappers_from_native_to_managed: u64,
pub reverse_pinvoke_wrapper_count: u64,
pub reverse_pinvoke_wrappers: u64,
pub delegate_wrappers_from_managed_to_native_count: u64,
pub delegate_wrappers_from_managed_to_native: u64,
pub marshaling_functions_count: u64,
pub marshaling_functions: u64,
pub ccw_marshaling_functions_count: u64,
pub ccw_marshaling_functions: u64,
pub generic_method_pointers_count: u64,
pub generic_method_pointers: u64,
pub generic_adjustor_thunks: u64,
pub invoker_pointers_count: u64,
pub invoker_pointers: u64,
pub custom_attribute_count: u64,
pub custom_attribute_generators: u64,
pub guid_count: u64,
pub guids: u64,
pub unresolved_virtual_call_count: u64,
pub unresolved_virtual_call_pointers: u64,
pub unresolved_instance_call_pointers: u64,
pub unresolved_static_call_pointers: u64,
pub interop_data_count: u64,
pub interop_data: u64,
pub windows_runtime_factory_count: u64,
pub windows_runtime_factory_table: u64,
pub code_gen_modules_count: u64,
pub code_gen_modules: u64,
}
impl Il2CppCodeRegistration {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
Ok(Self {
method_pointers_count: if version <= 24.1 { stream.read_ptr()? } else { 0 },
method_pointers: if version <= 24.1 { stream.read_ptr()? } else { 0 },
delegate_wrappers_from_native_to_managed_count: if version <= 21.0 { stream.read_ptr()? } else { 0 },
delegate_wrappers_from_native_to_managed: if version <= 21.0 { stream.read_ptr()? } else { 0 },
reverse_pinvoke_wrapper_count: if version >= 22.0 { stream.read_ptr()? } else { 0 },
reverse_pinvoke_wrappers: if version >= 22.0 { stream.read_ptr()? } else { 0 },
delegate_wrappers_from_managed_to_native_count: if version <= 22.0 { stream.read_ptr()? } else { 0 },
delegate_wrappers_from_managed_to_native: if version <= 22.0 { stream.read_ptr()? } else { 0 },
marshaling_functions_count: if version <= 22.0 { stream.read_ptr()? } else { 0 },
marshaling_functions: if version <= 22.0 { stream.read_ptr()? } else { 0 },
ccw_marshaling_functions_count: if version >= 21.0 && version <= 22.0 { stream.read_ptr()? } else { 0 },
ccw_marshaling_functions: if version >= 21.0 && version <= 22.0 { stream.read_ptr()? } else { 0 },
generic_method_pointers_count: stream.read_ptr()?,
generic_method_pointers: stream.read_ptr()?,
generic_adjustor_thunks: if version >= 24.5 { stream.read_ptr()? } else { 0 },
invoker_pointers_count: stream.read_ptr()?,
invoker_pointers: stream.read_ptr()?,
custom_attribute_count: if version <= 24.5 { stream.read_ptr()? } else { 0 },
custom_attribute_generators: if version <= 24.5 { stream.read_ptr()? } else { 0 },
guid_count: if version >= 21.0 && version <= 22.0 { stream.read_ptr()? } else { 0 },
guids: if version >= 21.0 && version <= 22.0 { stream.read_ptr()? } else { 0 },
unresolved_virtual_call_count: if version >= 22.0 { stream.read_ptr()? } else { 0 },
unresolved_virtual_call_pointers: if version >= 22.0 { stream.read_ptr()? } else { 0 },
unresolved_instance_call_pointers: if version >= 29.1 { stream.read_ptr()? } else { 0 },
unresolved_static_call_pointers: if version >= 29.1 { stream.read_ptr()? } else { 0 },
interop_data_count: if version >= 23.0 { stream.read_ptr()? } else { 0 },
interop_data: if version >= 23.0 { stream.read_ptr()? } else { 0 },
windows_runtime_factory_count: if version >= 24.3 { stream.read_ptr()? } else { 0 },
windows_runtime_factory_table: if version >= 24.3 { stream.read_ptr()? } else { 0 },
code_gen_modules_count: if version >= 24.2 { stream.read_ptr()? } else { 0 },
code_gen_modules: if version >= 24.2 { stream.read_ptr()? } else { 0 },
})
}
pub fn field_count(version: f64) -> usize {
let mut count = 0usize;
if version <= 24.1 { count += 2; }
if version <= 21.0 { count += 2; }
if version >= 22.0 { count += 2; }
if version <= 22.0 { count += 4; }
if version >= 21.0 && version <= 22.0 { count += 2; }
count += 4;
if version >= 24.5 { count += 1; }
if version <= 24.5 { count += 2; }
if version >= 21.0 && version <= 22.0 { count += 2; }
if version >= 22.0 { count += 2; }
if version >= 29.1 { count += 2; }
if version >= 23.0 { count += 2; }
if version >= 24.3 { count += 2; }
if version >= 24.2 { count += 2; }
count
}
pub fn struct_size(is_32bit: bool, version: f64) -> usize {
let ptr = if is_32bit { 4 } else { 8 };
Self::field_count(version) * ptr
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppMetadataRegistration {
pub generic_classes_count: u64,
pub generic_classes: u64,
pub generic_insts_count: u64,
pub generic_insts: u64,
pub generic_method_table_count: u64,
pub generic_method_table: u64,
pub types_count: u64,
pub types: u64,
pub method_specs_count: u64,
pub method_specs: u64,
pub method_references_count: u64,
pub method_references: u64,
pub field_offsets_count: u64,
pub field_offsets: u64,
pub type_definitions_sizes_count: u64,
pub type_definitions_sizes: u64,
pub metadata_usages_count: u64,
pub metadata_usages: u64,
}
impl Il2CppMetadataRegistration {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
Ok(Self {
generic_classes_count: stream.read_ptr()?,
generic_classes: stream.read_ptr()?,
generic_insts_count: stream.read_ptr()?,
generic_insts: stream.read_ptr()?,
generic_method_table_count: stream.read_ptr()?,
generic_method_table: stream.read_ptr()?,
types_count: stream.read_ptr()?,
types: stream.read_ptr()?,
method_specs_count: stream.read_ptr()?,
method_specs: stream.read_ptr()?,
method_references_count: if version <= 16.0 { stream.read_ptr()? } else { 0 },
method_references: if version <= 16.0 { stream.read_ptr()? } else { 0 },
field_offsets_count: stream.read_ptr()?,
field_offsets: stream.read_ptr()?,
type_definitions_sizes_count: stream.read_ptr()?,
type_definitions_sizes: stream.read_ptr()?,
metadata_usages_count: if version >= 19.0 { stream.read_ptr()? } else { 0 },
metadata_usages: if version >= 19.0 { stream.read_ptr()? } else { 0 },
})
}
pub fn field_count(version: f64) -> usize {
let mut count = 16usize; if version <= 16.0 { count += 2; }
if version >= 19.0 { count += 2; }
count
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppType {
pub datapoint: u64,
pub bits: u32,
pub attrs: u32,
pub type_enum: u8,
pub num_mods: u8,
pub byref: u8,
pub pinned: u8,
pub valuetype: u8,
}
impl Il2CppType {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
let datapoint = stream.read_ptr()?;
let bits = stream.read_u32()?;
let mut t = Self {
datapoint,
bits,
..Default::default()
};
t.attrs = bits & 0xFFFF;
t.type_enum = ((bits >> 16) & 0xFF) as u8;
Ok(t)
}
pub fn init(&mut self, version: f64) {
self.attrs = self.bits & 0xFFFF;
self.type_enum = ((self.bits >> 16) & 0xFF) as u8;
if version >= 27.2 {
self.num_mods = ((self.bits >> 24) & 0x1F) as u8;
self.byref = ((self.bits >> 29) & 1) as u8;
self.pinned = ((self.bits >> 30) & 1) as u8;
self.valuetype = (self.bits >> 31) as u8;
} else {
self.num_mods = ((self.bits >> 24) & 0x3F) as u8;
self.byref = ((self.bits >> 30) & 1) as u8;
self.pinned = (self.bits >> 31) as u8;
}
}
pub fn klass_index(&self) -> u64 {
self.datapoint
}
pub fn type_handle(&self) -> u64 {
self.datapoint
}
pub fn type_ptr(&self) -> u64 {
self.datapoint
}
pub fn array(&self) -> u64 {
self.datapoint
}
pub fn generic_parameter_index(&self) -> u64 {
self.datapoint
}
pub fn generic_parameter_handle(&self) -> u64 {
self.datapoint
}
pub fn generic_class(&self) -> u64 {
self.datapoint
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppGenericClass {
pub type_definition_index: u64,
pub type_ptr: u64,
pub context: Il2CppGenericContext,
pub cached_class: u64,
}
impl Il2CppGenericClass {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let type_definition_index;
let type_ptr;
if version >= 27.0 {
type_definition_index = 0;
type_ptr = stream.read_ptr()?;
} else {
type_definition_index = stream.read_ptr()?;
type_ptr = 0;
}
let context = Il2CppGenericContext::read(stream)?;
let cached_class = stream.read_ptr()?;
Ok(Self {
type_definition_index,
type_ptr,
context,
cached_class,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppGenericContext {
pub class_inst: u64,
pub method_inst: u64,
}
impl Il2CppGenericContext {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
class_inst: stream.read_ptr()?,
method_inst: stream.read_ptr()?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppGenericInst {
pub type_argc: u64,
pub type_argv: u64,
}
impl Il2CppGenericInst {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
type_argc: stream.read_ptr()?,
type_argv: stream.read_ptr()?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppArrayType {
pub etype: u64,
pub rank: i32,
pub numsizes: u8,
pub numlobounds: u8,
pub sizes: u64,
pub lobounds: u64,
}
impl Il2CppArrayType {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
let etype = stream.read_ptr()?;
let rank = stream.read_u8()?;
let numsizes = stream.read_u8()?;
let numlobounds = stream.read_u8()?;
let _padding = stream.read_u8()?;
let sizes = stream.read_ptr()?;
let lobounds = stream.read_ptr()?;
Ok(Self {
etype,
rank: rank as i32,
numsizes,
numlobounds,
sizes,
lobounds,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppGenericMethodFunctionsDefinitions {
pub generic_method_index: i32,
pub indices: Il2CppGenericMethodIndices,
}
impl Il2CppGenericMethodFunctionsDefinitions {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
Ok(Self {
generic_method_index: stream.read_i32()?,
indices: Il2CppGenericMethodIndices::read(stream, version)?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppGenericMethodIndices {
pub method_index: i32,
pub invoker_index: i32,
pub adjustor_thunk: i32,
}
impl Il2CppGenericMethodIndices {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
Ok(Self {
method_index: stream.read_i32()?,
invoker_index: stream.read_i32()?,
adjustor_thunk: if (version >= 24.5 && (version - 27.0).abs() > 0.001) || version >= 27.1 {
stream.read_i32()?
} else {
0
},
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppMethodSpec {
pub method_definition_index: i32,
pub class_index_index: i32,
pub method_index_index: i32,
}
impl Il2CppMethodSpec {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
method_definition_index: stream.read_i32()?,
class_index_index: stream.read_i32()?,
method_index_index: stream.read_i32()?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppCodeGenModule {
pub module_name: u64,
pub method_pointer_count: i64,
pub method_pointers: u64,
pub adjustor_thunk_count: u64,
pub adjustor_thunks: u64,
pub invoker_indices: u64,
pub reverse_pinvoke_wrapper_count: u64,
pub reverse_pinvoke_wrapper_indices: u64,
pub rgctx_ranges_count: i64,
pub rgctx_ranges: u64,
pub rgctxs_count: i64,
pub rgctxs: u64,
pub debugger_metadata: u64,
pub custom_attribute_cache_generator: u64,
pub module_initializer: u64,
pub static_constructor_type_indices: u64,
pub metadata_registration: u64,
pub code_registration: u64,
}
impl Il2CppCodeGenModule {
pub fn read(stream: &mut BinaryStream, version: f64) -> Result<Self> {
let module_name = stream.read_ptr()?;
let method_pointer_count = stream.read_ptr_signed()?;
let method_pointers = stream.read_ptr()?;
let has_adjustor_thunks = (version >= 24.5 && version < 27.0) || version >= 27.1;
let adjustor_thunk_count = if has_adjustor_thunks { stream.read_ptr()? } else { 0 };
let adjustor_thunks = if has_adjustor_thunks { stream.read_ptr()? } else { 0 };
let invoker_indices = stream.read_ptr()?;
let reverse_pinvoke_wrapper_count = stream.read_ptr()?;
let reverse_pinvoke_wrapper_indices = stream.read_ptr()?;
let rgctx_ranges_count = stream.read_ptr_signed()?;
let rgctx_ranges = stream.read_ptr()?;
let rgctxs_count = stream.read_ptr_signed()?;
let rgctxs = stream.read_ptr()?;
let debugger_metadata = stream.read_ptr()?;
let mut custom_attribute_cache_generator = 0u64;
let mut module_initializer = 0u64;
let mut static_constructor_type_indices = 0u64;
let mut metadata_registration = 0u64;
let mut code_registration = 0u64;
if version >= 27.0 {
if version < 29.0 {
custom_attribute_cache_generator = stream.read_ptr()?;
}
module_initializer = stream.read_ptr()?;
static_constructor_type_indices = stream.read_ptr()?;
metadata_registration = stream.read_ptr()?;
code_registration = stream.read_ptr()?;
}
Ok(Self {
module_name,
method_pointer_count,
method_pointers,
adjustor_thunk_count,
adjustor_thunks,
invoker_indices,
reverse_pinvoke_wrapper_count,
reverse_pinvoke_wrapper_indices,
rgctx_ranges_count,
rgctx_ranges,
rgctxs_count,
rgctxs,
debugger_metadata,
custom_attribute_cache_generator,
module_initializer,
static_constructor_type_indices,
metadata_registration,
code_registration,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppRange {
pub start: i32,
pub length: i32,
}
impl Il2CppRange {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
start: stream.read_i32()?,
length: stream.read_i32()?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppTokenRangePair {
pub token: u32,
pub range: Il2CppRange,
}
impl Il2CppTokenRangePair {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
token: stream.read_u32()?,
range: Il2CppRange::read(stream)?,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Il2CppTypeDefinitionSizes {
pub instance_size: u32,
pub native_size: i32,
pub static_fields_size: u32,
pub thread_static_fields_size: u32,
}
impl Il2CppTypeDefinitionSizes {
pub fn read(stream: &mut BinaryStream) -> Result<Self> {
Ok(Self {
instance_size: stream.read_u32()?,
native_size: stream.read_i32()?,
static_fields_size: stream.read_u32()?,
thread_static_fields_size: stream.read_u32()?,
})
}
}