forked from icsharpcode/ILSpy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
141 lines (127 loc) · 6.13 KB
/
Program.cs
File metadata and controls
141 lines (127 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using McMaster.Extensions.CommandLineUtils;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Disassembler;
using System.Threading;
using System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.Console
{
class Program
{
static int Main(string[] args)
{
// https://github.com/natemcmaster/CommandLineUtils/
// Older cmd line clients (for options reference): https://github.com/aerror2/ILSpy-For-MacOSX and https://github.com/andreif/ILSpyMono
var app = new CommandLineApplication();
app.LongVersionGetter = () => "ilspycmd " + typeof(FullTypeName).Assembly.GetName().Version.ToString();
app.HelpOption("-h|--help");
var inputAssemblyFileName = app.Argument("Assembly filename name", "The assembly that is being decompiled. This argument is mandatory.");
var projectOption = app.Option("-p|--project", "Decompile assembly as compilable project. This requires the output directory option.", CommandOptionType.NoValue);
var outputOption = app.Option("-o|--outputdir <directory>", "The output directory, if omitted decompiler output is written to standard out.", CommandOptionType.SingleValue);
var typeOption = app.Option("-t|--type <type-name>", "The fully qualified name of the type to decompile.", CommandOptionType.SingleValue);
var listOption = app.Option("-l|--list <entity-type(s)>", "Lists all entities of the specified type(s). Valid types: c(lass), i(interface), s(truct), d(elegate), e(num)", CommandOptionType.MultipleValue);
var ilViewerOption = app.Option("-il|--ilcode", "Show IL code.", CommandOptionType.NoValue);
app.ExtendedHelpText = Environment.NewLine + "-o is valid with every option and required when using -p.";
app.ThrowOnUnexpectedArgument = false; // Ignore invalid arguments / options
app.OnExecute(() => {
// HACK : the CommandLineUtils package does not allow us to specify an argument as mandatory.
// Therefore we're implementing it as simple as possible.
if (inputAssemblyFileName.Value == null) {
app.ShowVersion();
app.ShowHint();
return -1;
}
if (!File.Exists(inputAssemblyFileName.Value)) {
app.Error.WriteLine($"ERROR: Input file not found.");
return -1;
}
if (!outputOption.HasValue() && projectOption.HasValue()) {
app.Error.WriteLine($"ERROR: Output directory not speciified.");
return -1;
}
if (outputOption.HasValue() && !Directory.Exists(outputOption.Value())) {
app.Error.WriteLine($"ERROR: Output directory '{outputOption.Value()}' does not exist.");
return -1;
}
if (projectOption.HasValue()) {
DecompileAsProject(inputAssemblyFileName.Value, outputOption.Value());
} else if (listOption.HasValue()) {
var values = listOption.Values.SelectMany(v => v.Split(',', ';')).ToArray();
HashSet<TypeKind> kinds = TypesParser.ParseSelection(values);
TextWriter output = System.Console.Out;
if (outputOption.HasValue()) {
string directory = outputOption.Value();
string outputName = Path.GetFileNameWithoutExtension(inputAssemblyFileName.Value);
output = File.CreateText(Path.Combine(directory, outputName) + ".list.txt");
}
ListContent(inputAssemblyFileName.Value, output, kinds);
} else if (ilViewerOption.HasValue()) {
TextWriter output = System.Console.Out;
if (outputOption.HasValue()) {
string directory = outputOption.Value();
string outputName = Path.GetFileNameWithoutExtension(inputAssemblyFileName.Value);
output = File.CreateText(Path.Combine(directory, outputName) + ".il");
}
ShowIL(inputAssemblyFileName.Value, output);
} else {
TextWriter output = System.Console.Out;
if (outputOption.HasValue()) {
string directory = outputOption.Value();
string outputName = Path.GetFileNameWithoutExtension(inputAssemblyFileName.Value);
output = File.CreateText(Path.Combine(directory, (typeOption.Value() ?? outputName) + ".decompiled.cs"));
}
Decompile(inputAssemblyFileName.Value, output, typeOption.Value());
}
return 0;
});
return app.Execute(args);
}
static CSharpDecompiler GetDecompiler(string assemblyFileName)
{
return new CSharpDecompiler(assemblyFileName, new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false });
}
static void ListContent(string assemblyFileName, TextWriter output, ISet<TypeKind> kinds)
{
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName);
foreach (var type in decompiler.TypeSystem.MainModule.TypeDefinitions) {
if (!kinds.Contains(type.Kind))
continue;
output.WriteLine($"{type.Kind} {type.FullName}");
}
}
static void ShowIL(string assemblyFileName, TextWriter output)
{
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName);
ITextOutput textOutput = new PlainTextOutput();
ReflectionDisassembler disassembler = new ReflectionDisassembler(textOutput, CancellationToken.None);
disassembler.DisassembleNamespace(decompiler.TypeSystem.MainModule.RootNamespace.Name,
decompiler.TypeSystem.MainModule.PEFile,
decompiler.TypeSystem.MainModule.TypeDefinitions.Select(x => (TypeDefinitionHandle)x.MetadataToken));
output.WriteLine($"// IL code: {decompiler.TypeSystem.MainModule.AssemblyName}");
output.WriteLine(textOutput.ToString());
output.Flush();
}
static void DecompileAsProject(string assemblyFileName, string outputDirectory)
{
WholeProjectDecompiler decompiler = new WholeProjectDecompiler();
var module = new PEFile(assemblyFileName);
decompiler.AssemblyResolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId());
decompiler.DecompileProject(module, outputDirectory);
}
static void Decompile(string assemblyFileName, TextWriter output, string typeName = null)
{
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName);
if (typeName == null) {
output.Write(decompiler.DecompileWholeModuleAsString());
} else {
var name = new FullTypeName(typeName);
output.Write(decompiler.DecompileTypeAsString(name));
}
}
}
}