From f9ae51b12adb0eb3a056d7b428f2ee1977c18768 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 6 Oct 2024 09:24:25 +0200 Subject: [PATCH] Fix #3001: Support new resources format in ResourcesFile/ResXResourceWriter --- .../ICSharpCode.Decompiler.Tests.csproj | 2 - .../Util/ResXResourceWriter.cs | 6 +- ICSharpCode.Decompiler/Util/ResourcesFile.cs | 36 +++-- ILSpy.Tests/BitmapContainer.resources | Bin 0 -> 1158 bytes ILSpy.Tests/ILSpy.Tests.csproj | 13 ++ ILSpy.Tests/Icon.ico | Bin 0 -> 45451 bytes ILSpy.Tests/IconContainer.resx | 124 ++++++++++++++++++ .../ResourceReaderWriterTests.cs | 99 ++++++++++---- .../Util => ILSpy.Tests}/Test.resources | Bin 9 files changed, 239 insertions(+), 41 deletions(-) create mode 100644 ILSpy.Tests/BitmapContainer.resources create mode 100644 ILSpy.Tests/Icon.ico create mode 100644 ILSpy.Tests/IconContainer.resx rename {ICSharpCode.Decompiler.Tests/Util => ILSpy.Tests}/ResourceReaderWriterTests.cs (63%) rename {ICSharpCode.Decompiler.Tests/Util => ILSpy.Tests}/Test.resources (100%) diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index f1b1e5777..3f60f4548 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -130,7 +130,6 @@ - @@ -356,7 +355,6 @@ - diff --git a/ICSharpCode.Decompiler/Util/ResXResourceWriter.cs b/ICSharpCode.Decompiler/Util/ResXResourceWriter.cs index 7d18ef551..80d712353 100644 --- a/ICSharpCode.Decompiler/Util/ResXResourceWriter.cs +++ b/ICSharpCode.Decompiler/Util/ResXResourceWriter.cs @@ -36,6 +36,8 @@ using System.IO; using System.Text; using System.Xml; +using ICSharpCode.Decompiler.Metadata; + namespace ICSharpCode.Decompiler.Util { #if INSIDE_SYSTEM_WEB @@ -150,7 +152,7 @@ namespace ICSharpCode.Decompiler.Util { writer.WriteAttributeString("mimetype", BinSerializedObjectMimeType); writer.WriteStartElement("value"); - writer.WriteBase64(value, offset, length); + WriteNiceBase64(value, offset, length); } writer.WriteEndElement(); @@ -274,7 +276,7 @@ namespace ICSharpCode.Decompiler.Util break; case ResourceSerializedObject rso: var bytes = rso.GetBytes(); - WriteBytes(name, null, bytes, 0, bytes.Length, comment); + WriteBytes(name, rso.TypeName, bytes, 0, bytes.Length, comment); break; default: throw new NotSupportedException($"Value '{value}' of type {value.GetType().FullName} is not supported by this version of ResXResourceWriter. Use byte arrays or streams instead."); diff --git a/ICSharpCode.Decompiler/Util/ResourcesFile.cs b/ICSharpCode.Decompiler/Util/ResourcesFile.cs index 988fa01a2..5ef294a1f 100644 --- a/ICSharpCode.Decompiler/Util/ResourcesFile.cs +++ b/ICSharpCode.Decompiler/Util/ResourcesFile.cs @@ -76,12 +76,21 @@ namespace ICSharpCode.Decompiler.Util StartOfUserTypes = 0x40 } + enum SerializationFormat + { + BinaryFormatter = 1, + TypeConverterByteArray = 2, + TypeConverterString = 3, + ActivatorStream = 4 + } + /// Holds the number used to identify resource files. public const int MagicNumber = unchecked((int)0xBEEFCACE); const int ResourceSetVersion = 2; readonly MyBinaryReader reader; readonly int version; + readonly bool usesSerializationFormat; readonly int numResources; readonly string[] typeTable; readonly int[] namePositions; @@ -94,7 +103,7 @@ namespace ICSharpCode.Decompiler.Util /// Creates a new ResourcesFile. /// /// Input stream. - /// Whether the stream should be help open when the ResourcesFile is disposed. + /// Whether the stream should be held open when the ResourcesFile is disposed. /// /// The stream is must be held open while the ResourcesFile is in use. /// The stream must be seekable; any operation using the ResourcesFile will end up seeking the stream. @@ -130,7 +139,8 @@ namespace ICSharpCode.Decompiler.Util // We don't care about numBytesToSkip; read the rest of the header // readerType: - reader.ReadString(); + string readerType = reader.ReadString(); + usesSerializationFormat = readerType == "System.Resources.Extensions.DeserializingResourceReader, System.Resources.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"; // resourceSetType: reader.ReadString(); } @@ -369,7 +379,7 @@ namespace ICSharpCode.Decompiler.Util bits[i] = reader.ReadInt32(); return new decimal(bits); default: - return new ResourceSerializedObject(FindType(typeIndex), this, reader.BaseStream.Position); + return new ResourceSerializedObject(FindType(typeIndex), this, reader.BaseStream.Position, usesSerializationFormat); } } @@ -461,7 +471,7 @@ namespace ICSharpCode.Decompiler.Util { throw new BadImageFormatException("Invalid typeCode"); } - return new ResourceSerializedObject(FindType(typeCode - ResourceTypeCode.StartOfUserTypes), this, reader.BaseStream.Position); + return new ResourceSerializedObject(FindType(typeCode - ResourceTypeCode.StartOfUserTypes), this, reader.BaseStream.Position, usesSerializationFormat); } } @@ -509,7 +519,7 @@ namespace ICSharpCode.Decompiler.Util } } - internal byte[] GetBytesForSerializedObject(long pos) + internal byte[] GetBytesForSerializedObject(long pos, bool usesSerializationFormat) { long[] positions = GetStartPositions(); int i = Array.BinarySearch(positions, pos); @@ -535,6 +545,12 @@ namespace ICSharpCode.Decompiler.Util } int len = (int)(endPos - pos); reader.Seek(pos, SeekOrigin.Begin); + if (usesSerializationFormat) + { + int kind = reader.Read7BitEncodedInt(); + Debug.Assert(Enum.IsDefined(typeof(SerializationFormat), kind)); + len = reader.Read7BitEncodedInt(); + } return reader.ReadBytes(len); } } @@ -545,12 +561,14 @@ namespace ICSharpCode.Decompiler.Util public string? TypeName { get; } readonly ResourcesFile file; readonly long position; + readonly bool usesSerializationFormat; - internal ResourceSerializedObject(string? typeName, ResourcesFile file, long position) + internal ResourceSerializedObject(string? typeName, ResourcesFile file, long position, bool usesSerializationFormat) { - this.TypeName = typeName; + this.TypeName = usesSerializationFormat ? typeName : null; this.file = file; this.position = position; + this.usesSerializationFormat = usesSerializationFormat; } /// @@ -558,7 +576,7 @@ namespace ICSharpCode.Decompiler.Util /// public Stream GetStream() { - return new MemoryStream(file.GetBytesForSerializedObject(position), writable: false); + return new MemoryStream(file.GetBytesForSerializedObject(position, usesSerializationFormat), writable: false); } /// @@ -566,7 +584,7 @@ namespace ICSharpCode.Decompiler.Util /// public byte[] GetBytes() { - return file.GetBytesForSerializedObject(position); + return file.GetBytesForSerializedObject(position, usesSerializationFormat); } } } diff --git a/ILSpy.Tests/BitmapContainer.resources b/ILSpy.Tests/BitmapContainer.resources new file mode 100644 index 0000000000000000000000000000000000000000..d50495a740af107b61c9116f76979842e1b45b66 GIT binary patch literal 1158 zcmX?i>is@O1_p+SK%5g?SzMBus~417oL^d$oLUTL1*ImYq!#HYR*8GxXUf^%t3Noi54ZC+|=Nl{{sjzU0bQch;FcWPxwes*e}ZIZcpqG__J znW3ezNveT`r81^vrFkWpxv4PQgHubGfQ|w=4umtH>RpNw%QN%R^_((GauW-56i|i9 zahQQ|nrWJOnxSEesX?M~Vt}Iy5KUh5cPY?T22-HjJe~}>42cZs45Al2Q%3Nl|5)mW&{K{6~Zi6x2bOdz{CnSlg9h*$^YGIa*{x$|;KaRK?f zo*phiK-vI=IY4S}B;;KHQY`6?zK#qG8~eHcB(eheoCO|{#S9F5he4R}c>anMpg{qi zE{-7)?r*0V_8l@1aJ_sX;KGGQmu4XBT#;ePt^R;#${eObZk2NfBRA>)OiP(4pnlLr zT62BJvBw*qzpuzK^ZYN_yg&emY6Z5$=uH;C{`zX=?nN;dKL0FfK7WNL+smHy;lnp2 z9nU{U%JK5IGds^dI)A;#N8!%pFBh^`Wo(SF(7rFVP(n=YZvS!TO$`#7$CA&vv1qC6 ze({kv^w0#peH>@SOjP<7ye!FLTx9LI_~MJAohu}cKc1+0bHmLX5$1`kJ9#{fX8O#T zs&c7i!QZ<6LaVt2eaDmkgm@S((CgDYaeRI62iqGZwuh4$LBBj2*H)uG+XSGWk= zKKuOhucjZLJXUGhy}7(qVQEUm?z3AMM3mig&aqisbLCP2vigo?&?1cW2_>xaevjH?O@dRV@2Q`vIOZ0XIu}aPNKSR + + + + + + + + ResXCodeGenerator + + + + + diff --git a/ILSpy.Tests/Icon.ico b/ILSpy.Tests/Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5d06b9f2857b39f0b5d3395e3e7999ba6bcc3a38 GIT binary patch literal 45451 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 literal 0 HcmV?d00001 diff --git a/ILSpy.Tests/IconContainer.resx b/ILSpy.Tests/IconContainer.resx new file mode 100644 index 000000000..842140e25 --- /dev/null +++ b/ILSpy.Tests/IconContainer.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/Util/ResourceReaderWriterTests.cs b/ILSpy.Tests/ResourceReaderWriterTests.cs similarity index 63% rename from ICSharpCode.Decompiler.Tests/Util/ResourceReaderWriterTests.cs rename to ILSpy.Tests/ResourceReaderWriterTests.cs index 59f8aadce..4ade2b91a 100644 --- a/ICSharpCode.Decompiler.Tests/Util/ResourceReaderWriterTests.cs +++ b/ILSpy.Tests/ResourceReaderWriterTests.cs @@ -17,11 +17,10 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Drawing; using System.Globalization; using System.IO; using System.Linq; -using System.Resources; -using System.Runtime.CompilerServices; using System.Xml.Linq; using System.Xml.XPath; @@ -30,13 +29,16 @@ using ICSharpCode.Decompiler.Util; using NUnit.Framework; using NUnit.Framework.Internal; -namespace ICSharpCode.Decompiler.Tests.Util +using TomsToolbox.Essentials; + +namespace ICSharpCode.ILSpy.Tests { [TestFixture] public class ResourceReaderWriterTests { - const string WinFormsAssemblyName = ", System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; - const string MSCorLibAssemblyName = ", mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + const string winFormsAssemblyName = ", System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + const string msCorLibAssemblyName = ", mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + const string drawingAssemblyName = ", System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; [Serializable] public class SerializableClass @@ -45,22 +47,27 @@ namespace ICSharpCode.Decompiler.Tests.Util public int Age { get; set; } } - static readonly object[][] TestWriteCases = { - new object[] { "Decimal", 1.0m, "1.0", "System.Decimal" + MSCorLibAssemblyName }, - new object[] { "TimeSpan", TimeSpan.FromSeconds(42), "00:00:42", "System.TimeSpan" + MSCorLibAssemblyName }, - new object[] { "DateTime", DateTime.Parse("06/18/2023 21:36:30", CultureInfo.InvariantCulture), "06/18/2023 21:36:30", "System.DateTime" + MSCorLibAssemblyName }, + static readonly object[][] testWriteCases = { + new object[] { "Decimal", 1.0m, "1.0", "System.Decimal" + msCorLibAssemblyName }, + new object[] { "TimeSpan", TimeSpan.FromSeconds(42), "00:00:42", "System.TimeSpan" + msCorLibAssemblyName }, + new object[] { "DateTime", DateTime.Parse("06/18/2023 21:36:30", CultureInfo.InvariantCulture), "06/18/2023 21:36:30", "System.DateTime" + msCorLibAssemblyName }, }; - static readonly object[][] TestReadCases = { + static readonly object[][] testReadCases = { new object[] { "Decimal", 1.0m }, new object[] { "TimeSpan", TimeSpan.FromSeconds(42) }, new object[] { "DateTime", DateTime.Parse("06/18/2023 21:36:30", CultureInfo.InvariantCulture) }, }; + static Stream GetResource(string fileName) + { + return typeof(ResourceReaderWriterTests).Assembly.GetManifestResourceStream(typeof(ResourceReaderWriterTests).Namespace + "." + fileName); + } + static MemoryStream ProduceResourcesTestFile(string name, T value) { var ms = new MemoryStream(); - var writer = new ResourceWriter(ms); + var writer = new System.Resources.ResourceWriter(ms); writer.AddResource(name, value); writer.Generate(); ms.Position = 0; @@ -70,7 +77,7 @@ namespace ICSharpCode.Decompiler.Tests.Util static XElement ProduceResXTest(string name, T value) { using var ms = new MemoryStream(); - var writer = new ResXResourceWriter(ms); + var writer = new Decompiler.Util.ResXResourceWriter(ms); writer.AddResource(name, value); writer.Generate(); ms.Position = 0; @@ -94,7 +101,7 @@ namespace ICSharpCode.Decompiler.Tests.Util [TestCase("Single", 1.0f)] [TestCase("Double", 1.0d)] [TestCase("Bytes", new byte[] { 42, 43, 44 })] - [TestCaseSource(nameof(TestReadCases))] + [TestCaseSource(nameof(testReadCases))] public void Read(string name, object value) { using var testFile = ProduceResourcesTestFile(name, value); @@ -105,22 +112,22 @@ namespace ICSharpCode.Decompiler.Tests.Util Assert.That(items[0].Value, Is.EqualTo(value)); } - [TestCase("Null", null, null, "System.Resources.ResXNullRef" + WinFormsAssemblyName)] + [TestCase("Null", null, null, "System.Resources.ResXNullRef" + winFormsAssemblyName)] [TestCase("String", "Hello World!", "Hello World!", null)] - [TestCase("Bool", true, "True", "System.Boolean" + MSCorLibAssemblyName)] - [TestCase("Bool", false, "False", "System.Boolean" + MSCorLibAssemblyName)] - [TestCase("Char", 'A', "A", "System.Char" + MSCorLibAssemblyName)] - [TestCase("Byte", (byte)1, "1", "System.Byte" + MSCorLibAssemblyName)] - [TestCase("SByte", (sbyte)-1, "-1", "System.SByte" + MSCorLibAssemblyName)] - [TestCase("Int16", (short)1, "1", "System.Int16" + MSCorLibAssemblyName)] - [TestCase("UInt16", (ushort)1, "1", "System.UInt16" + MSCorLibAssemblyName)] - [TestCase("Int32", 1, "1", "System.Int32" + MSCorLibAssemblyName)] - [TestCase("UInt32", (uint)1, "1", "System.UInt32" + MSCorLibAssemblyName)] - [TestCase("Int64", (long)1, "1", "System.Int64" + MSCorLibAssemblyName)] - [TestCase("UInt64", (ulong)1, "1", "System.UInt64" + MSCorLibAssemblyName)] - [TestCase("Single", 1.0f, "1", "System.Single" + MSCorLibAssemblyName)] - [TestCase("Double", 1.0d, "1", "System.Double" + MSCorLibAssemblyName)] - [TestCaseSource(nameof(TestWriteCases))] + [TestCase("Bool", true, "True", "System.Boolean" + msCorLibAssemblyName)] + [TestCase("Bool", false, "False", "System.Boolean" + msCorLibAssemblyName)] + [TestCase("Char", 'A', "A", "System.Char" + msCorLibAssemblyName)] + [TestCase("Byte", (byte)1, "1", "System.Byte" + msCorLibAssemblyName)] + [TestCase("SByte", (sbyte)-1, "-1", "System.SByte" + msCorLibAssemblyName)] + [TestCase("Int16", (short)1, "1", "System.Int16" + msCorLibAssemblyName)] + [TestCase("UInt16", (ushort)1, "1", "System.UInt16" + msCorLibAssemblyName)] + [TestCase("Int32", 1, "1", "System.Int32" + msCorLibAssemblyName)] + [TestCase("UInt32", (uint)1, "1", "System.UInt32" + msCorLibAssemblyName)] + [TestCase("Int64", (long)1, "1", "System.Int64" + msCorLibAssemblyName)] + [TestCase("UInt64", (ulong)1, "1", "System.UInt64" + msCorLibAssemblyName)] + [TestCase("Single", 1.0f, "1", "System.Single" + msCorLibAssemblyName)] + [TestCase("Double", 1.0d, "1", "System.Double" + msCorLibAssemblyName)] + [TestCaseSource(nameof(testWriteCases))] public void Write(string name, object value, string serializedValue, string typeName) { var element = ProduceResXTest(name, value); @@ -153,6 +160,8 @@ namespace ICSharpCode.Decompiler.Tests.Util var item = items.FirstOrDefault(i => i.Key == "Bitmap"); Assert.That(item.Key, Is.Not.Null); Assert.That(item.Value, Is.InstanceOf()); + var rso = (ResourceSerializedObject)item.Value; + Assert.That(rso.TypeName, Is.Null); } [Test] @@ -185,5 +194,39 @@ namespace ICSharpCode.Decompiler.Tests.Util Assert.That(item.Key, Is.Not.Null); Assert.That(item.Value, Is.InstanceOf()); } + + [Test] + public void IconDataCanBeDeserializedFromResX() + { + // Uses new serialization format + var resourcesStream = GetResource("IconContainer.resources"); + var reader = new ResourcesFile(resourcesStream); + var item = reader.Single(); + Assert.That(item.Key, Is.EqualTo("Icon")); + Assert.That(item.Value, Is.InstanceOf()); + var rso = (ResourceSerializedObject)item.Value; + var xml = ProduceResXTest("Icon", rso); + Assert.That(xml.GetAttribute("name"), Is.EqualTo("Icon")); + Assert.That(xml.GetAttribute("type"), Is.EqualTo("System.Drawing.Icon" + drawingAssemblyName)); + Assert.That(xml.GetAttribute("mimetype"), Is.EqualTo("application/x-microsoft.net.object.bytearray.base64")); + var base64Icon = xml.Element("value").Value; + using var memory = new MemoryStream(Convert.FromBase64String(base64Icon)); + new Icon(memory); + } + + [Test] + public void BitmapDataCanBeDeserializedFromResX() + { + // Uses old serialization format + var resourcesStream = GetResource("BitmapContainer.resources"); + var reader = new ResourcesFile(resourcesStream); + var item = reader.Single(x => x.Key == "Image1"); + Assert.That(item.Value, Is.InstanceOf()); + var rso = (ResourceSerializedObject)item.Value; + var xml = ProduceResXTest("Image1", rso); + Assert.That(xml.GetAttribute("name"), Is.EqualTo("Image1")); + Assert.That(xml.GetAttribute("type"), Is.Null); + Assert.That(xml.GetAttribute("mimetype"), Is.EqualTo("application/x-microsoft.net.object.binary.base64")); + } } } \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/Util/Test.resources b/ILSpy.Tests/Test.resources similarity index 100% rename from ICSharpCode.Decompiler.Tests/Util/Test.resources rename to ILSpy.Tests/Test.resources