Browse Source

Port WholeProjectDecompiler

pull/1198/head
Siegfried Pammer 7 years ago
parent
commit
478ec4d632
  1. 88
      ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

88
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -29,8 +29,10 @@ using ICSharpCode.Decompiler.CSharp.Syntax; @@ -29,8 +29,10 @@ using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
using System.Threading;
using System.Reflection.PortableExecutable;
using System.Reflection.Metadata;
using static ICSharpCode.Decompiler.Metadata.DotNetCorePathFinderExtensions;
namespace ICSharpCode.Decompiler.CSharp
{
@ -74,15 +76,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -74,15 +76,15 @@ namespace ICSharpCode.Decompiler.CSharp
/// </remarks>
protected string targetDirectory;
public void DecompileProject(ModuleDefinition moduleDefinition, string targetDirectory, CancellationToken cancellationToken = default(CancellationToken))
public void DecompileProject(Metadata.PEFile moduleDefinition, string targetDirectory, CancellationToken cancellationToken = default(CancellationToken))
{
string projectFileName = Path.Combine(targetDirectory, CleanUpFileName(moduleDefinition.Assembly.Name.Name) + ".csproj");
string projectFileName = Path.Combine(targetDirectory, CleanUpFileName(moduleDefinition.Name) + ".csproj");
using (var writer = new StreamWriter(projectFileName)) {
DecompileProject(moduleDefinition, targetDirectory, writer, cancellationToken);
}
}
public void DecompileProject(ModuleDefinition moduleDefinition, string targetDirectory, TextWriter projectFileWriter, CancellationToken cancellationToken = default(CancellationToken))
public void DecompileProject(Metadata.PEFile moduleDefinition, string targetDirectory, TextWriter projectFileWriter, CancellationToken cancellationToken = default(CancellationToken))
{
if (string.IsNullOrEmpty(targetDirectory)) {
throw new InvalidOperationException("Must set TargetDirectory");
@ -101,7 +103,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -101,7 +103,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
#region WriteProjectFile
void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> files, ModuleDefinition module)
void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> files, Metadata.PEFile module)
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = GetPlatformName(module);
@ -126,11 +128,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -126,11 +128,11 @@ namespace ICSharpCode.Decompiler.CSharp
w.WriteValue(platformName);
w.WriteEndElement(); // </Platform>
switch (module.Kind) {
case ModuleKind.Windows:
switch (module.Reader.PEHeaders.PEHeader.Subsystem) {
case Subsystem.WindowsGui:
w.WriteElementString("OutputType", "WinExe");
break;
case ModuleKind.Console:
case Subsystem.WindowsCui:
w.WriteElementString("OutputType", "Exe");
break;
default:
@ -138,13 +140,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -138,13 +140,12 @@ namespace ICSharpCode.Decompiler.CSharp
break;
}
w.WriteElementString("AssemblyName", module.Assembly.Name.Name);
w.WriteElementString("AssemblyName", module.Name);
bool useTargetFrameworkAttribute = false;
LanguageTargets languageTargets = LanguageTargets.None;
var targetFrameworkAttribute = module.Assembly.CustomAttributes.FirstOrDefault(a => a.AttributeType.FullName == "System.Runtime.Versioning.TargetFrameworkAttribute");
if (targetFrameworkAttribute != null && targetFrameworkAttribute.ConstructorArguments.Any()) {
string frameworkName = (string)targetFrameworkAttribute.ConstructorArguments[0].Value;
string[] frameworkParts = frameworkName.Split(',');
string targetFramework = module.Reader.DetectTargetFrameworkId();
if (!string.IsNullOrEmpty(targetFramework)) {
string[] frameworkParts = targetFramework.Split(',');
string frameworkIdentifier = frameworkParts.FirstOrDefault(a => !a.StartsWith("Version=", StringComparison.OrdinalIgnoreCase) && !a.StartsWith("Profile=", StringComparison.OrdinalIgnoreCase));
if (frameworkIdentifier != null) {
w.WriteElementString("TargetFrameworkIdentifier", frameworkIdentifier);
@ -164,14 +165,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -164,14 +165,14 @@ namespace ICSharpCode.Decompiler.CSharp
w.WriteElementString("TargetFrameworkProfile", frameworkProfile.Substring("Profile=".Length));
}
if (!useTargetFrameworkAttribute) {
switch (module.Runtime) {
case TargetRuntime.Net_1_0:
switch (module.GetRuntime()) {
case Metadata.TargetRuntime.Net_1_0:
w.WriteElementString("TargetFrameworkVersion", "v1.0");
break;
case TargetRuntime.Net_1_1:
case Metadata.TargetRuntime.Net_1_1:
w.WriteElementString("TargetFrameworkVersion", "v1.1");
break;
case TargetRuntime.Net_2_0:
case Metadata.TargetRuntime.Net_2_0:
w.WriteElementString("TargetFrameworkVersion", "v2.0");
// TODO: Detect when .NET 3.0/3.5 is required
break;
@ -208,14 +209,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -208,14 +209,14 @@ namespace ICSharpCode.Decompiler.CSharp
w.WriteStartElement("ItemGroup"); // References
foreach (AssemblyNameReference r in module.AssemblyReferences) {
foreach (var r in module.AssemblyReferences) {
if (r.Name != "mscorlib") {
w.WriteStartElement("Reference");
w.WriteAttributeString("Include", r.Name);
var asm = module.AssemblyResolver.Resolve(r);
if (!IsGacAssembly(r, asm)) {
if (asm != null) {
w.WriteElementString("HintPath", asm.MainModule.FileName);
w.WriteElementString("HintPath", asm.FileName);
}
}
w.WriteEndElement();
@ -249,18 +250,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -249,18 +250,20 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
protected virtual bool IsGacAssembly(AssemblyNameReference r, AssemblyDefinition asm)
protected virtual bool IsGacAssembly(Metadata.IAssemblyReference r, Metadata.PEFile asm)
{
return false;
}
#endregion
#region WriteCodeFilesInProject
protected virtual bool IncludeTypeWhenDecompilingProject(TypeDefinition type)
protected virtual bool IncludeTypeWhenDecompilingProject(Metadata.PEFile module, TypeDefinitionHandle type)
{
if (type.Name == "<Module>" || CSharpDecompiler.MemberIsHidden(type, settings))
var metadata = module.GetMetadataReader();
var typeDef = metadata.GetTypeDefinition(type);
if (metadata.GetString(typeDef.Name) == "<Module>" || CSharpDecompiler.MemberIsHidden(module, type, settings))
return false;
if (type.Namespace == "XamlGeneratedNamespace" && type.Name == "GeneratedInternalTypeHelper")
if (metadata.GetString(typeDef.Namespace) == "XamlGeneratedNamespace" && metadata.GetString(typeDef.Name) == "GeneratedInternalTypeHelper")
return false;
return true;
}
@ -290,15 +293,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -290,15 +293,17 @@ namespace ICSharpCode.Decompiler.CSharp
return new Tuple<string, string>[] { Tuple.Create("Compile", assemblyInfo) };
}
IEnumerable<Tuple<string, string>> WriteCodeFilesInProject(ModuleDefinition module, CancellationToken cancellationToken)
IEnumerable<Tuple<string, string>> WriteCodeFilesInProject(Metadata.PEFile module, CancellationToken cancellationToken)
{
var files = module.Types.Where(IncludeTypeWhenDecompilingProject).GroupBy(
delegate (TypeDefinition type) {
string file = CleanUpFileName(type.Name) + ".cs";
if (string.IsNullOrEmpty(type.Namespace)) {
var metadata = module.GetMetadataReader();
var files = module.GetMetadataReader().TypeDefinitions.Where(td => IncludeTypeWhenDecompilingProject(module, td)).GroupBy(
delegate (TypeDefinitionHandle h) {
var type = metadata.GetTypeDefinition(h);
string file = CleanUpFileName(metadata.GetString(type.Name)) + ".cs";
if (string.IsNullOrEmpty(metadata.GetString(type.Namespace))) {
return file;
} else {
string dir = CleanUpFileName(type.Namespace);
string dir = CleanUpFileName(metadata.GetString(type.Namespace));
if (directories.Add(dir))
Directory.CreateDirectory(Path.Combine(targetDirectory, dir));
return Path.Combine(dir, file);
@ -311,7 +316,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -311,7 +316,7 @@ namespace ICSharpCode.Decompiler.CSharp
MaxDegreeOfParallelism = this.MaxDegreeOfParallelism,
CancellationToken = cancellationToken
},
delegate (IGrouping<string, TypeDefinition> file) {
delegate (IGrouping<string, TypeDefinitionHandle> file) {
using (StreamWriter w = new StreamWriter(Path.Combine(targetDirectory, file.Key))) {
CSharpDecompiler decompiler = CreateDecompiler(ts);
decompiler.CancellationToken = cancellationToken;
@ -324,10 +329,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -324,10 +329,10 @@ namespace ICSharpCode.Decompiler.CSharp
#endregion
#region WriteResourceFilesInProject
protected virtual IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(ModuleDefinition module)
protected virtual IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(Metadata.PEFile module)
{
foreach (EmbeddedResource r in module.Resources.OfType<EmbeddedResource>()) {
Stream stream = r.GetResourceStream();
foreach (var r in module.Resources.Where(r => r.ResourceType == Metadata.ResourceType.Embedded)) {
Stream stream = r.TryOpenStream();
stream.Position = 0;
IEnumerable<DictionaryEntry> entries;
@ -411,22 +416,23 @@ namespace ICSharpCode.Decompiler.CSharp @@ -411,22 +416,23 @@ namespace ICSharpCode.Decompiler.CSharp
return text;
}
public static string GetPlatformName(ModuleDefinition module)
public static string GetPlatformName(Metadata.PEFile module)
{
switch (module.Architecture) {
case TargetArchitecture.I386:
if ((module.Attributes & ModuleAttributes.Preferred32Bit) == ModuleAttributes.Preferred32Bit)
var headers = module.Reader.PEHeaders;
switch (headers.CoffHeader.Machine) {
case Machine.I386:
if ((headers.CorHeader.Flags & CorFlags.Prefers32Bit) != 0)
return "AnyCPU";
else if ((module.Attributes & ModuleAttributes.Required32Bit) == ModuleAttributes.Required32Bit)
else if ((headers.CorHeader.Flags & CorFlags.Requires32Bit) != 0)
return "x86";
else
return "AnyCPU";
case TargetArchitecture.AMD64:
case Machine.Amd64:
return "x64";
case TargetArchitecture.IA64:
case Machine.IA64:
return "Itanium";
default:
return module.Architecture.ToString();
return headers.CoffHeader.Machine.ToString();
}
}
}

Loading…
Cancel
Save