Exemple #1
0
        private Type PrepareFieldType(Type originalType)
        {
            var cppType = CppTypes.GetCppType(originalType);

            if (originalType.IsGenericType)
            {
                return(cppType.GetGenericTypeDefinition().MakeGenericType(cppType.GenericTypeArguments.Select(gp => PrepareFieldType(gp)).ToArray()));
            }

            if (cppType.Assembly == Assembly.GetExecutingAssembly() && !cppType.Assembly.IsDynamic)
            {
                return(CppTypes.CreateType("UF::" + RenameType(cppType)));
            }

            return(cppType);
        }
Exemple #2
0
        private void WriteFieldDeclaration(string name, UpdateField declarationType)
        {
            var    fieldGeneratedType = CppTypes.GetCppType(declarationType.Type);
            string typeName;

            if (_writeUpdateMasks)
            {
                var bit = CppTypes.CreateConstantForTemplateParameter(_fieldBitIndex[name][0]);
                if (fieldGeneratedType.IsArray)
                {
                    if (typeof(DynamicUpdateField).IsAssignableFrom(fieldGeneratedType.GetElementType()))
                    {
                        var elementType = PrepareFieldType(fieldGeneratedType.GetElementType().GenericTypeArguments[0]);
                        typeName           = TypeHandler.GetFriendlyName(elementType);
                        fieldGeneratedType = _arrayUpdateFieldType.MakeGenericType(
                            _dynamicUpdateFieldBaseType.MakeGenericType(elementType),
                            CppTypes.CreateConstantForTemplateParameter(declarationType.Size),
                            bit,
                            CppTypes.CreateConstantForTemplateParameter(_fieldBitIndex[name][1]));
                    }
                    else
                    {
                        var elementType = PrepareFieldType(fieldGeneratedType.GetElementType());
                        typeName           = TypeHandler.GetFriendlyName(elementType);
                        fieldGeneratedType = _arrayUpdateFieldType.MakeGenericType(elementType,
                                                                                   CppTypes.CreateConstantForTemplateParameter(declarationType.Size),
                                                                                   bit,
                                                                                   CppTypes.CreateConstantForTemplateParameter(_fieldBitIndex[name][1]));
                    }
                }
                else if (typeof(DynamicUpdateField).IsAssignableFrom(declarationType.Type))
                {
                    var elementType = PrepareFieldType(fieldGeneratedType.GenericTypeArguments[0]);
                    typeName           = TypeHandler.GetFriendlyName(elementType);
                    fieldGeneratedType = _dynamicUpdateFieldType.MakeGenericType(PrepareFieldType(fieldGeneratedType.GenericTypeArguments[0]),
                                                                                 CppTypes.CreateConstantForTemplateParameter(_fieldBitIndex[name][1]),
                                                                                 bit);
                }
                else if (typeof(BlzOptionalField).IsAssignableFrom(declarationType.Type))
                {
                    var elementType = PrepareFieldType(fieldGeneratedType.GenericTypeArguments[0]);
                    typeName           = TypeHandler.GetFriendlyName(elementType);
                    fieldGeneratedType = _optionalUpdateFieldType.MakeGenericType(elementType,
                                                                                  CppTypes.CreateConstantForTemplateParameter(_fieldBitIndex[name][1]),
                                                                                  bit);
                }
                else
                {
                    var elementType = PrepareFieldType(declarationType.Type);
                    typeName           = TypeHandler.GetFriendlyName(elementType);
                    fieldGeneratedType = _updateFieldType.MakeGenericType(PrepareFieldType(declarationType.Type),
                                                                          CppTypes.CreateConstantForTemplateParameter(_fieldBitIndex[name][1]),
                                                                          bit);
                }

                _header.WriteLine($"    {TypeHandler.GetFriendlyName(fieldGeneratedType)} {name};");
            }
            else if (fieldGeneratedType.IsArray)
            {
                typeName = TypeHandler.GetFriendlyName(fieldGeneratedType.GetElementType());
                _header.WriteLine($"    {typeName} {name}[{declarationType.Size}];");
            }
            else
            {
                typeName = TypeHandler.GetFriendlyName(fieldGeneratedType);
                _header.WriteLine($"    {typeName} {name};");
            }

            if ((declarationType.CustomFlag & CustomUpdateFieldFlag.ViewerDependent) != CustomUpdateFieldFlag.None)
            {
                _header.WriteLine($"    struct {name}Tag : ViewerDependentValueTag<{typeName}> {{}};");
            }
        }
Exemple #3
0
        public void TestCppTypes()
        {
            // NOTE: This test doesn't check for correct results, only that parsing doesn't fail!

            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.ToString("o") + "\n");
                }
            }

            // Do a few sanity checks taken from real applications
            // NOTE: Does not provide full code coverage!

            var cppTypes2 = CppTypes.FromUnityVersion(new UnityVersion("2019.3.1f1"), 64);

            CppComplexType ct;
            CppField       field;

            // Un-nested class
            ct = (CppComplexType)cppTypes2["Il2CppClass"];

            field = ct[0xD8].First();

            Assert.AreEqual(field.Name, "cctor_finished");

            field = ct[0x128].First();

            Assert.AreEqual(field.Name, "vtable");

            field = ct["cctor_finished"];

            Assert.AreEqual(field.OffsetBytes, 0xD8);

            field = ct["vtable"];

            Assert.AreEqual(field.OffsetBytes, 0x128);

            // Nested class
            ct = (CppComplexType)cppTypes2["Il2CppClass_Merged"];
            var fields = ct.Flattened;

            field = fields[0xD8].First();

            Assert.AreEqual(field.Name, "cctor_finished");

            field = fields[0x128].First();

            Assert.AreEqual(field.Name, "vtable");

            field = fields["cctor_finished"];

            Assert.AreEqual(field.OffsetBytes, 0xD8);

            field = fields["vtable"];

            Assert.AreEqual(field.OffsetBytes, 0x128);
        }
