123 lines
4.7 KiB
C#
Raw Normal View History

2021-09-20 18:20:01 +02:00
using System;
using System.ComponentModel.Composition;
using System.IO;
using dnSpy.Contracts.Decompiler;
using dnSpy.Contracts.Documents;
using dnSpy.Contracts.Documents.Tabs.DocViewer;
using dnSpy.Contracts.Documents.TreeView;
using dnSpy.Contracts.Images;
using dnSpy.Contracts.Text;
// Adds a new IDsDocument that can be loaded into the document treeview. It gets its own DsDocumentNode.
// Open a .txt/.xml/.cs/.vb (see supportedExtensions) file to trigger this code.
namespace Example2.Extension {
// All root nodes in the document treeview contain a IDsDocument instance. They don't need to be
// .NET files or even PE files, they can be any file or even non-file (eg. in-memory data).
sealed class MyDsDocument : DsDocument {
//TODO: Use your own guid
public static readonly Guid THE_GUID = new Guid("9058B02C-1FE0-4EC4-93D3-A378D4B6FCE1");
// We support serialization, so return a non-null value
public override DsDocumentInfo? SerializedDocument => new DsDocumentInfo(Filename, THE_GUID);
// Since we open files from disk, we return a FilenameKey.
// If this gets changed, also update MyDsDocumentProvider.CreateKey()
public override IDsDocumentNameKey Key => new FilenameKey(Filename);
// Used by MyDsDocumentNode.Decompile() to show the file in the text editor
public string Text {
get {
if (text is not null)
return text;
try {
return text = File.ReadAllText(Filename);
}
catch {
return text = $"Couldn't read the file: {Filename}";
}
}
}
string? text;
public static MyDsDocument? TryCreate(string filename) {
if (!File.Exists(filename))
return null;
return new MyDsDocument(filename);
}
MyDsDocument(string filename) => Filename = filename;
}
// Gets called by the IDsDocumentService instance to create IDsDocument instances. If it's a .txt file
// or our MyDsDocument.THE_GUID, then create a MyDsDocument instance.
[Export(typeof(IDsDocumentProvider))]
sealed class MyDsDocumentProvider : IDsDocumentProvider {
public double Order => 0;
public IDsDocument? Create(IDsDocumentService documentService, DsDocumentInfo documentInfo) {
if (documentInfo.Type == MyDsDocument.THE_GUID)
return MyDsDocument.TryCreate(documentInfo.Name);
// Also check for normal files
if (documentInfo.Type == DocumentConstants.DOCUMENTTYPE_FILE && IsSupportedFile(documentInfo.Name))
return MyDsDocument.TryCreate(documentInfo.Name);
return null;
}
public IDsDocumentNameKey? CreateKey(IDsDocumentService documentService, DsDocumentInfo documentInfo) {
if (documentInfo.Type == MyDsDocument.THE_GUID)
return new FilenameKey(documentInfo.Name); // Must match the key in MyDsDocument.Key
// Also check for normal files
if (documentInfo.Type == DocumentConstants.DOCUMENTTYPE_FILE && IsSupportedFile(documentInfo.Name))
return new FilenameKey(documentInfo.Name); // Must match the key in MyDsDocument.Key
return null;
}
static bool IsSupportedFile(string filename) {
foreach (var ext in supportedExtensions) {
if (filename.EndsWith(ext, StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
static readonly string[] supportedExtensions = new string[] {
".txt", ".xml", ".cs", ".vb",
};
}
// Gets called by dnSpy to create a DsDocumentNode
[ExportDsDocumentNodeProvider]
sealed class MyDsDocumentNodeProvider : IDsDocumentNodeProvider {
public DsDocumentNode? Create(IDocumentTreeView documentTreeView, DsDocumentNode? owner, IDsDocument document) {
if (document is MyDsDocument myDocument)
return new MyDsDocumentNode(myDocument);
return null;
}
}
// Our MyDsDocument tree node class. It implements IDecompileSelf to "decompile" itself. You could
// also export a IDecompileNode instance to do it, see TreeNodeDataProvider.cs for an example.
// Or you could create a completely new DocumentTabContent for these nodes, see AssemblyChildNodeTabContent.cs
sealed class MyDsDocumentNode : DsDocumentNode, IDecompileSelf {
//TODO: Use your own guid
public static readonly Guid THE_GUID = new Guid("4174A21D-D746-4658-9A44-DB8235EE5186");
readonly MyDsDocument document;
public override Guid Guid => THE_GUID;
public MyDsDocumentNode(MyDsDocument document)
: base(document) => this.document = document;
protected override ImageReference GetIcon(IDotNetImageService dnImgMgr) => DsImages.TextFile;
protected override void WriteCore(ITextColorWriter output, IDecompiler decompiler, DocumentNodeWriteOptions options) =>
output.WriteFilename(Path.GetFileName(document.Filename));
public bool Decompile(IDecompileNodeContext context) {
context.ContentTypeString = ContentTypes.PlainText;
context.Output.Write(document.Text, BoxedTextColor.Text);
return true;
}
}
}