Add support for CBOR tags
This commit is contained in:
parent
acf4d93fde
commit
b65c700c29
5 changed files with 120 additions and 17 deletions
|
@ -14,13 +14,10 @@ namespace CBOR
|
|||
using Error::Error;
|
||||
};
|
||||
|
||||
// Forward decl
|
||||
class Decoder;
|
||||
|
||||
class Item
|
||||
{
|
||||
private:
|
||||
Item(Decoder &decoder);
|
||||
Item(class Decoder &decoder);
|
||||
|
||||
public:
|
||||
bool Bool();
|
||||
|
@ -46,19 +43,42 @@ namespace CBOR
|
|||
class String IndefiniteString();
|
||||
class Array Array();
|
||||
class Map Map();
|
||||
class TaggedItem TaggedItem();
|
||||
|
||||
private:
|
||||
friend class Decoder;
|
||||
friend class Array;
|
||||
friend class TaggedItem;
|
||||
friend class KeyValue;
|
||||
|
||||
Decoder *mDecoder;
|
||||
};
|
||||
|
||||
class TaggedItem
|
||||
{
|
||||
private:
|
||||
TaggedItem(class Decoder &decoder);
|
||||
|
||||
public:
|
||||
std::uint64_t Tag();
|
||||
Item Item();
|
||||
|
||||
private:
|
||||
friend class Decoder;
|
||||
|
||||
enum class State
|
||||
{
|
||||
Initial, TagPulled, Done,
|
||||
};
|
||||
|
||||
State mState;
|
||||
Decoder *mDecoder;
|
||||
};
|
||||
|
||||
class KeyValue
|
||||
{
|
||||
private:
|
||||
KeyValue(Decoder &decoder);
|
||||
KeyValue(class Decoder &decoder);
|
||||
|
||||
public:
|
||||
Item Key();
|
||||
|
@ -79,7 +99,7 @@ namespace CBOR
|
|||
class Binary
|
||||
{
|
||||
private:
|
||||
Binary(Decoder &decoder);
|
||||
Binary(class Decoder &decoder);
|
||||
|
||||
public:
|
||||
bool Done();
|
||||
|
@ -97,7 +117,7 @@ namespace CBOR
|
|||
class String
|
||||
{
|
||||
private:
|
||||
String(Decoder &decoder);
|
||||
String(class Decoder &decoder);
|
||||
|
||||
public:
|
||||
bool Done();
|
||||
|
@ -115,7 +135,7 @@ namespace CBOR
|
|||
class Array
|
||||
{
|
||||
private:
|
||||
Array(Decoder &decoder);
|
||||
Array(class Decoder &decoder);
|
||||
|
||||
public:
|
||||
bool Done();
|
||||
|
@ -135,7 +155,7 @@ namespace CBOR
|
|||
class Map
|
||||
{
|
||||
private:
|
||||
Map(Decoder &decoder);
|
||||
Map(class Decoder &decoder);
|
||||
|
||||
public:
|
||||
bool Done();
|
||||
|
@ -180,12 +200,14 @@ namespace CBOR
|
|||
class String IndefiniteString();
|
||||
class Array Array();
|
||||
class Map Map();
|
||||
class TaggedItem TaggedItem();
|
||||
|
||||
private:
|
||||
friend class Binary;
|
||||
friend class String;
|
||||
friend class Array;
|
||||
friend class Map;
|
||||
friend class TaggedItem;
|
||||
|
||||
std::size_t mCurrent;
|
||||
std::span<std::uint8_t> mBuffer;
|
||||
|
|
|
@ -57,6 +57,8 @@ namespace CBOR
|
|||
|
||||
void End();
|
||||
|
||||
void EncodeTag(std::uint64_t value);
|
||||
|
||||
std::size_t EncodedSize() const;
|
||||
private:
|
||||
std::size_t mCurrent;
|
||||
|
|
|
@ -446,6 +446,41 @@ namespace CBOR
|
|||
return mDecoder->Map();
|
||||
}
|
||||
|
||||
TaggedItem Item::TaggedItem()
|
||||
{
|
||||
return mDecoder->TaggedItem();
|
||||
}
|
||||
|
||||
TaggedItem::TaggedItem(Decoder &decoder)
|
||||
: mState(State::Initial), mDecoder(&decoder)
|
||||
{}
|
||||
|
||||
std::uint64_t TaggedItem::Tag()
|
||||
{
|
||||
if (mState != State::Initial) {
|
||||
throw InvalidUsageError("the tag has already been pulled, or this pair is done");
|
||||
}
|
||||
|
||||
mState = State::TagPulled;
|
||||
std::uint8_t header = Consume1B(mDecoder->mBuffer, mDecoder->mCurrent);
|
||||
MajorType major = GetMajorType(header);
|
||||
if (major != MajorType::Tag) {
|
||||
throw TypeMismatchError("tagged item", ToString(major));
|
||||
}
|
||||
|
||||
return ArgumentValue(header, mDecoder->mBuffer, mDecoder->mCurrent);
|
||||
}
|
||||
|
||||
Item TaggedItem::Item()
|
||||
{
|
||||
if (mState != State::TagPulled) {
|
||||
throw InvalidUsageError("the tag must be pulled first, or this item is done");
|
||||
}
|
||||
|
||||
mState = State::Done;
|
||||
return { *mDecoder };
|
||||
}
|
||||
|
||||
KeyValue::KeyValue(Decoder &decoder)
|
||||
: mState(State::Initial), mDecoder(&decoder)
|
||||
{}
|
||||
|
@ -457,7 +492,7 @@ namespace CBOR
|
|||
}
|
||||
|
||||
mState = State::KeyPulled;
|
||||
return Item(*mDecoder);
|
||||
return { *mDecoder };
|
||||
}
|
||||
|
||||
Item KeyValue::Value()
|
||||
|
@ -897,4 +932,9 @@ namespace CBOR
|
|||
{
|
||||
return { *this };
|
||||
}
|
||||
|
||||
TaggedItem Decoder::TaggedItem()
|
||||
{
|
||||
return { *this };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -318,7 +318,7 @@ namespace CBOR
|
|||
|
||||
void BasicEncoder::Encode(std::span<std::uint8_t> value)
|
||||
{
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, value.size() + 1 + ArgumentSize(value.size()));
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value.size()) + value.size());
|
||||
if (value.size() <= 23) {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::Binary)
|
||||
| static_cast<std::uint8_t>(value.size());
|
||||
|
@ -354,7 +354,7 @@ namespace CBOR
|
|||
|
||||
void BasicEncoder::Encode(std::string_view value)
|
||||
{
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, value.size() + ArgumentSize(value.size()));
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value.size()) + value.size());
|
||||
if (value.size() <= 23) {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::String)
|
||||
| static_cast<std::uint8_t>(value.size());
|
||||
|
@ -385,7 +385,7 @@ namespace CBOR
|
|||
|
||||
void BasicEncoder::BeginArray(std::size_t size)
|
||||
{
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, ArgumentSize(size));
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(size));
|
||||
if (size <= 23) {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::Array)
|
||||
| static_cast<std::uint8_t>(size);
|
||||
|
@ -414,7 +414,7 @@ namespace CBOR
|
|||
|
||||
void BasicEncoder::BeginMap(std::size_t size)
|
||||
{
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, ArgumentSize(size));
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(size));
|
||||
if (size <= 23) {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::Map)
|
||||
| static_cast<std::uint8_t>(size);
|
||||
|
@ -476,6 +476,35 @@ namespace CBOR
|
|||
| std::to_underlying(MinorType::Break);
|
||||
}
|
||||
|
||||
void BasicEncoder::EncodeTag(std::uint64_t value)
|
||||
{
|
||||
EnsureEnoughSpace(mBuffer, mCurrent, 1 + ArgumentSize(value));
|
||||
if (value <= 23) {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
|
||||
| static_cast<std::uint8_t>(value);
|
||||
}
|
||||
else if (value <= 255) {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
|
||||
| std::to_underlying(ArgumentPosition::Next1B);
|
||||
mBuffer[mCurrent++] = static_cast<std::uint8_t>(value);
|
||||
}
|
||||
else if (value <= 65535) {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
|
||||
| std::to_underlying(ArgumentPosition::Next2B);
|
||||
Write(mBuffer, mCurrent, static_cast<std::uint16_t>(value));
|
||||
}
|
||||
else if (value <= 4294967295) {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
|
||||
| std::to_underlying(ArgumentPosition::Next4B);
|
||||
Write(mBuffer, mCurrent, static_cast<std::uint32_t>(value));
|
||||
}
|
||||
else {
|
||||
mBuffer[mCurrent++] = std::to_underlying(MajorType::Tag)
|
||||
| std::to_underlying(ArgumentPosition::Next8B);
|
||||
Write(mBuffer, mCurrent, static_cast<std::uint64_t>(value));
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t BasicEncoder::EncodedSize() const
|
||||
{
|
||||
return mBuffer.size() - (mBuffer.size() - mCurrent);
|
||||
|
|
|
@ -21,6 +21,8 @@ struct SomeStruct
|
|||
std::size_t Encode(const SomeStruct &value, std::span<std::uint8_t> buffer)
|
||||
{
|
||||
CBOR::BasicEncoder enc(buffer);
|
||||
enc.EncodeTag(15'000);
|
||||
|
||||
enc.BeginMap(7);
|
||||
|
||||
enc.Encode("name");
|
||||
|
@ -56,7 +58,11 @@ SomeStruct Decode1(std::span<std::uint8_t> buffer)
|
|||
SomeStruct result;
|
||||
|
||||
CBOR::Decoder dec(buffer);
|
||||
CBOR::Map object = dec.Map();
|
||||
CBOR::TaggedItem tagged = dec.TaggedItem();
|
||||
if (tagged.Tag() != 15'000) {
|
||||
throw std::runtime_error("test error: could not extract object tag");
|
||||
}
|
||||
CBOR::Map object = tagged.Item().Map();
|
||||
while (!object.Done()) {
|
||||
CBOR::KeyValue kv = object.Next();
|
||||
std::string_view key = kv.Key().String();
|
||||
|
@ -95,7 +101,11 @@ SomeStruct Decode2(std::span<std::uint8_t> buffer)
|
|||
SomeStruct result;
|
||||
|
||||
CBOR::Decoder dec(buffer);
|
||||
CBOR::Map object = dec.Map();
|
||||
CBOR::TaggedItem tagged = dec.TaggedItem();
|
||||
if (tagged.Tag() != 15'000) {
|
||||
throw std::runtime_error("test error: could not extract object tag");
|
||||
}
|
||||
CBOR::Map object = tagged.Item().Map();
|
||||
while (!object.Done()) {
|
||||
CBOR::KeyValue kv = object.Next();
|
||||
std::string_view key = kv.Key().String();
|
||||
|
@ -164,7 +174,7 @@ int main()
|
|||
{
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
std::array<std::uint8_t, 1024> buffer = {0};
|
||||
std::array<std::uint8_t, 1024> buffer {};
|
||||
|
||||
SomeStruct expected {
|
||||
.name = "Player1",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue