/// <summary> /// Generate C class/struct. /// </summary> /// <param name="type">Class type</param> public CClass(Type type) { Structure = ""; if (type.IsAbstract) { return; } if (type.Name.Contains("<") || type.Name.Contains("`")) { Console.WriteLine($"Unsupported and/or generic type {type.Name}"); return; } Structure += $"typedef struct {type.Name}\n" + "{\n"; var methods = type.GetMethods().ToList(); methods.AddRange(type.GetMethods(BindingFlags.NonPublic)); var methodList = (from method in type.GetMethods() where type.BaseType != null from info in type.BaseType?.GetMethods() where method.GetBaseDefinition() == info select method).ToList(); /* * Collect methods */ foreach (var method in type.GetMethods()) { if (method.GetCustomAttribute <CMethodCoverAttribute>() != null) { return; } if (type.BaseType != null) { var none = true; foreach (var info in type.BaseType.GetMethods()) { if (method.GetBaseDefinition() == info) { none = false; } } if (none) { methodList.Add(method); } } else { methodList.Add(method); } } foreach (var method in methodList) { if (method.IsStatic) { continue; } try { var parts = method.ReturnType.Name.Split('.'); Structure += $"\t{CType.Deserialize(parts[parts.Length - 1])} (*{method.Name}{Visualizer.Additional(method, type)})("; foreach (var parameter in method.GetParameters()) { Structure += $"{CType.Deserialize(parameter.ParameterType)} {parameter.Name}"; } if (!method.IsStatic) { if (method.GetParameters().Length > 0) { Structure += ", "; } Structure += $"struct {type.Name}*me"; } Structure += ");\n\n"; } catch { Console.WriteLine("Failed"); } } var fields = type.GetFields().ToList(); fields.AddRange(type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)); foreach (var field in fields) { if (field.IsStatic) { continue; } try { var newName = field.Name.Where(t => t != '<' && t != '>') .Aggregate("", (current, t) => current + t); Structure += $"\t{CType.Deserialize(field.FieldType.Name)} {newName};\n"; } catch { Console.WriteLine("Failed"); } } Structure += "}" + $" {type.Name};\n\n"; }
/// <summary> /// Generate C function. /// </summary> public CFunction(MethodInfo function, Type cls, IReadOnlyList <string> genericTypes = null) { Declaration = ""; Definition = ""; if (function.GetCustomAttribute <CMethodCoverAttribute>() != null || function.DeclaringType.IsAbstract) { return; } if (function.GetCustomAttribute <CMethodCoverAttribute>() != null) { return; } var pars = function.GetParameters().Select(parameter => $"{CType.Deserialize(parameter.ParameterType)} {parameter.Name}").ToList(); if (function.IsGenericMethod && genericTypes != null) { var generics = function.GetGenericArguments(); for (var i = 0; i < generics.Length; i++) { var generic = generics[i]; for (var index = 0; index < function.GetParameters().Length; index++) { var parameter = function.GetParameters()[index]; if (parameter.ParameterType.Name == generic.Name) { pars[index] = $"{genericTypes[i]} {parameter.Name}"; } } } } var parts = function.ReturnType.Name.Split('.'); /* * DEC */ Declaration = $"extern {CType.Deserialize(parts[parts.Length - 1])} " + $"{cls.Name + function.Name}" + $"{Visualizer.Additional(function, cls)} ("; foreach (var par in pars) { Declaration += $"{par}"; if (pars[pars.Count - 1] != par) { Declaration += ", "; } } if (!function.IsStatic) { if (pars.Count > 0) { Declaration += ", "; } Declaration += $"struct {function.DeclaringType?.Name}*me"; } Declaration += ");\n\n"; /* * DEF */ if (function.DeclaringType != null) { Definition = $"{CType.Deserialize(parts[parts.Length - 1])} " + $"{cls.Name + function.Name}" + $"{Visualizer.Additional(function, cls)} ("; foreach (var par in pars) { Definition += $"{par}"; if (pars[pars.Count - 1] != par) { Definition += ", "; } } if (!function.IsStatic) { if (pars.Count > 0) { Definition += ", "; } Definition += $"struct {function.DeclaringType?.Name}*me"; } Definition += ")\n{\n"; } Visualizer.FirstPass = false; foreach (var line in Visualizer.BuildBody(function)) { Definition += line; } Definition += "}\n\n"; }
/// <summary> /// Build C code body. /// </summary> /// <param name="body"></param> /// <returns></returns> public static IEnumerable <string> BuildBody(MethodBase body) { /* * Get methods from Mono.cil */ var assembly = AssemblyDefinition.ReadAssembly(body.DeclaringType?.Assembly.Location); var toInspect = assembly.MainModule .GetTypes() .SelectMany(t => t.Methods.Select(m => new { t, m })) .Where(x => x.m.HasBody).ToArray(); if (!toInspect.Any()) { //Failed to find any methods. yield return("return 0"); yield break; } /* * Find the correct method. */ var declared = false; var method = (MethodDefinition)null; foreach (var me in toInspect) { if (body.DeclaringType != null && (me.m.Name != body.Name || body.GetParameters().Length != me.m.Parameters.Count || me.t.FullName != body.DeclaringType.FullName)) { continue; } var hold = true; for (var index = 0; index < body.GetParameters().Length; index++) { var parameter = body.GetParameters()[index]; if (parameter.ParameterType.FullName == me.m.Parameters[index].ParameterType.FullName) { continue; } hold = false; break; } if (!hold) { continue; } declared = true; method = me.m; } if (!declared) { yield break; } for (var index = 0; index < method.Body.Instructions.Count; index++) { var instruction = method.Body.Instructions[index]; //For debugging Console.WriteLine($"[{instruction.Offset}][{index}] {instruction.OpCode} \"{instruction.Operand}\""); } /* * Collect the method's variables. */ Variables.Clear(); foreach (var variable in method.Body.Variables) { yield return($"\t{CType.Deserialize(variable)} var{variable.Index} = 0;\n"); Variables.Add(new ScopeVariable { Type = CType.Deserialize(variable.VariableType.Name), Value = "0" }); } /* * Build Scope Instructions from Instructors */ var instr = new List <ScopeInstruction>(); uint i = 0; foreach (var instruction in method.Body.Instructions) { var inst = new ScopeInstruction { Name = instruction.OpCode.Name, Offset = (uint)instruction.Offset, Operand = instruction.Operand != null?instruction.Operand.ToString() : "", Index = i, Template = instruction }; instr.Add(inst); i++; } //For label naming. FuncCount++; //Build scope. foreach (var str in BuildScope(new List <ScopeVariable>(), instr, body, 1, 0)) { yield return(str); } }
/// <summary> /// Generate C constructor. /// </summary> /// <param name="function">Method</param> /// <param name="cls">Class</param> public CConstructor(MethodBase function, Type cls) { Declaration = ""; Definition = ""; var pars = function.GetParameters().Select(parameter => $"{CType.Deserialize(parameter.ParameterType)} {parameter.Name}").ToList(); if (function.DeclaringType == null) { return; } Definition += $"struct {function.DeclaringType.Name}* new{function.DeclaringType.Name}{Visualizer.Additional(function, cls)} ("; foreach (var par in pars) { Definition += $"{par}"; if (pars[pars.Count - 1] != par) { Definition += ", "; } } Definition += ")\n{\n\t" + $"{function.DeclaringType.Name}* me = " + $"malloc(sizeof({function.DeclaringType.Name}));"; if (function.DeclaringType != null) { foreach (var method in function.DeclaringType.GetMethods()) { if (method.IsConstructor || method.IsStatic) { continue; } Definition += $"\n\tme->{method.Name}{Visualizer.Additional(method, cls)} = &{function.DeclaringType.Name + method.Name}{Visualizer.Additional(method, cls)};"; } Definition += "\n"; Visualizer.FirstPass = false; foreach (var line in Visualizer.BuildBody(function)) { Definition += line; } } Definition += "\n\treturn me;"; Definition += "\n}\n\n"; Declaration += $"struct {function.DeclaringType.Name}* new{function.DeclaringType.Name}{Visualizer.Additional(function, cls)} ("; foreach (var par in pars) { Declaration += $"{par}"; if (pars[pars.Count - 1] != par) { Declaration += ", "; } } Declaration += ");\n\n"; }