From 121230d9f1f659fb51765a046e17f050a68727d2 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Fri, 14 Jun 2024 17:29:02 +0200 Subject: [PATCH] Make System.Formats.Nrbf public (#103232) Co-authored-by: Jan Kotas Co-authored-by: Eric StJohn --- .../System.Formats.Nrbf.sln} | 13 +- .../ref/System.Formats.Nrbf.cs | 115 +++++++++++ .../ref/System.Formats.Nrbf.csproj | 20 ++ .../src/Resources/Strings.resx | 3 + .../src/System.Formats.Nrbf.csproj} | 14 +- .../System/Formats/Nrbf/AllowedRecordType.cs | 38 ++++ .../src/System/Formats/Nrbf}/ArrayInfo.cs | 12 +- .../Formats/Nrbf}/ArrayOfClassesRecord.cs | 16 +- .../src/System/Formats/Nrbf}/ArrayRecord.cs | 71 +------ .../Formats/Nrbf}/ArraySingleObjectRecord.cs | 20 +- .../Nrbf}/ArraySinglePrimitiveRecord.cs | 19 +- .../Formats/Nrbf}/ArraySingleStringRecord.cs | 19 +- .../System/Formats/Nrbf}/BinaryArrayRecord.cs | 64 ++---- .../System/Formats/Nrbf}/BinaryArrayType.cs | 26 +-- .../Formats/Nrbf}/BinaryLibraryRecord.cs | 23 ++- .../Formats/Nrbf}/BinaryObjectStringRecord.cs | 14 +- .../src/System/Formats/Nrbf}/BinaryType.cs | 2 +- .../src/System/Formats/Nrbf}/ClassInfo.cs | 15 +- .../src/System/Formats/Nrbf}/ClassRecord.cs | 33 ++- .../src/System/Formats/Nrbf}/ClassTypeInfo.cs | 6 +- .../System/Formats/Nrbf}/ClassWithIdRecord.cs | 17 +- .../Nrbf}/ClassWithMembersAndTypesRecord.cs | 12 +- .../Nrbf}/MemberPrimitiveTypedRecord.cs | 10 +- .../Formats/Nrbf}/MemberReferenceRecord.cs | 18 +- .../System/Formats/Nrbf}/MemberTypeInfo.cs | 156 +++++--------- .../System/Formats/Nrbf}/MessageEndRecord.cs | 18 +- .../src/System/Formats/Nrbf}/NextInfo.cs | 2 +- .../src/System/Formats/Nrbf/NrbfDecoder.cs} | 91 ++++----- .../src/System/Formats/Nrbf/NullsRecord.cs | 23 +++ .../Nrbf}/ObjectNullMultiple256Record.cs | 6 +- .../Formats/Nrbf}/ObjectNullMultipleRecord.cs | 6 +- .../System/Formats/Nrbf}/ObjectNullRecord.cs | 4 +- .../System/Formats/Nrbf}/PayloadOptions.cs | 18 +- .../src/System/Formats/Nrbf}/PrimitiveType.cs | 2 +- .../Formats/Nrbf/PrimitiveTypeRecord.cs | 34 +++ .../Formats/Nrbf/PrimitiveTypeRecordOfT.cs} | 23 ++- .../src/System/Formats/Nrbf}/RecordMap.cs | 52 ++--- .../Formats/Nrbf/RectangularArrayRecord.cs} | 43 ++-- .../src/System/Formats/Nrbf/SZArrayRecord.cs | 42 ++++ .../Formats/Nrbf/SerializationRecord.cs | 121 +++++++++++ .../Formats/Nrbf/SerializationRecordId.cs | 58 ++++++ .../Formats/Nrbf/SerializationRecordType.cs} | 66 +++--- .../Nrbf}/SerializedStreamHeaderRecord.cs | 26 ++- .../SystemClassWithMembersAndTypesRecord.cs | 16 +- .../Nrbf}/Utils/BinaryReaderExtensions.cs | 13 +- .../System/Formats/Nrbf}/Utils/ThrowHelper.cs | 11 +- .../Formats/Nrbf}/Utils/TypeNameExtensions.cs | 40 +++- .../tests/ArraySinglePrimitiveRecordTests.cs | 4 +- .../tests/AttackTests.cs | 59 +++--- .../tests/CustomOffsetArrays.cs | 82 ++++++++ .../tests/EdgeCaseTests.cs | 12 +- .../tests/InvalidInputTests.cs | 193 +++++++++--------- .../tests/JaggedArraysTests.cs | 40 ++-- .../tests/ReadAnythingTests.cs | 80 ++++---- .../tests/ReadExactTypesTests.cs | 67 +++--- .../tests/ReadTests.cs | 11 +- .../tests/RectangularArraysTests.cs | 81 ++++---- .../tests/StartsWithPayloadHeaderTests.cs | 12 +- .../tests/System.Formats.Nrbf.Tests.csproj} | 4 +- .../tests}/TypeExtensions.cs | 2 +- .../tests/TypeMatchTests.cs | 182 +++++------------ .../src/System.Resources.Extensions.csproj | 8 +- .../BinaryFormattedObject.IParseState.cs | 4 +- .../BinaryFormattedObject.ParseState.cs | 4 +- .../BinaryFormat/BinaryFormattedObject.cs | 10 +- .../BinaryFormattedObjectExtensions.cs | 37 ---- .../Deserializer/ArrayRecordDeserializer.cs | 66 +++--- .../BinaryFormat/Deserializer/ArrayUpdater.cs | 5 +- .../Deserializer/ClassRecordDeserializer.cs | 4 +- .../ClassRecordFieldInfoDeserializer.cs | 16 +- ...lassRecordSerializationInfoDeserializer.cs | 16 +- .../BinaryFormat/Deserializer/Deserializer.cs | 95 ++++----- .../Deserializer/FieldValueUpdater.cs | 5 +- .../Deserializer/IDeserializer.cs | 7 +- .../Deserializer/ObjectRecordDeserializer.cs | 30 +-- .../Deserializer/PendingSerializationInfo.cs | 7 +- .../SerializationInfoValueUpdater.cs | 5 +- .../BinaryFormat/Deserializer/ValueUpdater.cs | 9 +- .../Resources/Extensions/BinaryFormat/Id.cs | 46 ----- .../Common/CorruptedTests.cs | 4 +- .../Common/SerializationTest.cs | 12 +- .../FormattedObject/ArrayTests.cs | 4 +- .../BinaryFormattedObjectTests.cs | 77 +++---- .../FormattedObject/ExceptionTests.cs | 2 +- .../FormattedObject/HashTableTests.cs | 8 +- .../FormattedObject/ListTests.cs | 34 +-- .../FormattedObject/PrimitiveTypeTests.cs | 9 +- .../FormattedObject/SystemDrawingTests.cs | 12 +- ...urces.Extensions.BinaryFormat.Tests.csproj | 13 +- .../BinaryFormat/AllowedRecordType.cs | 38 ---- .../Serialization/BinaryFormat/NullsRecord.cs | 11 - .../BinaryFormat/SerializationRecord.cs | 66 ------ .../tests/CustomOffsetArrays.cs | 100 --------- 93 files changed, 1548 insertions(+), 1516 deletions(-) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/System.Runtime.Serialization.BinaryFormat.sln => System.Formats.Nrbf/System.Formats.Nrbf.sln} (63%) create mode 100644 src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.cs create mode 100644 src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.csproj rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/src/Resources/Strings.resx (98%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System.Runtime.Serialization.BinaryFormat.csproj => System.Formats.Nrbf/src/System.Formats.Nrbf.csproj} (64%) create mode 100644 src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/AllowedRecordType.cs rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ArrayInfo.cs (78%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ArrayOfClassesRecord.cs (81%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ArrayRecord.cs (61%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ArraySingleObjectRecord.cs (77%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ArraySinglePrimitiveRecord.cs (92%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ArraySingleStringRecord.cs (80%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/BinaryArrayRecord.cs (78%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/BinaryArrayType.cs (56%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/BinaryLibraryRecord.cs (50%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/BinaryObjectStringRecord.cs (62%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/BinaryType.cs (96%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ClassInfo.cs (86%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ClassRecord.cs (84%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ClassTypeInfo.cs (87%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ClassWithIdRecord.cs (65%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ClassWithMembersAndTypesRecord.cs (74%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/MemberPrimitiveTypedRecord.cs (61%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/MemberReferenceRecord.cs (66%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/MemberTypeInfo.cs (53%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/MessageEndRecord.cs (56%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/NextInfo.cs (95%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PayloadReader.cs => System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs} (77%) create mode 100644 src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ObjectNullMultiple256Record.cs (84%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ObjectNullMultipleRecord.cs (84%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/ObjectNullRecord.cs (83%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/PayloadOptions.cs (67%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/PrimitiveType.cs (94%) create mode 100644 src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecord.cs rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PrimitiveTypeRecord.cs => System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecordOfT.cs} (68%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/RecordMap.cs (50%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RectangularOrCustomOffsetArrayRecord.cs => System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs} (85%) create mode 100644 src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SZArrayRecord.cs create mode 100644 src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs create mode 100644 src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RecordType.cs => System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordType.cs} (64%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/SerializedStreamHeaderRecord.cs (59%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/SystemClassWithMembersAndTypesRecord.cs (89%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/Utils/BinaryReaderExtensions.cs (91%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/Utils/ThrowHelper.cs (81%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat => System.Formats.Nrbf/src/System/Formats/Nrbf}/Utils/TypeNameExtensions.cs (72%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/ArraySinglePrimitiveRecordTests.cs (97%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/AttackTests.cs (77%) create mode 100644 src/libraries/System.Formats.Nrbf/tests/CustomOffsetArrays.cs rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/EdgeCaseTests.cs (88%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/InvalidInputTests.cs (61%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/JaggedArraysTests.cs (70%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/ReadAnythingTests.cs (79%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/ReadExactTypesTests.cs (82%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/ReadTests.cs (81%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/RectangularArraysTests.cs (67%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/StartsWithPayloadHeaderTests.cs (71%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/tests/System.Runtime.Serialization.BinaryFormat.Tests.csproj => System.Formats.Nrbf/tests/System.Formats.Nrbf.Tests.csproj} (70%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils => System.Formats.Nrbf/tests}/TypeExtensions.cs (97%) rename src/libraries/{System.Runtime.Serialization.BinaryFormat => System.Formats.Nrbf}/tests/TypeMatchTests.cs (59%) delete mode 100644 src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObjectExtensions.cs delete mode 100644 src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Id.cs delete mode 100644 src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/AllowedRecordType.cs delete mode 100644 src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/NullsRecord.cs delete mode 100644 src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SerializationRecord.cs delete mode 100644 src/libraries/System.Runtime.Serialization.BinaryFormat/tests/CustomOffsetArrays.cs diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/System.Runtime.Serialization.BinaryFormat.sln b/src/libraries/System.Formats.Nrbf/System.Formats.Nrbf.sln similarity index 63% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/System.Runtime.Serialization.BinaryFormat.sln rename to src/libraries/System.Formats.Nrbf/System.Formats.Nrbf.sln index bdbb30a01de90..b8742ac25c485 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/System.Runtime.Serialization.BinaryFormat.sln +++ b/src/libraries/System.Formats.Nrbf/System.Formats.Nrbf.sln @@ -5,11 +5,15 @@ VisualStudioVersion = 17.11.34906.271 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8721A077-F840-4316-9D8A-6E48B3D5EA03}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Serialization.BinaryFormat", "src\System.Runtime.Serialization.BinaryFormat.csproj", "{E23A8E5A-9975-4ABE-BE54-B02328207F37}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Formats.Nrbf", "src\System.Formats.Nrbf.csproj", "{E23A8E5A-9975-4ABE-BE54-B02328207F37}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{32F1B10C-7A0C-440E-8F42-D5309D3D7DAA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Serialization.BinaryFormat.Tests", "tests\System.Runtime.Serialization.BinaryFormat.Tests.csproj", "{8B45136F-C266-4FE7-B5A3-CFD6F3648289}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Formats.Nrbf.Tests", "tests\System.Formats.Nrbf.Tests.csproj", "{8B45136F-C266-4FE7-B5A3-CFD6F3648289}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{D50A3723-4816-47D5-B6A2-E126D2F02722}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Formats.Nrbf", "ref\System.Formats.Nrbf.csproj", "{3415B821-490E-4B12-9A5F-135CAC6271B8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -25,6 +29,10 @@ Global {8B45136F-C266-4FE7-B5A3-CFD6F3648289}.Debug|Any CPU.Build.0 = Debug|Any CPU {8B45136F-C266-4FE7-B5A3-CFD6F3648289}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B45136F-C266-4FE7-B5A3-CFD6F3648289}.Release|Any CPU.Build.0 = Release|Any CPU + {3415B821-490E-4B12-9A5F-135CAC6271B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3415B821-490E-4B12-9A5F-135CAC6271B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3415B821-490E-4B12-9A5F-135CAC6271B8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3415B821-490E-4B12-9A5F-135CAC6271B8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -32,6 +40,7 @@ Global GlobalSection(NestedProjects) = preSolution {E23A8E5A-9975-4ABE-BE54-B02328207F37} = {8721A077-F840-4316-9D8A-6E48B3D5EA03} {8B45136F-C266-4FE7-B5A3-CFD6F3648289} = {32F1B10C-7A0C-440E-8F42-D5309D3D7DAA} + {3415B821-490E-4B12-9A5F-135CAC6271B8} = {D50A3723-4816-47D5-B6A2-E126D2F02722} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {CC885ACA-F5FA-4CAA-BA5F-2517D39C3066} diff --git a/src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.cs b/src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.cs new file mode 100644 index 0000000000000..22afcd0607119 --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.cs @@ -0,0 +1,115 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ + +namespace System.Formats.Nrbf +{ + public abstract partial class ArrayRecord : System.Formats.Nrbf.SerializationRecord + { + internal ArrayRecord() { } + public override System.Formats.Nrbf.SerializationRecordId Id { get { throw null; } } + public abstract System.ReadOnlySpan Lengths { get; } + public int Rank { get { throw null; } } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The code for an array of the specified type might not be available.")] + public System.Array GetArray(System.Type expectedArrayType, bool allowNulls = true) { throw null; } + } + public abstract partial class ClassRecord : System.Formats.Nrbf.SerializationRecord + { + internal ClassRecord() { } + public override System.Formats.Nrbf.SerializationRecordId Id { get { throw null; } } + public System.Collections.Generic.IEnumerable MemberNames { get { throw null; } } + public override System.Reflection.Metadata.TypeName TypeName { get { throw null; } } + public System.Formats.Nrbf.ArrayRecord? GetArrayRecord(string memberName) { throw null; } + public bool GetBoolean(string memberName) { throw null; } + public byte GetByte(string memberName) { throw null; } + public char GetChar(string memberName) { throw null; } + public System.Formats.Nrbf.ClassRecord? GetClassRecord(string memberName) { throw null; } + public System.DateTime GetDateTime(string memberName) { throw null; } + public decimal GetDecimal(string memberName) { throw null; } + public double GetDouble(string memberName) { throw null; } + public short GetInt16(string memberName) { throw null; } + public int GetInt32(string memberName) { throw null; } + public long GetInt64(string memberName) { throw null; } + public object? GetRawValue(string memberName) { throw null; } + public sbyte GetSByte(string memberName) { throw null; } + public System.Formats.Nrbf.SerializationRecord? GetSerializationRecord(string memberName) { throw null; } + public float GetSingle(string memberName) { throw null; } + public string? GetString(string memberName) { throw null; } + public System.TimeSpan GetTimeSpan(string memberName) { throw null; } + public ushort GetUInt16(string memberName) { throw null; } + public uint GetUInt32(string memberName) { throw null; } + public ulong GetUInt64(string memberName) { throw null; } + public bool HasMember(string memberName) { throw null; } + } + public static partial class NrbfDecoder + { + public static System.Formats.Nrbf.SerializationRecord Decode(System.IO.Stream payload, out System.Collections.Generic.IReadOnlyDictionary recordMap, System.Formats.Nrbf.PayloadOptions options=null, bool leaveOpen=false) { throw null; } + public static System.Formats.Nrbf.SerializationRecord Decode(System.IO.Stream payload, System.Formats.Nrbf.PayloadOptions? options=null, bool leaveOpen=false) { throw null; } + public static System.Formats.Nrbf.ClassRecord DecodeClassRecord(System.IO.Stream payload, System.Formats.Nrbf.PayloadOptions? options=null, bool leaveOpen=false) { throw null; } + public static bool StartsWithPayloadHeader(byte[] bytes) { throw null; } + public static bool StartsWithPayloadHeader(System.IO.Stream stream) { throw null; } + } + public sealed partial class PayloadOptions + { + public PayloadOptions() { } + public System.Reflection.Metadata.TypeNameParseOptions? TypeNameParseOptions { get { throw null; } set { } } + public bool UndoTruncatedTypeNames { get { throw null; } set { } } + } + public abstract partial class PrimitiveTypeRecord : System.Formats.Nrbf.SerializationRecord + { + internal PrimitiveTypeRecord() { } + public object Value { get { throw null; } } + } + public abstract partial class PrimitiveTypeRecord : System.Formats.Nrbf.PrimitiveTypeRecord + { + internal PrimitiveTypeRecord() { } + public override System.Reflection.Metadata.TypeName TypeName { get { throw null; } } + public new T Value { get { throw null; } } + } + public abstract partial class SerializationRecord + { + internal SerializationRecord() { } + public abstract System.Formats.Nrbf.SerializationRecordId Id { get; } + public abstract System.Formats.Nrbf.SerializationRecordType RecordType { get; } + public abstract System.Reflection.Metadata.TypeName TypeName { get; } + public bool TypeNameMatches(System.Type type) { throw null; } + } + public partial struct SerializationRecordId : System.IEquatable + { + public bool Equals(System.Formats.Nrbf.SerializationRecordId other) { throw null; } + public override bool Equals(object? obj) { throw null; } + public override int GetHashCode() { throw null; } + } + public enum SerializationRecordType + { + SerializedStreamHeader = 0, + ClassWithId = 1, + SystemClassWithMembers = 2, + ClassWithMembers = 3, + SystemClassWithMembersAndTypes = 4, + ClassWithMembersAndTypes = 5, + BinaryObjectString = 6, + BinaryArray = 7, + MemberPrimitiveTyped = 8, + MemberReference = 9, + ObjectNull = 10, + MessageEnd = 11, + BinaryLibrary = 12, + ObjectNullMultiple256 = 13, + ObjectNullMultiple = 14, + ArraySinglePrimitive = 15, + ArraySingleObject = 16, + ArraySingleString = 17, + MethodCall = 21, + MethodReturn = 22, + } + public abstract partial class SZArrayRecord : System.Formats.Nrbf.ArrayRecord + { + internal SZArrayRecord() { } + public int Length { get { throw null; } } + public override System.ReadOnlySpan Lengths { get { throw null; } } + public abstract T?[] GetArray(bool allowNulls = true); + } +} diff --git a/src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.csproj b/src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.csproj new file mode 100644 index 0000000000000..ce25b66a4473c --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.csproj @@ -0,0 +1,20 @@ + + + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) + false + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/Resources/Strings.resx b/src/libraries/System.Formats.Nrbf/src/Resources/Strings.resx similarity index 98% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/Resources/Strings.resx rename to src/libraries/System.Formats.Nrbf/src/Resources/Strings.resx index 5b5ad54c7d0dc..22ce2808f2406 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/Resources/Strings.resx +++ b/src/libraries/System.Formats.Nrbf/src/Resources/Strings.resx @@ -156,4 +156,7 @@ Specified member '{0}' was not of the expected type. + + Only arrays with zero offsets are supported. + \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System.Runtime.Serialization.BinaryFormat.csproj b/src/libraries/System.Formats.Nrbf/src/System.Formats.Nrbf.csproj similarity index 64% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System.Runtime.Serialization.BinaryFormat.csproj rename to src/libraries/System.Formats.Nrbf/src/System.Formats.Nrbf.csproj index 80566a72eed7f..53475dec19f23 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System.Runtime.Serialization.BinaryFormat.csproj +++ b/src/libraries/System.Formats.Nrbf/src/System.Formats.Nrbf.csproj @@ -4,9 +4,17 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true false - - false - $(DefineConstants);SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT + true + true + Provides a safe reader for .NET Remoting Binary Format (NRBF) payloads. + +Commonly Used Types: +System.Formats.Nrbf.NrbfDecoder + + + true diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/AllowedRecordType.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/AllowedRecordType.cs new file mode 100644 index 0000000000000..8a3b304610555 --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/AllowedRecordType.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Formats.Nrbf; + +[Flags] +internal enum AllowedRecordTypes : uint +{ + None = 0, + SerializedStreamHeader = 1 << SerializationRecordType.SerializedStreamHeader, + ClassWithId = 1 << SerializationRecordType.ClassWithId, + SystemClassWithMembersAndTypes = 1 << SerializationRecordType.SystemClassWithMembersAndTypes, + ClassWithMembersAndTypes = 1 << SerializationRecordType.ClassWithMembersAndTypes, + BinaryObjectString = 1 << SerializationRecordType.BinaryObjectString, + BinaryArray = 1 << SerializationRecordType.BinaryArray, + MemberPrimitiveTyped = 1 << SerializationRecordType.MemberPrimitiveTyped, + MemberReference = 1 << SerializationRecordType.MemberReference, + ObjectNull = 1 << SerializationRecordType.ObjectNull, + MessageEnd = 1 << SerializationRecordType.MessageEnd, + BinaryLibrary = 1 << SerializationRecordType.BinaryLibrary, + ObjectNullMultiple256 = 1 << SerializationRecordType.ObjectNullMultiple256, + ObjectNullMultiple = 1 << SerializationRecordType.ObjectNullMultiple, + ArraySinglePrimitive = 1 << SerializationRecordType.ArraySinglePrimitive, + ArraySingleObject = 1 << SerializationRecordType.ArraySingleObject, + ArraySingleString = 1 << SerializationRecordType.ArraySingleString, + + Nulls = ObjectNull | ObjectNullMultiple256 | ObjectNullMultiple, + + /// + /// Any .NET object (a primitive, a reference type, a reference or single null). + /// + AnyObject = MemberPrimitiveTyped + | ArraySingleObject | ArraySinglePrimitive | ArraySingleString | BinaryArray + | ClassWithId | ClassWithMembersAndTypes | SystemClassWithMembersAndTypes + | BinaryObjectString + | MemberReference + | ObjectNull, +} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs similarity index 78% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayInfo.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs index 5a24b394a96d6..e8b28825888e4 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs @@ -3,9 +3,9 @@ using System.Diagnostics; using System.IO; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Array information structure. @@ -18,15 +18,15 @@ internal readonly struct ArrayInfo { internal const int MaxArrayLength = 2147483591; // Array.MaxLength - internal ArrayInfo(int objectId, long totalElementsCount, BinaryArrayType arrayType = BinaryArrayType.Single, int rank = 1) + internal ArrayInfo(SerializationRecordId id, long totalElementsCount, BinaryArrayType arrayType = BinaryArrayType.Single, int rank = 1) { - ObjectId = objectId; + Id = id; TotalElementsCount = totalElementsCount; ArrayType = arrayType; Rank = rank; } - internal int ObjectId { get; } + internal SerializationRecordId Id { get; } internal long TotalElementsCount { get; } @@ -41,7 +41,7 @@ internal int GetSZArrayLength() } internal static ArrayInfo Decode(BinaryReader reader) - => new(reader.ReadInt32(), ParseValidArrayLength(reader)); + => new(SerializationRecordId.Decode(reader), ParseValidArrayLength(reader)); internal static int ParseValidArrayLength(BinaryReader reader) { diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayOfClassesRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayOfClassesRecord.cs similarity index 81% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayOfClassesRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayOfClassesRecord.cs index 97edd273a159e..46e066bd39dbb 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayOfClassesRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayOfClassesRecord.cs @@ -3,13 +3,13 @@ using System.Collections.Generic; using System.Reflection.Metadata; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; -internal sealed class ArrayOfClassesRecord : ArrayRecord +internal sealed class ArrayOfClassesRecord : SZArrayRecord { - private TypeName? _elementTypeName; + private TypeName? _typeName; internal ArrayOfClassesRecord(ArrayInfo arrayInfo, MemberTypeInfo memberTypeInfo) : base(arrayInfo) @@ -18,13 +18,14 @@ internal ArrayOfClassesRecord(ArrayInfo arrayInfo, MemberTypeInfo memberTypeInfo Records = []; } - public override RecordType RecordType => RecordType.BinaryArray; + public override SerializationRecordType RecordType => SerializationRecordType.BinaryArray; internal List Records { get; } private MemberTypeInfo MemberTypeInfo { get; } - public override TypeName ElementTypeName => _elementTypeName ??= MemberTypeInfo.GetElementTypeName(); + public override TypeName TypeName + => _typeName ??= MemberTypeInfo.GetArrayTypeName(ArrayInfo); /// public override ClassRecord?[] GetArray(bool allowNulls = true) @@ -79,7 +80,4 @@ internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetA return (allowed, primitiveType); } - - internal override bool IsElementType(Type typeElement) - => MemberTypeInfo.IsElementType(typeElement); } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayRecord.cs similarity index 61% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayRecord.cs index 39733a3041844..ddfd91a29fb1a 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArrayRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayRecord.cs @@ -3,19 +3,14 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection.Metadata; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Defines the core behavior for NRBF array records and provides a base for derived classes. /// -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -abstract class ArrayRecord : SerializationRecord +public abstract class ArrayRecord : SerializationRecord { private protected Array? _arrayNullsAllowed; private protected Array? _arrayNullsNotAllowed; @@ -42,16 +37,10 @@ private protected ArrayRecord(ArrayInfo arrayInfo) /// Gets the type of the array. /// /// The type of the array. - public BinaryArrayType ArrayType => ArrayInfo.ArrayType; - - /// - /// Gets the name of the array element type. - /// - /// The name of the array element type. - public abstract TypeName ElementTypeName { get; } + internal BinaryArrayType ArrayType => ArrayInfo.ArrayType; /// - public override int ObjectId => ArrayInfo.ObjectId; + public override SerializationRecordId Id => ArrayInfo.Id; internal long ValuesToRead { get; private protected set; } @@ -78,9 +67,9 @@ public Array GetArray(Type expectedArrayType, bool allowNulls = true) throw new ArgumentNullException(nameof(expectedArrayType)); } #endif - if (!IsTypeNameMatching(expectedArrayType)) + if (!TypeNameMatches(expectedArrayType)) { - throw new InvalidOperationException(SR.Format(SR.Serialization_TypeMismatch, expectedArrayType.AssemblyQualifiedName, ElementTypeName.AssemblyQualifiedName)); + throw new InvalidOperationException(SR.Format(SR.Serialization_TypeMismatch, expectedArrayType.AssemblyQualifiedName, TypeName.AssemblyQualifiedName)); } return allowNulls @@ -91,11 +80,6 @@ public Array GetArray(Type expectedArrayType, bool allowNulls = true) [RequiresDynamicCode("May call Array.CreateInstance() and Type.MakeArrayType().")] private protected abstract Array Deserialize(Type arrayType, bool allowNulls); - public override bool IsTypeNameMatching(Type type) - => type.IsArray - && type.GetArrayRank() == ArrayInfo.Rank - && IsElementType(type.GetElementType()!); - internal sealed override void HandleNextValue(object value, NextInfo info) => HandleNext(value, info, size: 1); @@ -104,8 +88,6 @@ internal sealed override void HandleNextRecord(SerializationRecord nextRecord, N private protected abstract void AddValue(object value); - internal abstract bool IsElementType(Type typeElement); - private void HandleNext(object value, NextInfo info, int size) { ValuesToRead -= size; @@ -126,42 +108,3 @@ private void HandleNext(object value, NextInfo info, int size) internal abstract (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetAllowedRecordType(); } - -/// -/// Defines the core behavior for NRBF single dimensional, zero-indexed array records and provides a base for derived classes. -/// -/// -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -abstract class ArrayRecord : ArrayRecord -{ - private protected ArrayRecord(ArrayInfo arrayInfo) : base(arrayInfo) - { - } - - /// - /// Gets the length of the array. - /// - /// The length of the array. - public int Length => ArrayInfo.GetSZArrayLength(); - - /// - public override ReadOnlySpan Lengths => new int[1] { Length }; - - /// - /// When overridden in a derived class, allocates an array of and fills it with the data provided in the serialized records (in case of primitive types like or ) or the serialized records themselves. - /// - /// - /// to permit values within the array; - /// otherwise, . - /// - /// An array filled with the data provided in the serialized records. - public abstract T?[] GetArray(bool allowNulls = true); - -#pragma warning disable IL3051 // RequiresDynamicCode is not required in this particualar case - private protected override Array Deserialize(Type arrayType, bool allowNulls) => GetArray(allowNulls); -#pragma warning restore IL3051 -} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySingleObjectRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleObjectRecord.cs similarity index 77% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySingleObjectRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleObjectRecord.cs index 4da46f61bb225..de77d3e0f84fa 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySingleObjectRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleObjectRecord.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; using System.IO; using System.Reflection.Metadata; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a single dimensional array of . @@ -14,23 +14,19 @@ namespace System.Runtime.Serialization.BinaryFormat; /// /// ArraySingleObject records are described in [MS-NRBF] 2.4.3.2. /// -internal sealed class ArraySingleObjectRecord : ArrayRecord +internal sealed class ArraySingleObjectRecord : SZArrayRecord { - private static TypeName? s_elementTypeName; + private static TypeName? s_typeName; private ArraySingleObjectRecord(ArrayInfo arrayInfo) : base(arrayInfo) => Records = []; - public override RecordType RecordType => RecordType.ArraySingleObject; + public override SerializationRecordType RecordType => SerializationRecordType.ArraySingleObject; - public override TypeName ElementTypeName - => s_elementTypeName ??= TypeName.Parse(typeof(object).FullName.AsSpan()).WithCoreLibAssemblyName(); + public override TypeName TypeName + => s_typeName ??= TypeName.Parse(("System.Object[], " + TypeNameExtensions.CoreLibAssemblyName).AsSpan()); private List Records { get; } - public override bool IsTypeNameMatching(Type type) => type == typeof(object[]); - - internal override bool IsElementType(Type typeElement) => typeElement == typeof(object); - /// public override object?[] GetArray(bool allowNulls = true) => (object?[])(allowNulls ? _arrayNullsAllowed ??= ToArray(true) : _arrayNullsNotAllowed ??= ToArray(false)); @@ -46,7 +42,7 @@ public override TypeName ElementTypeName int nullCount = record is NullsRecord nullsRecord ? nullsRecord.NullCount : 0; if (nullCount == 0) { - values[valueIndex++] = record is MemberReferenceRecord referenceRecord && referenceRecord.Reference == ObjectId + values[valueIndex++] = record is MemberReferenceRecord referenceRecord && referenceRecord.Reference.Equals(Id) ? values // a reference to self, and a way to get StackOverflow exception ;) : record.GetValue(); continue; diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySinglePrimitiveRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs similarity index 92% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySinglePrimitiveRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs index 5154be4a1b806..a09ca6b7e48d2 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySinglePrimitiveRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs @@ -11,9 +11,9 @@ using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a single-dimensional array of a primitive type. @@ -21,10 +21,10 @@ namespace System.Runtime.Serialization.BinaryFormat; /// /// ArraySinglePrimitive records are described in [MS-NRBF] 2.4.3.3. /// -internal sealed class ArraySinglePrimitiveRecord : ArrayRecord +internal sealed class ArraySinglePrimitiveRecord : SZArrayRecord where T : unmanaged { - private static TypeName? s_elementTypeName; + private static TypeName? s_typeName; internal ArraySinglePrimitiveRecord(ArrayInfo arrayInfo, IReadOnlyList values) : base(arrayInfo) { @@ -32,17 +32,14 @@ internal ArraySinglePrimitiveRecord(ArrayInfo arrayInfo, IReadOnlyList values ValuesToRead = 0; // there is nothing to read anymore } - public override RecordType RecordType => RecordType.ArraySinglePrimitive; + public override SerializationRecordType RecordType => SerializationRecordType.ArraySinglePrimitive; - public override TypeName ElementTypeName - => s_elementTypeName ??= TypeName.Parse(typeof(T).FullName.AsSpan()).WithAssemblyName(typeof(T).GetAssemblyNameIncludingTypeForwards()); + /// + public override TypeName TypeName + => s_typeName ??= TypeName.Parse((typeof(T[]).FullName + "," + TypeNameExtensions.CoreLibAssemblyName).AsSpan()); internal IReadOnlyList Values { get; } - public override bool IsTypeNameMatching(Type type) => typeof(T[]) == type; - - internal override bool IsElementType(Type typeElement) => typeElement == typeof(T); - /// public override T[] GetArray(bool allowNulls = true) => (T[])(_arrayNullsNotAllowed ??= (Values is T[] array ? array : Values.ToArray())); diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySingleStringRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs similarity index 80% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySingleStringRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs index 207a0a3499e6f..4d7f5ace47679 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ArraySingleStringRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; using System.IO; using System.Reflection.Metadata; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a single dimensional array of . @@ -14,23 +14,20 @@ namespace System.Runtime.Serialization.BinaryFormat; /// /// ArraySingleString records are described in [MS-NRBF] 2.4.3.4. /// -internal sealed class ArraySingleStringRecord : ArrayRecord +internal sealed class ArraySingleStringRecord : SZArrayRecord { - private static TypeName? s_elementTypeName; + private static TypeName? s_typeName; private ArraySingleStringRecord(ArrayInfo arrayInfo) : base(arrayInfo) => Records = []; - public override RecordType RecordType => RecordType.ArraySingleString; + public override SerializationRecordType RecordType => SerializationRecordType.ArraySingleString; - public override TypeName ElementTypeName - => s_elementTypeName ??= TypeName.Parse(typeof(string).FullName.AsSpan()).WithCoreLibAssemblyName(); + /// + public override TypeName TypeName + => s_typeName ??= TypeName.Parse(("System.String[], " + TypeNameExtensions.CoreLibAssemblyName).AsSpan()); private List Records { get; } - public override bool IsTypeNameMatching(Type type) => type == typeof(string[]); - - internal override bool IsElementType(Type typeElement) => typeElement == typeof(string); - internal static ArraySingleStringRecord Decode(BinaryReader reader) => new(ArrayInfo.Decode(reader)); diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryArrayRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs similarity index 78% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryArrayRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs index 1f66ed0903792..0c7e04e840a48 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryArrayRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs @@ -5,9 +5,9 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection.Metadata; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents an array other than single dimensional array of primitive types or . @@ -26,7 +26,7 @@ internal sealed class BinaryArrayRecord : ArrayRecord typeof(TimeSpan), typeof(string), typeof(object) ]; - private TypeName? _elementTypeName; + private TypeName? _typeName; private BinaryArrayRecord(ArrayInfo arrayInfo, MemberTypeInfo memberTypeInfo) : base(arrayInfo) @@ -35,13 +35,13 @@ private BinaryArrayRecord(ArrayInfo arrayInfo, MemberTypeInfo memberTypeInfo) Values = []; } - public override RecordType RecordType => RecordType.BinaryArray; + public override SerializationRecordType RecordType => SerializationRecordType.BinaryArray; /// public override ReadOnlySpan Lengths => new int[1] { Length }; - public override TypeName ElementTypeName - => _elementTypeName ??= MemberTypeInfo.GetElementTypeName(); + public override TypeName TypeName + => _typeName ??= MemberTypeInfo.GetArrayTypeName(ArrayInfo); private int Length => ArrayInfo.GetSZArrayLength(); @@ -80,17 +80,17 @@ private protected override Array Deserialize(Type arrayType, bool allowNulls) switch (record.RecordType) { - case RecordType.BinaryArray: - case RecordType.ArraySinglePrimitive: - case RecordType.ArraySingleObject: - case RecordType.ArraySingleString: + case SerializationRecordType.BinaryArray: + case SerializationRecordType.ArraySinglePrimitive: + case SerializationRecordType.ArraySingleObject: + case SerializationRecordType.ArraySingleString: ArrayRecord nestedArrayRecord = (ArrayRecord)record; Array nestedArray = nestedArrayRecord.GetArray(actualElementType, allowNulls); array.SetValue(nestedArray, resultIndex++); break; - case RecordType.ObjectNull: - case RecordType.ObjectNullMultiple256: - case RecordType.ObjectNullMultiple: + case SerializationRecordType.ObjectNull: + case SerializationRecordType.ObjectNullMultiple256: + case SerializationRecordType.ObjectNullMultiple: if (!allowNulls) { ThrowHelper.ThrowArrayContainedNulls(); @@ -115,11 +115,11 @@ private protected override Array Deserialize(Type arrayType, bool allowNulls) internal static ArrayRecord Decode(BinaryReader reader, RecordMap recordMap, PayloadOptions options) { - int objectId = reader.ReadInt32(); + SerializationRecordId objectId = SerializationRecordId.Decode(reader); BinaryArrayType arrayType = reader.ReadArrayType(); int rank = reader.ReadInt32(); - bool isRectangular = arrayType is BinaryArrayType.Rectangular or BinaryArrayType.RectangularOffset; + bool isRectangular = arrayType is BinaryArrayType.Rectangular; // It is an arbitrary limit in the current CoreCLR type loader. const int MaxSupportedArrayRank = 32; @@ -144,39 +144,12 @@ internal static ArrayRecord Decode(BinaryReader reader, RecordMap recordMap, Pay } } - int[] offsets = new int[rank]; // zero-init; adversary-controlled, but acceptable since upper limit of 32 - bool hasCustomOffset = false; - if (arrayType is BinaryArrayType.SingleOffset or BinaryArrayType.JaggedOffset or BinaryArrayType.RectangularOffset) - { - for (int i = 0; i < offsets.Length; i++) - { - int offset = reader.ReadInt32(); - - if (offset < 0) - { - ThrowHelper.ThrowInvalidValue(offset); - } - else if (offset > 0) - { - hasCustomOffset = true; - - long maxIndex = lengths[i] + offset; - if (maxIndex > int.MaxValue) - { - ThrowHelper.ThrowInvalidValue(maxIndex); - } - } - - offsets[i] = offset; - } - } - MemberTypeInfo memberTypeInfo = MemberTypeInfo.Decode(reader, 1, options, recordMap); ArrayInfo arrayInfo = new(objectId, totalElementCount, arrayType, rank); - if (isRectangular || hasCustomOffset) + if (isRectangular) { - return RectangularOrCustomOffsetArrayRecord.Create(reader, arrayInfo, memberTypeInfo, lengths, offsets); + return RectangularArrayRecord.Create(reader, arrayInfo, memberTypeInfo, lengths); } return memberTypeInfo.ShouldBeRepresentedAsArrayOfClassRecords() @@ -199,9 +172,6 @@ internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetA return (allowed, primitiveType); } - internal override bool IsElementType(Type typeElement) - => MemberTypeInfo.IsElementType(typeElement); - /// /// Complex types must not be instantiated, but represented as ClassRecord. /// For arrays of primitive types like int, string and object this method returns the element type. diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryArrayType.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayType.cs similarity index 56% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryArrayType.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayType.cs index 837b134dd4a1d..a4fac135a47a2 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryArrayType.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayType.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Indicates the kind of an array for an NRBF BinaryArray record. @@ -9,12 +9,7 @@ namespace System.Runtime.Serialization.BinaryFormat; /// /// BinaryArrayType enumeration is described in [MS-NRBF] 2.4.1.1. /// -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -enum BinaryArrayType : byte +internal enum BinaryArrayType : byte { /// /// A single-dimensional array. @@ -29,20 +24,5 @@ enum BinaryArrayType : byte /// /// A multi-dimensional rectangular array. /// - Rectangular = 2, - - /// - /// A single-dimensional array where the lower bound index is greater than 0. - /// - SingleOffset = 3, - - /// - /// A jagged array where the lower bound index is greater than 0. - /// - JaggedOffset = 4, - - /// - /// Multi-dimensional arrays where the lower bound index of at least one of the dimensions is greater than 0. - /// - RectangularOffset = 5, + Rectangular = 2 } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryLibraryRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs similarity index 50% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryLibraryRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs index c6f5ef47e65b9..d7a92293fdd2b 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryLibraryRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs @@ -1,9 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.IO; +using System.Reflection.Metadata; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a library. @@ -13,19 +15,28 @@ namespace System.Runtime.Serialization.BinaryFormat; /// internal sealed class BinaryLibraryRecord : SerializationRecord { - private BinaryLibraryRecord(int libraryId, string libraryName) + private BinaryLibraryRecord(SerializationRecordId libraryId, string libraryName) { - ObjectId = libraryId; + Id = libraryId; LibraryName = libraryName; } - public override RecordType RecordType => RecordType.BinaryLibrary; + public override SerializationRecordType RecordType => SerializationRecordType.BinaryLibrary; + + public override TypeName TypeName + { + get + { + Debug.Fail("TypeName should never be called on BinaryLibraryRecord"); + return TypeName.Parse(nameof(BinaryLibraryRecord).AsSpan()); + } + } internal string LibraryName { get; } /// - public override int ObjectId { get; } + public override SerializationRecordId Id { get; } internal static BinaryLibraryRecord Decode(BinaryReader reader) - => new(reader.ReadInt32(), reader.ReadString()); + => new(SerializationRecordId.Decode(reader), reader.ReadString()); } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryObjectStringRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryObjectStringRecord.cs similarity index 62% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryObjectStringRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryObjectStringRecord.cs index d29a4d3b613a4..0065a6a56eb62 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryObjectStringRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryObjectStringRecord.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.IO; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a record. @@ -12,19 +12,19 @@ namespace System.Runtime.Serialization.BinaryFormat; /// /// BinaryObjectString records are described in [MS-NRBF] 2.5.7. /// -[DebuggerDisplay("{Value}, {ObjectId}")] +[DebuggerDisplay("{Value}, {Id}")] internal sealed class BinaryObjectStringRecord : PrimitiveTypeRecord { - private BinaryObjectStringRecord(int objectId, string value) : base(value) + private BinaryObjectStringRecord(SerializationRecordId id, string value) : base(value) { - ObjectId = objectId; + Id = id; } - public override RecordType RecordType => RecordType.BinaryObjectString; + public override SerializationRecordType RecordType => SerializationRecordType.BinaryObjectString; /// - public override int ObjectId { get; } + public override SerializationRecordId Id { get; } internal static BinaryObjectStringRecord Decode(BinaryReader reader) - => new(reader.ReadInt32(), reader.ReadString()); + => new(SerializationRecordId.Decode(reader), reader.ReadString()); } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryType.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryType.cs similarity index 96% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryType.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryType.cs index bf8677faa787c..be89c7daf0d24 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/BinaryType.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryType.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Identifies the remoting type of a class member or array item. diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassInfo.cs similarity index 86% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassInfo.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassInfo.cs index 2c92b390b0c6b..75340b72a4f0d 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassInfo.cs @@ -5,9 +5,10 @@ using System.Diagnostics; using System.IO; using System.Reflection.Metadata; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; +using System.Runtime.Serialization; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Class info that provides type and member names. @@ -21,14 +22,14 @@ internal sealed class ClassInfo private readonly string _rawName; private TypeName? _typeName; - private ClassInfo(int objectId, string rawName, Dictionary memberNames) + private ClassInfo(SerializationRecordId id, string rawName, Dictionary memberNames) { - ObjectId = objectId; + Id = id; _rawName = rawName; MemberNames = memberNames; } - internal int ObjectId { get; } + internal SerializationRecordId Id { get; } internal TypeName TypeName { @@ -43,7 +44,7 @@ internal TypeName TypeName internal static ClassInfo Decode(BinaryReader reader) { - int objectId = reader.ReadInt32(); + SerializationRecordId id = SerializationRecordId.Decode(reader); string typeName = reader.ReadString(); int memberCount = reader.ReadInt32(); @@ -72,7 +73,7 @@ internal static ClassInfo Decode(BinaryReader reader) throw new SerializationException(SR.Format(SR.Serialization_DuplicateMemberName, memberName)); } - return new ClassInfo(objectId, typeName, memberNames); + return new ClassInfo(id, typeName, memberNames); } internal void LoadTypeName(BinaryLibraryRecord libraryRecord, PayloadOptions payloadOptions) diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassRecord.cs similarity index 84% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassRecord.cs index 4d2a57f633450..04a60dea40b72 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassRecord.cs @@ -5,17 +5,12 @@ using System.Diagnostics; using System.Reflection.Metadata; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Defines the core behavior for NRBF class records and provides a base for derived classes. /// -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -abstract class ClassRecord : SerializationRecord +public abstract class ClassRecord : SerializationRecord { private protected ClassRecord(ClassInfo classInfo, MemberTypeInfo memberTypeInfo) { @@ -24,13 +19,17 @@ private protected ClassRecord(ClassInfo classInfo, MemberTypeInfo memberTypeInfo MemberValues = []; } - public TypeName TypeName => ClassInfo.TypeName; + /// + public override TypeName TypeName => ClassInfo.TypeName; - // Currently we don't expose raw values, so we are not preserving the order here. + /// + /// Gets the names of the serialized members. + /// + /// The names of the serialized members. public IEnumerable MemberNames => ClassInfo.MemberNames.Keys; /// - public override int ObjectId => ClassInfo.ObjectId; + public override SerializationRecordId Id => ClassInfo.Id; internal ClassInfo ClassInfo { get; } @@ -99,22 +98,14 @@ private protected ClassRecord(ClassInfo classInfo, MemberTypeInfo memberTypeInfo /// For primitive types like , or returns their value. /// For nulls, returns a null. /// For other types that are not arrays, returns an instance of . - /// For single-dimensional arrays returns where the generic type is the primitive type or . + /// For single-dimensional arrays returns where the generic type is the primitive type or . /// For jagged and multi-dimensional arrays, returns an instance of . /// /// public object? GetRawValue(string memberName) => GetMember(memberName); - /// - /// Retrieves an array for the provided . - /// - /// The name of the field. - /// to permit values; otherwise, . - /// The array itself or null. - /// does not refer to a known member. You can use to check if given member exists. - /// The specified member is not an array, or is an array with an element type other than . - public T?[]? GetArrayOfPrimitiveType(string memberName, bool allowNulls = true) - => GetMember>(memberName)?.GetArray(allowNulls); + /// + public ArrayRecord? GetArrayRecord(string memberName) => GetMember(memberName); /// /// Retrieves the of the provided . diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassTypeInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassTypeInfo.cs similarity index 87% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassTypeInfo.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassTypeInfo.cs index f48aacdb6ba45..6a9e9d7b90afe 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassTypeInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassTypeInfo.cs @@ -4,9 +4,9 @@ using System.Diagnostics; using System.IO; using System.Reflection.Metadata; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Identifies a class by it's name and library id. @@ -24,7 +24,7 @@ internal sealed class ClassTypeInfo internal static ClassTypeInfo Decode(BinaryReader reader, PayloadOptions options, RecordMap recordMap) { string rawName = reader.ReadString(); - int libraryId = reader.ReadInt32(); + SerializationRecordId libraryId = SerializationRecordId.Decode(reader); BinaryLibraryRecord library = (BinaryLibraryRecord)recordMap[libraryId]; diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassWithIdRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassWithIdRecord.cs similarity index 65% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassWithIdRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassWithIdRecord.cs index d824775bbb92d..e18033524d17e 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassWithIdRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassWithIdRecord.cs @@ -2,8 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; +using System.Runtime.Serialization; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a class information that references another class record's metadata. @@ -13,16 +14,16 @@ namespace System.Runtime.Serialization.BinaryFormat; /// internal sealed class ClassWithIdRecord : ClassRecord { - private ClassWithIdRecord(int objectId, ClassRecord metadataClass) : base(metadataClass.ClassInfo, metadataClass.MemberTypeInfo) + private ClassWithIdRecord(SerializationRecordId id, ClassRecord metadataClass) : base(metadataClass.ClassInfo, metadataClass.MemberTypeInfo) { - ObjectId = objectId; + Id = id; MetadataClass = metadataClass; } - public override RecordType RecordType => RecordType.ClassWithId; + public override SerializationRecordType RecordType => SerializationRecordType.ClassWithId; /// - public override int ObjectId { get; } + public override SerializationRecordId Id { get; } internal ClassRecord MetadataClass { get; } @@ -30,15 +31,15 @@ internal static ClassWithIdRecord Decode( BinaryReader reader, RecordMap recordMap) { - int objectId = reader.ReadInt32(); - int metadataId = reader.ReadInt32(); + SerializationRecordId id = SerializationRecordId.Decode(reader); + SerializationRecordId metadataId = SerializationRecordId.Decode(reader); if (recordMap[metadataId] is not ClassRecord referencedRecord) { throw new SerializationException(SR.Serialization_InvalidReference); } - return new ClassWithIdRecord(objectId, referencedRecord); + return new ClassWithIdRecord(id, referencedRecord); } internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetNextAllowedRecordType() diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassWithMembersAndTypesRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassWithMembersAndTypesRecord.cs similarity index 74% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassWithMembersAndTypesRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassWithMembersAndTypesRecord.cs index a09f422433f03..117e5e90ef681 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ClassWithMembersAndTypesRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ClassWithMembersAndTypesRecord.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a class information with type info and the source library. @@ -19,17 +19,13 @@ private ClassWithMembersAndTypesRecord(ClassInfo classInfo, MemberTypeInfo membe { } - public override RecordType RecordType => RecordType.ClassWithMembersAndTypes; - - public override bool IsTypeNameMatching(Type type) - => type.GetTypeFullNameIncludingTypeForwards() == ClassInfo.TypeName.FullName - && type.GetAssemblyNameIncludingTypeForwards() == ClassInfo.TypeName.AssemblyName!.FullName; + public override SerializationRecordType RecordType => SerializationRecordType.ClassWithMembersAndTypes; internal static ClassWithMembersAndTypesRecord Decode(BinaryReader reader, RecordMap recordMap, PayloadOptions options) { ClassInfo classInfo = ClassInfo.Decode(reader); MemberTypeInfo memberTypeInfo = MemberTypeInfo.Decode(reader, classInfo.MemberNames.Count, options, recordMap); - int libraryId = reader.ReadInt32(); + SerializationRecordId libraryId = SerializationRecordId.Decode(reader); BinaryLibraryRecord library = (BinaryLibraryRecord)recordMap[libraryId]; classInfo.LoadTypeName(library, options); diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberPrimitiveTypedRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberPrimitiveTypedRecord.cs similarity index 61% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberPrimitiveTypedRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberPrimitiveTypedRecord.cs index 59561769c3b44..9655561e9445b 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberPrimitiveTypedRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberPrimitiveTypedRecord.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a primitive value other than . @@ -12,10 +12,12 @@ namespace System.Runtime.Serialization.BinaryFormat; internal sealed class MemberPrimitiveTypedRecord : PrimitiveTypeRecord where T : unmanaged { - internal MemberPrimitiveTypedRecord(T value, int objectId = 0) : base(value) => ObjectId = objectId; + internal MemberPrimitiveTypedRecord(T value) : base(value) => Id = default; - public override RecordType RecordType => RecordType.MemberPrimitiveTyped; + internal MemberPrimitiveTypedRecord(T value, SerializationRecordId id) : base(value) => Id = id; + + public override SerializationRecordType RecordType => SerializationRecordType.MemberPrimitiveTyped; /// - public override int ObjectId { get; } + public override SerializationRecordId Id { get; } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberReferenceRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberReferenceRecord.cs similarity index 66% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberReferenceRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberReferenceRecord.cs index 0988ab27aa833..162cf0b1d5c57 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberReferenceRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberReferenceRecord.cs @@ -1,9 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.IO; +using System.Reflection.Metadata; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a record that contains a reference to another record that contains the actual value. @@ -13,28 +15,28 @@ namespace System.Runtime.Serialization.BinaryFormat; /// internal sealed class MemberReferenceRecord : SerializationRecord { - private MemberReferenceRecord(int reference, RecordMap recordMap) + private MemberReferenceRecord(SerializationRecordId reference, RecordMap recordMap) { Reference = reference; RecordMap = recordMap; } - public override RecordType RecordType => RecordType.MemberReference; + public override SerializationRecordType RecordType => SerializationRecordType.MemberReference; - internal int Reference { get; } + internal SerializationRecordId Reference { get; } private RecordMap RecordMap { get; } // MemberReferenceRecord has no Id, which makes it impossible to create a cycle // by creating a reference to the reference itself. - public override int ObjectId => NoId; + public override SerializationRecordId Id => SerializationRecordId.NoId; - internal override object? GetValue() => GetReferencedRecord().GetValue(); + public override TypeName TypeName => GetReferencedRecord().TypeName; - public override bool IsTypeNameMatching(Type type) => GetReferencedRecord().IsTypeNameMatching(type); + internal override object? GetValue() => GetReferencedRecord().GetValue(); internal static MemberReferenceRecord Decode(BinaryReader reader, RecordMap recordMap) - => new(reader.ReadInt32(), recordMap); + => new(SerializationRecordId.Decode(reader), recordMap); internal SerializationRecord GetReferencedRecord() => RecordMap[Reference]; } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberTypeInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs similarity index 53% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberTypeInfo.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs index 8cbb429ac170a..9e6c2445877e0 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MemberTypeInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs @@ -5,9 +5,9 @@ using System.Diagnostics; using System.IO; using System.Reflection.Metadata; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Member type info. @@ -101,94 +101,25 @@ internal static MemberTypeInfo Decode(BinaryReader reader, int count, PayloadOpt }; } - internal bool IsElementType(Type typeElement) - { - (BinaryType binaryType, object? additionalInfo) = Infos[0]; - - switch (binaryType) - { - case BinaryType.String: - return typeElement == typeof(string); - case BinaryType.StringArray: - return typeElement == typeof(string[]); - case BinaryType.Object: - return typeElement == typeof(object); - case BinaryType.ObjectArray: - return typeElement == typeof(object[]); - case BinaryType.Primitive: - case BinaryType.PrimitiveArray: - if (binaryType is BinaryType.PrimitiveArray) - { - if (!typeElement.IsArray) - { - return false; - } - - typeElement = typeElement.GetElementType()!; - } - - return ((PrimitiveType)additionalInfo!) switch - { - PrimitiveType.Boolean => typeElement == typeof(bool), - PrimitiveType.Byte => typeElement == typeof(byte), - PrimitiveType.Char => typeElement == typeof(char), - PrimitiveType.Decimal => typeElement == typeof(decimal), - PrimitiveType.Double => typeElement == typeof(double), - PrimitiveType.Int16 => typeElement == typeof(short), - PrimitiveType.Int32 => typeElement == typeof(int), - PrimitiveType.Int64 => typeElement == typeof(long), - PrimitiveType.SByte => typeElement == typeof(sbyte), - PrimitiveType.Single => typeElement == typeof(float), - PrimitiveType.TimeSpan => typeElement == typeof(TimeSpan), - PrimitiveType.DateTime => typeElement == typeof(DateTime), - PrimitiveType.UInt16 => typeElement == typeof(ushort), - PrimitiveType.UInt32 => typeElement == typeof(uint), - PrimitiveType.UInt64 => typeElement == typeof(ulong), - _ => false - }; - case BinaryType.SystemClass: - if (typeElement.Assembly != typeof(object).Assembly) - { - return false; - } - - TypeName typeName = (TypeName)additionalInfo!; - string fullSystemClassName = typeElement.GetTypeFullNameIncludingTypeForwards(); - return typeName.FullName == fullSystemClassName; - default: - Debug.Assert(binaryType is BinaryType.Class, "The parsers should reject other inputs"); - - ClassTypeInfo typeInfo = (ClassTypeInfo)additionalInfo!; - string fullClassName = typeElement.GetTypeFullNameIncludingTypeForwards(); - if (typeInfo.TypeName.FullName != fullClassName) - { - return false; - } - - string assemblyName = typeElement.GetAssemblyNameIncludingTypeForwards(); - return assemblyName == typeInfo.TypeName.AssemblyName!.FullName; - } - } - internal bool ShouldBeRepresentedAsArrayOfClassRecords() { // This library tries to minimize the number of concepts the users need to learn to use it. - // Since SZArrays are most common, it provides an ArrayRecord abstraction. - // Every other array (jagged, multi-dimensional etc) is represented using ArrayRecord. - // The goal of this method is to determine whether given array can be represented as ArrayRecord. + // Since SZArrays are most common, it provides an SZArrayRecord abstraction. + // Every other array (jagged, multi-dimensional etc) is represented using SZArrayRecord. + // The goal of this method is to determine whether given array can be represented as SZArrayRecord. (BinaryType binaryType, object? additionalInfo) = Infos[0]; if (binaryType == BinaryType.Class) { - // An array of arrays can not be represented as ArrayRecord. + // An array of arrays can not be represented as SZArrayRecord. return !((ClassTypeInfo)additionalInfo!).TypeName.IsArray; } else if (binaryType == BinaryType.SystemClass) { TypeName typeName = (TypeName)additionalInfo!; - // An array of arrays can not be represented as ArrayRecord. + // An array of arrays can not be represented as SZArrayRecord. if (typeName.IsArray) { return false; @@ -199,7 +130,7 @@ internal bool ShouldBeRepresentedAsArrayOfClassRecords() return true; } - // Can't use ArrayRecord for Nullable[] + // Can't use SZArrayRecord for Nullable[] // as it consists of MemberPrimitiveTypedRecord and NullsRecord return typeName.GetGenericTypeDefinition().FullName != typeof(Nullable<>).FullName; } @@ -207,50 +138,67 @@ internal bool ShouldBeRepresentedAsArrayOfClassRecords() return false; } - internal TypeName GetElementTypeName() + internal TypeName GetArrayTypeName(ArrayInfo arrayInfo) { (BinaryType binaryType, object? additionalInfo) = Infos[0]; switch (binaryType) { case BinaryType.String: - return TypeName.Parse(typeof(string).FullName.AsSpan()).WithCoreLibAssemblyName(); + return typeof(string).BuildCoreLibArrayTypeName(arrayInfo.Rank); case BinaryType.StringArray: - return TypeName.Parse(typeof(string[]).FullName.AsSpan()).WithCoreLibAssemblyName(); + return typeof(string[]).BuildCoreLibArrayTypeName(arrayInfo.Rank); case BinaryType.Object: - return TypeName.Parse(typeof(object).FullName.AsSpan()).WithCoreLibAssemblyName(); + return typeof(object).BuildCoreLibArrayTypeName(arrayInfo.Rank); case BinaryType.ObjectArray: - return TypeName.Parse(typeof(object[]).FullName.AsSpan()).WithCoreLibAssemblyName(); + return typeof(object[]).BuildCoreLibArrayTypeName(arrayInfo.Rank); case BinaryType.Primitive: - case BinaryType.PrimitiveArray: - string? name = ((PrimitiveType)additionalInfo!) switch + Type primitiveType = ((PrimitiveType)additionalInfo!) switch { - PrimitiveType.Boolean => typeof(bool).FullName, - PrimitiveType.Byte => typeof(byte).FullName, - PrimitiveType.Char => typeof(char).FullName, - PrimitiveType.Decimal => typeof(decimal).FullName, - PrimitiveType.Double => typeof(double).FullName, - PrimitiveType.Int16 => typeof(short).FullName, - PrimitiveType.Int32 => typeof(int).FullName, - PrimitiveType.Int64 => typeof(long).FullName, - PrimitiveType.SByte => typeof(sbyte).FullName, - PrimitiveType.Single => typeof(float).FullName, - PrimitiveType.TimeSpan => typeof(TimeSpan).FullName, - PrimitiveType.DateTime => typeof(DateTime).FullName, - PrimitiveType.UInt16 => typeof(ushort).FullName, - PrimitiveType.UInt32 => typeof(uint).FullName, - _ => typeof(ulong).FullName, + PrimitiveType.Boolean => typeof(bool), + PrimitiveType.Byte => typeof(byte), + PrimitiveType.Char => typeof(char), + PrimitiveType.Decimal => typeof(decimal), + PrimitiveType.Double => typeof(double), + PrimitiveType.Int16 => typeof(short), + PrimitiveType.Int32 => typeof(int), + PrimitiveType.Int64 => typeof(long), + PrimitiveType.SByte => typeof(sbyte), + PrimitiveType.Single => typeof(float), + PrimitiveType.TimeSpan => typeof(TimeSpan), + PrimitiveType.DateTime => typeof(DateTime), + PrimitiveType.UInt16 => typeof(ushort), + PrimitiveType.UInt32 => typeof(uint), + _ => typeof(ulong), }; - return binaryType is BinaryType.PrimitiveArray - ? TypeName.Parse($"{name}[], {TypeNameExtensions.CoreLibAssemblyName}".AsSpan()) - : TypeName.Parse(name.AsSpan()).WithCoreLibAssemblyName(); + return primitiveType.BuildCoreLibArrayTypeName(arrayInfo.Rank); + case BinaryType.PrimitiveArray: + Type primitiveArrayType = ((PrimitiveType)additionalInfo!) switch + { + PrimitiveType.Boolean => typeof(bool[]), + PrimitiveType.Byte => typeof(byte[]), + PrimitiveType.Char => typeof(char[]), + PrimitiveType.Decimal => typeof(decimal[]), + PrimitiveType.Double => typeof(double[]), + PrimitiveType.Int16 => typeof(short[]), + PrimitiveType.Int32 => typeof(int[]), + PrimitiveType.Int64 => typeof(long[]), + PrimitiveType.SByte => typeof(sbyte[]), + PrimitiveType.Single => typeof(float[]), + PrimitiveType.TimeSpan => typeof(TimeSpan[]), + PrimitiveType.DateTime => typeof(DateTime[]), + PrimitiveType.UInt16 => typeof(ushort[]), + PrimitiveType.UInt32 => typeof(uint[]), + _ => typeof(ulong[]), + }; + return primitiveArrayType.BuildCoreLibArrayTypeName(arrayInfo.Rank); case BinaryType.SystemClass: - return (TypeName)additionalInfo!; + return ((TypeName)additionalInfo!).BuildArrayTypeName(arrayInfo.Rank); default: Debug.Assert(binaryType is BinaryType.Class, "The parsers should reject other inputs"); - return ((ClassTypeInfo)additionalInfo!).TypeName; + return (((ClassTypeInfo)additionalInfo!).TypeName).BuildArrayTypeName(arrayInfo.Rank); } } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MessageEndRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs similarity index 56% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MessageEndRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs index 6400bf8160ddc..7cb28224a890e 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/MessageEndRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs @@ -1,7 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.Serialization.BinaryFormat; +using System.Diagnostics; +using System.Reflection.Metadata; + +namespace System.Formats.Nrbf; /// /// Represents the record that marks the end of the binary format stream. @@ -17,7 +20,16 @@ private MessageEndRecord() { } - public override RecordType RecordType => RecordType.MessageEnd; + public override SerializationRecordType RecordType => SerializationRecordType.MessageEnd; + + public override SerializationRecordId Id => SerializationRecordId.NoId; - public override int ObjectId => NoId; + public override TypeName TypeName + { + get + { + Debug.Fail("TypeName should never be called on MessageEndRecord"); + return TypeName.Parse(nameof(MessageEndRecord).AsSpan()); + } + } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/NextInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NextInfo.cs similarity index 95% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/NextInfo.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NextInfo.cs index efcc9c70670d8..a01a25e60047a 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/NextInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NextInfo.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; [DebuggerDisplay("{Parent.RecordType}, {Allowed}, {PrimitiveType}")] internal readonly struct NextInfo diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PayloadReader.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs similarity index 77% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PayloadReader.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs index c88e8f20bbbea..426755ee7fe87 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PayloadReader.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs @@ -5,17 +5,16 @@ using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; using System.Text; +using System.Runtime.Serialization; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -static class PayloadReader +/// +/// Provides stateless methods for decoding .NET Remoting Binary Format (NRBF) encoded data. +/// +public static class NrbfDecoder { private static UTF8Encoding ThrowOnInvalidUtf8Encoding { get; } = new(false, throwOnInvalidBytes: true); @@ -36,7 +35,7 @@ public static bool StartsWithPayloadHeader(byte[] bytes) #endif return bytes.Length >= SerializedStreamHeaderRecord.Size - && bytes[0] == (byte)RecordType.SerializedStreamHeader + && bytes[0] == (byte)SerializationRecordType.SerializedStreamHeader #if NET && BinaryPrimitives.ReadInt32LittleEndian(bytes.AsSpan(9)) == SerializedStreamHeaderRecord.MajorVersion && BinaryPrimitives.ReadInt32LittleEndian(bytes.AsSpan(13)) == SerializedStreamHeaderRecord.MinorVersion; @@ -102,7 +101,7 @@ public static bool StartsWithPayloadHeader(Stream stream) } /// - /// Reads the provided NRBF payload. + /// Decodes the provided NRBF payload. /// /// The NRBF payload. /// Options to control behavior during parsing. @@ -118,12 +117,12 @@ public static bool StartsWithPayloadHeader(Stream stream) /// Reading from encounters invalid NRBF data. /// Reading from /// encounters an invalid UTF8 sequence. - public static SerializationRecord Read(Stream payload, PayloadOptions? options = default, bool leaveOpen = false) - => Read(payload, out _, options, leaveOpen); + public static SerializationRecord Decode(Stream payload, PayloadOptions? options = default, bool leaveOpen = false) + => Decode(payload, out _, options, leaveOpen); /// The NRBF payload. /// - /// When this method returns, contains a mapping of to the associated serialization record. + /// When this method returns, contains a mapping of to the associated serialization record. /// This parameter is treated as uninitialized. /// /// An object that describes optional parameters to use. @@ -131,8 +130,8 @@ public static SerializationRecord Read(Stream payload, PayloadOptions? options = /// to leave payload open /// after the reading is finished; otherwise, . /// - /// - public static SerializationRecord Read(Stream payload, out IReadOnlyDictionary recordMap, PayloadOptions? options = default, bool leaveOpen = false) + /// + public static SerializationRecord Decode(Stream payload, out IReadOnlyDictionary recordMap, PayloadOptions? options = default, bool leaveOpen = false) { #if NET ArgumentNullException.ThrowIfNull(payload); @@ -144,29 +143,29 @@ public static SerializationRecord Read(Stream payload, out IReadOnlyDictionary - /// Reads the provided NRBF payload that is expected to contain an instance of any class (or struct) that is not an or a primitive type. + /// Decodes the provided NRBF payload that is expected to contain an instance of any class (or struct) that is not an or a primitive type. /// /// A that represents the root object. - /// - public static ClassRecord ReadClassRecord(Stream payload, PayloadOptions? options = default, bool leaveOpen = false) - => (ClassRecord)Read(payload, options, leaveOpen); + /// + public static ClassRecord DecodeClassRecord(Stream payload, PayloadOptions? options = default, bool leaveOpen = false) + => (ClassRecord)Decode(payload, options, leaveOpen); - private static SerializationRecord Read(BinaryReader reader, PayloadOptions options, out IReadOnlyDictionary readOnlyRecordMap) + private static SerializationRecord Decode(BinaryReader reader, PayloadOptions options, out IReadOnlyDictionary readOnlyRecordMap) { Stack readStack = new(); - var recordMap = new RecordMap(); + RecordMap recordMap = new(); // Everything has to start with a header - var header = (SerializedStreamHeaderRecord)ReadNext(reader, recordMap, AllowedRecordTypes.SerializedStreamHeader, options, out _); + var header = (SerializedStreamHeaderRecord)DecodeNext(reader, recordMap, AllowedRecordTypes.SerializedStreamHeader, options, out _); // and can be followed by any Object, BinaryLibrary and a MessageEnd. const AllowedRecordTypes Allowed = AllowedRecordTypes.AnyObject | AllowedRecordTypes.BinaryLibrary | AllowedRecordTypes.MessageEnd; - RecordType recordType; + SerializationRecordType recordType; SerializationRecord nextRecord; do { @@ -176,10 +175,10 @@ private static SerializationRecord Read(BinaryReader reader, PayloadOptions opti if (nextInfo.Allowed != AllowedRecordTypes.None) { - // Read the next Record + // Decode the next Record do { - nextRecord = ReadNext(reader, recordMap, nextInfo.Allowed, options, out _); + nextRecord = DecodeNext(reader, recordMap, nextInfo.Allowed, options, out _); // BinaryLibrary often precedes class records. // It has been already added to the RecordMap and it must not be added // to the array record, so simply read next record. @@ -203,42 +202,42 @@ private static SerializationRecord Read(BinaryReader reader, PayloadOptions opti } } - nextRecord = ReadNext(reader, recordMap, Allowed, options, out recordType); + nextRecord = DecodeNext(reader, recordMap, Allowed, options, out recordType); PushFirstNestedRecordInfo(nextRecord, readStack); } - while (recordType != RecordType.MessageEnd); + while (recordType != SerializationRecordType.MessageEnd); readOnlyRecordMap = recordMap; return recordMap.GetRootRecord(header); } - private static SerializationRecord ReadNext(BinaryReader reader, RecordMap recordMap, - AllowedRecordTypes allowed, PayloadOptions options, out RecordType recordType) + private static SerializationRecord DecodeNext(BinaryReader reader, RecordMap recordMap, + AllowedRecordTypes allowed, PayloadOptions options, out SerializationRecordType recordType) { byte nextByte = reader.ReadByte(); if (((uint)allowed & (1u << nextByte)) == 0) { ThrowHelper.ThrowForUnexpectedRecordType(nextByte); } - recordType = (RecordType)nextByte; + recordType = (SerializationRecordType)nextByte; SerializationRecord record = recordType switch { - RecordType.ArraySingleObject => ArraySingleObjectRecord.Decode(reader), - RecordType.ArraySinglePrimitive => DecodeArraySinglePrimitiveRecord(reader), - RecordType.ArraySingleString => ArraySingleStringRecord.Decode(reader), - RecordType.BinaryArray => BinaryArrayRecord.Decode(reader, recordMap, options), - RecordType.BinaryLibrary => BinaryLibraryRecord.Decode(reader), - RecordType.BinaryObjectString => BinaryObjectStringRecord.Decode(reader), - RecordType.ClassWithId => ClassWithIdRecord.Decode(reader, recordMap), - RecordType.ClassWithMembersAndTypes => ClassWithMembersAndTypesRecord.Decode(reader, recordMap, options), - RecordType.MemberPrimitiveTyped => DecodeMemberPrimitiveTypedRecord(reader), - RecordType.MemberReference => MemberReferenceRecord.Decode(reader, recordMap), - RecordType.MessageEnd => MessageEndRecord.Singleton, - RecordType.ObjectNull => ObjectNullRecord.Instance, - RecordType.ObjectNullMultiple => ObjectNullMultipleRecord.Decode(reader), - RecordType.ObjectNullMultiple256 => ObjectNullMultiple256Record.Decode(reader), - RecordType.SerializedStreamHeader => SerializedStreamHeaderRecord.Decode(reader), + SerializationRecordType.ArraySingleObject => ArraySingleObjectRecord.Decode(reader), + SerializationRecordType.ArraySinglePrimitive => DecodeArraySinglePrimitiveRecord(reader), + SerializationRecordType.ArraySingleString => ArraySingleStringRecord.Decode(reader), + SerializationRecordType.BinaryArray => BinaryArrayRecord.Decode(reader, recordMap, options), + SerializationRecordType.BinaryLibrary => BinaryLibraryRecord.Decode(reader), + SerializationRecordType.BinaryObjectString => BinaryObjectStringRecord.Decode(reader), + SerializationRecordType.ClassWithId => ClassWithIdRecord.Decode(reader, recordMap), + SerializationRecordType.ClassWithMembersAndTypes => ClassWithMembersAndTypesRecord.Decode(reader, recordMap, options), + SerializationRecordType.MemberPrimitiveTyped => DecodeMemberPrimitiveTypedRecord(reader), + SerializationRecordType.MemberReference => MemberReferenceRecord.Decode(reader, recordMap), + SerializationRecordType.MessageEnd => MessageEndRecord.Singleton, + SerializationRecordType.ObjectNull => ObjectNullRecord.Instance, + SerializationRecordType.ObjectNullMultiple => ObjectNullMultipleRecord.Decode(reader), + SerializationRecordType.ObjectNullMultiple256 => ObjectNullMultiple256Record.Decode(reader), + SerializationRecordType.SerializedStreamHeader => SerializedStreamHeaderRecord.Decode(reader), _ => SystemClassWithMembersAndTypesRecord.Decode(reader, recordMap, options), }; diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs new file mode 100644 index 0000000000000..d3d859c193a9c --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Reflection.Metadata; + +namespace System.Formats.Nrbf; + +internal abstract class NullsRecord : SerializationRecord +{ + internal abstract int NullCount { get; } + + public override SerializationRecordId Id => SerializationRecordId.NoId; + + public override TypeName TypeName + { + get + { + Debug.Fail($"TypeName should never be called on {GetType().Name}"); + return TypeName.Parse(GetType().Name.AsSpan()); + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullMultiple256Record.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullMultiple256Record.cs similarity index 84% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullMultiple256Record.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullMultiple256Record.cs index bbab70b7d4174..aefaf167f3f62 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullMultiple256Record.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullMultiple256Record.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents multiple (less than 256) . @@ -16,7 +16,7 @@ internal sealed class ObjectNullMultiple256Record : NullsRecord { private ObjectNullMultiple256Record(byte count) => NullCount = count; - public override RecordType RecordType => RecordType.ObjectNullMultiple256; + public override SerializationRecordType RecordType => SerializationRecordType.ObjectNullMultiple256; internal override int NullCount { get; } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullMultipleRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullMultipleRecord.cs similarity index 84% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullMultipleRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullMultipleRecord.cs index 6ec35afe97870..42f292eccbf5e 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullMultipleRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullMultipleRecord.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents multiple . @@ -16,7 +16,7 @@ internal sealed class ObjectNullMultipleRecord : NullsRecord { private ObjectNullMultipleRecord(int count) => NullCount = count; - public override RecordType RecordType => RecordType.ObjectNullMultiple; + public override SerializationRecordType RecordType => SerializationRecordType.ObjectNullMultiple; internal override int NullCount { get; } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullRecord.cs similarity index 83% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullRecord.cs index 3797f1058d0aa..82b0a9b19e37a 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/ObjectNullRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ObjectNullRecord.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a . @@ -13,7 +13,7 @@ internal sealed class ObjectNullRecord : NullsRecord { internal static ObjectNullRecord Instance { get; } = new(); - public override RecordType RecordType => RecordType.ObjectNull; + public override SerializationRecordType RecordType => SerializationRecordType.ObjectNull; internal override int NullCount => 1; diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PayloadOptions.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PayloadOptions.cs similarity index 67% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PayloadOptions.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PayloadOptions.cs index 7d8dbc24aae1b..60d1aafcc5291 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PayloadOptions.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PayloadOptions.cs @@ -3,17 +3,21 @@ using System.Reflection.Metadata; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -sealed class PayloadOptions +/// +/// Defines a variety of configuration options for decoding NRBF payloads. +/// +public sealed class PayloadOptions { + /// + /// Initializes a instance with default values. + /// public PayloadOptions() { } + /// + /// Configuration options for parsing instances. + /// public TypeNameParseOptions? TypeNameParseOptions { get; set; } /// diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PrimitiveType.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs similarity index 94% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PrimitiveType.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs index 7d6b91ae3f962..9ddb9179518fa 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PrimitiveType.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Primitive type. diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecord.cs new file mode 100644 index 0000000000000..39e0794658c63 --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecord.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Formats.Nrbf; + +/// +/// Represents a record that itself represents a primitive value. +/// +/// +/// +/// The NRBF specification considers the following types to be primitive: +/// , , , +/// , , , +/// , , , , +/// , , , +/// and . +/// +/// Other serialization records are represented with or . +/// +[DebuggerDisplay("{Value}")] +public abstract class PrimitiveTypeRecord : SerializationRecord +{ + private protected PrimitiveTypeRecord() + { + } + + /// + /// Gets the serialized primitive value. + /// + /// The primitive value. + public object Value => GetValue()!; +} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PrimitiveTypeRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecordOfT.cs similarity index 68% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PrimitiveTypeRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecordOfT.cs index 593b9c826fb3a..72ef801e61eb3 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/PrimitiveTypeRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveTypeRecordOfT.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Formats.Nrbf.Utils; +using System.Reflection.Metadata; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents a record that itself represents the primitive value of type. @@ -21,18 +23,21 @@ namespace System.Runtime.Serialization.BinaryFormat; /// Other serialization records are represented with or . /// [DebuggerDisplay("{Value}")] -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -abstract class PrimitiveTypeRecord : SerializationRecord +public abstract class PrimitiveTypeRecord : PrimitiveTypeRecord { + private static TypeName? s_typeName; + private protected PrimitiveTypeRecord(T value) => Value = value; - public T Value { get; } + /// + /// Gets the serialized primitive value. + /// + /// The primitive value. + public new T Value { get; } - public override bool IsTypeNameMatching(Type type) => type == typeof(T); + /// + public override TypeName TypeName + => s_typeName ??= TypeName.Parse(typeof(T).FullName.AsSpan()).WithCoreLibAssemblyName(); internal override object? GetValue() => Value; } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RecordMap.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs similarity index 50% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RecordMap.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs index 6bb0b5c1c2de5..a25ab508f5db3 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RecordMap.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs @@ -4,28 +4,28 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.IO.Hashing; using System.Runtime.InteropServices; +using System.Runtime.Serialization; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; -internal sealed class RecordMap : IReadOnlyDictionary +internal sealed class RecordMap : IReadOnlyDictionary { - private readonly Dictionary _map = new(CollisionResistantInt32Comparer.Instance); + private readonly Dictionary _map = new(); - public IEnumerable Keys => _map.Keys; + public IEnumerable Keys => _map.Keys; public IEnumerable Values => _map.Values; public int Count => _map.Count; - public SerializationRecord this[int objectId] => _map[objectId]; + public SerializationRecord this[SerializationRecordId objectId] => _map[objectId]; - public bool ContainsKey(int key) => _map.ContainsKey(key); + public bool ContainsKey(SerializationRecordId key) => _map.ContainsKey(key); - public bool TryGetValue(int key, [MaybeNullWhen(false)] out SerializationRecord value) => _map.TryGetValue(key, out value); + public bool TryGetValue(SerializationRecordId key, [MaybeNullWhen(false)] out SerializationRecord value) => _map.TryGetValue(key, out value); - public IEnumerator> GetEnumerator() => _map.GetEnumerator(); + public IEnumerator> GetEnumerator() => _map.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _map.GetEnumerator(); @@ -34,29 +34,29 @@ internal void Add(SerializationRecord record) // From https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/0a192be0-58a1-41d0-8a54-9c91db0ab7bf: // "If the ObjectId is not referenced by any MemberReference in the serialization stream, // then the ObjectId SHOULD be positive, but MAY be negative." - if (record.ObjectId != SerializationRecord.NoId) + if (!record.Id.Equals(SerializationRecordId.NoId)) { - if (record.ObjectId < 0) + if (record.Id._id < 0) { // Negative record Ids should never be referenced. Duplicate negative ids can be // exported by the writer. The root object Id can be negative. - _map[record.ObjectId] = record; + _map[record.Id] = record; } else { #if NET - if (_map.TryAdd(record.ObjectId, record)) + if (_map.TryAdd(record.Id, record)) { return; } #else - if (!_map.ContainsKey(record.ObjectId)) + if (!_map.ContainsKey(record.Id)) { - _map.Add(record.ObjectId, record); + _map.Add(record.Id, record); return; } #endif - throw new SerializationException(SR.Format(SR.Serialization_DuplicateSerializationRecordId, record.ObjectId)); + throw new SerializationException(SR.Format(SR.Serialization_DuplicateSerializationRecordId, record.Id)); } } } @@ -72,24 +72,4 @@ internal SerializationRecord GetRootRecord(SerializedStreamHeaderRecord header) return rootRecord; } - - // keys (32-bit integer ids) are payload-provided so we need a collision-resistant comparer - private sealed class CollisionResistantInt32Comparer : IEqualityComparer - { - internal static CollisionResistantInt32Comparer Instance { get; } = new(); - - private CollisionResistantInt32Comparer() { } - - public bool Equals(int x, int y) => x == y; - - public int GetHashCode(int obj) - { -#if NET - Span integers = new(ref obj); -#else - Span integers = stackalloc int[1] { obj }; -#endif - return (int)XxHash32.HashToUInt32(MemoryMarshal.AsBytes(integers)); - } - } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RectangularOrCustomOffsetArrayRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs similarity index 85% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RectangularOrCustomOffsetArrayRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs index 5a1013ad0cb32..de3c6d671850a 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RectangularOrCustomOffsetArrayRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs @@ -7,23 +7,22 @@ using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; -internal sealed class RectangularOrCustomOffsetArrayRecord : ArrayRecord +internal sealed class RectangularArrayRecord : ArrayRecord { private readonly int[] _lengths; private readonly ICollection _values; - private TypeName? _elementTypeName; + private TypeName? _typeName; - private RectangularOrCustomOffsetArrayRecord(Type elementType, ArrayInfo arrayInfo, - MemberTypeInfo memberTypeInfo, int[] lengths, int[] offsets, bool canPreAllocate) : base(arrayInfo) + private RectangularArrayRecord(Type elementType, ArrayInfo arrayInfo, + MemberTypeInfo memberTypeInfo, int[] lengths, bool canPreAllocate) : base(arrayInfo) { ElementType = elementType; MemberTypeInfo = memberTypeInfo; _lengths = lengths; - Offsets = offsets; // A List can hold as many objects as an array, so for multi-dimensional arrays // with more elements than Array.MaxLength we use LinkedList. @@ -39,22 +38,17 @@ private RectangularOrCustomOffsetArrayRecord(Type elementType, ArrayInfo arrayIn } - public override RecordType RecordType => RecordType.BinaryArray; + public override SerializationRecordType RecordType => SerializationRecordType.BinaryArray; public override ReadOnlySpan Lengths => _lengths.AsSpan(); - public override TypeName ElementTypeName - => _elementTypeName ??= MemberTypeInfo.GetElementTypeName(); + public override TypeName TypeName + => _typeName ??= MemberTypeInfo.GetArrayTypeName(ArrayInfo); private Type ElementType { get; } private MemberTypeInfo MemberTypeInfo { get; } - private int[] Offsets { get; } - - internal override bool IsElementType(Type typeElement) - => MemberTypeInfo.IsElementType(typeElement); - [RequiresDynamicCode("May call Array.CreateInstance() and Type.MakeArrayType().")] private protected override Array Deserialize(Type arrayType, bool allowNulls) { @@ -63,15 +57,14 @@ private protected override Array Deserialize(Type arrayType, bool allowNulls) Array result = #if NET9_0_OR_GREATER ElementType == typeof(ClassRecord) - ? Array.CreateInstance(ElementType, _lengths, Offsets) - : Array.CreateInstanceFromArrayType(arrayType, _lengths, Offsets); + ? Array.CreateInstance(ElementType, _lengths) + : Array.CreateInstanceFromArrayType(arrayType, _lengths); #else - Array.CreateInstance(ElementType, _lengths, Offsets); + Array.CreateInstance(ElementType, _lengths); #endif #if !NET8_0_OR_GREATER - int[] indices = new int[Offsets.Length]; - Offsets.CopyTo(indices, 0); // respect custom offsets + int[] indices = new int[_lengths.Length]; foreach (object value in _values) { @@ -81,11 +74,11 @@ private protected override Array Deserialize(Type arrayType, bool allowNulls) while (dimension >= 0) { indices[dimension]++; - if (indices[dimension] < Offsets[dimension] + Lengths[dimension]) + if (indices[dimension] < Lengths[dimension]) { break; } - indices[dimension] = Offsets[dimension]; + indices[dimension] = 0; dimension--; } @@ -153,8 +146,8 @@ internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetA return (allowed, primitiveType); } - internal static RectangularOrCustomOffsetArrayRecord Create(BinaryReader reader, ArrayInfo arrayInfo, - MemberTypeInfo memberTypeInfo, int[] lengths, int[] offsets) + internal static RectangularArrayRecord Create(BinaryReader reader, ArrayInfo arrayInfo, + MemberTypeInfo memberTypeInfo, int[] lengths) { BinaryType binaryType = memberTypeInfo.Infos[0].BinaryType; Type elementType = binaryType switch @@ -202,7 +195,7 @@ internal static RectangularOrCustomOffsetArrayRecord Create(BinaryReader reader, } } - return new RectangularOrCustomOffsetArrayRecord(elementType, arrayInfo, memberTypeInfo, lengths, offsets, canPreAllocate); + return new RectangularArrayRecord(elementType, arrayInfo, memberTypeInfo, lengths, canPreAllocate); } private static Type MapPrimitive(PrimitiveType primitiveType) diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SZArrayRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SZArrayRecord.cs new file mode 100644 index 0000000000000..0eef853a1e18a --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SZArrayRecord.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata; +using System.Formats.Nrbf.Utils; + +namespace System.Formats.Nrbf; + +/// +/// Defines the core behavior for NRBF single dimensional, zero-indexed array records and provides a base for derived classes. +/// +/// +public abstract class SZArrayRecord : ArrayRecord +{ + private protected SZArrayRecord(ArrayInfo arrayInfo) : base(arrayInfo) + { + } + + /// + /// Gets the length of the array. + /// + /// The length of the array. + public int Length => ArrayInfo.GetSZArrayLength(); + + /// + public override ReadOnlySpan Lengths => new int[1] { Length }; + + /// + /// When overridden in a derived class, allocates an array of and fills it with the data provided in the serialized records (in case of primitive types like or ) or the serialized records themselves. + /// + /// + /// to permit values within the array; + /// otherwise, . + /// + /// An array filled with the data provided in the serialized records. + public abstract T?[] GetArray(bool allowNulls = true); + +#pragma warning disable IL3051 // RequiresDynamicCode is not required in this particualar case + private protected override Array Deserialize(Type arrayType, bool allowNulls) => GetArray(allowNulls); +#pragma warning restore IL3051 +} diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs new file mode 100644 index 0000000000000..ccfce69124b70 --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs @@ -0,0 +1,121 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Collections.Immutable; + +namespace System.Formats.Nrbf; + +/// +/// Abstract class that represents the serialization record. +/// +/// +/// +/// Every instance returned to the end user can be either , +/// a or an . +/// +/// +[DebuggerDisplay("{RecordType}, {Id}")] +public abstract class SerializationRecord +{ + internal SerializationRecord() // others can't derive from this type + { + } + + /// + /// Gets the type of the record. + /// + /// The type of the record. + public abstract SerializationRecordType RecordType { get; } + + /// + /// Gets the ID of the record. + /// + /// The ID of the record. + public abstract SerializationRecordId Id { get; } + + /// + /// Gets the name of the serialized type. + /// + /// The name of the serialized type. + public abstract TypeName TypeName { get; } + + /// + /// Compares the type name read from the payload against the specified type. + /// + /// + /// This method ignores assembly names. + /// This method does NOT take into account member names or their genericTypes. + /// + /// The type to compare against. + /// if the serialized type name match provided type; otherwise, . + public bool TypeNameMatches(Type type) => Matches(type, TypeName); + + private static bool Matches(Type type, TypeName typeName) + { + // We don't need to check for pointers and references to arrays, + // as it's impossible to serialize them with BF. + if (type.IsPointer || type.IsByRef) + { + return false; + } + + // At first, check the non-allocating properties for mismatch. + if (type.IsArray != typeName.IsArray || type.IsConstructedGenericType != typeName.IsConstructedGenericType + || type.IsNested != typeName.IsNested + || (type.IsArray && type.GetArrayRank() != typeName.GetArrayRank())) + { + return false; + } + + if (type.FullName == typeName.FullName) + { + return true; // The happy path with no type forwarding + } + else if (typeName.IsArray) + { + return Matches(type.GetElementType()!, typeName.GetElementType()); + } + else if (type.IsConstructedGenericType) + { + if (!Matches(type.GetGenericTypeDefinition(), typeName.GetGenericTypeDefinition())) + { + return false; + } + + ImmutableArray genericNames = typeName.GetGenericArguments(); + Type[] genericTypes = type.GetGenericArguments(); + + if (genericNames.Length != genericTypes.Length) + { + return false; + } + + for (int i = 0; i < genericTypes.Length; i++) + { + if (!Matches(genericTypes[i], genericNames[i])) + { + return false; + } + } + + return true; + } + + return false; + } + + /// + /// Gets the primitive, string or null record value. + /// For reference records, it returns the referenced record. + /// For other records, it returns the records themselves. + /// + internal virtual object? GetValue() => this; + + internal virtual void HandleNextRecord(SerializationRecord nextRecord, NextInfo info) + => Debug.Fail($"HandleNextRecord should not have been called for '{GetType().Name}'"); + + internal virtual void HandleNextValue(object value, NextInfo info) + => Debug.Fail($"HandleNextValue should not have been called for '{GetType().Name}'"); +} diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs new file mode 100644 index 0000000000000..5df884c2d6c56 --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Formats.Nrbf.Utils; +using System.IO; +using System.IO.Hashing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace System.Formats.Nrbf; + +/// +/// The ID of . +/// +public readonly struct SerializationRecordId : IEquatable +{ +#pragma warning disable CS0649 // the default value is used on purpose + internal static readonly SerializationRecordId NoId; +#pragma warning restore CS0649 + + internal readonly int _id; + + private SerializationRecordId(int id) => _id = id; + + internal static SerializationRecordId Decode(BinaryReader reader) + { + int id = reader.ReadInt32(); + + if (id == 0) + { + ThrowHelper.ThrowInvalidValue(id); + } + + return new SerializationRecordId(id); + } + + /// + public bool Equals(SerializationRecordId other) => _id == other._id; + + /// + public override bool Equals(object? obj) => obj is SerializationRecordId other && Equals(other); + + /// + public override int GetHashCode() + { + int id = _id; +#if NET + Span integers = new(ref id); +#else + Span integers = stackalloc int[1] { id }; +#endif + return (int)XxHash32.HashToUInt32(MemoryMarshal.AsBytes(integers)); + } +} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RecordType.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordType.cs similarity index 64% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RecordType.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordType.cs index 4872998af31f2..69b2c437c67fb 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/RecordType.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordType.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Record type. @@ -9,81 +9,93 @@ namespace System.Runtime.Serialization.BinaryFormat; /// /// /// The enumeration does not contain all values supported by the -/// [MS-NRBF] 2.1.2.1, but only those supported by the . +/// [MS-NRBF] 2.1.2.1, but only those supported by the . /// /// -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -enum RecordType : byte +public enum SerializationRecordType { /// /// The NRBF header (the first record in NRBF payload). /// - SerializedStreamHeader = 0, + SerializedStreamHeader, /// /// Class information that references another class record's metadata. /// - ClassWithId = 1, - - // SystemClassWithMembers and ClassWithMembers are not supported by design (require type loading) - + ClassWithId, + /// + /// A system class information without type info. + /// + /// Not supported by design. + SystemClassWithMembers, + /// + /// A class information with source library, but without type info. + /// + /// Not supported by design. + ClassWithMembers, /// /// A system class information with type info. /// - SystemClassWithMembersAndTypes = 4, + SystemClassWithMembersAndTypes, /// /// A class information with type info and the source library. /// - ClassWithMembersAndTypes = 5, + ClassWithMembersAndTypes, /// /// A . /// - BinaryObjectString = 6, + BinaryObjectString, /// /// An array of any rank or element type. /// - BinaryArray = 7, + BinaryArray, /// /// A primitive value other than . /// - MemberPrimitiveTyped = 8, + MemberPrimitiveTyped, /// /// A record that contains a reference to another record that contains the actual value. /// - MemberReference = 9, + MemberReference, /// /// A single value. /// - ObjectNull = 10, + ObjectNull, /// /// The record that marks the end of the binary format stream. /// - MessageEnd = 11, + MessageEnd, /// /// A record that associates a numeric identifier with a named library. /// - BinaryLibrary = 12, + BinaryLibrary, /// /// Multiple (less than 256) values. /// - ObjectNullMultiple256 = 13, + ObjectNullMultiple256, /// /// Multiple . /// - ObjectNullMultiple = 14, + ObjectNullMultiple, /// /// A single-dimensional array of a primitive type. /// - ArraySinglePrimitive = 15, + ArraySinglePrimitive, /// /// A single-dimensional array of values. /// - ArraySingleObject = 16, + ArraySingleObject, /// /// A single-dimensional array of values. /// - ArraySingleString = 17 + ArraySingleString, + /// + /// A remote method call. + /// + /// Not supported by design. + MethodCall = 21, + /// + /// An information returned by a remote method. + /// + /// Not supported by design. + MethodReturn } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SerializedStreamHeaderRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs similarity index 59% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SerializedStreamHeaderRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs index 0c3b401ec0196..4757958fcb777 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SerializedStreamHeaderRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs @@ -2,9 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Diagnostics; +using System.Formats.Nrbf.Utils; +using System.Reflection.Metadata; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Represents the NRBF header, it must be the first record in NRBF payload. @@ -14,21 +16,29 @@ namespace System.Runtime.Serialization.BinaryFormat; /// internal sealed class SerializedStreamHeaderRecord : SerializationRecord { - internal const int Size = sizeof(RecordType) + sizeof(int) * 4; + internal const int Size = sizeof(byte) + sizeof(int) * 4; internal const int MajorVersion = 1; internal const int MinorVersion = 0; - internal SerializedStreamHeaderRecord(int rootId) => RootId = rootId; + internal SerializedStreamHeaderRecord(SerializationRecordId rootId) => RootId = rootId; - public override RecordType RecordType => RecordType.SerializedStreamHeader; + public override SerializationRecordType RecordType => SerializationRecordType.SerializedStreamHeader; - internal int RootId { get; } + public override TypeName TypeName + { + get + { + Debug.Fail("TypeName should never be called on SerializedStreamHeaderRecord"); + return TypeName.Parse(nameof(SerializedStreamHeaderRecord).AsSpan()); + } + } + public override SerializationRecordId Id => SerializationRecordId.NoId; - public override int ObjectId => NoId; + internal SerializationRecordId RootId { get; } internal static SerializedStreamHeaderRecord Decode(BinaryReader reader) { - int rootId = reader.ReadInt32(); + SerializationRecordId rootId = SerializationRecordId.Decode(reader); _ = reader.ReadInt32(); // HeaderId int majorVersion = reader.ReadInt32(); int minorVersion = reader.ReadInt32(); diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SystemClassWithMembersAndTypesRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SystemClassWithMembersAndTypesRecord.cs similarity index 89% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SystemClassWithMembersAndTypesRecord.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SystemClassWithMembersAndTypesRecord.cs index 8feb6f946bd77..93095bc32b000 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SystemClassWithMembersAndTypesRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SystemClassWithMembersAndTypesRecord.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; -namespace System.Runtime.Serialization.BinaryFormat; +namespace System.Formats.Nrbf; /// /// Class information with type info. @@ -19,11 +19,7 @@ private SystemClassWithMembersAndTypesRecord(ClassInfo classInfo, MemberTypeInfo { } - public override RecordType RecordType => RecordType.SystemClassWithMembersAndTypes; - - public override bool IsTypeNameMatching(Type type) - => type.Assembly == typeof(object).Assembly - && type.GetTypeFullNameIncludingTypeForwards() == ClassInfo.TypeName.FullName; + public override SerializationRecordType RecordType => SerializationRecordType.SystemClassWithMembersAndTypes; internal static SystemClassWithMembersAndTypesRecord Decode(BinaryReader reader, RecordMap recordMap, PayloadOptions options) { @@ -82,14 +78,14 @@ internal SerializationRecord TryToMapToUserFriendly() else if (MemberValues.Count == 2 && HasMember("ticks") && HasMember("dateData") && MemberValues[0] is long value && MemberValues[1] is ulong - && IsTypeNameMatching(typeof(DateTime))) + && TypeNameMatches(typeof(DateTime))) { return Create(Utils.BinaryReaderExtensions.CreateDateTimeFromData(value)); } else if(MemberValues.Count == 4 && HasMember("lo") && HasMember("mid") && HasMember("hi") && HasMember("flags") && MemberValues[0] is int && MemberValues[1] is int && MemberValues[2] is int && MemberValues[3] is int - && IsTypeNameMatching(typeof(decimal))) + && TypeNameMatches(typeof(decimal))) { int[] bits = [ @@ -105,6 +101,6 @@ internal SerializationRecord TryToMapToUserFriendly() return this; SerializationRecord Create(T value) where T : unmanaged - => new MemberPrimitiveTypedRecord(value, ObjectId); + => new MemberPrimitiveTypedRecord(value, Id); } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/BinaryReaderExtensions.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs similarity index 91% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/BinaryReaderExtensions.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs index e6db17aa82488..73759a7a22dac 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/BinaryReaderExtensions.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs @@ -5,17 +5,24 @@ using System.IO; using System.Reflection.Metadata; using System.Runtime.CompilerServices; +using System.Runtime.Serialization; -namespace System.Runtime.Serialization.BinaryFormat.Utils; +namespace System.Formats.Nrbf.Utils; internal static class BinaryReaderExtensions { internal static BinaryArrayType ReadArrayType(this BinaryReader reader) { byte arrayType = reader.ReadByte(); - // RectangularOffset is the last defined value. - if (arrayType > (byte)BinaryArrayType.RectangularOffset) + // Rectangular is the last defined value. + if (arrayType > (byte)BinaryArrayType.Rectangular) { + // Custom offset arrays + if (arrayType >= 3 && arrayType <= 5) + { + throw new NotSupportedException(SR.NotSupported_NonZeroOffsets); + } + ThrowHelper.ThrowInvalidValue(arrayType); } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/ThrowHelper.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/ThrowHelper.cs similarity index 81% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/ThrowHelper.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/ThrowHelper.cs index 5bb3411d9aa93..de543f2e098cf 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/ThrowHelper.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/ThrowHelper.cs @@ -2,8 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; +using System.Runtime.Serialization; -namespace System.Runtime.Serialization.BinaryFormat.Utils; +namespace System.Formats.Nrbf.Utils; internal static class ThrowHelper { @@ -33,14 +34,14 @@ internal static void ThrowForUnexpectedRecordType(byte recordType) #pragma warning disable IDE0066 // Convert switch statement to expression switch (recordType) { - case 2: // SystemClassWithMembers (generated without FormatterTypeStyle.TypesAlways) - case 3: // ClassWithMembers (generated without FormatterTypeStyle.TypesAlways) + case (byte)SerializationRecordType.SystemClassWithMembers: // generated without FormatterTypeStyle.TypesAlways + case (byte)SerializationRecordType.ClassWithMembers: // generated without FormatterTypeStyle.TypesAlways // 18~20 are from the reference source but aren't in the OpenSpecs doc case 18: // CrossAppDomainMap case 19: // CrossAppDomainString case 20: // CrossAppDomainAssembly - case 21: // MethodCall - case 22: // MethodReturn + case (byte)SerializationRecordType.MethodCall: + case (byte)SerializationRecordType.MethodReturn: throw new NotSupportedException(SR.Format(SR.NotSupported_RecordType, recordType)); default: ThrowInvalidValue(recordType); diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/TypeNameExtensions.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameExtensions.cs similarity index 72% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/TypeNameExtensions.cs rename to src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameExtensions.cs index 0dd8353910070..017f4597bfc2d 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/TypeNameExtensions.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameExtensions.cs @@ -5,9 +5,10 @@ using System.Diagnostics; using System.Reflection.Metadata; using System.Runtime.CompilerServices; +using System.Runtime.Serialization; using System.Text; -namespace System.Runtime.Serialization.BinaryFormat.Utils; +namespace System.Formats.Nrbf.Utils; internal static class TypeNameExtensions { @@ -68,14 +69,43 @@ internal static TypeName WithAssemblyName(this TypeName typeName, string assembl return result; } - private static ArraySegment GetAssemblyQualifiedName(string typeName, string libraryName) + internal static TypeName BuildCoreLibArrayTypeName(this Type type, int arrayRank) { - int length = typeName.Length + 1 + libraryName.Length; + ArraySegment assemblyQualifiedName = GetAssemblyQualifiedName(type.FullName!, CoreLibAssemblyName, arrayRank); + TypeName result = TypeName.Parse(assemblyQualifiedName.AsSpan()); + ArrayPool.Shared.Return(assemblyQualifiedName.Array!); + + return result; + } + + internal static TypeName BuildArrayTypeName(this TypeName typeName, int arrayRank) + { + ArraySegment assemblyQualifiedName = GetAssemblyQualifiedName(typeName.FullName, typeName.AssemblyName!.FullName, arrayRank); + TypeName result = TypeName.Parse(assemblyQualifiedName.AsSpan()); + ArrayPool.Shared.Return(assemblyQualifiedName.Array!); + + return result; + } + + private static ArraySegment GetAssemblyQualifiedName(string typeName, string libraryName, int arrayRank = 0) + { + int arrayLength = arrayRank != 0 ? 2 + arrayRank - 1 : 0; + int length = typeName.Length + arrayLength + 1 + libraryName.Length; + char[] rented = ArrayPool.Shared.Rent(length); typeName.AsSpan().CopyTo(rented); - rented[typeName.Length] = ','; - libraryName.AsSpan().CopyTo(rented.AsSpan(typeName.Length + 1)); + if (arrayRank != 0) + { + rented[typeName.Length] = '['; + for (int i = 1; i < arrayRank; i++) + { + rented[typeName.Length + i] = ','; + } + rented[typeName.Length + arrayLength - 1] = ']'; + } + rented[typeName.Length + arrayLength] = ','; + libraryName.AsSpan().CopyTo(rented.AsSpan(typeName.Length + arrayLength + 1)); return new ArraySegment(rented, 0, length); } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ArraySinglePrimitiveRecordTests.cs b/src/libraries/System.Formats.Nrbf/tests/ArraySinglePrimitiveRecordTests.cs similarity index 97% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ArraySinglePrimitiveRecordTests.cs rename to src/libraries/System.Formats.Nrbf/tests/ArraySinglePrimitiveRecordTests.cs index 01701e5401805..d4a4b5b3c690a 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ArraySinglePrimitiveRecordTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/ArraySinglePrimitiveRecordTests.cs @@ -5,7 +5,7 @@ using System.IO; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class ArraySinglePrimitiveRecordTests : ReadTests { @@ -91,7 +91,7 @@ private void Test(int size, bool canSeek) MemoryStream stream = Serialize(input); stream = canSeek ? stream : new NonSeekableStream(stream.ToArray()); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + SZArrayRecord arrayRecord = (SZArrayRecord)NrbfDecoder.Decode(stream); Assert.Equal(size, arrayRecord.Length); T?[] output = arrayRecord.GetArray(); diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/AttackTests.cs b/src/libraries/System.Formats.Nrbf/tests/AttackTests.cs similarity index 77% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/AttackTests.cs rename to src/libraries/System.Formats.Nrbf/tests/AttackTests.cs index 195e878aad07b..e73c8290289ca 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/AttackTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/AttackTests.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Reflection.Emit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class AttackTests : ReadTests { @@ -25,7 +25,7 @@ public void CyclicReferencesInClassesDoNotCauseStackOverflow() using MemoryStream stream = Serialize(input); - ClassRecord classRecord = PayloadReader.ReadClassRecord(stream); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(stream); Assert.Same(classRecord, classRecord.GetClassRecord(nameof(WithCyclicReference.ReferenceToSelf))); Assert.Equal(input.Name, classRecord.GetString(nameof(WithCyclicReference.Name))); @@ -43,7 +43,7 @@ public void CyclicReferencesInSystemClassesDoNotCauseStackOverflow() using MemoryStream stream = Serialize(input); - ClassRecord classRecord = PayloadReader.ReadClassRecord(stream); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(stream); Assert.Same(classRecord, classRecord.GetClassRecord(nameof(Exception.InnerException))); Assert.Equal(input.Message, classRecord.GetString(nameof(Exception.Message))); @@ -56,8 +56,8 @@ public void CyclicReferencesInArraysOfObjectsDoNotCauseStackOverflow() input[0] = "not an array"; input[1] = input; - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); - object?[] output = ((ArrayRecord)arrayRecord).GetArray(); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); + object?[] output = ((SZArrayRecord)arrayRecord).GetArray(); Assert.Equal(input[0], output[0]); Assert.Same(input, input[1]); @@ -78,10 +78,10 @@ public void CyclicClassReferencesInArraysOfObjectsDoNotCauseStackOverflow() input.Name = "hello"; input.ArrayWithReferenceToSelf = [input]; - ClassRecord classRecord = PayloadReader.ReadClassRecord(Serialize(input)); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(Serialize(input)); Assert.Equal(input.Name, classRecord.GetString(nameof(WithCyclicReferenceInArrayOfObjects.Name))); - ArrayRecord arrayRecord = (ArrayRecord)classRecord.GetSerializationRecord(nameof(WithCyclicReferenceInArrayOfObjects.ArrayWithReferenceToSelf))!; + SZArrayRecord arrayRecord = (SZArrayRecord)classRecord.GetSerializationRecord(nameof(WithCyclicReferenceInArrayOfObjects.ArrayWithReferenceToSelf))!; object?[] array = arrayRecord.GetArray(); Assert.Same(classRecord, array.Single()); } @@ -100,10 +100,10 @@ public void CyclicClassReferencesInArraysOfTDoNotCauseStackOverflow() input.Name = "hello"; input.ArrayWithReferenceToSelf = [input]; - ClassRecord classRecord = PayloadReader.ReadClassRecord(Serialize(input)); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(Serialize(input)); Assert.Equal(input.Name, classRecord.GetString(nameof(WithCyclicReferenceInArrayOfT.Name))); - ArrayRecord classRecords = (ArrayRecord)classRecord.GetSerializationRecord(nameof(WithCyclicReferenceInArrayOfT.ArrayWithReferenceToSelf))!; + SZArrayRecord classRecords = (SZArrayRecord)classRecord.GetSerializationRecord(nameof(WithCyclicReferenceInArrayOfT.ArrayWithReferenceToSelf))!; Assert.Same(classRecord, classRecords.GetArray().Single()); } @@ -112,7 +112,8 @@ public void CyclicClassReferencesInArraysOfTDoNotCauseStackOverflow() // AppDomain.CurrentDomain.MonitoringTotalAllocatedMemorySize is available, // but it reports allocations for all threads. Using this API would require // ensuring that it's the only test that is being run at a time. - [Fact] + // Mono either allocates more than expected or the API is not precise enough + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime))] public void ArraysOfStringsAreNotBeingPreAllocated() { using MemoryStream stream = new(); @@ -120,23 +121,23 @@ public void ArraysOfStringsAreNotBeingPreAllocated() WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.ArraySingleString); + writer.Write((byte)SerializationRecordType.ArraySingleString); writer.Write(1); // object ID writer.Write(Array.MaxLength); // length - writer.Write((byte)RecordType.ObjectNullMultiple); + writer.Write((byte)SerializationRecordType.ObjectNullMultiple); writer.Write(Array.MaxLength); // null count - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; long before = GetAllocatedByteCount(); - SerializationRecord serializationRecord = PayloadReader.Read(stream); + SerializationRecord serializationRecord = NrbfDecoder.Decode(stream); long after = GetAllocatedByteCount(); - Assert.InRange(after, before, before + 1024); - Assert.Equal(RecordType.ArraySingleString, serializationRecord.RecordType); + Assert.InRange(after, before, before + 5000); + Assert.Equal(SerializationRecordType.ArraySingleString, serializationRecord.RecordType); } [Fact] @@ -147,17 +148,17 @@ public void ArraysOfBytesAreNotBeingPreAllocated() WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.ArraySinglePrimitive); + writer.Write((byte)SerializationRecordType.ArraySinglePrimitive); writer.Write(1); // object ID writer.Write(Array.MaxLength); // length writer.Write((byte)2); // PrimitiveType.Byte - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; long before = GetAllocatedByteCount(); - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); long after = GetAllocatedByteCount(); @@ -192,7 +193,7 @@ public void UnboundedRecursion_NestedTypes_ActualBinaryFormatterInput() using MemoryStream stream = Serialize(previous); - SerializationRecord serializationRecord = PayloadReader.Read(stream); + SerializationRecord serializationRecord = NrbfDecoder.Decode(stream); static Exception CreateNewExceptionTypeAndInstantiateIt(Type[] ctorTypes, ConstructorInfo baseCtor, ModuleBuilder module, Exception previous, int i) @@ -221,9 +222,9 @@ static Exception CreateNewExceptionTypeAndInstantiateIt(Type[] ctorTypes, Constr } [Theory] - [InlineData(RecordType.ClassWithMembersAndTypes)] - [InlineData(RecordType.SystemClassWithMembersAndTypes)] - public void UnboundedRecursion_NestedClasses_FakeButValidInput(RecordType recordType) + [InlineData(SerializationRecordType.ClassWithMembersAndTypes)] + [InlineData(SerializationRecordType.SystemClassWithMembersAndTypes)] + public void UnboundedRecursion_NestedClasses_FakeButValidInput(SerializationRecordType recordType) { const int ClassesCount = 10_000; const int LibraryId = ClassesCount + 1; @@ -247,33 +248,33 @@ public void UnboundedRecursion_NestedClasses_FakeButValidInput(RecordType record { writer.Write("memberName"); // MemberTypeInfo (if needed) - if (recordType is RecordType.ClassWithMembersAndTypes or RecordType.SystemClassWithMembersAndTypes) + if (recordType is SerializationRecordType.ClassWithMembersAndTypes or SerializationRecordType.SystemClassWithMembersAndTypes) { - byte memberType = recordType is RecordType.SystemClassWithMembersAndTypes + byte memberType = recordType is SerializationRecordType.SystemClassWithMembersAndTypes ? (byte)3 // BinaryType.SystemClass : (byte)4; // BinaryType.Class; writer.Write(memberType); writer.Write($"Class{i}"); // member type name - if (recordType is RecordType.ClassWithMembersAndTypes) + if (recordType is SerializationRecordType.ClassWithMembersAndTypes) { writer.Write(LibraryId); } } } // LibraryId (if needed) - if (recordType is RecordType.ClassWithMembersAndTypes) + if (recordType is SerializationRecordType.ClassWithMembersAndTypes) { writer.Write(LibraryId); } } - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - SerializationRecord serializationRecord = PayloadReader.Read(stream); + SerializationRecord serializationRecord = NrbfDecoder.Decode(stream); } [Fact] diff --git a/src/libraries/System.Formats.Nrbf/tests/CustomOffsetArrays.cs b/src/libraries/System.Formats.Nrbf/tests/CustomOffsetArrays.cs new file mode 100644 index 0000000000000..aaa60b2f260dc --- /dev/null +++ b/src/libraries/System.Formats.Nrbf/tests/CustomOffsetArrays.cs @@ -0,0 +1,82 @@ +using System.IO; +using Xunit; + +namespace System.Formats.Nrbf.Tests; + +public class CustomOffsetArrays : ReadTests +{ + [Fact] + public void SingleDimensionalArrayOfIntegersWithCustomOffset_ThrowsNSE() + { + const int lowerBound = 1; + Array input = Array.CreateInstance(typeof(int), lengths: [3], lowerBounds: [lowerBound]); + for (int i = lowerBound; i < lowerBound + input.Length; i++) + { + input.SetValue(value: i, index: i); + } + + using MemoryStream stream = Serialize(input); + + Assert.Throws(() => NrbfDecoder.Decode(stream)); + } + + [Fact] + public void RectangularArrayOfStringsWithCustomOffsets_ThrowsNSE() + { + const int lowerBound = 10; + Array input = Array.CreateInstance(typeof(string), lengths: [7, 5], lowerBounds: [lowerBound, lowerBound]); + for (int i = lowerBound; i < lowerBound + input.GetLength(0); i++) + { + for (int j = lowerBound; j < lowerBound + input.GetLength(1); j++) + { + input.SetValue(value: $"{i}. {j}", index1: i, index2: j); + } + } + + using MemoryStream stream = Serialize(input); + + Assert.Throws(() => NrbfDecoder.Decode(stream)); + } + + [Serializable] + public class ComplexType3D + { + public int I, J, K; + } + + [Fact] + public void RectangularArraysOfComplexTypes_ThrowsNSE() + { + const int lowerBoundI = 1, lowerBoundJ = 2, lowerBoundK = 2; + Array input = Array.CreateInstance(typeof(ComplexType3D), + lengths: [17, 5, 3], lowerBounds: [lowerBoundI, lowerBoundJ, lowerBoundK]); + + for (int i = 0; i < input.GetLength(0); i++) + { + for (int j = 0; j < input.GetLength(1); j++) + { + for (int k = 0; k < input.GetLength(2); k++) + { + input.SetValue( + new ComplexType3D() { I = i, J = j, K = k }, + i + lowerBoundI, j + lowerBoundJ, k + lowerBoundK); + } + } + } + + using MemoryStream stream = Serialize(input); + + Assert.Throws(() => NrbfDecoder.Decode(stream)); + } + + [Fact] + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "BinaryFormatter fails to serialize the input.")] + public void JaggedCustomOffset_ThrowsNSE() + { + Array input = Array.CreateInstance(typeof(uint[]), [5], [1]); + + using MemoryStream stream = Serialize(input); + + Assert.Throws(() => NrbfDecoder.Decode(stream)); + } +} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/EdgeCaseTests.cs b/src/libraries/System.Formats.Nrbf/tests/EdgeCaseTests.cs similarity index 88% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/EdgeCaseTests.cs rename to src/libraries/System.Formats.Nrbf/tests/EdgeCaseTests.cs index a26d097ec2f72..b443eba5ed4c9 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/EdgeCaseTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/EdgeCaseTests.cs @@ -4,7 +4,7 @@ using Microsoft.DotNet.XUnitExtensions; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class EdgeCaseTests : ReadTests { @@ -21,10 +21,10 @@ public void SurrogatesGetNoSpecialHandling() using MemoryStream stream = Serialize(typeof(object)); #endif - ClassRecord classRecord = (ClassRecord)PayloadReader.Read(stream); + ClassRecord classRecord = (ClassRecord)NrbfDecoder.Decode(stream); // It's a surrogate, so there is no type match. - Assert.False(classRecord.IsTypeNameMatching(typeof(Type))); + Assert.False(classRecord.TypeNameMatches(typeof(Type))); Assert.Equal("System.UnitySerializationHolder", classRecord.TypeName.FullName); Assert.Equal("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", classRecord.GetString("AssemblyName")); } @@ -46,7 +46,7 @@ public void ArraysOfStringsCanContainMemberReferences(FormatterTypeStyle typeFor binaryFormatter.Serialize(stream, input); stream.Position = 0; - string?[] ouput = ((ArrayRecord)PayloadReader.Read(stream)).GetArray(); + string?[] ouput = ((SZArrayRecord)NrbfDecoder.Decode(stream)).GetArray(); Assert.Equal(input, ouput); @@ -77,7 +77,7 @@ public void CanReadArrayOfAnySize(int length) // MemoryStream can not handle large array payloads as it's backed by an array. using FileStream stream = SerializeToFile(input); - byte[] output = ((ArrayRecord)PayloadReader.Read(stream)).GetArray(); + byte[] output = ((SZArrayRecord)NrbfDecoder.Decode(stream)).GetArray(); Assert.Equal(input, output); } catch (OutOfMemoryException) when (length == 2147483591) @@ -101,6 +101,6 @@ public void FormatterTypeStyleOtherThanTypesAlwaysAreNotSupportedByDesign(Format binaryFormatter.Serialize(ms, true); ms.Position = 0; - Assert.Throws(() => PayloadReader.Read(ms)); + Assert.Throws(() => NrbfDecoder.Decode(ms)); } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/InvalidInputTests.cs b/src/libraries/System.Formats.Nrbf/tests/InvalidInputTests.cs similarity index 61% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/InvalidInputTests.cs rename to src/libraries/System.Formats.Nrbf/tests/InvalidInputTests.cs index 7ab3ae64558f9..bc134350eb7c9 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/InvalidInputTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/InvalidInputTests.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; using System.IO; +using System.Runtime.Serialization; using System.Text; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class InvalidInputTests : ReadTests { @@ -17,7 +18,7 @@ public void ThrowsOnInvalidUtf8Input() byte[] invalidUtf8 = [(byte)'a', (byte)'b', 0xC0, (byte)'x', (byte)'y']; - writer.Write((byte)RecordType.BinaryObjectString); + writer.Write((byte)SerializationRecordType.BinaryObjectString); writer.Write((int)1); // object ID #if NETFRAMEWORK typeof(BinaryWriter).GetMethod("Write7BitEncodedInt", @@ -26,10 +27,10 @@ public void ThrowsOnInvalidUtf8Input() writer.Write7BitEncodedInt(invalidUtf8.Length); #endif writer.Write(invalidUtf8); - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Theory] @@ -43,15 +44,15 @@ public void ThrowsOnInvalidHeaderVersion(int major, int minor) WriteSerializedStreamHeader(writer, major, minor); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Theory] - [InlineData(10, RecordType.ArraySingleString)] // ObjectNullMultiple256 - [InlineData(byte.MaxValue + 1, RecordType.ArraySingleString)] // ObjectNullMultiple - [InlineData(10, RecordType.ArraySingleObject)] - [InlineData(byte.MaxValue + 1, RecordType.ArraySingleObject)] - public void ThrowsWhenNumberOfNullsIsLargerThanArraySize(int nullCount, RecordType recordType) + [InlineData(10, SerializationRecordType.ArraySingleString)] // ObjectNullMultiple256 + [InlineData(byte.MaxValue + 1, SerializationRecordType.ArraySingleString)] // ObjectNullMultiple + [InlineData(10, SerializationRecordType.ArraySingleObject)] + [InlineData(byte.MaxValue + 1, SerializationRecordType.ArraySingleObject)] + public void ThrowsWhenNumberOfNullsIsLargerThanArraySize(int nullCount, SerializationRecordType recordType) { using MemoryStream stream = new(); BinaryWriter writer = new(stream, Encoding.UTF8); @@ -61,31 +62,31 @@ public void ThrowsWhenNumberOfNullsIsLargerThanArraySize(int nullCount, RecordTy writer.Write((byte)recordType); writer.Write(1); // object ID writer.Write(nullCount - 1); // length - writer.Write((byte)RecordType.ObjectNullMultiple); + writer.Write((byte)SerializationRecordType.ObjectNullMultiple); writer.Write(nullCount); // null count - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Theory] - [InlineData(0, RecordType.ObjectNullMultiple256)] - [InlineData(0, RecordType.ObjectNullMultiple)] - [InlineData(-1, RecordType.ObjectNullMultiple)] - public void ThrowsWhenNumberOfNullsIsInvalid(int nullCount, RecordType recordType) + [InlineData(0, SerializationRecordType.ObjectNullMultiple256)] + [InlineData(0, SerializationRecordType.ObjectNullMultiple)] + [InlineData(-1, SerializationRecordType.ObjectNullMultiple)] + public void ThrowsWhenNumberOfNullsIsInvalid(int nullCount, SerializationRecordType recordType) { using MemoryStream stream = new(); BinaryWriter writer = new(stream, Encoding.UTF8); WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.ArraySingleString); + writer.Write((byte)SerializationRecordType.ArraySingleString); writer.Write(1); // object ID writer.Write(1); // length writer.Write((byte)recordType); - if (recordType == RecordType.ObjectNullMultiple256) + if (recordType == SerializationRecordType.ObjectNullMultiple256) { writer.Write((byte)nullCount); // null count } @@ -94,10 +95,10 @@ public void ThrowsWhenNumberOfNullsIsInvalid(int nullCount, RecordType recordTyp writer.Write(nullCount); // null count } - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Fact] @@ -111,15 +112,15 @@ public void ThrowWhenArrayOfStringsContainsReferenceToNonString() const int LibraryId = 2; WriteBinaryLibrary(writer, LibraryId, "LibraryName.dll"); - writer.Write((byte)RecordType.ArraySingleString); + writer.Write((byte)SerializationRecordType.ArraySingleString); writer.Write(1); // array Id writer.Write(1); // array length - writer.Write((byte)RecordType.MemberReference); + writer.Write((byte)SerializationRecordType.MemberReference); writer.Write(LibraryId); // reference to the library - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => ((ArrayRecord)PayloadReader.Read(stream)).GetArray()); + Assert.Throws(() => ((SZArrayRecord)NrbfDecoder.Decode(stream)).GetArray()); } [Theory] @@ -134,15 +135,15 @@ public void ThrowsWhenTypeNameIsInvalid(string typeName, bool mangling) WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.SystemClassWithMembersAndTypes); + writer.Write((byte)SerializationRecordType.SystemClassWithMembersAndTypes); writer.Write(1); // class Id writer.Write(typeName); writer.Write(0); // member count - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; PayloadOptions options = new() { UndoTruncatedTypeNames = mangling }; - Assert.Throws(() => PayloadReader.Read(stream, options)); + Assert.Throws(() => NrbfDecoder.Decode(stream, options)); } [Theory] @@ -157,7 +158,7 @@ public void ThrowsWhenMemberTypeNameIsInvalid_BinaryTypeSystemClass(string typeN WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.SystemClassWithMembersAndTypes); + writer.Write((byte)SerializationRecordType.SystemClassWithMembersAndTypes); writer.Write(1); // class Id writer.Write("ValidTypeName"); writer.Write(1); // member count @@ -165,11 +166,11 @@ public void ThrowsWhenMemberTypeNameIsInvalid_BinaryTypeSystemClass(string typeN // The Member writer.Write(3); // BinaryType.SystemClass writer.Write(typeName); - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; PayloadOptions options = new() { UndoTruncatedTypeNames = mangling }; - Assert.Throws(() => PayloadReader.Read(stream, options)); + Assert.Throws(() => NrbfDecoder.Decode(stream, options)); } [Theory] @@ -184,7 +185,7 @@ public void ThrowsWhenMemberTypeNameIsInvalid_BinaryTypeClass(string typeName, b WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.SystemClassWithMembersAndTypes); + writer.Write((byte)SerializationRecordType.SystemClassWithMembersAndTypes); writer.Write(1); // class Id writer.Write("ValidTypeName"); writer.Write(1); // member count @@ -193,11 +194,11 @@ public void ThrowsWhenMemberTypeNameIsInvalid_BinaryTypeClass(string typeName, b writer.Write(4); // BinaryType.Class (the difference!) writer.Write(typeName); // type name writer.Write(10); // class id - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; PayloadOptions options = new() { UndoTruncatedTypeNames = mangling }; - Assert.Throws(() => PayloadReader.Read(stream, options)); + Assert.Throws(() => NrbfDecoder.Decode(stream, options)); } [Theory] @@ -210,21 +211,21 @@ public void ThrowsWhenLibraryNameIsInvalid(bool mangling) WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.BinaryLibrary); + writer.Write((byte)SerializationRecordType.BinaryLibrary); writer.Write(2); // library Id writer.Write("Esc\\[aped"); // library name - writer.Write((byte)RecordType.ClassWithMembersAndTypes); + writer.Write((byte)SerializationRecordType.ClassWithMembersAndTypes); writer.Write(1); // class Id writer.Write("ValidTypeName"); writer.Write(0); // member count writer.Write(2); // library Id - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; PayloadOptions options = new() { UndoTruncatedTypeNames = mangling }; - Assert.Throws(() => PayloadReader.Read(stream, options)); + Assert.Throws(() => NrbfDecoder.Decode(stream, options)); } [Theory] @@ -240,37 +241,37 @@ public void UndoTruncatedTypeNamesIsRespected(bool mangling) WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.BinaryLibrary); + writer.Write((byte)SerializationRecordType.BinaryLibrary); writer.Write(2); // library Id writer.Write(LibraryName); - writer.Write((byte)RecordType.ClassWithMembersAndTypes); + writer.Write((byte)SerializationRecordType.ClassWithMembersAndTypes); writer.Write(1); // class Id writer.Write(TypeName); writer.Write(0); // member count writer.Write(2); // library Id - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; PayloadOptions options = new() { UndoTruncatedTypeNames = mangling }; if (mangling) { - ClassRecord classRecord = (ClassRecord)PayloadReader.Read(stream, options); + ClassRecord classRecord = (ClassRecord)NrbfDecoder.Decode(stream, options); Assert.Equal($"{TypeName}, {LibraryName}", classRecord.TypeName.FullName); } else { - Assert.Throws(() => PayloadReader.Read(stream, options)); + Assert.Throws(() => NrbfDecoder.Decode(stream, options)); } } [Theory] - [InlineData(RecordType.ArraySingleObject)] - [InlineData(RecordType.ArraySinglePrimitive)] - [InlineData(RecordType.ArraySingleString)] - public void ThrowsForNegativeSingleArrayLength(RecordType recordType) + [InlineData(SerializationRecordType.ArraySingleObject)] + [InlineData(SerializationRecordType.ArraySinglePrimitive)] + [InlineData(SerializationRecordType.ArraySingleString)] + public void ThrowsForNegativeSingleArrayLength(SerializationRecordType recordType) { using MemoryStream stream = new(); BinaryWriter writer = new(stream, Encoding.UTF8); @@ -280,84 +281,84 @@ public void ThrowsForNegativeSingleArrayLength(RecordType recordType) writer.Write((byte)recordType); writer.Write(1); // object Id writer.Write(-1); // length! - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Theory] - [InlineData(BinaryArrayType.Single)] - [InlineData(BinaryArrayType.Jagged)] - [InlineData(BinaryArrayType.Rectangular)] - public void ThrowsForNegativeArrayLength(BinaryArrayType arrayType) + [InlineData((byte)BinaryArrayType.Single)] + [InlineData((byte)BinaryArrayType.Jagged)] + [InlineData((byte)BinaryArrayType.Rectangular)] + public void ThrowsForNegativeArrayLength(byte arrayType) { using MemoryStream stream = new(); BinaryWriter writer = new(stream, Encoding.UTF8); WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.BinaryArray); + writer.Write((byte)SerializationRecordType.BinaryArray); writer.Write(1); // object Id - writer.Write((byte)arrayType); + writer.Write(arrayType); writer.Write(1); // rank writer.Write(-1); // length! - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Theory] - [InlineData(-1, BinaryArrayType.Single)] - [InlineData(0, BinaryArrayType.Single)] - [InlineData(-1, BinaryArrayType.Jagged)] - [InlineData(0, BinaryArrayType.Jagged)] - [InlineData(-1, BinaryArrayType.Rectangular)] - [InlineData(0, BinaryArrayType.Rectangular)] - public void ThrowsForInvalidArrayRank(int rank, BinaryArrayType arrayType) + [InlineData(-1, (byte)BinaryArrayType.Single)] + [InlineData(0, (byte)BinaryArrayType.Single)] + [InlineData(-1, (byte)BinaryArrayType.Jagged)] + [InlineData(0, (byte)BinaryArrayType.Jagged)] + [InlineData(-1, (byte)BinaryArrayType.Rectangular)] + [InlineData(0, (byte)BinaryArrayType.Rectangular)] + public void ThrowsForInvalidArrayRank(int rank, byte arrayType) { using MemoryStream stream = new(); BinaryWriter writer = new(stream, Encoding.UTF8); WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.BinaryArray); + writer.Write((byte)SerializationRecordType.BinaryArray); writer.Write(1); // object Id - writer.Write((byte)arrayType); + writer.Write(arrayType); writer.Write(rank); // rank! writer.Write(1); // length - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Theory] - [InlineData(2, BinaryArrayType.Single)] - [InlineData(2, BinaryArrayType.Jagged)] - public void ThrowsForInvalidPositiveArrayRank(int rank, BinaryArrayType arrayType) + [InlineData(2, (byte)BinaryArrayType.Single)] + [InlineData(2, (byte)BinaryArrayType.Jagged)] + public void ThrowsForInvalidPositiveArrayRank(int rank, byte arrayType) { using MemoryStream stream = new(); BinaryWriter writer = new(stream, Encoding.UTF8); WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.BinaryArray); + writer.Write((byte)SerializationRecordType.BinaryArray); writer.Write(1); // object Id - writer.Write((byte)arrayType); + writer.Write(arrayType); writer.Write(rank); // rank! writer.Write(1); // length - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Theory] - [InlineData(RecordType.ClassWithMembersAndTypes)] - [InlineData(RecordType.SystemClassWithMembersAndTypes)] - public void ThrowsForInvalidBinaryType(RecordType recordType) + [InlineData(SerializationRecordType.ClassWithMembersAndTypes)] + [InlineData(SerializationRecordType.SystemClassWithMembersAndTypes)] + public void ThrowsForInvalidBinaryType(SerializationRecordType recordType) { const int LibraryId = 2; using MemoryStream stream = new(); @@ -374,27 +375,27 @@ public void ThrowsForInvalidBinaryType(RecordType recordType) writer.Write("MemberName"); writer.Write((byte)8); - if (recordType is RecordType.ClassWithMembersAndTypes) + if (recordType is SerializationRecordType.ClassWithMembersAndTypes) { writer.Write(LibraryId); } - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Theory] - [InlineData(RecordType.ClassWithMembersAndTypes)] - [InlineData(RecordType.SystemClassWithMembersAndTypes)] - public void ThrowsForDuplicateMemberNames(RecordType recordType) + [InlineData(SerializationRecordType.ClassWithMembersAndTypes)] + [InlineData(SerializationRecordType.SystemClassWithMembersAndTypes)] + public void ThrowsForDuplicateMemberNames(SerializationRecordType recordType) { const int LibraryId = 2; using MemoryStream stream = new(); BinaryWriter writer = new(stream, Encoding.UTF8); WriteSerializedStreamHeader(writer); - if (recordType is RecordType.ClassWithMembersAndTypes) + if (recordType is SerializationRecordType.ClassWithMembersAndTypes) { WriteBinaryLibrary(writer, LibraryId, "LibraryName"); } @@ -409,19 +410,19 @@ public void ThrowsForDuplicateMemberNames(RecordType recordType) writer.Write(1); // BinaryType.String writer.Write(1); // BinaryType.String - if (recordType is RecordType.ClassWithMembersAndTypes) + if (recordType is SerializationRecordType.ClassWithMembersAndTypes) { writer.Write(LibraryId); } - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } public static IEnumerable ThrowsForInvalidPrimitiveType_Arguments() { - foreach (RecordType recordType in new[] { RecordType.ClassWithMembersAndTypes, RecordType.SystemClassWithMembersAndTypes }) + foreach (SerializationRecordType recordType in new[] { SerializationRecordType.ClassWithMembersAndTypes, SerializationRecordType.SystemClassWithMembersAndTypes }) { foreach (byte binaryType in new byte[] { (byte)0 /* BinaryType.Primitive */, (byte)7 /* BinaryType.PrimitiveArray */ }) { @@ -433,7 +434,7 @@ public static IEnumerable ThrowsForInvalidPrimitiveType_Arguments() [Theory] [MemberData(nameof(ThrowsForInvalidPrimitiveType_Arguments))] - public void ThrowsForInvalidPrimitiveType(RecordType recordType, byte binaryType, byte invalidPrimitiveType) + public void ThrowsForInvalidPrimitiveType(SerializationRecordType recordType, byte binaryType, byte invalidPrimitiveType) { const int LibraryId = 2; using MemoryStream stream = new(); @@ -451,14 +452,14 @@ public void ThrowsForInvalidPrimitiveType(RecordType recordType, byte binaryType writer.Write(binaryType); writer.Write(invalidPrimitiveType); - if (recordType is RecordType.ClassWithMembersAndTypes) + if (recordType is SerializationRecordType.ClassWithMembersAndTypes) { writer.Write(LibraryId); } - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } [Fact] @@ -468,13 +469,13 @@ public void ThrowsOnInvalidArrayType() BinaryWriter writer = new(stream, Encoding.UTF8); WriteSerializedStreamHeader(writer); - writer.Write((byte)RecordType.BinaryArray); + writer.Write((byte)SerializationRecordType.BinaryArray); writer.Write(1); // object id writer.Write((byte)6); - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); stream.Position = 0; - Assert.Throws(() => PayloadReader.Read(stream)); + Assert.Throws(() => NrbfDecoder.Decode(stream)); } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/JaggedArraysTests.cs b/src/libraries/System.Formats.Nrbf/tests/JaggedArraysTests.cs similarity index 70% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/JaggedArraysTests.cs rename to src/libraries/System.Formats.Nrbf/tests/JaggedArraysTests.cs index 331c57a5dfb91..a72c3227c1eec 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/JaggedArraysTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/JaggedArraysTests.cs @@ -1,7 +1,8 @@ -using System.Linq; +using System.Formats.Nrbf.Utils; +using System.Linq; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class JaggedArraysTests : ReadTests { @@ -14,10 +15,9 @@ public void CanReadJaggedArraysOfPrimitiveTypes_2D() input[i] = [i, i, i]; } - var arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); + var arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); - VerifyLength(input, arrayRecord); - Assert.Equal(BinaryArrayType.Jagged, arrayRecord.ArrayType); + Verify(input, arrayRecord); Assert.Equal(input, arrayRecord.GetArray(input.GetType())); } @@ -31,10 +31,9 @@ public void CanReadJaggedArraysOfPrimitiveTypes_3D() input[i][0] = [i, i, i]; } - var arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); + var arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); - VerifyLength(input, arrayRecord); - Assert.Equal(BinaryArrayType.Jagged, arrayRecord.ArrayType); + Verify(input, arrayRecord); Assert.Equal(input, arrayRecord.GetArray(input.GetType())); Assert.Equal(1, arrayRecord.Rank); } @@ -56,10 +55,9 @@ public void CanReadJaggedArrayOfRectangularArrays() } } - var arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); + var arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); - VerifyLength(input, arrayRecord); - Assert.Equal(BinaryArrayType.Jagged, arrayRecord.ArrayType); + Verify(input, arrayRecord); Assert.Equal(input, arrayRecord.GetArray(input.GetType())); Assert.Equal(1, arrayRecord.Rank); } @@ -73,10 +71,9 @@ public void CanReadJaggedArraysOfStrings() input[i] = ["a", "b", "c"]; } - var arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); + var arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); - VerifyLength(input, arrayRecord); - Assert.Equal(BinaryArrayType.Jagged, arrayRecord.ArrayType); + Verify(input, arrayRecord); Assert.Equal(input, arrayRecord.GetArray(input.GetType())); } @@ -89,10 +86,9 @@ public void CanReadJaggedArraysOfObjects() input[i] = ["a", 1, DateTime.MaxValue]; } - var arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); + var arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); - VerifyLength(input, arrayRecord); - Assert.Equal(BinaryArrayType.Jagged, arrayRecord.ArrayType); + Verify(input, arrayRecord); Assert.Equal(input, arrayRecord.GetArray(input.GetType())); } @@ -111,10 +107,9 @@ public void CanReadJaggedArraysOfComplexTypes() input[i] = Enumerable.Range(0, i + 1).Select(j => new ComplexType { SomeField = j }).ToArray(); } - var arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); + var arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); - VerifyLength(input, arrayRecord); - Assert.Equal(BinaryArrayType.Jagged, arrayRecord.ArrayType); + Verify(input, arrayRecord); var output = (ClassRecord?[][])arrayRecord.GetArray(input.GetType()); for (int i = 0; i < input.Length; i++) { @@ -125,9 +120,12 @@ public void CanReadJaggedArraysOfComplexTypes() } } - private static void VerifyLength(Array input, ArrayRecord arrayRecord) + private static void Verify(Array input, ArrayRecord arrayRecord) { Assert.Equal(1, arrayRecord.Lengths.Length); Assert.Equal(input.Length, arrayRecord.Lengths[0]); + Assert.True(arrayRecord.TypeName.GetElementType().IsArray); // true only for Jagged arrays + Assert.Equal(input.GetType().FullName, arrayRecord.TypeName.FullName); + Assert.Equal(input.GetType().GetAssemblyNameIncludingTypeForwards(), arrayRecord.TypeName.AssemblyName!.FullName); } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadAnythingTests.cs b/src/libraries/System.Formats.Nrbf/tests/ReadAnythingTests.cs similarity index 79% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadAnythingTests.cs rename to src/libraries/System.Formats.Nrbf/tests/ReadAnythingTests.cs index 4a5af61c4351a..fd84071fac8e0 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadAnythingTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/ReadAnythingTests.cs @@ -5,7 +5,7 @@ using System.Text.Json; using System.Reflection; -namespace System.Runtime.Serialization.BinaryFormat.Tests +namespace System.Formats.Nrbf.Tests { public class ReadAnythingTests : ReadTests { @@ -22,36 +22,36 @@ public void UserCanReadAnyValidInputAndCheckTypesUsingStronglyTypedTypeInstances using MemoryStream stream = Serialize(input); - SerializationRecord topLevel = PayloadReader.Read(stream); + SerializationRecord topLevel = NrbfDecoder.Decode(stream); Assert.IsAssignableFrom(topLevel); ClassRecord dictionaryRecord = (ClassRecord)topLevel; // this innocent line tests type forwards support ;) - Assert.True(dictionaryRecord.IsTypeNameMatching(typeof(Dictionary))); + Assert.True(dictionaryRecord.TypeNameMatches(typeof(Dictionary))); ClassRecord comparerRecord = dictionaryRecord.GetClassRecord(nameof(input.Comparer))!; - Assert.True(comparerRecord.IsTypeNameMatching(input.Comparer.GetType())); + Assert.True(comparerRecord.TypeNameMatches(input.Comparer.GetType())); - ArrayRecord arrayRecord = (ArrayRecord)dictionaryRecord.GetSerializationRecord("KeyValuePairs")!; + SZArrayRecord arrayRecord = (SZArrayRecord)dictionaryRecord.GetSerializationRecord("KeyValuePairs")!; ClassRecord[] keyValuePairs = arrayRecord.GetArray()!; - Assert.True(keyValuePairs[0].IsTypeNameMatching(typeof(KeyValuePair))); + Assert.True(keyValuePairs[0].TypeNameMatches(typeof(KeyValuePair))); ClassRecord exceptionPair = Find(keyValuePairs, "exception"); ClassRecord exceptionValue = exceptionPair.GetClassRecord("value")!; - Assert.True(exceptionValue.IsTypeNameMatching(typeof(Exception))); + Assert.True(exceptionValue.TypeNameMatches(typeof(Exception))); Assert.Equal("test", exceptionValue.GetString(nameof(Exception.Message))); ClassRecord structPair = Find(keyValuePairs, "struct"); ClassRecord structValue = structPair.GetClassRecord("value")!; - Assert.True(structValue.IsTypeNameMatching(typeof(ValueTuple))); + Assert.True(structValue.TypeNameMatches(typeof(ValueTuple))); Assert.True(structValue.GetBoolean("Item1")); Assert.Equal(123, structValue.GetInt32("Item2")); ClassRecord genericPair = Find(keyValuePairs, "generic"); ClassRecord genericValue = genericPair.GetClassRecord("value")!; - Assert.True(genericValue.IsTypeNameMatching(typeof(List))); + Assert.True(genericValue.TypeNameMatches(typeof(List))); Assert.Equal(4, genericValue.GetInt32("_size")); - Assert.Equal(new int[] { 1, 2, 3, 4 }, genericValue.GetArrayOfPrimitiveType("_items")); + Assert.Equal(new int[] { 1, 2, 3, 4 }, ((SZArrayRecord)genericValue.GetArrayRecord("_items")).GetArray()); static ClassRecord Find(ClassRecord[] keyValuePairs, string key) => keyValuePairs.Where(pair => pair.GetString("key") == key).Single(); @@ -119,7 +119,7 @@ public static IEnumerable GetAllInputTypes() [MemberData(nameof(GetAllInputTypes))] public void UserCanReadEveryPossibleSerializationRecord(object input) { - SerializationRecord root = PayloadReader.Read(Serialize(input)); + SerializationRecord root = NrbfDecoder.Decode(Serialize(input)); switch(root) { @@ -173,86 +173,86 @@ public void UserCanReadEveryPossibleSerializationRecord(object input) Assert.Equal(input, record.Value); break; // arrays of primitive types - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; - case ArrayRecord record: + case SZArrayRecord record: Assert.Equal(input, record.GetArray()); break; // class records - case ClassRecord record when record.IsTypeNameMatching(typeof(Exception)): + case ClassRecord record when record.TypeNameMatches(typeof(Exception)): Assert.Equal(((Exception)input).Message, record.GetString("Message")); break; - case ArrayRecord record when record.IsTypeNameMatching(typeof(Exception[])): + case SZArrayRecord record when record.TypeNameMatches(typeof(Exception[])): Assert.Equal(((Exception[])input)[0].Message, record.GetArray()[0]!.GetString("Message")); break; - case ClassRecord record when record.IsTypeNameMatching(typeof(JsonException)): + case ClassRecord record when record.TypeNameMatches(typeof(JsonException)): Assert.Equal(((JsonException)input).Message, record.GetString("Message")); break; - case ClassRecord record when record.IsTypeNameMatching(typeof(Dictionary)): + case ClassRecord record when record.TypeNameMatches(typeof(Dictionary)): VerifyDictionary(record); break; - case ClassRecord record when record.IsTypeNameMatching(typeof(Dictionary)): + case ClassRecord record when record.TypeNameMatches(typeof(Dictionary)): VerifyDictionary(record); break; - case ClassRecord record when record.IsTypeNameMatching(typeof(EmptyClass)): + case ClassRecord record when record.TypeNameMatches(typeof(EmptyClass)): Assert.Empty(record.MemberNames); break; - case ArrayRecord arrayRecord when arrayRecord.IsTypeNameMatching(typeof(int?[])): + case ArrayRecord arrayRecord when arrayRecord.TypeNameMatches(typeof(int?[])): Assert.Equal(input, arrayRecord.GetArray(typeof(int?[]))); break; - case ArrayRecord arrayRecord when arrayRecord.IsTypeNameMatching(typeof(EmptyClass[])): + case ArrayRecord arrayRecord when arrayRecord.TypeNameMatches(typeof(EmptyClass[])): Assert.Equal(0, arrayRecord.Lengths.ToArray().Single()); break; - case ArrayRecord arrayRecord when arrayRecord.IsTypeNameMatching(typeof(EmptyClass[,])): + case ArrayRecord arrayRecord when arrayRecord.TypeNameMatches(typeof(EmptyClass[,])): Assert.Equal(new int[2] { 0, 0 }, arrayRecord.Lengths.ToArray()); break; - case ArrayRecord arrayRecord when arrayRecord.IsTypeNameMatching(typeof(EmptyClass[][])): + case ArrayRecord arrayRecord when arrayRecord.TypeNameMatches(typeof(EmptyClass[][])): Assert.Equal(0, arrayRecord.Lengths.ToArray().Single()); break; - case ArrayRecord arrayRecord when arrayRecord.IsTypeNameMatching(typeof(EmptyClass[][,])): + case ArrayRecord arrayRecord when arrayRecord.TypeNameMatches(typeof(EmptyClass[][,])): Assert.Equal(0, arrayRecord.Lengths.ToArray().Single()); break; default: @@ -262,9 +262,9 @@ public void UserCanReadEveryPossibleSerializationRecord(object input) static void VerifyDictionary(ClassRecord record) { - ArrayRecord arrayRecord = (ArrayRecord)record.GetSerializationRecord("KeyValuePairs")!; + SZArrayRecord arrayRecord = (SZArrayRecord)record.GetSerializationRecord("KeyValuePairs")!; ClassRecord[] keyValuePairs = arrayRecord.GetArray()!; - Assert.True(keyValuePairs[0].IsTypeNameMatching(typeof(KeyValuePair))); + Assert.True(keyValuePairs[0].TypeNameMatches(typeof(KeyValuePair))); } } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadExactTypesTests.cs b/src/libraries/System.Formats.Nrbf/tests/ReadExactTypesTests.cs similarity index 82% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadExactTypesTests.cs rename to src/libraries/System.Formats.Nrbf/tests/ReadExactTypesTests.cs index 2519c5b915bce..ccf1dd402fc7b 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadExactTypesTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/ReadExactTypesTests.cs @@ -1,8 +1,9 @@ using System.IO; using System.Linq; +using System.Runtime.Serialization; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class ReadExactTypesTests : ReadTests { @@ -36,7 +37,7 @@ public void CanRead_CustomTypeWithPrimitiveFields() using MemoryStream stream = Serialize(input); - ClassRecord classRecord = PayloadReader.ReadClassRecord(stream); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(stream); Verify(input, classRecord); @@ -73,7 +74,7 @@ public void CanRead_CustomTypeWithStringFields(string? text) using MemoryStream stream = Serialize(input); - ClassRecord classRecord = PayloadReader.ReadClassRecord(stream); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(stream); Assert.True(classRecord.HasMember(nameof(CustomTypeWithStringField.Text))); Assert.Equal(input.Text, classRecord.GetString(nameof(CustomTypeWithStringField.Text))); @@ -106,7 +107,7 @@ public void CanRead_CustomTypeWithObjectFields() using MemoryStream stream = Serialize(input); - ClassRecord classRecord = PayloadReader.ReadClassRecord(stream); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(stream); Assert.Equal(input.SomeObject, classRecord.GetString(nameof(CustomTypeWithObjectField.SomeObject))); Assert.Same(classRecord.GetRawValue(nameof(CustomTypeWithObjectField.ActualObject)), @@ -144,7 +145,7 @@ public void CanRead_CustomTypeWithPrimitiveArrayFields() using MemoryStream stream = Serialize(input); - ClassRecord classRecord = PayloadReader.ReadClassRecord(stream); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(stream); Verify(input.Bytes, classRecord, nameof(CustomTypeWithPrimitiveArrayFields.Bytes)); Verify(input.SignedBytes, classRecord, nameof(CustomTypeWithPrimitiveArrayFields.SignedBytes)); @@ -157,7 +158,7 @@ public void CanRead_CustomTypeWithPrimitiveArrayFields() static void Verify(T[] expected, ClassRecord classRecord, string fieldName) where T : unmanaged { - var arrayRecord = (ArrayRecord)classRecord.GetSerializationRecord(fieldName)!; + var arrayRecord = (SZArrayRecord)classRecord.GetSerializationRecord(fieldName)!; Assert.Equal(expected, arrayRecord.GetArray()); } } @@ -179,9 +180,9 @@ public void CanRead_CustomTypeWithStringsArrayField(string value0, string value1 Texts = [value0, value1, value2] }; - ClassRecord classRecord = PayloadReader.ReadClassRecord(Serialize(input)); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(Serialize(input)); - Assert.Equal(input.Texts, classRecord.GetArrayOfPrimitiveType(nameof(CustomTypeWithStringArrayField.Texts))); + Assert.Equal(input.Texts, ((SZArrayRecord)classRecord.GetArrayRecord(nameof(CustomTypeWithStringArrayField.Texts))).GetArray()); } [Theory] @@ -194,9 +195,9 @@ public void CanRead_CustomTypeWithMultipleNullsInStringsArray(int nullCount) Texts = Enumerable.Repeat(null!, nullCount).ToArray() }; - ClassRecord classRecord = PayloadReader.ReadClassRecord(Serialize(input)); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(Serialize(input)); - Assert.Equal(input.Texts, classRecord.GetArrayOfPrimitiveType(nameof(CustomTypeWithStringArrayField.Texts))); + Assert.Equal(input.Texts, ((SZArrayRecord)classRecord.GetArrayRecord(nameof(CustomTypeWithStringArrayField.Texts))).GetArray()); } [Fact] @@ -206,7 +207,7 @@ public void CanRead_RawStringArrays() using MemoryStream stream = Serialize(input); - string?[] output = ((ArrayRecord)PayloadReader.Read(stream)).GetArray(); + string?[] output = ((SZArrayRecord)NrbfDecoder.Decode(stream)).GetArray(); Assert.Equal(input, output); } @@ -218,7 +219,7 @@ public void CanReadArraysOfPrimitiveTypes() using MemoryStream stream = Serialize(input); - ulong[] output = ((ArrayRecord)PayloadReader.Read(stream)).GetArray(); + ulong[] output = ((SZArrayRecord)NrbfDecoder.Decode(stream)).GetArray(); Assert.Equal(input, output); } @@ -228,7 +229,7 @@ public void CanRead_ComplexSystemType() { Exception input = new("Hello, World!"); - ClassRecord classRecord = PayloadReader.ReadClassRecord(Serialize(input)); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(Serialize(input)); Assert.True(classRecord.HasMember(nameof(Exception.Message))); Assert.Equal(input.Message, classRecord.GetString(nameof(Exception.Message))); @@ -243,7 +244,7 @@ public void CanRead_ComplexSystemType_ThatReferencesOtherClassRecord() ArgumentNullException inner = new(paramName: "innerPara"); Exception outer = new("outer", inner); - ClassRecord outerRecord = PayloadReader.ReadClassRecord(Serialize(outer)); + ClassRecord outerRecord = NrbfDecoder.DecodeClassRecord(Serialize(outer)); Assert.Equal(outer.Message, outerRecord.GetString(nameof(Exception.Message))); @@ -262,10 +263,10 @@ public void CanRead_ArraysOfComplexTypes() new () { Long = 5 }, ]; - ArrayRecord arrayRecord = ((ArrayRecord)PayloadReader.Read(Serialize(input))); + SZArrayRecord arrayRecord = ((SZArrayRecord)NrbfDecoder.Decode(Serialize(input))); - Assert.Equal(typeof(CustomTypeWithPrimitiveFields).FullName, arrayRecord.ElementTypeName.FullName); - Assert.Equal(typeof(CustomTypeWithPrimitiveFields).Assembly.FullName, arrayRecord.ElementTypeName.AssemblyName!.FullName); + Assert.Equal(typeof(CustomTypeWithPrimitiveFields[]).FullName, arrayRecord.TypeName.FullName); + Assert.Equal(typeof(CustomTypeWithPrimitiveFields).Assembly.FullName, arrayRecord.TypeName.GetElementType().AssemblyName!.FullName); ClassRecord?[] classRecords = arrayRecord.GetArray(); for (int i = 0; i < input.Length; i++) { @@ -295,9 +296,9 @@ public void CanRead_TypesWithArraysOfComplexTypes() ] }; - ClassRecord classRecord = PayloadReader.ReadClassRecord(Serialize(input)); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(Serialize(input)); - ArrayRecord classRecords = (ArrayRecord)classRecord.GetSerializationRecord(nameof(CustomTypeWithArrayOfComplexTypes.Array))!; + SZArrayRecord classRecords = (SZArrayRecord)classRecord.GetSerializationRecord(nameof(CustomTypeWithArrayOfComplexTypes.Array))!; ClassRecord?[] array = classRecords.GetArray(); } @@ -313,9 +314,9 @@ public void CanRead_TypesWithArraysOfComplexTypes_MultipleNulls(int nullCount) using MemoryStream stream = Serialize(input); - ClassRecord classRecord = PayloadReader.ReadClassRecord(stream); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(stream); - ArrayRecord classRecords = (ArrayRecord)classRecord.GetSerializationRecord(nameof(CustomTypeWithArrayOfComplexTypes.Array))!; + SZArrayRecord classRecords = (SZArrayRecord)classRecord.GetSerializationRecord(nameof(CustomTypeWithArrayOfComplexTypes.Array))!; ClassRecord?[] array = classRecords.GetArray(); Assert.Equal(nullCount, array.Length); Assert.All(array, Assert.Null); @@ -332,11 +333,11 @@ public void CanRead_ArraysOfObjects() null ]; - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); - Assert.Equal(typeof(object).FullName, arrayRecord.ElementTypeName.FullName); - Assert.Equal("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", arrayRecord.ElementTypeName.AssemblyName!.FullName); - Assert.Equal(input, ((ArrayRecord)arrayRecord).GetArray()); + Assert.Equal(typeof(object[]).FullName, arrayRecord.TypeName.FullName); + Assert.Equal("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", arrayRecord.TypeName.GetElementType().AssemblyName!.FullName); + Assert.Equal(input, ((SZArrayRecord)arrayRecord).GetArray()); } [Theory] @@ -346,8 +347,8 @@ public void CanRead_ArraysOfObjects_MultipleNulls(int nullCount) { object?[] input = Enumerable.Repeat(null!, nullCount).ToArray(); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); - object?[] output = ((ArrayRecord)arrayRecord).GetArray(); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(input)); + object?[] output = ((SZArrayRecord)arrayRecord).GetArray(); Assert.Equal(nullCount, output.Length); Assert.All(output, Assert.Null); @@ -372,8 +373,8 @@ public void CanRead_CustomTypeWithArrayOfObjects() ] }; - ClassRecord classRecord = PayloadReader.ReadClassRecord(Serialize(input)); - ArrayRecord arrayRecord = (ArrayRecord)classRecord.GetSerializationRecord(nameof(CustomTypeWithArrayOfObjects.Array))!; + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(Serialize(input)); + SZArrayRecord arrayRecord = (SZArrayRecord)classRecord.GetSerializationRecord(nameof(CustomTypeWithArrayOfObjects.Array))!; Assert.Equal(input.Array, arrayRecord.GetArray()); } @@ -383,7 +384,7 @@ public void CanRead_CustomTypeWithArrayOfObjects() [InlineData("")] // null is prohibited by the BinaryFormatter itself public void CanReadString(string input) { - string output = ((PrimitiveTypeRecord)PayloadReader.Read(Serialize(input))).Value; + string output = ((PrimitiveTypeRecord)NrbfDecoder.Decode(Serialize(input))).Value; Assert.Equal(input, output); } @@ -413,7 +414,7 @@ public void CanReadPrimitiveTypes() static void Verify(T input) where T : unmanaged { - PrimitiveTypeRecord record = (PrimitiveTypeRecord)PayloadReader.Read(Serialize(input)); + PrimitiveTypeRecord record = (PrimitiveTypeRecord)NrbfDecoder.Decode(Serialize(input)); Assert.Equal(input, record.Value); } } @@ -434,7 +435,7 @@ public void CanReadStruct() Text = "StructsAreRepresentedWithClassRecords" }; - ClassRecord classRecord = PayloadReader.ReadClassRecord(Serialize(input)); + ClassRecord classRecord = NrbfDecoder.DecodeClassRecord(Serialize(input)); Assert.Equal(input.Integer, classRecord.GetInt32(nameof(SerializableStruct.Integer))); Assert.Equal(input.Text, classRecord.GetString(nameof(SerializableStruct.Text))); @@ -442,4 +443,4 @@ public void CanReadStruct() Assert.Equal(typeof(SerializableStruct).AssemblyQualifiedName, classRecord.TypeName.AssemblyQualifiedName); Assert.Equal(typeof(SerializableStruct).Assembly.FullName, classRecord.TypeName.AssemblyName!.FullName); } -} \ No newline at end of file +} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadTests.cs b/src/libraries/System.Formats.Nrbf/tests/ReadTests.cs similarity index 81% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadTests.cs rename to src/libraries/System.Formats.Nrbf/tests/ReadTests.cs index 24ba9c6f889b3..b9bee7d881a69 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/ReadTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/ReadTests.cs @@ -1,8 +1,9 @@ using System.IO; +using System.Runtime.Serialization.Formatters; using System.Runtime.Serialization.Formatters.Binary; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsBinaryFormatterSupported))] public abstract class ReadTests @@ -37,16 +38,16 @@ protected static BinaryFormatter CreateBinaryFormatter() => new() { #if DEBUG // Ensure both valid formats are covered by the tests - TypeFormat = Formatters.FormatterTypeStyle.TypesAlways | Formatters.FormatterTypeStyle.XsdString, + TypeFormat = FormatterTypeStyle.TypesAlways | FormatterTypeStyle.XsdString, #else - TypeFormat = Formatters.FormatterTypeStyle.TypesAlways + TypeFormat = FormatterTypeStyle.TypesAlways #endif }; #pragma warning restore SYSLIB0011 // Type or member is obsolete protected static void WriteSerializedStreamHeader(BinaryWriter writer, int major = 1, int minor = 0) { - writer.Write((byte)RecordType.SerializedStreamHeader); + writer.Write((byte)SerializationRecordType.SerializedStreamHeader); writer.Write(1); // root ID writer.Write(1); // header ID writer.Write(major); // major version @@ -55,7 +56,7 @@ protected static void WriteSerializedStreamHeader(BinaryWriter writer, int major protected static void WriteBinaryLibrary(BinaryWriter writer, int objectId, string libraryName) { - writer.Write((byte)RecordType.BinaryLibrary); + writer.Write((byte)SerializationRecordType.BinaryLibrary); writer.Write(objectId); writer.Write(libraryName); } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/RectangularArraysTests.cs b/src/libraries/System.Formats.Nrbf/tests/RectangularArraysTests.cs similarity index 67% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/RectangularArraysTests.cs rename to src/libraries/System.Formats.Nrbf/tests/RectangularArraysTests.cs index 1acd373c1d4de..25e7bb5a4d533 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/RectangularArraysTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/RectangularArraysTests.cs @@ -1,7 +1,8 @@ -using System.IO; +using System.Formats.Nrbf.Utils; +using System.IO; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class RectangularArraysTests : ReadTests { @@ -20,11 +21,11 @@ public void CanReadRectangularArraysOfPrimitiveTypes_2D(int x, int y) } using FileStream stream = SerializeToFile(array); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream); - VerifyLength(array, arrayRecord); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(byte[,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(string[,]))); + Verify(array, arrayRecord); + Assert.True(arrayRecord.TypeNameMatches(typeof(byte[,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(string[,]))); Assert.Equal(array, arrayRecord.GetArray(typeof(byte[,]))); Assert.Equal(2, arrayRecord.Rank); } @@ -42,11 +43,11 @@ public void CanReadRectangularArraysOfStrings_2D() } using MemoryStream stream = Serialize(array); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream); - VerifyLength(array, arrayRecord); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(string[,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(int[,]))); + Verify(array, arrayRecord); + Assert.True(arrayRecord.TypeNameMatches(typeof(string[,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(int[,]))); Assert.Equal(array, arrayRecord.GetArray(typeof(string[,]))); } @@ -62,11 +63,11 @@ public void CanReadRectangularArraysOfObjects_2D() } using MemoryStream stream = Serialize(array); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream); - VerifyLength(array, arrayRecord); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(object[,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(int[,]))); + Verify(array, arrayRecord); + Assert.True(arrayRecord.TypeNameMatches(typeof(object[,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(int[,]))); Assert.Equal(array, arrayRecord.GetArray(typeof(object[,]))); } @@ -89,11 +90,11 @@ public void CanReadRectangularArraysOfComplexTypes_2D() } using MemoryStream stream = Serialize(array); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream); - VerifyLength(array, arrayRecord); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(ComplexType2D[,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(int[,]))); + Verify(array, arrayRecord); + Assert.True(arrayRecord.TypeNameMatches(typeof(ComplexType2D[,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(int[,]))); var inputEnumerator = array.GetEnumerator(); foreach(ClassRecord classRecord in arrayRecord.GetArray(typeof(ComplexType2D[,]))) @@ -122,12 +123,12 @@ public void CanReadRectangularArraysOfPrimitiveTypes_3D() } using MemoryStream stream = Serialize(array); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream); - VerifyLength(array, arrayRecord); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(int[,,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(int[,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(string[,,]))); + Verify(array, arrayRecord); + Assert.True(arrayRecord.TypeNameMatches(typeof(int[,,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(int[,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(string[,,]))); Assert.Equal(array, arrayRecord.GetArray(typeof(int[,,]))); Assert.Equal(3, arrayRecord.Rank); } @@ -148,12 +149,12 @@ public void CanReadRectangularArraysOfStrings_3D() } using MemoryStream stream = Serialize(array); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream); - VerifyLength(array, arrayRecord); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(string[,,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(string[,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(int[,,]))); + Verify(array, arrayRecord); + Assert.True(arrayRecord.TypeNameMatches(typeof(string[,,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(string[,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(int[,,]))); Assert.Equal(array, arrayRecord.GetArray(typeof(string[,,]))); } @@ -169,12 +170,12 @@ public void CanReadRectangularArraysOfObjects_3D() } using MemoryStream stream = Serialize(array); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream); - VerifyLength(array, arrayRecord); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(object[,,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(object[,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(int[,,]))); + Verify(array, arrayRecord); + Assert.True(arrayRecord.TypeNameMatches(typeof(object[,,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(object[,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(int[,,]))); Assert.Equal(array, arrayRecord.GetArray(typeof(object[,,]))); } @@ -200,12 +201,12 @@ public void CanReadRectangularArraysOfComplexTypes_3D() } using MemoryStream stream = Serialize(array); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(stream); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream); - VerifyLength(array, arrayRecord); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(ComplexType3D[,,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(ComplexType3D[,]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(int[,,]))); + Verify(array, arrayRecord); + Assert.True(arrayRecord.TypeNameMatches(typeof(ComplexType3D[,,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(ComplexType3D[,]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(int[,,]))); var inputEnumerator = array.GetEnumerator(); foreach (ClassRecord classRecord in arrayRecord.GetArray(typeof(ComplexType3D[,,]))) @@ -219,12 +220,14 @@ public void CanReadRectangularArraysOfComplexTypes_3D() } } - internal static void VerifyLength(Array input, ArrayRecord arrayRecord) + internal static void Verify(Array input, ArrayRecord arrayRecord) { Assert.Equal(input.Rank, arrayRecord.Lengths.Length); for (int i = 0; i < input.Rank; i++) { Assert.Equal(input.GetLength(i), arrayRecord.Lengths[i]); } + Assert.Equal(input.GetType().FullName, arrayRecord.TypeName.FullName); + Assert.Equal(input.GetType().GetAssemblyNameIncludingTypeForwards(), arrayRecord.TypeName.AssemblyName!.FullName); } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/StartsWithPayloadHeaderTests.cs b/src/libraries/System.Formats.Nrbf/tests/StartsWithPayloadHeaderTests.cs similarity index 71% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/StartsWithPayloadHeaderTests.cs rename to src/libraries/System.Formats.Nrbf/tests/StartsWithPayloadHeaderTests.cs index 64847319672a4..1958d5396447e 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/StartsWithPayloadHeaderTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/StartsWithPayloadHeaderTests.cs @@ -4,7 +4,7 @@ using System.Text; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class StartsWithPayloadHeaderTests { @@ -13,18 +13,18 @@ public static IEnumerable GetArguments() // too few bytes yield return new object[] { - new byte[] { (byte)RecordType.SerializedStreamHeader, (byte)RecordType.MessageEnd }, + new byte[] { (byte)SerializationRecordType.SerializedStreamHeader, (byte)SerializationRecordType.MessageEnd }, false }; using MemoryStream memoryStream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(memoryStream, Encoding.UTF8); - writer.Write((byte)RecordType.SerializedStreamHeader); + writer.Write((byte)SerializationRecordType.SerializedStreamHeader); writer.Write(1); // root id writer.Write(2); // header id writer.Write(1); // major version writer.Write(0); // minor version - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); byte[] smallestValid = memoryStream.ToArray(); yield return new object[] { smallestValid, true }; @@ -36,9 +36,9 @@ public static IEnumerable GetArguments() [MemberData(nameof(GetArguments))] public void StartsWithPayloadHeader_ReturnsExpectedResult(byte[] bytes, bool expected) { - Assert.Equal(expected, PayloadReader.StartsWithPayloadHeader(bytes)); + Assert.Equal(expected, NrbfDecoder.StartsWithPayloadHeader(bytes)); using MemoryStream stream = new MemoryStream(bytes); - Assert.Equal(expected, PayloadReader.StartsWithPayloadHeader(stream)); + Assert.Equal(expected, NrbfDecoder.StartsWithPayloadHeader(stream)); } } diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/System.Runtime.Serialization.BinaryFormat.Tests.csproj b/src/libraries/System.Formats.Nrbf/tests/System.Formats.Nrbf.Tests.csproj similarity index 70% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/System.Runtime.Serialization.BinaryFormat.Tests.csproj rename to src/libraries/System.Formats.Nrbf/tests/System.Formats.Nrbf.Tests.csproj index 10736ae01359e..2acfeb3e162ba 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/System.Runtime.Serialization.BinaryFormat.Tests.csproj +++ b/src/libraries/System.Formats.Nrbf/tests/System.Formats.Nrbf.Tests.csproj @@ -6,12 +6,12 @@ - + - + diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/TypeExtensions.cs b/src/libraries/System.Formats.Nrbf/tests/TypeExtensions.cs similarity index 97% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/TypeExtensions.cs rename to src/libraries/System.Formats.Nrbf/tests/TypeExtensions.cs index 3e5cf134daeb6..81f0af4c49f7f 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/Utils/TypeExtensions.cs +++ b/src/libraries/System.Formats.Nrbf/tests/TypeExtensions.cs @@ -5,7 +5,7 @@ using System.Runtime.CompilerServices; using System.Text; -namespace System.Runtime.Serialization.BinaryFormat.Utils; +namespace System.Formats.Nrbf.Utils; internal static class TypeExtensions { diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/TypeMatchTests.cs b/src/libraries/System.Formats.Nrbf/tests/TypeMatchTests.cs similarity index 59% rename from src/libraries/System.Runtime.Serialization.BinaryFormat/tests/TypeMatchTests.cs rename to src/libraries/System.Formats.Nrbf/tests/TypeMatchTests.cs index 8cba03d54f926..7bf48eab61689 100644 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/TypeMatchTests.cs +++ b/src/libraries/System.Formats.Nrbf/tests/TypeMatchTests.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; -using System.Runtime.Serialization.BinaryFormat.Utils; +using System.Formats.Nrbf.Utils; using Xunit; -namespace System.Runtime.Serialization.BinaryFormat.Tests; +namespace System.Formats.Nrbf.Tests; public class TypeMatchTests : ReadTests { @@ -73,6 +73,18 @@ public void CanRecognizeGenericSystemTypes() Verify(new Dictionary>>()); } + [Fact] + public void TakesGenericTypeDefinitionIntoAccount() + { + List input = new List(); + + SerializationRecord one = NrbfDecoder.Decode(Serialize(input)); + + // The generic arguments match, the generic type definition does not. + Assert.False(one.TypeNameMatches(typeof(Stack))); + Assert.True(one.TypeNameMatches(typeof(List))); + } + [Fact] public void CanRecognizeGenericNonSystemTypes() { @@ -284,87 +296,15 @@ public void CanRecognizeRectangular5DArraysOfGenericNonSystemTypes() VerifyRectangularArray_5D(new GenericNonSystemClass>()); } - [Theory] - [InlineData(1)] // BinaryArrayType.SingleOffset - [InlineData(2)] // BinaryArrayType.JaggedOffset - [InlineData(3)] // BinaryArrayType.RectangularOffset - [InlineData(32)] // max rank - public void CanRecognizeArraysOfAllSupportedPrimitiveTypesWithCustomOffsets(int arrayRank) - { - VerifyCustomOffsetArray(true, arrayRank); - VerifyCustomOffsetArray('c', arrayRank); - VerifyCustomOffsetArray(byte.MaxValue, arrayRank); - VerifyCustomOffsetArray(sbyte.MaxValue, arrayRank); - VerifyCustomOffsetArray(short.MaxValue, arrayRank); - VerifyCustomOffsetArray(ushort.MaxValue, arrayRank); - VerifyCustomOffsetArray(int.MaxValue, arrayRank); - VerifyCustomOffsetArray(uint.MaxValue, arrayRank); -#if !NETFRAMEWORK - VerifyCustomOffsetArray(nint.MaxValue, arrayRank); - VerifyCustomOffsetArray(nuint.MaxValue, arrayRank); -#endif - VerifyCustomOffsetArray(long.MaxValue, arrayRank); - VerifyCustomOffsetArray(ulong.MaxValue, arrayRank); - VerifyCustomOffsetArray(float.MaxValue, arrayRank); - VerifyCustomOffsetArray(double.MaxValue, arrayRank); - VerifyCustomOffsetArray(decimal.MaxValue, arrayRank); - VerifyCustomOffsetArray(TimeSpan.MaxValue, arrayRank); - VerifyCustomOffsetArray(DateTime.Now, arrayRank); - } - - [Theory] - // [InlineData(1)] // BinaryArrayType.SingleOffset bug in BinaryFormatter!! - [InlineData(2)] // BinaryArrayType.JaggedOffset - [InlineData(3)] // BinaryArrayType.RectangularOffset - [InlineData(32)] // max rank - public void CanRecognizeArraysOfSystemTypesWithCustomOffsets(int arrayRank) - { - VerifyCustomOffsetArray(new NotSupportedException(), arrayRank); - } - - [Theory] - // [InlineData(1)] // BinaryArrayType.SingleOffset bug in BinaryFormatter!! - [InlineData(2)] // BinaryArrayType.JaggedOffset - [InlineData(3)] // BinaryArrayType.RectangularOffset - [InlineData(32)] // max rank - public void CanRecognizeArraysOfNonSystemTypesWithCustomOffsets(int arrayRank) - { - VerifyCustomOffsetArray(new NonSystemClass(), arrayRank); - } - - [Theory] - // [InlineData(1)] // BinaryArrayType.SingleOffset bug in BinaryFormatter!! - [InlineData(2)] // BinaryArrayType.JaggedOffset - [InlineData(3)] // BinaryArrayType.RectangularOffset - [InlineData(32)] // max rank - public void CanRecognizeArraysOfGenericSystemTypesWithCustomOffsets(int arrayRank) - { - VerifyCustomOffsetArray(new List(), arrayRank); - VerifyCustomOffsetArray(new List>(), arrayRank); - VerifyCustomOffsetArray(new Dictionary(), arrayRank); - VerifyCustomOffsetArray(new Dictionary>>(), arrayRank); - } - - [Theory] - // [InlineData(1)] // BinaryArrayType.SingleOffset bug in BinaryFormatter!! - [InlineData(2)] // BinaryArrayType.JaggedOffset - [InlineData(3)] // BinaryArrayType.RectangularOffset - [InlineData(32)] // max rank - public void CanRecognizeArraysOfGenericNonSystemTypesWithCustomOffsets(int arrayRank) - { - VerifyCustomOffsetArray(new GenericNonSystemClass(), arrayRank); - VerifyCustomOffsetArray(new GenericNonSystemClass>(), arrayRank); - } - private static void Verify(T input) where T : notnull { - SerializationRecord one = PayloadReader.Read(Serialize(input)); + SerializationRecord one = NrbfDecoder.Decode(Serialize(input)); - Assert.True(one.IsTypeNameMatching(typeof(T))); + Assert.True(one.TypeNameMatches(typeof(T))); foreach (Type type in PrimitiveTypes) { - Assert.Equal(typeof(T) == type, one.IsTypeNameMatching(type)); + Assert.Equal(typeof(T) == type, one.TypeNameMatches(type)); } } @@ -372,26 +312,31 @@ private static void VerifySZArray(T input) where T : notnull { T[] array = [input]; - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(array)); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(array)); + + Assert.Equal(typeof(T[]).GetTypeFullNameIncludingTypeForwards(), arrayRecord.TypeName.FullName); - Assert.Equal(typeof(T).GetTypeFullNameIncludingTypeForwards(), arrayRecord.ElementTypeName.FullName); - Assert.Equal(typeof(T).GetAssemblyNameIncludingTypeForwards(), arrayRecord.ElementTypeName.AssemblyName!.FullName); + string expectedAssemblyName = typeof(T).Assembly == typeof(object).Assembly + ? "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" + : typeof(T).Assembly.FullName; + + Assert.Equal(expectedAssemblyName, arrayRecord.TypeName.AssemblyName!.FullName); if (PrimitiveTypes.Contains(typeof(T))) { - Assert.True(arrayRecord is ArrayRecord, userMessage: typeof(T).Name); + Assert.True(arrayRecord is SZArrayRecord, userMessage: typeof(T).Name); } else { - Assert.True(arrayRecord is ArrayRecord, userMessage: typeof(T).Name); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(T[]))); - Assert.Equal(arrayRecord.ElementTypeName.AssemblyName.FullName, typeof(T).GetAssemblyNameIncludingTypeForwards()); + Assert.True(arrayRecord is SZArrayRecord, userMessage: typeof(T).Name); + Assert.True(arrayRecord.TypeNameMatches(typeof(T[]))); + Assert.Equal(arrayRecord.TypeName.GetElementType().AssemblyName.FullName, typeof(T).GetAssemblyNameIncludingTypeForwards()); } foreach (Type type in PrimitiveTypes) { - Assert.False(arrayRecord.IsTypeNameMatching(type)); - Assert.Equal(typeof(T) == type, arrayRecord.IsTypeNameMatching(type.MakeArrayType())); + Assert.False(arrayRecord.TypeNameMatches(type)); + Assert.Equal(typeof(T) == type, arrayRecord.TypeNameMatches(type.MakeArrayType())); } if (PrimitiveTypes.Contains(typeof(T))) @@ -404,20 +349,20 @@ private static void VerifyJaggedArray(T input) where T : notnull { T[][] jaggedArray = [[input]]; - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(jaggedArray)); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(jaggedArray)); - Assert.Equal(typeof(T[]).GetTypeFullNameIncludingTypeForwards(), arrayRecord.ElementTypeName.FullName); + Assert.Equal(typeof(T[]).GetTypeFullNameIncludingTypeForwards(), arrayRecord.TypeName.GetElementType().FullName); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(T[]))); - Assert.True(arrayRecord.IsTypeNameMatching(typeof(T[][]))); - Assert.False(arrayRecord.IsTypeNameMatching(typeof(T[][][]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(T[]))); + Assert.True(arrayRecord.TypeNameMatches(typeof(T[][]))); + Assert.False(arrayRecord.TypeNameMatches(typeof(T[][][]))); foreach (Type type in PrimitiveTypes) { - Assert.False(arrayRecord.IsTypeNameMatching(type)); - Assert.False(arrayRecord.IsTypeNameMatching(type.MakeArrayType())); - Assert.Equal(typeof(T) == type, arrayRecord.IsTypeNameMatching(type.MakeArrayType().MakeArrayType())); - Assert.False(arrayRecord.IsTypeNameMatching(type.MakeArrayType().MakeArrayType().MakeArrayType())); + Assert.False(arrayRecord.TypeNameMatches(type)); + Assert.False(arrayRecord.TypeNameMatches(type.MakeArrayType())); + Assert.Equal(typeof(T) == type, arrayRecord.TypeNameMatches(type.MakeArrayType().MakeArrayType())); + Assert.False(arrayRecord.TypeNameMatches(type.MakeArrayType().MakeArrayType().MakeArrayType())); } } @@ -440,50 +385,19 @@ private static void VerifyRectangularArray_5D(T input) where T : notnull private static void VerifyRectangularArray(Array array) { int arrayRank = array.GetType().GetArrayRank(); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(array)); - - Assert.Equal(typeof(T).GetTypeFullNameIncludingTypeForwards(), arrayRecord.ElementTypeName.FullName); - Assert.False(arrayRecord is ArrayRecord, userMessage: typeof(T).Name); - Assert.True(arrayRecord.ArrayType is BinaryArrayType.Rectangular); - - foreach (Type type in PrimitiveTypes.Concat([typeof(T)])) - { - Assert.False(arrayRecord.IsTypeNameMatching(type)); - Assert.False(arrayRecord.IsTypeNameMatching(type.MakeArrayType(arrayRank - 1))); - Assert.Equal(typeof(T) == type, arrayRecord.IsTypeNameMatching(type.MakeArrayType(arrayRank))); - Assert.False(arrayRecord.IsTypeNameMatching(type.MakeArrayType(arrayRank + 1))); - } - } - - private static void VerifyCustomOffsetArray(T input, int arrayRank) where T : notnull - { - int[] lengths = Enumerable.Repeat(1 /* length */, arrayRank).ToArray(); - int[] offsets = Enumerable.Repeat(10 /* offset */, arrayRank).ToArray(); - - Array array = Array.CreateInstance(typeof(T), lengths, offsets); - for (int dimension = 0; dimension < lengths.Length; dimension++) - { - Assert.Equal(offsets[dimension], array.GetLowerBound(dimension)); - } - array.SetValue(input, offsets); + ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(Serialize(array)); - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(array)); + Assert.Equal(typeof(T).GetTypeFullNameIncludingTypeForwards(), arrayRecord.TypeName.GetElementType().FullName); - Assert.Equal(typeof(T).GetTypeFullNameIncludingTypeForwards(), arrayRecord.ElementTypeName.FullName); - Assert.False(arrayRecord is ArrayRecord, userMessage: typeof(T).Name); + Assert.False(arrayRecord is SZArrayRecord, userMessage: typeof(T).Name); + Assert.True(arrayRecord.Rank > 1); foreach (Type type in PrimitiveTypes.Concat([typeof(T)])) { - Assert.False(arrayRecord.IsTypeNameMatching(type)); - if (arrayRank > 1) - { - Assert.False(arrayRecord.IsTypeNameMatching(type.MakeArrayType(arrayRank - 1))); - } - Assert.Equal(typeof(T) == type, arrayRecord.IsTypeNameMatching(type.MakeArrayType(arrayRank))); - if (arrayRank <= 31) // 32 is max - { - Assert.False(arrayRecord.IsTypeNameMatching(type.MakeArrayType(arrayRank + 1))); - } + Assert.False(arrayRecord.TypeNameMatches(type)); + Assert.False(arrayRecord.TypeNameMatches(type.MakeArrayType(arrayRank - 1))); + Assert.Equal(typeof(T) == type, arrayRecord.TypeNameMatches(type.MakeArrayType(arrayRank))); + Assert.False(arrayRecord.TypeNameMatches(type.MakeArrayType(arrayRank + 1))); } } } diff --git a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj index 74a16e4dc024d..d5bfd3dc7046c 100644 --- a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj +++ b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj @@ -44,8 +44,6 @@ System.Resources.Extensions.PreserializedResourceWriter - - @@ -65,12 +63,8 @@ System.Resources.Extensions.PreserializedResourceWriter Link="System\Numerics\Hashing\HashHelpers.cs" /> - - - - - + diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.IParseState.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.IParseState.cs index 01dc73bc49681..b03c06ab43671 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.IParseState.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.IParseState.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat; @@ -15,7 +15,7 @@ internal sealed partial class BinaryFormattedObject internal interface IParseState { BinaryReader Reader { get; } - IReadOnlyDictionary RecordMap { get; } + IReadOnlyDictionary RecordMap { get; } Options Options { get; } ITypeResolver TypeResolver { get; } } diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.ParseState.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.ParseState.cs index 6ca0c290e060f..eb7bcc4aa75e3 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.ParseState.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.ParseState.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat; @@ -23,7 +23,7 @@ public ParseState(BinaryReader reader, BinaryFormattedObject format) } public BinaryReader Reader { get; } - public IReadOnlyDictionary RecordMap => _format.RecordMap; + public IReadOnlyDictionary RecordMap => _format.RecordMap; public Options Options => _format._options; public ITypeResolver TypeResolver => _format.TypeResolver; } diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.cs index 35502f066054c..56b1814381520 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObject.cs @@ -7,7 +7,7 @@ using System.Reflection; using System.Runtime.ExceptionServices; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat; @@ -45,7 +45,7 @@ public BinaryFormattedObject(Stream stream, Options? options = null) try { - RootRecord = PayloadReader.Read(stream, out var readonlyRecordMap, options: s_payloadOptions, leaveOpen: true); + RootRecord = NrbfDecoder.Decode(stream, out var readonlyRecordMap, options: s_payloadOptions, leaveOpen: true); RecordMap = readonlyRecordMap; } catch (Exception ex) when (ex is ArgumentException or InvalidCastException or ArithmeticException or IOException) @@ -67,7 +67,7 @@ public object Deserialize() { try { - return Deserializer.Deserializer.Deserialize(RootRecord.ObjectId, RecordMap, TypeResolver, _options); + return Deserializer.Deserializer.Deserialize(RootRecord.Id, RecordMap, TypeResolver, _options); } catch (Exception ex) when (ex is ArgumentException or InvalidCastException or ArithmeticException or IOException) { @@ -89,7 +89,7 @@ public object Deserialize() /// Gets a record by it's identifier. Not all records have identifiers, only ones that /// can be referenced by other records. /// - public SerializationRecord this[Id id] => RecordMap[id]; + public SerializationRecord this[SerializationRecordId id] => RecordMap[id]; - public IReadOnlyDictionary RecordMap { get; } + public IReadOnlyDictionary RecordMap { get; } } diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObjectExtensions.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObjectExtensions.cs deleted file mode 100644 index 49595e9a5f89d..0000000000000 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/BinaryFormattedObjectExtensions.cs +++ /dev/null @@ -1,37 +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.Diagnostics; -using System.Runtime.Serialization.BinaryFormat; - -namespace System.Resources.Extensions.BinaryFormat; - -internal static class BinaryFormattedObjectExtensions -{ - internal static object GetMemberPrimitiveTypedValue(this SerializationRecord record) - { - Debug.Assert(record.RecordType is RecordType.MemberPrimitiveTyped or RecordType.BinaryObjectString); - - return record switch - { - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - PrimitiveTypeRecord primitive => primitive.Value, - _ => ((PrimitiveTypeRecord)record).Value - }; - } -} diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ArrayRecordDeserializer.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ArrayRecordDeserializer.cs index 11b8cc1101173..0c8e5d00fe454 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ArrayRecordDeserializer.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ArrayRecordDeserializer.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -22,15 +22,14 @@ internal ArrayRecordDeserializer(ArrayRecord arrayRecord, IDeserializer deserial : base(arrayRecord, deserializer) { // Other array types are handled directly (ArraySinglePrimitive and ArraySingleString). - Debug.Assert(arrayRecord.RecordType is not (RecordType.ArraySingleString or RecordType.ArraySinglePrimitive)); - Debug.Assert(arrayRecord.ArrayType is (BinaryArrayType.Single or BinaryArrayType.Jagged or BinaryArrayType.Rectangular)); + Debug.Assert(arrayRecord.RecordType is not (SerializationRecordType.ArraySingleString or SerializationRecordType.ArraySinglePrimitive)); _arrayRecord = arrayRecord; - _elementType = deserializer.TypeResolver.GetType(arrayRecord.ElementTypeName); - Type expectedArrayType = arrayRecord.ArrayType switch + _elementType = deserializer.TypeResolver.GetType(arrayRecord.TypeName.GetElementType()); + Type expectedArrayType = arrayRecord.Rank switch { - BinaryArrayType.Rectangular => _elementType.MakeArrayType(arrayRecord.Rank), - _ => _elementType.MakeArrayType() + 1 => _elementType.MakeArrayType(), + _ => _elementType.MakeArrayType(arrayRecord.Rank), }; // Tricky part: for arrays of classes/structs the following record allocates and array of class records // (because the payload reader can not load types, instantiate objects and rehydrate them) @@ -48,14 +47,14 @@ internal ArrayRecordDeserializer(ArrayRecord arrayRecord, IDeserializer deserial _canIterate = _arrayOfT.Length > 0; } - internal override Id Continue() + internal override SerializationRecordId Continue() { int[] indices = _indices; int[] lengths = _lengths; while (_canIterate) { - (object? memberValue, Id reference) = UnwrapMemberValue(_arrayOfClassRecords.GetValue(indices)); + (object? memberValue, SerializationRecordId reference) = UnwrapMemberValue(_arrayOfClassRecords.GetValue(indices)); if (s_missingValueSentinel == memberValue) { @@ -67,7 +66,7 @@ internal override Id Continue() { // Need to track a fixup for this index. _hasFixups = true; - Deserializer.PendValueUpdater(new ArrayUpdater(_arrayRecord.ObjectId, reference, indices.ToArray())); + Deserializer.PendValueUpdater(new ArrayUpdater(_arrayRecord.Id, reference, indices.ToArray())); } _arrayOfT.SetValue(memberValue, indices); @@ -95,41 +94,36 @@ internal override Id Continue() if (!_hasFixups) { - Deserializer.CompleteObject(_arrayRecord.ObjectId); + Deserializer.CompleteObject(_arrayRecord.Id); } - return Id.Null; + return default(SerializationRecordId); } internal static Array GetArraySinglePrimitive(SerializationRecord record) => record switch { - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), - ArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), + SZArrayRecord primitiveArray => primitiveArray.GetArray(), _ => throw new NotSupportedException(), }; [RequiresUnreferencedCode("Calls System.Windows.Forms.BinaryFormat.BinaryFormattedObject.TypeResolver.GetType(TypeName)")] internal static Array? GetSimpleBinaryArray(ArrayRecord arrayRecord, BinaryFormattedObject.ITypeResolver typeResolver) { - if (arrayRecord.ArrayType is not (BinaryArrayType.Single or BinaryArrayType.Jagged or BinaryArrayType.Rectangular)) - { - throw new NotSupportedException(SR.NotSupported_NonZeroOffsets); - } - - Type arrayRecordElementType = typeResolver.GetType(arrayRecord.ElementTypeName); + Type arrayRecordElementType = typeResolver.GetType(arrayRecord.TypeName.GetElementType()); Type elementType = arrayRecordElementType; while (elementType.IsArray) { @@ -142,10 +136,10 @@ internal override Id Continue() return null; } - Type expectedArrayType = arrayRecord.ArrayType switch + Type expectedArrayType = arrayRecord.Rank switch { - BinaryArrayType.Rectangular => arrayRecordElementType.MakeArrayType(arrayRecord.Rank), - _ => arrayRecordElementType.MakeArrayType() + 1 => arrayRecordElementType.MakeArrayType(), + _ => arrayRecordElementType.MakeArrayType(arrayRecord.Rank) }; return arrayRecord.GetArray(expectedArrayType); diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ArrayUpdater.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ArrayUpdater.cs index 8cd8326278103..be0f7690a3bf1 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ArrayUpdater.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ArrayUpdater.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -9,12 +10,12 @@ internal sealed class ArrayUpdater : ValueUpdater { private readonly int[] _indices; - internal ArrayUpdater(int objectId, int valueId, int[] indices) : base(objectId, valueId) + internal ArrayUpdater(SerializationRecordId objectId, SerializationRecordId valueId, int[] indices) : base(objectId, valueId) { _indices = indices; } - internal override void UpdateValue(IDictionary objects) + internal override void UpdateValue(IDictionary objects) { object value = objects[ValueId]; Array array = (Array)objects[ObjectId]; diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordDeserializer.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordDeserializer.cs index a076db8262b77..67611a70612a5 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordDeserializer.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordDeserializer.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -31,7 +31,7 @@ private protected ClassRecordDeserializer(ClassRecord classRecord, object @objec internal static ObjectRecordDeserializer Create(ClassRecord classRecord, IDeserializer deserializer) { Type type = deserializer.TypeResolver.GetType(classRecord.TypeName); - Id id = classRecord.ObjectId; + SerializationRecordId id = classRecord.Id; ISerializationSurrogate? surrogate = deserializer.GetSurrogate(type); diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordFieldInfoDeserializer.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordFieldInfoDeserializer.cs index 87a3ee4bc5e89..c06a5e247e81e 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordFieldInfoDeserializer.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordFieldInfoDeserializer.cs @@ -5,7 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; using System.Runtime.Serialization.Formatters; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -17,14 +17,14 @@ namespace System.Resources.Extensions.BinaryFormat.Deserializer; /// internal sealed class ClassRecordFieldInfoDeserializer : ClassRecordDeserializer { - private readonly Runtime.Serialization.BinaryFormat.ClassRecord _classRecord; + private readonly ClassRecord _classRecord; private readonly MemberInfo[] _fieldInfo; private int _currentFieldIndex; private readonly bool _isValueType; private bool _hasFixups; internal ClassRecordFieldInfoDeserializer( - Runtime.Serialization.BinaryFormat.ClassRecord classRecord, + ClassRecord classRecord, object @object, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type type, @@ -38,7 +38,7 @@ internal ClassRecordFieldInfoDeserializer( _isValueType = type.IsValueType; } - internal override Id Continue() + internal override SerializationRecordId Continue() { // When directly setting fields we need to populate fields with primitive types before we // can add the object to the deserialized object list to handle value types. This ensures @@ -65,7 +65,7 @@ internal override Id Continue() throw new SerializationException(SR.Format(SR.Serialization_MissingField, field.Name, field.DeclaringType!.Name)); } - (object? memberValue, Id reference) = UnwrapMemberValue(_classRecord.GetRawValue(field.Name)); + (object? memberValue, SerializationRecordId reference) = UnwrapMemberValue(_classRecord.GetRawValue(field.Name)); if (s_missingValueSentinel == memberValue) { // Record has not been encountered yet, need to pend iteration. @@ -78,7 +78,7 @@ internal override Id Continue() { // Need to track a fixup for this field. _hasFixups = true; - Deserializer.PendValueUpdater(new FieldValueUpdater(_classRecord.ObjectId, reference, field)); + Deserializer.PendValueUpdater(new FieldValueUpdater(_classRecord.Id, reference, field)); } _currentFieldIndex++; @@ -88,11 +88,11 @@ internal override Id Continue() { // We can be used for completion even with fixups if we're not a value type as our fixups won't need to be // copied to propogate them. Note that surrogates cannot replace our created instance for reference types. - Deserializer.CompleteObject(_classRecord.ObjectId); + Deserializer.CompleteObject(_classRecord.Id); } // No more missing member refs. - return Id.Null; + return default(SerializationRecordId); } } diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordSerializationInfoDeserializer.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordSerializationInfoDeserializer.cs index 71053d04cebc1..d4543c400894e 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordSerializationInfoDeserializer.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ClassRecordSerializationInfoDeserializer.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -19,14 +19,14 @@ namespace System.Resources.Extensions.BinaryFormat.Deserializer; /// internal sealed class ClassRecordSerializationInfoDeserializer : ClassRecordDeserializer { - private readonly Runtime.Serialization.BinaryFormat.ClassRecord _classRecord; + private readonly ClassRecord _classRecord; private readonly SerializationInfo _serializationInfo; private readonly ISerializationSurrogate? _surrogate; private readonly IEnumerator _memberNamesIterator; private bool _canIterate; internal ClassRecordSerializationInfoDeserializer( - Runtime.Serialization.BinaryFormat.ClassRecord classRecord, + ClassRecord classRecord, object @object, Type type, ISerializationSurrogate? surrogate, @@ -39,14 +39,14 @@ internal ClassRecordSerializationInfoDeserializer( _canIterate = _memberNamesIterator.MoveNext(); // start the iterator } - internal override Id Continue() + internal override SerializationRecordId Continue() { if (_canIterate) { do { string memberName = _memberNamesIterator.Current; - (object? memberValue, Id reference) = UnwrapMemberValue(_classRecord.GetRawValue(memberName)); + (object? memberValue, SerializationRecordId reference) = UnwrapMemberValue(_classRecord.GetRawValue(memberName)); if (s_missingValueSentinel == memberValue) { @@ -57,7 +57,7 @@ internal override Id Continue() if (memberValue is not null && DoesValueNeedUpdated(memberValue, reference)) { Deserializer.PendValueUpdater(new SerializationInfoValueUpdater( - _classRecord.ObjectId, + _classRecord.Id, reference, _serializationInfo, memberName)); @@ -81,11 +81,11 @@ internal override Id Continue() // If we were confident that there were no cycles in the graph to this point we could apply directly // if there were no pending value types (which should also not happen if there are no cycles). - PendingSerializationInfo pending = new(_classRecord.ObjectId, _serializationInfo, _surrogate); + PendingSerializationInfo pending = new(_classRecord.Id, _serializationInfo, _surrogate); Deserializer.PendSerializationInfo(pending); // No more missing member refs. - return Id.Null; + return default(SerializationRecordId); } } diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/Deserializer.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/Deserializer.cs index b553b2367a7d4..8e763fe850d86 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/Deserializer.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/Deserializer.cs @@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -51,7 +51,7 @@ namespace System.Resources.Extensions.BinaryFormat.Deserializer; /// internal sealed partial class Deserializer : IDeserializer { - private readonly IReadOnlyDictionary _recordMap; + private readonly IReadOnlyDictionary _recordMap; private readonly BinaryFormattedObject.ITypeResolver _typeResolver; BinaryFormattedObject.ITypeResolver IDeserializer.TypeResolver => _typeResolver; @@ -60,8 +60,8 @@ internal sealed partial class Deserializer : IDeserializer BinaryFormattedObject.Options IDeserializer.Options => Options; /// - private readonly Dictionary _deserializedObjects = []; - IDictionary IDeserializer.DeserializedObjects => _deserializedObjects; + private readonly Dictionary _deserializedObjects = []; + IDictionary IDeserializer.DeserializedObjects => _deserializedObjects; // Surrogate cache. private readonly Dictionary? _surrogates; @@ -75,34 +75,32 @@ internal sealed partial class Deserializer : IDeserializer // dictionary, to do so we'd need to know if any referenced object is going to get to this state // even if it hasn't finished parsing, which isn't easy to do with cycles involved. private Queue? _pendingSerializationInfo; - private HashSet? _pendingSerializationInfoIds; + private HashSet? _pendingSerializationInfoIds; - // Keeping a separate stack for ids for fast infinite loop checks. - private readonly Stack _parseStack = []; private readonly Stack _parserStack = []; /// - private readonly HashSet _incompleteObjects = []; - public HashSet IncompleteObjects => _incompleteObjects; + private readonly HashSet _incompleteObjects = []; + public HashSet IncompleteObjects => _incompleteObjects; // For a given object id, the set of ids that it is waiting on to complete. - private Dictionary>? _incompleteDependencies; + private Dictionary>? _incompleteDependencies; // The pending value updaters. Scanned each time an object is completed. private HashSet? _pendingUpdates; // Kept as a field to avoid allocating a new one every time we complete objects. - private readonly Queue _pendingCompletions = []; + private readonly Queue _pendingCompletions = []; - private readonly Id _rootId; + private readonly SerializationRecordId _rootId; // We group individual object events here to fire them all when we complete the graph. private event Action? OnDeserialization; private event Action? OnDeserialized; private Deserializer( - Id rootId, - IReadOnlyDictionary recordMap, + SerializationRecordId rootId, + IReadOnlyDictionary recordMap, BinaryFormattedObject.ITypeResolver typeResolver, BinaryFormattedObject.Options options) { @@ -122,8 +120,8 @@ private Deserializer( /// [RequiresUnreferencedCode("Calls System.Windows.Forms.BinaryFormat.Deserializer.Deserializer.Deserialize()")] internal static object Deserialize( - Id rootId, - IReadOnlyDictionary recordMap, + SerializationRecordId rootId, + IReadOnlyDictionary recordMap, BinaryFormattedObject.ITypeResolver typeResolver, BinaryFormattedObject.Options options) { @@ -131,7 +129,7 @@ internal static object Deserialize( return deserializer.Deserialize(); } - [RequiresUnreferencedCode("Calls System.Windows.Forms.BinaryFormat.Deserializer.Deserializer.DeserializeRoot(Id)")] + [RequiresUnreferencedCode("Calls System.Windows.Forms.BinaryFormat.Deserializer.Deserializer.DeserializeRoot(SerializationRecordId)")] private object Deserialize() { DeserializeRoot(_rootId); @@ -146,7 +144,7 @@ private object Deserialize() if (--pendingCount >= 0 && _pendingSerializationInfo.Count != 0 && _incompleteDependencies is not null - && _incompleteDependencies.TryGetValue(pending.ObjectId, out HashSet? dependencies)) + && _incompleteDependencies.TryGetValue(pending.ObjectId, out HashSet? dependencies)) { // We can get here with nested ISerializable value types. @@ -180,8 +178,8 @@ private object Deserialize() return _deserializedObjects[_rootId]; } - [RequiresUnreferencedCode("Calls DeserializeNew(Id)")] - private void DeserializeRoot(Id rootId) + [RequiresUnreferencedCode("Calls DeserializeNew(SerializationRecordId)")] + private void DeserializeRoot(SerializationRecordId rootId) { object root = DeserializeNew(rootId); if (root is not ObjectRecordDeserializer parser) @@ -189,35 +187,24 @@ private void DeserializeRoot(Id rootId) return; } - _parseStack.Push(rootId); _parserStack.Push(parser); while (_parserStack.Count > 0) { ObjectRecordDeserializer? currentParser = _parserStack.Pop(); - int currentId = _parseStack.Pop(); - Debug.Assert(currentId == currentParser.ObjectRecord.ObjectId); - Id requiredId; - while (!(requiredId = currentParser.Continue()).IsNull) + SerializationRecordId requiredId; + while (!(requiredId = currentParser.Continue()).Equals(default(SerializationRecordId))) { // Beside ObjectRecordDeserializer, DeserializeNew can return a raw value like int, string or an array. if (DeserializeNew(requiredId) is ObjectRecordDeserializer requiredParser) { // The required object is not complete. - if (_parseStack.Contains(requiredId)) - { - // All objects should be available before they're asked for a second time. - throw new SerializationException(SR.Serialization_Cycle); - } - // Push our current parser. - _parseStack.Push(currentId); _parserStack.Push(currentParser); // Push the required parser so we can complete it. - _parseStack.Push(requiredId); _parserStack.Push(requiredParser); break; @@ -226,8 +213,8 @@ private void DeserializeRoot(Id rootId) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - [RequiresUnreferencedCode("Calls System.Windows.Forms.BinaryFormat.Deserializer.ObjectRecordParser.Create(Id, IRecord, IDeserializer)")] - object DeserializeNew(Id id) + [RequiresUnreferencedCode("Calls System.Windows.Forms.BinaryFormat.Deserializer.ObjectRecordParser.Create(SerializationRecordId, IRecord, IDeserializer)")] + object DeserializeNew(SerializationRecordId id) { // Strings, string arrays, and primitive arrays can be completed without creating a // parser object. Single primitives don't normally show up as records unless they are top @@ -238,22 +225,26 @@ object DeserializeNew(Id id) object? value = record.RecordType switch { - RecordType.BinaryObjectString => ((PrimitiveTypeRecord)record).Value, - RecordType.MemberPrimitiveTyped => record.GetMemberPrimitiveTypedValue(), - RecordType.ArraySingleString => ((ArrayRecord)record).GetArray(), - RecordType.ArraySinglePrimitive => ArrayRecordDeserializer.GetArraySinglePrimitive(record), - RecordType.BinaryArray => ArrayRecordDeserializer.GetSimpleBinaryArray((ArrayRecord)record, _typeResolver), + SerializationRecordType.BinaryObjectString => ((PrimitiveTypeRecord)record).Value, + SerializationRecordType.MemberPrimitiveTyped => ((PrimitiveTypeRecord)record).Value, + SerializationRecordType.ArraySingleString => ((SZArrayRecord)record).GetArray(), + SerializationRecordType.ArraySinglePrimitive => ArrayRecordDeserializer.GetArraySinglePrimitive(record), + SerializationRecordType.BinaryArray => ArrayRecordDeserializer.GetSimpleBinaryArray((ArrayRecord)record, _typeResolver), _ => null }; if (value is not null) { - _deserializedObjects.Add(record.ObjectId, value); + _deserializedObjects.Add(record.Id, value); return value; } // Not a simple case, need to do a full deserialization of the record. - _incompleteObjects.Add(id); + if (!_incompleteObjects.Add(id)) + { + // All objects should be available before they're asked for a second time. + throw new SerializationException(SR.Serialization_Cycle); + } var deserializer = ObjectRecordDeserializer.Create(record, this); @@ -300,7 +291,7 @@ void IDeserializer.PendValueUpdater(ValueUpdater updater) _incompleteDependencies ??= []; - if (_incompleteDependencies.TryGetValue(updater.ObjectId, out HashSet? dependencies)) + if (_incompleteDependencies.TryGetValue(updater.ObjectId, out HashSet? dependencies)) { dependencies.Add(updater.ValueId); } @@ -314,21 +305,21 @@ void IDeserializer.PendValueUpdater(ValueUpdater updater) "Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "The type is already in the cache of the TypeResolver, no need to mark this one again.")] - void IDeserializer.CompleteObject(Id id) + void IDeserializer.CompleteObject(SerializationRecordId id) { // Need to use a queue as Completion is recursive. _pendingCompletions.Enqueue(id); - Id completed = Id.Null; + SerializationRecordId completed = default(SerializationRecordId); while (_pendingCompletions.Count > 0) { - int completedId = _pendingCompletions.Dequeue(); + SerializationRecordId completedId = _pendingCompletions.Dequeue(); _incompleteObjects.Remove(completedId); // When we've recursed, we've done so because there are no more dependencies for the current id, so we can // remove it from the dictionary. We have to pend as we can't remove while we're iterating the dictionary. - if (!completed.IsNull) + if (!completed.Equals(default(SerializationRecordId))) { _incompleteDependencies?.Remove(completed); @@ -339,7 +330,7 @@ void IDeserializer.CompleteObject(Id id) continue; } - completed = Id.Null; + completed = default(SerializationRecordId); } if (_recordMap[completedId] is ClassRecord classRecord @@ -371,10 +362,10 @@ void IDeserializer.CompleteObject(Id id) Debug.Assert(_pendingUpdates is not null); - foreach (KeyValuePair> pair in _incompleteDependencies) + foreach (KeyValuePair> pair in _incompleteDependencies) { - int incompleteId = pair.Key; - HashSet dependencies = pair.Value; + SerializationRecordId incompleteId = pair.Key; + HashSet dependencies = pair.Value; if (!dependencies.Remove(completedId)) { @@ -384,7 +375,7 @@ void IDeserializer.CompleteObject(Id id) // Search for fixups that need to be applied for this dependency. int removals = _pendingUpdates.RemoveWhere((ValueUpdater updater) => { - if (updater.ValueId != completedId) + if (!updater.ValueId.Equals(completedId)) { return false; } diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/FieldValueUpdater.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/FieldValueUpdater.cs index 646cbed28345c..0ec934b919c86 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/FieldValueUpdater.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/FieldValueUpdater.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Formats.Nrbf; using System.Reflection; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -10,12 +11,12 @@ internal sealed class FieldValueUpdater : ValueUpdater { private readonly FieldInfo _field; - internal FieldValueUpdater(int objectId, int valueId, FieldInfo field) : base(objectId, valueId) + internal FieldValueUpdater(SerializationRecordId objectId, SerializationRecordId valueId, FieldInfo field) : base(objectId, valueId) { _field = field; } - internal override void UpdateValue(IDictionary objects) + internal override void UpdateValue(IDictionary objects) { object newValue = objects[ValueId]; _field.SetValue(objects[ObjectId], newValue); diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/IDeserializer.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/IDeserializer.cs index 166e17d192784..174c9f803ed39 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/IDeserializer.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/IDeserializer.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Formats.Nrbf; using System.Runtime.Serialization; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -30,7 +31,7 @@ internal interface IDeserializer /// has not yet been applied. /// /// - HashSet IncompleteObjects { get; } + HashSet IncompleteObjects { get; } /// /// The set of objects that have been deserialized, indexed by record id. @@ -42,7 +43,7 @@ internal interface IDeserializer /// be ready if there are cycles in the object graph). /// /// - IDictionary DeserializedObjects { get; } + IDictionary DeserializedObjects { get; } /// /// Resolver for types. @@ -62,7 +63,7 @@ internal interface IDeserializer /// /// Mark the object id as complete. This will check dependencies and resolve relevant s. /// - void CompleteObject(Id id); + void CompleteObject(SerializationRecordId id); /// /// Check for a surrogate for the given type. If none exists, returns . diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ObjectRecordDeserializer.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ObjectRecordDeserializer.cs index 9351e1718b635..e32c713bed218 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ObjectRecordDeserializer.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ObjectRecordDeserializer.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -31,40 +31,40 @@ private protected ObjectRecordDeserializer(SerializationRecord objectRecord, IDe /// /// Continue parsing. /// - /// The id that is necessary to complete parsing or if complete. - internal abstract Id Continue(); + /// The id that is necessary to complete parsing or default value if complete. + internal abstract SerializationRecordId Continue(); /// /// Gets the actual object for a member value primitive or record. Returns if /// the object record has not been encountered yet. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private protected (object? value, Id id) UnwrapMemberValue(object? memberValue) + private protected (object? value, SerializationRecordId id) UnwrapMemberValue(object? memberValue) { - if (memberValue is null) // PayloadReader does not return NullRecord, just null + if (memberValue is null) // NrbfDecoder does not return NullRecord, just null { - return (null, Id.Null); + return (null, default(SerializationRecordId)); } else if (memberValue is not SerializationRecord serializationRecord) // a primitive value { - return (memberValue, Id.Null); + return (memberValue, default(SerializationRecordId)); } - else if (serializationRecord.RecordType is RecordType.BinaryObjectString) + else if (serializationRecord.RecordType is SerializationRecordType.BinaryObjectString) { PrimitiveTypeRecord stringRecord = (PrimitiveTypeRecord)serializationRecord; - return (stringRecord.Value, stringRecord.ObjectId); + return (stringRecord.Value, stringRecord.Id); } - else if (serializationRecord.RecordType is RecordType.MemberPrimitiveTyped) + else if (serializationRecord.RecordType is SerializationRecordType.MemberPrimitiveTyped) { - return (serializationRecord.GetMemberPrimitiveTypedValue(), Id.Null); + return (((PrimitiveTypeRecord)serializationRecord).Value, default(SerializationRecordId)); } else { // ClassRecords & ArrayRecords - return TryGetObject(serializationRecord.ObjectId); + return TryGetObject(serializationRecord.Id); } - (object? value, Id id) TryGetObject(Id id) + (object? value, SerializationRecordId id) TryGetObject(SerializationRecordId id) { if (!Deserializer.DeserializedObjects.TryGetValue(id, out object? value)) { @@ -84,9 +84,9 @@ private protected virtual void ValidateNewMemberObjectValue(object value) { } /// /// Returns if the given record's value needs an updater applied. /// - private protected bool DoesValueNeedUpdated(object value, Id valueRecord) => // Null Id is a primitive value. - !valueRecord.IsNull + private protected bool DoesValueNeedUpdated(object value, SerializationRecordId valueRecord) => + !valueRecord.Equals(default(SerializationRecordId)) // IObjectReference is going to have its object replaced. && (value is IObjectReference // Value types that aren't "complete" need to be reapplied. diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/PendingSerializationInfo.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/PendingSerializationInfo.cs index 4031835e2ca81..7ea1452199553 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/PendingSerializationInfo.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/PendingSerializationInfo.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Formats.Nrbf; using System.Reflection; using System.Runtime.Serialization; @@ -12,12 +13,12 @@ namespace System.Resources.Extensions.BinaryFormat.Deserializer; internal sealed class PendingSerializationInfo { - internal int ObjectId { get; } + internal SerializationRecordId ObjectId { get; } private readonly ISerializationSurrogate? _surrogate; private readonly SerializationInfo _info; internal PendingSerializationInfo( - int objectId, + SerializationRecordId objectId, SerializationInfo info, ISerializationSurrogate? surrogate) { @@ -27,7 +28,7 @@ internal PendingSerializationInfo( } [RequiresUnreferencedCode("We can't guarantee that the ctor will be present, as the type is not known up-front.")] - internal void Populate(IDictionary objects, StreamingContext context) + internal void Populate(IDictionary objects, StreamingContext context) { object @object = objects[ObjectId]; Type type = @object.GetType(); diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/SerializationInfoValueUpdater.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/SerializationInfoValueUpdater.cs index fe76daf424491..7d0147f912617 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/SerializationInfoValueUpdater.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/SerializationInfoValueUpdater.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Formats.Nrbf; using System.Runtime.Serialization; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -11,13 +12,13 @@ internal sealed class SerializationInfoValueUpdater : ValueUpdater private readonly SerializationInfo _info; private readonly string _name; - internal SerializationInfoValueUpdater(int objectId, int valueId, SerializationInfo info, string name) : base(objectId, valueId) + internal SerializationInfoValueUpdater(SerializationRecordId objectId, SerializationRecordId valueId, SerializationInfo info, string name) : base(objectId, valueId) { _info = info; _name = name; } - internal override void UpdateValue(IDictionary objects) + internal override void UpdateValue(IDictionary objects) { object newValue = objects[ValueId]; _info.UpdateValue(_name, newValue, newValue.GetType()); diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ValueUpdater.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ValueUpdater.cs index 973392c2020c3..2f45572686b14 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ValueUpdater.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Deserializer/ValueUpdater.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Formats.Nrbf; namespace System.Resources.Extensions.BinaryFormat.Deserializer; @@ -10,18 +11,18 @@ internal abstract class ValueUpdater /// /// The value id that needs to be reapplied. /// - internal int ValueId { get; } + internal SerializationRecordId ValueId { get; } /// /// The object id that is dependent on . /// - internal int ObjectId { get; } + internal SerializationRecordId ObjectId { get; } - private protected ValueUpdater(int objectId, int valueId) + private protected ValueUpdater(SerializationRecordId objectId, SerializationRecordId valueId) { ObjectId = objectId; ValueId = valueId; } - internal abstract void UpdateValue(IDictionary objects); + internal abstract void UpdateValue(IDictionary objects); } diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Id.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Id.cs deleted file mode 100644 index e64031f4646f0..0000000000000 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/BinaryFormat/Id.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.Diagnostics.CodeAnalysis; - -namespace System.Resources.Extensions; - -/// -/// Identifier struct. -/// -internal readonly struct Id : IEquatable -{ - private readonly int _id; - private readonly bool _isNull = true; - - // It is possible that the id may be negative with value types. See BinaryObjectWriter.InternalGetId. - private Id(int id) - { - _id = id; - _isNull = false; - } - - private Id(bool isNull) - { - _id = 0; - _isNull = isNull; - } - - public static Id Null => new(isNull: true); - public bool IsNull => _isNull; - - public static implicit operator int(Id value) => value._isNull ? throw new InvalidOperationException() : value._id; - public static implicit operator Id(int value) => new(value); - - public override bool Equals([NotNullWhen(true)] object? obj) - => (obj is Id id && Equals(id)) || (obj is int value && value == _id); - - public bool Equals(Id other) => _isNull == other._isNull && _id == other._id; - - public override readonly int GetHashCode() => _id.GetHashCode(); - public override readonly string ToString() => _isNull ? "" : _id.ToString(); - - public static bool operator ==(Id left, Id right) => left.Equals(right); - - public static bool operator !=(Id left, Id right) => !(left == right); -} diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/Common/CorruptedTests.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/Common/CorruptedTests.cs index 9ea3839e37472..ebd655660061f 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/Common/CorruptedTests.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/Common/CorruptedTests.cs @@ -4,7 +4,7 @@ using System.Resources.Extensions.Tests.Common.TestTypes; using System.Resources.Extensions.Tests.FormattedObject; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; using System.Text; namespace System.Resources.Extensions.Tests.Common; @@ -114,7 +114,7 @@ public virtual void ValueTypeReferencesSelf5() WriteMemberReference(writer, NextClassId); WriteMemberReference(writer, NextClassId); // ClassWithId - writer.Write((byte)RecordType.ClassWithId); + writer.Write((byte)SerializationRecordType.ClassWithId); writer.Write(NextClassId); // id writer.Write(ClassId); // id of the class that provides metadata WriteMemberReference(writer, ClassId); diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/Common/SerializationTest.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/Common/SerializationTest.cs index 3a7b404605883..d893fca6899bf 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/Common/SerializationTest.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/Common/SerializationTest.cs @@ -3,7 +3,7 @@ using System.Buffers; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; using System.Runtime.Serialization.Formatters; namespace System.Resources.Extensions.Tests.Common; @@ -89,7 +89,7 @@ private protected static SurrogateSelector CreateSurrogateSelector( protected static void WriteSerializedStreamHeader(BinaryWriter writer, int major = 1, int minor = 0) { - writer.Write((byte)RecordType.SerializedStreamHeader); + writer.Write((byte)SerializationRecordType.SerializedStreamHeader); writer.Write(1); // root ID writer.Write(1); // header ID writer.Write(major); // major version @@ -98,14 +98,14 @@ protected static void WriteSerializedStreamHeader(BinaryWriter writer, int major protected static void WriteBinaryLibrary(BinaryWriter writer, int objectId, string libraryName) { - writer.Write((byte)RecordType.BinaryLibrary); + writer.Write((byte)SerializationRecordType.BinaryLibrary); writer.Write(objectId); writer.Write(libraryName); } protected static void WriteClassInfo(BinaryWriter writer, int objectId, string typeName, params string[] memberNames) { - writer.Write((byte)RecordType.ClassWithMembersAndTypes); + writer.Write((byte)SerializationRecordType.ClassWithMembersAndTypes); writer.Write(objectId); writer.Write(typeName); writer.Write(memberNames.Length); @@ -125,12 +125,12 @@ protected static void WriteClassFieldInfo(BinaryWriter writer, string typeName, protected static void WriteMemberReference(BinaryWriter writer, int referencedObjectId) { - writer.Write((byte)RecordType.MemberReference); + writer.Write((byte)SerializationRecordType.MemberReference); writer.Write(referencedObjectId); } protected static void WriteMessageEnd(BinaryWriter writer) { - writer.Write((byte)RecordType.MessageEnd); + writer.Write((byte)SerializationRecordType.MessageEnd); } } diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ArrayTests.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ArrayTests.cs index 9b01702ce14b3..3dfc79ac55b8b 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ArrayTests.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ArrayTests.cs @@ -4,7 +4,7 @@ using System.Drawing; using System.Linq; using System.Resources.Extensions.BinaryFormat; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.Tests.FormattedObject; @@ -21,7 +21,7 @@ public override void Roundtrip_ArrayContainingArrayAtNonZeroLowerBound() public void StringArray_Parse(string?[] strings) { BinaryFormattedObject format = new(Serialize(strings)); - var arrayRecord = (ArrayRecord)format.RootRecord; + var arrayRecord = (SZArrayRecord)format.RootRecord; arrayRecord.GetArray().Should().BeEquivalentTo(strings); } diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/BinaryFormattedObjectTests.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/BinaryFormattedObjectTests.cs index 34f5261cfec11..072e10f98dac3 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/BinaryFormattedObjectTests.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/BinaryFormattedObjectTests.cs @@ -4,7 +4,7 @@ using System.Collections; using System.Linq; using System.Resources.Extensions.BinaryFormat; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; using System.Resources.Extensions.Tests.Common; namespace System.Resources.Extensions.Tests.FormattedObject; @@ -15,7 +15,8 @@ public class BinaryFormattedObjectTests : SerializationTest stringRecord = (PrimitiveTypeRecord)format[1]; - stringRecord.ObjectId.Should().Be(1); + PrimitiveTypeRecord stringRecord = (PrimitiveTypeRecord)format[format.RootRecord.Id]; stringRecord.Value.Should().Be(testString); } @@ -35,21 +35,18 @@ public void ReadEmptyHashTable() { BinaryFormattedObject format = new(Serialize(new Hashtable())); - ClassRecord systemClass = (ClassRecord)format[1]; + ClassRecord systemClass = (ClassRecord)format[format.RootRecord.Id]; VerifyHashTable(systemClass, expectedVersion: 0, expectedHashSize: 3); - ArrayRecord keys = (ArrayRecord)systemClass.GetSerializationRecord("Keys")!; - keys.ObjectId.Should().Be(2); + SZArrayRecord keys = (SZArrayRecord)systemClass.GetSerializationRecord("Keys")!; keys.Length.Should().Be(0); - ArrayRecord values = (ArrayRecord)systemClass.GetSerializationRecord("Values")!; - values.ObjectId.Should().Be(3); + SZArrayRecord values = (SZArrayRecord)systemClass.GetSerializationRecord("Values")!; values.Length.Should().Be(0); } private static void VerifyHashTable(ClassRecord systemClass, int expectedVersion, int expectedHashSize) { - systemClass.RecordType.Should().Be(RecordType.SystemClassWithMembersAndTypes); - systemClass.ObjectId.Should().Be(1); + systemClass.RecordType.Should().Be(SerializationRecordType.SystemClassWithMembersAndTypes); systemClass.TypeName.FullName.Should().Be("System.Collections.Hashtable"); systemClass.MemberNames.Should().BeEquivalentTo( [ @@ -77,15 +74,13 @@ public void ReadHashTableWithStringPair() { "This", "That" } })); - ClassRecord systemClass = (ClassRecord)format[1]; + ClassRecord systemClass = (ClassRecord)format[format.RootRecord.Id]; VerifyHashTable(systemClass, expectedVersion: 1, expectedHashSize: 3); - ArrayRecord keys = (ArrayRecord)format[2]; - keys.ObjectId.Should().Be(2); + SZArrayRecord keys = (SZArrayRecord)format[systemClass.GetArrayRecord("Keys").Id]; keys.Length.Should().Be(1); keys.GetArray().Single().Should().Be("This"); - ArrayRecord values = (ArrayRecord)format[3]; - values.ObjectId.Should().Be(3); + SZArrayRecord values = (SZArrayRecord)format[systemClass.GetArrayRecord("Values").Id]; values.Length.Should().Be(1); values.GetArray().Single().Should().Be("That"); } @@ -100,13 +95,12 @@ public void ReadHashTableWithRepeatedStrings() { "That", "This" } })); - ClassRecord systemClass = (ClassRecord)format[1]; + ClassRecord systemClass = (ClassRecord)format[format.RootRecord.Id]; VerifyHashTable(systemClass, expectedVersion: 4, expectedHashSize: 7); // The collections themselves get ids first before the strings do. // Everything in the second keys is a string reference. - ArrayRecord array = (ArrayRecord)systemClass.GetSerializationRecord("Keys")!; - array.ObjectId.Should().Be(2); + SZArrayRecord array = (SZArrayRecord)systemClass.GetSerializationRecord("Keys")!; array.GetArray().Should().BeEquivalentTo(["This", "TheOther", "That"]); } @@ -120,17 +114,15 @@ public void ReadHashTableWithNullValues() { "Meeza", null } })); - ClassRecord systemClass = (ClassRecord)format[1]; + ClassRecord systemClass = (ClassRecord)format[format.RootRecord.Id]; VerifyHashTable(systemClass, expectedVersion: 4, expectedHashSize: 7); // The collections themselves get ids first before the strings do. // Everything in the second keys is a string reference. - ArrayRecord keys = (ArrayRecord)systemClass.GetSerializationRecord("Keys")!; - keys.ObjectId.Should().Be(2); + SZArrayRecord keys = (SZArrayRecord)systemClass.GetSerializationRecord("Keys")!; keys.GetArray().Should().BeEquivalentTo(new object[] { "Yowza", "Youza", "Meeza" }); - ArrayRecord values = (ArrayRecord)systemClass.GetSerializationRecord("Values")!; - values.ObjectId.Should().Be(3); + SZArrayRecord values = (SZArrayRecord)systemClass.GetSerializationRecord("Values")!; values.GetArray().Should().BeEquivalentTo(new object?[] { null, null, null }); } @@ -138,7 +130,7 @@ public void ReadHashTableWithNullValues() public void ReadObject() { BinaryFormattedObject format = new(Serialize(new object())); - format[1].RecordType.Should().Be(RecordType.SystemClassWithMembersAndTypes); + format[format.RootRecord.Id].RecordType.Should().Be(SerializationRecordType.SystemClassWithMembersAndTypes); } [Fact] @@ -146,7 +138,7 @@ public void ReadStruct() { ValueTuple tuple = new(355); BinaryFormattedObject format = new(Serialize(tuple)); - format[1].RecordType.Should().Be(RecordType.SystemClassWithMembersAndTypes); + format[format.RootRecord.Id].RecordType.Should().Be(SerializationRecordType.SystemClassWithMembersAndTypes); } [Fact] @@ -155,8 +147,7 @@ public void ReadSimpleSerializableObject() BinaryFormattedObject format = new(Serialize(new SimpleSerializableObject())); ClassRecord @class = (ClassRecord)format.RootRecord; - @class.RecordType.Should().Be(RecordType.ClassWithMembersAndTypes); - @class.ObjectId.Should().Be(1); + @class.RecordType.Should().Be(SerializationRecordType.ClassWithMembersAndTypes); @class.TypeName.FullName.Should().Be(typeof(SimpleSerializableObject).FullName); @class.TypeName.AssemblyName!.FullName.Should().Be(typeof(SimpleSerializableObject).Assembly.FullName); @class.MemberNames.Should().BeEmpty(); @@ -168,8 +159,7 @@ public void ReadNestedSerializableObject() BinaryFormattedObject format = new(Serialize(new NestedSerializableObject())); ClassRecord @class = (ClassRecord)format.RootRecord; - @class.RecordType.Should().Be(RecordType.ClassWithMembersAndTypes); - @class.ObjectId.Should().Be(1); + @class.RecordType.Should().Be(SerializationRecordType.ClassWithMembersAndTypes); @class.TypeName.FullName.Should().Be(typeof(NestedSerializableObject).FullName); @class.TypeName.AssemblyName!.FullName.Should().Be(typeof(NestedSerializableObject).Assembly.FullName); @class.MemberNames.Should().BeEquivalentTo(["_object", "_meaning"]); @@ -183,8 +173,7 @@ public void ReadTwoIntObject() BinaryFormattedObject format = new(Serialize(new TwoIntSerializableObject())); ClassRecord @class = (ClassRecord)format.RootRecord; - @class.RecordType.Should().Be(RecordType.ClassWithMembersAndTypes); - @class.ObjectId.Should().Be(1); + @class.RecordType.Should().Be(SerializationRecordType.ClassWithMembersAndTypes); @class.TypeName.FullName.Should().Be(typeof(TwoIntSerializableObject).FullName); @class.TypeName.AssemblyName!.FullName.Should().Be(typeof(TwoIntSerializableObject).Assembly.FullName); @class.MemberNames.Should().BeEquivalentTo(["_value", "_meaning"]); @@ -196,10 +185,11 @@ public void ReadTwoIntObject() public void ReadRepeatedNestedObject() { BinaryFormattedObject format = new(Serialize(new RepeatedNestedSerializableObject())); - ClassRecord firstClass = (ClassRecord)format[3]; - firstClass.RecordType.Should().Be(RecordType.ClassWithMembersAndTypes); - ClassRecord classWithId = (ClassRecord)format[4]; - classWithId.RecordType.Should().Be(RecordType.ClassWithId); + ClassRecord classRecord = (ClassRecord)format.RootRecord; + ClassRecord firstClass = classRecord.GetClassRecord("_first"); + firstClass.RecordType.Should().Be(SerializationRecordType.ClassWithMembersAndTypes); + ClassRecord classWithId = classRecord.GetClassRecord("_second"); + classWithId.RecordType.Should().Be(SerializationRecordType.ClassWithId); classWithId.GetRawValue("_value").Should().Be(1970); classWithId.GetInt32("_meaning").Should().Be(42); } @@ -211,7 +201,7 @@ public void ReadPrimitiveArray() BinaryFormattedObject format = new(Serialize(input)); - ArrayRecord array = (ArrayRecord)format[1]; + SZArrayRecord array = (SZArrayRecord)format[format.RootRecord.Id]; array.Length.Should().Be(4); array.GetArray().Should().BeEquivalentTo(input); } @@ -223,8 +213,7 @@ public void ReadStringArray() BinaryFormattedObject format = new(Serialize(input)); - ArrayRecord array = (ArrayRecord)format[1]; - array.ObjectId.Should().Be(1); + SZArrayRecord array = (SZArrayRecord)format[format.RootRecord.Id]; array.Length.Should().Be(3); array.GetArray().Should().BeEquivalentTo(input); format.RecordMap.Count.Should().Be(4); @@ -237,8 +226,7 @@ public void ReadStringArrayWithNulls() BinaryFormattedObject format = new(Serialize(input)); - ArrayRecord array = (ArrayRecord)format[1]; - array.ObjectId.Should().Be(1); + SZArrayRecord array = (SZArrayRecord)format[format.RootRecord.Id]; array.Length.Should().Be(6); array.GetArray().Should().BeEquivalentTo(input); } @@ -250,8 +238,7 @@ public void ReadDuplicatedStringArray() BinaryFormattedObject format = new(Serialize(input)); - ArrayRecord array = (ArrayRecord)format[1]; - array.ObjectId.Should().Be(1); + SZArrayRecord array = (SZArrayRecord)format[format.RootRecord.Id]; array.Length.Should().Be(3); array.GetArray().Should().BeEquivalentTo(input); format.RecordMap.Count.Should().Be(3); @@ -262,7 +249,7 @@ public void ReadObjectWithNullableObjects() { BinaryFormattedObject format = new(Serialize(new ObjectWithNullableObjects())); ClassRecord classRecord = (ClassRecord)format.RootRecord; - classRecord.RecordType.Should().Be(RecordType.ClassWithMembersAndTypes); + classRecord.RecordType.Should().Be(SerializationRecordType.ClassWithMembersAndTypes); classRecord.TypeName.AssemblyName!.FullName.Should().Be(typeof(ObjectWithNullableObjects).Assembly.FullName); } @@ -271,7 +258,7 @@ public void ReadNestedObjectWithNullableObjects() { BinaryFormattedObject format = new(Serialize(new NestedObjectWithNullableObjects())); ClassRecord classRecord = (ClassRecord)format.RootRecord; - classRecord.RecordType.Should().Be(RecordType.ClassWithMembersAndTypes); + classRecord.RecordType.Should().Be(SerializationRecordType.ClassWithMembersAndTypes); classRecord.TypeName.AssemblyName!.FullName.Should().Be(typeof(NestedObjectWithNullableObjects).Assembly.FullName); } diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ExceptionTests.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ExceptionTests.cs index 2408651ff5dc6..6ba0e1bbc5b3d 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ExceptionTests.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ExceptionTests.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Resources.Extensions.BinaryFormat; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; using System.Resources.Extensions.Tests.Common; namespace System.Resources.Extensions.Tests.FormattedObject; diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/HashTableTests.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/HashTableTests.cs index ca50d84befdae..63c63ca66fe45 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/HashTableTests.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/HashTableTests.cs @@ -5,7 +5,7 @@ using System.Drawing; using System.Resources.Extensions.BinaryFormat; using System.Runtime.Serialization; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; using System.Resources.Extensions.Tests.Common; namespace System.Resources.Extensions.Tests.FormattedObject; @@ -68,12 +68,12 @@ public void HashTable_CustomComparer() BinaryFormattedObject format = new(Serialize(hashtable)); ClassRecord systemClass = (ClassRecord)format.RootRecord; - systemClass.RecordType.Should().Be(RecordType.SystemClassWithMembersAndTypes); + systemClass.RecordType.Should().Be(SerializationRecordType.SystemClassWithMembersAndTypes); systemClass.TypeName.FullName.Should().Be("System.Collections.Hashtable"); systemClass.GetSerializationRecord("Comparer")!.Should().BeAssignableTo().Which.TypeName.FullName.Should().Be("System.OrdinalComparer"); systemClass.GetSerializationRecord("HashCodeProvider")!.Should().BeAssignableTo().Which.TypeName.FullName.Should().Be("System.Resources.Extensions.Tests.FormattedObject.HashtableTests+CustomHashCodeProvider"); - systemClass.GetSerializationRecord("Keys")!.Should().BeAssignableTo>(); - systemClass.GetSerializationRecord("Values")!.Should().BeAssignableTo>(); + systemClass.GetSerializationRecord("Keys")!.Should().BeAssignableTo>(); + systemClass.GetSerializationRecord("Values")!.Should().BeAssignableTo>(); } [Serializable] diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ListTests.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ListTests.cs index 0d47d090c3c21..fa5a5f9ce3a5e 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ListTests.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/ListTests.cs @@ -5,7 +5,7 @@ using System.Drawing; using System.Linq; using System.Resources.Extensions.BinaryFormat; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; using System.Resources.Extensions.Tests.Common; namespace System.Resources.Extensions.Tests.FormattedObject; @@ -17,18 +17,18 @@ public void BinaryFormattedObject_ParseEmptyArrayList() { BinaryFormattedObject format = new(Serialize(new ArrayList())); - VerifyArrayList((ClassRecord)format[1]); + VerifyArrayList((ClassRecord)format[format.RootRecord.Id]); - format[2].Should().BeAssignableTo>(); + format[((ClassRecord)format.RootRecord).GetArrayRecord("_items").Id].Should().BeAssignableTo>(); } private static void VerifyArrayList(ClassRecord systemClass) { - systemClass.RecordType.Should().Be(RecordType.SystemClassWithMembersAndTypes); + systemClass.RecordType.Should().Be(SerializationRecordType.SystemClassWithMembersAndTypes); systemClass.TypeName.FullName.Should().Be(typeof(ArrayList).FullName); systemClass.MemberNames.Should().BeEquivalentTo(["_items", "_size", "_version"]); - systemClass.GetSerializationRecord("_items").Should().BeAssignableTo>(); + systemClass.GetSerializationRecord("_items").Should().BeAssignableTo>(); } [Theory] @@ -40,10 +40,10 @@ public void BinaryFormattedObject_ParsePrimitivesArrayList(object value) value })); - ClassRecord listRecord = (ClassRecord)format[1]; + ClassRecord listRecord = (ClassRecord)format[format.RootRecord.Id]; VerifyArrayList(listRecord); - ArrayRecord array = (ArrayRecord)format[2]; + SZArrayRecord array = (SZArrayRecord)format[listRecord.GetArrayRecord("_items").Id]; array.GetArray().Take(listRecord.GetInt32("_size")).Should().BeEquivalentTo(new[] { value }); } @@ -56,10 +56,10 @@ public void BinaryFormattedObject_ParseStringArrayList() "JarJar" })); - ClassRecord listRecord = (ClassRecord)format[1]; + ClassRecord listRecord = (ClassRecord)format[format.RootRecord.Id]; VerifyArrayList(listRecord); - ArrayRecord array = (ArrayRecord)format[2]; + SZArrayRecord array = (SZArrayRecord)format[listRecord.GetArrayRecord("_items").Id]; array.GetArray().Take(listRecord.GetInt32("_size")).ToArray().Should().BeEquivalentTo(new object[] { "JarJar" }); } @@ -125,8 +125,8 @@ public void BinaryFormattedObject_ParseStringArrayList() public void BinaryFormattedObject_ParseEmptyIntList() { BinaryFormattedObject format = new(Serialize(new List())); - ClassRecord classInfo = (ClassRecord)format[1]; - classInfo.RecordType.Should().Be(RecordType.SystemClassWithMembersAndTypes); + ClassRecord classInfo = (ClassRecord)format[format.RootRecord.Id]; + classInfo.RecordType.Should().Be(SerializationRecordType.SystemClassWithMembersAndTypes); // Note that T types are serialized as the mscorlib type. classInfo.TypeName.FullName.Should().Be( @@ -143,11 +143,11 @@ public void BinaryFormattedObject_ParseEmptyIntList() "_version" ]); - classInfo.GetSerializationRecord("_items").Should().BeAssignableTo>(); + classInfo.GetSerializationRecord("_items").Should().BeAssignableTo>(); classInfo.GetInt32("_size").Should().Be(0); classInfo.GetInt32("_version").Should().Be(0); - ArrayRecord array = (ArrayRecord)format[2]; + SZArrayRecord array = (SZArrayRecord)format[classInfo.GetArrayRecord("_items").Id]; array.Length.Should().Be(0); } @@ -156,12 +156,12 @@ public void BinaryFormattedObject_ParseEmptyStringList() { BinaryFormattedObject format = new(Serialize(new List())); - ClassRecord classInfo = (ClassRecord)format[1]; - classInfo.RecordType.Should().Be(RecordType.SystemClassWithMembersAndTypes); + ClassRecord classInfo = (ClassRecord)format[format.RootRecord.Id]; + classInfo.RecordType.Should().Be(SerializationRecordType.SystemClassWithMembersAndTypes); classInfo.TypeName.FullName.Should().StartWith("System.Collections.Generic.List`1[[System.String,"); - classInfo.GetSerializationRecord("_items").Should().BeAssignableTo>(); + classInfo.GetSerializationRecord("_items").Should().BeAssignableTo>(); - ArrayRecord array = (ArrayRecord)format[2]; + SZArrayRecord array = (SZArrayRecord)format[classInfo.GetArrayRecord("_items").Id]; array.Length.Should().Be(0); } diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/PrimitiveTypeTests.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/PrimitiveTypeTests.cs index 77868fb2d6201..e8071d2905c52 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/PrimitiveTypeTests.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/PrimitiveTypeTests.cs @@ -1,11 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; using System.Runtime.Serialization.Formatters.Binary; using System.Resources.Extensions.BinaryFormat; using System.Resources.Extensions.Tests.Common; -using PrimitiveType = System.Runtime.Serialization.BinaryFormat.PrimitiveType; +using PrimitiveType = System.Formats.Nrbf.PrimitiveType; namespace System.Resources.Extensions.Tests.FormattedObject; @@ -70,7 +70,7 @@ public class PrimitiveTypeTests : SerializationTest public void PrimitiveTypeMemberName(object value) { BinaryFormattedObject format = new(Serialize(value)); - VerifyNonGeneric(value, format[1]); + VerifyNonGeneric(value, format[format.RootRecord.Id]); } [Theory] @@ -79,7 +79,7 @@ public void PrimitiveTypeMemberName(object value) public void BinaryFormattedObject_ReadPrimitive(object value) { BinaryFormattedObject formattedObject = new(Serialize(value)); - formattedObject.RootRecord.GetMemberPrimitiveTypedValue().Should().Be(value); + ((PrimitiveTypeRecord)formattedObject.RootRecord).Value.Should().Be(value); } public static TheoryData Primitive_Data => new() @@ -117,6 +117,7 @@ private static void VerifyNonGeneric(object value, SerializationRecord record) private static void VerifyGeneric(T value, SerializationRecord record) where T : unmanaged { + record.As().Value.Should().Be(value); record.As>().Value.Should().Be(value); } } diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/SystemDrawingTests.cs b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/SystemDrawingTests.cs index ce96ceef12ea8..bb26d521a9e3e 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/SystemDrawingTests.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/FormattedObject/SystemDrawingTests.cs @@ -3,7 +3,7 @@ using System.Drawing; using System.Resources.Extensions.BinaryFormat; -using System.Runtime.Serialization.BinaryFormat; +using System.Formats.Nrbf; namespace System.Resources.Extensions.Tests.FormattedObject; @@ -16,8 +16,9 @@ public void PointF_Parse() BinaryFormattedObject format = new(Serialize(input)); ClassRecord classInfo = (ClassRecord)format.RootRecord; - classInfo.RecordType.Should().Be(RecordType.ClassWithMembersAndTypes); - classInfo.ObjectId.Should().Be(1); + classInfo.RecordType.Should().Be(SerializationRecordType.ClassWithMembersAndTypes); + classInfo.Id.Should().NotBe(default); + format[format.RootRecord.Id].Should().Be(classInfo); classInfo.TypeName.FullName.Should().Be("System.Drawing.PointF"); classInfo.TypeName.AssemblyName!.FullName.Should().Be("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); classInfo.MemberNames.Should().BeEquivalentTo(["x", "y"]); @@ -32,8 +33,9 @@ public void RectangleF_Parse() BinaryFormattedObject format = new(Serialize(input)); ClassRecord classInfo = (ClassRecord)format.RootRecord; - classInfo.RecordType.Should().Be(RecordType.ClassWithMembersAndTypes); - classInfo.ObjectId.Should().Be(1); + classInfo.RecordType.Should().Be(SerializationRecordType.ClassWithMembersAndTypes); + classInfo.Id.Should().NotBe(default); + format[format.RootRecord.Id].Should().Be(classInfo); classInfo.TypeName.FullName.Should().Be("System.Drawing.RectangleF"); classInfo.MemberNames.Should().BeEquivalentTo(["x", "y", "width", "height"]); classInfo.GetSingle("x").Should().Be(input.X); diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/System.Resources.Extensions.BinaryFormat.Tests.csproj b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/System.Resources.Extensions.BinaryFormat.Tests.csproj index 3e3cada29f4c8..9eb577c43c89c 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/System.Resources.Extensions.BinaryFormat.Tests.csproj +++ b/src/libraries/System.Resources.Extensions/tests/BinaryFormatTests/System.Resources.Extensions.BinaryFormat.Tests.csproj @@ -39,17 +39,18 @@ - - + - - - - + + + + + + diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/AllowedRecordType.cs b/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/AllowedRecordType.cs deleted file mode 100644 index df80ce32ee99d..0000000000000 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/AllowedRecordType.cs +++ /dev/null @@ -1,38 +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.Runtime.Serialization.BinaryFormat; - -[Flags] -internal enum AllowedRecordTypes : uint -{ - None = 0, - SerializedStreamHeader = 1 << RecordType.SerializedStreamHeader, - ClassWithId = 1 << RecordType.ClassWithId, - SystemClassWithMembersAndTypes = 1 << RecordType.SystemClassWithMembersAndTypes, - ClassWithMembersAndTypes = 1 << RecordType.ClassWithMembersAndTypes, - BinaryObjectString = 1 << RecordType.BinaryObjectString, - BinaryArray = 1 << RecordType.BinaryArray, - MemberPrimitiveTyped = 1 << RecordType.MemberPrimitiveTyped, - MemberReference = 1 << RecordType.MemberReference, - ObjectNull = 1 << RecordType.ObjectNull, - MessageEnd = 1 << RecordType.MessageEnd, - BinaryLibrary = 1 << RecordType.BinaryLibrary, - ObjectNullMultiple256 = 1 << RecordType.ObjectNullMultiple256, - ObjectNullMultiple = 1 << RecordType.ObjectNullMultiple, - ArraySinglePrimitive = 1 << RecordType.ArraySinglePrimitive, - ArraySingleObject = 1 << RecordType.ArraySingleObject, - ArraySingleString = 1 << RecordType.ArraySingleString, - - Nulls = ObjectNull | ObjectNullMultiple256 | ObjectNullMultiple, - - /// - /// Any .NET object (a primitive, a reference type, a reference or single null). - /// - AnyObject = MemberPrimitiveTyped - | ArraySingleObject | ArraySinglePrimitive | ArraySingleString | BinaryArray - | ClassWithId | ClassWithMembersAndTypes | SystemClassWithMembersAndTypes - | BinaryObjectString - | MemberReference - | ObjectNull, -} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/NullsRecord.cs b/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/NullsRecord.cs deleted file mode 100644 index 14f6a6767d1d7..0000000000000 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/NullsRecord.cs +++ /dev/null @@ -1,11 +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.Runtime.Serialization.BinaryFormat; - -internal abstract class NullsRecord : SerializationRecord -{ - internal abstract int NullCount { get; } - - public override int ObjectId => NoId; -} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SerializationRecord.cs b/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SerializationRecord.cs deleted file mode 100644 index f5c8a5e4108e4..0000000000000 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/src/System/Runtime/Serialization/BinaryFormat/SerializationRecord.cs +++ /dev/null @@ -1,66 +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.Diagnostics; - -namespace System.Runtime.Serialization.BinaryFormat; - -/// -/// Abstract class that represents the serialization record. -/// -/// -/// -/// Every instance returned to the end user can be either , -/// a or an . -/// -/// -[DebuggerDisplay("{RecordType}, {ObjectId}")] -#if SYSTEM_RUNTIME_SERIALIZATION_BINARYFORMAT -public -#else -internal -#endif -abstract class SerializationRecord -{ - internal const int NoId = 0; - - internal SerializationRecord() // others can't derive from this type - { - } - - /// - /// Gets the type of the record. - /// - /// The type of the record. - public abstract RecordType RecordType { get; } - - /// - /// Gets the ID of the record. - /// - /// The ID of the record. - public abstract int ObjectId { get; } - - /// - /// Compares the type and assembly name read from the payload against the specified type. - /// - /// - /// This method takes type forwarding into account. - /// This method does NOT take into account member names or their types. - /// - /// The type to compare against. - /// if the serialized type and assembly name match provided type; otherwise, . - public virtual bool IsTypeNameMatching(Type type) => false; - - /// - /// Gets the primitive, string or null record value. - /// For reference records, it returns the referenced record. - /// For other records, it returns the records themselves. - /// - internal virtual object? GetValue() => this; - - internal virtual void HandleNextRecord(SerializationRecord nextRecord, NextInfo info) - => Debug.Fail($"HandleNextRecord should not have been called for '{GetType().Name}'"); - - internal virtual void HandleNextValue(object value, NextInfo info) - => Debug.Fail($"HandleNextValue should not have been called for '{GetType().Name}'"); -} diff --git a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/CustomOffsetArrays.cs b/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/CustomOffsetArrays.cs deleted file mode 100644 index aa3e07292c410..0000000000000 --- a/src/libraries/System.Runtime.Serialization.BinaryFormat/tests/CustomOffsetArrays.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Xunit; - -namespace System.Runtime.Serialization.BinaryFormat.Tests; - -public class CustomOffsetArrays : ReadTests -{ - [Fact] - public void CanReadSingleDimensionalArrayOfIntegersWithCustomOffset() - { - const int lowerBound = 1; - Array input = Array.CreateInstance(typeof(int), lengths: [3], lowerBounds: [lowerBound]); - for (int i = lowerBound; i < lowerBound + input.Length; i++) - { - input.SetValue(value: i, index: i); - } - - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); - - Assert.Equal(input, arrayRecord.GetArray(input.GetType())); - } - - [Fact] - public void CanReadRectangularArrayOfStringsWithCustomOffsets() - { - const int lowerBound = 10; - Array input = Array.CreateInstance(typeof(string), lengths: [7, 5], lowerBounds: [lowerBound, lowerBound]); - for (int i = lowerBound; i < lowerBound + input.GetLength(0); i++) - { - for (int j = lowerBound; j < lowerBound + input.GetLength(1); j++) - { - input.SetValue(value: $"{i}. {j}", index1: i, index2: j); - } - } - - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); - - Assert.Equal(input, arrayRecord.GetArray(input.GetType())); - } - - [Serializable] - public class ComplexType3D - { - public int I, J, K; - } - - [Fact] - public void CanReadRectangularArraysOfComplexTypes_3D() - { - const int lowerBoundI = 1, lowerBoundJ = 2, lowerBoundK = 2; - Array input = Array.CreateInstance(typeof(ComplexType3D), - lengths: [17, 5, 3], lowerBounds: [lowerBoundI, lowerBoundJ, lowerBoundK]); - - for (int i = 0; i < input.GetLength(0); i++) - { - for (int j = 0; j < input.GetLength(1); j++) - { - for (int k = 0; k < input.GetLength(2); k++) - { - input.SetValue( - new ComplexType3D() { I = i, J = j, K = k }, - i + lowerBoundI, j + lowerBoundJ, k + lowerBoundK); - } - } - } - - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); - - RectangularArraysTests.VerifyLength(input, arrayRecord); - Array output = arrayRecord.GetArray(input.GetType()); - - for (int i = 0; i < input.GetLength(0); i++) - { - for (int j = 0; j < input.GetLength(1); j++) - { - for (int k = 0; k < input.GetLength(2); k++) - { - ComplexType3D expected = (ComplexType3D)input.GetValue(i + lowerBoundI, j + lowerBoundJ, k + lowerBoundK)!; - ClassRecord got = (ClassRecord)output.GetValue(i + lowerBoundI, j + lowerBoundJ, k + lowerBoundK)!; - - Assert.Equal(expected.I, got.GetInt32(nameof(ComplexType3D.I))); - Assert.Equal(expected.J, got.GetInt32(nameof(ComplexType3D.J))); - Assert.Equal(expected.K, got.GetInt32(nameof(ComplexType3D.K))); - } - } - } - } - - [Fact] - [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Not supported, custom offsets will be soon removed.")] - public void JaggedCustomOffset() - { - Array input = Array.CreateInstance(typeof(uint[]), [5], [1]); - - ArrayRecord arrayRecord = (ArrayRecord)PayloadReader.Read(Serialize(input)); - - Array output = arrayRecord.GetArray(expectedArrayType: input.GetType()); - - Assert.Equal(input, output); - } -}