Skip to content

Commit 373b004

Browse files
Save non-assembly files
1 parent a26a6ef commit 373b004

File tree

1 file changed

+75
-104
lines changed

1 file changed

+75
-104
lines changed

ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs

Lines changed: 75 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// DEALINGS IN THE SOFTWARE.
1818

1919
using System;
20+
using System.Collections.Generic;
2021
using System.Composition;
2122
using System.Diagnostics;
2223
using System.IO;
@@ -45,7 +46,7 @@ sealed class ExtractPackageEntryContextMenuEntry(DockWorkspace dockWorkspace) :
4546
{
4647
public void Execute(TextViewContext context)
4748
{
48-
var selectedNodes = Array.FindAll(context.SelectedTreeNodes, x => x is AssemblyTreeNode { PackageEntry: { } } or PackageFolderTreeNode);
49+
var selectedNodes = Array.FindAll(context.SelectedTreeNodes, IsBundleItem);
4950
// Get root assembly to infer the initial directory for the save dialog.
5051
var bundleNode = selectedNodes.FirstOrDefault()?.Ancestors().OfType<AssemblyTreeNode>()
5152
.FirstOrDefault(asm => asm.PackageEntry == null);
@@ -57,21 +58,17 @@ public void Execute(TextViewContext context)
5758
dlg.FileName = Path.GetFileName(WholeProjectDecompiler.SanitizeFileName(assembly.Name));
5859
dlg.Filter = ".NET assemblies|*.dll;*.exe;*.winmd" + Resources.AllFiles;
5960
dlg.InitialDirectory = Path.GetDirectoryName(bundleNode.LoadedAssembly.FileName);
60-
if (dlg.ShowDialog() != true)
61-
return;
62-
63-
string fileName = dlg.FileName;
64-
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
65-
AvalonEditTextOutput output = new AvalonEditTextOutput();
66-
Stopwatch stopwatch = Stopwatch.StartNew();
67-
SaveEntry(output, assembly, fileName);
68-
stopwatch.Stop();
69-
output.WriteLine(Resources.GenerationCompleteInSeconds, stopwatch.Elapsed.TotalSeconds.ToString("F1"));
70-
output.WriteLine();
71-
output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); });
72-
output.WriteLine();
73-
return output;
74-
}, ct)).Then(dockWorkspace.ShowText).HandleExceptions();
61+
if (dlg.ShowDialog() == true)
62+
Save(dockWorkspace, selectedNodes, dlg.FileName, true);
63+
}
64+
else if (selectedNodes is [ResourceTreeNode { Resource: { } resource }])
65+
{
66+
SaveFileDialog dlg = new SaveFileDialog();
67+
dlg.FileName = Path.GetFileName(WholeProjectDecompiler.SanitizeFileName(resource.Name));
68+
dlg.Filter = Resources.AllFiles[1..];
69+
dlg.InitialDirectory = Path.GetDirectoryName(bundleNode.LoadedAssembly.FileName);
70+
if (dlg.ShowDialog() == true)
71+
Save(dockWorkspace, selectedNodes, dlg.FileName, true);
7572
}
7673
else
7774
{
@@ -91,40 +88,7 @@ public void Execute(TextViewContext context)
9188
return;
9289
}
9390

94-
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
95-
AvalonEditTextOutput output = new AvalonEditTextOutput();
96-
Stopwatch stopwatch = Stopwatch.StartNew();
97-
foreach (var selectedNode in selectedNodes)
98-
{
99-
if (selectedNode is AssemblyTreeNode { PackageEntry: { } assembly })
100-
{
101-
string fileName = Path.Combine(folderName, GetFullPath(selectedNode.Parent) + WholeProjectDecompiler.SanitizeFileName(assembly.Name));
102-
SaveEntry(output, assembly, fileName);
103-
}
104-
else if (selectedNode is PackageFolderTreeNode)
105-
{
106-
selectedNode.EnsureLazyChildren();
107-
foreach (var node in selectedNode.DescendantsAndSelf())
108-
{
109-
if (node is AssemblyTreeNode { PackageEntry: { } asm })
110-
{
111-
string fileName = Path.Combine(folderName, GetFullPath(node.Parent) + WholeProjectDecompiler.SanitizeFileName(asm.Name));
112-
SaveEntry(output, asm, fileName);
113-
}
114-
else if (node is PackageFolderTreeNode)
115-
{
116-
Directory.CreateDirectory(Path.Combine(folderName, GetFullPath(node)));
117-
}
118-
}
119-
}
120-
}
121-
stopwatch.Stop();
122-
output.WriteLine(Resources.GenerationCompleteInSeconds, stopwatch.Elapsed.TotalSeconds.ToString("F1"));
123-
output.WriteLine();
124-
output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "\"" + folderName + "\""); });
125-
output.WriteLine();
126-
return output;
127-
}, ct)).Then(dockWorkspace.ShowText).HandleExceptions();
91+
Save(dockWorkspace, selectedNodes, folderName, false);
12892
}
12993
}
13094

@@ -140,7 +104,55 @@ static string GetFullPath(SharpTreeNode node)
140104
return null;
141105
}
142106

