C++: Parse array fields

This commit is contained in:
Katy Coe
2020-06-27 17:38:37 +02:00
parent 630b0a771d
commit f6e4c6eb09

View File

@@ -10,11 +10,9 @@ 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.CppUtils.UnityHeaders;
using Il2CppInspector.Reflection;
namespace Il2CppInspector.CppUtils
{
@@ -45,6 +43,9 @@ namespace Il2CppInspector.CppUtils
// Generate pointer to this type
public CppPointerType AsPointer(int WordSize) => new CppPointerType(WordSize, this);
// Generate array of this type
public CppArrayType AsArray(int Length) => new CppArrayType(this, Length);
// Generate typedef to this type
public CppAlias AsAlias(string Name) => new CppAlias(Name, this);
@@ -61,6 +62,28 @@ namespace Il2CppInspector.CppUtils
public CppPointerType(int WordSize, CppType elementType) : base(null, WordSize) => ElementType = elementType;
}
// An array type
public class CppArrayType : CppType
{
public override string Name => ElementType.Name;
public int Length { get; }
public CppType ElementType { get; }
// Even an array of 1-bit bitfirleds must use at least 1 byte each
public override int Size => SizeBytes * 8;
public override int SizeBytes => ElementType.SizeBytes * Length;
public CppArrayType(CppType elementType, int length) : base(null) {
ElementType = elementType;
Length = length;
}
public override string ToString() => ElementType + "[" + Length + "]";
}
// A typedef alias
public class CppAlias : CppType
{
@@ -96,7 +119,6 @@ namespace Il2CppInspector.CppUtils
// Add a field to the type. Returns the offset of the field in the type
public int AddField(CppField field) {
// TODO: Use InheritanceStyleEnum to determine whether the field is embedded or a pointer
field.Offset = CompoundType == CompoundType.Struct ? Size : 0;
// If we just came out of a bitfield, move to the next byte if necessary
@@ -168,13 +190,17 @@ namespace Il2CppInspector.CppUtils
internal CppType Type { get; set; }
// C++ representation of field (might be incorrect due to the above)
public override string ToString() => $"/* 0x{OffsetBytes:x2} - 0x{OffsetBytes + SizeBytes - 1:x2} (0x{SizeBytes:x2}) */"
// nested anonymous types
+ (Type is CppComplexType && Type.Name == "" ? "\n" + Type.ToString()[..^1] + " " + Name :
// regular fields
$" {Type.Name} {Name}" + (BitfieldSize > 0? $" : {BitfieldSize}" : ""))
+ ";"
+ (BitfieldSize > 0? $" // bits {BitfieldLSB} - {BitfieldMSB}" : "");
public override string ToString() =>
$"/* 0x{OffsetBytes:x2} - 0x{OffsetBytes + SizeBytes - 1:x2} (0x{SizeBytes:x2}) */"
// nested anonymous types
+ (Type is CppComplexType && Type.Name == "" ? "\n" + Type.ToString()[..^1] + " " + Name :
// regular fields
$" {Type.Name} {Name}" + (BitfieldSize > 0? $" : {BitfieldSize}" : ""))
// arrays
+ (Type is CppArrayType? "[" + ((CppArrayType)Type).Length + "]" : "")
+ ";"
// bitfields
+ (BitfieldSize > 0? $" // bits {BitfieldLSB} - {BitfieldMSB}" : "");
}
// A collection of C++ types
@@ -231,11 +257,12 @@ namespace Il2CppInspector.CppUtils
var rgxStripKeywords = new Regex(@"\b(?:const|unsigned|volatile)\b");
var rgxCompressPtrs = new Regex(@"\*\s+\*");
var rgxArrayField = new Regex(@"(\S+?)\[([0-9]+)\]");
var currentType = new Stack<CppComplexType>();
bool inEnum = false;
string line;
// TODO: Arrays
// TODO: Alignment directives
// TODO: enum prefix in field (Il2CppWindowsRuntimeTypeName)
// TODO: comma-separated fields
@@ -433,6 +460,15 @@ namespace Il2CppInspector.CppUtils
var name = field.Groups[2].Captures[0].ToString();
var typeName = field.Groups[1].Captures[0].ToString();
// Array
var array = rgxArrayField.Match(name);
int arraySize = 0;
if (array.Success && array.Groups[2].Captures.Count > 0) {
arraySize = int.Parse(array.Groups[2].Captures[0].ToString());
name = array.Groups[1].Captures[0].ToString();
}
// Bitfield
int bitfield = 0;
if (field.Groups[3].Captures.Count > 0)
bitfield = int.Parse(field.Groups[3].Captures[0].ToString());
@@ -444,6 +480,10 @@ namespace Il2CppInspector.CppUtils
type = type.AsPointer(WordSize);
var ct = currentType.Peek();
if (arraySize > 0)
type = type.AsArray(arraySize);
ct.AddField(new CppField {Name = name, Type = type, BitfieldSize = bitfield});
if (bitfield == 0)