Exemple #4
0
        string GetTypeCode(CppType mangleType, Dictionary <string, int> compressMap)
        {
            CppTypes element = mangleType.ElementType;
            IEnumerable <CppModifiers> modifiers = mangleType.Modifiers;

            StringBuilder code = new StringBuilder();

            var ptrOrRef     = For.AnyInputIn(CppModifiers.Pointer, CppModifiers.Reference);
            var modifierCode = modifiers.Reverse().Transform(
                For.AnyInputIn(CppModifiers.Pointer, CppModifiers.Array).Emit("P"),
                For.AnyInputIn(CppModifiers.Reference).Emit("R"),

                // Itanium mangled names do not include const or volatile unless
                //  they modify the type pointed to by pointer or reference.
                Choose.TopOne(
                    For.AllInputsIn(CppModifiers.Volatile, CppModifiers.Const).InAnyOrder().After(ptrOrRef).Emit("VK"),
                    For.AnyInputIn(CppModifiers.Volatile).After(ptrOrRef).Emit("V"),
                    For.AnyInputIn(CppModifiers.Const).After(ptrOrRef).Emit("K")
                    )
                );

            code.Append(string.Join(string.Empty, modifierCode.ToArray()));
            int modifierLength = code.Length;

            switch (element)
            {
            case CppTypes.Int:
                code.Append(modifiers.Transform(
                                For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder().Emit('t'),
                                For.AnyInputIn(CppModifiers.Short).Emit('s'),
                                For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Long, CppModifiers.Long).InAnyOrder().Emit('y'),
                                For.AllInputsIn(CppModifiers.Long, CppModifiers.Long).InAnyOrder().Emit('x'),
                                For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Long).InAnyOrder().Emit('m'),
                                For.AnyInputIn(CppModifiers.Long).Emit('l'),
                                For.AnyInputIn(CppModifiers.Unsigned).Emit('j')
                                ).DefaultIfEmpty('i').ToArray());
                break;

            case CppTypes.Bool:
                code.Append('b');
                break;

            case CppTypes.Char:
                if (modifiers.Contains(CppModifiers.Signed))
                {
                    code.Append('a');
                }
                else if (modifiers.Contains(CppModifiers.Unsigned))
                {
                    code.Append('h');
                }
                else
                {
                    code.Append('c');
                }
                break;

            case CppTypes.Float:
                code.Append('f');
                break;

            case CppTypes.Double:
                if (modifiers.Contains(CppModifiers.Long))
                {
                    code.Append('e');
                }
                else
                {
                    code.Append('d');
                }
                break;

            case CppTypes.Class:
            case CppTypes.Struct:
            case CppTypes.Union:
            case CppTypes.Enum:
                // TODO: This is getting a little ridiculous and should probably be refactored...

                // Determine if we have any namespaces to print out
                bool hasNamespace = (mangleType.Namespaces != null);
                if (hasNamespace)
                {
                    code.Append('N');
                    foreach (var ns in mangleType.Namespaces)
                    {
                        code.Append(GetIdentifier(compressMap, ns));
                    }
                }

                // Look up the type by itself first
                // NOTE: Order here is important so that they get sequenced properly
                bool   foundType;
                string value = GetIdentifier(compressMap, mangleType.ElementTypeName, 0, out foundType);
                if (modifierLength > 0)
                {
                    // Next lookup the type with modifiers for a match
                    bool   foundExact;
                    string exact = GetIdentifier(compressMap, mangleType.ToString(), modifierLength, out foundExact);
                    if (foundExact)
                    {
                        // Use the exact values sequence ID and remove all modifiers and namespaces
                        code.Length  = 0;
                        hasNamespace = false;
                        value        = exact;
                    }
                    else if (foundType)
                    {
                        // We didn't get an exact match but we know the type
                        // so remove the namespaces, but not the modifiers
                        code.Length  = modifierLength;
                        hasNamespace = false;
                    }
                }

                // Print out our class identifier
                code.Append(value);

                // If we're printing out namespaces then signal the end of the namespace
                if (hasNamespace)
                {
                    code.Append('E');
                }

                // Since we handle the modifier compression in here make sure we skip the logic below
                modifierLength = 0;
                break;
            }

            // If there were modifiers then always add it to the compression map
            // NOTE: If there were multiple modifiers this causes us to skip sequence numbers
            if (modifierLength > 0)
            {
                bool   found;
                string value = GetIdentifier(compressMap, mangleType.ToString(), modifierLength, out found);
                if (found)
                {
                    return(value);
                }
            }

            return(code.ToString());
        }
Exemple #5
0
        string GetTypeCode(CppType mangleType, Dictionary <string, int> compressMap)
        {
            CppTypes element = mangleType.ElementType;
            IEnumerable <CppModifiers> modifiers = mangleType.Modifiers;

            StringBuilder code = new StringBuilder();

            var ptrOrRef     = For.AnyInputIn(CppModifiers.Pointer, CppModifiers.Reference);
            var modifierCode = modifiers.Reverse().Transform(
                For.AnyInputIn(CppModifiers.Pointer, CppModifiers.Array).Emit("P"),
                For.AnyInputIn(CppModifiers.Reference).Emit("R"),

                // Itanium mangled names do not include const or volatile unless
                //  they modify the type pointed to by pointer or reference.
                Choose.TopOne(
                    For.AllInputsIn(CppModifiers.Volatile, CppModifiers.Const).InAnyOrder().After(ptrOrRef).Emit("VK"),
                    For.AnyInputIn(CppModifiers.Volatile).After(ptrOrRef).Emit("V"),
                    For.AnyInputIn(CppModifiers.Const).After(ptrOrRef).Emit("K")
                    )
                );

            code.Append(string.Join(string.Empty, modifierCode.ToArray()));

            switch (element)
            {
            case CppTypes.Int:
                code.Append(modifiers.Transform(
                                For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder().Emit('t'),
                                For.AnyInputIn(CppModifiers.Short).Emit('s'),
                                For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Long, CppModifiers.Long).InAnyOrder().Emit('y'),
                                For.AllInputsIn(CppModifiers.Long, CppModifiers.Long).InAnyOrder().Emit('x'),
                                For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Long).InAnyOrder().Emit('m'),
                                For.AnyInputIn(CppModifiers.Long).Emit('l'),
                                For.AnyInputIn(CppModifiers.Unsigned).Emit('j')
                                ).DefaultIfEmpty('i').ToArray());
                break;

            case CppTypes.Bool:
                code.Append('b');
                break;

            case CppTypes.Char:
                if (modifiers.Contains(CppModifiers.Signed))
                {
                    code.Append('a');
                }
                else if (modifiers.Contains(CppModifiers.Unsigned))
                {
                    code.Append('h');
                }
                else
                {
                    code.Append('c');
                }
                break;

            case CppTypes.Float:
                code.Append('f');
                break;

            case CppTypes.Double:
                if (modifiers.Contains(CppModifiers.Long))
                {
                    code.Append('e');
                }
                else
                {
                    code.Append('d');
                }
                break;

            case CppTypes.Class:
            case CppTypes.Struct:
            case CppTypes.Union:
            case CppTypes.Enum:
                if (mangleType.Namespaces != null)
                {
                    code.Append('N');
                    foreach (var ns in mangleType.Namespaces)
                    {
                        code.Append(GetIdentifier(compressMap, ns));
                    }
                }

                code.Append(GetIdentifier(compressMap, mangleType.ElementTypeName));

                if (mangleType.Namespaces != null)
                {
                    code.Append('E');
                }
                break;
            }

            return(code.ToString());
        }
