mirror of https://github.com/icsharpcode/ILSpy.git
6 changed files with 303 additions and 10 deletions
@ -0,0 +1,212 @@
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2020 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Reflection.PortableExecutable; |
||||
using System.Xml; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler |
||||
{ |
||||
/// <summary>
|
||||
/// A <see cref="IProjectFileWriter"/> implementation that creates the projects in the SDK style format.
|
||||
/// </summary>
|
||||
sealed class ProjectFileWriterSdkStyle : IProjectFileWriter |
||||
{ |
||||
const string AspNetCorePrefix = "Microsoft.AspNetCore"; |
||||
const string PresentationFrameworkName = "PresentationFramework"; |
||||
const string WindowsFormsName = "System.Windows.Forms"; |
||||
const string TrueString = "True"; |
||||
const string FalseString = "False"; |
||||
const string AnyCpuString = "AnyCPU"; |
||||
|
||||
static readonly HashSet<string> ImplicitReferences = new HashSet<string> { |
||||
"mscorlib", |
||||
"netstandard", |
||||
"PresentationFramework", |
||||
"System", |
||||
"System.Diagnostics.Debug", |
||||
"System.Diagnostics.Tools", |
||||
"System.Drawing", |
||||
"System.Runtime", |
||||
"System.Runtime.Extensions", |
||||
"System.Windows.Forms", |
||||
"System.Xaml", |
||||
}; |
||||
|
||||
enum ProjectType { Default, WinForms, Wpf, Web } |
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ProjectFileWriterSdkStyle"/> class.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the <see cref="ProjectFileWriterSdkStyle"/> class.</returns>
|
||||
public static IProjectFileWriter Create() => new ProjectFileWriterSdkStyle(); |
||||
|
||||
/// <inheritdoc />
|
||||
public void Write( |
||||
TextWriter target, |
||||
IProjectInfoProvider project, |
||||
IEnumerable<(string itemType, string fileName)> files, |
||||
PEFile module) |
||||
{ |
||||
using (XmlTextWriter xmlWriter = new XmlTextWriter(target)) { |
||||
xmlWriter.Formatting = Formatting.Indented; |
||||
Write(xmlWriter, project, module); |
||||
} |
||||
} |
||||
|
||||
static void Write(XmlTextWriter xml, IProjectInfoProvider project, PEFile module) |
||||
{ |
||||
xml.WriteStartElement("Project"); |
||||
|
||||
var projectType = GetProjectType(module); |
||||
xml.WriteAttributeString("Sdk", GetSdkString(projectType)); |
||||
|
||||
PlaceIntoTag("PropertyGroup", xml, () => WriteAssemblyInfo(xml, module, projectType)); |
||||
PlaceIntoTag("PropertyGroup", xml, () => WriteProjectInfo(xml, project)); |
||||
PlaceIntoTag("ItemGroup", xml, () => WriteReferences(xml, module, project)); |
||||
|
||||
xml.WriteEndElement(); |
||||
} |
||||
|
||||
static void PlaceIntoTag(string tagName, XmlTextWriter xml, Action content) |
||||
{ |
||||
xml.WriteStartElement(tagName); |
||||
try { |
||||
content(); |
||||
} finally { |
||||
xml.WriteEndElement(); |
||||
} |
||||
} |
||||
|
||||
static void WriteAssemblyInfo(XmlTextWriter xml, PEFile module, ProjectType projectType) |
||||
{ |
||||
xml.WriteElementString("AssemblyName", module.Name); |
||||
|
||||
// Since we create AssemblyInfo.cs manually, we need to disable the auto-generation
|
||||
xml.WriteElementString("GenerateAssemblyInfo", FalseString); |
||||
|
||||
// 'Library' is default, so only need to specify output type for executables
|
||||
if (!module.Reader.PEHeaders.IsDll) { |
||||
WriteOutputType(xml, module.Reader.PEHeaders.PEHeader.Subsystem); |
||||
} |
||||
|
||||
WriteDesktopExtensions(xml, projectType); |
||||
|
||||
string platformName = TargetServices.GetPlatformName(module); |
||||
var targetFramework = TargetServices.DetectTargetFramework(module); |
||||
|
||||
if (targetFramework.Moniker == null) { |
||||
throw new NotSupportedException($"Cannot decompile this assembly to a SDK style project. Use default project format instead."); |
||||
} |
||||
|
||||
xml.WriteElementString("TargetFramework", targetFramework.Moniker); |
||||
|
||||
// 'AnyCPU' is default, so only need to specify platform if it differs
|
||||
if (platformName != AnyCpuString) { |
||||
xml.WriteElementString("PlatformTarget", platformName); |
||||
} |
||||
|
||||
if (platformName == AnyCpuString && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) != 0) { |
||||
xml.WriteElementString("Prefer32Bit", TrueString); |
||||
} |
||||
} |
||||
|
||||
static void WriteOutputType(XmlTextWriter xml, Subsystem moduleSubsystem) |
||||
{ |
||||
switch (moduleSubsystem) { |
||||
case Subsystem.WindowsGui: |
||||
xml.WriteElementString("OutputType", "WinExe"); |
||||
break; |
||||
case Subsystem.WindowsCui: |
||||
xml.WriteElementString("OutputType", "Exe"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void WriteDesktopExtensions(XmlTextWriter xml, ProjectType projectType) |
||||
{ |
||||
if (projectType == ProjectType.Wpf) { |
||||
xml.WriteElementString("UseWPF", TrueString); |
||||
} else if (projectType == ProjectType.WinForms) { |
||||
xml.WriteElementString("UseWindowsForms", TrueString); |
||||
} |
||||
} |
||||
|
||||
static void WriteProjectInfo(XmlTextWriter xml, IProjectInfoProvider project) |
||||
{ |
||||
xml.WriteElementString("LangVersion", project.LanguageVersion.ToString().Replace("CSharp", "").Replace('_', '.')); |
||||
xml.WriteElementString("AllowUnsafeBlocks", TrueString); |
||||
|
||||
if (project.StrongNameKeyFile != null) { |
||||
xml.WriteElementString("SignAssembly", TrueString); |
||||
xml.WriteElementString("AssemblyOriginatorKeyFile", Path.GetFileName(project.StrongNameKeyFile)); |
||||
} |
||||
} |
||||
|
||||
static void WriteReferences(XmlTextWriter xml, PEFile module, IProjectInfoProvider project) |
||||
{ |
||||
foreach (var reference in module.AssemblyReferences.Where(r => !ImplicitReferences.Contains(r.Name))) { |
||||
xml.WriteStartElement("Reference"); |
||||
xml.WriteAttributeString("Include", reference.Name); |
||||
|
||||
var asembly = project.AssemblyResolver.Resolve(reference); |
||||
if (asembly != null) { |
||||
xml.WriteElementString("HintPath", asembly.FileName); |
||||
} |
||||
|
||||
xml.WriteEndElement(); |
||||
} |
||||
} |
||||
|
||||
static string GetSdkString(ProjectType projectType) |
||||
{ |
||||
switch (projectType) { |
||||
case ProjectType.WinForms: |
||||
case ProjectType.Wpf: |
||||
return "Microsoft.NET.Sdk.WindowsDesktop"; |
||||
case ProjectType.Web: |
||||
return "Microsoft.NET.Sdk.Web"; |
||||
default: |
||||
return "Microsoft.NET.Sdk"; |
||||
} |
||||
} |
||||
|
||||
static ProjectType GetProjectType(PEFile module) |
||||
{ |
||||
foreach (var referenceName in module.AssemblyReferences.Select(r => r.Name)) { |
||||
if (referenceName.StartsWith(AspNetCorePrefix, StringComparison.Ordinal)) { |
||||
return ProjectType.Web; |
||||
} |
||||
|
||||
if (referenceName == PresentationFrameworkName) { |
||||
return ProjectType.Wpf; |
||||
} |
||||
|
||||
if (referenceName == WindowsFormsName) { |
||||
return ProjectType.WinForms; |
||||
} |
||||
} |
||||
|
||||
return ProjectType.Default; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue