diff --git a/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedImageUtilities.cs b/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedImageUtilities.cs
index de4d0add50..a1675056b2 100644
--- a/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedImageUtilities.cs
+++ b/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedImageUtilities.cs
@@ -20,6 +20,7 @@ You should have received a copy of the GNU General Public License
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
+using System.Text;
using dnlib.DotNet;
using dnlib.DotNet.Resources;
@@ -36,34 +37,84 @@ public static class SerializedImageUtilities {
/// Serialized data
/// Updated with the image data
///
- public static bool GetImageData(ModuleDef? module, string typeName, byte[] serializedData, [NotNullWhen(true)] out byte[]? imageData) {
+ public static bool GetImageData(ModuleDef? module, string typeName, byte[] serializedData, [NotNullWhen(true)] out byte[]? imageData) =>
+ GetImageData(module, typeName, serializedData, SerializationFormat.BinaryFormatter, out imageData);
+
+ ///
+ /// Gets the image data
+ ///
+ /// Module
+ /// Name of type
+ /// Serialized data
+ /// Format of serialized data
+ /// Updated with the image data
+ ///
+ public static bool GetImageData(ModuleDef? module, string typeName, byte[] serializedData, SerializationFormat format, [NotNullWhen(true)] out byte[]? imageData) {
imageData = null;
+
if (CouldBeBitmap(module, typeName)) {
- var dict = Deserializer.Deserialize(SystemDrawingBitmap.DefinitionAssembly.FullName, SystemDrawingBitmap.ReflectionFullName, serializedData);
- // Bitmap loops over every item looking for "Data" (case insensitive)
- foreach (var v in dict.Values) {
- var d = v.Value as byte[];
- if (d is null)
- continue;
- if ("Data".Equals(v.Name, StringComparison.OrdinalIgnoreCase)) {
- imageData = d;
- return true;
+ if (format == SerializationFormat.BinaryFormatter) {
+ var dict = Deserializer.Deserialize(SystemDrawingBitmap.DefinitionAssembly.FullName, SystemDrawingBitmap.ReflectionFullName, serializedData);
+ // Bitmap loops over every item looking for "Data" (case insensitive)
+ foreach (var v in dict.Values) {
+ var d = v.Value as byte[];
+ if (d is null)
+ continue;
+ if ("Data".Equals(v.Name, StringComparison.OrdinalIgnoreCase)) {
+ imageData = d;
+ return true;
+ }
}
+ return false;
+ }
+ if (format == SerializationFormat.ActivatorStream) {
+ imageData = serializedData;
+ return true;
+ }
+ if (format == SerializationFormat.TypeConverterByteArray) {
+ imageData = GetBitmapData(serializedData) ?? serializedData;
+ return true;
}
- return false;
}
if (CouldBeIcon(module, typeName)) {
- var dict = Deserializer.Deserialize(SystemDrawingIcon.DefinitionAssembly.FullName, SystemDrawingIcon.ReflectionFullName, serializedData);
- if (!dict.TryGetValue("IconData", out var info))
- return false;
- imageData = info.Value as byte[];
- return imageData is not null;
+ if (format == SerializationFormat.BinaryFormatter) {
+ var dict = Deserializer.Deserialize(SystemDrawingIcon.DefinitionAssembly.FullName, SystemDrawingIcon.ReflectionFullName, serializedData);
+ if (!dict.TryGetValue("IconData", out var info))
+ return false;
+ imageData = info.Value as byte[];
+ return imageData is not null;
+ }
+ if (format == SerializationFormat.ActivatorStream || format == SerializationFormat.TypeConverterByteArray) {
+ imageData = serializedData;
+ return true;
+ }
}
return false;
}
+ static byte[]? GetBitmapData(byte[] rawData) {
+ // Based on ImageConverter.GetBitmapStream
+ // See https://github.com/dotnet/winforms/blob/main/src/System.Drawing.Common/src/System/Drawing/ImageConverter.cs
+ if (rawData.Length <= 18)
+ return null;
+
+ short sig = (short)(rawData[0] | rawData[1] << 8);
+ if (sig != 0x1C15)
+ return null;
+
+ short headerSize = (short)(rawData[2] | rawData[3] << 8);
+ if (rawData.Length <= headerSize + 18)
+ return null;
+ if (Encoding.ASCII.GetString(rawData, headerSize + 12, 6) != "PBrush")
+ return null;
+
+ var newData = new byte[rawData.Length - 78];
+ Buffer.BlockCopy(rawData, 78, newData, 0, newData.Length);
+ return newData;
+ }
+
static bool CouldBeBitmap(ModuleDef? module, string name) => CheckType(module, name, SystemDrawingBitmap);
static bool CouldBeIcon(ModuleDef? module, string name) => CheckType(module, name, SystemDrawingIcon);
diff --git a/dnSpy/dnSpy/Documents/TreeView/Resources/SerializedImageResourceElementNode.cs b/dnSpy/dnSpy/Documents/TreeView/Resources/SerializedImageResourceElementNode.cs
index d17a7ef783..045ad294e8 100644
--- a/dnSpy/dnSpy/Documents/TreeView/Resources/SerializedImageResourceElementNode.cs
+++ b/dnSpy/dnSpy/Documents/TreeView/Resources/SerializedImageResourceElementNode.cs
@@ -42,7 +42,7 @@ sealed class SerializedImageResourceElementNodeProvider : IResourceNodeProvider
if (serializedData is null)
return null;
- if (SerializedImageUtilities.GetImageData(module, serializedData.TypeName, serializedData.Data, out var imageData))
+ if (SerializedImageUtilities.GetImageData(module, serializedData.TypeName, serializedData.Data, serializedData.Format, out var imageData))
return new SerializedImageResourceElementNodeImpl(treeNodeGroup, resourceElement, imageData);
return null;
@@ -94,7 +94,7 @@ protected override IEnumerable GetDeserializedData() {
return res;
var binData = (BinaryResourceData)newResElem.ResourceData;
- if (!SerializedImageUtilities.GetImageData(this.GetModule(), binData.TypeName, binData.Data, out var imageData))
+ if (!SerializedImageUtilities.GetImageData(this.GetModule(), binData.TypeName, binData.Data, binData.Format, out var imageData))
return dnSpy_Resources.NewDataIsNotAnImage;
try {
@@ -111,7 +111,7 @@ public override void UpdateData(ResourceElement newResElem) {
base.UpdateData(newResElem);
var binData = (BinaryResourceData)newResElem.ResourceData;
- SerializedImageUtilities.GetImageData(this.GetModule(), binData.TypeName, binData.Data, out var imageData);
+ SerializedImageUtilities.GetImageData(this.GetModule(), binData.TypeName, binData.Data, binData.Format, out var imageData);
Debug2.Assert(imageData is not null);
InitializeImageData(imageData);
}