From efe9817fc156ca7aac540f176fc54f5858dbb781 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Tue, 5 Sep 2023 20:31:17 +0200 Subject: [PATCH] Extend support for new serialization formats --- .../Resources/ResourceCommands.cs | 3 +- .../Resources/SerializedImageUtilities.cs | 33 ++++++++++- .../SerializedResourceElementNode.cs | 58 +++++++++++++++++-- 3 files changed, 85 insertions(+), 9 deletions(-) diff --git a/Extensions/dnSpy.AsmEditor/Resources/ResourceCommands.cs b/Extensions/dnSpy.AsmEditor/Resources/ResourceCommands.cs index 8bc9bf5ee4..430cd24bb6 100644 --- a/Extensions/dnSpy.AsmEditor/Resources/ResourceCommands.cs +++ b/Extensions/dnSpy.AsmEditor/Resources/ResourceCommands.cs @@ -2038,7 +2038,8 @@ static void Execute(Lazy undoCommandService, IAppService ap var opts = data.CreateResourceElementOptions(); string? error; try { - opts = new ResourceElementOptions(SerializedImageUtilities.Serialize(opts.Create())); + var format = ((BinaryResourceData)imgRsrcElNode.ResourceElement.ResourceData).Format; + opts = new ResourceElementOptions(SerializedImageUtilities.Serialize(opts.Create(), format)); error = imgRsrcElNode.CheckCanUpdateData(opts.Create()); } catch (Exception ex) { diff --git a/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedImageUtilities.cs b/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedImageUtilities.cs index a1675056b2..ef778c4e7f 100644 --- a/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedImageUtilities.cs +++ b/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedImageUtilities.cs @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License */ using System; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; @@ -150,7 +151,15 @@ public static bool CheckType(ModuleDef? module, string name, TypeRef expectedTyp /// /// Resource element /// - public static ResourceElement Serialize(ResourceElement resElem) { + public static ResourceElement Serialize(ResourceElement resElem) => Serialize(resElem, SerializationFormat.BinaryFormatter); + + /// + /// Serializes the image + /// + /// Resource element + /// Serialization format to use + /// + public static ResourceElement Serialize(ResourceElement resElem, SerializationFormat format) { var data = (byte[])((BuiltInResourceData)resElem.ResourceData).Data; bool isIcon = BitConverter.ToUInt32(data, 0) == 0x00010000; @@ -165,9 +174,29 @@ public static ResourceElement Serialize(ResourceElement resElem) { typeName = SystemDrawingBitmap.AssemblyQualifiedName; } + byte[] serializedData; + if (format == SerializationFormat.BinaryFormatter) { + serializedData = SerializationUtilities.Serialize(obj); + } + else if (format == SerializationFormat.TypeConverterByteArray) { + var converter = TypeDescriptor.GetConverter(obj.GetType()); + serializedData = (byte[])converter.ConvertTo(obj, typeof(byte[])); + } + else if (format == SerializationFormat.ActivatorStream) { + using (var stream = new MemoryStream()) { + if (obj is System.Drawing.Bitmap bitmap) + bitmap.Save(stream, bitmap.RawFormat); + else + ((System.Drawing.Icon)obj).Save(stream); + serializedData = stream.ToArray(); + } + } + else + throw new ArgumentOutOfRangeException(); + return new ResourceElement { Name = resElem.Name, - ResourceData = new BinaryResourceData(new UserResourceType(typeName, ResourceTypeCode.UserTypes), SerializationUtilities.Serialize(obj), SerializationFormat.BinaryFormatter), + ResourceData = new BinaryResourceData(new UserResourceType(typeName, ResourceTypeCode.UserTypes), serializedData, format), }; } } diff --git a/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedResourceElementNode.cs b/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedResourceElementNode.cs index 8560f692fb..50acb6a645 100644 --- a/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedResourceElementNode.cs +++ b/dnSpy/dnSpy.Contracts.DnSpy/Documents/TreeView/Resources/SerializedResourceElementNode.cs @@ -17,10 +17,13 @@ You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ +using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Runtime.Serialization.Formatters.Binary; +using System.Text; using System.Threading; using dnlib.DotNet.Resources; using dnSpy.Contracts.Images; @@ -91,16 +94,59 @@ public void Deserialize() { if (!CanDeserialize) return; - var serializedData = ((BinaryResourceData)ResourceElement.ResourceData).Data; - var formatter = new BinaryFormatter(); - try { + var binaryResourceData = ((BinaryResourceData)ResourceElement.ResourceData); + var serializedData = binaryResourceData.Data; + if (binaryResourceData.Format == SerializationFormat.BinaryFormatter) { + var formatter = new BinaryFormatter(); + try { #pragma warning disable SYSLIB0011 - deserializedData = formatter.Deserialize(new MemoryStream(serializedData)); + deserializedData = formatter.Deserialize(new MemoryStream(serializedData)); #pragma warning restore SYSLIB0011 + } + catch { + return; + } } - catch { - return; + else if (binaryResourceData.Format == SerializationFormat.TypeConverterByteArray) { + try { + var type = Type.GetType(binaryResourceData.TypeName); + if (type is null) + return; + var converter = TypeDescriptor.GetConverter(type); + if (converter is null) + return; + deserializedData = converter.ConvertFrom(serializedData); + } + catch { + return; + } } + else if (binaryResourceData.Format == SerializationFormat.TypeConverterString) { + try { + var type = Type.GetType(binaryResourceData.TypeName); + if (type is null) + return; + var converter = TypeDescriptor.GetConverter(type); + if (converter is null) + return; + deserializedData = converter.ConvertFromInvariantString(Encoding.UTF8.GetString(serializedData)); + } + catch { + return; + } + } + else if (binaryResourceData.Format == SerializationFormat.ActivatorStream) { + try { + var type = Type.GetType(binaryResourceData.TypeName); + if (type is null) + return; + deserializedData = Activator.CreateInstance(type, new MemoryStream(serializedData)); + } + catch { + return; + } + } + if (deserializedData is null) return;