예제 #1
0
        // We try decently hard to avoid creating clashing names, and also sanitize any invalid names.
        // You can customize how naming works by modifying this function.
        private void InitializeNaming()
        {
            TypeNamespace = CreateNamespace();
            // Type names that may appear in the header
            foreach (var typeName in new string[] { "CustomAttributesCache", "CustomAttributeTypeCache", "EventInfo", "FieldInfo", "Hash16", "MemberInfo", "MethodInfo", "MethodVariableKind", "MonitorData", "ParameterInfo", "PInvokeArguments", "PropertyInfo", "SequencePointKind", "StackFrameType", "VirtualInvokeData" })
            {
                TypeNamespace.ReserveName(typeName);
            }
            TypeNamer = TypeNamespace.MakeNamer <TypeInfo>((ti) => {
                if (ti.IsArray)
                {
                    return(TypeNamer.GetName(ti.ElementType) + "__Array");
                }
                var name = ti.Name.ToCIdentifier();
                if (name.StartsWith("Il2Cpp"))
                {
                    name = "_" + name;
                }
                name = Regex.Replace(name, "__+", "_");
                // Work around a dumb IDA bug: enums can't be named the same as certain "built-in" types
                // like KeyCode, Position, ErrorType. This only applies to enums, not structs.
                if (ti.IsEnum)
                {
                    name += "__Enum";
                }
                return(name);
            });

            GlobalsNamespace = CreateNamespace();
            GlobalNamer      = GlobalsNamespace.MakeNamer <MethodBase>((method) => $"{TypeNamer.GetName(method.DeclaringType)}_{method.Name.ToCIdentifier()}");
            EnumNamer        = GlobalsNamespace.MakeNamer <FieldInfo>((field) => $"{TypeNamer.GetName(field.DeclaringType)}_{field.Name.ToCIdentifier()}");
        }
        // Generate the C structure for a value type, such as an enum or struct
        private (CppComplexType valueType, CppComplexType boxedType) GenerateValueFieldStruct(TypeInfo ti)
        {
            CppComplexType valueType, boxedType;
            string         name = TypeNamer.GetName(ti);

            if (ti.IsEnum)
            {
                // Enums should be represented using enum syntax
                // They otherwise behave like value types
                var namer          = CreateNamespace().MakeNamer <FieldInfo>((field) => field.Name.ToCIdentifier());
                var underlyingType = AsCType(ti.GetEnumUnderlyingType());
                valueType = types.Enum(underlyingType, name);
                foreach (var field in ti.DeclaredFields)
                {
                    if (field.Name != "value__")
                    {
                        ((CppEnumType)valueType).AddField(namer.GetName(field), field.DefaultValue);
                    }
                }

                boxedType = GenerateObjectStruct(name + "__Boxed", ti);
                boxedType.AddField("value", AsCType(ti));
            }
            else
            {
                // This structure is passed by value, so it doesn't include Il2CppObject fields.
                valueType = types.Struct(name);
                GenerateFieldList(valueType, CreateNamespace(), ti);

                // Also generate the boxed form of the structure which includes the Il2CppObject header.
                boxedType = GenerateObjectStruct(name + "__Boxed", ti);
                boxedType.AddField("fields", AsCType(ti));
            }
            return(valueType, boxedType);
        }
        // Generate the fields for the base class of all objects (Il2CppObject)
        // The two fields are inlined so that we can specialize the klass member for each type object
        private CppComplexType GenerateObjectStruct(string name, TypeInfo ti)
        {
            var type = types.Struct(name);

            types.AddField(type, "klass", TypeNamer.GetName(ti) + "__Class *");
            types.AddField(type, "monitor", "MonitorData *");
            return(type);
        }
