using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using ICSharpCode.Decompiler.TypeSystem.Implementation; using Mono.Cecil; namespace ICSharpCode.Decompiler { public static class DotNetCorePathFinderExtensions { static readonly string RefPathPattern = @"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<1>.NETFramework)[/\\]v(?<2>[^/\\]+)[/\\])" + @"|(NuGetFallbackFolder[/\\](?<1>[^/\\]+)\\(?<2>[^/\\]+)([/\\].*)?[/\\]ref[/\\])"; public static string DetectTargetFrameworkId(this 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; var blobReader = new BlobReader(attribute.GetBlob(), null); if (blobReader.ReadUInt16() == 0x0001) { return blobReader.ReadSerString(); } } // 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, RefPathPattern, 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; } } public class ReferenceLoadInfo { readonly Dictionary loadedAssemblyReferences = new Dictionary(); public void AddMessage(string fullName, MessageKind kind, string message) { lock (loadedAssemblyReferences) { if (!loadedAssemblyReferences.TryGetValue(fullName, out var referenceInfo)) { referenceInfo = new UnresolvedAssemblyNameReference(fullName); loadedAssemblyReferences.Add(fullName, referenceInfo); } referenceInfo.Messages.Add((kind, message)); } } public void AddMessageOnce(string fullName, MessageKind kind, string message) { lock (loadedAssemblyReferences) { if (!loadedAssemblyReferences.TryGetValue(fullName, out var referenceInfo)) { referenceInfo = new UnresolvedAssemblyNameReference(fullName); loadedAssemblyReferences.Add(fullName, referenceInfo); referenceInfo.Messages.Add((kind, message)); } else { var lastMsg = referenceInfo.Messages.LastOrDefault(); if (kind != lastMsg.Item1 && message != lastMsg.Item2) referenceInfo.Messages.Add((kind, message)); } } } public bool TryGetInfo(string fullName, out UnresolvedAssemblyNameReference info) { lock (loadedAssemblyReferences) { return loadedAssemblyReferences.TryGetValue(fullName, out info); } } public bool HasErrors { get { lock (loadedAssemblyReferences) { return loadedAssemblyReferences.Any(i => i.Value.HasErrors); } } } } }