C++: Add parse loop, implement typedef alias parsing
This commit is contained in:
@@ -6,16 +6,27 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Il2CppInspector.Outputs;
|
||||||
|
using Il2CppInspector.Outputs.UnityHeaders;
|
||||||
|
using Il2CppInspector.Reflection;
|
||||||
|
|
||||||
namespace Il2CppInspector.Cpp
|
namespace Il2CppInspector.Cpp
|
||||||
{
|
{
|
||||||
public abstract class CppType
|
public abstract class CppType
|
||||||
{
|
{
|
||||||
|
// The name of the type
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
// Calculate the size of the C++ type in bytes
|
// Calculate the size of the C++ type in bytes
|
||||||
public abstract int GetSize();
|
public abstract int GetSize();
|
||||||
|
|
||||||
|
protected CppType(string name) => Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A non-struct non-class type
|
// A non-struct non-class type
|
||||||
@@ -25,7 +36,7 @@ namespace Il2CppInspector.Cpp
|
|||||||
|
|
||||||
public override int GetSize() => size;
|
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
|
// A struct or class type
|
||||||
@@ -36,6 +47,10 @@ namespace Il2CppInspector.Cpp
|
|||||||
|
|
||||||
// Calculate the size by summing the size of each field's type
|
// 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 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
|
// A field in a C++ type
|
||||||
@@ -44,6 +59,9 @@ namespace Il2CppInspector.Cpp
|
|||||||
// The name of the field
|
// The name of the field
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
// The offset of the field into the type
|
||||||
|
public int Offset { get; }
|
||||||
|
|
||||||
// The type of the field
|
// The type of the field
|
||||||
public CppType Type { get; }
|
public CppType Type { get; }
|
||||||
}
|
}
|
||||||
@@ -51,23 +69,92 @@ namespace Il2CppInspector.Cpp
|
|||||||
// A collection of C++ types
|
// A collection of C++ types
|
||||||
public class CppTypes
|
public class CppTypes
|
||||||
{
|
{
|
||||||
|
// All of the types
|
||||||
private Dictionary<string, CppType> types { get; }
|
private Dictionary<string, CppType> types { get; }
|
||||||
|
|
||||||
public CppType this[string s] => types[s];
|
public CppType this[string s] => types[s];
|
||||||
|
|
||||||
public CppTypes() {
|
// Architecture width in bytes (4 bytes for 32-bit or 8 bytes for 64-bit, to determine pointer sizes)
|
||||||
types = new Dictionary<string, CppType> {
|
public int WordSize { get; }
|
||||||
["uint8_t"] = new CppPrimitiveType(1),
|
|
||||||
["uint16_t"] = new CppPrimitiveType(2),
|
private static readonly List<CppPrimitiveType> primitiveTypes = new List<CppPrimitiveType> {
|
||||||
["uint32_t"] = new CppPrimitiveType(4),
|
new CppPrimitiveType("uint8_t", 1),
|
||||||
["uint64_t"] = new CppPrimitiveType(8),
|
new CppPrimitiveType("uint16_t", 2),
|
||||||
["int8_t"] = new CppPrimitiveType(1),
|
new CppPrimitiveType("uint32_t", 4),
|
||||||
["int16_t"] = new CppPrimitiveType(2),
|
new CppPrimitiveType("uint64_t", 8),
|
||||||
["int32_t"] = new CppPrimitiveType(4),
|
new CppPrimitiveType("int8_t", 1),
|
||||||
["int64_t"] = new CppPrimitiveType(8),
|
new CppPrimitiveType("int16_t", 2),
|
||||||
["char"] = new CppPrimitiveType(1),
|
new CppPrimitiveType("int32_t", 4),
|
||||||
["void"] = new CppPrimitiveType(4), // or 8; pointer
|
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 <retType> (*<alias>)(<args>);
|
||||||
|
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 <targetType> <alias>;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user