mirror of https://github.com/icsharpcode/ILSpy.git
9 changed files with 594 additions and 218 deletions
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2020 Daniel Grunwald
|
||||
//
|
||||
// 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 ICSharpCode.Decompiler.CSharp.ProjectDecompiler; |
||||
using NUnit.Framework; |
||||
|
||||
namespace ICSharpCode.Decompiler.Tests |
||||
{ |
||||
[TestFixture] |
||||
public sealed class TargetFrameworkTests |
||||
{ |
||||
[TestCase(-1)] |
||||
[TestCase(0)] |
||||
[TestCase(1)] |
||||
[TestCase(99)] |
||||
[TestCase(int.MinValue)] |
||||
public void VerifyThrowsForInvalidVersion(int invalidVersion) |
||||
{ |
||||
// Arrange - nothing
|
||||
|
||||
// Act
|
||||
void CreateInstance() => new TargetFramework(identifier: null, invalidVersion, profile: null); |
||||
|
||||
// Assert
|
||||
Assert.Throws<ArgumentException>(CreateInstance); |
||||
} |
||||
|
||||
[TestCase(100, "v1.0")] |
||||
[TestCase(102, "v1.0.2")] |
||||
[TestCase(130, "v1.3")] |
||||
[TestCase(145, "v1.4.5")] |
||||
[TestCase(1670, "v16.7")] |
||||
[TestCase(1800, "v18.0")] |
||||
public void VerifyVersion(int version, string expectedVersion) |
||||
{ |
||||
// Arrange - nothing
|
||||
|
||||
// Act
|
||||
var targetFramework = new TargetFramework(identifier: null, version, profile: null); |
||||
|
||||
// Assert
|
||||
Assert.AreEqual(version, targetFramework.VersionNumber); |
||||
Assert.AreEqual(expectedVersion, targetFramework.VersionString); |
||||
} |
||||
|
||||
[Test] |
||||
public void VerifyPortableLibrary() |
||||
{ |
||||
// Arrange
|
||||
const string identifier = ".NETPortable"; |
||||
|
||||
// Act
|
||||
var targetFramework = new TargetFramework(identifier, 100, profile: null); |
||||
|
||||
// Assert
|
||||
Assert.IsTrue(targetFramework.IsPortableClassLibrary); |
||||
Assert.AreEqual(identifier, targetFramework.Identifier); |
||||
} |
||||
|
||||
[Test] |
||||
[Pairwise] |
||||
public void VerifyIdentifierAndProfile( |
||||
[Values(null, "", ".NETFramework")] string identifier, |
||||
[Values(null, "", ".Client")] string profile) |
||||
{ |
||||
// Arrange - nothing
|
||||
|
||||
// Act
|
||||
var targetFramework = new TargetFramework(identifier, 100, profile); |
||||
|
||||
// Assert
|
||||
Assert.AreEqual(identifier, targetFramework.Identifier); |
||||
Assert.AreEqual(profile, targetFramework.Profile); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
// 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.Collections.Generic; |
||||
using System.IO; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler |
||||
{ |
||||
/// <summary>
|
||||
/// An interface for a service that creates and writes a project file structure
|
||||
/// for a specific module being decompiled.
|
||||
/// </summary>
|
||||
interface IProjectFileWriter |
||||
{ |
||||
/// <summary>
|
||||
/// Writes the content of a new project file for the specified <paramref name="module"/> being decompiled.
|
||||
/// </summary>
|
||||
/// <param name="target">The target to write to.</param>
|
||||
/// <param name="project">The information about the project being created.</param>
|
||||
/// <param name="files">A collection of source files to be included into the project, each item is a pair
|
||||
/// of the project entry type and the file path.</param>
|
||||
/// <param name="module">The module being decompiled.</param>
|
||||
void Write(TextWriter target, IProjectInfoProvider project, IEnumerable<(string itemType, string fileName)> files, PEFile module); |
||||
} |
||||
} |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2020 Daniel Grunwald
|
||||
//
|
||||
// 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 ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler |
||||
{ |
||||
/// <summary>
|
||||
/// An interface that provides common information for a project being decompiled to.
|
||||
/// </summary>
|
||||
interface IProjectInfoProvider |
||||
{ |
||||
/// <summary>
|
||||
/// Gets the assembly resolver active for the project.
|
||||
/// </summary>
|
||||
IAssemblyResolver AssemblyResolver { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the C# language version of the project.
|
||||
/// </summary>
|
||||
LanguageVersion LanguageVersion { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the unique ID of the project.
|
||||
/// </summary>
|
||||
Guid ProjectGuid { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the key file being used for strong name signing. Can be null if no file is available.
|
||||
/// </summary>
|
||||
string StrongNameKeyFile { get; } |
||||
} |
||||
} |
@ -0,0 +1,175 @@
@@ -0,0 +1,175 @@
|
||||
// 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; |
||||
using ICSharpCode.Decompiler.Solution; |
||||
|
||||
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler |
||||
{ |
||||
/// <summary>
|
||||
/// A <see cref="IProjectFileWriter"/> implementation that creates the projects in the default format.
|
||||
/// </summary>
|
||||
sealed class ProjectFileWriterDefault : IProjectFileWriter |
||||
{ |
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ProjectFileWriterDefault"/> class.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the <see cref="ProjectFileWriterDefault"/> class.</returns>
|
||||
public static IProjectFileWriter Create() => new ProjectFileWriterDefault(); |
||||
|
||||
/// <inheritdoc />
|
||||
public void Write( |
||||
TextWriter target, |
||||
IProjectInfoProvider project, |
||||
IEnumerable<(string itemType, string fileName)> files, |
||||
PEFile module) |
||||
{ |
||||
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003"; |
||||
string platformName = TargetServices.GetPlatformName(module); |
||||
var targetFramework = TargetServices.DetectTargetFramework(module); |
||||
|
||||
List<Guid> typeGuids = new List<Guid>(); |
||||
if (targetFramework.IsPortableClassLibrary) |
||||
typeGuids.Add(ProjectTypeGuids.PortableLibrary); |
||||
typeGuids.Add(ProjectTypeGuids.CSharpWindows); |
||||
|
||||
using (XmlTextWriter w = new XmlTextWriter(target)) { |
||||
w.Formatting = Formatting.Indented; |
||||
w.WriteStartDocument(); |
||||
w.WriteStartElement("Project", ns); |
||||
w.WriteAttributeString("ToolsVersion", "4.0"); |
||||
w.WriteAttributeString("DefaultTargets", "Build"); |
||||
|
||||
w.WriteStartElement("PropertyGroup"); |
||||
w.WriteElementString("ProjectGuid", project.ProjectGuid.ToString("B").ToUpperInvariant()); |
||||
w.WriteElementString("ProjectTypeGuids", string.Join(";", typeGuids.Select(g => g.ToString("B").ToUpperInvariant()))); |
||||
|
||||
w.WriteStartElement("Configuration"); |
||||
w.WriteAttributeString("Condition", " '$(Configuration)' == '' "); |
||||
w.WriteValue("Debug"); |
||||
w.WriteEndElement(); // </Configuration>
|
||||
|
||||
w.WriteStartElement("Platform"); |
||||
w.WriteAttributeString("Condition", " '$(Platform)' == '' "); |
||||
w.WriteValue(platformName); |
||||
w.WriteEndElement(); // </Platform>
|
||||
|
||||
if (module.Reader.PEHeaders.IsDll) { |
||||
w.WriteElementString("OutputType", "Library"); |
||||
} else { |
||||
switch (module.Reader.PEHeaders.PEHeader.Subsystem) { |
||||
case Subsystem.WindowsGui: |
||||
w.WriteElementString("OutputType", "WinExe"); |
||||
break; |
||||
case Subsystem.WindowsCui: |
||||
w.WriteElementString("OutputType", "Exe"); |
||||
break; |
||||
default: |
||||
w.WriteElementString("OutputType", "Library"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
w.WriteElementString("LangVersion", project.LanguageVersion.ToString().Replace("CSharp", "").Replace('_', '.')); |
||||
|
||||
w.WriteElementString("AssemblyName", module.Name); |
||||
if (targetFramework.Identifier != null) |
||||
w.WriteElementString("TargetFrameworkIdentifier", targetFramework.Identifier); |
||||
if (targetFramework.VersionString != null) |
||||
w.WriteElementString("TargetFrameworkVersion", targetFramework.VersionString); |
||||
if (targetFramework.Profile != null) |
||||
w.WriteElementString("TargetFrameworkProfile", targetFramework.Profile); |
||||
w.WriteElementString("WarningLevel", "4"); |
||||
w.WriteElementString("AllowUnsafeBlocks", "True"); |
||||
|
||||
if (project.StrongNameKeyFile != null) { |
||||
w.WriteElementString("SignAssembly", "True"); |
||||
w.WriteElementString("AssemblyOriginatorKeyFile", Path.GetFileName(project.StrongNameKeyFile)); |
||||
} |
||||
|
||||
w.WriteEndElement(); // </PropertyGroup>
|
||||
|
||||
w.WriteStartElement("PropertyGroup"); // platform-specific
|
||||
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' "); |
||||
w.WriteElementString("PlatformTarget", platformName); |
||||
if (targetFramework.VersionNumber > 400 && platformName == "AnyCPU" && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) == 0) { |
||||
w.WriteElementString("Prefer32Bit", "false"); |
||||
} |
||||
w.WriteEndElement(); // </PropertyGroup> (platform-specific)
|
||||
|
||||
w.WriteStartElement("PropertyGroup"); // Debug
|
||||
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' "); |
||||
w.WriteElementString("OutputPath", "bin\\Debug\\"); |
||||
w.WriteElementString("DebugSymbols", "true"); |
||||
w.WriteElementString("DebugType", "full"); |
||||
w.WriteElementString("Optimize", "false"); |
||||
w.WriteEndElement(); // </PropertyGroup> (Debug)
|
||||
|
||||
w.WriteStartElement("PropertyGroup"); // Release
|
||||
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' "); |
||||
w.WriteElementString("OutputPath", "bin\\Release\\"); |
||||
w.WriteElementString("DebugSymbols", "true"); |
||||
w.WriteElementString("DebugType", "pdbonly"); |
||||
w.WriteElementString("Optimize", "true"); |
||||
w.WriteEndElement(); // </PropertyGroup> (Release)
|
||||
|
||||
|
||||
w.WriteStartElement("ItemGroup"); // References
|
||||
foreach (var r in module.AssemblyReferences) { |
||||
if (r.Name != "mscorlib") { |
||||
w.WriteStartElement("Reference"); |
||||
w.WriteAttributeString("Include", r.Name); |
||||
var asm = project.AssemblyResolver.Resolve(r); |
||||
if (asm != null && !project.AssemblyResolver.IsGacAssembly(r)) { |
||||
w.WriteElementString("HintPath", asm.FileName); |
||||
} |
||||
w.WriteEndElement(); |
||||
} |
||||
} |
||||
w.WriteEndElement(); // </ItemGroup> (References)
|
||||
|
||||
foreach (IGrouping<string, string> gr in from f in files group f.fileName by f.itemType into g orderby g.Key select g) { |
||||
w.WriteStartElement("ItemGroup"); |
||||
foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) { |
||||
w.WriteStartElement(gr.Key); |
||||
w.WriteAttributeString("Include", file); |
||||
w.WriteEndElement(); |
||||
} |
||||
w.WriteEndElement(); |
||||
} |
||||
if (targetFramework.IsPortableClassLibrary) { |
||||
w.WriteStartElement("Import"); |
||||
w.WriteAttributeString("Project", "$(MSBuildExtensionsPath32)\\Microsoft\\Portable\\$(TargetFrameworkVersion)\\Microsoft.Portable.CSharp.targets"); |
||||
w.WriteEndElement(); |
||||
} else { |
||||
w.WriteStartElement("Import"); |
||||
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"); |
||||
w.WriteEndElement(); |
||||
} |
||||
|
||||
w.WriteEndDocument(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,94 @@
@@ -0,0 +1,94 @@
|
||||
// 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.Text; |
||||
|
||||
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler |
||||
{ |
||||
/// <summary>
|
||||
/// A class describing the target framework of a module.
|
||||
/// </summary>
|
||||
sealed class TargetFramework |
||||
{ |
||||
const string DotNetPortableIdentifier = ".NETPortable"; |
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TargetFramework"/> class.
|
||||
/// </summary>
|
||||
/// <param name="identifier">The framework identifier string. Can be null.</param>
|
||||
/// <param name="version">The framework version string. Must be greater than 100 (where 100 corresponds to v1.0).</param>
|
||||
/// <param name="profile">The framework profile. Can be null.</param>
|
||||
public TargetFramework(string identifier, int version, string profile) |
||||
{ |
||||
if (version < 100) { |
||||
throw new ArgumentException("The version number must be greater than or equal to 100", nameof(version)); |
||||
} |
||||
|
||||
Identifier = identifier; |
||||
VersionNumber = version; |
||||
VersionString = "v" + GetVersionString(version); |
||||
Profile = profile; |
||||
IsPortableClassLibrary = identifier == DotNetPortableIdentifier; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the target framework identifier. Can be null if not defined.
|
||||
/// </summary>
|
||||
public string Identifier { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the target framework version, e.g. "v4.5".
|
||||
/// </summary>
|
||||
public string VersionString { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the target framework version as integer (multiplied by 100), e.g. 450.
|
||||
/// </summary>
|
||||
public int VersionNumber { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the target framework profile. Can be null if not set or not available.
|
||||
/// </summary>
|
||||
public string Profile { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the target is a portable class library (PCL).
|
||||
/// </summary>
|
||||
public bool IsPortableClassLibrary { get; } |
||||
|
||||
static string GetVersionString(int version) |
||||
{ |
||||
int major = version / 100; |
||||
int minor = version % 100 / 10; |
||||
int patch = version % 10; |
||||
|
||||
var versionBuilder = new StringBuilder(8); |
||||
versionBuilder.Append(major); |
||||
versionBuilder.Append('.'); |
||||
versionBuilder.Append(minor); |
||||
|
||||
if (patch != 0) { |
||||
versionBuilder.Append('.'); |
||||
versionBuilder.Append(patch); |
||||
} |
||||
|
||||
return versionBuilder.ToString(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,129 @@
@@ -0,0 +1,129 @@
|
||||
// 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.Linq; |
||||
using System.Reflection.PortableExecutable; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler |
||||
{ |
||||
/// <summary>
|
||||
/// Helper services for determining the target framework and platform of a module.
|
||||
/// </summary>
|
||||
static class TargetServices |
||||
{ |
||||
const string VersionToken = "Version="; |
||||
const string ProfileToken = "Profile="; |
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="TargetFramework"/> for the specified <paramref name="module"/>.
|
||||
/// </summary>
|
||||
/// <param name="module">The module to get the target framework description for. Cannot be null.</param>
|
||||
/// <returns>A new instance of the <see cref="TargetFramework"/> class that describes the specified <paramref name="module"/>.
|
||||
/// </returns>
|
||||
public static TargetFramework DetectTargetFramework(PEFile module) |
||||
{ |
||||
if (module is null) { |
||||
throw new ArgumentNullException(nameof(module)); |
||||
} |
||||
|
||||
int versionNumber; |
||||
switch (module.GetRuntime()) { |
||||
case TargetRuntime.Net_1_0: |
||||
versionNumber = 100; |
||||
break; |
||||
|
||||
case TargetRuntime.Net_1_1: |
||||
versionNumber = 110; |
||||
break; |
||||
|
||||
case TargetRuntime.Net_2_0: |
||||
versionNumber = 200; |
||||
// TODO: Detect when .NET 3.0/3.5 is required
|
||||
break; |
||||
|
||||
default: |
||||
versionNumber = 400; |
||||
break; |
||||
} |
||||
|
||||
string targetFrameworkIdentifier = null; |
||||
string targetFrameworkProfile = null; |
||||
|
||||
string targetFramework = module.DetectTargetFrameworkId(); |
||||
if (!string.IsNullOrEmpty(targetFramework)) { |
||||
string[] frameworkParts = targetFramework.Split(','); |
||||
targetFrameworkIdentifier = frameworkParts.FirstOrDefault(a => !a.StartsWith(VersionToken, StringComparison.OrdinalIgnoreCase) && !a.StartsWith(ProfileToken, StringComparison.OrdinalIgnoreCase)); |
||||
string frameworkVersion = frameworkParts.FirstOrDefault(a => a.StartsWith(VersionToken, StringComparison.OrdinalIgnoreCase)); |
||||
|
||||
if (frameworkVersion != null) { |
||||
versionNumber = int.Parse(frameworkVersion.Substring(VersionToken.Length + 1).Replace(".", "")); |
||||
if (versionNumber < 100) versionNumber *= 10; |
||||
} |
||||
|
||||
string frameworkProfile = frameworkParts.FirstOrDefault(a => a.StartsWith(ProfileToken, StringComparison.OrdinalIgnoreCase)); |
||||
if (frameworkProfile != null) |
||||
targetFrameworkProfile = frameworkProfile.Substring(ProfileToken.Length); |
||||
} |
||||
|
||||
return new TargetFramework(targetFrameworkIdentifier, versionNumber, targetFrameworkProfile); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the string representation (name) of the target platform of the specified <paramref name="module"/>.
|
||||
/// </summary>
|
||||
/// <param name="module">The module to get the target framework description for. Cannot be null.</param>
|
||||
/// <returns>The platform name, e.g. "AnyCPU" or "x86".</returns>
|
||||
public static string GetPlatformName(PEFile module) |
||||
{ |
||||
if (module is null) { |
||||
throw new ArgumentNullException(nameof(module)); |
||||
} |
||||
|
||||
var headers = module.Reader.PEHeaders; |
||||
var architecture = headers.CoffHeader.Machine; |
||||
var characteristics = headers.CoffHeader.Characteristics; |
||||
var corflags = headers.CorHeader.Flags; |
||||
|
||||
switch (architecture) { |
||||
case Machine.I386: |
||||
if ((corflags & CorFlags.Prefers32Bit) != 0) |
||||
return "AnyCPU"; |
||||
|
||||
if ((corflags & CorFlags.Requires32Bit) != 0) |
||||
return "x86"; |
||||
|
||||
// According to ECMA-335, II.25.3.3.1 CorFlags.Requires32Bit and Characteristics.Bit32Machine must be in sync
|
||||
// for assemblies containing managed code. However, this is not true for C++/CLI assemblies.
|
||||
if ((corflags & CorFlags.ILOnly) == 0 && (characteristics & Characteristics.Bit32Machine) != 0) |
||||
return "x86"; |
||||
return "AnyCPU"; |
||||
|
||||
case Machine.Amd64: |
||||
return "x64"; |
||||
|
||||
case Machine.IA64: |
||||
return "Itanium"; |
||||
|
||||
default: |
||||
return architecture.ToString(); |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue