|
|
|
@ -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(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|