예제 #4
0
        /// <summary>
        /// Include the given type into this generator. This will add the given type and all types it depends on.
        /// Call GenerateRemainingTypeDeclarations to produce the actual type declarations afterwards.
        /// </summary>
        /// <param name="ti"></param>
        public void IncludeType(TypeInfo ti)
        {
            if (VisitedTypes.Contains(ti))
            {
                return;
            }
            if (ti.ContainsGenericParameters)
            {
                return;
            }
            VisitedTypes.Add(ti);

            if (ti.IsArray)
            {
                VisitFieldStructs(ti);
                IncludeType(ti.ElementType);
                IncludeType(ti.BaseType);
                return;
            }
            else if (ti.HasElementType)
            {
                IncludeType(ti.ElementType);
                return;
            }
            else if (ti.IsEnum)
            {
                VisitFieldStructs(ti);
                IncludeType(ti.GetEnumUnderlyingType());
                return;
            }

            // Visit all fields first, considering only value types,
            // so that we can get the layout correct.
            VisitFieldStructs(ti);

            if (ti.BaseType != null)
            {
                IncludeType(ti.BaseType);
            }

            TypeNamer.GetName(ti);

            foreach (var fi in ti.DeclaredFields)
            {
                IncludeType(fi.FieldType);
            }

            foreach (var mi in GetFilledVTable(ti))
            {
                if (mi != null && !mi.ContainsGenericParameters)
                {
                    IncludeMethod(mi);
                }
            }

            TodoTypeStructs.Add(ti);
        }
        // Generate a C declaration for a method
        private CppFnPtrType GenerateMethodDeclaration(MethodBase method, string name, TypeInfo declaringType)
        {
            CppType retType;

            if (method is MethodInfo mi)
            {
                retType = mi.ReturnType.FullName == "System.Void" ? types["void"] : AsCType(mi.ReturnType);
            }
            else
            {
                retType = types["void"];
            }

            var paramNs = CreateNamespace();

            paramNs.ReserveName("method");
            var paramNamer = paramNs.MakeNamer <ParameterInfo>((pi) => pi.Name == "" ? "arg" : pi.Name.ToCIdentifier());

            var paramList = new List <(string, CppType)>();

            // Figure out the "this" param
            if (method.IsStatic)
            {
                // In older versions, static methods took a dummy this parameter
                if (UnityVersion.CompareTo("2018.3.0") < 0)
                {
                    paramList.Add(("this", types.GetType("void *")));
                }
            }
            else
            {
                if (declaringType.IsValueType)
                {
                    // Methods for structs take the boxed object as the this param
                    paramList.Add(("this", types.GetType(TypeNamer.GetName(declaringType) + "__Boxed *")));
                }
                else
                {
                    paramList.Add(("this", AsCType(declaringType)));
                }
            }

            foreach (var pi in method.DeclaredParameters)
            {
                paramList.Add((paramNamer.GetName(pi), AsCType(pi.ParameterType)));
            }

            paramList.Add(("method", types.GetType("MethodInfo *")));

            return(new CppFnPtrType(types.WordSize, retType, paramList)
            {
                Name = name
            });
        }
예제 #6
0
        // Generate a C declaration for a method
        private string GenerateMethodDeclaration(MethodBase method, string name, TypeInfo declaringType)
        {
            string retType;

            if (method is MethodInfo mi)
            {
                retType = mi.ReturnType.FullName == "System.Void" ? "void" : AsCType(mi.ReturnType);
            }
            else
            {
                retType = "void";
            }

            var paramNs = CreateNamespace();

            paramNs.ReserveName("method");
            var paramNamer = paramNs.MakeNamer <ParameterInfo>((pi) => pi.Name == "" ? "arg" : pi.Name.ToCIdentifier());

            var paramList = new List <string>();

            // Figure out the "this" param
            if (method.IsStatic)
            {
                // In older versions, static methods took a dummy this parameter
                if (UnityVersion.CompareTo("2018.3.0") < 0)
                {
                    paramList.Add("void *this");
                }
            }
            else
            {
                if (declaringType.IsValueType)
                {
                    // Methods for structs take the boxed object as the this param
                    paramList.Add($"struct {TypeNamer.GetName(declaringType)}__Boxed * this");
                }
                else
                {
                    paramList.Add($"{AsCType(declaringType)} this");
                }
            }

            foreach (var pi in method.DeclaredParameters)
            {
                paramList.Add($"{AsCType(pi.ParameterType)} {paramNamer.GetName(pi)}");
            }

            paramList.Add($"struct MethodInfo *method");

            return($"{retType} {name}({string.Join(", ", paramList)})");
        }
예제 #7
0
        // C type declaration used to name variables of the given C# type
        public string AsCType(TypeInfo ti)
        {
            // IsArray case handled by TypeNamer.GetName
            if (ti.IsByRef || ti.IsPointer)
            {
                return($"{AsCType(ti.ElementType)} *");
            }
            else if (ti.IsValueType)
            {
                if (ti.IsPrimitive)
                {
                    switch (ti.Name)
                    {
                    case "Boolean": return("bool");

                    case "Byte": return("uint8_t");

                    case "SByte": return("int8_t");

                    case "Int16": return("int16_t");

                    case "UInt16": return("uint16_t");

                    case "Int32": return("int32_t");

                    case "UInt32": return("uint32_t");

                    case "Int64": return("int64_t");

                    case "UInt64": return("uint64_t");

                    case "IntPtr": return("void *");

                    case "UIntPtr": return("void *");

                    case "Char": return("uint16_t");

                    case "Double": return("double");

                    case "Single": return("float");
                    }
                }
                return($"struct {TypeNamer.GetName(ti)}");
            }
            else if (ti.IsEnum)
            {
                return($"enum {TypeNamer.GetName(ti)}");
            }
            return($"struct {TypeNamer.GetName(ti)} *");
        }
예제 #8
0
        // Generate the overall Il2CppClass-shaped structure for the given type
        private void GenerateTypeStruct(StringBuilder csrc, TypeInfo ti)
        {
            var name = TypeNamer.GetName(ti);

            GenerateVTableStruct(csrc, ti);

            csrc.Append($"struct {name}__StaticFields {{\n");
            var namer = CreateNamespace().MakeNamer <FieldInfo>((field) => field.Name.ToCIdentifier());

            foreach (var field in ti.DeclaredFields)
            {
                if (field.IsLiteral || !field.IsStatic)
                {
                    continue;
                }
                csrc.Append($"  {AsCType(field.FieldType)} {namer.GetName(field)};\n");
            }
            csrc.Append($"}};\n");

            /* TODO: type the rgctx_data */
            if (UnityVersion.CompareTo("5.5.0") < 0)
            {
                csrc.Append(
                    $"struct {name}__Class {{\n" +
                    $"  struct Il2CppClass_0 _0;\n" +
                    $"  struct {name}__VTable *vtable;\n" +
                    $"  Il2CppRuntimeInterfaceOffsetPair *interfaceOffsets;\n" +
                    $"  struct {name}__StaticFields *static_fields;\n" +
                    $"  const Il2CppRGCTXData *rgctx_data;\n" +
                    $"  struct Il2CppClass_1 _1;\n" +
                    $"}};\n");
            }
            else
            {
                csrc.Append(
                    $"struct {name}__Class {{\n" +
                    $"  struct Il2CppClass_0 _0;\n" +
                    $"  Il2CppRuntimeInterfaceOffsetPair *interfaceOffsets;\n" +
                    $"  struct {name}__StaticFields *static_fields;\n" +
                    $"  const Il2CppRGCTXData *rgctx_data;\n" +
                    $"  struct Il2CppClass_1 _1;\n" +
                    $"  struct {name}__VTable vtable;\n" +
                    $"}};\n");
            }
        }
        // Generate the C structure for virtual function calls in a given type (the VTable)
        private CppComplexType GenerateVTableStruct(TypeInfo ti)
        {
            MethodBase[] vtable;
            if (ti.IsInterface)
            {
                /* Interface vtables are just all of the interface methods.
                 * You might have to type a local variable manually as an
                 * interface vtable during an interface call, but the result
                 * should display the correct method name (with a computed
                 * InterfaceOffset added).
                 */
                vtable = ti.DeclaredMethods.ToArray();
            }
            else
            {
                vtable = ti.GetVTable();
            }
            var name  = TypeNamer.GetName(ti);
            var namer = CreateNamespace().MakeNamer <int>((i) => vtable[i]?.Name?.ToCIdentifier() ?? "__unknown");

            // Il2Cpp switched to `VirtualInvokeData *vtable` in Unity 5.3.6.
            // Previous versions used `MethodInfo **vtable`.
            // TODO: Consider adding function types. This considerably increases the script size
            // but can significantly help with reverse-engineering certain binaries.
            var vtableStruct = types.Struct(name + "__VTable");

            if (UnityVersion.CompareTo("5.3.6") < 0)
            {
                for (int i = 0; i < vtable.Length; i++)
                {
                    types.AddField(vtableStruct, namer.GetName(i), "MethodInfo *");
                }
            }
            else
            {
                for (int i = 0; i < vtable.Length; i++)
                {
                    types.AddField(vtableStruct, namer.GetName(i), "VirtualInvokeData");
                }
            }
            return(vtableStruct);
        }
 public CppType AsCType(TypeInfo ti)
 {
     // IsArray case handled by TypeNamer.GetName
     if (ti.IsByRef || ti.IsPointer)
     {
         return(AsCType(ti.ElementType).AsPointer(WordSize));
     }
     if (ti.IsValueType)
     {
         if (ti.IsPrimitive && primitiveTypeMap.ContainsKey(ti.Name))
         {
             return(types.GetType(primitiveTypeMap[ti.Name]));
         }
         return(types.GetType(TypeNamer.GetName(ti)));
     }
     if (ti.IsEnum)
     {
         return(types.GetType(TypeNamer.GetName(ti)));
     }
     return(types.GetType(TypeNamer.GetName(ti) + " *"));
 }
        // Generate the overall Il2CppClass-shaped structure for the given type
        private (CppComplexType type, CppComplexType staticFields, CppComplexType vtable) GenerateTypeStruct(TypeInfo ti)
        {
            var name   = TypeNamer.GetName(ti);
            var vtable = GenerateVTableStruct(ti);

            var statics = types.Struct(name + "__StaticFields");
            var namer   = CreateNamespace().MakeNamer <FieldInfo>((field) => field.Name.ToCIdentifier());

            foreach (var field in ti.DeclaredFields)
            {
                if (field.IsLiteral || !field.IsStatic)
                {
                    continue;
                }
                statics.AddField(namer.GetName(field), AsCType(field.FieldType));
            }

            /* TODO: type the rgctx_data */
            var cls = types.Struct(name + "__Class");

            types.AddField(cls, "_0", "Il2CppClass_0");

            if (UnityVersion.CompareTo("5.5.0") < 0)
            {
                cls.AddField("vtable", vtable.AsPointer(types.WordSize));
                types.AddField(cls, "interfaceOffsets", "Il2CppRuntimeInterfaceOffsetPair *");
                cls.AddField("static_fields", statics.AsPointer(types.WordSize));
                types.AddField(cls, "rgctx_data", "Il2CppRGCTXData *", true);
                types.AddField(cls, "_1", "Il2CppClass_1");
            }
            else
            {
                types.AddField(cls, "interfaceOffsets", "Il2CppRuntimeInterfaceOffsetPair *");
                cls.AddField("static_fields", statics.AsPointer(types.WordSize));
                types.AddField(cls, "rgctx_data", "Il2CppRGCTXData *", true);
                types.AddField(cls, "_1", "Il2CppClass_1");
                cls.AddField("vtable", vtable);
            }
            return(cls, statics, vtable);
        }
        // We try decently hard to avoid creating clashing names, and also sanitize any invalid names.
        // You can customize how naming works by modifying this function.
        private void InitializeNaming()
        {
            TypeNamespace = CreateNamespace();
            TypeNamer     = TypeNamespace.MakeNamer <TypeInfo>((ti) => {
                if (ti.IsArray)
                {
                    return(TypeNamer.GetName(ti.ElementType) + "__Array");
                }
                var name = ti.Name.ToCIdentifier();
                name     = Regex.Replace(name, "__+", "_");
                // Work around a dumb IDA bug: enums can't be named the same as certain "built-in" types
                // like KeyCode, Position, ErrorType. This only applies to enums, not structs.
                if (ti.IsEnum)
                {
                    name += "__Enum";
                }
                return(name);
            });

            GlobalsNamespace = CreateNamespace();
            GlobalNamer      = GlobalsNamespace.MakeNamer <MethodBase>((method) => $"{TypeNamer.GetName(method.DeclaringType)}_{method.Name.ToCIdentifier()}");
        }
예제 #13
0
        // Generate the C structure for a value type, such as an enum or struct
        private void GenerateValueFieldStruct(StringBuilder csrc, TypeInfo ti)
        {
            string name = TypeNamer.GetName(ti);

            if (ti.IsEnum)
            {
                // Enums should be represented using enum syntax
                // They otherwise behave like value types
                csrc.Append($"enum {name} : {AsCType(ti.GetEnumUnderlyingType())} {{\n");
                foreach (var field in ti.DeclaredFields)
                {
                    if (field.Name != "value__")
                    {
                        csrc.Append($"  {EnumNamer.GetName(field)} = {field.DefaultValue},\n");
                    }
                }
                csrc.Append($"}};\n");

                // Use System.Enum base type as klass
                csrc.Append($"struct {name}__Boxed {{\n");
                GenerateObjectFields(csrc, ti.BaseType);
                csrc.Append($"  {AsCType(ti)} value;\n");
                csrc.Append($"}};\n");
            }
            else
            {
                // This structure is passed by value, so it doesn't include Il2CppObject fields.
                csrc.Append($"struct {name} {{\n");
                GenerateFieldList(csrc, CreateNamespace(), ti);
                csrc.Append($"}};\n");

                // Also generate the boxed form of the structure which includes the Il2CppObject header.
                csrc.Append($"struct {name}__Boxed {{\n");
                GenerateObjectFields(csrc, ti);
                csrc.Append($"  {AsCType(ti)} fields;\n");
                csrc.Append($"}};\n");
            }
        }
        // Generate the C structure for a reference type, such as a class or array
        private (CppComplexType objectOrArrayType, CppComplexType fieldsType) GenerateRefFieldStruct(TypeInfo ti)
        {
            var name = TypeNamer.GetName(ti);

            if (ti.IsArray)
            {
                var klassType   = ti.IsArray ? ti : ti.BaseType;
                var elementType = ti.IsArray ? AsCType(ti.ElementType) : types.GetType("void *");
                var type        = GenerateObjectStruct(name, klassType);
                types.AddField(type, "bounds", "Il2CppArrayBounds *");
                types.AddField(type, "max_length", "il2cpp_array_size_t");
                type.AddField("vector", elementType.AsArray(32));
                return(type, null);
            }

            /* Generate a list of all base classes starting from the root */
            List <TypeInfo> baseClasses = new List <TypeInfo>();

            for (var bti = ti; bti != null; bti = bti.BaseType)
            {
                baseClasses.Add(bti);
            }
            baseClasses.Reverse();

            var ns = CreateNamespace();

            if (InheritanceStyle == CppCompilerType.MSVC)
            {
                /* MSVC style: classes directly contain their base class as the first member.
                 * This causes all classes to be aligned to the alignment of their base class. */
                TypeInfo firstNonEmpty = null;
                foreach (var bti in baseClasses)
                {
                    if (bti.DeclaredFields.Any(field => !field.IsStatic && !field.IsLiteral))
                    {
                        firstNonEmpty = bti;
                        break;
                    }
                }
                if (firstNonEmpty == null)
                {
                    /* This struct is completely empty. Omit __Fields entirely. */
                    return(GenerateObjectStruct(name, ti), null);
                }
                else
                {
                    CppComplexType fieldType;
                    if (firstNonEmpty == ti)
                    {
                        /* All base classes are empty, so this class forms the root of a new hierarchy.
                         * We have to be a little careful: the root-most class needs to have its alignment
                         * set to that of Il2CppObject, but we can't explicitly include Il2CppObject
                         * in the hierarchy because we want to customize the type of the klass parameter. */
                        var align = model.Package.BinaryImage.Bits == 32 ? 4 : 8;
                        fieldType = types.Struct(name + "__Fields", align);
                        GenerateFieldList(fieldType, ns, ti);
                    }
                    else
                    {
                        /* Include the base class fields. Alignment will be dictated by the hierarchy. */
                        ns.ReserveName("_");
                        fieldType = types.Struct(name + "__Fields");
                        var baseFieldType = types[TypeNamer.GetName(ti.BaseType) + "__Fields"];
                        fieldType.AddField("_", baseFieldType);
                        GenerateFieldList(fieldType, ns, ti);
                    }

                    var type = GenerateObjectStruct(name, ti);
                    types.AddField(type, "fields", name + "__Fields");
                    return(type, fieldType);
                }
            }
            else if (InheritanceStyle == CppCompilerType.GCC)
            {
                /* GCC style: after the base class, all fields in the hierarchy are concatenated.
                 * This saves space (fields are "packed") but requires us to repeat fields from
                 * base classes. */
                ns.ReserveName("klass");
                ns.ReserveName("monitor");

                var type = GenerateObjectStruct(name, ti);
                foreach (var bti in baseClasses)
                {
                    GenerateFieldList(type, ns, bti);
                }
                return(type, null);
            }
            throw new InvalidOperationException("Could not generate ref field struct");
        }
