C++: CppTypes add enumerators & indexers, flattened fields, force sorting, update test

This commit is contained in:
Katy Coe
2020-06-29 18:24:29 +02:00
parent 46f2b9eb53
commit 4ca640d551
2 changed files with 107 additions and 4 deletions

View File

@@ -115,14 +115,70 @@ namespace Il2CppInspector.CppUtils
}
// A struct, union or class type (type with fields)
public class CppComplexType : CppType
public class CppComplexType : CppType, IEnumerable<CppField>
{
// Various enumerators
public List<CppField> this[int byteOffset] => Fields[byteOffset * 8];
public CppField this[string fieldName] => Fields.Values.SelectMany(f => f).FirstOrDefault(f => f.Name == fieldName);
public IEnumerator<CppField> GetEnumerator() => Fields.Values.SelectMany(f => f).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
// Collection which flattens all nested fields, calculating their direct bit offsets from the start of the type
// Unions can still cause some offsets to have multiple values
public class FlattenedFieldsCollection : IEnumerable<CppField>
{
public SortedDictionary<int, List<CppField>> Fields;
public FlattenedFieldsCollection(CppComplexType t) => Fields = getFlattenedFields(t);
private SortedDictionary<int, List<CppField>> getFlattenedFields(CppComplexType t) {
var flattened = new SortedDictionary<int, List<CppField>>();
foreach (var field in t.Fields.Values.SelectMany(f => f)) {
if (field.Type is CppComplexType ct) {
var baseOffset = field.Offset;
var fields = ct.Flattened.Fields.Select(kl => new {
Key = kl.Key + baseOffset,
Value = kl.Value.Select(f => new CppField { Name = f.Name, Type = f.Type, BitfieldSize = f.BitfieldSize, Offset = f.Offset + baseOffset }).ToList()
}).ToDictionary(kv => kv.Key, kv => kv.Value);
flattened = new SortedDictionary<int, List<CppField>>(flattened.Union(fields).ToDictionary(kv => kv.Key, kv => kv.Value));
} else {
if (flattened.ContainsKey(field.Offset))
flattened[field.Offset].Add(field);
else
flattened.Add(field.Offset, new List<CppField> { field });
}
}
return flattened;
}
public List<CppField> this[int byteOffset] => Fields[byteOffset * 8];
public CppField this[string fieldName] => Fields.Values.SelectMany(f => f).FirstOrDefault(f => f.Name == fieldName);
public IEnumerator<CppField> GetEnumerator() => Fields.Values.SelectMany(f => f).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
private FlattenedFieldsCollection flattenedFields;
public FlattenedFieldsCollection Flattened {
get {
if (flattenedFields == null)
flattenedFields = new FlattenedFieldsCollection(this);
return flattenedFields;
}
}
// The compound type
public CompoundType CompoundType;
// Dictionary of byte offset in the type to each field
// Unions and bitfields can have more than one field at the same offset
public Dictionary<int, List<CppField>> Fields { get; internal set; } = new Dictionary<int, List<CppField>>();
public SortedDictionary<int, List<CppField>> Fields { get; internal set; } = new SortedDictionary<int, List<CppField>>();
public CppComplexType(CompoundType compoundType) : base("", 0) => CompoundType = compoundType;
@@ -147,7 +203,7 @@ namespace Il2CppInspector.CppUtils
if (alignmentBytes > 0 && field.OffsetBytes % alignmentBytes != 0)
field.Offset += (alignmentBytes - field.OffsetBytes % alignmentBytes) * 8;
if (Fields.ContainsKey(field.Offset))
if (Fields.ContainsKey(field.Offset))
Fields[field.Offset].Add(field);
else
Fields.Add(field.Offset, new List<CppField> { field });
@@ -216,7 +272,7 @@ namespace Il2CppInspector.CppUtils
var offset = $"/* 0x{OffsetBytes:x2} - 0x{OffsetBytes + SizeBytes - 1:x2} (0x{SizeBytes:x2}) */";
var field = Type switch {
// nested anonymouse types
// nested anonymous types
CppComplexType t when string.IsNullOrEmpty(t.Name) => "\n" + t.ToString()[..^1] + " " + Name,
// function pointers
CppFnPtrType t when string.IsNullOrEmpty(t.Name) => $" {t.ReturnType} (*{Name})({t.Arguments})",