Skip to content

Commit 7841ec9

Browse files
committed
Show all bundle entries in the tree view
1 parent 031b357 commit 7841ec9

File tree

10 files changed

+149
-9
lines changed

10 files changed

+149
-9
lines changed

Extensions/dnSpy.AsmEditor/SaveModule/SaveModuleCommand.cs

+12-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ You should have received a copy of the GNU General Public License
2626
using dnSpy.AsmEditor.Hex;
2727
using dnSpy.AsmEditor.Properties;
2828
using dnSpy.AsmEditor.UndoRedo;
29+
using dnSpy.Contracts.App;
2930
using dnSpy.Contracts.Controls;
3031
using dnSpy.Contracts.Documents.Tabs;
3132
using dnSpy.Contracts.Documents.TreeView;
@@ -87,7 +88,8 @@ sealed class SaveModuleCommand : FileMenuHandler {
8788
this.documentSaver = documentSaver;
8889
}
8990

90-
HashSet<object> GetDocuments(DocumentTreeNodeData[] nodes) {
91+
HashSet<object> GetDocuments(DocumentTreeNodeData[] nodes, out bool hitBundle) {
92+
hitBundle = false;
9193
var hash = new HashSet<object>();
9294

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

105+
if (fileNode.Document.SingleFileBundle is not null)
106+
hitBundle = true;
107+
103108
bool added = false;
104109

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

130135
public override bool IsVisible(AsmEditorContext context) => true;
131-
public override bool IsEnabled(AsmEditorContext context) => GetDocuments(context.Nodes).Count > 0;
136+
public override bool IsEnabled(AsmEditorContext context) => GetDocuments(context.Nodes, out _).Count > 0;
132137

133138
public override void Execute(AsmEditorContext context) {
134-
var asmNodes = GetDocuments(context.Nodes);
139+
var asmNodes = GetDocuments(context.Nodes, out bool bundle);
140+
if (bundle)
141+
MsgBox.Instance.Show("Warning: Entries inside bundles will not be updated!"); //TODO: localize
142+
135143
documentSaver.Value.Save(asmNodes);
136144
}
137145

138-
public override string? GetHeader(AsmEditorContext context) => GetDocuments(context.Nodes).Count <= 1 ? dnSpy_AsmEditor_Resources.SaveModuleCommand : dnSpy_AsmEditor_Resources.SaveModulesCommand;
146+
public override string? GetHeader(AsmEditorContext context) => GetDocuments(context.Nodes, out _).Count <= 1 ? dnSpy_AsmEditor_Resources.SaveModuleCommand : dnSpy_AsmEditor_Resources.SaveModulesCommand;
139147
}
140148
}

dnSpy/dnSpy.Contracts.DnSpy/Documents/Bundles/BundleEntry.cs

+18-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ public sealed class BundleEntry {
2222
/// </summary>
2323
public string RelativePath { get; }
2424

25+
/// <summary>
26+
/// The offset of the entry's data.
27+
/// </summary>
28+
public long Offset { get; }
29+
30+
/// <summary>
31+
/// The size of the entry's data.
32+
/// </summary>
33+
public long Size { get; }
34+
2535
/// <summary>
2636
/// The file name of the entry.
2737
/// </summary>
@@ -44,15 +54,19 @@ public byte[] Data {
4454
}
4555
}
4656

