| File: System\Formats\Cbor\Writer\CborWriter.Simple.cs | Web Access |
| Project: src\runtime\src\libraries\System.Formats.Cbor\src\System.Formats.Cbor.csproj (System.Formats.Cbor) |
// 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.CompilerServices; namespace System.Formats.Cbor { public partial class CborWriter { // CBOR RFC 8949 says: if NaN is an allowed value, and there is no intent to support NaN payloads or signaling NaNs, the protocol needs to pick a single representation, typically 0xf97e00. If that simple choice is not possible, specific attention will be needed for NaN handling. // In this implementation "that simple choice is not possible" for CTAP2 mode (RequiresPreservingFloatPrecision), in which "representations of any floating-point values are not changed". private const ushort PositiveQNaNBitsHalf = 0x7e00; // Implements major type 7 encoding per https://tools.ietf.org/html/rfc7049#section-2.1 /// <summary>Writes a single-precision floating point number (major type 7).</summary> /// <param name="value">The value to write.</param> /// <exception cref="InvalidOperationException"><para>Writing a new value exceeds the definite length of the parent data item.</para> /// <para>-or-</para> /// <para>The major type of the encoded value is not permitted in the parent data item.</para> /// <para>-or-</para> /// <para>The written data is not accepted under the current conformance mode.</para></exception> public void WriteSingle(float value) { if (!CborConformanceModeHelpers.RequiresPreservingFloatPrecision(ConformanceMode) && TryConvertSingleToHalf(value, out var half)) { WriteHalf(half); } else { WriteSingleCore(value); } } /// <summary>Writes a double-precision floating point number (major type 7).</summary> /// <param name="value">The value to write.</param> /// <exception cref="InvalidOperationException"><para>Writing a new value exceeds the definite length of the parent data item.</para> /// <para>-or-</para> /// <para>The major type of the encoded value is not permitted in the parent data item.</para> /// <para>-or-</para> /// <para>The written data is not accepted under the current conformance mode.</para></exception> public void WriteDouble(double value) { if (!CborConformanceModeHelpers.RequiresPreservingFloatPrecision(ConformanceMode) && TryConvertDoubleToSingle(value, out float single)) { if (TryConvertSingleToHalf(single, out var half)) { WriteHalf(half); } else { WriteSingleCore(single); } } else { WriteDoubleCore(value); } } private void WriteSingleCore(float value) { EnsureWriteCapacity(1 + sizeof(float)); WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional32BitData)); CborHelpers.WriteSingleBigEndian(_buffer.AsSpan(_offset), value); _offset += sizeof(float); AdvanceDataItemCounters(); } private void WriteDoubleCore(double value) { EnsureWriteCapacity(1 + sizeof(double)); WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional64BitData)); CborHelpers.WriteDoubleBigEndian(_buffer.AsSpan(_offset), value); _offset += sizeof(double); AdvanceDataItemCounters(); } /// <summary>Writes a boolean value (major type 7).</summary> /// <param name="value">The value to write.</param> /// <exception cref="InvalidOperationException">Writing a new value exceeds the definite length of the parent data item. /// -or- /// The major type of the encoded value is not permitted in the parent data item. /// -or- /// The written data is not accepted under the current conformance mode.</exception> public void WriteBoolean(bool value) { WriteSimpleValue(value ? CborSimpleValue.True : CborSimpleValue.False); } /// <summary>Writes a <see langword="null" /> value (major type 7).</summary> /// <exception cref="InvalidOperationException">Writing a new value exceeds the definite length of the parent data item. /// -or- /// The major type of the encoded value is not permitted in the parent data item. /// -or- /// The written data is not accepted under the current conformance mode.</exception> public void WriteNull() { WriteSimpleValue(CborSimpleValue.Null); } /// <summary>Writes a simple value encoding (major type 7).</summary> /// <param name="value">The value to write.</param> /// <exception cref="ArgumentOutOfRangeException">The <paramref name="value" /> parameter is in the invalid 24-31 range.</exception> /// <exception cref="InvalidOperationException">Writing a new value exceeds the definite length of the parent data item. /// -or- /// The major type of the encoded value is not permitted in the parent data item. /// -or- /// The written data is not accepted under the current conformance mode.</exception> public void WriteSimpleValue(CborSimpleValue value) { if (value < (CborSimpleValue)CborAdditionalInfo.Additional8BitData) { EnsureWriteCapacity(1); WriteInitialByte(new CborInitialByte(CborMajorType.Simple, (CborAdditionalInfo)value)); } else if (value <= (CborSimpleValue)CborAdditionalInfo.IndefiniteLength && CborConformanceModeHelpers.RequireCanonicalSimpleValueEncodings(ConformanceMode)) { throw new ArgumentOutOfRangeException(SR.Format(SR.Cbor_ConformanceMode_InvalidSimpleValueEncoding, ConformanceMode)); } else { EnsureWriteCapacity(2); WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional8BitData)); _buffer[_offset++] = (byte)value; } AdvanceDataItemCounters(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvertDoubleToSingle(double value, out float result) { result = (float)value; return double.IsNaN(value) || BitConverter.DoubleToInt64Bits(result) == BitConverter.DoubleToInt64Bits(value); } } }