mirror of https://github.com/icsharpcode/ILSpy.git
9 changed files with 594 additions and 218 deletions
@ -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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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