47-
BundleEntry(BundleFileType type, string relativePath, byte[] data) {
57+
BundleEntry(BundleFileType type, string relativePath, long offset, long size, byte[] data) {
4858
Type = type;
4959
RelativePath = relativePath.Replace('/', '\\');
60+
Offset = offset;
61+
Size = size;
5062
this.data = data;
5163
}
5264

53-
BundleEntry(BundleFileType type, string relativePath, DataReader reader) {
65+
BundleEntry(BundleFileType type, string relativePath, long offset, long size, DataReader reader) {
5466
Type = type;
5567
RelativePath = relativePath.Replace('/', '\\');
68+
Offset = offset;
69+
Size = size;
5670
this.reader = reader;
5771
}
5872

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

6983
if (compSize == 0)
70-
res[i] = new BundleEntry(type, path, reader.Slice((uint)offset, (uint)size));
84+
res[i] = new BundleEntry(type, path, offset, size, reader.Slice((uint)offset, (uint)size));
7185
else
72-
res[i] = new BundleEntry(type, path, ReadCompressedEntryData(reader, offset, size, compSize));
86+
res[i] = new BundleEntry(type, path, offset, size, ReadCompressedEntryData(reader, offset, size, compSize));
7387
}
7488

7589
return res;

dnSpy/dnSpy.Contracts.DnSpy/Documents/DsDocument.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ protected override TList<IDsDocument> CreateChildren() {
359359
list.Add(document);
360360
}
361361
else if (entry.Type == BundleFileType.NativeBinary)
362-
list.Add(new DsPEDocument(new PEImage(entry.Data, Path.Combine(directoryOfBundle, entry.RelativePath))));
362+
list.Add(entry.Document = new DsPEDocument(new PEImage(entry.Data, Path.Combine(directoryOfBundle, entry.RelativePath))));
363363
}
364364

365365
return list;

dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/DocumentTreeViewConstants.cs

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ public static class DocumentTreeViewConstants {
5151
/// <summary><see cref="BundleFolderNode"/></summary>
5252
public const string BUNDLE_FOLDER_NODE_GUID = "BCF6AA92-94FF-4837-9E55-0C770FCB3BB4";
5353

54+
/// <summary><see cref="UnknownBundleEntryNode"/></summary>
55+
public const string BUNDLE_UNKNOWN_ENTRY_NODE_GUID = "582A8F1D-2D9E-476A-84B6-6053B983C374";
56+
57+
/// <summary><see cref="JsonBundleEntryNode"/></summary>
58+
public const string BUNDLE_JSON_ENTRY_NODE_GUID = "9C972EA7-9E52-4283-B38A-7C876A50F897";
59+
5460
/// <summary><see cref="ResourcesFolderNode"/></summary>
5561
public const string RESOURCES_FOLDER_NODE_GUID = "1DD75445-9DED-482F-B6EB-4FD13E4A2197";
5662

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Diagnostics;
2+
3+
namespace dnSpy.Contracts.Documents.TreeView {
4+
/// <summary>
5+
/// JSON bundle entry node
6+
/// </summary>
7+
public abstract class JsonBundleEntryNode : DocumentTreeNodeData {
8+
/// <summary>
9+
/// Constructor
10+
/// </summary>
11+
protected JsonBundleEntryNode(BundleEntry bundleEntry) => Debug2.Assert(bundleEntry is not null);
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Diagnostics;
2+
3+
namespace dnSpy.Contracts.Documents.TreeView {
4+
/// <summary>
5+
/// Unknown bundle entry node
6+
/// </summary>
7+
public abstract class UnknownBundleEntryNode : DocumentTreeNodeData {
8+
/// <summary>
9+
/// Constructor
10+
/// </summary>
11+
protected UnknownBundleEntryNode(BundleEntry bundleEntry) => Debug2.Assert(bundleEntry is not null);
12+
}
13+
}

dnSpy/dnSpy/Documents/TreeView/BundleDocumentNodeImpl.cs

+14
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ public override IEnumerable<TreeNodeData> CreateChildren() {
3131
foreach (var entry in Document.SingleFileBundle.TopLevelEntries) {
3232
if (entry.Document is not null)
3333
yield return Context.DocumentTreeView.CreateNode(this, entry.Document);
34+
else {
35+
switch (entry.Type) {
36+
case BundleFileType.Unknown:
37+
case BundleFileType.Symbols:
38+
yield return new UnknownBundleEntryNodeImpl(entry);
39+
break;
40+
case BundleFileType.DepsJson:
41+
case BundleFileType.RuntimeConfigJson:
42+
yield return new JsonBundleEntryNodeImpl(entry);
43+
break;
44+
default:
45+
throw new ArgumentOutOfRangeException();
46+
}
47+
}
3448
}
3549

3650
// TODO: return all bundle entries

dnSpy/dnSpy/Documents/TreeView/BundleFolderNodeImpl.cs

+14
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ public override IEnumerable<TreeNodeData> CreateChildren() {
3131
foreach (var entry in bundleFolder.Entries) {
3232
if (entry.Document is not null)
3333
yield return Context.DocumentTreeView.CreateNode(owner, entry.Document);
34+
else {
35+
switch (entry.Type) {
36+
case BundleFileType.Unknown:
37+
case BundleFileType.Symbols:
38+
yield return new UnknownBundleEntryNodeImpl(entry);
39+
break;
40+
case BundleFileType.DepsJson:
41+
case BundleFileType.RuntimeConfigJson:
42+
yield return new JsonBundleEntryNodeImpl(entry);
43+
break;
44+
default:
45+
throw new ArgumentOutOfRangeException();
46+
}
47+
}
3448
}
3549
}
3650

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Text;
3+
using dnSpy.Contracts.Decompiler;
4+
using dnSpy.Contracts.Documents;
5+
using dnSpy.Contracts.Documents.Tabs.DocViewer;
6+
using dnSpy.Contracts.Documents.TreeView;
7+
using dnSpy.Contracts.Images;
8+
using dnSpy.Contracts.Text;
9+
10+
namespace dnSpy.Documents.TreeView {
11+
public class JsonBundleEntryNodeImpl : JsonBundleEntryNode, IDecompileSelf {
12+
readonly BundleEntry bundleEntry;
13+
14+
public JsonBundleEntryNodeImpl(BundleEntry bundleEntry) : base(bundleEntry) => this.bundleEntry = bundleEntry;
15+
16+
public override Guid Guid => new Guid(DocumentTreeViewConstants.BUNDLE_JSON_ENTRY_NODE_GUID);
17+
18+
public override NodePathName NodePathName => new NodePathName(Guid);
19+
20+
protected override ImageReference GetIcon(IDotNetImageService dnImgMgr) => DsImages.TextFile;
21+
22+
protected override void WriteCore(ITextColorWriter output, IDecompiler decompiler, DocumentNodeWriteOptions options) {
23+
// TODO: better tooltip
24+
output.Write(BoxedTextColor.Text, bundleEntry.FileName);
25+
}
26+
27+
public bool Decompile(IDecompileNodeContext context) {
28+
//TODO: implement syntax highlighting
29+
context.Output.Write(Encoding.UTF8.GetString(bundleEntry.Data), BoxedTextColor.Text);
30+
return true;
31+
}
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using dnSpy.Contracts.Decompiler;
3+
using dnSpy.Contracts.Documents;
4+
using dnSpy.Contracts.Documents.TreeView;
5+
using dnSpy.Contracts.Images;
6+
using dnSpy.Contracts.Text;
7+
8+
namespace dnSpy.Documents.TreeView {
9+
sealed class UnknownBundleEntryNodeImpl : UnknownBundleEntryNode {
10+
readonly BundleEntry bundleEntry;
11+
12+
public UnknownBundleEntryNodeImpl(BundleEntry bundleEntry) : base(bundleEntry) {
13+
this.bundleEntry = bundleEntry;
14+
}
15+
16+
public override Guid Guid => new Guid(DocumentTreeViewConstants.BUNDLE_UNKNOWN_ENTRY_NODE_GUID);
17+
protected override ImageReference GetIcon(IDotNetImageService dnImgMgr) => DsImages.BinaryFile;
18+
public override NodePathName NodePathName => new NodePathName(Guid);
19+
20+
protected override void WriteCore(ITextColorWriter output, IDecompiler decompiler, DocumentNodeWriteOptions options) {
21+
// TODO: better tooltip
22+
output.Write(BoxedTextColor.Text, bundleEntry.FileName);
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)