Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CBOR] Implement tag and special value support for CborWriter and CborReader #34046

Merged
merged 8 commits into from
Mar 30, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,49 @@ public static void ReadCborNegativeIntegerEncoding_SingleValue_HappyPath(ulong e
Assert.Equal(CborReaderState.Finished, reader.Peek());
}

[Theory]
[InlineData(2, 2, "c202")]
[InlineData(0, "2013-03-21T20:04:00Z", "c074323031332d30332d32315432303a30343a30305a")]
[InlineData(1, 1363896240, "c11a514b67b0")]
[InlineData(23, new byte[] { 1, 2, 3, 4 }, "d74401020304")]
[InlineData(32, "http://www.example.com", "d82076687474703a2f2f7777772e6578616d706c652e636f6d")]
[InlineData(int.MaxValue, 2, "da7fffffff02")]
[InlineData(ulong.MaxValue, new object[] { 1, 2 }, "dbffffffffffffffff820102")]
public static void ReadTag_SingleValue_HappyPath(ulong expectedTag, object expectedValue, string hexEncoding)
{
byte[] encoding = hexEncoding.HexToByteArray();
var reader = new CborReader(encoding);

Assert.Equal(CborReaderState.Tag, reader.Peek());
ulong tag = reader.ReadTag();
Assert.Equal(expectedTag, tag);

Helpers.VerifyValue(reader, expectedValue);
Assert.Equal(CborReaderState.Finished, reader.Peek());
}

[Theory]
[InlineData(new ulong[] { 1, 2, 3 }, 2, "c1c2c302")]
[InlineData(new ulong[] { 0, 0, 0 }, "2013-03-21T20:04:00Z", "c0c0c074323031332d30332d32315432303a30343a30305a")]
[InlineData(new ulong[] { int.MaxValue, ulong.MaxValue }, 1363896240, "da7fffffffdbffffffffffffffff1a514b67b0")]
[InlineData(new ulong[] { 23, 24, 100 }, new byte[] { 1, 2, 3, 4 }, "d7d818d8644401020304")]
[InlineData(new ulong[] { 32, 1, 1 }, new object[] { 1, "lorem ipsum" }, "d820c1c182016b6c6f72656d20697073756d")]
public static void ReadTag_NestedTags_HappyPath(ulong[] expectedTags, object expectedValue, string hexEncoding)
{
byte[] encoding = hexEncoding.HexToByteArray();
var reader = new CborReader(encoding);

foreach (ulong expectedTag in expectedTags)
{
Assert.Equal(CborReaderState.Tag, reader.Peek());
ulong tag = reader.ReadTag();
Assert.Equal(expectedTag, tag);
}

Helpers.VerifyValue(reader, expectedValue);
Assert.Equal(CborReaderState.Finished, reader.Peek());
}

