C++: Handle unsigned/volatile, improve output, typedefs, regexes
This commit is contained in:
@@ -107,13 +107,22 @@ namespace Il2CppInspector.Cpp
|
|||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
if (Name.Length > 0)
|
||||||
|
sb.Append("typedef ");
|
||||||
sb.Append(CompoundType == CompoundType.Struct ? "struct " : "union ");
|
sb.Append(CompoundType == CompoundType.Struct ? "struct " : "union ");
|
||||||
sb.AppendLine(Name + (Name.Length > 0? " ":"") + "{");
|
sb.Append(Name + (Name.Length > 0 ? " " : ""));
|
||||||
|
|
||||||
foreach (var field in Fields.Values.SelectMany(f => f))
|
if (Fields.Any()) {
|
||||||
sb.AppendLine(" " + field);
|
sb.AppendLine("{");
|
||||||
|
foreach (var field in Fields.Values.SelectMany(f => f))
|
||||||
|
sb.AppendLine(" " + field);
|
||||||
|
|
||||||
sb.Append($"}} /* Size: 0x{Size:x2} */;");
|
sb.Append($"}} {Name}{(Name.Length > 0 ? " " : "")}/* Size: 0x{Size:x2} */;");
|
||||||
|
}
|
||||||
|
// Forward declaration
|
||||||
|
else {
|
||||||
|
sb.Append($"{Name};");
|
||||||
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
@@ -191,11 +200,12 @@ namespace Il2CppInspector.Cpp
|
|||||||
var rgxExternDecl = new Regex(@"struct (\S+);");
|
var rgxExternDecl = new Regex(@"struct (\S+);");
|
||||||
var rgxTypedefForwardDecl = new Regex(@"typedef struct (\S+) (\S+);");
|
var rgxTypedefForwardDecl = new Regex(@"typedef struct (\S+) (\S+);");
|
||||||
var rgxTypedefFnPtr = new Regex(@"typedef\s+(?:struct )?\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
|
var rgxTypedefFnPtr = new Regex(@"typedef\s+(?:struct )?\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
|
||||||
var rgxTypedefPtr = new Regex(@"typedef (\S+?)\s*\*+\s*(\S+);");
|
var rgxTypedef = new Regex(@"typedef (\S+?)\s*\**\s*(\S+);");
|
||||||
var rgxTypedef = new Regex(@"typedef (\S+) (\S+);");
|
|
||||||
var rgxFieldFnPtr = new Regex(@"\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
|
var rgxFieldFnPtr = new Regex(@"\S+\s*\(\s*\*(\S+)\)\s*\(.*\);");
|
||||||
var rgxFieldPtr = new Regex(@"^(?:struct )?(\S+?)\s*\*+\s*(\S+);");
|
var rgxField = new Regex(@"^(?:struct )?(\S+?)\s*\**\s*(\S+);");
|
||||||
var rgxFieldVal = new Regex(@"^(?:struct )?(\S+)\s+(\S+);");
|
|
||||||
|
var rgxStripKeywords = new Regex(@"\b(?:const|unsigned|volatile)\b");
|
||||||
|
var rgxCompressPtrs = new Regex(@"\*\s+\*");
|
||||||
|
|
||||||
var currentType = new Stack<CppComplexType>();
|
var currentType = new Stack<CppComplexType>();
|
||||||
bool inEnum = false;
|
bool inEnum = false;
|
||||||
@@ -204,22 +214,17 @@ namespace Il2CppInspector.Cpp
|
|||||||
// TODO: Bitfields
|
// TODO: Bitfields
|
||||||
// TODO: Arrays
|
// TODO: Arrays
|
||||||
// TODO: Alignment directives
|
// TODO: Alignment directives
|
||||||
// TODO: unsigned
|
|
||||||
// TODO: enum prefix in field (Il2CppWindowsRuntimeTypeName)
|
// TODO: enum prefix in field (Il2CppWindowsRuntimeTypeName)
|
||||||
// TODO: comma-separated fields
|
// TODO: comma-separated fields
|
||||||
// TODO: #ifdef IS_32BIT
|
// TODO: #ifdef IS_32BIT
|
||||||
// TODO: volatile
|
|
||||||
// TODO: function pointer signatures
|
// TODO: function pointer signatures
|
||||||
|
|
||||||
while ((line = lines.ReadLine()) != null) {
|
while ((line = lines.ReadLine()) != null) {
|
||||||
|
|
||||||
// Sanitize
|
// Sanitize
|
||||||
|
line = rgxStripKeywords.Replace(line, "");
|
||||||
|
line = rgxCompressPtrs.Replace(line, "**");
|
||||||
line = line.Trim();
|
line = line.Trim();
|
||||||
line = line.Replace(" const ", " ");
|
|
||||||
line = line.Replace("const*", "*");
|
|
||||||
if (line.StartsWith("const "))
|
|
||||||
line = line.Substring(6);
|
|
||||||
line = line.Replace("* *", "**"); // pointer to const pointer
|
|
||||||
|
|
||||||
// External declaration
|
// External declaration
|
||||||
// struct <external-type>;
|
// struct <external-type>;
|
||||||
@@ -238,15 +243,16 @@ namespace Il2CppInspector.Cpp
|
|||||||
// typedef struct <struct-type> <alias>
|
// typedef struct <struct-type> <alias>
|
||||||
var typedef = rgxTypedefForwardDecl.Match(line);
|
var typedef = rgxTypedefForwardDecl.Match(line);
|
||||||
if (typedef.Success) {
|
if (typedef.Success) {
|
||||||
// We're lazy so we're just going to hope that the struct and alias names are the same
|
|
||||||
var alias = typedef.Groups[2].Captures[0].ToString();
|
var alias = typedef.Groups[2].Captures[0].ToString();
|
||||||
var declType = typedef.Groups[1].Captures[0].ToString();
|
var declType = typedef.Groups[1].Captures[0].ToString();
|
||||||
|
|
||||||
Debug.Assert(alias == declType);
|
|
||||||
|
|
||||||
// Sometimes we might get multiple forward declarations for the same type
|
// Sometimes we might get multiple forward declarations for the same type
|
||||||
|
if (!Types.ContainsKey(declType))
|
||||||
|
Types.Add(declType, new CppComplexType(CompoundType.Struct) {Name = declType});
|
||||||
|
|
||||||
|
// Sometimes the alias might be the same name as the type (this is usually the case)
|
||||||
if (!Types.ContainsKey(alias))
|
if (!Types.ContainsKey(alias))
|
||||||
Types.Add(alias, new CppComplexType(CompoundType.Struct) {Name = alias});
|
Types.Add(alias, Types[declType].AsAlias(alias));
|
||||||
|
|
||||||
Debug.WriteLine($"[FORWARD DECL ] {line}");
|
Debug.WriteLine($"[FORWARD DECL ] {line}");
|
||||||
continue;
|
continue;
|
||||||
@@ -263,34 +269,22 @@ namespace Il2CppInspector.Cpp
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pointer alias
|
// Alias
|
||||||
// typedef <targetType>*+ <alias>;
|
// typedef <targetType>[*..] <alias>;
|
||||||
typedef = rgxTypedefPtr.Match(line);
|
typedef = rgxTypedef.Match(line);
|
||||||
if (typedef.Success) {
|
if (typedef.Success) {
|
||||||
var alias = typedef.Groups[2].Captures[0].ToString();
|
var alias = typedef.Groups[2].Captures[0].ToString();
|
||||||
var existingType = typedef.Groups[1].Captures[0].ToString();
|
var existingType = typedef.Groups[1].Captures[0].ToString();
|
||||||
|
|
||||||
// Potential multiple indirection
|
// Potential multiple indirection
|
||||||
var type = Types[existingType];
|
var type = Types[existingType];
|
||||||
for (int i = 0; i < line.Count(c => c == '*'); i++)
|
var pointers = line.Count(c => c == '*');
|
||||||
|
for (int i = 0; i < pointers; i++)
|
||||||
type = type.AsPointer(WordSize);
|
type = type.AsPointer(WordSize);
|
||||||
|
|
||||||
Types.Add(alias, type.AsAlias(alias));
|
Types.Add(alias, type.AsAlias(alias));
|
||||||
|
|
||||||
Debug.WriteLine($"[TYPEDEF PTR ] {line} -- Adding pointer typedef from {type.Name} to {alias}");
|
Debug.WriteLine($"[TYPEDEF {(pointers > 0? "PTR":"VAL")} ] {line} -- Adding typedef from {type.Name} to {alias}");
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alias
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
Types.Add(alias, Types[existingType].AsAlias(alias));
|
|
||||||
|
|
||||||
Debug.WriteLine($"[TYPEDEF ALIAS] {line} -- Adding typedef from {existingType} to {alias}");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,23 +404,22 @@ namespace Il2CppInspector.Cpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pointer or value field
|
// Pointer or value field
|
||||||
var fieldPtr = rgxFieldPtr.Match(line);
|
var field = rgxField.Match(line);
|
||||||
var fieldVal = rgxFieldVal.Match(line);
|
|
||||||
|
|
||||||
if (fieldPtr.Success || fieldVal.Success) {
|
if (field.Success) {
|
||||||
var fieldMatch = fieldPtr.Success ? fieldPtr : fieldVal;
|
var name = field.Groups[2].Captures[0].ToString();
|
||||||
var name = fieldMatch.Groups[2].Captures[0].ToString();
|
var typeName = field.Groups[1].Captures[0].ToString();
|
||||||
var typeName = fieldMatch.Groups[1].Captures[0].ToString();
|
|
||||||
|
|
||||||
// Potential multiple indirection
|
// Potential multiple indirection
|
||||||
var type = Types[typeName];
|
var type = Types[typeName];
|
||||||
for (int i = 0; i < line.Count(c => c == '*'); i++)
|
var pointers = line.Count(c => c == '*');
|
||||||
|
for (int i = 0; i < pointers; i++)
|
||||||
type = type.AsPointer(WordSize);
|
type = type.AsPointer(WordSize);
|
||||||
|
|
||||||
var ct = currentType.Peek();
|
var ct = currentType.Peek();
|
||||||
ct.AddField(new CppField {Name = name, Type = type});
|
ct.AddField(new CppField {Name = name, Type = type});
|
||||||
|
|
||||||
Debug.WriteLine($"[FIELD {(fieldPtr.Success? "PTR":"VAL")} ] {line} -- {name}");
|
Debug.WriteLine($"[FIELD {(pointers > 0? "PTR":"VAL")} ] {line} -- {name}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user