| File: System\ComponentModel\Design\DesigntimeLicenseContextSerializer.cs | Web Access |
| Project: src\runtime\src\libraries\System.ComponentModel.TypeConverter\src\System.ComponentModel.TypeConverter.csproj (System.ComponentModel.TypeConverter) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace System.ComponentModel.Design { /// <summary> /// Provides support for design-time license context serialization. /// </summary> public class DesigntimeLicenseContextSerializer { internal const byte BinaryWriterMagic = 255; [FeatureSwitchDefinition("System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization")] private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization { get; } = AppContext.TryGetSwitch("System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization", out bool isEnabled) ? isEnabled : false; // Not creatable. private DesigntimeLicenseContextSerializer() { } /// <summary> /// Serializes the licenses within the specified design-time license context /// using the specified key and output stream. /// </summary> public static void Serialize(Stream o, string cryptoKey, DesigntimeLicenseContext context) { if (EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization) { SerializeWithBinaryFormatter(o, cryptoKey, context); } else { using (BinaryWriter writer = new BinaryWriter(o, encoding: Text.Encoding.UTF8, leaveOpen: true)) { writer.Write(BinaryWriterMagic); // flag to identify BinaryWriter writer.Write(cryptoKey); writer.Write(context._savedLicenseKeys.Count); foreach (DictionaryEntry keyAndValue in context._savedLicenseKeys) { writer.Write(keyAndValue.Key.ToString()!); writer.Write(keyAndValue.Value!.ToString()!); } } } } private static void SerializeWithBinaryFormatter(Stream o, string cryptoKey, DesigntimeLicenseContext context) { #pragma warning disable SYSLIB0011 #pragma warning disable IL2026 // suppressed in ILLink.Suppressions.LibraryBuild.xml var formatter = new BinaryFormatter(); formatter.Serialize(o, new object[] { cryptoKey, context._savedLicenseKeys }); #pragma warning restore IL2026 #pragma warning restore SYSLIB0011 } private sealed class StreamWrapper : Stream { private readonly Stream _stream; private bool _readFirstByte; internal byte _firstByte; public StreamWrapper(Stream stream) { _stream = stream; _readFirstByte = false; _firstByte = 0; } public override bool CanRead => _stream.CanRead; public override bool CanSeek => _stream.CanSeek; public override bool CanWrite => _stream.CanWrite; public override long Length => _stream.Length; public override long Position { get => _stream.Position; set => _stream.Position = value; } public override void Flush() => _stream.Flush(); public override int Read(byte[] buffer, int offset, int count) => Read(new Span<byte>(buffer, offset, count)); public override int Read(Span<byte> buffer) { Debug.Assert(_stream.Position != 0, "Expected the first byte to be read first"); if (_stream.Position == 1) { Debug.Assert(_readFirstByte); // Add the first byte read by ReadByte into buffer here buffer[0] = _firstByte; return _stream.Read(buffer.Slice(1)) + 1; } return _stream.Read(buffer); } public override long Seek(long offset, SeekOrigin origin) => _stream.Seek(offset, origin); public override void SetLength(long value) => _stream.SetLength(value); public override void Write(byte[] buffer, int offset, int count) => _stream.Write(buffer, offset, count); public override int ReadByte() { byte read = (byte)_stream.ReadByte(); _firstByte = read; _readFirstByte = true; return read; } } /// <summary> /// During deserialization, the stream passed in may be binary formatted or may have used binary writer. This is a quick test to discern between them. /// </summary> private static bool StreamIsBinaryFormatted(StreamWrapper stream) { // For binary formatter, the first byte is the SerializationHeaderRecord and has a value 0 int firstByte = stream.ReadByte(); if (firstByte != 0) { return false; } return true; } private static void DeserializeUsingBinaryFormatter(StreamWrapper wrappedStream, string cryptoKey, RuntimeLicenseContext context) { if (EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization) { #pragma warning disable SYSLIB0011 var formatter = new BinaryFormatter(); #pragma warning disable IL3050 #pragma warning disable IL2026 // suppressed in ILLink.Suppressions.LibraryBuild.xml object obj = formatter.Deserialize(wrappedStream); #pragma warning restore IL2026 #pragma warning restore IL3050 #pragma warning restore SYSLIB0011 if (obj is object[] value) { if (value[0] is string && (string)value[0] == cryptoKey) { context._savedLicenseKeys = (Hashtable)value[1]; } } } else { throw new NotSupportedException(SR.BinaryFormatterMessage); } } internal static void Deserialize(Stream o, string cryptoKey, RuntimeLicenseContext context) { StreamWrapper wrappedStream = new StreamWrapper(o); if (StreamIsBinaryFormatted(wrappedStream)) { DeserializeUsingBinaryFormatter(wrappedStream, cryptoKey, context); } else { using (BinaryReader reader = new BinaryReader(wrappedStream, encoding: Text.Encoding.UTF8, leaveOpen: true)) { byte binaryWriterIdentifier = wrappedStream._firstByte; Debug.Assert(binaryWriterIdentifier == BinaryWriterMagic, $"Expected the first byte to be {BinaryWriterMagic}"); string streamCryptoKey = reader.ReadString(); int numEntries = reader.ReadInt32(); if (streamCryptoKey == cryptoKey) { context._savedLicenseKeys!.Clear(); for (int i = 0; i < numEntries; i++) { string key = reader.ReadString(); string value = reader.ReadString(); context._savedLicenseKeys.Add(key, value); } } } } } } }