Model: Handle nested types
This commit is contained in:
@@ -31,6 +31,7 @@ namespace Il2CppInspector
|
||||
public Il2CppPropertyDefinition[] Properties => Metadata.Properties;
|
||||
public Il2CppEventDefinition[] Events => Metadata.Events;
|
||||
public int[] InterfaceUsageIndices => Metadata.InterfaceUsageIndices;
|
||||
public int[] NestedTypeIndices => Metadata.NestedTypeIndices;
|
||||
public Dictionary<int, object> FieldDefaultValue { get; } = new Dictionary<int, object>();
|
||||
public List<long> FieldOffsets { get; }
|
||||
public List<Il2CppType> TypeUsages => Binary.Types;
|
||||
|
||||
@@ -15,20 +15,18 @@ namespace Il2CppInspector.Reflection
|
||||
public Il2CppInspector Package { get; }
|
||||
public List<Assembly> Assemblies { get; } = new List<Assembly>();
|
||||
|
||||
// List of all types ordered by their TypeDefinitionIndex
|
||||
public TypeInfo[] TypesByIndex { get; }
|
||||
|
||||
public Il2CppModel(Il2CppInspector package) {
|
||||
Package = package;
|
||||
TypesByIndex = new TypeInfo[package.TypeDefinitions.Length];
|
||||
|
||||
// Create Assembly objects from Il2Cpp package
|
||||
for (var image = 0; image < package.Images.Length; image++)
|
||||
Assemblies.Add(new Assembly(this, image));
|
||||
}
|
||||
|
||||
// Get the assembly in which a type is defined
|
||||
public Assembly GetAssembly(TypeInfo type) => Assemblies.FirstOrDefault(x => x.DefinedTypes.Contains(type));
|
||||
|
||||
// Get a type from its IL2CPP type index
|
||||
public TypeInfo GetTypeFromIndex(long typeIndex) => Assemblies.SelectMany(x => x.DefinedTypes).FirstOrDefault(x => x.Index == typeIndex);
|
||||
|
||||
// Get or generate a type from its IL2CPP binary type usage reference
|
||||
// (field, return type, generic type parameter etc.)
|
||||
public TypeInfo GetType(Il2CppType pType, MemberTypes memberType = MemberTypes.All) {
|
||||
@@ -36,7 +34,7 @@ namespace Il2CppInspector.Reflection
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
|
||||
// Classes defined in the metadata
|
||||
return GetTypeFromIndex((int) pType.datapoint);
|
||||
return TypesByIndex[(int) pType.datapoint];
|
||||
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
||||
@@ -57,7 +55,8 @@ namespace Il2CppInspector.Reflection
|
||||
if ((int)t >= Il2CppConstants.FullNameTypeString.Count)
|
||||
return null;
|
||||
|
||||
return Assemblies.SelectMany(x => x.DefinedTypes).First(x => x.FullName == Il2CppConstants.FullNameTypeString[(int)t]);
|
||||
var fqn = Il2CppConstants.FullNameTypeString[(int) t];
|
||||
return TypesByIndex.First(x => x.FullName == fqn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace Il2CppInspector
|
||||
public Il2CppEventDefinition[] Events { get; }
|
||||
|
||||
public int[] InterfaceUsageIndices { get; }
|
||||
public int[] NestedTypeIndices { get; }
|
||||
|
||||
public Dictionary<int, string> Strings { get; } = new Dictionary<int, string>();
|
||||
|
||||
@@ -96,6 +97,7 @@ namespace Il2CppInspector
|
||||
Properties = ReadArray<Il2CppPropertyDefinition>(Header.propertiesOffset, Header.propertiesCount / Sizeof(typeof(Il2CppPropertyDefinition)));
|
||||
Events = ReadArray<Il2CppEventDefinition>(Header.eventsOffset, Header.eventsCount / Sizeof(typeof(Il2CppEventDefinition)));
|
||||
InterfaceUsageIndices = ReadArray<int>(Header.interfacesOffset, Header.interfacesCount / sizeof(int));
|
||||
NestedTypeIndices = ReadArray<int>(Header.nestedTypesOffset, Header.nestedTypesCount / sizeof(int));
|
||||
// TODO: ParameterDefaultValue, GenericParameters, ParameterConstraints, GenericContainers, MetadataUsage, CustomAttributes
|
||||
|
||||
// Get all string literals
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Il2CppInspector.Reflection {
|
||||
|
||||
// Generate types in DefinedTypes from typeStart to typeStart+typeCount-1
|
||||
for (var t = Definition.typeStart; t < Definition.typeStart + Definition.typeCount; t++) {
|
||||
var type = new TypeInfo(Model.Package, t, this);
|
||||
var type = new TypeInfo(t, this);
|
||||
|
||||
// Don't add empty module definitions
|
||||
if (type.Name != "<Module>")
|
||||
|
||||
@@ -18,7 +18,8 @@ namespace Il2CppInspector.Reflection {
|
||||
public IEnumerable<CustomAttributeData> CustomAttributes => throw new NotImplementedException();
|
||||
|
||||
// Type that this type is declared in for nested types
|
||||
public TypeInfo DeclaringType { get; }
|
||||
protected int declaringTypeDefinitionIndex { private get; set; } = -1;
|
||||
public TypeInfo DeclaringType => declaringTypeDefinitionIndex != -1? Assembly.Model.TypesByIndex[declaringTypeDefinitionIndex] : null;
|
||||
|
||||
// What sort of member this is, eg. method, field etc.
|
||||
public abstract MemberTypes MemberType { get; }
|
||||
@@ -29,16 +30,13 @@ namespace Il2CppInspector.Reflection {
|
||||
// TODO: GetCustomAttributes etc.
|
||||
|
||||
// For top-level members in an assembly (ie. non-nested types)
|
||||
protected MemberInfo(Assembly asm, TypeInfo declaringType = null) {
|
||||
Assembly = asm;
|
||||
DeclaringType = declaringType;
|
||||
}
|
||||
protected MemberInfo(Assembly asm) => Assembly = asm;
|
||||
|
||||
// For lower level members, eg. fields, properties etc. and nested types
|
||||
protected MemberInfo(TypeInfo declaringType) {
|
||||
protected MemberInfo(TypeInfo declaringType = null) {
|
||||
if (declaringType != null) {
|
||||
Assembly = declaringType.Assembly;
|
||||
DeclaringType = declaringType;
|
||||
declaringTypeDefinitionIndex = declaringType.Index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Il2CppInspector.Reflection
|
||||
public TypeInfo ParameterType => Member.Assembly.Model.GetType(paramType, MemberTypes.TypeInfo);
|
||||
|
||||
// Zero-indexed position of the parameter in parameter list
|
||||
public int Position { get; private set; }
|
||||
public int Position { get; }
|
||||
|
||||
// Create a parameter. Specify paramIndex == -1 for a return type parameter
|
||||
public ParameterInfo(Il2CppInspector pkg, int paramIndex, MethodBase declaringMethod) {
|
||||
|
||||
@@ -47,7 +47,10 @@ namespace Il2CppInspector.Reflection {
|
||||
public List<FieldInfo> DeclaredFields { get; } = new List<FieldInfo>();
|
||||
public List<MemberInfo> DeclaredMembers => throw new NotImplementedException();
|
||||
public List<MethodInfo> DeclaredMethods { get; } = new List<MethodInfo>();
|
||||
public List<TypeInfo> DeclaredNestedTypes => throw new NotImplementedException();
|
||||
|
||||
private int[] declaredNestedTypes;
|
||||
public IEnumerable<TypeInfo> DeclaredNestedTypes => declaredNestedTypes.Select(x => Assembly.Model.TypesByIndex[x]);
|
||||
|
||||
public List<PropertyInfo> DeclaredProperties { get; } = new List<PropertyInfo>();
|
||||
|
||||
// Method that the type is declared in if this is a type parameter of a generic method
|
||||
@@ -68,6 +71,7 @@ namespace Il2CppInspector.Reflection {
|
||||
public string FullName => (IsPointer? "void *" : "")
|
||||
+ Namespace
|
||||
+ (Namespace.Length > 0? "." : "")
|
||||
+ (DeclaringType != null? DeclaringType.Name + "." : "")
|
||||
+ base.Name
|
||||
+ (GenericTypeParameters != null ? "<" + string.Join(", ", GenericTypeParameters.Select(x => x.Name)) + ">" : "")
|
||||
+ (IsArray? "[]" : "");
|
||||
@@ -91,7 +95,7 @@ namespace Il2CppInspector.Reflection {
|
||||
public bool IsGenericTypeDefinition => throw new NotImplementedException();
|
||||
public bool IsImport => (Attributes & TypeAttributes.Import) == TypeAttributes.Import;
|
||||
public bool IsInterface => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
|
||||
public bool IsNested { get; } // TODO: Partially implemented
|
||||
public bool IsNested => DeclaringType != null;
|
||||
public bool IsNestedAssembly => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
|
||||
public bool IsNestedFamANDAssem => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
|
||||
public bool IsNestedFamily => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
|
||||
@@ -108,7 +112,8 @@ namespace Il2CppInspector.Reflection {
|
||||
public bool IsSpecialName => (Attributes & TypeAttributes.SpecialName) == TypeAttributes.SpecialName;
|
||||
public bool IsValueType => BaseType?.FullName == "System.ValueType";
|
||||
|
||||
public override MemberTypes MemberType { get; }
|
||||
// May get overridden by Il2CppType-based constructor below
|
||||
public override MemberTypes MemberType { get; } = MemberTypes.TypeInfo;
|
||||
|
||||
public override string Name {
|
||||
get => (IsPointer ? "void *" : "")
|
||||
@@ -118,7 +123,11 @@ namespace Il2CppInspector.Reflection {
|
||||
protected set => base.Name = value;
|
||||
}
|
||||
|
||||
public string Namespace { get; }
|
||||
private string @namespace;
|
||||
public string Namespace {
|
||||
get => !string.IsNullOrEmpty(@namespace) ? @namespace : DeclaringType?.Namespace ?? "<default namespace>";
|
||||
set => @namespace = value;
|
||||
}
|
||||
|
||||
// Number of dimensions of an array
|
||||
private readonly int arrayRank;
|
||||
@@ -135,8 +144,11 @@ namespace Il2CppInspector.Reflection {
|
||||
// TODO: Generic stuff
|
||||
|
||||
// Initialize from specified type index in metadata
|
||||
public TypeInfo(Il2CppInspector pkg, int typeIndex, Assembly owner) :
|
||||
base(owner) {
|
||||
|
||||
// Top-level types
|
||||
public TypeInfo(int typeIndex, Assembly owner) : base(owner) {
|
||||
var pkg = Assembly.Model.Package;
|
||||
|
||||
Definition = pkg.TypeDefinitions[typeIndex];
|
||||
Index = typeIndex;
|
||||
Namespace = pkg.Strings[Definition.namespaceIndex];
|
||||
@@ -145,6 +157,14 @@ namespace Il2CppInspector.Reflection {
|
||||
if (Definition.parentIndex >= 0)
|
||||
baseType = pkg.TypeUsages[Definition.parentIndex];
|
||||
|
||||
// Nested type?
|
||||
if (Definition.declaringTypeIndex >= 0) {
|
||||
declaringTypeDefinitionIndex = (int) pkg.TypeUsages[Definition.declaringTypeIndex].datapoint;
|
||||
}
|
||||
|
||||
// Add to global type definition list
|
||||
Assembly.Model.TypesByIndex[Index] = this;
|
||||
|
||||
if ((Definition.flags & Il2CppConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0)
|
||||
Attributes |= TypeAttributes.Serializable;
|
||||
if ((Definition.flags & Il2CppConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == Il2CppConstants.TYPE_ATTRIBUTE_PUBLIC)
|
||||
@@ -187,6 +207,11 @@ namespace Il2CppInspector.Reflection {
|
||||
for (var i = 0; i < Definition.interfaces_count; i++)
|
||||
implementedInterfaces[i] = pkg.TypeUsages[pkg.InterfaceUsageIndices[Definition.interfacesStart + i]];
|
||||
|
||||
// Add all nested types
|
||||
declaredNestedTypes = new int[Definition.nested_type_count];
|
||||
for (var n = 0; n < Definition.nested_type_count; n++)
|
||||
declaredNestedTypes[n] = pkg.NestedTypeIndices[Definition.nestedTypesStart + n];
|
||||
|
||||
// Add all fields
|
||||
for (var f = Definition.fieldStart; f < Definition.fieldStart + Definition.field_count; f++)
|
||||
DeclaredFields.Add(new FieldInfo(pkg, f, this));
|
||||
@@ -207,20 +232,21 @@ namespace Il2CppInspector.Reflection {
|
||||
// Add all events
|
||||
for (var e = Definition.eventStart; e < Definition.eventStart + Definition.event_count; e++)
|
||||
DeclaredEvents.Add(new EventInfo(pkg, e, this));
|
||||
MemberType = MemberTypes.TypeInfo;
|
||||
}
|
||||
|
||||
// Initialize type from binary usage
|
||||
public TypeInfo(Il2CppModel model, Il2CppType pType, MemberTypes memberType) : base(null) {
|
||||
public TypeInfo(Il2CppModel model, Il2CppType pType, MemberTypes memberType) {
|
||||
var image = model.Package.BinaryImage;
|
||||
|
||||
IsNested = true;
|
||||
// TODO: IsNested = true;
|
||||
MemberType = memberType;
|
||||
|
||||
// TODO: Set Assembly and DeclaringType
|
||||
|
||||
// Generic type unresolved and concrete instance types
|
||||
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) {
|
||||
var generic = image.ReadMappedObject<Il2CppGenericClass>(pType.datapoint);
|
||||
var genericTypeDef = model.GetTypeFromIndex(generic.typeDefinitionIndex);
|
||||
var genericTypeDef = model.TypesByIndex[generic.typeDefinitionIndex];
|
||||
|
||||
Namespace = genericTypeDef.Namespace;
|
||||
Name = genericTypeDef.Name;
|
||||
|
||||
Reference in New Issue
Block a user