.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
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.
 
 
 
 

109 lines
4.3 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.AddIn
{
public class AssemblyFileFinder
{
public static string FindAssemblyFile(AssemblyDefinition assemblyDefinition, string assemblyFile)
{
var assemblyName = assemblyDefinition.Name;
var detectedTargetFramework = DetectTargetFrameworkId(assemblyDefinition, assemblyFile);
if (string.IsNullOrEmpty(detectedTargetFramework)) {
// Without a target framework id it makes no sense to continue
return null;
}
var targetFramework = detectedTargetFramework.Split(new[] { ",Version=v" }, StringSplitOptions.None);
string file = null;
switch (targetFramework[0]) {
case ".NETCoreApp":
case ".NETStandard":
if (targetFramework.Length != 2)
return FindAssemblyFromGAC(assemblyDefinition);
var version = targetFramework[1].Length == 3 ? new Version(targetFramework[1] + ".0") : new Version(targetFramework[1]);
var dotNetCorePathFinder = new DotNetCorePathFinder(assemblyFile, detectedTargetFramework, version);
file = dotNetCorePathFinder.TryResolveDotNetCore(Decompiler.Metadata.AssemblyNameReference.Parse(assemblyName.FullName));
if (file != null)
return file;
return FindAssemblyFromGAC(assemblyDefinition);
default:
return FindAssemblyFromGAC(assemblyDefinition);
}
}
static string FindAssemblyFromGAC(AssemblyDefinition assemblyDefinition)
{
return GacInterop.FindAssemblyInNetGac(Decompiler.Metadata.AssemblyNameReference.Parse(assemblyDefinition.Name.FullName));
}
static readonly string RefPathPattern = @"NuGetFallbackFolder[/\\][^/\\]+[/\\][^/\\]+[/\\]ref[/\\]";
public static bool IsReferenceAssembly(AssemblyDefinition assemblyDef, string assemblyFile)
{
if (assemblyDef.CustomAttributes.Any(ca => ca.AttributeType.FullName == "System.Runtime.CompilerServices.ReferenceAssemblyAttribute"))
return true;
// Try to detect reference assembly through specific path pattern
var refPathMatch = Regex.Match(assemblyFile, RefPathPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
return refPathMatch.Success;
}
static readonly string DetectTargetFrameworkIdRefPathPattern =
@"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<1>.NETFramework)[/\\]v(?<2>[^/\\]+)[/\\])" +
@"|(NuGetFallbackFolder[/\\](?<1>[^/\\]+)\\(?<2>[^/\\]+)([/\\].*)?[/\\]ref[/\\])";
public static string DetectTargetFrameworkId(AssemblyDefinition assembly, string assemblyPath = null)
{
if (assembly == null)
throw new ArgumentNullException(nameof(assembly));
const string TargetFrameworkAttributeName = "System.Runtime.Versioning.TargetFrameworkAttribute";
foreach (var attribute in assembly.CustomAttributes) {
if (attribute.AttributeType.FullName != TargetFrameworkAttributeName)
continue;
if (attribute.HasConstructorArguments) {
if (attribute.ConstructorArguments[0].Value is string value)
return value;
}
}
// 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, DetectTargetFrameworkIdRefPathPattern,
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
if (pathMatch.Success) {
var type = pathMatch.Groups[1].Value;
var version = pathMatch.Groups[2].Value;
if (type == ".NETFramework") {
return $".NETFramework,Version=v{version}";
} else if (type.Contains("netcore")) {
return $".NETCoreApp,Version=v{version}";
} else if (type.Contains("netstandard")) {
return $".NETStandard,Version=v{version}";
}
}
}
return string.Empty;
}
}
}