| File: System\Formats\Nrbf\ClassInfo.cs | Web Access |
| Project: src\runtime\src\libraries\System.Formats.Nrbf\src\System.Formats.Nrbf.csproj (System.Formats.Nrbf) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection.Metadata; using System.Formats.Nrbf.Utils; using System.Runtime.Serialization; namespace System.Formats.Nrbf; /// <summary> /// Class info that provides type and member names. /// </summary> /// <remarks> /// ClassInfo structures are described in <see href="https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/0a192be0-58a1-41d0-8a54-9c91db0ab7bf">[MS-NRBF] 2.3.1.1</see>. /// </remarks> [DebuggerDisplay("{TypeName}")] internal sealed class ClassInfo { private readonly string _rawName; private TypeName? _typeName; private ClassInfo(SerializationRecordId id, string rawName, Dictionary<string, int> memberNames) { Id = id; _rawName = rawName; MemberNames = memberNames; } internal SerializationRecordId Id { get; } internal TypeName TypeName { get { Debug.Assert(_typeName is not null); return _typeName; } } internal Dictionary<string, int> MemberNames { get; } internal static ClassInfo Decode(BinaryReader reader) { SerializationRecordId id = SerializationRecordId.Decode(reader); string typeName = reader.ReadString(); int memberCount = reader.ReadInt32(); // Use Dictionary instead of List so that searching for member IDs by name // is O(n) instead of O(m * n), where m = memberCount and n = memberNameLength, // in degenerate cases. Since memberCount may be hostile, don't allow it to be // used as the initial capacity in the collection instance. Dictionary<string, int> memberNames = new(StringComparer.Ordinal); for (int i = 0; i < memberCount; i++) { // The NRBF specification does not prohibit multiple members with the same names, // however it's impossible to get such output with BinaryFormatter, // so we prohibit that on purpose. string memberName = reader.ReadString(); if (!memberNames.TryAdd(memberName, i)) { ThrowHelper.ThrowDuplicateMemberName(); } } return new ClassInfo(id, typeName, memberNames); } internal void LoadTypeName(BinaryLibraryRecord libraryRecord, PayloadOptions payloadOptions) => _typeName = _rawName.ParseNonSystemClassRecordTypeName(libraryRecord, payloadOptions); internal void LoadTypeName(PayloadOptions payloadOptions) => _typeName = _rawName.ParseSystemRecordTypeName(payloadOptions); }