/* 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.Collections.Generic; using System.Diagnostics; using System.Linq; using dnSpy.AsmEditor.Hex.PE; using dnSpy.Contracts.Decompiler; using dnSpy.Contracts.Documents.Tabs.DocViewer; using dnSpy.Contracts.Documents.TreeView; using dnSpy.Contracts.Hex; using dnSpy.Contracts.Images; using dnSpy.Contracts.Text; namespace dnSpy.AsmEditor.Hex.Nodes { abstract class HexNode : DocumentTreeNodeData, IDecompileSelf { protected abstract IEnumerable HexVMs { get; } public abstract object VMObject { get; } public virtual bool IsVirtualizingCollectionVM => false; public HexSpan Span { get; } protected sealed override ImageReference GetIcon(IDotNetImageService dnImgMgr) => IconReference; protected abstract ImageReference IconReference { get; } protected virtual IEnumerable Spans { get { yield return Span; } } protected HexNode(HexSpan span) => Span = span; public override FilterType GetFilterType(IDocumentTreeNodeFilter filter) => filter.GetResultOther(this).FilterType; public bool Decompile(IDecompileNodeContext context) { context.ContentTypeString = context.Decompiler.ContentTypeString; context.Decompiler.WriteCommentLine(context.Output, $"{Span.Start.ToUInt64():X8} - {Span.End.ToUInt64() - 1:X8} {ToString()}"); DecompileFields(context.Decompiler, context.Output); (context.Output as IDocumentViewerOutput)?.DisableCaching(); return true; } protected virtual void DecompileFields(IDecompiler decompiler, IDecompilerOutput output) { foreach (var vm in HexVMs) { decompiler.WriteCommentLine(output, string.Empty); decompiler.WriteCommentLine(output, $"{vm.Name}:"); foreach (var field in vm.HexFields) decompiler.WriteCommentLine(output, $"{field.Span.Start.ToUInt64():X8} - {field.Span.End.ToUInt64() - 1:X8} {field.FormattedValue} = {field.Name}"); } } protected override void WriteCore(ITextColorWriter output, IDecompiler decompiler, DocumentNodeWriteOptions options) { WriteCore(output, options); if ((options & DocumentNodeWriteOptions.ToolTip) != 0) { output.WriteLine(); WriteFilename(output); } } protected abstract void WriteCore(ITextColorWriter output, DocumentNodeWriteOptions options); public virtual void OnBufferChanged(NormalizedHexChangeCollection changes) { if (!changes.OverlapsWith(Span)) return; foreach (var vm in HexVMs) vm.OnBufferChanged(changes); } public HexNode? FindNode(HexVM structure, HexField field) { Debug.Assert(!(structure is MetadataTableRecordVM), "Use " + nameof(PENode) + "'s method instead"); bool found = false; foreach (var span in Spans) { if (span.Contains(field.Span)) { found = true; break; } } if (!found) return null; foreach (var vm in HexVMs) { foreach (var f in vm.HexFields) { if (f == field) return this; } } TreeNode.EnsureChildrenLoaded(); foreach (var child in TreeNode.DataChildren.OfType()) { var node = child.FindNode(structure, field); if (node is not null) return node; } return null; } } }