Browse Source

Refactor resource loading.

pull/2191/head
Daniel Grunwald 5 years ago
parent
commit
2d0df349d8
  1. 17
      ICSharpCode.Decompiler/Metadata/Dom.cs
  2. 6
      ILSpy.BamlDecompiler/BamlResourceEntryNode.cs
  3. 9
      ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
  4. 33
      ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs
  5. 1
      ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs
  6. 24
      ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs
  7. 5
      ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs
  8. 26
      ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs
  9. 39
      ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
  10. 9
      ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
  11. 9
      ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
  12. 20
      ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs
  13. 24
      ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs

17
ICSharpCode.Decompiler/Metadata/Dom.cs

@ -35,6 +35,23 @@ namespace ICSharpCode.Decompiler.Metadata
public abstract Stream TryOpenStream(); public abstract Stream TryOpenStream();
} }
public class ByteArrayResource : Resource
{
public override string Name { get; }
byte[] data;
public ByteArrayResource(string name, byte[] data)
{
this.Name = name ?? throw new ArgumentNullException(nameof(name));
this.data = data ?? throw new ArgumentNullException(nameof(data));
}
public override Stream TryOpenStream()
{
return new MemoryStream(data);
}
}
sealed class MetadataResource : Resource sealed class MetadataResource : Resource
{ {
public PEFile Module { get; } public PEFile Module { get; }

6
ILSpy.BamlDecompiler/BamlResourceEntryNode.cs

@ -42,7 +42,7 @@ namespace ILSpy.BamlDecompiler
{ {
public sealed class BamlResourceEntryNode : ResourceEntryNode public sealed class BamlResourceEntryNode : ResourceEntryNode
{ {
public BamlResourceEntryNode(string key, Stream data) : base(key, data) public BamlResourceEntryNode(string key, Func<Stream> data) : base(key, data)
{ {
} }
@ -74,8 +74,8 @@ namespace ILSpy.BamlDecompiler
bool LoadBaml(AvalonEditTextOutput output, CancellationToken cancellationToken) bool LoadBaml(AvalonEditTextOutput output, CancellationToken cancellationToken)
{ {
var asm = this.Ancestors().OfType<AssemblyTreeNode>().FirstOrDefault().LoadedAssembly; var asm = this.Ancestors().OfType<AssemblyTreeNode>().FirstOrDefault().LoadedAssembly;
Data.Position = 0; using var data = OpenStream();
XDocument xamlDocument = LoadIntoDocument(asm.GetPEFileOrNull(), asm.GetAssemblyResolver(), Data, cancellationToken); XDocument xamlDocument = LoadIntoDocument(asm.GetPEFileOrNull(), asm.GetAssemblyResolver(), data, cancellationToken);
output.Write(xamlDocument.ToString()); output.Write(xamlDocument.ToString());
return true; return true;
} }

9
ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs

@ -31,13 +31,8 @@ namespace ILSpy.BamlDecompiler
{ {
public ILSpyTreeNode CreateNode(Resource resource) public ILSpyTreeNode CreateNode(Resource resource)
{ {
return null; if (resource.Name.EndsWith(".baml", StringComparison.OrdinalIgnoreCase))
} return new BamlResourceEntryNode(resource.Name, resource.TryOpenStream);
public ILSpyTreeNode CreateNode(string key, object data)
{
if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase) && data is Stream stream)
return new BamlResourceEntryNode(key, stream);
else else
return null; return null;
} }

33
ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs

@ -36,20 +36,11 @@ namespace ICSharpCode.ILSpy.TreeNodes
public ILSpyTreeNode CreateNode(Resource resource) public ILSpyTreeNode CreateNode(Resource resource)
{ {
Stream stream = resource.TryOpenStream(); string key = resource.Name;
if (stream == null)
return null;
return CreateNode(resource.Name, stream);
}
public ILSpyTreeNode CreateNode(string key, object data)
{
if (!(data is Stream))
return null;
foreach (string fileExt in imageFileExtensions) foreach (string fileExt in imageFileExtensions)
{ {
if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase))
return new CursorResourceEntryNode(key, (Stream)data); return new CursorResourceEntryNode(key, resource.TryOpenStream);
} }
return null; return null;
} }
@ -57,8 +48,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
sealed class CursorResourceEntryNode : ResourceEntryNode sealed class CursorResourceEntryNode : ResourceEntryNode
{ {
public CursorResourceEntryNode(string key, Stream data) public CursorResourceEntryNode(string key, Func<Stream> openStream)
: base(key, data) : base(key, openStream)
{ {
} }
@ -69,19 +60,23 @@ namespace ICSharpCode.ILSpy.TreeNodes
try try
{ {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
Data.Position = 0;
BitmapImage image = new BitmapImage(); BitmapImage image = new BitmapImage();
byte[] curData;
using (var data = OpenStream())
{
if (data == null)
return false;
//HACK: windows imaging does not understand that .cur files have the same layout as .ico //HACK: windows imaging does not understand that .cur files have the same layout as .ico
// so load to data, and modify the ResourceType in the header to make look like an icon... // so load to data, and modify the ResourceType in the header to make look like an icon...
MemoryStream s = Data as MemoryStream; MemoryStream s = data as MemoryStream;
if (null == s) if (s == null)
{ {
// data was stored in another stream type (e.g. PinnedBufferedMemoryStream) // data was stored in another stream type (e.g. PinnedBufferedMemoryStream)
s = new MemoryStream(); s = new MemoryStream();
Data.CopyTo(s); data.CopyTo(s);
}
curData = s.ToArray();
} }
byte[] curData = s.ToArray();
curData[2] = 1; curData[2] = 1;
using (Stream stream = new MemoryStream(curData)) using (Stream stream = new MemoryStream(curData))
{ {

1
ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs

@ -26,6 +26,5 @@ namespace ICSharpCode.ILSpy.TreeNodes
public interface IResourceNodeFactory public interface IResourceNodeFactory
{ {
ILSpyTreeNode CreateNode(Resource resource); ILSpyTreeNode CreateNode(Resource resource);
ILSpyTreeNode CreateNode(string key, object data);
} }
} }

24
ILSpy/TreeNodes/ResourceNodes/IconResourceEntryNode.cs

@ -34,29 +34,17 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
public ILSpyTreeNode CreateNode(Resource resource) public ILSpyTreeNode CreateNode(Resource resource)
{ {
Stream stream = resource.TryOpenStream(); if (resource.Name.EndsWith(".ico", StringComparison.OrdinalIgnoreCase))
if (stream == null)
return null;
return CreateNode(resource.Name, stream);
}
public ILSpyTreeNode CreateNode(string key, object data)
{ {
if (data is System.Drawing.Icon) return new IconResourceEntryNode(resource.Name, resource.TryOpenStream);
{
MemoryStream s = new MemoryStream();
((System.Drawing.Icon)data).Save(s);
return new IconResourceEntryNode(key, s);
} }
if (data is Stream && key.EndsWith(".ico", StringComparison.OrdinalIgnoreCase))
return new IconResourceEntryNode(key, (Stream)data);
return null; return null;
} }
} }
sealed class IconResourceEntryNode : ResourceEntryNode sealed class IconResourceEntryNode : ResourceEntryNode
{ {
public IconResourceEntryNode(string key, Stream data) public IconResourceEntryNode(string key, Func<Stream> data)
: base(key, data) : base(key, data)
{ {
} }
@ -68,8 +56,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
try try
{ {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
Data.Position = 0; using var data = OpenStream();
IconBitmapDecoder decoder = new IconBitmapDecoder(Data, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None); if (data == null)
return false;
IconBitmapDecoder decoder = new IconBitmapDecoder(data, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
foreach (var frame in decoder.Frames) foreach (var frame in decoder.Frames)
{ {
output.Write(String.Format("{0}x{1}, {2} bit: ", frame.PixelHeight, frame.PixelWidth, frame.Thumbnail.Format.BitsPerPixel)); output.Write(String.Format("{0}x{1}, {2} bit: ", frame.PixelHeight, frame.PixelWidth, frame.Thumbnail.Format.BitsPerPixel));

5
ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs

@ -18,6 +18,7 @@
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
@ -65,7 +66,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
int i = 0; int i = 0;
foreach (Image image in this.data.Images) foreach (Image image in this.data.Images)
{ {
var node = ResourceEntryNode.Create("Image" + i.ToString(), image); using var s = new MemoryStream();
image.Save(s, System.Drawing.Imaging.ImageFormat.Bmp);
var node = ResourceEntryNode.Create("Image" + i.ToString(), s.ToArray());
if (node != null) if (node != null)
Children.Add(node); Children.Add(node);
++i; ++i;

26
ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs

@ -36,26 +36,11 @@ namespace ICSharpCode.ILSpy.TreeNodes
public ILSpyTreeNode CreateNode(Resource resource) public ILSpyTreeNode CreateNode(Resource resource)
{ {
Stream stream = resource.TryOpenStream(); string key = resource.Name;
if (stream == null)
return null;
return CreateNode(resource.Name, stream);
}
public ILSpyTreeNode CreateNode(string key, object data)
{
if (data is System.Drawing.Image)
{
MemoryStream s = new MemoryStream();
((System.Drawing.Image)data).Save(s, System.Drawing.Imaging.ImageFormat.Bmp);
return new ImageResourceEntryNode(key, s);
}
if (!(data is Stream))
return null;
foreach (string fileExt in imageFileExtensions) foreach (string fileExt in imageFileExtensions)
{ {
if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase))
return new ImageResourceEntryNode(key, (Stream)data); return new ImageResourceEntryNode(key, resource.TryOpenStream);
} }
return null; return null;
} }
@ -63,8 +48,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
sealed class ImageResourceEntryNode : ResourceEntryNode sealed class ImageResourceEntryNode : ResourceEntryNode
{ {
public ImageResourceEntryNode(string key, Stream data) public ImageResourceEntryNode(string key, Func<Stream> openStream)
: base(key, data) : base(key, openStream)
{ {
} }
@ -75,10 +60,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
try try
{ {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
Data.Position = 0;
BitmapImage image = new BitmapImage(); BitmapImage image = new BitmapImage();
image.BeginInit(); image.BeginInit();
image.StreamSource = Data; image.StreamSource = OpenStream();
image.EndInit(); image.EndInit();
output.AddUIElement(() => new Image { Source = image }); output.AddUIElement(() => new Image { Source = image });
output.WriteLine(); output.WriteLine();

39
ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs

@ -20,6 +20,7 @@ using System;
using System.IO; using System.IO;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using Microsoft.Win32; using Microsoft.Win32;
@ -32,42 +33,47 @@ namespace ICSharpCode.ILSpy.TreeNodes
public class ResourceEntryNode : ILSpyTreeNode public class ResourceEntryNode : ILSpyTreeNode
{ {
private readonly string key; private readonly string key;
private readonly Stream data; private readonly Func<Stream> openStream;
public override object Text => this.key; public override object Text => this.key;
public override object Icon => Images.Resource; public override object Icon => Images.Resource;
protected Stream Data => data; protected Stream OpenStream()
{
return openStream();
}
public ResourceEntryNode(string key, Stream data) public ResourceEntryNode(string key, Func<Stream> openStream)
{ {
if (key == null) if (key == null)
throw new ArgumentNullException(nameof(key)); throw new ArgumentNullException(nameof(key));
if (data == null) if (openStream == null)
throw new ArgumentNullException(nameof(data)); throw new ArgumentNullException(nameof(openStream));
this.key = key; this.key = key;
this.data = data; this.openStream = openStream;
} }
public static ILSpyTreeNode Create(string key, object data) public static ILSpyTreeNode Create(Resource resource)
{ {
ILSpyTreeNode result = null; ILSpyTreeNode result = null;
foreach (var factory in App.ExportProvider.GetExportedValues<IResourceNodeFactory>()) foreach (var factory in App.ExportProvider.GetExportedValues<IResourceNodeFactory>())
{ {
result = factory.CreateNode(key, data); result = factory.CreateNode(resource);
if (result != null) if (result != null)
return result; break;
}
return result ?? new ResourceTreeNode(resource);
} }
var streamData = data as Stream;
if (streamData != null)
result = new ResourceEntryNode(key, data as Stream);
return result; public static ILSpyTreeNode Create(string name, byte[] data)
{
return Create(new ByteArrayResource(name, data));
} }
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{ {
using var data = OpenStream();
language.WriteCommentLine(output, string.Format("{0} = {1}", key, data)); language.WriteCommentLine(output, string.Format("{0} = {1}", key, data));
} }
@ -77,13 +83,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
dlg.FileName = Path.GetFileName(DecompilerTextView.CleanUpName(key)); dlg.FileName = Path.GetFileName(DecompilerTextView.CleanUpName(key));
if (dlg.ShowDialog() == true) if (dlg.ShowDialog() == true)
{ {
var data = this.Data; using var data = OpenStream();
data.Position = 0; using var fs = dlg.OpenFile();
using (var fs = dlg.OpenFile())
{
data.CopyTo(fs); data.CopyTo(fs);
} }
}
return true; return true;
} }
} }

9
ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs

@ -119,14 +119,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public static ILSpyTreeNode Create(Resource resource) public static ILSpyTreeNode Create(Resource resource)
{ {
ILSpyTreeNode result = null; return ResourceEntryNode.Create(resource);
foreach (var factory in App.ExportProvider.GetExportedValues<IResourceNodeFactory>())
{
result = factory.CreateNode(resource);
if (result != null)
break;
}
return result ?? new ResourceTreeNode(resource);
} }
} }
} }

9
ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs

@ -99,14 +99,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (entry.Value is byte[]) if (entry.Value is byte[])
{ {
Children.Add(ResourceEntryNode.Create(entry.Key, new MemoryStream((byte[])entry.Value))); Children.Add(ResourceEntryNode.Create(entry.Key, (byte[])entry.Value));
return;
}
var node = ResourceEntryNode.Create(entry.Key, entry.Value);
if (node != null)
{
Children.Add(node);
return; return;
} }

20
ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs

@ -34,13 +34,8 @@ namespace ICSharpCode.ILSpy.Xaml
{ {
public ILSpyTreeNode CreateNode(Resource resource) public ILSpyTreeNode CreateNode(Resource resource)
{ {
return null; if (resource.Name.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase))
} return new XamlResourceEntryNode(resource.Name, resource.TryOpenStream);
public ILSpyTreeNode CreateNode(string key, object data)
{
if (key.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase) && data is Stream)
return new XamlResourceEntryNode(key, (Stream)data);
else else
return null; return null;
} }
@ -50,7 +45,7 @@ namespace ICSharpCode.ILSpy.Xaml
{ {
string xaml; string xaml;
public XamlResourceEntryNode(string key, Stream data) : base(key, data) public XamlResourceEntryNode(string key, Func<Stream> openStream) : base(key, openStream)
{ {
} }
@ -67,7 +62,14 @@ namespace ICSharpCode.ILSpy.Xaml
// cache read XAML because stream will be closed after first read // cache read XAML because stream will be closed after first read
if (xaml == null) if (xaml == null)
{ {
using (var reader = new StreamReader(Data)) using var data = OpenStream();
if (data == null)
{
output.Write("ILSpy: Failed opening resource stream.");
output.WriteLine();
return output;
}
using (var reader = new StreamReader(data))
{ {
xaml = reader.ReadToEnd(); xaml = reader.ReadToEnd();
} }

24
ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs

@ -36,20 +36,11 @@ namespace ICSharpCode.ILSpy.Xaml
public ILSpyTreeNode CreateNode(Resource resource) public ILSpyTreeNode CreateNode(Resource resource)
{ {
Stream stream = resource.TryOpenStream(); string key = resource.Name;
if (stream == null)
return null;
return CreateNode(resource.Name, stream);
}
public ILSpyTreeNode CreateNode(string key, object data)
{
if (!(data is Stream))
return null;
foreach (string fileExt in xmlFileExtensions) foreach (string fileExt in xmlFileExtensions)
{ {
if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase))
return new XmlResourceEntryNode(key, (Stream)data); return new XmlResourceEntryNode(key, resource.TryOpenStream);
} }
return null; return null;
} }
@ -59,7 +50,7 @@ namespace ICSharpCode.ILSpy.Xaml
{ {
string xml; string xml;
public XmlResourceEntryNode(string key, Stream data) public XmlResourceEntryNode(string key, Func<Stream> data)
: base(key, data) : base(key, data)
{ {
} }
@ -91,7 +82,14 @@ namespace ICSharpCode.ILSpy.Xaml
// cache read XAML because stream will be closed after first read // cache read XAML because stream will be closed after first read
if (xml == null) if (xml == null)
{ {
using (var reader = new StreamReader(Data)) using var data = OpenStream();
if (data == null)
{
output.Write("ILSpy: Failed opening resource stream.");
output.WriteLine();
return output;
}
using (var reader = new StreamReader(data))
{ {
xml = reader.ReadToEnd(); xml = reader.ReadToEnd();
} }

Loading…
Cancel
Save