/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; using System.IO; using System.Linq; using dnlib.DotNet; using dnlib.PE; namespace dnSpy.Contracts.Documents { /// /// A document, see also and /// public interface IDsDocument : IAnnotations { /// /// Used to serialize this instance. Null if it can't be serialized. /// DsDocumentInfo? SerializedDocument { get; } /// /// Gets a key for this document. Eg. a instance if it's a file /// loaded from disk. It's used to detect duplicate documents when adding a new document. /// IDsDocumentNameKey Key { get; } /// /// Gets the assembly or null if it's not a .NET file or if it's a netmodule /// AssemblyDef? AssemblyDef { get; } /// /// Gets the module or null if it's not a .NET file /// ModuleDef? ModuleDef { get; } /// /// Gets the PE image or null if it's not available /// IPEImage? PEImage { get; } /// /// Gets/sets the filename /// string Filename { get; set; } /// /// true if it was not loaded by the user /// bool IsAutoLoaded { get; set; } /// /// Gets any children. Eg. if it's a .NET assembly, the children would be modules of the /// assembly. /// TList Children { get; } /// /// true if has been initialized /// bool ChildrenLoaded { get; } } /// /// A document /// public interface IDsDocument2 : IDsDocument { /// /// Called after it's been added to the documents list /// void OnAdded(); } /// /// Extension methods /// public static class DsDocumentExtensionMethods { /// /// Gets the short name of , which is usually the filename without /// the extension. /// /// Document /// public static string GetShortName(this IDsDocument document) { var shortName = GetShortName(document.Filename); if (string.IsNullOrEmpty(shortName)) shortName = GetDefaultShortName(document) ?? string.Empty; return shortName; } static string GetDefaultShortName(IDsDocument document) => document.ModuleDef?.Name; static string GetShortName(string filename) { if (string.IsNullOrEmpty(filename)) return filename; try { var s = Path.GetFileNameWithoutExtension(filename); if (!string.IsNullOrWhiteSpace(s)) return s; s = Path.GetFileName(filename); if (!string.IsNullOrWhiteSpace(s)) return s; } catch (ArgumentException) { } return filename; } /// /// Gets self and all descendants that have been loaded /// /// Document /// public static IEnumerable NonLoadedDescendantsAndSelf(this IDsDocument document) { if (document is null) throw new ArgumentNullException(nameof(document)); yield return document; if (document.ChildrenLoaded) { foreach (var child in document.Children) { foreach (var f in child.NonLoadedDescendantsAndSelf()) yield return f; } } } /// /// Gets all modules in this instance and any children /// /// or /// Document /// public static IEnumerable GetModules(this IDsDocument document) where T : ModuleDef => GetModules(new HashSet(), new[] { document }); /// /// Gets all modules in this instance and any children /// /// or /// Documents /// public static IEnumerable GetModules(this IEnumerable documents) where T : ModuleDef => GetModules(new HashSet(), documents); static IEnumerable GetModules(HashSet hash, IEnumerable documents) where T : ModuleDef { foreach (var f in documents.SelectMany(f => f.NonLoadedDescendantsAndSelf())) { var mod = f.ModuleDef as T; if (mod is not null && !hash.Contains(mod)) { hash.Add(mod); yield return mod; } var asm = mod?.Assembly; if (asm is null) continue; foreach (var m in asm.Modules) { mod = m as T; if (mod is not null && !hash.Contains(mod)) { hash.Add(mod); yield return mod; } } } } /// /// Gets self and all its children /// /// This /// public static IEnumerable GetAllChildrenAndSelf(this IDsDocument self) { yield return self; foreach (var c in self.GetAllChildren()) yield return c; } /// /// Gets all its children and their children /// /// This /// public static IEnumerable GetAllChildren(this IDsDocument self) { foreach (var c in GetAllChildren(self.Children)) yield return c; } static IEnumerable GetAllChildren(IEnumerable documents) { foreach (var d in documents) { yield return d; foreach (var c in GetAllChildren(d.Children)) yield return c; } } } }