143-
void SaveEntry(ITextOutput output, PackageEntry entry, string targetFileName)
107+
internal static void Save(DockWorkspace dockWorkspace, IEnumerable<SharpTreeNode> nodes, string path, bool isFile)
108+
{
109+
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
110+
AvalonEditTextOutput output = new AvalonEditTextOutput();
111+
Stopwatch stopwatch = Stopwatch.StartNew();
112+
foreach (var node in nodes)
113+
{
114+
if (node is AssemblyTreeNode { PackageEntry: { } assembly })
115+
{
116+
string fileName = isFile ? path : Path.Combine(path, GetFullPath(node.Parent) + WholeProjectDecompiler.SanitizeFileName(assembly.Name));
117+
SaveEntry(output, assembly, fileName);
118+
}
119+
else if (node is ResourceTreeNode { Resource: PackageEntry { } resource })
120+
{
121+
string fileName = isFile ? path : Path.Combine(path, GetFullPath(node.Parent) + WholeProjectDecompiler.SanitizeFileName(resource.Name));
122+
SaveEntry(output, resource, fileName);
123+
}
124+
else if (node is PackageFolderTreeNode)
125+
{
126+
node.EnsureLazyChildren();
127+
foreach (var item in node.DescendantsAndSelf())
128+
{
129+
if (item is AssemblyTreeNode { PackageEntry: { } asm })
130+
{
131+
string fileName = Path.Combine(path, GetFullPath(item.Parent) + WholeProjectDecompiler.SanitizeFileName(asm.Name));
132+
SaveEntry(output, asm, fileName);
133+
}
134+
else if (item is ResourceTreeNode { Resource: PackageEntry { } entry })
135+
{
136+
string fileName = Path.Combine(path, GetFullPath(item.Parent) + WholeProjectDecompiler.SanitizeFileName(entry.Name));
137+
SaveEntry(output, entry, fileName);
138+
}
139+
else if (item is PackageFolderTreeNode)
140+
{
141+
Directory.CreateDirectory(Path.Combine(path, GetFullPath(item)));
142+
}
143+
}
144+
}
145+
}
146+
stopwatch.Stop();
147+
output.WriteLine(Resources.GenerationCompleteInSeconds, stopwatch.Elapsed.TotalSeconds.ToString("F1"));
148+
output.WriteLine();
149+
output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", isFile ? $"/select,\"{path}\"" : $"\"{path}\""); });
150+
output.WriteLine();
151+
return output;
152+
}, ct)).Then(dockWorkspace.ShowText).HandleExceptions();
153+
}
154+
155+
static void SaveEntry(ITextOutput output, PackageEntry entry, string targetFileName)
144156
{
145157
output.Write(entry.Name + ": ");
146158
using Stream stream = entry.TryOpenStream();
@@ -158,8 +170,16 @@ void SaveEntry(ITextOutput output, PackageEntry entry, string targetFileName)
158170

159171
public bool IsEnabled(TextViewContext context) => true;
160172

161-
public bool IsVisible(TextViewContext context) =>
162-
context.SelectedTreeNodes?.Any(x => x is AssemblyTreeNode { PackageEntry: { } } or PackageFolderTreeNode) == true;
173+
public bool IsVisible(TextViewContext context) => context.SelectedTreeNodes?.Any(IsBundleItem) == true;
174+
175+
static bool IsBundleItem(SharpTreeNode node)
176+
{
177+
if (node is AssemblyTreeNode { PackageEntry: { } } or PackageFolderTreeNode)
178+
return true;
179+
if (node is ResourceTreeNode { Resource: PackageEntry { } resource } && resource.FullName.StartsWith("bundle://"))
180+
return true;
181+
return false;
182+
}
163183
}
164184

165185
[ExportContextMenuEntry(Header = nameof(Resources.ExtractAllPackageEntries), Category = nameof(Resources.Save), Icon = "Images/Save")]
@@ -186,57 +206,8 @@ public void Execute(TextViewContext context)
186206
return;
187207
}
188208

189-
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
190-
AvalonEditTextOutput output = new AvalonEditTextOutput();
191-
Stopwatch stopwatch = Stopwatch.StartNew();
192-
asm.EnsureLazyChildren();
193-
foreach (var node in asm.Descendants())
194-
{
195-
if (node is AssemblyTreeNode { PackageEntry: { } assembly })
196-
{
197-
string fileName = Path.Combine(folderName, GetFullPath(node.Parent) + WholeProjectDecompiler.SanitizeFileName(assembly.Name));
198-
SaveEntry(output, assembly, fileName);
199-
}
200-
else if (node is PackageFolderTreeNode)
201-
{
202-
Directory.CreateDirectory(Path.Combine(folderName, GetFullPath(node)));
203-
}
204-
}
205-
stopwatch.Stop();
206-
output.WriteLine(Resources.GenerationCompleteInSeconds, stopwatch.Elapsed.TotalSeconds.ToString("F1"));
207-
output.WriteLine();
208-
output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "\"" + folderName + "\""); });
209-
output.WriteLine();
210-
return output;
211-
}, ct)).Then(dockWorkspace.ShowText).HandleExceptions();
212-
}
213-
214-
static string GetFullPath(SharpTreeNode node)
215-
{
216-
if (node is PackageFolderTreeNode)
217-
{
218-
string name = node.Text + "\\";
219-
if (GetFullPath(node.Parent) is string parent)
220-
return parent + "\\" + name;
221-
return name;
222-
}
223-
return null;
224-
}
225-
226-
void SaveEntry(ITextOutput output, PackageEntry entry, string targetFileName)
227-
{
228-
output.Write(entry.Name + ": ");
229-
using Stream stream = entry.TryOpenStream();
230-
if (stream == null)
231-
{
232-
output.WriteLine("Could not open stream!");
233-
return;
234-
}
235-
236-
stream.Position = 0;
237-
using FileStream fileStream = new FileStream(targetFileName, FileMode.OpenOrCreate);
238-
stream.CopyTo(fileStream);
239-
output.WriteLine("Written to " + targetFileName);
209+
asm.EnsureLazyChildren();
210+
ExtractPackageEntryContextMenuEntry.Save(dockWorkspace, asm.Descendants(), folderName, false);
240211
}
241212

242213
public bool IsEnabled(TextViewContext context) => true;

0 commit comments

Comments
 (0)