Exemple #6
0
        public virtual string GetTypeCode(CppType mangleType)
        {
            CppTypes element = mangleType.ElementType;
            IEnumerable <CppModifiers> modifiers = mangleType.Modifiers;

            StringBuilder code = new StringBuilder();

            var ptr           = For.AnyInputIn(CppModifiers.Pointer);
            var ptrRefOrArray = For.AnyInputIn(CppModifiers.Pointer, CppModifiers.Reference, CppModifiers.Array);

            var modifierCode = modifiers.Reverse().Transform(

                Choose.TopOne(
                    For.AllInputsIn(CppModifiers.Const, CppModifiers.Volatile).InAnyOrder().After(ptrRefOrArray).Emit('D'),
                    For.AnyInputIn(CppModifiers.Const).After(ptrRefOrArray).Emit('B'),
                    For.AnyInputIn(CppModifiers.Volatile).After(ptrRefOrArray).Emit('C'),
                    For.AnyInput <CppModifiers> ().After(ptrRefOrArray).Emit('A')
                    ),

                For.AnyInputIn(CppModifiers.Array).Emit('Q'),
                For.AnyInputIn(CppModifiers.Reference).Emit('A'),

                Choose.TopOne(
                    ptr.After().AllInputsIn(CppModifiers.Const, CppModifiers.Volatile).InAnyOrder().Emit('S'),
                    ptr.After().AnyInputIn(CppModifiers.Const).Emit('Q'),
                    ptr.After().AnyInputIn(CppModifiers.Volatile).Emit('R'),
                    ptr.Emit('P')
                    ),

                ptrRefOrArray.AtEnd().Emit('A')
                );

            code.Append(modifierCode.ToArray());

            switch (element)
            {
            case CppTypes.Void:
                code.Append('X');
                break;

            case CppTypes.Int:
                code.Append(modifiers.Transform(
                                For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder().Emit('G')
                                ).DefaultIfEmpty('H').ToArray());
                break;

            case CppTypes.Char:
                code.Append('D');
                break;

            case CppTypes.Class:
                code.Append('V');
                code.Append(mangleType.ElementTypeName);
                code.Append("@@");
                break;

            case CppTypes.Struct:
                code.Append('U');
                code.Append(mangleType.ElementTypeName);
                code.Append("@@");
                break;

            case CppTypes.Union:
                code.Append('T');
                code.Append(mangleType.ElementTypeName);
                code.Append("@@");
                break;

            case CppTypes.Enum:
                code.Append("W4");
                code.Append(mangleType.ElementTypeName);
                code.Append("@@");
                break;
            }

            return(code.ToString());
        }
