diff --git a/Il2CppInspector.Common/Cpp/CppType.cs b/Il2CppInspector.Common/Cpp/CppType.cs index edd682d..a69c2ab 100644 --- a/Il2CppInspector.Common/Cpp/CppType.cs +++ b/Il2CppInspector.Common/Cpp/CppType.cs @@ -6,16 +6,27 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; +using System.Text.RegularExpressions; +using Il2CppInspector.Outputs; +using Il2CppInspector.Outputs.UnityHeaders; +using Il2CppInspector.Reflection; namespace Il2CppInspector.Cpp { public abstract class CppType { + // The name of the type + public string Name { get; } + // Calculate the size of the C++ type in bytes public abstract int GetSize(); + + protected CppType(string name) => Name = name; } // A non-struct non-class type @@ -25,7 +36,7 @@ namespace Il2CppInspector.Cpp public override int GetSize() => size; - public CppPrimitiveType(int size) => this.size = size; + public CppPrimitiveType(string name, int size) : base(name) => this.size = size; } // A struct or class type @@ -36,6 +47,10 @@ namespace Il2CppInspector.Cpp // Calculate the size by summing the size of each field's type public override int GetSize() => Fields.Values.Select(f => f.Type.GetSize()).Sum(); + + public CppComplexType(string name) : base(name) {} + + // TODO: Add fields } // A field in a C++ type @@ -44,6 +59,9 @@ namespace Il2CppInspector.Cpp // The name of the field public string Name { get; } + // The offset of the field into the type + public int Offset { get; } + // The type of the field public CppType Type { get; } } @@ -51,23 +69,92 @@ namespace Il2CppInspector.Cpp // A collection of C++ types public class CppTypes { + // All of the types private Dictionary types { get; } public CppType this[string s] => types[s]; - public CppTypes() { - types = new Dictionary { - ["uint8_t"] = new CppPrimitiveType(1), - ["uint16_t"] = new CppPrimitiveType(2), - ["uint32_t"] = new CppPrimitiveType(4), - ["uint64_t"] = new CppPrimitiveType(8), - ["int8_t"] = new CppPrimitiveType(1), - ["int16_t"] = new CppPrimitiveType(2), - ["int32_t"] = new CppPrimitiveType(4), - ["int64_t"] = new CppPrimitiveType(8), - ["char"] = new CppPrimitiveType(1), - ["void"] = new CppPrimitiveType(4), // or 8; pointer - }; + // Architecture width in bytes (4 bytes for 32-bit or 8 bytes for 64-bit, to determine pointer sizes) + public int WordSize { get; } + + private static readonly List primitiveTypes = new List { + new CppPrimitiveType("uint8_t", 1), + new CppPrimitiveType("uint16_t", 2), + new CppPrimitiveType("uint32_t", 4), + new CppPrimitiveType("uint64_t", 8), + new CppPrimitiveType("int8_t", 1), + new CppPrimitiveType("int16_t", 2), + new CppPrimitiveType("int32_t", 4), + new CppPrimitiveType("int64_t", 8), + new CppPrimitiveType("char", 1) + }; + + public CppTypes(int wordSize) { + WordSize = wordSize; + types = primitiveTypes.ToDictionary(t => t.Name, t => (CppType) t); + + // This is all compiler-dependent, let's hope for the best! + types.Add("uintptr_t", new CppPrimitiveType("uintptr_t", WordSize)); + types.Add("size_t", new CppPrimitiveType("size_t", WordSize)); + } + + // Parse a block of C++ source code, adding any types found + public void AddFromDeclarationText(string text) { + using StringReader lines = new StringReader(text); + + var rgxTypedef = new Regex(@"typedef (\S+) (\S+);"); + var rgxTypedefFnPtr = new Regex(@"typedef\s+\S+\s*\(\s*\*(\S+)\)\s*\(.*\);"); + + string line; + while ((line = lines.ReadLine()) != null) { + + // Sanitize + line = line.Trim(); + line = line.Replace(" const ", " "); + + // typedef (*)(); + var typedef = rgxTypedefFnPtr.Match(line); + if (typedef.Success) { + var alias = typedef.Groups[1].Captures[0].ToString(); + + Debug.WriteLine($"[TYPEDEF] {line} -- Adding method pointer typedef to {alias}"); + + types.Add(alias, types["uintptr_t"]); + continue; + } + + // typedef ; + typedef = rgxTypedef.Match(line); + if (typedef.Success) { + var alias = typedef.Groups[2].Captures[0].ToString(); + var existingType = typedef.Groups[1].Captures[0].ToString(); + + // Pointers + if (existingType.Contains("*")) { + // TODO: Typedef pointers + } + // Regular aliases + else { + Debug.WriteLine($"[TYPEDEF] {line} -- Adding typedef from {existingType} to {alias}"); + + types.Add(alias, types[existingType]); + continue; + } + } + + Debug.WriteLine("[IGNORE ] " + line); + } + } + + // Generate a populated CppTypes object from an + public static CppTypes FromUnityHeaders(UnityVersion version) { + var cppTypes = new CppTypes(8); + + // Process Unity headers + var headers = UnityHeader.GetHeaderForVersion(version).GetHeaderText(); + cppTypes.AddFromDeclarationText(headers); + + return cppTypes; } } }