File: System\Formats\Cbor\Writer\CborWriter.Integer.cs
Web Access
Project: src\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.Buffers.Binary;
 
namespace System.Formats.Cbor
{
    public partial class CborWriter
    {
        // Implements major type 0,1 encoding per https://tools.ietf.org/html/rfc7049#section-2.1
 
        /// <summary>Writes a value as a signed integer encoding (major types 0,1)</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 WriteInt32(int value) => WriteInt64(value);
 
        /// <summary>Writes the provided value as a signed integer encoding (major types 0,1)</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 WriteInt64(long value)
        {
            if (value < 0)
            {
                ulong unsignedRepresentation = (value == long.MinValue) ? (ulong)long.MaxValue : (ulong)(-value) - 1;
                WriteUnsignedInteger(CborMajorType.NegativeInteger, unsignedRepresentation);
            }
            else
            {
                WriteUnsignedInteger(CborMajorType.UnsignedInteger, (ulong)value);
            }
 
            AdvanceDataItemCounters();
        }
 
        /// <summary>Writes a value as an unsigned integer encoding (major type 0).</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>
        [CLSCompliant(false)]
        public void WriteUInt32(uint value) => WriteUInt64(value);
 
        /// <summary>Writes a value as an unsigned integer encoding (major type 0).</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>
        [CLSCompliant(false)]
        public void WriteUInt64(ulong value)
        {
            WriteUnsignedInteger(CborMajorType.UnsignedInteger, value);
            AdvanceDataItemCounters();
        }
 
        /// <summary>Writes the provided value as a CBOR negative integer representation (major type 1).</summary>
        /// <param name="value">An unsigned integer denoting -1 minus the integer.</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>
        /// <remarks>
        /// This method supports encoding integers between -18446744073709551616 and -1.
        /// Useful for handling values that do not fit in the <see cref="long" /> type.
        /// </remarks>
        [CLSCompliant(false)]
        public void WriteCborNegativeIntegerRepresentation(ulong value)
        {
            WriteUnsignedInteger(CborMajorType.NegativeInteger, value);
            AdvanceDataItemCounters();
        }
 
        private void WriteUnsignedInteger(CborMajorType type, ulong value)
        {
            if (value < (byte)CborAdditionalInfo.Additional8BitData)
            {
                EnsureWriteCapacity(1);
                WriteInitialByte(new CborInitialByte(type, (CborAdditionalInfo)value));
            }
            else if (value <= byte.MaxValue)
            {
                EnsureWriteCapacity(1 + sizeof(byte));
                WriteInitialByte(new CborInitialByte(type, CborAdditionalInfo.Additional8BitData));
                _buffer[_offset++] = (byte)value;
            }
            else if (value <= ushort.MaxValue)
            {
                EnsureWriteCapacity(1 + sizeof(ushort));
                WriteInitialByte(new CborInitialByte(type, CborAdditionalInfo.Additional16BitData));
                BinaryPrimitives.WriteUInt16BigEndian(_buffer.AsSpan(_offset), (ushort)value);
                _offset += sizeof(ushort);
            }
            else if (value <= uint.MaxValue)
            {
                EnsureWriteCapacity(1 + sizeof(uint));
                WriteInitialByte(new CborInitialByte(type, CborAdditionalInfo.Additional32BitData));
                BinaryPrimitives.WriteUInt32BigEndian(_buffer.AsSpan(_offset), (uint)value);
                _offset += sizeof(uint);
            }
            else
            {
                EnsureWriteCapacity(1 + sizeof(ulong));
                WriteInitialByte(new CborInitialByte(type, CborAdditionalInfo.Additional64BitData));
                BinaryPrimitives.WriteUInt64BigEndian(_buffer.AsSpan(_offset), value);
                _offset += sizeof(ulong);
            }
        }
 
        private static int GetIntegerEncodingLength(ulong value)
        {
            if (value < (byte)CborAdditionalInfo.Additional8BitData)
            {
                return 1;
            }
            else if (value <= byte.MaxValue)
            {
                return 1 + sizeof(byte);
            }
            else if (value <= ushort.MaxValue)
            {
                return 1 + sizeof(ushort);
            }
            else if (value <= uint.MaxValue)
            {
                return 1 + sizeof(uint);
            }
            else
            {
                return 1 + sizeof(ulong);
            }
        }
    }
}