-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
CborReader.PeekState.cs
156 lines (139 loc) · 6.83 KB
/
CborReader.PeekState.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
namespace System.Formats.Cbor
{
public partial class CborReader
{
/// <summary>Reads the next CBOR token, without advancing the reader.</summary>
/// <returns>An object that represents the current CBOR reader state.</returns>
/// <exception cref="CborContentException">The underlying data is not a well-formed CBOR encoding.</exception>
public CborReaderState PeekState()
{
if (_cachedState == CborReaderState.Undefined)
{
_cachedState = PeekStateCore();
}
return _cachedState;
}
private CborReaderState PeekStateCore()
{
if (_definiteLength - _itemsRead == 0)
{
// is at the end of a definite-length context
switch (_currentMajorType)
{
case null:
// finished reading root-level document
Debug.Assert(!AllowMultipleRootLevelValues);
return CborReaderState.Finished;
case CborMajorType.Array: return CborReaderState.EndArray;
case CborMajorType.Map: return CborReaderState.EndMap;
default:
Debug.Fail("CborReader internal error. Invalid CBOR major type pushed to stack.");
throw new Exception();
}
}
if (_offset == _data.Length)
{
// is at the end of the read buffer
if (_currentMajorType is null && _definiteLength is null)
{
// is at the end of a well-defined sequence of root-level values
return CborReaderState.Finished;
}
else
{
// incomplete CBOR document(s)
throw new CborContentException(SR.Cbor_Reader_InvalidCbor_UnexpectedEndOfBuffer);
}
}
// peek the next initial byte
var initialByte = new CborInitialByte(_data.Span[_offset]);
if (initialByte.InitialByte == CborInitialByte.IndefiniteLengthBreakByte)
{
if (_isTagContext)
{
throw new CborContentException(SR.Cbor_Reader_InvalidCbor_TagNotFollowedByValue);
}
if (_definiteLength is null)
{
switch (_currentMajorType)
{
case null:
// found a break byte at the end of a root-level data item sequence
Debug.Assert(AllowMultipleRootLevelValues);
throw new CborContentException(SR.Cbor_Reader_InvalidCbor_UnexpectedBreakByte);
case CborMajorType.ByteString: return CborReaderState.EndIndefiniteLengthByteString;
case CborMajorType.TextString: return CborReaderState.EndIndefiniteLengthTextString;
case CborMajorType.Array: return CborReaderState.EndArray;
case CborMajorType.Map when _itemsRead % 2 == 0: return CborReaderState.EndMap;
case CborMajorType.Map:
throw new CborContentException(SR.Cbor_Reader_InvalidCbor_KeyMissingValue);
default:
Debug.Fail("CborReader internal error. Invalid CBOR major type pushed to stack.");
throw new Exception();
};
}
else
{
throw new CborContentException(SR.Cbor_Reader_InvalidCbor_UnexpectedBreakByte);
}
}
if (_definiteLength is null && _currentMajorType != null)
{
// is at indefinite-length nested data item
switch (_currentMajorType.Value)
{
case CborMajorType.ByteString:
case CborMajorType.TextString:
if (initialByte.MajorType != _currentMajorType.Value)
{
throw new CborContentException(SR.Cbor_Reader_InvalidCbor_IndefiniteLengthStringContainsInvalidDataItem);
}
break;
}
}
switch (initialByte.MajorType)
{
case CborMajorType.UnsignedInteger: return CborReaderState.UnsignedInteger;
case CborMajorType.NegativeInteger: return CborReaderState.NegativeInteger;
case CborMajorType.ByteString:
return (initialByte.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) ?
CborReaderState.StartIndefiniteLengthByteString :
CborReaderState.ByteString;
case CborMajorType.TextString:
return (initialByte.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) ?
CborReaderState.StartIndefiniteLengthTextString :
CborReaderState.TextString;
case CborMajorType.Array: return CborReaderState.StartArray;
case CborMajorType.Map: return CborReaderState.StartMap;
case CborMajorType.Tag: return CborReaderState.Tag;
case CborMajorType.Simple: return MapSimpleValueDataToReaderState(initialByte.AdditionalInfo);
default:
Debug.Fail("CborReader internal error. Invalid CBOR major type.");
throw new Exception();
};
static CborReaderState MapSimpleValueDataToReaderState(CborAdditionalInfo value)
{
// https://tools.ietf.org/html/rfc7049#section-2.3
switch (value)
{
case (CborAdditionalInfo)CborSimpleValue.Null:
return CborReaderState.Null;
case (CborAdditionalInfo)CborSimpleValue.True:
case (CborAdditionalInfo)CborSimpleValue.False:
return CborReaderState.Boolean;
case CborAdditionalInfo.Additional16BitData:
return CborReaderState.HalfPrecisionFloat;
case CborAdditionalInfo.Additional32BitData:
return CborReaderState.SinglePrecisionFloat;
case CborAdditionalInfo.Additional64BitData:
return CborReaderState.DoublePrecisionFloat;
default:
return CborReaderState.SimpleValue;
}
}
}
}
}