/*
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;
}
}
}
}