| File: System\Formats\Cbor\Reader\CborReader.Integer.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.Buffers.Binary; namespace System.Formats.Cbor { public partial class CborReader { // Implements major type 0,1 decoding per https://tools.ietf.org/html/rfc7049#section-2.1 /// <summary>Reads the next data item as a signed integer (major types 0,1)</summary> /// <returns>The decoded integer value.</returns> /// <exception cref="InvalidOperationException">The next data item does not have the correct major type.</exception> /// <exception cref="OverflowException">The encoded integer is out of range for <see cref="int" />.</exception> /// <exception cref="CborContentException"><para>The next value has an invalid CBOR encoding.</para> /// <para>-or-</para> /// <para>There was an unexpected end of CBOR encoding data.</para> /// <para>-or-</para> /// <para>The next value uses a CBOR encoding that is not valid under the current conformance mode.</para></exception> public int ReadInt32() { int value = checked((int)PeekSignedInteger(out int bytesRead)); AdvanceBuffer(bytesRead); AdvanceDataItemCounters(); return value; } /// <summary>Reads the next data item as an unsigned integer (major type 0).</summary> /// <returns>The decoded integer value.</returns> /// <exception cref="InvalidOperationException">The next data item does not have the correct major type.</exception> /// <exception cref="OverflowException">The encoded integer is out of range for <see cref="uint" />.</exception> /// <exception cref="CborContentException"><para>The next value has an invalid CBOR encoding.</para> /// <para>-or-</para> /// <para>There was an unexpected end of CBOR encoding data.</para> /// <para>-or-</para> /// <para>The next value uses a CBOR encoding that is not valid under the current conformance mode.</para></exception> [CLSCompliant(false)] public uint ReadUInt32() { uint value = checked((uint)PeekUnsignedInteger(out int bytesRead)); AdvanceBuffer(bytesRead); AdvanceDataItemCounters(); return value; } /// <summary>Reads the next data item as a signed integer (major types 0,1)</summary> /// <returns>The decoded integer value.</returns> /// <exception cref="InvalidOperationException">The next data item does not have the correct major type.</exception> /// <exception cref="OverflowException">The encoded integer is out of range for <see cref="long" />.</exception> /// <exception cref="CborContentException"><para>The next value has an invalid CBOR encoding.</para> /// <para>-or-</para> /// <para>There was an unexpected end of CBOR encoding data.</para> /// <para>-or-</para> /// <para>The next value uses a CBOR encoding that is not valid under the current conformance mode.</para></exception> public long ReadInt64() { long value = PeekSignedInteger(out int bytesRead); AdvanceBuffer(bytesRead); AdvanceDataItemCounters(); return value; } /// <summary>Reads the next data item as an unsigned integer (major type 0).</summary> /// <returns>The decoded integer value.</returns> /// <exception cref="InvalidOperationException">The next data item does not have the correct major type.</exception> /// <exception cref="OverflowException">The encoded integer is out of range for <see cref="ulong" />.</exception> /// <exception cref="CborContentException"><para>The next value has an invalid CBOR encoding.</para> /// <para>-or-</para> /// <para>There was an unexpected end of CBOR encoding data.</para> /// <para>-or-</para> /// <para>The next value uses a CBOR encoding that is not valid under the current conformance mode.</para></exception> [CLSCompliant(false)] public ulong ReadUInt64() { ulong value = PeekUnsignedInteger(out int bytesRead); AdvanceBuffer(bytesRead); AdvanceDataItemCounters(); return value; } /// <summary>Reads the next data item as a CBOR negative integer representation (major type 1).</summary> /// <returns>An unsigned integer denoting -1 minus the integer.</returns> /// <exception cref="InvalidOperationException">The next data item does not have the correct major type.</exception> /// <exception cref="CborContentException"><para>The next value has an invalid CBOR encoding.</para> /// <para>-or-</para> /// <para>There was an unexpected end of CBOR encoding data.</para> /// <para>-or-</para> /// <para>The next value uses a CBOR encoding that is not valid under the current conformance mode.</para></exception> /// <remarks> /// This method supports decoding integers between -18446744073709551616 and -1. /// Useful for handling values that do not fit in the <see cref="long" /> type. /// </remarks> [CLSCompliant(false)] public ulong ReadCborNegativeIntegerRepresentation() { CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.NegativeInteger); ulong value = DecodeUnsignedInteger(header, GetRemainingBytes(), out int bytesRead); AdvanceBuffer(bytesRead); AdvanceDataItemCounters(); return value; } private ulong PeekUnsignedInteger(out int bytesRead) { CborInitialByte header = PeekInitialByte(); switch (header.MajorType) { case CborMajorType.UnsignedInteger: ulong value = DecodeUnsignedInteger(header, GetRemainingBytes(), out bytesRead); return value; case CborMajorType.NegativeInteger: throw new OverflowException(); default: throw new InvalidOperationException(SR.Format(SR.Cbor_Reader_MajorTypeMismatch, (int)header.MajorType)); } } private long PeekSignedInteger(out int bytesRead) { CborInitialByte header = PeekInitialByte(); long value; switch (header.MajorType) { case CborMajorType.UnsignedInteger: value = checked((long)DecodeUnsignedInteger(header, GetRemainingBytes(), out bytesRead)); return value; case CborMajorType.NegativeInteger: value = checked(-1 - (long)DecodeUnsignedInteger(header, GetRemainingBytes(), out bytesRead)); return value; default: throw new InvalidOperationException(SR.Format(SR.Cbor_Reader_MajorTypeMismatch, (int)header.MajorType)); } } // Peek definite length for given data item private int DecodeDefiniteLength(CborInitialByte header, ReadOnlySpan<byte> data, out int bytesRead) { ulong length = DecodeUnsignedInteger(header, data, out bytesRead); // conservative check: ensure the buffer has the minimum required length for declared definite length. if (length > (ulong)(data.Length - bytesRead)) { throw new CborContentException(SR.Cbor_Reader_DefiniteLengthExceedsBufferSize); } return (int)length; } // Unsigned integer decoding https://tools.ietf.org/html/rfc7049#section-2.1 private ulong DecodeUnsignedInteger(CborInitialByte header, ReadOnlySpan<byte> data, out int bytesRead) { ulong result; switch (header.AdditionalInfo) { case CborAdditionalInfo x when (x < CborAdditionalInfo.Additional8BitData): bytesRead = 1; return (ulong)x; case CborAdditionalInfo.Additional8BitData: EnsureReadCapacity(data, 1 + sizeof(byte)); result = data[1]; if (result < (int)CborAdditionalInfo.Additional8BitData) { ValidateIsNonStandardIntegerRepresentationSupported(); } bytesRead = 1 + sizeof(byte); return result; case CborAdditionalInfo.Additional16BitData: EnsureReadCapacity(data, 1 + sizeof(ushort)); result = BinaryPrimitives.ReadUInt16BigEndian(data.Slice(1)); if (result <= byte.MaxValue) { ValidateIsNonStandardIntegerRepresentationSupported(); } bytesRead = 1 + sizeof(ushort); return result; case CborAdditionalInfo.Additional32BitData: EnsureReadCapacity(data, 1 + sizeof(uint)); result = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(1)); if (result <= ushort.MaxValue) { ValidateIsNonStandardIntegerRepresentationSupported(); } bytesRead = 1 + sizeof(uint); return result; case CborAdditionalInfo.Additional64BitData: EnsureReadCapacity(data, 1 + sizeof(ulong)); result = BinaryPrimitives.ReadUInt64BigEndian(data.Slice(1)); if (result <= uint.MaxValue) { ValidateIsNonStandardIntegerRepresentationSupported(); } bytesRead = 1 + sizeof(ulong); return result; default: throw new CborContentException(SR.Cbor_Reader_InvalidCbor_InvalidIntegerEncoding); } void ValidateIsNonStandardIntegerRepresentationSupported() { if (_isConformanceModeCheckEnabled && CborConformanceModeHelpers.RequiresCanonicalIntegerRepresentation(ConformanceMode)) { throw new CborContentException(SR.Format(SR.Cbor_ConformanceMode_NonCanonicalIntegerRepresentation, ConformanceMode)); } } } } }