From 4c0bdd0d1a3002ff5f8be987220019fd98131b57 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Tue, 30 Jul 2024 10:06:41 +0200 Subject: [PATCH] Switch to System.Formats.Nrbf (#9465) * install the System.Formats.Nrbf package * switch to the new API * remove unused methods * remove everything related to parsing NRBF payloads and records that don't support writing * try to fix and update the tests * remove more unused code --- eng/Versions.props | 1 + .../PresentationCore/PresentationCore.csproj | 12 +- .../System/Windows/BinaryFormat/ArrayInfo.cs | 7 - .../Windows/BinaryFormat/ArraySingleObject.cs | 14 +- .../BinaryFormat/ArraySinglePrimitive.cs | 18 +- .../Windows/BinaryFormat/ArraySingleString.cs | 14 +- .../Windows/BinaryFormat/BinaryArray.cs | 69 --- .../Windows/BinaryFormat/BinaryArrayType.cs | 33 -- .../BinaryFormat/BinaryFormattedObject.cs | 81 --- .../BinaryFormattedObjectExtensions.cs | 531 ------------------ .../Windows/BinaryFormat/BinaryLibrary.cs | 14 +- .../BinaryFormat/BinaryObjectString.cs | 12 +- .../BinaryFormat/BinaryReaderExtensions.cs | 57 -- .../System/Windows/BinaryFormat/ClassInfo.cs | 14 - .../Windows/BinaryFormat/ClassRecord.cs | 7 - .../Windows/BinaryFormat/ClassTypeInfo.cs | 5 - .../Windows/BinaryFormat/ClassWithId.cs | 43 +- .../Windows/BinaryFormat/ClassWithMembers.cs | 53 -- .../BinaryFormat/ClassWithMembersAndTypes.cs | 20 +- .../System/Windows/BinaryFormat/Count.cs | 2 + .../BinaryFormat/IBinaryFormatParseable.cs | 21 - .../System/Windows/BinaryFormat/IRecord.cs | 7 - .../System/Windows/BinaryFormat/Id.cs | 2 + .../Windows/BinaryFormat/ListConverter.cs | 1 - .../BinaryFormat/ListConverterHelper.cs | 33 -- .../BinaryFormat/MemberPrimitiveTyped.cs | 13 +- .../Windows/BinaryFormat/MemberReference.cs | 6 +- .../Windows/BinaryFormat/MemberTypeInfo.cs | 42 -- .../System/Windows/BinaryFormat/MessageEnd.cs | 8 +- .../NullRecord.ObjectNullMultiple.cs | 8 +- .../NullRecord.ObjectNullMultiple256.cs | 6 +- .../System/Windows/BinaryFormat/NullRecord.cs | 2 +- .../BinaryFormat/NullableAttributes.cs | 197 ------- .../System/Windows/BinaryFormat/ObjectNull.cs | 6 +- .../System/Windows/BinaryFormat/Record.cs | 151 ----- .../System/Windows/BinaryFormat/RecordMap.cs | 22 - .../BinaryFormat/SerializationExtensions.cs | 12 - .../BinaryFormat/SerializationHeader.cs | 12 +- .../BinaryFormat/SystemClassWithMembers.cs | 46 -- .../SystemClassWithMembersAndTypes.cs | 19 +- .../System/Windows/BinaryFormat/TypeInfo.cs | 24 - .../Nrbf/SerializationRecordExtensions.cs | 357 ++++++++++++ .../System/Windows/dataobject.cs | 3 +- .../MS/Internal/DataStreams.cs | 8 +- .../PresentationFramework.csproj | 1 + .../BinaryFormat/ArrayTests.cs | 68 --- .../BinaryFormat/BinaryFormatWriterTests.cs | 5 +- .../BinaryFormattedObjectTests.cs | 414 -------------- .../BinaryFormat/ClassInfoTests.cs | 80 --- .../BinaryFormat/ExceptionTests.cs | 67 --- .../BinaryFormat/HashTableTests.cs | 40 +- .../BinaryFormat/ListTests.cs | 101 +--- .../BinaryFormat/MemberTypeInfoTests.cs | 71 --- .../BinaryFormat/PointFTests.cs | 31 - .../BinaryFormat/PrimitiveTypeTests.cs | 80 ++- .../BinaryFormat/RecordMapTests.cs | 30 - .../BinaryFormat/SystemDrawingTests.cs | 53 +- .../PresentationCore.Tests.csproj | 1 + .../BinaryFormatTestExtensions.cs | 5 +- 59 files changed, 490 insertions(+), 2570 deletions(-) delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryArray.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryArrayType.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryFormattedObject.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryFormattedObjectExtensions.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryReaderExtensions.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithMembers.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/IBinaryFormatParseable.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullableAttributes.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/RecordMap.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SystemClassWithMembers.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Nrbf/SerializationRecordExtensions.cs delete mode 100644 src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/BinaryFormattedObjectTests.cs delete mode 100644 src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ClassInfoTests.cs delete mode 100644 src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ExceptionTests.cs delete mode 100644 src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/MemberTypeInfoTests.cs delete mode 100644 src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/PointFTests.cs delete mode 100644 src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/RecordMapTests.cs diff --git a/eng/Versions.props b/eng/Versions.props index 8a6df44fa7d..d2cc93a7ef6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,6 +34,7 @@ 9.0.0-rc.1.24379.3 9.0.0-rc.1.24379.3 9.0.0-rc.1.24379.3 + 9.0.0-rc.1.24379.3 9.0.0-rc.1.24379.3 9.0.0-rc.1.24379.3 4.6.0-preview4.19176.11 diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj index 4572d7307cd..1dcab38bf60 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj @@ -338,19 +338,15 @@ - - - - - + @@ -366,19 +362,14 @@ - - - - - @@ -1480,6 +1471,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArrayInfo.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArrayInfo.cs index f041cebb1ee..fea38896b8a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArrayInfo.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArrayInfo.cs @@ -26,13 +26,6 @@ public ArrayInfo(Id objectId, Count length) ObjectId = objectId; } - public static ArrayInfo Parse(BinaryReader reader, out Count length) - { - ArrayInfo arrayInfo = new(reader.ReadInt32(), reader.ReadInt32()); - length = arrayInfo.Length; - return arrayInfo; - } - public readonly void Write(BinaryWriter writer) { writer.Write(ObjectId); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySingleObject.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySingleObject.cs index 67212d7b576..ccb65ec4d24 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySingleObject.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySingleObject.cs @@ -16,7 +16,7 @@ namespace System.Windows /// /// /// - internal sealed class ArraySingleObject : ArrayRecord, IRecord + internal sealed class ArraySingleObject : ArrayRecord { public static RecordType RecordType => RecordType.ArraySingleObject; @@ -24,18 +24,6 @@ public ArraySingleObject(ArrayInfo arrayInfo, IReadOnlyList arrayObjects : base(arrayInfo, arrayObjects) { } - static ArraySingleObject IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - ArraySingleObject record = new( - ArrayInfo.Parse(reader, out Count length), - ReadRecords(reader, recordMap, length)); - - recordMap[record.ObjectId] = record; - return record; - } - public override void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySinglePrimitive.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySinglePrimitive.cs index 0b63f41141f..ff997e8413d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySinglePrimitive.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySinglePrimitive.cs @@ -16,7 +16,7 @@ namespace System.Windows /// /// /// - internal sealed class ArraySinglePrimitive : ArrayRecord, IRecord + internal sealed class ArraySinglePrimitive : ArrayRecord { public PrimitiveType PrimitiveType { get; } @@ -28,22 +28,6 @@ public ArraySinglePrimitive(ArrayInfo arrayInfo, PrimitiveType primitiveType, IR PrimitiveType = primitiveType; } - static ArraySinglePrimitive IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - ArrayInfo arrayInfo = ArrayInfo.Parse(reader, out Count length); - PrimitiveType primitiveType = (PrimitiveType)reader.ReadByte(); - - ArraySinglePrimitive record = new( - arrayInfo, - primitiveType, - ReadPrimitiveTypes(reader, primitiveType, length)); - - recordMap[record.ObjectId] = record; - return record; - } - public override void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySingleString.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySingleString.cs index 34fb5d77a7f..51030de4f0d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySingleString.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ArraySingleString.cs @@ -17,7 +17,7 @@ namespace System.Windows /// /// /// - internal sealed class ArraySingleString : ArrayRecord, IRecord + internal sealed class ArraySingleString : ArrayRecord { public static RecordType RecordType => RecordType.ArraySingleString; @@ -25,18 +25,6 @@ public ArraySingleString(ArrayInfo arrayInfo, IReadOnlyList arrayObjects : base(arrayInfo, arrayObjects) { } - static ArraySingleString IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - ArraySingleString record = new( - ArrayInfo.Parse(reader, out Count length), - ReadRecords(reader, recordMap, length)); - - recordMap[record.ObjectId] = record; - return record; - } - public override void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryArray.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryArray.cs deleted file mode 100644 index d42d0545e31..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryArray.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#nullable enable -using System.Collections.Generic; -using System.IO; - -namespace System.Windows -{ - /// - /// Array of objects. - /// - /// - /// - /// - /// [MS-NRBF] 2.4.3.1 - /// - /// - /// - internal sealed class BinaryArray : ArrayRecord, IRecord - { - public Count Rank { get; } - public BinaryArrayType Type { get; } - public MemberTypeInfo TypeInfo { get; } - - private BinaryArray( - Count rank, - BinaryArrayType type, - ArrayInfo arrayInfo, - MemberTypeInfo typeInfo, - IReadOnlyList arrayObjects) - : base(arrayInfo, arrayObjects) - { - Rank = rank; - Type = type; - TypeInfo = typeInfo; - } - - public static RecordType RecordType => RecordType.BinaryArray; - - static BinaryArray IBinaryFormatParseable.Parse(BinaryReader reader, RecordMap recordMap) - { - Id objectId = reader.ReadInt32(); - BinaryArrayType arrayType = (BinaryArrayType)reader.ReadByte(); - Count rank = reader.ReadInt32(); - Count length = reader.ReadInt32(); - - if (arrayType != BinaryArrayType.Single || rank != 1) - { - throw new NotSupportedException("Only single dimensional arrays are currently supported."); - } - - MemberTypeInfo memberTypeInfo = MemberTypeInfo.Parse(reader, 1); - List arrayObjects = new(Math.Min(BinaryFormattedObject.MaxNewCollectionSize, length)); - (BinaryType type, object? typeInfo) = memberTypeInfo[0]; - for (int i = 0; i < length; i++) - { - arrayObjects.Add(ReadValue(reader, recordMap, type, typeInfo)); - } - - return new(rank, arrayType, new ArrayInfo(objectId, length), memberTypeInfo, arrayObjects); - } - - public override void Write(BinaryWriter writer) - { - throw new NotSupportedException(); - } - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryArrayType.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryArrayType.cs deleted file mode 100644 index cdc9b3e9e61..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryArrayType.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Windows -{ - /// - /// Binary array type. - /// - /// - /// - /// - /// [MS-NRBF] 2.4.1.1 - /// - /// - /// - internal enum BinaryArrayType : byte - { - /// - /// A single-dimensional array. - /// - Single = 0, - - /// - /// An array whose elements are arrays. The elements of a jagged array can be of different dimensions and sizes. - /// - Jagged = 1, - - /// - /// A multi-dimensional rectangular array. - /// - Rectangular = 2, - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryFormattedObject.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryFormattedObject.cs deleted file mode 100644 index 87644df7f0f..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryFormattedObject.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#nullable enable -using System.Runtime.Serialization; -using System.Text; -using System.IO; -using System.Collections.Generic; - -namespace System.Windows -{ - /// - /// Object model for the binary format put out by BinaryFormatter. It parses and creates a model but does not - /// instantiate any reference types outside of string. - /// - /// - /// - /// This is useful for explicitly controlling the rehydration of binary formatted data. BinaryFormatter is - /// depreciated for security concerns (it has no way to constrain what it hydrates from an incoming stream). - /// - /// - /// NOTE: Multidimensional and jagged arrays are not yet implemented. - /// - /// - internal sealed class BinaryFormattedObject - { - // Don't reserve space in collections based on read lengths for more than this size to defend against corrupted lengths. -#if DEBUG - internal const int MaxNewCollectionSize = 1024 * 10; -#else - internal const int MaxNewCollectionSize = 10; -#endif - private readonly List _records = new(); - private readonly RecordMap _recordMap = new(); - /// - /// Creates by parsing . - /// - public BinaryFormattedObject(Stream stream, bool leaveOpen = false) - { - ArgumentNullException.ThrowIfNull(stream); - using BinaryReader reader = new(stream, Encoding.UTF8, leaveOpen: leaveOpen); - IRecord? currentRecord; - do - { - try - { - currentRecord = Record.ReadBinaryFormatRecord(reader, _recordMap); - } - catch (SerializationException) - { - throw; - } - catch (Exception ex) when (ex is ArgumentException or InvalidCastException or ArithmeticException or IOException) - { - // Make the exception easier to catch, but retain the original stack trace. - throw; - } - - _records.Add(currentRecord); - } - while (currentRecord is not MessageEnd); - } - - /// - /// Total count of top-level records. - /// - public int RecordCount => _records.Count; - - /// - /// Gets a record by it's index. - /// - public IRecord this[int index] => _records[index]; - - /// - /// Gets a record by it's identfier. Not all records have identifiers, only ones that - /// can be referenced by other records. - /// - public IRecord this[Id id] => _recordMap[id]; - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryFormattedObjectExtensions.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryFormattedObjectExtensions.cs deleted file mode 100644 index f4f9ee5da6b..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryFormattedObjectExtensions.cs +++ /dev/null @@ -1,531 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - - -using System.Collections; -using System.Drawing; -using System.Runtime.CompilerServices; -using System.IO; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -#nullable enable -namespace System.Windows -{ - internal static class BinaryFormattedObjectExtensions - { - /// - /// Type names for that are raw primitives. - /// - private static bool IsPrimitiveTypeClassName(ReadOnlySpan typeName) - => TypeInfo.GetPrimitiveType(typeName) switch - { - PrimitiveType.Boolean => true, - PrimitiveType.Byte => true, - PrimitiveType.Char => true, - PrimitiveType.Double => true, - PrimitiveType.Int32 => true, - PrimitiveType.Int64 => true, - PrimitiveType.SByte => true, - PrimitiveType.Single => true, - PrimitiveType.Int16 => true, - PrimitiveType.UInt16 => true, - PrimitiveType.UInt32 => true, - PrimitiveType.UInt64 => true, - _ => false, - }; - - private delegate bool TryGetDelegate(BinaryFormattedObject format, [NotNullWhen(true)] out object? value); - - private static bool TryGet(TryGetDelegate get, BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - try - { - return get(format, out value); - } - catch (Exception ex) when (ex is KeyNotFoundException or InvalidCastException) - { - // This should only really happen with corrupted data. - Debug.Fail(ex.Message); - value = default; - return false; - } - } - - /// - /// Tries to get this object as a . - /// - public static bool TryGetPointF(this BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - return TryGet(Get, format, out value); - - static bool Get(BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - value = default; - - if (format.RecordCount < 4 - || format[1] is not BinaryLibrary binaryLibrary - || binaryLibrary.LibraryName != TypeInfo.SystemDrawingAssemblyName - || format[2] is not ClassWithMembersAndTypes classInfo - || classInfo.Name != typeof(PointF).FullName - || classInfo.MemberValues.Count != 2) - { - return false; - } - - value = new PointF((float)classInfo["x"], (float)classInfo["y"]); - - return true; - } - } - - /// - /// Tries to get this object as a . - /// - public static bool TryGetRectangleF(this BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - return TryGet(Get, format, out value); - - static bool Get(BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - value = default; - - if (format.RecordCount < 4 - || format[1] is not BinaryLibrary binaryLibrary - || binaryLibrary.LibraryName != TypeInfo.SystemDrawingAssemblyName - || format[2] is not ClassWithMembersAndTypes classInfo - || classInfo.Name != typeof(RectangleF).FullName - || classInfo.MemberValues.Count != 4) - { - return false; - } - - value = new RectangleF( - (float)classInfo["x"], - (float)classInfo["y"], - (float)classInfo["width"], - (float)classInfo["height"]); - - return true; - } - } - - /// - /// Trys to get this object as a primitive type or string. - /// - /// if this represented a primitive type or string. - public static bool TryGetPrimitiveType(this BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - return TryGet(Get, format, out value); - - static bool Get(BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - value = default; - if (format.RecordCount < 3) - { - return false; - } - - if (format[1] is BinaryObjectString binaryString) - { - value = binaryString.Value; - return true; - } - - if (format[1] is not SystemClassWithMembersAndTypes systemClass) - { - return false; - } - - if (IsPrimitiveTypeClassName(systemClass.Name) && systemClass.MemberTypeInfo[0].Type == BinaryType.Primitive) - { - value = systemClass.MemberValues[0]; - return true; - } - - if (systemClass.Name == typeof(TimeSpan).FullName) - { - value = new TimeSpan((long)systemClass.MemberValues[0]); - return true; - } - - switch (systemClass.Name) - { - case TypeInfo.TimeSpanType: - value = new TimeSpan((long)systemClass.MemberValues[0]); - return true; - case TypeInfo.DateTimeType: - ulong ulongValue = (ulong)systemClass["dateData"]; - value = Unsafe.As(ref ulongValue); - return true; - case TypeInfo.DecimalType: - Span bits = stackalloc int[4] - { - (int)systemClass["lo"], - (int)systemClass["mid"], - (int)systemClass["hi"], - (int)systemClass["flags"] - }; - - value = new decimal(bits); - return true; - case TypeInfo.IntPtrType: - // Rehydrating still throws even though casting doesn't any more - value = checked((nint)(long)systemClass.MemberValues[0]); - return true; - case TypeInfo.UIntPtrType: - value = checked((nuint)(ulong)systemClass.MemberValues[0]); - return true; - default: - return false; - } - } - } - - /// - /// Trys to get this object as a of . - /// - public static bool TryGetPrimitiveList(this BinaryFormattedObject format, [NotNullWhen(true)] out object? list) - { - return TryGet(Get, format, out list); - - static bool Get(BinaryFormattedObject format, [NotNullWhen(true)] out object? list) - { - list = null; - - const string ListTypeName = "System.Collections.Generic.List`1[["; - - if (format.RecordCount != 4 - || format[1] is not SystemClassWithMembersAndTypes classInfo - || !classInfo.Name.StartsWith(ListTypeName, StringComparison.Ordinal) - || format[2] is not ArrayRecord array) - { - return false; - } - - int commaIndex = classInfo.Name.IndexOf(','); - if (commaIndex == -1) - { - return false; - } - - ReadOnlySpan typeName = classInfo.Name.AsSpan()[ListTypeName.Length..commaIndex]; - PrimitiveType primitiveType = TypeInfo.GetPrimitiveType(typeName); - - int size; - try - { - // Lists serialize the entire backing array. - if ((size = (int)classInfo["_size"]) > array.Length) - { - return false; - } - } - catch (KeyNotFoundException) - { - return false; - } - - switch (primitiveType) - { - case default(PrimitiveType): - return false; - case PrimitiveType.String: - if (array is ArraySingleString stringArray) - { - List stringList = new(size); - stringList.AddRange((IEnumerable)format.GetStringValues(stringArray, size)); - list = stringList; - return true; - } - - return false; - } - - if (array is not ArraySinglePrimitive primitiveArray || primitiveArray.PrimitiveType != primitiveType) - { - return false; - } - - IList primitiveList = primitiveType switch - { - PrimitiveType.Boolean => new List(size), - PrimitiveType.Byte => new List(size), - PrimitiveType.Char => new List(size), - PrimitiveType.Decimal => new List(size), - PrimitiveType.Double => new List(size), - PrimitiveType.Int16 => new List(size), - PrimitiveType.Int32 => new List(size), - PrimitiveType.Int64 => new List(size), - PrimitiveType.SByte => new List(size), - PrimitiveType.Single => new List(size), - PrimitiveType.TimeSpan => new List(size), - PrimitiveType.DateTime => new List(size), - PrimitiveType.UInt16 => new List(size), - PrimitiveType.UInt32 => new List(size), - PrimitiveType.UInt64 => new List(size), - _ => throw new InvalidOperationException() - }; - - foreach (object item in array.Take(size)) - { - primitiveList.Add(item); - } - - list = primitiveList; - return true; - } - } - - /// - /// Tries to get this object as a of values. - /// - public static bool TryGetPrimitiveArrayList(this BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - return TryGet(Get, format, out value); - - static bool Get(BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - value = null; - - if (format.RecordCount != 4 - || format[1] is not SystemClassWithMembersAndTypes classInfo - || classInfo.Name != typeof(ArrayList).FullName - || format[2] is not ArraySingleObject array) - { - return false; - } - - int size; - try - { - // Lists serialize the entire backing array. - if ((size = (int)classInfo["_size"]) > array.Length) - { - return false; - } - } - catch (KeyNotFoundException) - { - return false; - } - - ArrayList arrayList = new(size); - for (int i = 0; i < size; i++) - { - if (!format.TryGetPrimitiveRecordValueOrNull((IRecord)array[i], out object? item)) - { - return false; - } - - arrayList.Add(item); - } - - value = arrayList; - return true; - } - } - - /// - /// Tries to get this object as an of primitive types. - /// - public static bool TryGetPrimitiveArray(this BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - return TryGet(Get, format, out value); - - static bool Get(BinaryFormattedObject format, [NotNullWhen(true)] out object? value) - { - value = null; - if (format.RecordCount != 3) - { - return false; - } - - if (format[1] is ArraySingleString stringArray) - { - value = format.GetStringValues(stringArray, stringArray.Length).ToArray(); - return true; - } - - if (format[1] is not ArraySinglePrimitive primitiveArray) - { - return false; - } - - value = primitiveArray.PrimitiveType switch - { - PrimitiveType.Boolean => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.Byte => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.Char => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.Decimal => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.Double => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.Int16 => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.Int32 => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.Int64 => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.SByte => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.Single => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.TimeSpan => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.DateTime => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.UInt16 => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.UInt32 => primitiveArray.ArrayObjects.Cast().ToArray(), - PrimitiveType.UInt64 => primitiveArray.ArrayObjects.Cast().ToArray(), - _ => null - }; - - return value is not null; - } - } - - /// - /// Trys to get this object as a binary formatted of keys and values. - /// - public static bool TryGetPrimitiveHashtable(this BinaryFormattedObject format, [NotNullWhen(true)] out Hashtable? hashtable) - { - bool success = format.TryGetPrimitiveHashtable(out object? value); - hashtable = (Hashtable?)value; - return success; - } - - /// - /// Trys to get this object as a binary formatted of keys and values. - /// - public static bool TryGetPrimitiveHashtable(this BinaryFormattedObject format, [NotNullWhen(true)] out object? hashtable) - { - return TryGet(Get, format, out hashtable); - - static bool Get(BinaryFormattedObject format, [NotNullWhen(true)] out object? hashtable) - { - hashtable = null; - - // Note that hashtables with custom comparers and/or hash code providers will have that information before - // the value pair arrays. - if (format.RecordCount != 5 - || format[1] is not SystemClassWithMembersAndTypes classInfo - || classInfo.Name != TypeInfo.HashtableType - || format[2] is not ArraySingleObject keys - || format[3] is not ArraySingleObject values - || keys.Length != values.Length) - { - return false; - } - - Hashtable temp = new(keys.Length); - for (int i = 0; i < keys.Length; i++) - { - if (!format.TryGetPrimitiveRecordValue((IRecord)keys[i], out object? key) - || !format.TryGetPrimitiveRecordValueOrNull((IRecord)values[i], out object? value)) - { - return false; - } - if(key!=null) - { - temp[key] = value; - } - - } - - hashtable = temp; - return true; - } - } - - /// - /// Tries to get the value for the given if it represents a - /// that isn't . - /// - public static bool TryGetPrimitiveRecordValue( - this BinaryFormattedObject format, - IRecord record, - [NotNullWhen(true)] out object? value) - { - format.TryGetPrimitiveRecordValueOrNull(record, out value); - return value is not null; - } - - /// - /// Tries to get the value for the given if it represents a . - /// - public static bool TryGetPrimitiveRecordValueOrNull( - this BinaryFormattedObject format, - IRecord record, - out object? value) - { - value = null; - if (record is ObjectNull) - { - return true; - } - - value = format.Dereference(record) switch - { - BinaryObjectString valueString => valueString.Value, - MemberPrimitiveTyped primitive => primitive.Value, - _ => null, - }; - - return value is not null; - } - - /// - /// Trys to get this object as a binary formatted . - /// - public static bool TryGetNotSupportedException( - this BinaryFormattedObject format, - out object? exception) - { - return TryGet(Get, format, out exception); - - static bool Get(BinaryFormattedObject format, [NotNullWhen(true)] out object? exception) - { - exception = null; - - if (format.RecordCount < 3 - || format[1] is not SystemClassWithMembersAndTypes classInfo - || classInfo.Name != TypeInfo.NotSupportedExceptionType) - { - return false; - } - - exception = new NotSupportedException(classInfo["Message"].ToString()); - return true; - } - } - - /// - /// Try to get a supported .NET type object (not WinForms). - /// - public static bool TryGetFrameworkObject( - this BinaryFormattedObject format, - [NotNullWhen(true)] out object? value) - => format.TryGetPrimitiveType(out value) - || format.TryGetPrimitiveList(out value) - || format.TryGetPrimitiveArray(out value) - || format.TryGetPrimitiveArrayList(out value) - || format.TryGetPrimitiveHashtable(out value) - || format.TryGetRectangleF(out value) - || format.TryGetPointF(out value) - || format.TryGetNotSupportedException(out value); - - /// - /// Dereferences records. - /// - public static IRecord Dereference(this BinaryFormattedObject format, IRecord record) => record switch - { - MemberReference reference => format[reference.IdRef], - _ => record - }; - - /// - /// Gets number of strings from a . - /// - public static IEnumerable GetStringValues(this BinaryFormattedObject format, ArraySingleString array, int count) - => array.ArrayObjects.Take(count).Select(record => - format.Dereference((IRecord)record) switch - { - BinaryObjectString stringRecord => stringRecord.Value, - _ => null - }); - } - -} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryLibrary.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryLibrary.cs index ad1e4388012..e2c62229137 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryLibrary.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryLibrary.cs @@ -16,7 +16,7 @@ namespace System.Windows /// /// /// - internal sealed class BinaryLibrary : IRecord + internal sealed class BinaryLibrary : IRecord { public Id LibraryId { get; } public string LibraryName { get; } @@ -29,18 +29,6 @@ public BinaryLibrary(Id libraryId, string libraryName) public static RecordType RecordType => RecordType.BinaryLibrary; - static BinaryLibrary IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - BinaryLibrary record = new( - reader.ReadInt32(), - reader.ReadString()); - - recordMap[record.LibraryId] = record; - return record; - } - public void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryObjectString.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryObjectString.cs index 329edd1ecc3..0c78ebadd22 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryObjectString.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryObjectString.cs @@ -16,7 +16,7 @@ namespace System.Windows /// /// /// - internal sealed class BinaryObjectString : IRecord + internal sealed class BinaryObjectString : IRecord { public Id ObjectId { get; } public string Value { get; } @@ -29,16 +29,6 @@ public BinaryObjectString(Id objectId, string value) Value = value; } - static BinaryObjectString IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - BinaryObjectString record = new(reader.ReadInt32(), reader.ReadString()); - - recordMap[record.ObjectId] = record; - return record; - } - public void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryReaderExtensions.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryReaderExtensions.cs deleted file mode 100644 index 455a39b7bdd..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/BinaryReaderExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.Serialization; -using System.Runtime.CompilerServices; -using System.IO; - -namespace System.Windows -{ - internal static class BinaryReaderExtensions - { - /// - /// Reads a binary formatted from the given . - /// - /// The data was invalid. - public static unsafe DateTime ReadDateTime(this BinaryReader reader) - => CreateDateTimeFromData(reader.ReadInt64()); - - /// - /// Creates a object from raw data with validation. - /// - /// was invalid. - private static DateTime CreateDateTimeFromData(long data) - { - // Copied from System.Runtime.Serialization.Formatters.Binary.BinaryParser - - // Use DateTime's public constructor to validate the input, but we - // can't return that result as it strips off the kind. To address - // that, store the value directly into a DateTime via an unsafe cast. - // See BinaryFormatterWriter.WriteDateTime for details. - - try - { - const long TicksMask = 0x3FFFFFFFFFFFFFFF; - _ = new DateTime(data & TicksMask); - } - catch (ArgumentException ex) - { - // Bad data - throw new SerializationException(ex.Message, ex); - } - - return Unsafe.As(ref data); - } - - /// - /// Returns the remaining amount of bytes in the given . - /// - public static long Remaining(this BinaryReader reader) - { - Stream stream = reader.BaseStream; - return stream.Length - stream.Position; - } - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassInfo.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassInfo.cs index f6a8966c120..900e25f1825 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassInfo.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassInfo.cs @@ -29,20 +29,6 @@ public ClassInfo(Id objectId, string name, IReadOnlyList memberNames) MemberNames = memberNames; } - public static ClassInfo Parse(BinaryReader reader, out Count memberCount) - { - Id objectId = reader.ReadInt32(); - string name = reader.ReadString(); - memberCount = reader.ReadInt32(); - List memberNames = new(Math.Min(BinaryFormattedObject.MaxNewCollectionSize, memberCount)); - for (int i = 0; i < memberCount; i++) - { - memberNames.Add(reader.ReadString()); - } - - return new(objectId, name, memberNames); - } - public void Write(BinaryWriter writer) { writer.Write(ObjectId); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassRecord.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassRecord.cs index fecf48c4894..a1a9966c06e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassRecord.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassRecord.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.IO; namespace System.Windows { @@ -48,11 +47,5 @@ private protected ClassRecord(ClassInfo classInfo, IReadOnlyList memberV ClassInfo = classInfo; MemberValues = memberValues; } - - private protected static List ReadDataFromClassInfo(BinaryReader reader, RecordMap recordMap, ClassInfo info) - { - // Not sure what gets us into this state yet. - return ReadRecords(reader, recordMap, info.MemberNames.Count); - } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassTypeInfo.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassTypeInfo.cs index ce007e7d643..00d6e0d250d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassTypeInfo.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassTypeInfo.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.IO; namespace System.Windows @@ -27,10 +26,6 @@ public ClassTypeInfo(string typeName, Id libraryId) LibraryId = libraryId; } - public static ClassTypeInfo Parse(BinaryReader reader) => new( - reader.ReadString(), - reader.ReadInt32()); - public void Write(BinaryWriter writer) { writer.Write(TypeName); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithId.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithId.cs index c5e1e89edc9..5c3853e1260 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithId.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithId.cs @@ -17,15 +17,15 @@ namespace System.Windows /// /// /// - internal sealed class ClassWithId : ClassRecord, IRecord + internal sealed class ClassWithId : ClassRecord { private readonly ClassRecord _metadataClass; public override Id ObjectId { get; } /// - /// The ObjectId of a prior , , - /// , or . + /// The ObjectId of a prior , + /// or . /// public Id MetadataId { get; } @@ -39,40 +39,6 @@ public ClassWithId(Id id, ClassRecord metadataClass, IReadOnlyList membe public static RecordType RecordType => RecordType.ClassWithId; - static ClassWithId IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - Id objectId = reader.ReadInt32(); - Id metadataId = reader.ReadInt32(); - - if (recordMap[metadataId] is not ClassRecord referencedRecord) - { - throw new SerializationException(); - } - - ClassWithId record = new( - objectId, - referencedRecord, - ReadDataFromRefId(reader, recordMap, referencedRecord)); - recordMap[record.ObjectId] = record; - - return record; - - static IReadOnlyList ReadDataFromRefId(BinaryReader reader, RecordMap recordMap, ClassRecord record) => record switch - { - ClassWithMembersAndTypes classWithMembersAndTypes - => ReadValuesFromMemberTypeInfo(reader, recordMap, classWithMembersAndTypes.MemberTypeInfo), - SystemClassWithMembersAndTypes systemClassWithMembersAndTypes - => ReadValuesFromMemberTypeInfo(reader, recordMap, systemClassWithMembersAndTypes.MemberTypeInfo), - ClassWithMembers classWithMembers - => ReadRecords(reader, recordMap, classWithMembers.MemberValues.Count), - SystemClassWithMembers systemClassWithMembers - => ReadRecords(reader, recordMap, systemClassWithMembers.MemberValues.Count), - _ => throw new SerializationException(), - }; - } - public override void Write(BinaryWriter writer) { writer.Write((byte)RecordType); @@ -87,9 +53,6 @@ public override void Write(BinaryWriter writer) case SystemClassWithMembersAndTypes systemClassWithMembersAndTypes: WriteValuesFromMemberTypeInfo(writer, systemClassWithMembersAndTypes.MemberTypeInfo, MemberValues); break; - case ClassWithMembers or SystemClassWithMembers: - WriteRecords(writer, MemberValues); - break; default: throw new SerializationException(); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithMembers.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithMembers.cs deleted file mode 100644 index 8b263263f7c..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithMembers.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.IO; - -namespace System.Windows -{ - /// - /// Class information with the source library. - /// - /// - /// - /// - /// [MS-NRBF] 2.3.2.2 - /// - /// - /// - internal sealed class ClassWithMembers : ClassRecord, IRecord - { - public Id LibraryId { get; } - - public ClassWithMembers(ClassInfo classInfo, Id libraryId, IReadOnlyList memberValues) - : base(classInfo, memberValues) - { - LibraryId = libraryId; - } - - public static RecordType RecordType => RecordType.ClassWithMembers; - - static ClassWithMembers IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - ClassInfo classInfo = ClassInfo.Parse(reader, out _); - ClassWithMembers record = new( - classInfo, - reader.ReadInt32(), - ReadDataFromClassInfo(reader, recordMap, classInfo)); - - // Index this record by the id of the embedded ClassInfo's object id. - recordMap[classInfo.ObjectId] = record; - return record; - } - - public override void Write(BinaryWriter writer) - { - writer.Write((byte)RecordType); - ClassInfo.Write(writer); - writer.Write(LibraryId); - } - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithMembersAndTypes.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithMembersAndTypes.cs index 183d78dc2c0..71c4df82e98 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithMembersAndTypes.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ClassWithMembersAndTypes.cs @@ -16,7 +16,7 @@ namespace System.Windows /// /// /// - internal sealed class ClassWithMembersAndTypes : ClassRecord, IRecord + internal sealed class ClassWithMembersAndTypes : ClassRecord { public MemberTypeInfo MemberTypeInfo { get; } public Id LibraryId { get; } @@ -43,24 +43,6 @@ public ClassWithMembersAndTypes( public static RecordType RecordType => RecordType.ClassWithMembersAndTypes; - static ClassWithMembersAndTypes IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - ClassInfo classInfo = ClassInfo.Parse(reader, out Count memberCount); - MemberTypeInfo memberTypeInfo = MemberTypeInfo.Parse(reader, memberCount); - - ClassWithMembersAndTypes record = new( - classInfo, - reader.ReadInt32(), - memberTypeInfo, - ReadValuesFromMemberTypeInfo(reader, recordMap, memberTypeInfo)); - - // Index this record by the id of the embedded ClassInfo's object id. - recordMap[record.ClassInfo.ObjectId] = record; - return record; - } - public override void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Count.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Count.cs index ec314827e01..e51e8d77362 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Count.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Count.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. #nullable enable +using System.Diagnostics.CodeAnalysis; + namespace System.Windows { /// diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/IBinaryFormatParseable.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/IBinaryFormatParseable.cs deleted file mode 100644 index b427143fa7b..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/IBinaryFormatParseable.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -namespace System.Windows -{ - /// - /// Specifies that the given record type can be created from a . - /// - internal interface IBinaryFormatParseable where T : IRecord - { - /// - /// Creates the type utilizaing the given . - /// - /// - /// Record map for looking up referenced records. If this record has an id it will be added to the map. - /// - static abstract T Parse(BinaryReader reader, RecordMap recordMap); - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/IRecord.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/IRecord.cs index 1a75cf4d6f6..9bd946977cb 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/IRecord.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/IRecord.cs @@ -11,12 +11,5 @@ internal interface IRecord : IBinaryWriteable { static virtual RecordType RecordType { get; } } - - /// - /// Typed record interface. - /// - internal interface IRecord : IRecord, IBinaryFormatParseable where T : class, IRecord - { - } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Id.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Id.cs index d162e5cda39..d132c3c6d4b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Id.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Id.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable enable +using System.Diagnostics.CodeAnalysis; + namespace System.Windows { /// diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ListConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ListConverter.cs index d504fd67572..20cfb8f0c6d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ListConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ListConverter.cs @@ -3,7 +3,6 @@ #nullable enable -using System.Windows; using System.Collections; namespace System.Windows diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ListConverterHelper.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ListConverterHelper.cs index 05e49b42618..eef755b7750 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ListConverterHelper.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ListConverterHelper.cs @@ -5,41 +5,9 @@ #nullable enable using System.Collections.Generic; using System.Collections; -using System.Linq; namespace System.Windows { - /// - /// Helper class for converting values. - /// - /// - /// - /// It is intended to save the allocation of a temporary list when converting values. If there are multiple passes - /// through the list this class should usually be avoided. - /// - /// - internal class ListConverter : IReadOnlyList - { - private readonly IReadOnlyList _values; - private readonly Func _converter; - - public ListConverter(IReadOnlyList values, Func conveter) - { - _values = values; - _converter = conveter; - } - - public TOut this[int index] => _converter(_values[index]); - - public int Count => _values.Count; - - // Saving a little bit of code by not writing an enumerator. It isn't huge, so this can be - // added if needed. - - IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); - IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); - } - internal class ListConverter : IReadOnlyList { private readonly IList _values; @@ -61,5 +29,4 @@ public ListConverter(IList values, Func converter) IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); } - } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberPrimitiveTyped.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberPrimitiveTyped.cs index d501478345a..74aae406679 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberPrimitiveTyped.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberPrimitiveTyped.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.IO; namespace System.Windows @@ -16,7 +15,7 @@ namespace System.Windows /// /// /// - internal sealed class MemberPrimitiveTyped : Record, IRecord + internal sealed class MemberPrimitiveTyped : Record { public PrimitiveType PrimitiveType { get; } public object Value { get; } @@ -42,16 +41,6 @@ internal MemberPrimitiveTyped(object value) public static RecordType RecordType => RecordType.MemberPrimitiveTyped; - static MemberPrimitiveTyped IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - PrimitiveType primitiveType = (PrimitiveType)reader.ReadByte(); - return new( - primitiveType, - ReadPrimitiveType(reader, primitiveType)); - } - public override void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberReference.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberReference.cs index ff33f9096fc..241090fc1eb 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberReference.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberReference.cs @@ -15,7 +15,7 @@ namespace System.Windows /// /// /// - internal sealed class MemberReference : IRecord + internal sealed class MemberReference : IRecord { public Id IdRef { get; } @@ -23,10 +23,6 @@ internal sealed class MemberReference : IRecord public static RecordType RecordType => RecordType.MemberReference; - static MemberReference IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) => new(reader.ReadInt32()); - public void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberTypeInfo.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberTypeInfo.cs index a8614c8ebe3..55d43cd9f27 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberTypeInfo.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MemberTypeInfo.cs @@ -31,47 +31,6 @@ namespace System.Windows public readonly (BinaryType Type, object? Info) this[int index] => _info[index]; public readonly int Count => _info.Count; - public static MemberTypeInfo Parse(BinaryReader reader, Count expectedCount) - { - List<(BinaryType Type, object? Info)> info = new(expectedCount); - - // Get all of the BinaryTypes - for (int i = 0; i < expectedCount; i++) - { - info.Add(((BinaryType)reader.ReadByte(), null)); - } - - // Check for more clarifying information - - for (int i = 0; i < expectedCount; i++) - { - BinaryType type = info[i].Type; - switch (type) - { - case BinaryType.Primitive: - case BinaryType.PrimitiveArray: - info[i] = (type, (PrimitiveType)reader.ReadByte()); - break; - case BinaryType.SystemClass: - info[i] = (type, reader.ReadString()); - break; - case BinaryType.Class: - info[i] = (type, ClassTypeInfo.Parse(reader)); - break; - case BinaryType.String: - case BinaryType.ObjectArray: - case BinaryType.StringArray: - case BinaryType.Object: - // Other types have no additional data. - break; - default: - throw new SerializationException("Unexpected binary type."); - } - } - - return new MemberTypeInfo(info); - } - public readonly void Write(BinaryWriter writer) { foreach ((BinaryType type, _) in this) @@ -111,4 +70,3 @@ public readonly void Write(BinaryWriter writer) IEnumerator IEnumerable.GetEnumerator() => _info.GetEnumerator(); } } - diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MessageEnd.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MessageEnd.cs index 523c7c7a081..04c02dd364a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MessageEnd.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/MessageEnd.cs @@ -1,13 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.IO; + namespace System.Windows { - /// /// Record that marks the end of the binary format stream. /// - internal sealed class MessageEnd : IRecord + internal sealed class MessageEnd : IRecord { public static MessageEnd Instance { get; } = new(); @@ -15,10 +15,6 @@ private MessageEnd() { } public static RecordType RecordType => RecordType.MessageEnd; - static MessageEnd IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) => Instance; - public void Write(BinaryWriter writer) => writer.Write((byte)RecordType); } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.ObjectNullMultiple.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.ObjectNullMultiple.cs index eb5c4650674..a945df178ff 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.ObjectNullMultiple.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.ObjectNullMultiple.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; -using System.Collections.Generic; namespace System.Windows { @@ -18,17 +17,12 @@ internal abstract partial class NullRecord /// /// /// - internal sealed class ObjectNullMultiple : NullRecord, IRecord + internal sealed class ObjectNullMultiple : NullRecord, IRecord { public static RecordType RecordType => RecordType.ObjectNullMultiple; public ObjectNullMultiple(Count count) => NullCount = count; - static ObjectNullMultiple IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - => new(reader.ReadInt32()); - public void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.ObjectNullMultiple256.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.ObjectNullMultiple256.cs index 7e2e9f3d1de..7fa9ac269f7 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.ObjectNullMultiple256.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.ObjectNullMultiple256.cs @@ -17,16 +17,12 @@ internal abstract partial class NullRecord /// /// /// - internal sealed class ObjectNullMultiple256 : NullRecord, IRecord + internal sealed class ObjectNullMultiple256 : NullRecord, IRecord { public static RecordType RecordType => RecordType.ObjectNullMultiple256; public ObjectNullMultiple256(Count count) => NullCount = count; - static ObjectNullMultiple256 IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) => new(reader.ReadByte()); - public void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.cs index 2c62ff22648..cdbb4ec1360 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullRecord.cs @@ -1,6 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; + using System.IO; namespace System.Windows diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullableAttributes.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullableAttributes.cs deleted file mode 100644 index 8f8266a39bb..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/NullableAttributes.cs +++ /dev/null @@ -1,197 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Windows -{ - #if !NETSTANDARD2_1 - /// Specifies that null is allowed as an input even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class AllowNullAttribute : Attribute { } - - /// Specifies that null is disallowed as an input even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class DisallowNullAttribute : Attribute { } - - /// Specifies that an output may be null even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class MaybeNullAttribute : Attribute { } - - /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class NotNullAttribute : Attribute { } - - /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class MaybeNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter may be null. - /// - public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - - /// Gets the return value condition. - public bool ReturnValue { get; } - } - - /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class NotNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - - /// Gets the return value condition. - public bool ReturnValue { get; } - } - - /// Specifies that the output will be non-null if the named parameter is non-null. - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class NotNullIfNotNullAttribute : Attribute - { - /// Initializes the attribute with the associated parameter name. - /// - /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. - /// - public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; - - /// Gets the associated parameter name. - public string ParameterName { get; } - } - - /// Applied to a method that will never return under any circumstance. - [AttributeUsage(AttributeTargets.Method, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class DoesNotReturnAttribute : Attribute { } - - /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class DoesNotReturnIfAttribute : Attribute - { - /// Initializes the attribute with the specified parameter value. - /// - /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to - /// the associated parameter matches this value. - /// - public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; - - /// Gets the condition parameter value. - public bool ParameterValue { get; } - } - #endif - - /// Specifies that the method or property will ensure that the listed field and property members have not-null values. - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class MemberNotNullAttribute : Attribute - { - /// Initializes the attribute with a field or property member. - /// - /// The field or property member that is promised to be not-null. - /// - public MemberNotNullAttribute(string member) => Members = new[] { member }; - - /// Initializes the attribute with the list of field and property members. - /// - /// The list of field and property members that are promised to be not-null. - /// - public MemberNotNullAttribute(params string[] members) => Members = members; - - /// Gets field or property member names. - public string[] Members { get; } - } - - /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] - #if SYSTEM_PRIVATE_CORELIB - public - #else - internal - #endif - sealed class MemberNotNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition and a field or property member. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - /// - /// The field or property member that is promised to be not-null. - /// - public MemberNotNullWhenAttribute(bool returnValue, string member) - { - ReturnValue = returnValue; - Members = new[] { member }; - } - - /// Initializes the attribute with the specified return value condition and list of field and property members. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - /// - /// The list of field and property members that are promised to be not-null. - /// - public MemberNotNullWhenAttribute(bool returnValue, params string[] members) - { - ReturnValue = returnValue; - Members = members; - } - - /// Gets the return value condition. - public bool ReturnValue { get; } - - /// Gets field or property member names. - public string[] Members { get; } - } -} - diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ObjectNull.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ObjectNull.cs index a43b48badca..eccbfdee96e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ObjectNull.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/ObjectNull.cs @@ -16,7 +16,7 @@ namespace System.Windows /// /// /// - internal sealed class ObjectNull : NullRecord, IRecord + internal sealed class ObjectNull : NullRecord, IRecord { public static ObjectNull Instance { get; } = new(); @@ -26,10 +26,6 @@ private ObjectNull() { } public static RecordType RecordType => RecordType.ObjectNull; - static ObjectNull IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) => Instance; - public void Write(BinaryWriter writer) => writer.Write((byte)RecordType); public override bool Equals(object? obj) => obj is ObjectNull; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Record.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Record.cs index 8567e19ac6a..fe59b386a1b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Record.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/Record.cs @@ -3,7 +3,6 @@ #nullable enable using System.Globalization; -using System.Runtime.Serialization; using System.IO; using System.Collections.Generic; @@ -14,44 +13,6 @@ namespace System.Windows /// internal abstract class Record : IRecord { - /// - /// Reads a primitive of from the given . - /// - private protected static object ReadPrimitiveType(BinaryReader reader, PrimitiveType primitiveType) => primitiveType switch - { - PrimitiveType.Boolean => reader.ReadBoolean(), - PrimitiveType.Byte => reader.ReadByte(), - PrimitiveType.SByte => reader.ReadSByte(), - PrimitiveType.Char => reader.ReadChar(), - PrimitiveType.Int16 => reader.ReadInt16(), - PrimitiveType.UInt16 => reader.ReadUInt16(), - PrimitiveType.Int32 => reader.ReadInt32(), - PrimitiveType.UInt32 => reader.ReadUInt32(), - PrimitiveType.Int64 => reader.ReadInt64(), - PrimitiveType.UInt64 => reader.ReadUInt64(), - PrimitiveType.Single => reader.ReadSingle(), - PrimitiveType.Double => reader.ReadDouble(), - PrimitiveType.Decimal => decimal.Parse(reader.ReadString(), CultureInfo.InvariantCulture), - PrimitiveType.DateTime => reader.ReadDateTime(), - PrimitiveType.TimeSpan => new TimeSpan(reader.ReadInt64()), - // String is handled with a record, never on it's own - _ => throw new SerializationException($"Failure trying to read primitve '{primitiveType}'"), - }; - - /// - /// Reads primitives of from the given . - /// - private protected static IReadOnlyList ReadPrimitiveTypes(BinaryReader reader, PrimitiveType primitiveType, int count) - { - List values = new(Math.Min(count, BinaryFormattedObject.MaxNewCollectionSize)); - for (int i = 0; i < count; i++) - { - values.Add(ReadPrimitiveType(reader, primitiveType)); - } - - return values; - } - /// /// Writes as to the given . /// @@ -123,80 +84,6 @@ private protected static void WritePrimitiveTypes(BinaryWriter writer, Primitive } } - /// - /// Reads the next record from the given . - /// - /// Found a mulitdimensional array. - /// Found a remote method invocation record. - /// Unknown or corrupted data. - internal static IRecord ReadBinaryFormatRecord(BinaryReader reader, RecordMap recordMap) - { - RecordType recordType = (RecordType)reader.ReadByte(); - - return recordType switch - { - RecordType.SerializedStreamHeader => ReadSpecificRecord(recordMap), - RecordType.ClassWithId => ReadSpecificRecord(recordMap), - RecordType.SystemClassWithMembers => ReadSpecificRecord(recordMap), - RecordType.ClassWithMembers => ReadSpecificRecord(recordMap), - RecordType.SystemClassWithMembersAndTypes => ReadSpecificRecord(recordMap), - RecordType.ClassWithMembersAndTypes => ReadSpecificRecord(recordMap), - RecordType.BinaryObjectString => ReadSpecificRecord(recordMap), - // The BinaryArray record is used for all types of arrays, but we currently only support single dimension. - RecordType.BinaryArray => ReadSpecificRecord(recordMap), - RecordType.MemberPrimitiveTyped => ReadSpecificRecord(recordMap), - RecordType.MemberReference => ReadSpecificRecord(recordMap), - RecordType.ObjectNull => ReadSpecificRecord(recordMap), - RecordType.MessageEnd => ReadSpecificRecord(recordMap), - RecordType.BinaryLibrary => ReadSpecificRecord(recordMap), - RecordType.ObjectNullMultiple256 => ReadSpecificRecord(recordMap), - RecordType.ObjectNullMultiple => ReadSpecificRecord(recordMap), - RecordType.ArraySinglePrimitive => ReadSpecificRecord(recordMap), - RecordType.ArraySingleObject => ReadSpecificRecord(recordMap), - RecordType.ArraySingleString => ReadSpecificRecord(recordMap), - RecordType.MethodCall => throw new NotSupportedException(), - RecordType.MethodReturn => throw new NotSupportedException(), - _ => throw new SerializationException("Invalid record type."), - }; - - unsafe TRecord ReadSpecificRecord(RecordMap recordMap) where TRecord : class, IRecord - { - return TRecord.Parse(reader, recordMap); - } - } - - /// - /// Reads records, expanding null records into individual entries. - /// - private protected static List ReadRecords(BinaryReader reader, RecordMap recordMap, Count count) - { - List objects = new(Math.Min(count, BinaryFormattedObject.MaxNewCollectionSize)); - - for (int i = 0; i < count; i++) - { - var record = ReadBinaryFormatRecord(reader, recordMap); - if (record is not NullRecord nullRecord) - { - objects.Add(record); - } - else - { - i += nullRecord.NullCount - 1; - if (i >= count) - { - throw new SerializationException(); - } - - for (int j = 0; j < nullRecord.NullCount; j++) - { - objects.Add(ObjectNull.Instance); - } - } - } - - return objects; - } - /// /// Writes records, coalescing null records into single entries. /// @@ -236,44 +123,6 @@ private protected static void WriteRecords(BinaryWriter writer, IReadOnlyList - /// Reads object member values using . - /// - private protected static IReadOnlyList ReadValuesFromMemberTypeInfo( - BinaryReader reader, - RecordMap recordMap, - MemberTypeInfo memberTypeInfo) - { - List memberValues = new(memberTypeInfo.Count); - foreach ((BinaryType type, object? info) in memberTypeInfo) - { - memberValues.Add(ReadValue(reader, recordMap, type, info)); - } - - return memberValues; - } - - /// - /// Reads an object member value of with optional clarifying . - /// - /// was unexpected. - private protected static object ReadValue( - BinaryReader reader, - RecordMap recordMap, - BinaryType type, - object? typeInfo) => type switch - { - BinaryType.Primitive => ReadPrimitiveType(reader, (PrimitiveType)typeInfo!), - BinaryType.String - or BinaryType.Object - or BinaryType.StringArray - or BinaryType.PrimitiveArray - or BinaryType.Class - or BinaryType.SystemClass - or BinaryType.ObjectArray => ReadBinaryFormatRecord(reader, recordMap), - _ => throw new SerializationException("Invalid binary type."), - }; - /// /// Writes as specified by the /// diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/RecordMap.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/RecordMap.cs deleted file mode 100644 index 4269acaa78d..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/RecordMap.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - - using System.Collections.Generic; - -namespace System.Windows -{ - /// - /// Map of records that ensures that IDs are only entered once. - /// - internal class RecordMap - { - private readonly Dictionary _records = new(); - - public IRecord this[Id id] - { - get => _records[id]; - set => _records.Add(id, value); - } - } - -} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SerializationExtensions.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SerializationExtensions.cs index ba4d102f424..196acbef374 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SerializationExtensions.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SerializationExtensions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. #nullable enable -using System.Runtime.ExceptionServices; using System.Runtime.Serialization; namespace System.Windows @@ -13,16 +12,5 @@ internal static class SerializationExtensions /// Get a typed value. Hard casts. /// public static T? GetValue(this SerializationInfo info, string name) => (T?)info.GetValue(name, typeof(T)); - - /// - /// Converts the given exception to a if needed, nesting the original exception - /// and assigning the original stack trace. - /// - public static SerializationException ConvertToSerializationException(this Exception ex) - => ex is SerializationException serializationException - ? serializationException - : (SerializationException)ExceptionDispatchInfo.SetRemoteStackTrace( - new SerializationException(ex.Message, ex), - ex.StackTrace ?? string.Empty); } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SerializationHeader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SerializationHeader.cs index 9aa9b12af98..76557ae60d3 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SerializationHeader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SerializationHeader.cs @@ -15,7 +15,7 @@ namespace System.Windows /// /// /// - internal sealed class SerializationHeader : IRecord + internal sealed class SerializationHeader : IRecord { /// /// The id of the root object record. @@ -46,16 +46,6 @@ internal sealed class SerializationHeader : IRecord HeaderId = -1, }; - static SerializationHeader IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) => new() - { - RootId = reader.ReadInt32(), - HeaderId = reader.ReadInt32(), - MajorVersion = reader.ReadInt32(), - MinorVersion = reader.ReadInt32(), - }; - public void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SystemClassWithMembers.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SystemClassWithMembers.cs deleted file mode 100644 index 7c25b2b7be9..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SystemClassWithMembers.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.IO; - -namespace System.Windows -{ - /// - /// System class information. - /// - /// - /// - /// - /// [MS-NRBF] 2.3.2.4 - /// - /// - /// - internal sealed class SystemClassWithMembers : ClassRecord, IRecord - { - public SystemClassWithMembers(ClassInfo classInfo, IReadOnlyList memberValues) - : base(classInfo, memberValues) { } - - public static RecordType RecordType => RecordType.SystemClassWithMembers; - - static SystemClassWithMembers IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - ClassInfo classInfo = ClassInfo.Parse(reader, out _); - SystemClassWithMembers record = new( - classInfo, - ReadDataFromClassInfo(reader, recordMap, classInfo)); - - // Index this record by the id of the embedded ClassInfo's object id. - recordMap[record.ClassInfo.ObjectId] = record; - return record; - } - - public override void Write(BinaryWriter writer) - { - writer.Write((byte)RecordType); - ClassInfo.Write(writer); - } - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SystemClassWithMembersAndTypes.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SystemClassWithMembersAndTypes.cs index 8a279a0bea4..1f6003e8d65 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SystemClassWithMembersAndTypes.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/SystemClassWithMembersAndTypes.cs @@ -16,7 +16,7 @@ namespace System.Windows /// /// /// - internal sealed class SystemClassWithMembersAndTypes : ClassRecord, IRecord + internal sealed class SystemClassWithMembersAndTypes : ClassRecord, IRecord { public MemberTypeInfo MemberTypeInfo { get; } @@ -39,23 +39,6 @@ public SystemClassWithMembersAndTypes( public static RecordType RecordType => RecordType.SystemClassWithMembersAndTypes; - static SystemClassWithMembersAndTypes IBinaryFormatParseable.Parse( - BinaryReader reader, - RecordMap recordMap) - { - ClassInfo classInfo = ClassInfo.Parse(reader, out Count memberCount); - MemberTypeInfo memberTypeInfo = MemberTypeInfo.Parse(reader, memberCount); - - SystemClassWithMembersAndTypes record = new( - classInfo, - memberTypeInfo, - ReadValuesFromMemberTypeInfo(reader, recordMap, memberTypeInfo)); - - // Index this record by the id of the embedded ClassInfo's object id. - recordMap[record.ClassInfo.ObjectId] = record; - return record; - } - public override void Write(BinaryWriter writer) { writer.Write((byte)RecordType); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/TypeInfo.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/TypeInfo.cs index 29e9ef542af..cfc3d206872 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/TypeInfo.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/BinaryFormat/TypeInfo.cs @@ -34,30 +34,6 @@ public const string MscorlibAssemblyName public const string SystemDrawingAssemblyName = "System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; - /// - /// Returns the for the given . - /// - internal static PrimitiveType GetPrimitiveType(ReadOnlySpan typeName) => typeName switch - { - BooleanType => PrimitiveType.Boolean, - CharType => PrimitiveType.Char, - SByteType => PrimitiveType.SByte, - ByteType => PrimitiveType.Byte, - Int16Type => PrimitiveType.Int16, - UInt16Type => PrimitiveType.UInt16, - Int32Type => PrimitiveType.Int32, - UInt32Type => PrimitiveType.UInt32, - Int64Type => PrimitiveType.Int64, - UInt64Type => PrimitiveType.UInt64, - SingleType => PrimitiveType.Single, - DoubleType => PrimitiveType.Double, - DecimalType => PrimitiveType.Decimal, - DateTimeType => PrimitiveType.DateTime, - StringType => PrimitiveType.String, - TimeSpanType => PrimitiveType.TimeSpan, - _ => default, - }; - /// /// Returns the for the given . /// diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Nrbf/SerializationRecordExtensions.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Nrbf/SerializationRecordExtensions.cs new file mode 100644 index 00000000000..1f8ca58837a --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Nrbf/SerializationRecordExtensions.cs @@ -0,0 +1,357 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + + +using System.Collections; +using System.Drawing; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +#nullable enable +namespace System.Formats.Nrbf +{ + internal static class SerializationRecordExtensions + { + private delegate bool TryGetDelegate(SerializationRecord record, [NotNullWhen(true)] out object? value); + + private static bool TryGet(TryGetDelegate get, SerializationRecord record, [NotNullWhen(true)] out object? value) + { + try + { + return get(record, out value); + } + catch (Exception ex) when (ex is KeyNotFoundException or InvalidCastException) + { + // This should only really happen with corrupted data. + Debug.Fail(ex.Message); + value = default; + return false; + } + } + + /// + /// Tries to get this object as a . + /// + public static bool TryGetPointF(this SerializationRecord record, [NotNullWhen(true)] out object? value) + { + return TryGet(Get, record, out value); + + static bool Get(SerializationRecord record, [NotNullWhen(true)] out object? value) + { + value = default; + + if (record is not ClassRecord classInfo + || !classInfo.TypeNameMatches(typeof(PointF)) + || !classInfo.HasMember("x") + || !classInfo.HasMember("y")) + { + return false; + } + + value = new PointF(classInfo.GetSingle("x"), classInfo.GetSingle("y")); + + return true; + } + } + + /// + /// Tries to get this object as a . + /// + public static bool TryGetRectangleF(this SerializationRecord record, [NotNullWhen(true)] out object? value) + { + return TryGet(Get, record, out value); + + static bool Get(SerializationRecord record, [NotNullWhen(true)] out object? value) + { + value = default; + + if (record is not ClassRecord classInfo + || !classInfo.TypeNameMatches(typeof(RectangleF)) + || !classInfo.HasMember("x") + || !classInfo.HasMember("y") + || !classInfo.HasMember("width") + || !classInfo.HasMember("height")) + { + return false; + } + + value = new RectangleF( + classInfo.GetSingle("x"), + classInfo.GetSingle("y"), + classInfo.GetSingle("width"), + classInfo.GetSingle("height")); + + return true; + } + } + + /// + /// Trys to get this object as a primitive type or string. + /// + /// if this represented a primitive type or string. + public static bool TryGetPrimitiveType(this SerializationRecord record, [NotNullWhen(true)] out object? value) + { + return TryGet(Get, record, out value); + + static bool Get(SerializationRecord record, [NotNullWhen(true)] out object? value) + { + if (record.RecordType is SerializationRecordType.BinaryObjectString) + { + value = ((PrimitiveTypeRecord)record).Value; + return true; + } + else if (record.RecordType is SerializationRecordType.MemberPrimitiveTyped) + { + value = ((PrimitiveTypeRecord)record).Value; + return true; + } + + value = null; + return false; + } + } + + /// + /// Trys to get this object as a of . + /// + public static bool TryGetPrimitiveList(this SerializationRecord record, [NotNullWhen(true)] out object? list) + { + return TryGet(Get, record, out list); + + static bool Get(SerializationRecord record, [NotNullWhen(true)] out object? list) + { + list = null; + + if (record is not ClassRecord classInfo + || !classInfo.HasMember("_items") + || !classInfo.HasMember("_size") + || classInfo.GetRawValue("_size") is not int size + || !classInfo.TypeName.IsConstructedGenericType + || classInfo.TypeName.GetGenericTypeDefinition().Name != typeof(List<>).Name + || classInfo.TypeName.GetGenericArguments().Length != 1 + || classInfo.GetRawValue("_items") is not ArrayRecord arrayRecord + || !IsPrimitiveArrayRecord(arrayRecord)) + { + return false; + } + + // BinaryFormatter serializes the entire backing array, so we need to trim it down to the size of the list. + list = arrayRecord switch + { + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + SZArrayRecord ar => ar.GetArray().CreateTrimmedList(size), + _ => throw new InvalidOperationException() + }; + + return true; + } + } + + /// + /// Tries to get this object as a of values. + /// + public static bool TryGetPrimitiveArrayList(this SerializationRecord record, [NotNullWhen(true)] out object? value) + { + return TryGet(Get, record, out value); + + static bool Get(SerializationRecord record, [NotNullWhen(true)] out object? value) + { + value = null; + + if (record is not ClassRecord classInfo + || !classInfo.TypeNameMatches(typeof(ArrayList)) + || !classInfo.HasMember("_items") + || !classInfo.HasMember("_size") + || classInfo.GetRawValue("_size") is not int size + || classInfo.GetRawValue("_items") is not SZArrayRecord arrayRecord + || size > arrayRecord.Length) + { + return false; + } + + ArrayList arrayList = new(size); + object?[] array = arrayRecord.GetArray(); + for (int i = 0; i < size; i++) + { + if (array[i] is SerializationRecord) + { + return false; + } + + arrayList.Add(array[i]); + } + + value = arrayList; + return true; + } + } + + /// + /// Tries to get this object as an of primitive types. + /// + public static bool TryGetPrimitiveArray(this SerializationRecord record, [NotNullWhen(true)] out object? value) + { + return TryGet(Get, record, out value); + + static bool Get(SerializationRecord record, [NotNullWhen(true)] out object? value) + { + if (!IsPrimitiveArrayRecord(record)) + { + value = null; + return false; + } + + value = record switch + { + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + SZArrayRecord ar => ar.GetArray(), + _ => throw new InvalidOperationException() + }; + + return value is not null; + } + } + + /// + /// Trys to get this object as a binary recordted of keys and values. + /// + public static bool TryGetPrimitiveHashtable(this SerializationRecord record, [NotNullWhen(true)] out object? hashtable) + { + return TryGet(Get, record, out hashtable); + + static bool Get(SerializationRecord record, [NotNullWhen(true)] out object? hashtable) + { + hashtable = null; + + if (record.RecordType != SerializationRecordType.SystemClassWithMembersAndTypes + || record is not ClassRecord classInfo + || !classInfo.TypeNameMatches(typeof(Hashtable)) + || !classInfo.HasMember("Keys") + || !classInfo.HasMember("Values") + // Note that hashtables with custom comparers and/or hash code providers will have non null Comparer + || classInfo.GetSerializationRecord("Comparer") is not null + || classInfo.GetSerializationRecord("Keys") is not SZArrayRecord keysRecord + || classInfo.GetSerializationRecord("Values") is not SZArrayRecord valuesRecord + || keysRecord.Length != valuesRecord.Length) + { + return false; + } + + Hashtable temp = new(keysRecord.Length); + object?[] keys = keysRecord.GetArray(); + object?[] values = valuesRecord.GetArray(); + for (int i = 0; i < keys.Length; i++) + { + object? key = keys[i]; + object? value = values[i]; + + if (key is null or SerializationRecord || value is SerializationRecord) + { + return false; + } + + temp[key] = value; + } + + hashtable = temp; + return true; + } + } + + /// + /// Trys to get this object as a binary recordted . + /// + public static bool TryGetNotSupportedException( + this SerializationRecord record, + out object? exception) + { + return TryGet(Get, record, out exception); + + static bool Get(SerializationRecord record, [NotNullWhen(true)] out object? exception) + { + exception = null; + + if (record is not ClassRecord classInfo + || !classInfo.TypeNameMatches(typeof(NotSupportedException))) + { + return false; + } + + exception = new NotSupportedException(classInfo.GetString("Message")); + return true; + } + } + + /// + /// Try to get a supported .NET type object (not WinForms). + /// + public static bool TryGetFrameworkObject( + this SerializationRecord record, + [NotNullWhen(true)] out object? value) + => record.TryGetPrimitiveType(out value) + || record.TryGetPrimitiveList(out value) + || record.TryGetPrimitiveArray(out value) + || record.TryGetPrimitiveArrayList(out value) + || record.TryGetPrimitiveHashtable(out value) + || record.TryGetRectangleF(out value) + || record.TryGetPointF(out value) + || record.TryGetNotSupportedException(out value); + + private static bool IsPrimitiveArrayRecord(SerializationRecord serializationRecord) + => serializationRecord.RecordType is SerializationRecordType.ArraySingleString or SerializationRecordType.ArraySinglePrimitive; + + /// + /// Creates a list trimmed to the given count. + /// + /// + /// + /// This is an optimized implementation that avoids iterating over the entire list when possible. + /// + /// + internal static List CreateTrimmedList(this IReadOnlyList readOnlyList, int count) + { + ArgumentOutOfRangeException.ThrowIfLessThan(readOnlyList.Count, count, nameof(count)); + + // List will use ICollection.CopyTo if it's available, which is faster than iterating over the list. + // If we just have an array this can be done easily with ArraySegment. + if (readOnlyList is T[] array) + { + return new List(new ArraySegment(array, 0, count)); + } + + // Fall back to just setting the count (by removing). + List list = new(readOnlyList); + list.RemoveRange(count, list.Count - count); + return list; + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/dataobject.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/dataobject.cs index c4de31e4ce7..2b681df6f52 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/dataobject.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/dataobject.cs @@ -20,6 +20,7 @@ namespace System.Windows using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; + using System.Formats.Nrbf; using System.IO; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; @@ -3063,7 +3064,7 @@ private Object ReadObjectFromHandle(IntPtr handle, bool restrictDeserialization) long startPosition = stream.Position; try { - if (new BinaryFormattedObject(stream, leaveOpen: true).TryGetFrameworkObject(out object val)) + if (NrbfDecoder.Decode(stream, leaveOpen: true).TryGetFrameworkObject(out object val)) { return val; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/DataStreams.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/DataStreams.cs index dc681cc17b6..fb38fea8b64 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/DataStreams.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/DataStreams.cs @@ -12,6 +12,7 @@ using System.Collections; using System.Collections.Specialized; using System.Diagnostics; +using System.Formats.Nrbf; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; @@ -254,9 +255,11 @@ private void LoadSubStreams(UIElement element, ArrayList subStreams) object newValue = null; if (subStream._data != null) { + using MemoryStream dataStream = new(subStream._data); + try { - new BinaryFormattedObject(new MemoryStream(subStream._data),leaveOpen: true).TryGetFrameworkObject(out object val); + NrbfDecoder.Decode(dataStream, leaveOpen: true).TryGetFrameworkObject(out object val); newValue = val; } catch (Exception ex) when (!ex.IsCriticalException()) @@ -268,8 +271,9 @@ private void LoadSubStreams(UIElement element, ArrayList subStreams) //Using Binary formatter if(newValue == null) { + dataStream.Position = 0; #pragma warning disable SYSLIB0011 // BinaryFormatter is obsolete - newValue = this.Formatter.Deserialize(new MemoryStream(subStream._data)); + newValue = this.Formatter.Deserialize(dataStream); #pragma warning restore SYSLIB0011 // BinaryFormatter is obsolete } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj index 0b63773acd8..e5e20434592 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj @@ -1431,6 +1431,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ArrayTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ArrayTests.cs index d188b4938df..695e7bb9ee8 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ArrayTests.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ArrayTests.cs @@ -1,68 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Drawing; -using System.IO; -using FluentAssertions; -using System.Threading; -using System.Windows; -using PresentationCore.Tests.TestUtilities; -using PresentationCore.Tests.FluentAssertions; - namespace PresentationCore.Tests.BinaryFormat; public class ArrayTests { - [Theory] - [MemberData(nameof(ArrayInfo_ParseSuccessData))] - public void ArrayInfo_Parse_Success(MemoryStream stream, int expectedId, int expectedLength) - { - using BinaryReader reader = new(stream); - ArrayInfo info = ArrayInfo.Parse(reader, out Count length); - info.ObjectId.Should().Be(expectedId); - info.Length.Should().Be(expectedLength); - length.Should().Be(expectedLength); - } - - public static TheoryData ArrayInfo_ParseSuccessData => new() - { - { new MemoryStream(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }), 0, 0 }, - { new MemoryStream(new byte[] { 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }), 1, 1 }, - { new MemoryStream(new byte[] { 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }), 2, 1 }, - { new MemoryStream(new byte[] { 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F }), int.MaxValue, int.MaxValue } - }; - - [Theory] - [MemberData(nameof(ArrayInfo_ParseNegativeData))] - public void ArrayInfo_Parse_Negative(MemoryStream stream, Type expectedException) - { - using BinaryReader reader = new(stream); - Assert.Throws(expectedException, () => ArrayInfo.Parse(reader, out Count length)); - } - - public static TheoryData ArrayInfo_ParseNegativeData => new() - { - // Not enough data - { new MemoryStream(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }), typeof(EndOfStreamException) }, - { new MemoryStream(new byte[] { 0x00, 0x00, 0x00 }), typeof(EndOfStreamException) }, - // Negative numbers - { new MemoryStream(new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }), typeof(ArgumentOutOfRangeException) } - }; - - [Theory] - [MemberData(nameof(StringArray_Parse_Data))] - public void StringArray_Parse(string?[] strings) - { - BinaryFormattedObject format = strings.SerializeAndParse(); - format.RecordCount.Should().BeGreaterThanOrEqualTo(3); - ArraySingleString array = (ArraySingleString)format[1]; - format.GetStringValues(array, strings.Length).Should().BeEquivalentTo(strings); - } - public static TheoryData StringArray_Parse_Data => new() { new string?[] { "one", "two" }, @@ -70,16 +12,6 @@ public void StringArray_Parse(string?[] strings) new string?[] { "same", "same", "same" } }; - [Theory] - [MemberData(nameof(PrimitiveArray_Parse_Data))] - public void PrimitiveArray_Parse(Array array) - { - BinaryFormattedObject format = array.SerializeAndParse(); - format.RecordCount.Should().BeGreaterThanOrEqualTo(3); - ArraySinglePrimitive arrayRecord = (ArraySinglePrimitive)format[1]; - ((IEnumerable)arrayRecord.ArrayObjects).Should().BeEquivalentTo((IEnumerable)array); - } - public static TheoryData PrimitiveArray_Parse_Data => new() { new int[] { 1, 2, 3 }, diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/BinaryFormatWriterTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/BinaryFormatWriterTests.cs index 342a28b21ee..1965b78edbd 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/BinaryFormatWriterTests.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/BinaryFormatWriterTests.cs @@ -6,6 +6,7 @@ using System.Runtime.Serialization.Formatters.Binary; using PresentationCore.Tests.TestUtilities; using PresentationCore.Tests.FluentAssertions; +using System.Formats.Nrbf; namespace PresentationCore.Tests.BinaryFormat; @@ -71,7 +72,7 @@ public void BinaryFormatWriter_TryWriteObject_SupportedObjects_RoundTrip(object BinaryFormatWriter.TryWriteFrameworkObject(stream, value).Should().BeTrue(); stream.Position = 0; - BinaryFormattedObject format = new(stream); + SerializationRecord format = NrbfDecoder.Decode(stream); format.TryGetFrameworkObject(out object? deserialized).Should().BeTrue(); if (value is Hashtable hashtable) @@ -115,4 +116,4 @@ public void BinaryFormatWriter_TryWriteObject_UnsupportedObjects_RoundTrip(objec ListTests.Lists_UnsupportedTestData).Concat( ListTests.ArrayLists_UnsupportedTestData).Concat( ArrayTests.Array_UnsupportedTestData); -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/BinaryFormattedObjectTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/BinaryFormattedObjectTests.cs deleted file mode 100644 index 041168b5fff..00000000000 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/BinaryFormattedObjectTests.cs +++ /dev/null @@ -1,414 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections; -using PresentationCore.Tests.TestUtilities; - -namespace PresentationCore.Tests.BinaryFormat; - -public class BinaryFormattedObjectTests -{ - [Fact] - public void ReadHeader() - { - BinaryFormattedObject format = "Hello World.".SerializeAndParse(); - SerializationHeader header = (SerializationHeader)format[0]; - header.MajorVersion.Should().Be(1); - header.MinorVersion.Should().Be(0); - header.RootId.Should().Be(1); - header.HeaderId.Should().Be(-1); - } - - [Theory] - [InlineData("Hello there.")] - [InlineData("")] - [InlineData("Embedded\0 Null.")] - public void ReadBinaryObjectString(string testString) - { - BinaryFormattedObject format = testString.SerializeAndParse(); - BinaryObjectString stringRecord = (BinaryObjectString)format[1]; - stringRecord.ObjectId.Should().Be(1); - stringRecord.Value.Should().Be(testString); - } - - [Fact] - public void ReadEmptyHashTable() - { - BinaryFormattedObject format = new Hashtable().SerializeAndParse(); - - SystemClassWithMembersAndTypes systemClass = (SystemClassWithMembersAndTypes)format[1]; - systemClass.ObjectId.Should().Be(1); - systemClass.Name.Should().Be("System.Collections.Hashtable"); - systemClass.MemberNames.Should().BeEquivalentTo(new[] - { - "LoadFactor", - "Version", - "Comparer", - "HashCodeProvider", - "HashSize", - "Keys", - "Values" - }); - - systemClass.MemberTypeInfo.Should().BeEquivalentTo(new (BinaryType Type, object? Info)[] - { - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.SystemClass, "System.Collections.IComparer"), - (BinaryType.SystemClass, "System.Collections.IHashCodeProvider"), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.ObjectArray, null), - (BinaryType.ObjectArray, null) - }); - - systemClass.MemberValues.Should().BeEquivalentTo(new object?[] - { - 0.72f, - 0, - ObjectNull.Instance, - ObjectNull.Instance, - 3, - new MemberReference(2), - new MemberReference(3) - }); - - ArraySingleObject array = (ArraySingleObject)format[2]; - array.ArrayInfo.ObjectId.Should().Be(2); - array.ArrayInfo.Length.Should().Be(0); - - array = (ArraySingleObject)format[3]; - array.ArrayInfo.ObjectId.Should().Be(3); - array.ArrayInfo.Length.Should().Be(0); - } - - [Fact] - public void ReadHashTableWithStringPair() - { - BinaryFormattedObject format = new Hashtable() - { - { "This", "That" } - }.SerializeAndParse(); - - SystemClassWithMembersAndTypes systemClass = (SystemClassWithMembersAndTypes)format[1]; - - systemClass.MemberTypeInfo.Should().BeEquivalentTo(new (BinaryType Type, object? Info)[] - { - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.SystemClass, "System.Collections.IComparer"), - (BinaryType.SystemClass, "System.Collections.IHashCodeProvider"), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.ObjectArray, null), - (BinaryType.ObjectArray, null) - }); - - systemClass.MemberValues.Should().BeEquivalentTo(new object?[] - { - 0.72f, - 1, - ObjectNull.Instance, - ObjectNull.Instance, - 3, - new MemberReference(2), - new MemberReference(3) - }); - - ArraySingleObject array = (ArraySingleObject)format[2]; - array.ArrayInfo.ObjectId.Should().Be(2); - array.ArrayInfo.Length.Should().Be(1); - BinaryObjectString value = (BinaryObjectString)array.ArrayObjects[0]; - value.ObjectId.Should().Be(4); - value.Value.Should().Be("This"); - - array = (ArraySingleObject)format[3]; - array.ArrayInfo.ObjectId.Should().Be(3); - array.ArrayInfo.Length.Should().Be(1); - value = (BinaryObjectString)array.ArrayObjects[0]; - value.ObjectId.Should().Be(5); - value.Value.Should().Be("That"); - } - - [Fact] - public void ReadHashTableWithRepeatedStrings() - { - BinaryFormattedObject format = new Hashtable() - { - { "This", "That" }, - { "TheOther", "This" }, - { "That", "This" } - }.SerializeAndParse(); - - // The collections themselves get ids first before the strings do. - // Everything in the second array is a string reference. - ArraySingleObject array = (ArraySingleObject)format[3]; - array.ObjectId.Should().Be(3); - array[0].Should().BeOfType(); - array[1].Should().BeOfType(); - array[2].Should().BeOfType(); - } - - [Fact] - public void ReadHashTableWithNullValues() - { - BinaryFormattedObject format = new Hashtable() - { - { "Yowza", null }, - { "Youza", null }, - { "Meeza", null } - }.SerializeAndParse(); - - SystemClassWithMembersAndTypes systemClass = (SystemClassWithMembersAndTypes)format[1]; - - systemClass.MemberValues.Should().BeEquivalentTo(new object?[] - { - 0.72f, - 4, - ObjectNull.Instance, - ObjectNull.Instance, - 7, - new MemberReference(2), - new MemberReference(3) - }); - - ArrayRecord array = (ArrayRecord)format[(MemberReference)systemClass.MemberValues[5]]; - - array.ArrayInfo.ObjectId.Should().Be(2); - array.ArrayInfo.Length.Should().Be(3); - BinaryObjectString value = (BinaryObjectString)array.ArrayObjects[0]; - value.ObjectId.Should().Be(4); - value.Value.Should().BeOneOf("Yowza", "Youza", "Meeza"); - - array = (ArrayRecord)format[(MemberReference)systemClass["Values"]]; - array.ArrayInfo.ObjectId.Should().Be(3); - array.ArrayInfo.Length.Should().Be(3); - array.ArrayObjects[0].Should().BeOfType(); - } - - [Fact] - public void ReadObject() - { - BinaryFormattedObject format = new object().SerializeAndParse(); - format[1].Should().BeOfType(); - } - - [Fact] - public void ReadStruct() - { - ValueTuple tuple = new(355); - BinaryFormattedObject format = tuple.SerializeAndParse(); - format[1].Should().BeOfType(); - } - - [Fact] - public void ReadSimpleSerializableObject() - { - BinaryFormattedObject format = new SimpleSerializableObject().SerializeAndParse(); - - BinaryLibrary library = (BinaryLibrary)format[1]; - library.LibraryName.Should().Be(typeof(BinaryFormattedObjectTests).Assembly.FullName); - library.LibraryId.Should().Be(2); - - ClassWithMembersAndTypes @class = (ClassWithMembersAndTypes)format[2]; - @class.ObjectId.Should().Be(1); - @class.Name.Should().Be(typeof(SimpleSerializableObject).FullName); - @class.MemberNames.Should().BeEmpty(); - @class.LibraryId.Should().Be(2); - @class.MemberTypeInfo.Should().BeEmpty(); - - format[3].Should().BeOfType(); - } - - [Fact] - public void ReadNestedSerializableObject() - { - BinaryFormattedObject format = new NestedSerializableObject().SerializeAndParse(); - - BinaryLibrary library = (BinaryLibrary)format[1]; - library.LibraryName.Should().Be(typeof(BinaryFormattedObjectTests).Assembly.FullName); - library.LibraryId.Should().Be(2); - - ClassWithMembersAndTypes @class = (ClassWithMembersAndTypes)format[2]; - @class.ObjectId.Should().Be(1); - @class.Name.Should().Be(typeof(NestedSerializableObject).FullName); - @class.MemberNames.Should().BeEquivalentTo(new[] { "_object", "_meaning" }); - @class.LibraryId.Should().Be(2); - @class.MemberTypeInfo.Should().BeEquivalentTo(new (BinaryType Type, object? Info)[] - { - (BinaryType.Class, new ClassTypeInfo(typeof(SimpleSerializableObject).FullName!, 2)), - (BinaryType.Primitive, PrimitiveType.Int32) - }); - @class.MemberValues.Should().BeEquivalentTo(new object?[] - { - new MemberReference(3), - 42 - }); - - @class = (ClassWithMembersAndTypes)format[3]; - @class.ObjectId.Should().Be(3); - @class.Name.Should().Be(typeof(SimpleSerializableObject).FullName); - @class.MemberNames.Should().BeEmpty(); - @class.LibraryId.Should().Be(2); - @class.MemberTypeInfo.Should().BeEmpty(); - - format[4].Should().BeOfType(); - } - - [Fact] - public void ReadTwoIntObject() - { - BinaryFormattedObject format = new TwoIntSerializableObject().SerializeAndParse(); - - BinaryLibrary library = (BinaryLibrary)format[1]; - library.LibraryName.Should().Be(typeof(BinaryFormattedObjectTests).Assembly.FullName); - library.LibraryId.Should().Be(2); - - ClassWithMembersAndTypes @class = (ClassWithMembersAndTypes)format[2]; - @class.ObjectId.Should().Be(1); - @class.Name.Should().Be(typeof(TwoIntSerializableObject).FullName); - @class.MemberNames.Should().BeEquivalentTo(new[] { "_value", "_meaning" }); - @class.LibraryId.Should().Be(2); - @class.MemberTypeInfo.Should().BeEquivalentTo(new (BinaryType Type, object? Info)[] - { - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.Primitive, PrimitiveType.Int32) - }); - - @class.MemberValues.Should().BeEquivalentTo(new object?[] - { - 1970, - 42 - }); - - format[3].Should().BeOfType(); - } - - [Fact] - public void ReadRepeatedNestedObject() - { - BinaryFormattedObject format = new RepeatedNestedSerializableObject().SerializeAndParse(); - ClassWithMembersAndTypes firstClass = (ClassWithMembersAndTypes)format[3]; - ClassWithId classWithId = (ClassWithId)format[4]; - classWithId.MetadataId.Should().Be(firstClass.ObjectId); - classWithId.MemberValues.Should().BeEquivalentTo(new object[] { 1970, 42 }); - } - - [Fact] - public void ReadPrimitiveArray() - { - BinaryFormattedObject format = new int[] { 10, 9, 8, 7 }.SerializeAndParse(); - - ArraySinglePrimitive array = (ArraySinglePrimitive)format[1]; - array.ArrayInfo.Length.Should().Be(4); - array.PrimitiveType.Should().Be(PrimitiveType.Int32); - array.ArrayObjects.Should().BeEquivalentTo(new object[] { 10, 9, 8, 7 }); - } - - [Fact] - public void ReadStringArray() - { - BinaryFormattedObject format = new string[] { "Monday", "Tuesday", "Wednesday" }.SerializeAndParse(); - ArraySingleString array = (ArraySingleString)format[1]; - array.ArrayInfo.ObjectId.Should().Be(1); - array.ArrayInfo.Length.Should().Be(3); - BinaryObjectString value = (BinaryObjectString)array.ArrayObjects[0]; - } - - [Fact] - public void ReadStringArrayWithNulls() - { - BinaryFormattedObject format = new string?[] { "Monday", null, "Wednesday", null, null, null }.SerializeAndParse(); - ArraySingleString array = (ArraySingleString)format[1]; - array.ArrayInfo.ObjectId.Should().Be(1); - array.ArrayInfo.Length.Should().Be(6); - array.ArrayObjects.Should().BeEquivalentTo(new object?[] - { - new BinaryObjectString(2, "Monday"), - ObjectNull.Instance, - new BinaryObjectString(3, "Wednesday"), - ObjectNull.Instance, - ObjectNull.Instance, - ObjectNull.Instance - }); - BinaryObjectString value = (BinaryObjectString)array.ArrayObjects[0]; - } - - [Fact] - public void ReadDuplicatedStringArray() - { - BinaryFormattedObject format = new string[] { "Monday", "Tuesday", "Monday" }.SerializeAndParse(); - ArraySingleString array = (ArraySingleString)format[1]; - array.ArrayInfo.ObjectId.Should().Be(1); - array.ArrayInfo.Length.Should().Be(3); - BinaryObjectString value = (BinaryObjectString)array.ArrayObjects[0]; - MemberReference reference = (MemberReference)array.ArrayObjects[2]; - reference.IdRef.Should().Be(value.ObjectId); - } - - [Fact] - public void ReadObjectWithNullableObjects() - { - BinaryFormattedObject format = new ObjectWithNullableObjects().SerializeAndParse(); - ClassWithMembersAndTypes classRecord = (ClassWithMembersAndTypes)format[2]; - BinaryLibrary library = (BinaryLibrary)format[classRecord.LibraryId]; - } - - [Fact] - public void ReadNestedObjectWithNullableObjects() - { - BinaryFormattedObject format = new NestedObjectWithNullableObjects().SerializeAndParse(); - ClassWithMembersAndTypes classRecord = (ClassWithMembersAndTypes)format[2]; - BinaryLibrary library = (BinaryLibrary)format[classRecord.LibraryId]; - } - - [Serializable] - private class SimpleSerializableObject - { - } - -#pragma warning disable IDE0052 // Remove unread private members -#pragma warning disable IDE0051 // Remove unused private members -#pragma warning disable CS0414 // Field is assigned but its value is never used -#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value null -#pragma warning disable CA1823 // Avoid unused private fields - [Serializable] - private class ObjectWithNullableObjects - { - public object? First; - public object? Second; - public object? Third; - } - - [Serializable] - private class NestedObjectWithNullableObjects - { - public ObjectWithNullableObjects? First; - public ObjectWithNullableObjects? Second; - public ObjectWithNullableObjects? Third = new(); - } - - [Serializable] - private class NestedSerializableObject - { - private readonly SimpleSerializableObject _object = new(); - private readonly int _meaning = 42; - } - - [Serializable] - private class TwoIntSerializableObject - { - private readonly int _value = 1970; - private readonly int _meaning = 42; - } - - [Serializable] - private class RepeatedNestedSerializableObject - { - private readonly TwoIntSerializableObject _first = new(); - private readonly TwoIntSerializableObject _second = new(); - } -#pragma warning restore IDE0052 // Remove unread private members -#pragma warning restore IDE0051 // Remove unused private members -#pragma warning restore CS0414 // Field is assigned but its value is never used -#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value null -#pragma warning restore CA1823 // Avoid unused private fields -} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ClassInfoTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ClassInfoTests.cs deleted file mode 100644 index 3b67a86b265..00000000000 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ClassInfoTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using PresentationCore.Tests.TestUtilities; -using PresentationCore.Tests.FluentAssertions; -namespace PresentationCore.Tests.BinaryFormat; - -public class ClassInfoTests -{ - private static readonly byte[] s_hashtableClassInfo = new byte[] - { - 0x01, 0x00, 0x00, 0x00, 0x1c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x4c, 0x6f, 0x61, 0x64, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, - 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, - 0x72, 0x10, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x08, 0x48, 0x61, 0x73, 0x68, 0x53, 0x69, 0x7a, 0x65, 0x04, 0x4b, 0x65, 0x79, 0x73, - 0x06, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73 - }; - - [Fact] - public void ClassInfo_ReadHashtable() - { - using BinaryReader reader = new(new MemoryStream(s_hashtableClassInfo)); - ClassInfo info = ClassInfo.Parse(reader, out Count memberCount); - - memberCount.Should().Be(7); - info.ObjectId.Should().Be(1); - info.Name.Should().Be("System.Collections.Hashtable"); - info.MemberNames.Should().BeEquivalentTo(new[] - { - "LoadFactor", - "Version", - "Comparer", - "HashCodeProvider", - "HashSize", - "Keys", - "Values" - }); - } - - [Fact] - public void ClassInfo_Hashtable_RoundTrip() - { - using BinaryReader reader = new(new MemoryStream(s_hashtableClassInfo)); - ClassInfo info = ClassInfo.Parse(reader, out Count memberCount); - - MemoryStream stream = new(); - BinaryWriter writer = new(stream); - info.Write(writer); - stream.Position = 0; - - using BinaryReader reader2 = new(stream); - info = ClassInfo.Parse(reader2, out memberCount); - - memberCount.Should().Be(7); - info.ObjectId.Should().Be(1); - info.Name.Should().Be("System.Collections.Hashtable"); - info.MemberNames.Should().BeEquivalentTo(new[] - { - "LoadFactor", - "Version", - "Comparer", - "HashCodeProvider", - "HashSize", - "Keys", - "Values" - }); - } - - [Fact] - public void MemberTypeInfo_ReadHashtable_TooShort() - { - MemoryStream stream = new(s_hashtableClassInfo); - stream.SetLength(stream.Length - 1); - using BinaryReader reader = new(stream); - Action action = () => ClassInfo.Parse(reader, out _); - action.Should().Throw(); - } -} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ExceptionTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ExceptionTests.cs deleted file mode 100644 index f2b53b197bf..00000000000 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ExceptionTests.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections; -using PresentationCore.Tests.TestUtilities; -using PresentationCore.Tests.FluentAssertions; - -namespace PresentationCore.Tests.BinaryFormat; - -public class ExceptionTests -{ - [Fact] - public void NotSupportedException_Parse() - { - BinaryFormattedObject format = new NotSupportedException().SerializeAndParse(); - format.RecordCount.Should().Be(3); - var systemClass = (SystemClassWithMembersAndTypes)format[1]; - systemClass.Name.Should().Be(typeof(NotSupportedException).FullName); - systemClass.MemberNames.Should().BeEquivalentTo(new string[] - { - "ClassName", - "Message", - "Data", - "InnerException", - "HelpURL", - "StackTraceString", - "RemoteStackTraceString", - "RemoteStackIndex", - "ExceptionMethod", - "HResult", - "Source", - "WatsonBuckets" - }); - - systemClass.MemberTypeInfo.Should().BeEquivalentTo(new (BinaryType, object?)[] - { - (BinaryType.String, null), - (BinaryType.String, null), - (BinaryType.SystemClass, typeof(IDictionary).FullName), - (BinaryType.SystemClass, typeof(Exception).FullName), - (BinaryType.String, null), - (BinaryType.String, null), - (BinaryType.String, null), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.String, null), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.String, null), - (BinaryType.PrimitiveArray, PrimitiveType.Byte) - }); - - systemClass.MemberValues.Should().BeEquivalentTo(new object[] - { - new BinaryObjectString(2, "System.NotSupportedException"), - new BinaryObjectString(3, "Specified method is not supported."), - ObjectNull.Instance, - ObjectNull.Instance, - ObjectNull.Instance, - ObjectNull.Instance, - ObjectNull.Instance, - 0, - ObjectNull.Instance, - unchecked((int)0x80131515), - ObjectNull.Instance, - ObjectNull.Instance - }); - } -} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/HashTableTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/HashTableTests.cs index e67fc257935..5113c08be0b 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/HashTableTests.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/HashTableTests.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Generic; using System.Drawing; +using System.Formats.Nrbf; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using PresentationCore.Tests.TestUtilities; @@ -60,23 +61,6 @@ public void HashTable_GetObjectData() enumerator.Current.Value.Should().BeEquivalentTo(new object[] { "That" }); } - [Fact] - public void HashTable_CustomComparer() - { - Hashtable hashtable = new(new CustomHashCodeProvider(), StringComparer.OrdinalIgnoreCase) - { - { "This", "That" } - }; - - BinaryFormattedObject format = hashtable.SerializeAndParse(); - format[1].Should().BeOfType(); - format[2].Should().BeOfType().Which.Name.Should().Be("System.Collections.Hashtable"); - format[3].Should().BeOfType().Which.Name.Should().Be("System.OrdinalComparer"); - format[4].Should().BeOfType().Which.Name.Should().Be("PresentationCore.Tests.BinaryFormat.HashtableTests+CustomHashCodeProvider"); - format[5].Should().BeOfType(); - format[6].Should().BeOfType(); - } - [Fact] public void HashTable_CustomComparer_DoesNotRead() { @@ -85,8 +69,8 @@ public void HashTable_CustomComparer_DoesNotRead() { "This", "That" } }; - BinaryFormattedObject format = hashtable.SerializeAndParse(); - format.TryGetPrimitiveHashtable(out Hashtable? deserialized).Should().BeFalse(); + SerializationRecord format = hashtable.SerializeAndParse(); + format.TryGetPrimitiveHashtable(out object? deserialized).Should().BeFalse(); deserialized.Should().BeNull(); } @@ -144,13 +128,13 @@ public void BinaryFormatWriter_WriteUnsupportedHashtables(Hashtable hashtable) [MemberData(nameof(Hashtables_TestData))] public void BinaryFormattedObjectExtensions_TryGetPrimitiveHashtable(Hashtable hashtable) { - BinaryFormattedObject format = hashtable.SerializeAndParse(); - format.TryGetPrimitiveHashtable(out Hashtable? deserialized).Should().BeTrue(); + SerializationRecord format = hashtable.SerializeAndParse(); + format.TryGetPrimitiveHashtable(out object? deserialized).Should().BeTrue(); - deserialized!.Count.Should().Be(hashtable.Count); + ((Hashtable)deserialized!).Count.Should().Be(hashtable.Count); foreach (object? key in hashtable.Keys) { - deserialized[key].Should().Be(hashtable[key]); + ((Hashtable)deserialized)[key].Should().Be(hashtable[key]); } } @@ -162,12 +146,12 @@ public void RoundTripHashtables(Hashtable hashtable) BinaryFormatWriter.WritePrimitiveHashtable(stream, hashtable); stream.Position = 0; - BinaryFormattedObject format = new(stream); - format.TryGetPrimitiveHashtable(out Hashtable? deserialized).Should().BeTrue(); - deserialized!.Count.Should().Be(hashtable.Count); + SerializationRecord format = NrbfDecoder.Decode(stream); + format.TryGetPrimitiveHashtable(out object? deserialized).Should().BeTrue(); + ((Hashtable)deserialized!).Count.Should().Be(hashtable.Count); foreach (object? key in hashtable.Keys) { - deserialized[key].Should().Be(hashtable[key]); + ((Hashtable)deserialized)[key].Should().Be(hashtable[key]); } } @@ -298,4 +282,4 @@ private static Hashtable MakeRepeatedHashtable(int countOfEntries, object? value // public uint ToUInt32(object value) => throw new NotImplementedException(); // public ulong ToUInt64(object value) => throw new NotImplementedException(); // } -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ListTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ListTests.cs index 536fb82a1b4..e8fa948b6b9 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ListTests.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/ListTests.cs @@ -9,63 +9,12 @@ using FluentAssertions; using PresentationCore.Tests.TestUtilities; using PresentationCore.Tests.FluentAssertions; +using System.Formats.Nrbf; namespace PresentationCore.Tests.BinaryFormat; public class ListTests { - [Fact] - public void BinaryFormattedObject_ParseEmptyArrayList() - { - BinaryFormattedObject format = new ArrayList().SerializeAndParse(); - SystemClassWithMembersAndTypes systemClass = (SystemClassWithMembersAndTypes)format[1]; - - systemClass.Name.Should().Be(typeof(ArrayList).FullName); - systemClass.MemberNames.Should().BeEquivalentTo(new string[] { "_items", "_size", "_version" }); - systemClass.MemberTypeInfo[0].Should().Be((BinaryType.ObjectArray, null)); - - format[2].Should().BeOfType(); - } - - [Theory] - [MemberData(nameof(ArrayList_Primitive_Data))] - public void BinaryFormattedObject_ParsePrimitivesArrayList(object value) - { - BinaryFormattedObject format = new ArrayList() - { - value - }.SerializeAndParse(); - - SystemClassWithMembersAndTypes systemClass = (SystemClassWithMembersAndTypes)format[1]; - - systemClass.Name.Should().Be(typeof(ArrayList).FullName); - systemClass.MemberNames.Should().BeEquivalentTo(new string[] { "_items", "_size", "_version" }); - systemClass.MemberTypeInfo[0].Should().Be((BinaryType.ObjectArray, null)); - - ArraySingleObject array = (ArraySingleObject)format[2]; - MemberPrimitiveTyped primitve = (MemberPrimitiveTyped)array[0]; - primitve.Value.Should().Be(value); - } - - [Fact] - public void BinaryFormattedObject_ParseStringArrayList() - { - BinaryFormattedObject format = new ArrayList() - { - "JarJar" - }.SerializeAndParse(); - - SystemClassWithMembersAndTypes systemClass = (SystemClassWithMembersAndTypes)format[1]; - - systemClass.Name.Should().Be(typeof(ArrayList).FullName); - systemClass.MemberNames.Should().BeEquivalentTo(new string[] { "_items", "_size", "_version" }); - systemClass.MemberTypeInfo[0].Should().Be((BinaryType.ObjectArray, null)); - - ArraySingleObject array = (ArraySingleObject)format[2]; - BinaryObjectString binaryString = (BinaryObjectString)array[0]; - binaryString.Value.Should().Be("JarJar"); - } - public static TheoryData ArrayList_Primitive_Data => new() { int.MaxValue, @@ -123,50 +72,6 @@ public void BinaryFormattedObject_ParseStringArrayList() } }; - [Fact] - public void BinaryFormattedObject_ParseEmptyIntList() - { - BinaryFormattedObject format = new List().SerializeAndParse(); - SystemClassWithMembersAndTypes classInfo = (SystemClassWithMembersAndTypes)format[1]; - - // Note that T types are serialized as the mscorlib type. - classInfo.Name.Should().Be( - "System.Collections.Generic.List`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"); - - classInfo.ClassInfo.MemberNames.Should().BeEquivalentTo(new string[] - { - "_items", - // This is something that wouldn't be needed if List implemented ISerializable. If we format - // we can save any extra unused array spots. - "_size", - // It is a bit silly that _version gets serialized, it's only use is as a check to see if - // the collection is modified while it is being enumerated. - "_version" - }); - classInfo.MemberTypeInfo[0].Should().Be((BinaryType.PrimitiveArray, PrimitiveType.Int32)); - classInfo.MemberTypeInfo[1].Should().Be((BinaryType.Primitive, PrimitiveType.Int32)); - classInfo.MemberTypeInfo[2].Should().Be((BinaryType.Primitive, PrimitiveType.Int32)); - classInfo["_items"].Should().BeOfType(); - classInfo["_size"].Should().Be(0); - classInfo["_version"].Should().Be(0); - - ArraySinglePrimitive array = (ArraySinglePrimitive)format[2]; - array.Length.Should().Be(0); - } - - [Fact] - public void BinaryFormattedObject_ParseEmptyStringList() - { - BinaryFormattedObject format = new List().SerializeAndParse(); - SystemClassWithMembersAndTypes classInfo = (SystemClassWithMembersAndTypes)format[1]; - classInfo.ClassInfo.Name.Should().StartWith("System.Collections.Generic.List`1[[System.String,"); - classInfo.MemberTypeInfo[0].Should().Be((BinaryType.StringArray, null)); - classInfo["_items"].Should().BeOfType(); - - ArraySingleString array = (ArraySingleString)format[2]; - array.Length.Should().Be(0); - } - [Theory] [MemberData(nameof(PrimitiveLists_TestData))] public void BinaryFormatWriter_TryWritePrimitiveList(IList list) @@ -197,7 +102,7 @@ public void BinaryFormatWriter_TryWritePrimitiveList_Unsupported(IList list) [MemberData(nameof(PrimitiveLists_TestData))] public void BinaryFormattedObjectExtensions_TryGetPrimitiveList(IList list) { - BinaryFormattedObject format = list.SerializeAndParse(); + SerializationRecord format = list.SerializeAndParse(); format.TryGetPrimitiveList(out object? deserialized).Should().BeTrue(); deserialized.Should().BeEquivalentTo(list); } @@ -223,4 +128,4 @@ public void BinaryFormattedObjectExtensions_TryGetPrimitiveList(IList list) new List(), new List<(int, int)>() }; -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/MemberTypeInfoTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/MemberTypeInfoTests.cs deleted file mode 100644 index bfd882a95fa..00000000000 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/MemberTypeInfoTests.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using PresentationCore.Tests.TestUtilities; - -namespace PresentationCore.Tests.BinaryFormat; - -public class MemberTypeInfoTests -{ - private static readonly byte[] s_hashtableMemberInfo = new byte[] - { - 0x00, 0x00, 0x03, 0x03, 0x00, 0x05, 0x05, 0x0b, 0x08, 0x1c, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x43, 0x6f, - 0x6d, 0x70, 0x61, 0x72, 0x65, 0x72, 0x24, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x43, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x48, 0x61, 0x73, 0x68, 0x43, - 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x08 - }; - - [Fact] - public void MemberTypeInfo_ReadHashtable() - { - using BinaryReader reader = new(new MemoryStream(s_hashtableMemberInfo)); - MemberTypeInfo info = MemberTypeInfo.Parse(reader, 7); - - info.Should().BeEquivalentTo(new (BinaryType Type, object? Info)[] - { - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.SystemClass, "System.Collections.IComparer"), - (BinaryType.SystemClass, "System.Collections.IHashCodeProvider"), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.ObjectArray, null), - (BinaryType.ObjectArray, null) - }); - } - - [Fact] - public void MemberTypeInfo_HashtableRoundTrip() - { - using BinaryReader reader = new(new MemoryStream(s_hashtableMemberInfo)); - MemberTypeInfo info = MemberTypeInfo.Parse(reader, 7); - - MemoryStream stream = new(); - BinaryWriter writer = new(stream); - info.Write(writer); - stream.Position = 0; - - using BinaryReader reader2 = new(stream); - info = MemberTypeInfo.Parse(reader2, 7); - info.Should().BeEquivalentTo(new (BinaryType Type, object? Info)[] - { - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.SystemClass, "System.Collections.IComparer"), - (BinaryType.SystemClass, "System.Collections.IHashCodeProvider"), - (BinaryType.Primitive, PrimitiveType.Int32), - (BinaryType.ObjectArray, null), - (BinaryType.ObjectArray, null) - }); - } - - [Fact] - public void MemberTypeInfo_ReadHashtable_TooShort() - { - MemoryStream stream = new(s_hashtableMemberInfo); - stream.SetLength(stream.Length - 1); - using BinaryReader reader = new(stream); - Action action = () => MemberTypeInfo.Parse(reader, 7); - action.Should().Throw(); - } -} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/PointFTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/PointFTests.cs deleted file mode 100644 index d80e85862f0..00000000000 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/PointFTests.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Drawing; -using PresentationCore.Tests.TestUtilities; - -namespace PresentationCore.Tests.BinaryFormat; - -public class PointFTests -{ - [Fact] - public void PointF_Parse() - { - BinaryFormattedObject format = new PointF().SerializeAndParse(); - - BinaryLibrary binaryLibrary = (BinaryLibrary)format[1]; - binaryLibrary.LibraryId.Should().Be(2); - binaryLibrary.LibraryName.Should().Be("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - - ClassWithMembersAndTypes classInfo = (ClassWithMembersAndTypes)format[2]; - classInfo.ObjectId.Should().Be(1); - classInfo.Name.Should().Be("System.Drawing.PointF"); - classInfo.MemberNames.Should().BeEquivalentTo(new string[] { "x", "y" }); - classInfo.MemberValues.Should().BeEquivalentTo(new object[] { 0.0f, 0.0f }); - classInfo.MemberTypeInfo.Should().BeEquivalentTo(new[] - { - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Single) - }); - } -} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/PrimitiveTypeTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/PrimitiveTypeTests.cs index d9042f33753..da83b1c030f 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/PrimitiveTypeTests.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/PrimitiveTypeTests.cs @@ -8,6 +8,9 @@ using FluentAssertions; using System.IO; using PresentationCore.Tests.TestUtilities; +using System.Globalization; +using System.Runtime.Serialization; +using System.Runtime.CompilerServices; namespace PresentationCore.Tests.BinaryFormat; @@ -84,16 +87,6 @@ public void WriteReadPrimitiveValue_RoundTrip(byte type, object value) { (byte)PrimitiveType.DateTime, DateTime.MaxValue }, }; - [Theory] - [MemberData(nameof(Primitive_Data))] - public void PrimitiveTypeMemberName(object value) - { - BinaryFormattedObject format = value.SerializeAndParse(); - SystemClassWithMembersAndTypes systemClass = (SystemClassWithMembersAndTypes)format[1]; - systemClass.MemberNames[0].Should().Be("m_value"); - systemClass.MemberValues.Count.Should().Be(1); - } - [Theory] [MemberData(nameof(Primitive_Data))] [MemberData(nameof(Primitive_ExtendedData))] @@ -111,16 +104,6 @@ public void BinaryFormatWriter_WritePrimitive(object value) deserialized.Should().Be(value); } - [Theory] - [MemberData(nameof(Primitive_Data))] - [MemberData(nameof(Primitive_ExtendedData))] - public void BinaryFormattedObject_ReadPrimitive(object value) - { - BinaryFormattedObject formattedObject = value.SerializeAndParse(); - formattedObject.TryGetPrimitiveType(out object? deserialized).Should().BeTrue(); - deserialized.Should().Be(value); - } - public static TheoryData Primitive_Data => new() { int.MaxValue, @@ -153,11 +136,64 @@ public static void WritePrimitiveValue(BinaryWriter writer, PrimitiveType type, => WritePrimitiveType(writer, type, value); public static object ReadPrimitiveValue(BinaryReader reader, PrimitiveType type) - => ReadPrimitiveType(reader, type); + => type switch + { + PrimitiveType.Boolean => reader.ReadBoolean(), + PrimitiveType.Byte => reader.ReadByte(), + PrimitiveType.SByte => reader.ReadSByte(), + PrimitiveType.Char => reader.ReadChar(), + PrimitiveType.Int16 => reader.ReadInt16(), + PrimitiveType.UInt16 => reader.ReadUInt16(), + PrimitiveType.Int32 => reader.ReadInt32(), + PrimitiveType.UInt32 => reader.ReadUInt32(), + PrimitiveType.Int64 => reader.ReadInt64(), + PrimitiveType.UInt64 => reader.ReadUInt64(), + PrimitiveType.Single => reader.ReadSingle(), + PrimitiveType.Double => reader.ReadDouble(), + PrimitiveType.Decimal => decimal.Parse(reader.ReadString(), CultureInfo.InvariantCulture), + PrimitiveType.DateTime => ReadDateTime(reader), + PrimitiveType.TimeSpan => new TimeSpan(reader.ReadInt64()), + // String is handled with a record, never on it's own + _ => throw new SerializationException($"Failure trying to read primitve '{type}'"), + }; + + /// + /// Reads a binary formatted from the given . + /// + /// The data was invalid. + private static unsafe DateTime ReadDateTime(BinaryReader reader) + => CreateDateTimeFromData(reader.ReadInt64()); + + /// + /// Creates a object from raw data with validation. + /// + /// was invalid. + private static DateTime CreateDateTimeFromData(long data) + { + // Copied from System.Runtime.Serialization.Formatters.Binary.BinaryParser + + // Use DateTime's public constructor to validate the input, but we + // can't return that result as it strips off the kind. To address + // that, store the value directly into a DateTime via an unsafe cast. + // See BinaryFormatterWriter.WriteDateTime for details. + + try + { + const long TicksMask = 0x3FFFFFFFFFFFFFFF; + _ = new DateTime(data & TicksMask); + } + catch (ArgumentException ex) + { + // Bad data + throw new SerializationException(ex.Message, ex); + } + + return Unsafe.As(ref data); + } public override void Write(BinaryWriter writer) { throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/RecordMapTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/RecordMapTests.cs deleted file mode 100644 index 061e2a7925e..00000000000 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/RecordMapTests.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -using PresentationCore.Tests.TestUtilities; - -namespace PresentationCore.Tests.BinaryFormat; - -public class RecordMapTests -{ - private class Record : IRecord - { - void IBinaryWriteable.Write(BinaryWriter writer) { } - } - - [Fact] - public void RecordMap_CannotAddSameIndexTwice() - { - RecordMap map = new(); - Action action = () => map[1] = new Record(); - action(); - action.Should().Throw(); - } - - [Fact] - public void RecordMap_GetMissingThrowsKeyNotFound() - { - RecordMap map = new(); - Func func = () => map[0]; - func.Should().Throw(); - } -} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/SystemDrawingTests.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/SystemDrawingTests.cs index 123b3577de2..7ef30fc027a 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/SystemDrawingTests.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/BinaryFormat/SystemDrawingTests.cs @@ -4,6 +4,7 @@ using System.Drawing; using PresentationCore.Tests.TestUtilities; using PresentationCore.Tests.FluentAssertions; +using System.Formats.Nrbf; namespace PresentationCore.Tests.BinaryFormat; @@ -12,45 +13,27 @@ public class SystemDrawingTests [Fact] public void PointF_Parse() { - BinaryFormattedObject format = new PointF().SerializeAndParse(); - - BinaryLibrary binaryLibrary = (BinaryLibrary)format[1]; - binaryLibrary.LibraryId.Should().Be(2); - binaryLibrary.LibraryName.ToString().Should().Be("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - - ClassWithMembersAndTypes classInfo = (ClassWithMembersAndTypes)format[2]; - classInfo.ObjectId.Should().Be(1); - classInfo.Name.Should().Be("System.Drawing.PointF"); - classInfo.MemberNames.Should().BeEquivalentTo(new string[] { "x", "y" }); - classInfo.MemberValues.Should().BeEquivalentTo(new object[] { 0.0f, 0.0f }); - classInfo.MemberTypeInfo.Should().BeEquivalentTo(new[] - { - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Single) - }); + PointF input = new(1.5f, 2.1f); + SerializationRecord record = input.SerializeAndParse(); + + Assert.True(record.TryGetPointF(out object? read)); + + Assert.Equal(input.X, ((PointF)read!).X); + Assert.Equal(input.Y, ((PointF)read).Y); } [Fact] public void RectangleF_Parse() { - BinaryFormattedObject format = new RectangleF().SerializeAndParse(); - - BinaryLibrary binaryLibrary = (BinaryLibrary)format[1]; - binaryLibrary.LibraryId.Should().Be(2); - binaryLibrary.LibraryName.ToString().Should().Be("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - - ClassWithMembersAndTypes classInfo = (ClassWithMembersAndTypes)format[2]; - classInfo.ObjectId.Should().Be(1); - classInfo.Name.Should().Be("System.Drawing.RectangleF"); - classInfo.MemberNames.Should().BeEquivalentTo(new string[] { "x", "y", "width", "height" }); - classInfo.MemberValues.Should().BeEquivalentTo(new object[] { 0.0f, 0.0f, 0.0f, 0.0f }); - classInfo.MemberTypeInfo.Should().BeEquivalentTo(new[] - { - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Single), - (BinaryType.Primitive, PrimitiveType.Single) - }); + RectangleF input = new(1.5f, 2.1f, 100.7f, 15.9f); + SerializationRecord record = input.SerializeAndParse(); + + Assert.True(record.TryGetRectangleF(out object? read)); + + Assert.Equal(input.X, ((RectangleF)read!).X); + Assert.Equal(input.Y, ((RectangleF)read).Y); + Assert.Equal(input.Width, ((RectangleF)read).Width); + Assert.Equal(input.Height, ((RectangleF)read).Height); } public static TheoryData SystemDrawing_TestData => new() @@ -58,4 +41,4 @@ public void RectangleF_Parse() new PointF(), new RectangleF() }; -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/PresentationCore.Tests.csproj b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/PresentationCore.Tests.csproj index c20b096b1e1..edc1f9cffa0 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/PresentationCore.Tests.csproj +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/PresentationCore.Tests.csproj @@ -23,6 +23,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/TestUtilities/BinaryFormatTestExtensions.cs b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/TestUtilities/BinaryFormatTestExtensions.cs index 7927e10225f..06ff94533e3 100644 --- a/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/TestUtilities/BinaryFormatTestExtensions.cs +++ b/src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/TestUtilities/BinaryFormatTestExtensions.cs @@ -7,6 +7,7 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Windows; +using System.Formats.Nrbf; namespace PresentationCore.Tests.TestUtilities; @@ -15,7 +16,7 @@ internal static class BinaryFormatTestExtensions /// /// Serializes the object using the and reads it into a . /// - public static BinaryFormattedObject SerializeAndParse(this object source) => new(source.Serialize()); + public static SerializationRecord SerializeAndParse(this object source) => NrbfDecoder.Decode(source.Serialize()); /// /// Serializes the object using the . @@ -62,4 +63,4 @@ public static bool IsBinaryFormatted(this Type type) return !((converter.CanConvertFrom(typeof(string)) && converter.CanConvertTo(typeof(string))) || (converter.CanConvertFrom(typeof(byte[])) && converter.CanConvertTo(typeof(byte[])))); } -} \ No newline at end of file +}