mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
8.0 KiB
237 lines
8.0 KiB
// Copyright (c) 2018 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.Reflection.Metadata; |
|
using System.Reflection.PortableExecutable; |
|
using System.Text.RegularExpressions; |
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
namespace ICSharpCode.Decompiler.Metadata |
|
{ |
|
public static class DotNetCorePathFinderExtensions |
|
{ |
|
static readonly string PathPattern = |
|
@"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<type>.NETFramework)[/\\]v(?<version>[^/\\]+)[/\\])" + |
|
@"|((?<type>Microsoft\.NET)[/\\]assembly[/\\]GAC_(MSIL|32|64)[/\\])" + |
|
@"|((?<type>Microsoft\.NET)[/\\]Framework(64)?[/\\](?<version>[^/\\]+)[/\\])" + |
|
@"|(NuGetFallbackFolder[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\]ref[/\\])" + |
|
@"|(shared[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\])" + |
|
@"|(packs[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)\\ref([/\\].*)?[/\\])"; |
|
|
|
static readonly string RefPathPattern = |
|
@"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<type>.NETFramework)[/\\]v(?<version>[^/\\]+)[/\\])" + |
|
@"|(NuGetFallbackFolder[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\]ref[/\\])" + |
|
@"|(packs[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)\\ref([/\\].*)?[/\\])"; |
|
|
|
public static string DetectTargetFrameworkId(this PEFile assembly) |
|
{ |
|
return DetectTargetFrameworkId(assembly.Metadata, assembly.FileName); |
|
} |
|
|
|
public static string DetectTargetFrameworkId(this MetadataReader metadata, string assemblyPath = null) |
|
{ |
|
if (metadata == null) |
|
throw new ArgumentNullException(nameof(metadata)); |
|
|
|
const string TargetFrameworkAttributeName = "System.Runtime.Versioning.TargetFrameworkAttribute"; |
|
|
|
foreach (var h in metadata.GetCustomAttributes(Handle.AssemblyDefinition)) |
|
{ |
|
try |
|
{ |
|
var attribute = metadata.GetCustomAttribute(h); |
|
if (attribute.GetAttributeType(metadata).GetFullTypeName(metadata).ToString() != TargetFrameworkAttributeName) |
|
continue; |
|
var blobReader = metadata.GetBlobReader(attribute.Value); |
|
if (blobReader.ReadUInt16() == 0x0001) |
|
{ |
|
return blobReader.ReadSerializedString()?.Replace(" ", ""); |
|
} |
|
} |
|
catch (BadImageFormatException) |
|
{ |
|
// ignore malformed attributes |
|
} |
|
} |
|
|
|
if (metadata.IsAssembly) |
|
{ |
|
AssemblyDefinition assemblyDefinition = metadata.GetAssemblyDefinition(); |
|
switch (metadata.GetString(assemblyDefinition.Name)) |
|
{ |
|
case "mscorlib": |
|
return $".NETFramework,Version=v{assemblyDefinition.Version.ToString(2)}"; |
|
case "netstandard": |
|
return $".NETStandard,Version=v{assemblyDefinition.Version.ToString(2)}"; |
|
} |
|
} |
|
|
|
foreach (var h in metadata.AssemblyReferences) |
|
{ |
|
try |
|
{ |
|
var r = metadata.GetAssemblyReference(h); |
|
if (r.PublicKeyOrToken.IsNil) |
|
continue; |
|
string version; |
|
switch (metadata.GetString(r.Name)) |
|
{ |
|
case "netstandard": |
|
version = r.Version.ToString(2); |
|
return $".NETStandard,Version=v{version}"; |
|
case "System.Runtime": |
|
// System.Runtime.dll uses the following scheme: |
|
// 4.2.0 => .NET Core 2.0 |
|
// 4.2.1 => .NET Core 2.1 / 3.0 |
|
// 4.2.2 => .NET Core 3.1 |
|
if (r.Version >= new Version(4, 2, 0)) |
|
{ |
|
version = "2.0"; |
|
if (r.Version >= new Version(4, 2, 1)) |
|
{ |
|
version = "3.0"; |
|
} |
|
if (r.Version >= new Version(4, 2, 2)) |
|
{ |
|
version = "3.1"; |
|
} |
|
return $".NETCoreApp,Version=v{version}"; |
|
} |
|
else |
|
{ |
|
continue; |
|
} |
|
case "mscorlib": |
|
version = r.Version.ToString(2); |
|
return $".NETFramework,Version=v{version}"; |
|
} |
|
} |
|
catch (BadImageFormatException) |
|
{ |
|
// ignore malformed references |
|
} |
|
} |
|
|
|
// Optionally try to detect target version through assembly path as a fallback (use case: reference assemblies) |
|
if (assemblyPath != null) |
|
{ |
|
/* |
|
* Detected path patterns (examples): |
|
* |
|
* - .NETFramework -> C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll |
|
* - .NETCore -> C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Console.dll |
|
* - .NETStandard -> C:\Program Files\dotnet\sdk\NuGetFallbackFolder\netstandard.library\2.0.3\build\netstandard2.0\ref\netstandard.dll |
|
*/ |
|
var pathMatch = Regex.Match(assemblyPath, PathPattern, |
|
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture); |
|
string version; |
|
if (pathMatch.Success) |
|
{ |
|
var type = pathMatch.Groups["type"].Value; |
|
version = pathMatch.Groups["version"].Value; |
|
if (string.IsNullOrEmpty(version)) |
|
version = metadata.MetadataVersion; |
|
if (string.IsNullOrEmpty(version)) |
|
version = "4.0"; |
|
version = version.TrimStart('v'); |
|
|
|
if (type == "Microsoft.NET" || type == ".NETFramework") |
|
{ |
|
return $".NETFramework,Version=v{version.Substring(0, Math.Min(3, version.Length))}"; |
|
} |
|
else if (type.IndexOf("netcore", StringComparison.OrdinalIgnoreCase) >= 0) |
|
{ |
|
return $".NETCoreApp,Version=v{version}"; |
|
} |
|
else if (type.IndexOf("netstandard", StringComparison.OrdinalIgnoreCase) >= 0) |
|
{ |
|
return $".NETStandard,Version=v{version}"; |
|
} |
|
} |
|
else |
|
{ |
|
version = metadata.MetadataVersion; |
|
if (string.IsNullOrEmpty(version)) |
|
version = "4.0"; |
|
version = version.TrimStart('v'); |
|
return $".NETFramework,Version=v{version.Substring(0, Math.Min(3, version.Length))}"; |
|
} |
|
} |
|
|
|
return string.Empty; |
|
} |
|
|
|
public static bool IsReferenceAssembly(this PEFile assembly) |
|
{ |
|
return IsReferenceAssembly(assembly.Reader, assembly.FileName); |
|
} |
|
|
|
public static bool IsReferenceAssembly(this PEReader assembly, string assemblyPath) |
|
{ |
|
if (assembly == null) |
|
throw new ArgumentNullException(nameof(assembly)); |
|
|
|
var metadata = assembly.GetMetadataReader(); |
|
if (metadata.GetCustomAttributes(Handle.AssemblyDefinition).HasKnownAttribute(metadata, KnownAttribute.ReferenceAssembly)) |
|
return true; |
|
|
|
// Try to detect reference assembly through specific path pattern |
|
var refPathMatch = Regex.Match(assemblyPath, RefPathPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); |
|
return refPathMatch.Success; |
|
} |
|
|
|
public static string DetectRuntimePack(this PEFile assembly) |
|
{ |
|
if (assembly is null) |
|
{ |
|
throw new ArgumentNullException(nameof(assembly)); |
|
} |
|
|
|
var metadata = assembly.Metadata; |
|
|
|
foreach (var r in metadata.AssemblyReferences) |
|
{ |
|
var reference = metadata.GetAssemblyReference(r); |
|
|
|
if (reference.PublicKeyOrToken.IsNil) |
|
continue; |
|
|
|
if (metadata.StringComparer.Equals(reference.Name, "WindowsBase")) |
|
{ |
|
return "Microsoft.WindowsDesktop.App"; |
|
} |
|
|
|
if (metadata.StringComparer.Equals(reference.Name, "PresentationFramework")) |
|
{ |
|
return "Microsoft.WindowsDesktop.App"; |
|
} |
|
|
|
if (metadata.StringComparer.Equals(reference.Name, "PresentationCore")) |
|
{ |
|
return "Microsoft.WindowsDesktop.App"; |
|
} |
|
|
|
// TODO add support for ASP.NET Core |
|
} |
|
|
|
return "Microsoft.NETCore.App"; |
|
} |
|
} |
|
}
|
|
|