Skip to content

Commit

Permalink
Show all bundle entries in the tree view
Browse files Browse the repository at this point in the history
  • Loading branch information
ElektroKill committed Jun 17, 2023
1 parent d3d7223 commit 073864d
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 9 deletions.
16 changes: 12 additions & 4 deletions Extensions/dnSpy.AsmEditor/SaveModule/SaveModuleCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ You should have received a copy of the GNU General Public License
using dnSpy.AsmEditor.Hex;
using dnSpy.AsmEditor.Properties;
using dnSpy.AsmEditor.UndoRedo;
using dnSpy.Contracts.App;
using dnSpy.Contracts.Controls;
using dnSpy.Contracts.Documents.Tabs;
using dnSpy.Contracts.Documents.TreeView;
Expand Down Expand Up @@ -87,7 +88,8 @@ sealed class SaveModuleCommand : FileMenuHandler {
this.documentSaver = documentSaver;
}

HashSet<object> GetDocuments(DocumentTreeNodeData[] nodes) {
HashSet<object> GetDocuments(DocumentTreeNodeData[] nodes, out bool hitBundle) {
hitBundle = false;
var hash = new HashSet<object>();

foreach (var node in nodes) {
Expand All @@ -100,6 +102,9 @@ HashSet<object> GetDocuments(DocumentTreeNodeData[] nodes) {
if (topNode is null || topNode.TreeNode.Parent is null)
continue;

if (fileNode.Document.SingleFileBundle is not null)
hitBundle = true;

bool added = false;

if (fileNode.Document.ModuleDef is not null) {
Expand Down Expand Up @@ -128,13 +133,16 @@ HashSet<object> GetDocuments(DocumentTreeNodeData[] nodes) {
}

public override bool IsVisible(AsmEditorContext context) => true;
public override bool IsEnabled(AsmEditorContext context) => GetDocuments(context.Nodes).Count > 0;
public override bool IsEnabled(AsmEditorContext context) => GetDocuments(context.Nodes, out _).Count > 0;

public override void Execute(AsmEditorContext context) {
var asmNodes = GetDocuments(context.Nodes);
var asmNodes = GetDocuments(context.Nodes, out bool bundle);
if (bundle)
MsgBox.Instance.Show("Warning: Entries inside bundles will not be updated!"); //TODO: localize

documentSaver.Value.Save(asmNodes);
}

public override string? GetHeader(AsmEditorContext context) => GetDocuments(context.Nodes).Count <= 1 ? dnSpy_AsmEditor_Resources.SaveModuleCommand : dnSpy_AsmEditor_Resources.SaveModulesCommand;
public override string? GetHeader(AsmEditorContext context) => GetDocuments(context.Nodes, out _).Count <= 1 ? dnSpy_AsmEditor_Resources.SaveModuleCommand : dnSpy_AsmEditor_Resources.SaveModulesCommand;
}
}
22 changes: 18 additions & 4 deletions dnSpy/dnSpy.Contracts.DnSpy/Documents/Bundles/BundleEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ public sealed class BundleEntry {
/// </summary>
public string RelativePath { get; }

/// <summary>
/// The offset of the entry's data.
/// </summary>
public long Offset { get; }

/// <summary>
/// The size of the entry's data.
/// </summary>
public long Size { get; }

/// <summary>
/// The file name of the entry.
/// </summary>
Expand All @@ -44,15 +54,19 @@ public byte[] Data {
}
}

BundleEntry(BundleFileType type, string relativePath, byte[] data) {
BundleEntry(BundleFileType type, string relativePath, long offset, long size, byte[] data) {
Type = type;
RelativePath = relativePath.Replace('/', '\\');
Offset = offset;
Size = size;
this.data = data;
}

BundleEntry(BundleFileType type, string relativePath, DataReader reader) {
BundleEntry(BundleFileType type, string relativePath, long offset, long size, DataReader reader) {
Type = type;
RelativePath = relativePath.Replace('/', '\\');
Offset = offset;
Size = size;
this.reader = reader;
}

Expand All @@ -67,9 +81,9 @@ internal static IReadOnlyList<BundleEntry> ReadEntries(DataReader reader, int co
string path = reader.ReadSerializedString();

if (compSize == 0)
res[i] = new BundleEntry(type, path, reader.Slice((uint)offset, (uint)size));
res[i] = new BundleEntry(type, path, offset, size, reader.Slice((uint)offset, (uint)size));
else
res[i] = new BundleEntry(type, path, ReadCompressedEntryData(reader, offset, size, compSize));
res[i] = new BundleEntry(type, path, offset, size, ReadCompressedEntryData(reader, offset, size, compSize));
}

return res;
Expand Down
2 changes: 1 addition & 1 deletion dnSpy/dnSpy.Contracts.DnSpy/Documents/DsDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ protected override TList<IDsDocument> CreateChildren() {
list.Add(document);
}
else if (entry.Type == BundleFileType.NativeBinary)
list.Add(new DsPEDocument(new PEImage(entry.Data, Path.Combine(directoryOfBundle, entry.RelativePath))));
list.Add(entry.Document = new DsPEDocument(new PEImage(entry.Data, Path.Combine(directoryOfBundle, entry.RelativePath))));
}

return list;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public static class DocumentTreeViewConstants {
/// <summary><see cref="BundleFolderNode"/></summary>
public const string BUNDLE_FOLDER_NODE_GUID = "BCF6AA92-94FF-4837-9E55-0C770FCB3BB4";

/// <summary><see cref="UnknownBundleEntryNode"/></summary>
public const string BUNDLE_UNKNOWN_ENTRY_NODE_GUID = "582A8F1D-2D9E-476A-84B6-6053B983C374";

/// <summary><see cref="JsonBundleEntryNode"/></summary>
public const string BUNDLE_JSON_ENTRY_NODE_GUID = "9C972EA7-9E52-4283-B38A-7C876A50F897";

/// <summary><see cref="ResourcesFolderNode"/></summary>
public const string RESOURCES_FOLDER_NODE_GUID = "1DD75445-9DED-482F-B6EB-4FD13E4A2197";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Diagnostics;

namespace dnSpy.Contracts.Documents.TreeView {
/// <summary>
/// JSON bundle entry node
/// </summary>
public abstract class JsonBundleEntryNode : DocumentTreeNodeData {
/// <summary>
/// Constructor
/// </summary>
protected JsonBundleEntryNode(BundleEntry bundleEntry) => Debug2.Assert(bundleEntry is not null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Diagnostics;

namespace dnSpy.Contracts.Documents.TreeView {
/// <summary>
/// Unknown bundle entry node
/// </summary>
public abstract class UnknownBundleEntryNode : DocumentTreeNodeData {
/// <summary>
/// Constructor
/// </summary>
protected UnknownBundleEntryNode(BundleEntry bundleEntry) => Debug2.Assert(bundleEntry is not null);
}
}
14 changes: 14 additions & 0 deletions dnSpy/dnSpy/Documents/TreeView/BundleDocumentNodeImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ public override IEnumerable<TreeNodeData> CreateChildren() {
foreach (var entry in Document.SingleFileBundle.TopLevelEntries) {
if (entry.Document is not null)
yield return Context.DocumentTreeView.CreateNode(this, entry.Document);
else {
switch (entry.Type) {
case BundleFileType.Unknown:
case BundleFileType.Symbols:
yield return new UnknownBundleEntryNodeImpl(entry);
break;
case BundleFileType.DepsJson:
case BundleFileType.RuntimeConfigJson:
yield return new JsonBundleEntryNodeImpl(entry);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}

// TODO: return all bundle entries
Expand Down
14 changes: 14 additions & 0 deletions dnSpy/dnSpy/Documents/TreeView/BundleFolderNodeImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ public override IEnumerable<TreeNodeData> CreateChildren() {
foreach (var entry in bundleFolder.Entries) {
if (entry.Document is not null)
yield return Context.DocumentTreeView.CreateNode(owner, entry.Document);
else {
switch (entry.Type) {
case BundleFileType.Unknown:
case BundleFileType.Symbols:
yield return new UnknownBundleEntryNodeImpl(entry);
break;
case BundleFileType.DepsJson:
case BundleFileType.RuntimeConfigJson:
yield return new JsonBundleEntryNodeImpl(entry);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}

Expand Down
33 changes: 33 additions & 0 deletions dnSpy/dnSpy/Documents/TreeView/JsonBundleEntryNodeImpl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Text;
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;

namespace dnSpy.Documents.TreeView {
public class JsonBundleEntryNodeImpl : JsonBundleEntryNode, IDecompileSelf {
readonly BundleEntry bundleEntry;

public JsonBundleEntryNodeImpl(BundleEntry bundleEntry) : base(bundleEntry) => this.bundleEntry = bundleEntry;

public override Guid Guid => new Guid(DocumentTreeViewConstants.BUNDLE_JSON_ENTRY_NODE_GUID);

public override NodePathName NodePathName => new NodePathName(Guid);

protected override ImageReference GetIcon(IDotNetImageService dnImgMgr) => DsImages.TextFile;

protected override void WriteCore(ITextColorWriter output, IDecompiler decompiler, DocumentNodeWriteOptions options) {
// TODO: better tooltip
output.Write(BoxedTextColor.Text, bundleEntry.FileName);
}

public bool Decompile(IDecompileNodeContext context) {
//TODO: implement syntax highlighting
context.Output.Write(Encoding.UTF8.GetString(bundleEntry.Data), BoxedTextColor.Text);
return true;
}
}
}
25 changes: 25 additions & 0 deletions dnSpy/dnSpy/Documents/TreeView/UnknownBundleEntryNodeImpl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using dnSpy.Contracts.Decompiler;
using dnSpy.Contracts.Documents;
using dnSpy.Contracts.Documents.TreeView;
using dnSpy.Contracts.Images;
using dnSpy.Contracts.Text;

namespace dnSpy.Documents.TreeView {
sealed class UnknownBundleEntryNodeImpl : UnknownBundleEntryNode {
readonly BundleEntry bundleEntry;

public UnknownBundleEntryNodeImpl(BundleEntry bundleEntry) : base(bundleEntry) {
this.bundleEntry = bundleEntry;
}

public override Guid Guid => new Guid(DocumentTreeViewConstants.BUNDLE_UNKNOWN_ENTRY_NODE_GUID);
protected override ImageReference GetIcon(IDotNetImageService dnImgMgr) => DsImages.BinaryFile;
public override NodePathName NodePathName => new NodePathName(Guid);

protected override void WriteCore(ITextColorWriter output, IDecompiler decompiler, DocumentNodeWriteOptions options) {
// TODO: better tooltip
output.Write(BoxedTextColor.Text, bundleEntry.FileName);
}
}
}

0 comments on commit 073864d

Please sign in to comment.