diff --git a/Il2CppDumper/Il2CppCSharpDumper.cs b/Il2CppDumper/Il2CppCSharpDumper.cs index e64c54a..c913489 100644 --- a/Il2CppDumper/Il2CppCSharpDumper.cs +++ b/Il2CppDumper/Il2CppCSharpDumper.cs @@ -77,22 +77,10 @@ namespace Il2CppInspector // See https://docs.microsoft.com/en-us/dotnet/api/system.reflection.defaultmemberattribute?view=netframework-4.8 writer.Write(type.CustomAttributes.Where(a => a.AttributeType.Name != "DefaultMemberAttribute").ToString(prefix)); - writer.Write(prefix); - if (type.IsPublic || type.IsNestedPublic) - writer.Write("public "); - if (type.IsNestedPrivate) - writer.Write("private "); - if (type.IsNestedFamily) - writer.Write("protected "); - if (type.IsNestedAssembly || type.IsNotPublic) - writer.Write("internal "); - if (type.IsNestedFamORAssem) - writer.Write("protected internal "); - if (type.IsNestedFamANDAssem) - writer.Write("private protected "); - // Roll-up multicast delegates to use the 'delegate' syntactic sugar if (type.IsClass && type.IsSealed && type.BaseType?.FullName == "System.MulticastDelegate") { + writer.Write(prefix + type.GetAccessModifierString()); + var del = type.GetMethod("Invoke"); // IL2CPP doesn't seem to retain return type attributes //writer.Write(del.ReturnType.CustomAttributes.ToString(prefix, "return: ")); @@ -102,23 +90,7 @@ namespace Il2CppInspector return; } - // An abstract sealed class is a static class - if (type.IsAbstract && type.IsSealed) - writer.Write("static "); - else { - if (type.IsAbstract && !type.IsInterface) - writer.Write("abstract "); - if (type.IsSealed && !type.IsValueType && !type.IsEnum) - writer.Write("sealed "); - } - if (type.IsInterface) - writer.Write("interface "); - else if (type.IsValueType) - writer.Write("struct "); - else if (type.IsEnum) - writer.Write("enum "); - else - writer.Write("class "); + writer.Write(prefix + type.GetModifierString()); var @base = type.ImplementedInterfaces.Select(x => x.CSharpName).ToList(); if (type.BaseType != null && type.BaseType.FullName != "System.Object" && type.BaseType.FullName != "System.ValueType" && !type.IsEnum) @@ -143,32 +115,14 @@ namespace Il2CppInspector // Attributes writer.Write(field.CustomAttributes.Where(a => a.AttributeType.FullName != FBAttribute).ToString(prefix + "\t")); - writer.Write(prefix + "\t"); - if (field.IsPrivate) - writer.Write("private "); - if (field.IsPublic) - writer.Write("public "); - if (field.IsFamily) - writer.Write("protected "); - if (field.IsAssembly) - writer.Write("internal "); - if (field.IsFamilyOrAssembly) - writer.Write("protected internal "); - if (field.IsFamilyAndAssembly) - writer.Write("private protected "); - if (field.IsLiteral) - writer.Write("const "); - // All const fields are also static by implication - else if (field.IsStatic) - writer.Write("static "); - if (field.IsInitOnly) - writer.Write("readonly "); - if (field.IsPinvokeImpl) - writer.Write("extern "); + writer.Write(field.GetModifierString()); + + // Fixed buffers if (field.GetCustomAttributes(FBAttribute).Any()) - writer.Write($"fixed /* {((ulong) field.GetCustomAttributes(FBAttribute)[0].VirtualAddress).ToAddressString()} */" + + writer.Write($"/* {((ulong) field.GetCustomAttributes(FBAttribute)[0].VirtualAddress).ToAddressString()} */" + $" {field.FieldType.GetField("FixedElementField").FieldType.CSharpName} {field.Name}[0]"); + // Regular fields else writer.Write($"{field.FieldType.CSharpName} {field.Name}"); if (field.HasDefaultValue) diff --git a/Il2CppInspector/Reflection/FieldInfo.cs b/Il2CppInspector/Reflection/FieldInfo.cs index 81a7442..a802a09 100644 --- a/Il2CppInspector/Reflection/FieldInfo.cs +++ b/Il2CppInspector/Reflection/FieldInfo.cs @@ -5,7 +5,9 @@ */ using System.Collections.Generic; +using System.Linq; using System.Reflection; +using System.Text; namespace Il2CppInspector.Reflection { public class FieldInfo : MemberInfo @@ -112,5 +114,32 @@ namespace Il2CppInspector.Reflection { if (pkg.FieldDefaultValue.TryGetValue(fieldIndex, out object variant)) DefaultValue = variant; } + + public string GetAccessModifierString() => this switch { + { IsPrivate: true } => "private ", + { IsPublic: true } => "public ", + { IsFamily: true } => "protected ", + { IsAssembly: true } => "internal ", + { IsFamilyOrAssembly: true } => "protected internal ", + { IsFamilyAndAssembly: true } => "private protected ", + _ => "" + }; + + public string GetModifierString() { + var modifiers = new StringBuilder(GetAccessModifierString()); + + if (IsLiteral) + modifiers.Append("const "); + // All const fields are also static by implication + else if (IsStatic) + modifiers.Append("static "); + if (IsInitOnly) + modifiers.Append("readonly "); + if (IsPinvokeImpl) + modifiers.Append("extern "); + if (GetCustomAttributes("System.Runtime.CompilerServices.FixedBufferAttribute").Any()) + modifiers.Append("fixed "); + return modifiers.ToString(); + } } } \ No newline at end of file diff --git a/Il2CppInspector/Reflection/MethodBase.cs b/Il2CppInspector/Reflection/MethodBase.cs index 219c54c..026eff8 100644 --- a/Il2CppInspector/Reflection/MethodBase.cs +++ b/Il2CppInspector/Reflection/MethodBase.cs @@ -115,26 +115,22 @@ namespace Il2CppInspector.Reflection DeclaredParameters.Add(new ParameterInfo(pkg, p, this)); } - public string GetAccessModifierString() { - return this switch { - { IsPrivate: true } => "private ", - { IsPublic: true } => "public ", - { IsFamily: true } => "protected ", - { IsAssembly: true } => "internal ", - { IsFamilyOrAssembly: true } => "protected internal ", - { IsFamilyAndAssembly: true } => "private protected ", - _ => "" - }; - } + public string GetAccessModifierString() => this switch { + { IsPrivate: true } => "private ", + { IsPublic: true } => "public ", + { IsFamily: true } => "protected ", + { IsAssembly: true } => "internal ", + { IsFamilyOrAssembly: true } => "protected internal ", + { IsFamilyAndAssembly: true } => "private protected ", + _ => "" + }; public string GetModifierString() { // Interface methods and properties have no visible modifiers (they are always declared 'public abstract') if (DeclaringType.IsInterface) return string.Empty; - StringBuilder modifiers = new StringBuilder(); - - modifiers.Append(GetAccessModifierString()); + var modifiers = new StringBuilder(GetAccessModifierString()); if (IsAbstract) modifiers.Append("abstract "); diff --git a/Il2CppInspector/Reflection/TypeInfo.cs b/Il2CppInspector/Reflection/TypeInfo.cs index b0ce9ac..da5be57 100644 --- a/Il2CppInspector/Reflection/TypeInfo.cs +++ b/Il2CppInspector/Reflection/TypeInfo.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Text; namespace Il2CppInspector.Reflection { public class TypeInfo : MemberInfo @@ -453,6 +454,43 @@ namespace Il2CppInspector.Reflection { + (IsArray ? "[" + new string(',', GetArrayRank() - 1) + "]" : "") + (IsPointer ? "*" : ""); + public string GetAccessModifierString() => this switch { + { IsPublic: true } => "public ", + { IsNotPublic: true } => "internal ", + + { IsNestedPublic: true } => "public ", + { IsNestedPrivate: true } => "private ", + { IsNestedFamily: true } => "protected ", + { IsNestedAssembly: true } => "internal ", + { IsNestedFamORAssem: true } => "protected internal ", + { IsNestedFamANDAssem: true } => "private protected ", + _ => throw new InvalidOperationException("Unknown type access modifier") + }; + + public string GetModifierString() { + var modifiers = new StringBuilder(GetAccessModifierString()); + + // An abstract sealed class is a static class + if (IsAbstract && IsSealed) + modifiers.Append("static "); + else { + if (IsAbstract && !IsInterface) + modifiers.Append("abstract "); + if (IsSealed && !IsValueType && !IsEnum) + modifiers.Append("sealed "); + } + if (IsInterface) + modifiers.Append("interface "); + else if (IsValueType) + modifiers.Append("struct "); + else if (IsEnum) + modifiers.Append("enum "); + else + modifiers.Append("class "); + + return modifiers.ToString(); + } + public override string ToString() => Name; } } \ No newline at end of file