예제 #15
0
        // Generate the C structure for a reference type, such as a class or array
        private void GenerateRefFieldStruct(StringBuilder csrc, TypeInfo ti)
        {
            var name = TypeNamer.GetName(ti);

            if (ti.IsArray || ti.FullName == "System.Array")
            {
                var klassType   = ti.IsArray ? ti : ti.BaseType;
                var elementType = ti.IsArray ? AsCType(ti.ElementType) : "void *";
                csrc.Append($"struct {name} {{\n");
                GenerateObjectFields(csrc, klassType);
                csrc.Append(
                    $"  struct Il2CppArrayBounds *bounds;\n" +
                    $"  il2cpp_array_size_t max_length;\n" +
                    $"  {elementType} vector[32];\n");
                csrc.Append($"}};\n");
                return;
            }

            /* Generate a list of all base classes starting from the root */
            List <TypeInfo> baseClasses = new List <TypeInfo>();

            for (var bti = ti; bti != null; bti = bti.BaseType)
            {
                baseClasses.Add(bti);
            }
            baseClasses.Reverse();

            var ns = CreateNamespace();

            if (InheritanceStyle == CppCompiler.Type.MSVC)
            {
                /* MSVC style: classes directly contain their base class as the first member.
                 * This causes all classes to be aligned to the alignment of their base class. */
                TypeInfo firstNonEmpty = null;
                foreach (var bti in baseClasses)
                {
                    if (bti.DeclaredFields.Any(field => !field.IsStatic && !field.IsLiteral))
                    {
                        firstNonEmpty = bti;
                        break;
                    }
                }
                if (firstNonEmpty == null)
                {
                    /* This struct is completely empty. Omit __Fields entirely. */
                    csrc.Append($"struct {name} {{\n");
                    GenerateObjectFields(csrc, ti);
                    csrc.Append($"}};\n");
                }
                else
                {
                    if (firstNonEmpty == ti)
                    {
                        /* All base classes are empty, so this class forms the root of a new hierarchy.
                         * We have to be a little careful: the rootmost class needs to have its alignment
                         * set to that of Il2CppObject, but we can't explicitly include Il2CppObject
                         * in the hierarchy because we want to customize the type of the klass parameter. */
                        var align = model.Package.BinaryImage.Bits == 32 ? 4 : 8;
                        csrc.Append($"struct __declspec(align({align})) {name}__Fields {{\n");
                        GenerateFieldList(csrc, ns, ti);
                        csrc.Append($"}};\n");
                    }
                    else
                    {
                        /* Include the base class fields. Alignment will be dictated by the hierarchy. */
                        ns.ReserveName("_");
                        csrc.Append($"struct {name}__Fields {{\n");
                        csrc.Append($"  struct {TypeNamer.GetName(ti.BaseType)}__Fields _;\n");
                        GenerateFieldList(csrc, ns, ti);
                        csrc.Append($"}};\n");
                    }
                    csrc.Append($"struct {name} {{\n");
                    GenerateObjectFields(csrc, ti);
                    csrc.Append($"  struct {name}__Fields fields;\n");
                    csrc.Append($"}};\n");
                }
            }
            else if (InheritanceStyle == CppCompiler.Type.GCC)
            {
                /* GCC style: after the base class, all fields in the hierarchy are concatenated.
                 * This saves space (fields are "packed") but requires us to repeat fields from
                 * base classes. */
                ns.ReserveName("klass");
                ns.ReserveName("monitor");

                csrc.Append($"struct {name} {{\n");
                GenerateObjectFields(csrc, ti);
                foreach (var bti in baseClasses)
                {
                    GenerateFieldList(csrc, ns, bti);
                }
                csrc.Append($"}};\n");
            }
        }