[Theory]
// all possible definite-length encodings for the value 23
[InlineData("17")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public partial class CborWriterTests
[InlineData(-2 - uint.MaxValue, "3b0000000100000000")]
[InlineData(long.MinValue, "3b7fffffffffffffff")]
[InlineData(long.MaxValue, "1b7fffffffffffffff")]
public static void Int64Writer_SingleValue_HappyPath(long input, string hexExpectedEncoding)
public static void WriteInt64_SingleValue_HappyPath(long input, string hexExpectedEncoding)
{
byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray();
using var writer = new CborWriter();
Expand All @@ -70,14 +70,50 @@ public static void Int64Writer_SingleValue_HappyPath(long input, string hexExpec
[InlineData((ulong)uint.MaxValue + 1, "1b0000000100000000")]
[InlineData(long.MaxValue, "1b7fffffffffffffff")]
[InlineData(ulong.MaxValue, "1bffffffffffffffff")]
public static void UInt64Writer_SingleValue_HappyPath(ulong input, string hexExpectedEncoding)
public static void WriteUInt64_SingleValue_HappyPath(ulong input, string hexExpectedEncoding)
{
byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray();
using var writer = new CborWriter();
writer.WriteUInt64(input);
AssertHelper.HexEqual(expectedEncoding, writer.ToArray());
}

[Theory]
[InlineData(2, 2, "c202")]
[InlineData(0, "2013-03-21T20:04:00Z", "c074323031332d30332d32315432303a30343a30305a")]
[InlineData(1, 1363896240, "c11a514b67b0")]
[InlineData(23, new byte[] { 1, 2, 3, 4 }, "d74401020304")]
[InlineData(32, "http://www.example.com", "d82076687474703a2f2f7777772e6578616d706c652e636f6d")]
[InlineData(int.MaxValue, 2, "da7fffffff02")]
[InlineData(ulong.MaxValue, new object[] { 1, 2 }, "dbffffffffffffffff820102")]
public static void WriteTag_SingleValue_HappyPath(ulong tag, object value, string hexExpectedEncoding)
{
byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray();
using var writer = new CborWriter();
writer.WriteTag(tag);
Helpers.WriteValue(writer, value);
AssertHelper.HexEqual(expectedEncoding, writer.ToArray());
}

[Theory]
[InlineData(new ulong[] { 1, 2, 3 }, 2, "c1c2c302")]
[InlineData(new ulong[] { 0, 0, 0 }, "2013-03-21T20:04:00Z", "c0c0c074323031332d30332d32315432303a30343a30305a")]
[InlineData(new ulong[] { int.MaxValue, ulong.MaxValue }, 1363896240, "da7fffffffdbffffffffffffffff1a514b67b0")]
[InlineData(new ulong[] { 23, 24, 100 }, new byte[] { 1, 2, 3, 4 }, "d7d818d8644401020304")]
[InlineData(new ulong[] { 32, 1, 1 }, new object[] { 1, "lorem ipsum" }, "d820c1c182016b6c6f72656d20697073756d")]
public static void WriteTag_NestedTags_HappyPath(ulong[] tags, object value, string hexExpectedEncoding)
{
byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray();
using var writer = new CborWriter();
foreach (var tag in tags)
{
writer.WriteTag(tag);
}
Helpers.WriteValue(writer, value);
AssertHelper.HexEqual(expectedEncoding, writer.ToArray());
}
}

internal static class AssertHelper
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ public long ReadInt64()
}
}

public ulong ReadTag()
{
CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Tag);
ulong tag = ReadUnsignedInteger(_buffer.Span, header, out int additionalBytes);
AdvanceBuffer(1 + additionalBytes);
return tag;
}

// Returns the next CBOR negative integer encoding according to
// https://tools.ietf.org/html/rfc7049#section-2.1
public ulong ReadCborNegativeIntegerEncoding()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public void WriteStartArray(int definiteLength)
}

WriteUnsignedInteger(CborMajorType.Array, (ulong)definiteLength);
DecrementRemainingItemCount();
PushDataItem(CborMajorType.Array, (uint)definiteLength);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal partial class CborWriter
public void WriteUInt64(ulong value)
{
WriteUnsignedInteger(CborMajorType.UnsignedInteger, value);
DecrementRemainingItemCount();
}

// Implements major type 0,1 encoding per https://tools.ietf.org/html/rfc7049#section-2.1
Expand All @@ -26,6 +27,13 @@ public void WriteInt64(long value)
{
WriteUnsignedInteger(CborMajorType.UnsignedInteger, (ulong)value);
}

DecrementRemainingItemCount();
}

public void WriteTag(ulong tag)
{
WriteUnsignedInteger(CborMajorType.Tag, tag);
}

// Unsigned integer encoding https://tools.ietf.org/html/rfc7049#section-2.1
Expand Down Expand Up @@ -63,8 +71,6 @@ private void WriteUnsignedInteger(CborMajorType type, ulong value)
BinaryPrimitives.WriteUInt64BigEndian(_buffer.AsSpan(_offset), value);
_offset += 8;
}

DecrementRemainingItemCount();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public void WriteStartMap(int definiteLength)
}

WriteUnsignedInteger(CborMajorType.Map, (ulong)definiteLength);
DecrementRemainingItemCount();
PushDataItem(CborMajorType.Map, 2 * (uint)definiteLength);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public void WriteByteString(ReadOnlySpan<byte> value)
EnsureWriteCapacity(value.Length);
value.CopyTo(_buffer.AsSpan(_offset));
_offset += value.Length;
DecrementRemainingItemCount();
}

// Implements major type 3 encoding per https://tools.ietf.org/html/rfc7049#section-2.1
Expand All @@ -29,6 +30,7 @@ public void WriteTextString(ReadOnlySpan<char> value)
EnsureWriteCapacity(length);
s_utf8Encoding.GetBytes(value, _buffer.AsSpan(_offset));
_offset += length;
DecrementRemainingItemCount();
}

public void WriteStartByteStringIndefiniteLength()
Expand Down