From 14a9c8980488f4c95d883ead1dde0ef737ad7399 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Tue, 5 Nov 2019 20:09:13 +0100 Subject: [PATCH] Model and Output: Implement default method parameter values --- Il2CppInspector/Il2CppInspector.cs | 127 ++++++++++---------- Il2CppInspector/Metadata.cs | 4 +- Il2CppInspector/MetadataClasses.cs | 7 ++ Il2CppInspector/Reflection/MethodBase.cs | 3 +- Il2CppInspector/Reflection/ParameterInfo.cs | 7 +- 5 files changed, 81 insertions(+), 67 deletions(-) diff --git a/Il2CppInspector/Il2CppInspector.cs b/Il2CppInspector/Il2CppInspector.cs index 0ffc457..08c746a 100644 --- a/Il2CppInspector/Il2CppInspector.cs +++ b/Il2CppInspector/Il2CppInspector.cs @@ -37,6 +37,7 @@ namespace Il2CppInspector public int[] NestedTypeIndices => Metadata.NestedTypeIndices; public int[] AttributeTypeIndices => Metadata.AttributeTypeIndices; public Dictionary FieldDefaultValue { get; } = new Dictionary(); + public Dictionary ParameterDefaultValue { get; } = new Dictionary(); public List FieldOffsets { get; } public List TypeUsages => Binary.Types; public Dictionary Modules => Binary.Modules; @@ -45,75 +46,77 @@ namespace Il2CppInspector // TODO: Finish all file access in the constructor and eliminate the need for this public IFileFormatReader BinaryImage => Binary.Image; + private object getDefaultValue(int typeIndex, int dataIndex) { + // No default + if (dataIndex == -1) + return null; + + // Get pointer in binary to default value + var pValue = Metadata.Header.fieldAndParameterDefaultValueDataOffset + dataIndex; + var type = TypeUsages[typeIndex]; + + // Default value is null + if (pValue == 0) + return null; + + object value = null; + Metadata.Position = pValue; + switch (type.type) { + case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: + value = Metadata.ReadBoolean(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_U1: + case Il2CppTypeEnum.IL2CPP_TYPE_I1: + value = Metadata.ReadByte(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: + // UTF-8 character assumed + value = BitConverter.ToChar(Metadata.ReadBytes(2), 0); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_U2: + value = Metadata.ReadUInt16(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_I2: + value = Metadata.ReadInt16(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_U4: + value = Metadata.ReadUInt32(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_I4: + value = Metadata.ReadInt32(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_U8: + value = Metadata.ReadUInt64(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_I8: + value = Metadata.ReadInt64(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_R4: + value = Metadata.ReadSingle(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_R8: + value = Metadata.ReadDouble(); + break; + case Il2CppTypeEnum.IL2CPP_TYPE_STRING: + var uiLen = Metadata.ReadInt32(); + value = Encoding.UTF8.GetString(Metadata.ReadBytes(uiLen)); + break; + } + return value; + } + public Il2CppInspector(Il2CppBinary binary, Metadata metadata) { // Store stream representations Binary = binary; Metadata = metadata; // Get all field default values - foreach (var fdv in Metadata.FieldDefaultValues) { - // No default - if (fdv.dataIndex == -1) { - FieldDefaultValue.Add(fdv.fieldIndex, null); - continue; - } + foreach (var fdv in Metadata.FieldDefaultValues) + FieldDefaultValue.Add(fdv.fieldIndex, getDefaultValue(fdv.typeIndex, fdv.dataIndex)); - // Get pointer in binary to default value - var pValue = Metadata.Header.fieldAndParameterDefaultValueDataOffset + fdv.dataIndex; - var type = TypeUsages[fdv.typeIndex]; - - // Default value is null - if (pValue == 0) { - FieldDefaultValue.Add(fdv.fieldIndex, null); - continue; - } - - object value = null; - Metadata.Position = pValue; - switch (type.type) { - case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: - value = Metadata.ReadBoolean(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U1: - case Il2CppTypeEnum.IL2CPP_TYPE_I1: - value = Metadata.ReadByte(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: - // UTF-8 character assumed - value = BitConverter.ToChar(Metadata.ReadBytes(2), 0); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U2: - value = Metadata.ReadUInt16(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I2: - value = Metadata.ReadInt16(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U4: - value = Metadata.ReadUInt32(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I4: - value = Metadata.ReadInt32(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_U8: - value = Metadata.ReadUInt64(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_I8: - value = Metadata.ReadInt64(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_R4: - value = Metadata.ReadSingle(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_R8: - value = Metadata.ReadDouble(); - break; - case Il2CppTypeEnum.IL2CPP_TYPE_STRING: - var uiLen = Metadata.ReadInt32(); - value = Encoding.UTF8.GetString(Metadata.ReadBytes(uiLen)); - break; - } - - FieldDefaultValue.Add(fdv.fieldIndex, value); - } + // Get all parameter default values + foreach (var pdv in Metadata.ParameterDefaultValues) + ParameterDefaultValue.Add(pdv.parameterIndex, getDefaultValue(pdv.typeIndex, pdv.dataIndex)); // Get all field offsets if (Binary.FieldOffsets != null) { diff --git a/Il2CppInspector/Metadata.cs b/Il2CppInspector/Metadata.cs index 0b43c6a..926a3cf 100644 --- a/Il2CppInspector/Metadata.cs +++ b/Il2CppInspector/Metadata.cs @@ -24,6 +24,7 @@ namespace Il2CppInspector public Il2CppParameterDefinition[] Params { get; } public Il2CppFieldDefinition[] Fields { get; } public Il2CppFieldDefaultValue[] FieldDefaultValues { get; } + public Il2CppParameterDefaultValue[] ParameterDefaultValues { get; } public Il2CppPropertyDefinition[] Properties { get; } public Il2CppEventDefinition[] Events { get; } public Il2CppGenericContainer[] GenericContainers { get; } @@ -98,6 +99,7 @@ namespace Il2CppInspector Params = ReadArray(Header.parametersOffset, Header.parametersCount / Sizeof(typeof(Il2CppParameterDefinition))); Fields = ReadArray(Header.fieldsOffset, Header.fieldsCount / Sizeof(typeof(Il2CppFieldDefinition))); FieldDefaultValues = ReadArray(Header.fieldDefaultValuesOffset, Header.fieldDefaultValuesCount / Sizeof(typeof(Il2CppFieldDefaultValue))); + ParameterDefaultValues = ReadArray(Header.parameterDefaultValuesOffset, Header.parameterDefaultValuesCount / Sizeof(typeof(Il2CppParameterDefaultValue))); Properties = ReadArray(Header.propertiesOffset, Header.propertiesCount / Sizeof(typeof(Il2CppPropertyDefinition))); Events = ReadArray(Header.eventsOffset, Header.eventsCount / Sizeof(typeof(Il2CppEventDefinition))); InterfaceUsageIndices = ReadArray(Header.interfacesOffset, Header.interfacesCount / sizeof(int)); @@ -109,7 +111,7 @@ namespace Il2CppInspector AttributeTypeIndices = ReadArray(Header.attributeTypesOffset, Header.attributeTypesCount / sizeof(int)); AttributeTypeRanges = ReadArray(Header.attributesInfoOffset, Header.attributesInfoCount / Sizeof(typeof(Il2CppCustomAttributeTypeRange))); } - // TODO: ParameterDefaultValue, ParameterConstraints, MetadataUsage + // TODO: ParameterConstraints, MetadataUsage // Get all string literals Position = Header.stringOffset; diff --git a/Il2CppInspector/MetadataClasses.cs b/Il2CppInspector/MetadataClasses.cs index 08482fd..9abf734 100644 --- a/Il2CppInspector/MetadataClasses.cs +++ b/Il2CppInspector/MetadataClasses.cs @@ -254,6 +254,13 @@ namespace Il2CppInspector public int typeIndex; } + public class Il2CppParameterDefaultValue + { + public int parameterIndex; + public int typeIndex; + public int dataIndex; + } + public class Il2CppFieldDefinition { public int nameIndex; diff --git a/Il2CppInspector/Reflection/MethodBase.cs b/Il2CppInspector/Reflection/MethodBase.cs index 4a00a3a..13ab9d7 100644 --- a/Il2CppInspector/Reflection/MethodBase.cs +++ b/Il2CppInspector/Reflection/MethodBase.cs @@ -160,7 +160,8 @@ namespace Il2CppInspector.Reflection // Get C# syntax-friendly list of parameters public string GetParametersString() => string.Join(", ", DeclaredParameters.Select(p => $"{p.CustomAttributes.ToString(inline: true).Replace("[ParamArray]", "params")}" - + $"{p.GetModifierString()}{p.ParameterType.CSharpName} {p.Name}")); + + $"{p.GetModifierString()}{p.ParameterType.CSharpName} {p.Name}" + + (p.HasDefaultValue? " = " + p.DefaultValue.ToCSharpValue() : ""))); public string GetTypeParametersString() => GenericTypeParameters == null? "" : "<" + string.Join(", ", GenericTypeParameters.Select(p => p.CSharpName)) + ">"; diff --git a/Il2CppInspector/Reflection/ParameterInfo.cs b/Il2CppInspector/Reflection/ParameterInfo.cs index 58f07e8..14cbf06 100644 --- a/Il2CppInspector/Reflection/ParameterInfo.cs +++ b/Il2CppInspector/Reflection/ParameterInfo.cs @@ -26,7 +26,7 @@ namespace Il2CppInspector.Reflection public bool HasDefaultValue => (Attributes & ParameterAttributes.HasDefault) != 0; // Default value for the parameter - public object DefaultValue => throw new NotImplementedException(); + public object DefaultValue { get; } public bool IsIn => (Attributes & ParameterAttributes.In) != 0; public bool IsOptional => (Attributes & ParameterAttributes.Optional) != 0; @@ -80,11 +80,12 @@ namespace Il2CppInspector.Reflection if (Position == -1) Attributes |= ParameterAttributes.Retval; - // TODO: DefaultValue/HasDefaultValue + // Default initialization value if present + if (pkg.ParameterDefaultValue.TryGetValue(paramIndex, out object variant)) + DefaultValue = variant; } public string GetModifierString() => - (IsOptional? "optional " : "") + (IsOut? "out " : ""); } }