Exemple #7
0
        public virtual string GetTypeCode(CppType mangleType, BackReferenceList backReferences)
        {
            CppTypes element = mangleType.ElementType;
            IEnumerable <CppModifiers> modifiers = mangleType.Modifiers;

            StringBuilder code = new StringBuilder();

            var ptr           = For.AnyInputIn(CppModifiers.Pointer);
            var ptrRefOrArray = For.AnyInputIn(CppModifiers.Pointer, CppModifiers.Reference, CppModifiers.Array);

            var modifierCode = modifiers.Reverse().Transform(

                Choose.TopOne(
                    For.AllInputsIn(CppModifiers.Const, CppModifiers.Volatile).InAnyOrder().After(ptrRefOrArray).Emit('D'),
                    For.AnyInputIn(CppModifiers.Const).After(ptrRefOrArray).Emit('B'),
                    For.AnyInputIn(CppModifiers.Volatile).After(ptrRefOrArray).Emit('C'),
                    For.AnyInput <CppModifiers> ().After(ptrRefOrArray).Emit('A')
                    ),

                For.AnyInputIn(CppModifiers.Array).Emit('Q'),
                For.AnyInputIn(CppModifiers.Reference).Emit('A'),

                Choose.TopOne(
                    ptr.After().AllInputsIn(CppModifiers.Const, CppModifiers.Volatile).InAnyOrder().Emit('S'),
                    ptr.After().AnyInputIn(CppModifiers.Const).Emit('Q'),
                    ptr.After().AnyInputIn(CppModifiers.Volatile).Emit('R'),
                    ptr.Emit('P')
                    ),
                ptrRefOrArray.AtEnd().Emit('A')
                );

            code.Append(modifierCode.ToArray());

            // Type codes taken from http://www.kegel.com/mangle.html#operators
            switch (element)
            {
            case CppTypes.Void:
                code.Append('X');
                break;

            case CppTypes.Int:
                code.Append(modifiers.Transform(Choose.TopOne(
                                                    For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder().Emit('G'),
                                                    For.AllInputsIn(CppModifiers.Short).InAnyOrder().Emit('F'),
                                                    For.AllInputsIn(CppModifiers.Unsigned, CppModifiers.Long).InAnyOrder().Emit('K'),
                                                    For.AllInputsIn(CppModifiers.Long).InAnyOrder().Emit('J'),
                                                    For.AllInputsIn(CppModifiers.Unsigned).InAnyOrder().Emit('I')
                                                    )).DefaultIfEmpty('H').ToArray());
                break;

            case CppTypes.Float:
                code.Append('M');
                break;

            case CppTypes.Double:
                code.Append(modifiers.Transform(
                                For.AllInputsIn(CppModifiers.Long).InAnyOrder().Emit('O')
                                ).DefaultIfEmpty('N').ToArray());
                break;

            case CppTypes.Char:
                code.Append(modifiers.Transform(Choose.TopOne(
                                                    For.AllInputsIn(CppModifiers.Unsigned).InAnyOrder().Emit('E'),
                                                    For.AllInputsIn(CppModifiers.Signed).InAnyOrder().Emit('C')
                                                    )).DefaultIfEmpty('D').ToArray());
                break;

            case CppTypes.Class:
                code.Append('V');
                code.Append(GetTypeNameWithBackReferences(mangleType, backReferences));
                code.Append("@");
                break;

            case CppTypes.Struct:
                code.Append('U');
                code.Append(GetTypeNameWithBackReferences(mangleType, backReferences));
                code.Append("@");
                break;

            case CppTypes.Union:
                code.Append('T');
                code.Append(GetTypeNameWithBackReferences(mangleType, backReferences));
                code.Append("@");
                break;

            case CppTypes.Enum:
                code.Append("W4");
                code.Append(GetTypeNameWithBackReferences(mangleType, backReferences));
                code.Append("@");
                break;

            case CppTypes.Bool:
                code.Append("_N");
                break;
            }

            return(code.ToString());
        }