diff --git a/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs b/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs index 561c25704..7d9d2ca5b 100644 --- a/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs +++ b/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs @@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.Metadata return publicKeyTokenBytes.TakeLast(8).Reverse().ToHexString(8); } - public static string GetFullAssemblyName(this MetadataReader reader) + public static string GetPublicKeyToken(this MetadataReader reader) { if (!reader.IsAssembly) return string.Empty; @@ -59,6 +59,15 @@ namespace ICSharpCode.Decompiler.Metadata // AssemblyFlags.PublicKey does not apply to assembly definitions publicKey = CalculatePublicKeyToken(asm.PublicKey, reader); } + return publicKey; + } + + public static string GetFullAssemblyName(this MetadataReader reader) + { + if (!reader.IsAssembly) + return string.Empty; + var asm = reader.GetAssemblyDefinition(); + string publicKey = reader.GetPublicKeyToken(); return $"{reader.GetString(asm.Name)}, " + $"Version={asm.Version}, " + $"Culture={(asm.Culture.IsNil ? "neutral" : reader.GetString(asm.Culture))}, " + diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 530547711..31e80a05d 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -172,6 +172,7 @@ Resources.resx + diff --git a/ILSpy/Search/AssemblySearchStrategy.cs b/ILSpy/Search/AssemblySearchStrategy.cs new file mode 100644 index 000000000..30859b3a2 --- /dev/null +++ b/ILSpy/Search/AssemblySearchStrategy.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Reflection.Metadata; +using System.Threading; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Util; +using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.TreeView; + +namespace ICSharpCode.ILSpy.Search +{ + class AssemblySearchStrategy : AbstractSearchStrategy + { + readonly AssemblySearchKind searchKind; + + public AssemblySearchStrategy(string term, IProducerConsumerCollection resultQueue, AssemblySearchKind searchKind) + : this(resultQueue, new[] { term }, searchKind) + { + } + + public AssemblySearchStrategy(IProducerConsumerCollection resultQueue, string[] terms, AssemblySearchKind searchKind) + : base(resultQueue, terms) + { + this.searchKind = searchKind; + } + + public override void Search(PEFile module, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (searchKind == AssemblySearchKind.NameOrFileName) { + string localName = GetNameToMatch(module, AssemblySearchKind.Name); + string fileName = Path.GetFileName(GetNameToMatch(module, AssemblySearchKind.FilePath)); + if (IsMatch(localName) || IsMatch(fileName)) + OnFoundResult(module); + return; + } + + string name = GetNameToMatch(module, searchKind); + if (IsMatch(name)) + OnFoundResult(module); + } + + string GetNameToMatch(PEFile module, AssemblySearchKind kind) + { + switch (kind) { + case AssemblySearchKind.FullName: + return module.FullName; + case AssemblySearchKind.Name: + return module.Name; + case AssemblySearchKind.FilePath: + return module.FileName; + } + + if (!module.IsAssembly) + return null; + + var metadata = module.Metadata; + var definition = module.Metadata.GetAssemblyDefinition(); + + switch (kind) { + case AssemblySearchKind.Culture: + if (definition.Culture.IsNil) + return "neutral"; + return metadata.GetString(definition.Culture); + case AssemblySearchKind.Version: + return definition.Version.ToString(); + case AssemblySearchKind.PublicKey: + return module.Metadata.GetPublicKeyToken(); + case AssemblySearchKind.HashAlgorithm: + return definition.HashAlgorithm.ToString(); + case AssemblySearchKind.Flags: + return definition.Flags.ToString(); + } + + return null; + } + + void OnFoundResult(PEFile module) + { + var result = new AssemblySearchResult { + Module = module, + Fitness = 1.0f / module.Name.Length, + Name = module.Name, + Location = module.FileName, + Assembly = module.FullName, + ToolTip = module.FileName, + }; + OnFoundResult(result); + } + } + + enum AssemblySearchKind + { + NameOrFileName, + Name, + FullName, + FilePath, + Culture, + Version, + PublicKey, + HashAlgorithm, + Flags + } +} diff --git a/ILSpy/Search/SearchPane.cs b/ILSpy/Search/SearchPane.cs index f1394239e..f2bbf7760 100644 --- a/ILSpy/Search/SearchPane.cs +++ b/ILSpy/Search/SearchPane.cs @@ -76,6 +76,7 @@ namespace ICSharpCode.ILSpy searchModeComboBox.Items.Add(new { Image = Images.Literal, Name = "Constant" }); searchModeComboBox.Items.Add(new { Image = Images.Library, Name = "Metadata Token" }); searchModeComboBox.Items.Add(new { Image = Images.Resource, Name = "Resource" }); + searchModeComboBox.Items.Add(new { Image = Images.Assembly, Name = "Assembly" }); ContextMenuProvider.Add(listBox); MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged; @@ -345,6 +346,15 @@ namespace ICSharpCode.ILSpy if (searchTerm[0].StartsWith("r:", StringComparison.Ordinal)) return new ResourceSearchStrategy(apiVisibility, resultQueue, searchTerm[0].Substring(2)); + + if (searchTerm[0].StartsWith("a:", StringComparison.Ordinal)) + return new AssemblySearchStrategy(searchTerm[0].Substring(2), resultQueue, AssemblySearchKind.NameOrFileName); + + if (searchTerm[0].StartsWith("af:", StringComparison.Ordinal)) + return new AssemblySearchStrategy(searchTerm[0].Substring(3), resultQueue, AssemblySearchKind.FilePath); + + if (searchTerm[0].StartsWith("an:", StringComparison.Ordinal)) + return new AssemblySearchStrategy(searchTerm[0].Substring(3), resultQueue, AssemblySearchKind.FullName); } switch (searchMode) @@ -369,6 +379,8 @@ namespace ICSharpCode.ILSpy return new MetadataTokenSearchStrategy(language, apiVisibility, resultQueue, searchTerm); case SearchMode.Resource: return new ResourceSearchStrategy(apiVisibility, resultQueue, searchTerm); + case SearchMode.Assembly: + return new AssemblySearchStrategy(resultQueue, searchTerm, AssemblySearchKind.NameOrFileName); } return null; @@ -400,6 +412,7 @@ namespace ICSharpCode.ILSpy Event, Literal, Token, - Resource + Resource, + Assembly } } \ No newline at end of file diff --git a/ILSpy/Search/SearchResult.cs b/ILSpy/Search/SearchResult.cs index eb78c0bef..d632129f2 100644 --- a/ILSpy/Search/SearchResult.cs +++ b/ILSpy/Search/SearchResult.cs @@ -94,4 +94,13 @@ namespace ICSharpCode.ILSpy public Resource Resource { get; set; } public override object Reference => ValueTuple.Create(Resource, Name); } + + public class AssemblySearchResult : SearchResult + { + public PEFile Module { get; set; } + public override object Reference => Module; + + public override ImageSource Image => Images.Assembly; + public override ImageSource LocationImage => Images.Library; + } } \ No newline at end of file