CLI: Implement --select-outpus option (#128)

This commit is contained in:
Katy Coe
2021-01-26 12:05:53 +01:00
parent 1b1ae55d58
commit 973d88913a

View File

@@ -25,6 +25,13 @@ namespace Il2CppInspector.CLI
{
public class App
{
// Default file paths for output modules
private const string CsOutDefault = "types.cs";
private const string PyOutDefault = "il2cpp.py";
private const string CppOutDefault = "cpp";
private const string JsonOutDefault = "metadata.json";
private const string DllOutDefault = "dll";
private class Options
{
[Option('i', "bin", Required = false, Separator = ',', HelpText = "IL2CPP binary, APK, AAB, XAPK, IPA, Zip or Linux process map text input file(s) (single file or comma-separated list for split APKs)", Default = new[] { "libil2cpp.so" })]
@@ -36,19 +43,22 @@ namespace Il2CppInspector.CLI
[Option("image-base", Required = false, HelpText = "For ELF memory dumps, the image base address in hex (ignored for standard ELF files and other file formats)")]
public string ElfImageBaseString { get; set; }
[Option('c', "cs-out", Required = false, HelpText = "C# output file (when using single-file layout) or path (when using per namespace, assembly or class layout)", Default = "types.cs")]
[Option("select-outputs", Required = false, HelpText = "Only generate outputs specified on the command line (use --cs-out, --py-out, --cpp-out, --json-out, --dll-out to select outputs). If not specified, all outputs are generated")]
public bool SpecifiedOutputsOnly { get; set; }
[Option('c', "cs-out", Required = false, HelpText = "(Default: " + CsOutDefault + ") C# output file (when using single-file layout) or path (when using per namespace, assembly or class layout)")]
public string CSharpOutPath { get; set; }
[Option('p', "py-out", Required = false, HelpText = "Python script output file", Default = "il2cpp.py")]
[Option('p', "py-out", Required = false, HelpText = "(Default: " + PyOutDefault + ") Python script output file")]
public string PythonOutFile { get; set; }
[Option('h', "cpp-out", Required = false, HelpText = "C++ scaffolding / DLL injection project output path", Default = "cpp")]
[Option('h', "cpp-out", Required = false, HelpText = "(Default: " + CppOutDefault + ") C++ scaffolding / DLL injection project output path")]
public string CppOutPath { get; set; }
[Option('o', "json-out", Required = false, HelpText = "JSON metadata output file", Default = "metadata.json")]
[Option('o', "json-out", Required = false, HelpText = "(Default: " + JsonOutDefault + ") JSON metadata output file")]
public string JsonOutPath { get; set; }
[Option('d', "dll-out", Required = false, HelpText = ".NET assembly shim DLLs output path", Default = "dll")]
[Option('d', "dll-out", Required = false, HelpText = "(Default: " + DllOutDefault + ") .NET assembly shim DLLs output path")]
public string DllOutPath { get; set; }
[Option("metadata-out", Required = false, HelpText = "IL2CPP metadata file output (for extracted or decrypted metadata; ignored otherwise)")]
@@ -178,13 +188,25 @@ namespace Il2CppInspector.CLI
}
catch (Exception ex) when (ex is InvalidOperationException || ex is DirectoryNotFoundException) {
Console.Error.WriteLine(ex.Message);
Environment.Exit(1);
return 1;
}
// Check plugin options are valid
if (!PluginOptions.ParsePluginOptions(options.PluginOptions, PluginOptions.GetPluginOptionTypes()))
return 1;
// Make sure at least one output is specified if the user has restricted outputs
if (options.SpecifiedOutputsOnly
&& options.CSharpOutPath == null
&& options.PythonOutFile == null
&& options.CppOutPath == null
&& options.JsonOutPath == null
&& options.DllOutPath == null) {
Console.Error.WriteLine("At least one output must be specified when using --select-outputs.");
Console.Error.WriteLine("Use --cs-out, --py-out, --cpp-out, --json-out and/or --dll-out, or omit --select-outputs to generate all output types");
return 1;
}
// Check script target is valid
if (!PythonScript.GetAvailableTargets().Contains(options.ScriptTarget)) {
Console.Error.WriteLine($"Script target {options.ScriptTarget} is invalid.");
@@ -345,22 +367,44 @@ namespace Il2CppInspector.CLI
}
}
// Determine which outputs to generate
var GenerateCS = !string.IsNullOrEmpty(options.CSharpOutPath);
var GeneratePython = !string.IsNullOrEmpty(options.PythonOutFile);
var GenerateCpp = !string.IsNullOrEmpty(options.CppOutPath) || GeneratePython;
var GenerateJSON = !string.IsNullOrEmpty(options.JsonOutPath) || GeneratePython;
var GenerateDLL = !string.IsNullOrEmpty(options.DllOutPath);
if (!options.SpecifiedOutputsOnly)
GenerateCS = GeneratePython = GenerateCpp = GenerateJSON = GenerateDLL = true;
// Set defaults for outputs where the user hasn't specified a path
options.CSharpOutPath = options.CSharpOutPath ?? CsOutDefault;
options.PythonOutFile = options.PythonOutFile ?? PyOutDefault;
options.CppOutPath = options.CppOutPath ?? CppOutDefault;
options.JsonOutPath = options.JsonOutPath ?? JsonOutDefault;
options.DllOutPath = options.DllOutPath ?? DllOutDefault;
var NeedAppModel = GeneratePython | GenerateJSON | GenerateCpp;
// Write output files for each binary
int imageIndex = 0;
foreach (var il2cpp in il2cppInspectors) {
Console.WriteLine($"Processing image {imageIndex} - {il2cpp.BinaryImage.Arch} / {il2cpp.BinaryImage.Bits}-bit");
// Create model
// Create type model
TypeModel model;
using (new Benchmark("Create .NET type model"))
model = new TypeModel(il2cpp);
AppModel appModel;
// Create application model only if needed
AppModel appModel = null;
if (NeedAppModel)
using (new Benchmark("Create C++ application model")) {
appModel = new AppModel(model, makeDefaultBuild: false).Build(options.UnityVersion, options.CppCompiler);
}
// C# signatures output
if (GenerateCS)
using (new Benchmark("Generate C# code")) {
var writer = new CSharpCodeStubs(model) {
ExcludedNamespaces = options.ExcludedNamespaces.ToList(),
@@ -410,16 +454,19 @@ namespace Il2CppInspector.CLI
}
// C++ output
if (GenerateCpp)
using (new Benchmark("Generate C++ code")) {
new CppScaffolding(appModel).Write(getOutputPath(options.CppOutPath, "", imageIndex));
}
// JSON output
if (GenerateJSON)
using (new Benchmark("Generate JSON metadata")) {
new JSONMetadata(appModel).Write(getOutputPath(options.JsonOutPath, "json", imageIndex));
}
// Python script output
if (GeneratePython)
using (new Benchmark($"Generate {options.ScriptTarget} Python script")) {
new PythonScript(appModel).WriteScriptToFile(
getOutputPath(options.PythonOutFile, "py", imageIndex),
@@ -429,6 +476,7 @@ namespace Il2CppInspector.CLI
}
// DLL output
if (GenerateDLL)
using (new Benchmark("Generate .NET assembly shim DLLs"))
new AssemblyShims(model) {
SuppressMetadata = options.SuppressDllMetadata