C++: Various tweaks

Indent output
Handle bool fields
Skip comments and methods
Check that every line that matters is parsed
Update test to check every Unity version
This commit is contained in:
Katy Coe
2020-06-27 21:47:55 +02:00
parent 8f56aea002
commit 8a85acb242
2 changed files with 106 additions and 8 deletions

View File

@@ -151,7 +151,7 @@ namespace Il2CppInspector.CppUtils
if (Fields.Any()) {
sb.AppendLine("{");
foreach (var field in Fields.Values.SelectMany(f => f))
sb.AppendLine(" " + field);
sb.AppendLine(" " + string.Join("\n ", field.ToString().Split('\n')));
sb.Append($"}} {Name}{(Name.Length > 0 ? " " : "")}/* Size: 0x{SizeBytes:x2} */;");
}
@@ -236,6 +236,7 @@ namespace Il2CppInspector.CppUtils
new CppType("int", 32),
new CppType("float", 32),
new CppType("double", 64),
new CppType("bool", 8),
new CppType("void", 0)
};
@@ -270,10 +271,13 @@ namespace Il2CppInspector.CppUtils
var rgxAlignment = new Regex(@"__attribute__\(\(aligned\(([0-9]+)\)\)\)");
var rgxIsBitDirective = new Regex(@"#ifdef\s+IS_(32|64)BIT");
var rgxSingleLineComment = new Regex(@"/\*.*?\*/");
var currentType = new Stack<CppComplexType>();
bool inEnum = false;
bool falseIfBlock = false;
bool inComment = false;
bool inMethod = false;
string line;
// TODO: function pointer signatures
@@ -281,9 +285,65 @@ namespace Il2CppInspector.CppUtils
while ((line = lines.ReadLine()) != null) {
// Sanitize
// Remove comments
if (line.Contains("//"))
line = line.Substring(0, line.IndexOf("//", StringComparison.Ordinal));
// End of multi-line comment?
if (line.Contains("*/") && inComment) {
inComment = false;
line = line.Substring(line.IndexOf("*/", StringComparison.Ordinal) + 2);
}
if (inComment) {
Debug.WriteLine($"[COMMENT ] {line}");
continue;
}
// Remove all single-line comments
line = rgxSingleLineComment.Replace(line, "");
// Start of multi-line comment?
if (line.Contains("/*") && !inComment) {
inComment = true;
line = line.Substring(0, line.IndexOf("/*"));
}
// Ignore global variables
if (line.StartsWith("const ") && currentType.Count == 0) {
Debug.WriteLine($"[GLOBAL ] {line}");
continue;
}
// Ignore methods
// Note: This is a very lazy way of processing early version IL2CPP headers
if (line != "}" && inMethod) {
Debug.WriteLine($"[METHOD ] {line}");
continue;
}
if (line == "}" && inMethod) {
inMethod = false;
Debug.WriteLine($"[METHOD END ] {line}");
continue;
}
if (line.StartsWith("static inline ")) {
inMethod = true;
Debug.WriteLine($"[METHOD START ] {line}");
continue;
}
// Remove keywords we don't care about
line = rgxStripKeywords.Replace(line, "");
// Remove whitespace in multiple indirections
line = rgxCompressPtrs.Replace(line, "**");
// Process __attribute((aligned(x)))
var alignment = 0;
var alignmentMatch = rgxAlignment.Match(line);
if (alignmentMatch.Success) {
@@ -293,6 +353,10 @@ namespace Il2CppInspector.CppUtils
line = line.Trim();
// Ignore blank lines
if (line.Length == 0)
continue;
// Process #ifs before anything else
// Doesn't handle nesting but we probably don't need to (use a Stack if we do)
var ifdef = rgxIsBitDirective.Match(line);
@@ -544,16 +608,42 @@ namespace Il2CppInspector.CppUtils
continue;
}
// Make sure we're not ignoring anything we shouldn't
Debug.WriteLine($"[IGNORE ] {line}");
// Block opens
if (line == "{")
continue;
// Enum values
if (inEnum)
continue;
// Global variables
if (line.StartsWith("static"))
continue;
// Pragma directives
if (line.StartsWith("#pragma"))
continue;
// Imports
if (line.StartsWith("extern"))
continue;
throw new InvalidOperationException("Could not understand C++ code: " + line);
}
}
// Generate a populated CppTypes object from a set of Unity headers
public static CppTypes FromUnityHeaders(UnityVersion version, int wordSize = 32) {
public static CppTypes FromUnityVersion(UnityVersion version, int wordSize = 32)
=> FromUnityHeaders(UnityHeader.GetHeaderForVersion(version));
public static CppTypes FromUnityHeaders(UnityHeader header, int wordSize = 32) {
var cppTypes = new CppTypes(wordSize);
// Process Unity headers
var headers = UnityHeader.GetHeaderForVersion(version).GetHeaderText();
var headers = header.GetHeaderText();
cppTypes.AddFromDeclarationText(headers);
return cppTypes;

View File

@@ -7,6 +7,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Il2CppInspector.CppUtils;
using Il2CppInspector.CppUtils.UnityHeaders;
using Il2CppInspector.Reflection;
@@ -19,14 +20,21 @@ namespace Il2CppInspector
{
[Test]
public void TestCppTypes() {
// TODO: Flesh out CppTypes test
// NOTE: This test doesn't check for correct results, only that parsing doesn't fail!
var cppTypes = CppTypes.FromUnityHeaders(new UnityVersion("2019.3.1f1"));
var unityAllHeaders = UnityHeader.GetAllHeaders();
// Ensure we have read the embedded assembly resources
Assert.IsTrue(unityAllHeaders.Any());
// Ensure we can interpret every header from every version of Unity without errors
// This will throw InvalidOperationException if there is a problem
foreach (var unityHeader in unityAllHeaders) {
var cppTypes = CppTypes.FromUnityHeaders(unityHeader);
foreach (var cppType in cppTypes.Types)
Debug.WriteLine(cppType.Key + ":\n" + cppType.Value + "\n");
throw new NotImplementedException();
Debug.WriteLine("// " + cppType.Key + "\n" + cppType.Value + "\n");
}
}
}
}