diff --git a/Il2CppInspector.Common/Reflection/EventInfo.cs b/Il2CppInspector.Common/Reflection/EventInfo.cs index ff90d22..0adb09e 100644 --- a/Il2CppInspector.Common/Reflection/EventInfo.cs +++ b/Il2CppInspector.Common/Reflection/EventInfo.cs @@ -28,8 +28,8 @@ namespace Il2CppInspector.Reflection public MethodInfo RaiseMethod { get; } // Event handler delegate type - private int eventTypeReference; - public TypeInfo EventHandlerType => Assembly.Model.TypesByReferenceIndex[eventTypeReference]; + private readonly TypeRef eventTypeReference; + public TypeInfo EventHandlerType => eventTypeReference.Value; // True if the event has a special name public bool IsSpecialName => (Attributes & EventAttributes.SpecialName) == EventAttributes.SpecialName; @@ -42,8 +42,8 @@ namespace Il2CppInspector.Reflection Index = eventIndex; Name = pkg.Strings[Definition.nameIndex]; - eventTypeReference = Definition.typeIndex; - var eventType = pkg.TypeReferences[eventTypeReference]; + eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex); + var eventType = pkg.TypeReferences[Definition.typeIndex]; if ((eventType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) == Il2CppConstants.FIELD_ATTRIBUTE_SPECIAL_NAME) Attributes |= EventAttributes.SpecialName; diff --git a/Il2CppInspector.Common/Reflection/FieldInfo.cs b/Il2CppInspector.Common/Reflection/FieldInfo.cs index 98ba195..4560704 100644 --- a/Il2CppInspector.Common/Reflection/FieldInfo.cs +++ b/Il2CppInspector.Common/Reflection/FieldInfo.cs @@ -37,8 +37,8 @@ namespace Il2CppInspector.Reflection { public FieldAttributes Attributes { get; } // Type of field - private readonly int fieldTypeReference; - public TypeInfo FieldType => Assembly.Model.TypesByReferenceIndex[fieldTypeReference]; + private readonly TypeRef fieldTypeReference; + public TypeInfo FieldType => fieldTypeReference.Value; // For the Is* definitions below, see: // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.fieldinfo.isfamilyandassembly?view=netframework-4.7.1#System_Reflection_FieldInfo_IsFamilyAndAssembly @@ -89,8 +89,8 @@ namespace Il2CppInspector.Reflection { rawOffset = pkg.FieldOffsets[fieldIndex]; - fieldTypeReference = Definition.typeIndex; - var fieldType = pkg.TypeReferences[fieldTypeReference]; + fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex); + var fieldType = pkg.TypeReferences[Definition.typeIndex]; if ((fieldType.attrs & Il2CppConstants.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == Il2CppConstants.FIELD_ATTRIBUTE_PRIVATE) Attributes |= FieldAttributes.Private; diff --git a/Il2CppInspector.Common/Reflection/MethodInfo.cs b/Il2CppInspector.Common/Reflection/MethodInfo.cs index e3ed429..3864a1d 100644 --- a/Il2CppInspector.Common/Reflection/MethodInfo.cs +++ b/Il2CppInspector.Common/Reflection/MethodInfo.cs @@ -17,8 +17,8 @@ namespace Il2CppInspector.Reflection public ParameterInfo ReturnParameter { get; } // Return type of the method - private readonly int returnTypeReference; - public TypeInfo ReturnType => Assembly.Model.TypesByReferenceIndex[returnTypeReference]; + private readonly TypeRef returnTypeReference; + public TypeInfo ReturnType => returnTypeReference.Value; public override bool RequiresUnsafeContext => base.RequiresUnsafeContext || ReturnType.RequiresUnsafeContext; @@ -26,15 +26,14 @@ namespace Il2CppInspector.Reflection public MethodInfo(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(pkg, methodIndex, declaringType) { // Add return parameter - returnTypeReference = Definition.returnType; + returnTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.returnType); ReturnParameter = new ParameterInfo(pkg, -1, this); } public MethodInfo(Il2CppModel model, Il2CppMethodSpec spec, TypeInfo declaringType) : base(model, spec, declaringType) { var methodDef = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex]; - - // Add return parameter - returnTypeReference = methodDef.Definition.returnType; + // Add return parameter (TODO substitute type) + returnTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, methodDef.Definition.returnType); ReturnParameter = ((MethodInfo) methodDef).ReturnParameter; } diff --git a/Il2CppInspector.Common/Reflection/ParameterInfo.cs b/Il2CppInspector.Common/Reflection/ParameterInfo.cs index 8fcde75..6261ec5 100644 --- a/Il2CppInspector.Common/Reflection/ParameterInfo.cs +++ b/Il2CppInspector.Common/Reflection/ParameterInfo.cs @@ -43,8 +43,8 @@ namespace Il2CppInspector.Reflection public string CSharpSafeName => Constants.Keywords.Contains(Name) ? "@" + Name : Name; // Type of this parameter - private readonly int paramTypeReference; - public TypeInfo ParameterType => DeclaringMethod.Assembly.Model.TypesByReferenceIndex[paramTypeReference]; + private readonly TypeRef paramTypeReference; + public TypeInfo ParameterType => paramTypeReference.Value; // Zero-indexed position of the parameter in parameter list public int Position { get; } @@ -56,7 +56,7 @@ namespace Il2CppInspector.Reflection if (paramIndex == -1) { Position = -1; - paramTypeReference = declaringMethod.Definition.returnType; + paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, declaringMethod.Definition.returnType); Attributes |= ParameterAttributes.Retval; return; } @@ -69,8 +69,9 @@ namespace Il2CppInspector.Reflection Name = string.Format($"param_{Index:x8}"); Position = paramIndex - declaringMethod.Definition.parameterStart; - paramTypeReference = Definition.typeIndex; - var paramType = pkg.TypeReferences[paramTypeReference]; + paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, Definition.typeIndex); + + var paramType = pkg.TypeReferences[Definition.typeIndex]; if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_HAS_DEFAULT) != 0) Attributes |= ParameterAttributes.HasDefault; @@ -103,8 +104,8 @@ namespace Il2CppInspector.Reflection Position = generic.Position; Attributes = generic.Attributes; - // Search for the concrete type's TypeRef index to store as the parameter type reference index - paramTypeReference = Array.IndexOf(model.TypesByReferenceIndex, concrete); + // TODO substitute concrete params? + paramTypeReference = TypeRef.FromTypeInfo(concrete); DefaultValue = generic.DefaultValue; DefaultValueMetadataAddress = generic.DefaultValueMetadataAddress; diff --git a/Il2CppInspector.Common/Reflection/TypeInfo.cs b/Il2CppInspector.Common/Reflection/TypeInfo.cs index 6068af7..79c67e0 100644 --- a/Il2CppInspector.Common/Reflection/TypeInfo.cs +++ b/Il2CppInspector.Common/Reflection/TypeInfo.cs @@ -510,14 +510,14 @@ namespace Il2CppInspector.Reflection { // See: https://docs.microsoft.com/en-us/dotnet/api/system.type.haselementtype?view=netframework-4.8 public bool HasElementType => ElementType != null; - private readonly int[] implementedInterfaceReferences; - public IEnumerable ImplementedInterfaces => implementedInterfaceReferences.Select(x => Assembly.Model.TypesByReferenceIndex[x]); + private readonly TypeRef[] implementedInterfaceReferences; + public IEnumerable ImplementedInterfaces => implementedInterfaceReferences.Select(x => x.Value); public bool IsAbstract => (Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract; public bool IsArray { get; } public bool IsByRef { get; } public bool IsClass => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class; - public bool IsEnum => enumUnderlyingTypeReference != -1; + public bool IsEnum { get; } public bool IsGenericParameter { get; } public bool IsGenericType { get; } public bool IsGenericTypeDefinition => (Definition != null) && genericArguments.Any(); @@ -559,14 +559,12 @@ namespace Il2CppInspector.Reflection { public string[] GetEnumNames() => IsEnum? DeclaredFields.Where(x => x.Name != "value__").Select(x => x.Name).ToArray() : throw new InvalidOperationException("Type is not an enumeration"); // The underlying type of an enumeration (int by default) - private readonly int enumUnderlyingTypeReference = -1; - private TypeInfo enumUnderlyingType; + private readonly TypeRef enumUnderlyingTypeReference = null; public TypeInfo GetEnumUnderlyingType() { if (!IsEnum) return null; - enumUnderlyingType ??= Assembly.Model.TypesByReferenceIndex[enumUnderlyingTypeReference]; - return enumUnderlyingType; + return enumUnderlyingTypeReference.Value; } public Array GetEnumValues() => IsEnum? DeclaredFields.Where(x => x.Name != "value__").Select(x => x.DefaultValue).ToArray() : throw new InvalidOperationException("Type is not an enumeration"); @@ -634,17 +632,19 @@ namespace Il2CppInspector.Reflection { Attributes |= TypeAttributes.Interface; // Enumerations - bit 1 of bitfield indicates this (also the baseTypeReference will be System.Enum) - if (((Definition.bitfield >> 1) & 1) == 1) - enumUnderlyingTypeReference = Definition.elementTypeIndex; + if (((Definition.bitfield >> 1) & 1) == 1) { + IsEnum = true; + enumUnderlyingTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.elementTypeIndex); + } // Pass-by-reference type // NOTE: This should actually always evaluate to false in the current implementation IsByRef = Index == Definition.byrefTypeIndex; // Add all implemented interfaces - implementedInterfaceReferences = new int[Definition.interfaces_count]; + implementedInterfaceReferences = new TypeRef[Definition.interfaces_count]; for (var i = 0; i < Definition.interfaces_count; i++) - implementedInterfaceReferences[i] = pkg.InterfaceUsageIndices[Definition.interfacesStart + i]; + implementedInterfaceReferences[i] = TypeRef.FromReferenceIndex(Assembly.Model, pkg.InterfaceUsageIndices[Definition.interfacesStart + i]); // Add all nested types declaredNestedTypes = new int[Definition.nested_type_count]; diff --git a/Il2CppInspector.Common/Reflection/TypeRef.cs b/Il2CppInspector.Common/Reflection/TypeRef.cs new file mode 100644 index 0000000..ab1b40c --- /dev/null +++ b/Il2CppInspector.Common/Reflection/TypeRef.cs @@ -0,0 +1,33 @@ +namespace Il2CppInspector.Reflection +{ + /// + /// A class which lazily refers to a TypeInfo instance + /// + internal class TypeRef { + private Il2CppModel model; + private int referenceIndex = -1; + private int definitionIndex = -1; + private TypeInfo typeInfo = null; + + private TypeRef() { } + + public TypeInfo Value { + get { + if (referenceIndex != -1) + return model.TypesByReferenceIndex[referenceIndex]; + if (definitionIndex != -1) + return model.TypesByDefinitionIndex[definitionIndex]; + return typeInfo; + } + } + + public static TypeRef FromReferenceIndex(Il2CppModel model, int index) + => new TypeRef { model = model, referenceIndex = index }; + + public static TypeRef FromDefinitionIndex(Il2CppModel model, int index) + => new TypeRef { model = model, definitionIndex = index }; + + public static TypeRef FromTypeInfo(TypeInfo type) + => new TypeRef { typeInfo = type }; + } +}