예제 #16
0
        public void Build(CodeWriter writer)
        {
            // Create namer
            TypeNamer namer = new TypeNamer();

            // System types with custom keywords
            namer.Aliases[Type.Module.TypeSystem.Boolean.FullName] = "bool";
            namer.Aliases[Type.Module.TypeSystem.Byte.FullName]    = "byte";
            namer.Aliases[Type.Module.TypeSystem.Char.FullName]    = "char";
            namer.Aliases[Type.Module.TypeSystem.Double.FullName]  = "double";
            namer.Aliases[Type.Module.TypeSystem.Int16.FullName]   = "short";
            namer.Aliases[Type.Module.TypeSystem.Int32.FullName]   = "int";
            namer.Aliases[Type.Module.TypeSystem.Int64.FullName]   = "long";
            namer.Aliases[Type.Module.TypeSystem.Object.FullName]  = "object";
            namer.Aliases[Type.Module.TypeSystem.SByte.FullName]   = "bool";
            namer.Aliases[Type.Module.TypeSystem.Single.FullName]  = "float";
            namer.Aliases[Type.Module.TypeSystem.String.FullName]  = "string";
            namer.Aliases[Type.Module.TypeSystem.UInt16.FullName]  = "ushort";
            namer.Aliases[Type.Module.TypeSystem.UInt32.FullName]  = "uint";
            namer.Aliases[Type.Module.TypeSystem.UInt64.FullName]  = "ulong";
            namer.Aliases[Type.Module.TypeSystem.Void.FullName]    = "void";

            // This type
            namer.Aliases[this.Type.FullName] = this.Type.Name;

            // Information
            writer.WriteLine($"// Assembly: {Type.Module.Assembly.Name}");
            writer.WriteLine($"// Module: {Type.Module.Name}");
            writer.WriteLine($"// Type: {Type.Name}");

            // Namespace
            writer.WriteLine($"namespace {Type.Namespace}");
            writer.WriteLine("{");
            writer.AddIndent();

            // Modifiers
            writer.WriteIndent();
            if (Type.IsPublic)
            {
                writer.Write("public ");
            }
            else if (Type.IsNotPublic)
            {
                writer.Write("private ");
            }
            if (Type.IsAbstract && Type.IsSealed)
            {
                writer.Write("static ");
            }
            else if (Type.IsAbstract)
            {
                writer.Write("abstract ");
            }
            else if (Type.IsSealed)
            {
                writer.Write("sealed ");
            }

            // Class name
            writer.Write($"class {Type.Name}");

            // Inherited types
            List <string> inherited = new List <string>();

            if (Type.BaseType != null && Type.BaseType.FullName != Type.Module.TypeSystem.Object.FullName)
            {
                inherited.Add(namer.GetName(Type.BaseType));
            }

            inherited.AddRange(from i in Type.Interfaces
                               select namer.GetName(i));

            if (inherited.Any())
            {
                writer.Write($" : {string.Join(", ", inherited)}");
            }

            // Opening brace - Type
            writer.WriteLine();
            writer.WriteLine("{");
            writer.AddIndent();

            // Write each method
            foreach (MethodDefinition method in Type.Methods)
            {
                MethodBuilder builder = new MethodBuilder(method, namer);
                builder.Build(writer);
                writer.WriteLine();
            }

            // Closing brace - Type
            writer.RemoveIndent();
            writer.WriteLine("}");

            // Closing brace - Namespace
            writer.RemoveIndent();
            writer.WriteLine("}");
        }
예제 #17
0
 // Generate the fields for the base class of all objects (Il2CppObject)
 // The two fields are inlined so that we can specialize the klass member for each type object
 private void GenerateObjectFields(StringBuilder csrc, TypeInfo ti)
 {
     csrc.Append(
         $"  struct {TypeNamer.GetName(ti)}__Class *klass;\n" +
         $"  struct MonitorData *monitor;\n");
 }