Compare commits

...

5 commits

Author SHA1 Message Date
e06b85632a Make all decoder components move-only 2025-09-26 02:54:05 +02:00
ca8750aab2 Refactors
- Refer to std::span<std::uint8_t> as Buffer
- Refer to std::span<const std::uint8_t> as ConstBuffer
- Use more consistent naming for members

These were mostly added so the function prototypes look a bit better.
2025-09-26 02:16:52 +02:00
d5680eaccb Add trailing newline to item print 2025-09-26 02:06:11 +02:00
9bda00793d Add the ability to print a nested item 2025-09-26 01:54:28 +02:00
f383ea9f66 Add the ability to print a nearly arbitrary CBOR encoded value 2025-09-26 01:52:23 +02:00
9 changed files with 567 additions and 100 deletions

View file

@ -25,4 +25,5 @@ target_sources(LibCBOR
"Source/Core.cpp"
"Source/Decoder.cpp"
"Source/Encoder.cpp"
"Source/Printer.cpp"
)

View file

@ -3,6 +3,7 @@
#include <cstdint>
#include <limits>
#include <span>
#include <stdexcept>
namespace CBOR
@ -148,6 +149,9 @@ namespace CBOR
public:
using std::runtime_error::runtime_error;
};
using Buffer = std::span<std::uint8_t>;
using ConstBuffer = std::span<const std::uint8_t>;
}
#endif // LIBCBOR_CORE_HPP

View file

@ -3,7 +3,7 @@
#include "Core.hpp"
#include <span>
#include <limits>
#include <string_view>
namespace CBOR
@ -19,7 +19,21 @@ namespace CBOR
private:
Item(class Decoder &decoder);
Item(const Item &) = delete;
Item &operator=(const Item &) = delete;
public:
Item(Item &&other);
Item &operator=(Item &&other);
~Item() = default;
static constexpr
std::uint64_t ArgumentIndefinite = std::numeric_limits<std::uint64_t>::max();
MajorType GetMajor() const;
MinorType GetMinor() const;
std::uint64_t GetArgument() const;
bool Bool();
Special Special();
@ -37,13 +51,13 @@ namespace CBOR
float Float();
double Double();
std::span<std::uint8_t> Binary();
std::string_view String();
class Binary IndefiniteBinary();
class String IndefiniteString();
class Array Array();
class Map Map();
class TaggedItem TaggedItem();
ConstBuffer Binary();
std::string_view String();
class Binary IndefiniteBinary();
class String IndefiniteString();
class Array Array();
class Map Map();
class TaggedItem TaggedItem();
private:
friend class Decoder;
@ -59,7 +73,14 @@ namespace CBOR
private:
TaggedItem(class Decoder &decoder);
TaggedItem(const TaggedItem &) = delete;
TaggedItem &operator=(const TaggedItem &) = delete;
public:
TaggedItem(TaggedItem &&other);
TaggedItem &operator=(TaggedItem &&other);
~TaggedItem() = default;
std::uint64_t Tag();
Item Item();
@ -80,7 +101,14 @@ namespace CBOR
private:
KeyValue(class Decoder &decoder);
KeyValue(const KeyValue &) = delete;
KeyValue &operator=(const KeyValue &) = delete;
public:
KeyValue(KeyValue &&other);
KeyValue &operator=(KeyValue &&other);
~KeyValue() = default;
Item Key();
Item Value();
private:
@ -101,9 +129,16 @@ namespace CBOR
private:
Binary(class Decoder &decoder);
Binary(const Binary &) = delete;
Binary &operator=(const Binary &) = delete;
public:
bool Done();
std::span<std::uint8_t> Next();
Binary(Binary &&other);
Binary &operator=(Binary &&other);
~Binary() = default;
bool Done();
ConstBuffer Next();
private:
friend class Decoder;
@ -119,7 +154,14 @@ namespace CBOR
private:
String(class Decoder &decoder);
String(const String &) = delete;
String &operator=(const String &) = delete;
public:
String(String &&other);
String &operator=(String &&other);
~String() = default;
bool Done();
std::string_view Next();
@ -137,7 +179,14 @@ namespace CBOR
private:
Array(class Decoder &decoder);
Array(const Array &) = delete;
Array &operator=(const Array &) = delete;
public:
Array(Array &&other);
Array &operator=(Array &&other);
~Array() = default;
bool Done();
Item Next();
@ -157,7 +206,14 @@ namespace CBOR
private:
Map(class Decoder &decoder);
Map(const Map &) = delete;
Map &operator=(const Map &) = delete;
public:
Map(Map &&other);
Map &operator=(Map &&other);
~Map() = default;
bool Done();
KeyValue Next();
@ -175,7 +231,20 @@ namespace CBOR
class Decoder
{
public:
Decoder(std::span<std::uint8_t> buffer);
Decoder(ConstBuffer buffer);
Decoder(const Decoder &) = delete;
Decoder &operator=(const Decoder &) = delete;
Decoder(Decoder &&other);
Decoder &operator=(Decoder &&other);
~Decoder() = default;
static constexpr
std::uint64_t ArgumentIndefinite = std::numeric_limits<std::uint64_t>::max();
MajorType GetMajor() const;
MinorType GetMinor() const;
std::uint64_t GetArgument() const;
bool Bool();
Special Special();
@ -194,14 +263,15 @@ namespace CBOR
float Float();
double Double();
std::span<std::uint8_t> Binary();
std::string_view String();
class Binary IndefiniteBinary();
class String IndefiniteString();
class Array Array();
class Map Map();
class TaggedItem TaggedItem();
ConstBuffer Binary();
std::string_view String();
class Binary IndefiniteBinary();
class String IndefiniteString();
class Array Array();
class Map Map();
class TaggedItem TaggedItem();
class Item AsItem();
private:
friend class Binary;
friend class String;
@ -209,8 +279,8 @@ namespace CBOR
friend class Map;
friend class TaggedItem;
std::size_t mCurrent;
std::span<std::uint8_t> mBuffer;
std::size_t mCurrent;
ConstBuffer mBuffer;
};
}

View file

@ -21,7 +21,7 @@ namespace CBOR
class EncoderBuffer
{
public:
EncoderBuffer(std::span<std::uint8_t> buffer);
EncoderBuffer(Buffer buffer);
EncoderBuffer(std::vector<std::uint8_t> &buffer);
template <std::size_t N>
@ -39,7 +39,7 @@ namespace CBOR
void Write(std::uint16_t value);
void Write(std::uint32_t value);
void Write(std::uint64_t value);
void Write(std::span<std::uint8_t> value);
void Write(Buffer value);
void Write(std::string_view value);
std::size_t Size() const;
@ -51,14 +51,14 @@ namespace CBOR
void Write(std::uint16_t value);
void Write(std::uint32_t value);
void Write(std::uint64_t value);
void Write(std::span<std::uint8_t> value);
void Write(Buffer value);
void Write(std::string_view value);
std::size_t Size() const;
void EnsureSpace(std::size_t size) const;
std::size_t Current;
std::span<std::uint8_t> Buffer;
std::size_t mCurrent;
Buffer mBuffer;
};
struct DynamicBuffer
@ -67,12 +67,12 @@ namespace CBOR
void Write(std::uint16_t value);
void Write(std::uint32_t value);
void Write(std::uint64_t value);
void Write(std::span<std::uint8_t> value);
void Write(Buffer value);
void Write(std::string_view value);
std::size_t Size() const;
std::vector<std::uint8_t> *Buffer;
std::vector<std::uint8_t> *mBuffer;
};
using BufferType = std::variant<FixedBuffer, DynamicBuffer>;
@ -108,7 +108,7 @@ namespace CBOR
void Encode(float value);
void Encode(double value);
void Encode(std::span<std::uint8_t> value);
void Encode(Buffer value);
void Encode(const char *value);
void Encode(std::string_view value);

View file

@ -0,0 +1,15 @@
#ifndef LIBCBOR_PRINTER_HPP
#define LIBCBOR_PRINTER_HPP
#include "Core.hpp"
#include "Decoder.hpp"
#include <ostream>
namespace CBOR
{
void Print(std::ostream &out, ConstBuffer buffer);
void Print(std::ostream &out, Item item);
}
#endif // LIBCBOR_PRINTER_HPP

View file

@ -57,7 +57,7 @@ namespace CBOR
{
static constexpr std::size_t Indefinite = std::numeric_limits<std::size_t>::max();
std::size_t SpaceLeft(std::span<std::uint8_t> buffer, std::size_t offset)
std::size_t SpaceLeft(ConstBuffer buffer, std::size_t offset)
{
if (offset >= buffer.size()) {
return 0;
@ -65,8 +65,7 @@ namespace CBOR
return buffer.size() - offset;
}
void EnsureEnoughSpace(std::span<std::uint8_t> buffer, std::size_t offset,
std::size_t spaceRequired)
void EnsureEnoughSpace(ConstBuffer buffer, std::size_t offset, std::size_t spaceRequired)
{
if (SpaceLeft(buffer, offset) < spaceRequired) {
using namespace std::string_view_literals;
@ -75,19 +74,13 @@ namespace CBOR
}
}
std::uint8_t Read1B(std::span<std::uint8_t> buffer, std::size_t current)
std::uint8_t Read1B(ConstBuffer buffer, std::size_t current)
{
EnsureEnoughSpace(buffer, current, 1);
return buffer[current];
}
std::uint8_t Consume1B(std::span<std::uint8_t> buffer, std::size_t &current)
{
EnsureEnoughSpace(buffer, current, 1);
return buffer[current++];
}
std::uint16_t Consume2B(std::span<std::uint8_t> buffer, std::size_t &current)
std::uint16_t Read2B(ConstBuffer buffer, std::size_t current)
{
EnsureEnoughSpace(buffer, current, 2);
std::uint16_t result = 0;
@ -96,7 +89,7 @@ namespace CBOR
return NetworkToHost(result);
}
std::uint32_t Consume4B(std::span<std::uint8_t> buffer, std::size_t &current)
std::uint32_t Read4B(ConstBuffer buffer, std::size_t current)
{
EnsureEnoughSpace(buffer, current, 4);
std::uint32_t result = 0;
@ -107,7 +100,48 @@ namespace CBOR
return NetworkToHost(result);
}
std::uint64_t Consume8B(std::span<std::uint8_t> buffer, std::size_t &current)
std::uint64_t Read8B(ConstBuffer buffer, std::size_t current)
{
EnsureEnoughSpace(buffer, current, 8);
std::uint64_t result = 0;
result |= std::uint64_t(buffer[current++]) ;
result |= std::uint64_t(buffer[current++]) << 8;
result |= std::uint64_t(buffer[current++]) << 16;
result |= std::uint64_t(buffer[current++]) << 24;
result |= std::uint64_t(buffer[current++]) << 32;
result |= std::uint64_t(buffer[current++]) << 40;
result |= std::uint64_t(buffer[current++]) << 48;
result |= std::uint64_t(buffer[current++]) << 56;
return NetworkToHost(result);
}
std::uint8_t Consume1B(ConstBuffer buffer, std::size_t &current)
{
EnsureEnoughSpace(buffer, current, 1);
return buffer[current++];
}
std::uint16_t Consume2B(ConstBuffer buffer, std::size_t &current)
{
EnsureEnoughSpace(buffer, current, 2);
std::uint16_t result = 0;
result |= std::uint16_t(buffer[current++]) ;
result |= std::uint16_t(buffer[current++]) << 8;
return NetworkToHost(result);
}
std::uint32_t Consume4B(ConstBuffer buffer, std::size_t &current)
{
EnsureEnoughSpace(buffer, current, 4);
std::uint32_t result = 0;
result |= std::uint32_t(buffer[current++]) ;
result |= std::uint32_t(buffer[current++]) << 8;
result |= std::uint32_t(buffer[current++]) << 16;
result |= std::uint32_t(buffer[current++]) << 24;
return NetworkToHost(result);
}
std::uint64_t Consume8B(ConstBuffer buffer, std::size_t &current)
{
EnsureEnoughSpace(buffer, current, 8);
std::uint64_t result = 0;
@ -137,7 +171,7 @@ namespace CBOR
return ArgumentPosition(header & std::to_underlying(ArgumentPosition::PositionMask));
}
std::uint64_t ArgumentValue(std::uint8_t header, std::span<std::uint8_t> buffer, std::size_t &current)
std::uint64_t ArgumentValue(std::uint8_t header, ConstBuffer buffer, std::size_t &current)
{
ArgumentPosition position = GetArgumentPosition(header);
if (std::to_underlying(position) <= 23) {
@ -158,8 +192,29 @@ namespace CBOR
}
}
std::uint64_t ReadArgumentValue(std::uint8_t header, ConstBuffer buffer, std::size_t current)
{
ArgumentPosition position = GetArgumentPosition(header);
if (std::to_underlying(position) <= 23) {
return std::to_underlying(position);
}
switch (position) {
case ArgumentPosition::Next1B:
return Read1B(buffer, current);
case ArgumentPosition::Next2B:
return Read2B(buffer, current);
case ArgumentPosition::Next4B:
return Read4B(buffer, current);
case ArgumentPosition::Next8B:
return Read8B(buffer, current);
default:
throw MalformedDataError("argument position is reserved for future use, incorrect, "
"or the parser is out of date");
}
}
template <std::unsigned_integral T>
T ExtractUnsigned(std::span<std::uint8_t> buffer, std::size_t &current)
T ExtractUnsigned(ConstBuffer buffer, std::size_t &current)
{
static constexpr std::uint64_t maxValue = std::numeric_limits<T>::max();
@ -214,7 +269,7 @@ namespace CBOR
// Note(3011): In this case it includes zero, even though zero is not technically positive.
template <std::signed_integral T>
T SignedPositive(std::uint8_t header, std::span<std::uint8_t> buffer, std::size_t &current)
T SignedPositive(std::uint8_t header, ConstBuffer buffer, std::size_t &current)
{
static constexpr std::uint64_t maxValue = std::numeric_limits<T>::max();
@ -266,7 +321,7 @@ namespace CBOR
}
template <std::signed_integral T>
T SignedNegative(std::uint8_t header, std::span<std::uint8_t> buffer, std::size_t &current)
T SignedNegative(std::uint8_t header, ConstBuffer buffer, std::size_t &current)
{
static constexpr auto actualMin = std::numeric_limits<T>::min();
static constexpr std::uint64_t minValue = -std::int64_t(actualMin + 1);
@ -319,7 +374,7 @@ namespace CBOR
}
template <std::signed_integral T>
T ExtractSigned(std::span<std::uint8_t> buffer, std::size_t &current)
T ExtractSigned(ConstBuffer buffer, std::size_t &current)
{
std::uint8_t header = Consume1B(buffer, current);
MajorType major = GetMajorType(header);
@ -335,15 +390,15 @@ namespace CBOR
}
}
std::span<std::uint8_t> ExtractBinary(std::size_t size, std::span<std::uint8_t> buffer, std::size_t &current)
ConstBuffer ExtractBinary(std::size_t size, ConstBuffer buffer, std::size_t &current)
{
EnsureEnoughSpace(buffer, current, size);
std::span<std::uint8_t> result(buffer.data() + current, size);
ConstBuffer result(buffer.data() + current, size);
current += size;
return result;
}
std::string_view ExtractString(std::size_t size, std::span<std::uint8_t> buffer, std::size_t &current)
std::string_view ExtractString(std::size_t size, ConstBuffer buffer, std::size_t &current)
{
EnsureEnoughSpace(buffer, current, size);
std::string_view result(reinterpret_cast<const char *>(buffer.data() + current), size);
@ -356,6 +411,31 @@ namespace CBOR
: mDecoder(&decoder)
{}
Item::Item(Item &&other)
: mDecoder(std::exchange(other.mDecoder, nullptr))
{}
Item &Item::operator=(Item &&other)
{
mDecoder = std::exchange(other.mDecoder, nullptr);
return *this;
}
MajorType Item::GetMajor() const
{
return mDecoder->GetMajor();
}
MinorType Item::GetMinor() const
{
return mDecoder->GetMinor();
}
std::uint64_t Item::GetArgument() const
{
return mDecoder->GetArgument();
}
bool Item::Bool()
{
return mDecoder->Bool();
@ -416,7 +496,7 @@ namespace CBOR
return mDecoder->Double();
}
std::span<std::uint8_t> Item::Binary()
ConstBuffer Item::Binary()
{
return mDecoder->Binary();
}
@ -455,6 +535,18 @@ namespace CBOR
: mState(State::Initial), mDecoder(&decoder)
{}
TaggedItem::TaggedItem(TaggedItem &&other)
: mState(std::exchange(other.mState, State::Done))
, mDecoder(std::exchange(other.mDecoder, nullptr))
{}
TaggedItem &TaggedItem::operator=(TaggedItem &&other)
{
mState = std::exchange(other.mState, State::Done);
mDecoder = std::exchange(other.mDecoder, nullptr);
return *this;
}
std::uint64_t TaggedItem::Tag()
{
if (mState != State::Initial) {
@ -485,6 +577,18 @@ namespace CBOR
: mState(State::Initial), mDecoder(&decoder)
{}
KeyValue::KeyValue(KeyValue &&other)
: mState(std::exchange(other.mState, State::Done))
, mDecoder(std::exchange(other.mDecoder, nullptr))
{}
KeyValue &KeyValue::operator=(KeyValue &&other)
{
mState = std::exchange(other.mState, State::Done);
mDecoder = std::exchange(other.mDecoder, nullptr);
return *this;
}
Item KeyValue::Key()
{
if (mState != State::Initial) {
@ -512,6 +616,22 @@ namespace CBOR
, mDecoder(&decoder)
{}
Binary::Binary(Binary &&other)
: mHeaderParsed(std::exchange(other.mHeaderParsed, true))
, mDone(std::exchange(other.mDone, true))
, mCheckedDone(std::exchange(other.mCheckedDone, true))
, mDecoder(std::exchange(other.mDecoder, nullptr))
{}
Binary &Binary::operator=(Binary &&other)
{
mHeaderParsed = std::exchange(other.mHeaderParsed, true);
mDone = std::exchange(other.mDone, true);
mCheckedDone = std::exchange(other.mCheckedDone, true);
mDecoder = std::exchange(other.mDecoder, nullptr);
return *this;
}
bool Binary::Done()
{
if (!mHeaderParsed) {
@ -531,7 +651,7 @@ namespace CBOR
return mDone;
}
std::span<std::uint8_t> Binary::Next()
ConstBuffer Binary::Next()
{
if (!mHeaderParsed) {
std::uint8_t header = Consume1B(mDecoder->mBuffer, mDecoder->mCurrent);
@ -579,6 +699,22 @@ namespace CBOR
, mDecoder(&decoder)
{}
String::String(String &&other)
: mHeaderParsed(std::exchange(other.mHeaderParsed, true))
, mDone(std::exchange(other.mDone, true))
, mCheckedDone(std::exchange(other.mCheckedDone, true))
, mDecoder(std::exchange(other.mDecoder, nullptr))
{}
String &String::operator=(String &&other)
{
mHeaderParsed = std::exchange(other.mHeaderParsed, true);
mDone = std::exchange(other.mDone, true);
mCheckedDone = std::exchange(other.mCheckedDone, true);
mDecoder = std::exchange(other.mDecoder, nullptr);
return *this;
}
bool String::Done()
{
if (!mHeaderParsed) {
@ -648,6 +784,26 @@ namespace CBOR
, mDecoder(&decoder)
{}
Array::Array(Array &&other)
: mHeaderParsed(std::exchange(other.mHeaderParsed, true))
, mDone(std::exchange(other.mDone, true))
, mCheckedDone(std::exchange(other.mCheckedDone, true))
, mCurrent(std::exchange(other.mCurrent, 0))
, mSize(std::exchange(other.mSize, 0))
, mDecoder(std::exchange(other.mDecoder, nullptr))
{}
Array &Array::operator=(Array &&other)
{
mHeaderParsed = std::exchange(other.mHeaderParsed, true);
mDone = std::exchange(other.mDone, true);
mCheckedDone = std::exchange(other.mCheckedDone, true);
mCurrent = std::exchange(other.mCurrent, 0);
mSize = std::exchange(other.mSize, 0);
mDecoder = std::exchange(other.mDecoder, nullptr);
return *this;
}
bool Array::Done()
{
if (!mHeaderParsed) {
@ -712,6 +868,26 @@ namespace CBOR
, mDecoder(&decoder)
{}
Map::Map(Map &&other)
: mHeaderParsed(std::exchange(other.mHeaderParsed, true))
, mDone(std::exchange(other.mDone, true))
, mCheckedDone(std::exchange(other.mCheckedDone, true))
, mCurrent(std::exchange(other.mCurrent, 0))
, mSize(std::exchange(other.mSize, 0))
, mDecoder(std::exchange(other.mDecoder, nullptr))
{}
Map &Map::operator=(Map &&other)
{
mHeaderParsed = std::exchange(other.mHeaderParsed, true);
mDone = std::exchange(other.mDone, true);
mCheckedDone = std::exchange(other.mCheckedDone, true);
mCurrent = std::exchange(other.mCurrent, 0);
mSize = std::exchange(other.mSize, 0);
mDecoder = std::exchange(other.mDecoder, nullptr);
return *this;
}
bool Map::Done()
{
if (!mHeaderParsed) {
@ -767,10 +943,49 @@ namespace CBOR
return KeyValue(*mDecoder);
}
Decoder::Decoder(std::span<std::uint8_t> buffer)
Decoder::Decoder(ConstBuffer buffer)
: mCurrent(0), mBuffer(buffer)
{}
Decoder::Decoder(Decoder &&other)
: mCurrent(std::exchange(other.mCurrent, 0))
, mBuffer(std::exchange(other.mBuffer, {}))
{}
Decoder &Decoder::operator=(Decoder &&other)
{
mCurrent = std::exchange(other.mCurrent, 0);
mBuffer = std::exchange(other.mBuffer, {});
return *this;
}
MajorType Decoder::GetMajor() const
{
std::uint8_t header = Read1B(mBuffer, mCurrent);
return GetMajorType(header);
}
MinorType Decoder::GetMinor() const
{
std::uint8_t header = Read1B(mBuffer, mCurrent);
if (GetMajorType(header) != MajorType::Other) {
throw InvalidUsageError("use the GetArgument function instead");
}
return GetMinorType(header);
}
std::uint64_t Decoder::GetArgument() const
{
std::uint8_t header = Read1B(mBuffer, mCurrent);
if (GetMajorType(header) != MajorType::Other) {
throw InvalidUsageError("use the GetMinor function instead");
}
if (GetArgumentPosition(header) == ArgumentPosition::Indefinite) {
return Decoder::ArgumentIndefinite;
}
return ReadArgumentValue(header, mBuffer, mCurrent);
}
bool Decoder::Bool()
{
std::uint8_t header = Consume1B(mBuffer, mCurrent);
@ -881,7 +1096,7 @@ namespace CBOR
throw TypeMismatchError("double", ToString(major));
}
std::span<std::uint8_t> Decoder::Binary()
ConstBuffer Decoder::Binary()
{
std::uint8_t header = Consume1B(mBuffer, mCurrent);
MajorType major = GetMajorType(header);
@ -937,4 +1152,9 @@ namespace CBOR
{
return { *this };
}
Item Decoder::AsItem()
{
return { *this };
}
}

View file

@ -76,16 +76,16 @@ namespace CBOR
}
}
EncoderBuffer::EncoderBuffer(std::span<std::uint8_t> buffer)
: mBuffer(FixedBuffer { .Current = 0, .Buffer = buffer, })
EncoderBuffer::EncoderBuffer(Buffer buffer)
: mBuffer(FixedBuffer { .mCurrent = 0, .mBuffer = buffer, })
{}
EncoderBuffer::EncoderBuffer(std::vector<std::uint8_t> &buffer)
: mBuffer(DynamicBuffer { .Buffer = &buffer })
: mBuffer(DynamicBuffer { .mBuffer = &buffer })
{}
EncoderBuffer::EncoderBuffer(EncoderBuffer &&other)
: mBuffer(std::exchange(other.mBuffer, FixedBuffer { .Current = 0, .Buffer = {}, }))
: mBuffer(std::exchange(other.mBuffer, FixedBuffer { .mCurrent = 0, .mBuffer = {}, }))
{}
void EncoderBuffer::Write(std::uint8_t value)
@ -120,7 +120,7 @@ namespace CBOR
}, mBuffer);
}
void EncoderBuffer::Write(std::span<std::uint8_t> value)
void EncoderBuffer::Write(Buffer value)
{
std::visit(Overload {
[value] (FixedBuffer &buffer) { buffer.Write(value); },
@ -147,7 +147,7 @@ namespace CBOR
void EncoderBuffer::FixedBuffer::Write(std::uint8_t value)
{
EnsureSpace(1);
Buffer[Current++] = value;
mBuffer[mCurrent++] = value;
}
void EncoderBuffer::FixedBuffer::Write(std::uint16_t value)
@ -155,8 +155,8 @@ namespace CBOR
EnsureSpace(2);
static constexpr std::uint16_t mask = 0x00'FF;
std::uint16_t network = HostToNetwork(value);
Buffer[Current++] = static_cast<std::uint8_t>((network ) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 8) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network ) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 8) & mask);
}
void EncoderBuffer::FixedBuffer::Write(std::uint32_t value)
@ -164,10 +164,10 @@ namespace CBOR
EnsureSpace(4);
static constexpr std::uint32_t mask = 0x00'00'00'FF;
std::uint32_t network = HostToNetwork(value);
Buffer[Current++] = static_cast<std::uint8_t>((network ) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 8) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 16) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 24) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network ) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 8) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 16) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 24) & mask);
}
void EncoderBuffer::FixedBuffer::Write(std::uint64_t value)
@ -175,33 +175,33 @@ namespace CBOR
EnsureSpace(8);
static constexpr std::uint64_t mask = 0x00'00'00'00'00'00'00'FF;
std::uint64_t network = HostToNetwork(value);
Buffer[Current++] = static_cast<std::uint8_t>((network ) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 8) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 16) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 24) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 32) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 40) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 48) & mask);
Buffer[Current++] = static_cast<std::uint8_t>((network >> 56) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network ) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 8) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 16) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 24) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 32) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 40) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 48) & mask);
mBuffer[mCurrent++] = static_cast<std::uint8_t>((network >> 56) & mask);
}
void EncoderBuffer::FixedBuffer::Write(std::span<std::uint8_t> value)
void EncoderBuffer::FixedBuffer::Write(Buffer value)
{
EnsureSpace(value.size());
std::memcpy(Buffer.data() + Current, value.data(), value.size());
Current += value.size();
std::memcpy(mBuffer.data() + mCurrent, value.data(), value.size());
mCurrent += value.size();
}
void EncoderBuffer::FixedBuffer::Write(std::string_view value)
{
EnsureSpace(value.size());
std::memcpy(Buffer.data() + Current, value.data(), value.size());
Current += value.size();
std::memcpy(mBuffer.data() + mCurrent, value.data(), value.size());
mCurrent += value.size();
}
void EncoderBuffer::FixedBuffer::EnsureSpace(std::size_t size) const
{
std::size_t spaceLeft = Current > Buffer.size() ? 0 : Buffer.size() - Current;
std::size_t spaceLeft = mCurrent > mBuffer.size() ? 0 : mBuffer.size() - mCurrent;
if (size > spaceLeft) {
throw NotEnoughSpace(spaceLeft, size);
@ -210,59 +210,59 @@ namespace CBOR
std::size_t EncoderBuffer::FixedBuffer::Size() const
{
return Current;
return mCurrent;
}
void EncoderBuffer::DynamicBuffer::Write(std::uint8_t value)
{
Buffer->push_back(value);
mBuffer->push_back(value);
}
void EncoderBuffer::DynamicBuffer::Write(std::uint16_t value)
{
static constexpr std::uint16_t mask = 0x00'FF;
std::uint16_t network = HostToNetwork(value);
Buffer->push_back(static_cast<std::uint8_t>((network ) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network ) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
}
void EncoderBuffer::DynamicBuffer::Write(std::uint32_t value)
{
static constexpr std::uint32_t mask = 0x00'00'00'FF;
std::uint32_t network = HostToNetwork(value);
Buffer->push_back(static_cast<std::uint8_t>((network ) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 16) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 24) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network ) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 16) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 24) & mask));
}
void EncoderBuffer::DynamicBuffer::Write(std::uint64_t value)
{
static constexpr std::uint64_t mask = 0x00'00'00'00'00'00'00'FF;
std::uint64_t network = HostToNetwork(value);
Buffer->push_back(static_cast<std::uint8_t>((network ) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 16) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 24) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 32) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 40) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 48) & mask));
Buffer->push_back(static_cast<std::uint8_t>((network >> 56) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network ) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 8) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 16) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 24) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 32) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 40) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 48) & mask));
mBuffer->push_back(static_cast<std::uint8_t>((network >> 56) & mask));
}
void EncoderBuffer::DynamicBuffer::Write(std::span<std::uint8_t> value)
void EncoderBuffer::DynamicBuffer::Write(Buffer value)
{
Buffer->append_range(value);
mBuffer->append_range(value);
}
void EncoderBuffer::DynamicBuffer::Write(std::string_view value)
{
Buffer->append_range(value);
mBuffer->append_range(value);
}
std::size_t EncoderBuffer::DynamicBuffer::Size() const
{
return Buffer->size();
return mBuffer->size();
}
BasicEncoder::BasicEncoder(EncoderBuffer buffer)
@ -447,7 +447,7 @@ namespace CBOR
mBuffer.Write(std::bit_cast<std::uint64_t>(value));
}
void BasicEncoder::Encode(std::span<std::uint8_t> value)
void BasicEncoder::Encode(Buffer value)
{
WriteHeader(mBuffer, MajorType::Binary, value.size());
mBuffer.Write(value);

152
LibCBOR/Source/Printer.cpp Normal file
View file

@ -0,0 +1,152 @@
#include "Printer.hpp"
#include "Core.hpp"
#include "Decoder.hpp"
#include <print>
#include <string>
namespace CBOR
{
namespace
{
void Print(std::ostream &out, std::size_t depth, CBOR::Item item);
char AsChar(std::uint8_t nibble)
{
if (nibble < 10) {
return nibble + '0';
}
if (nibble < 16) {
return nibble + 'A';
}
return 'X';
}
std::string AsString(std::uint8_t byte)
{
std::string result;
result.push_back(AsChar((byte >> 4) & 15));
result.push_back(AsChar((byte ) & 15));
return result;
}
void PrintBinary(std::ostream &out, CBOR::Binary binary)
{
out << "b\"";
while (!binary.Done()) {
std::span<const std::uint8_t> chunk = binary.Next();
for (std::uint8_t byte: chunk) {
out << AsString(byte);
}
}
out << '\"';
}
void PrintString(std::ostream &out, CBOR::String string)
{
out << '\"';
while (!string.Done()) {
out << string.Next();
}
out << '\"';
}
void PrintArray(std::ostream &out, std::size_t depth, CBOR::Array array)
{
out << "[\n";
while (!array.Done()) {
out << std::string((depth + 1) * 4, ' ');
Print(out, depth + 1, array.Next());
out << ",\n";
}
out << std::string(depth * 4, ' ') << "]";
}
void PrintMap(std::ostream &out, std::size_t depth, CBOR::Map map)
{
out << "{\n";
while (!map.Done()) {
CBOR::KeyValue kv = map.Next();
out << std::string((depth + 1) * 4, ' ');
Print(out, depth + 1, kv.Key());
out << ": ";
Print(out, depth + 1, kv.Value());
out << ",\n";
}
out << std::string(depth * 4, ' ') << "}";
}
void PrintTagged(std::ostream &out, std::size_t depth, CBOR::TaggedItem item)
{
out << item.Tag();
out << '(';
Print(out, depth, item.Item());
out << ')';
}
void Print(std::ostream &out, std::size_t depth, CBOR::Item item)
{
switch (item.GetMajor()) {
case MajorType::Unsigned:
out << item.Uint64();
break;
case MajorType::Negative:
out << item.Int64();
break;
case MajorType::Binary:
PrintBinary(out, item.IndefiniteBinary());
break;
case MajorType::String:
PrintString(out, item.IndefiniteString());
break;
case MajorType::Array:
PrintArray(out, depth, item.Array());
break;
case MajorType::Map:
PrintMap(out, depth, item.Map());
break;
case MajorType::Tag:
PrintTagged(out, depth, item.TaggedItem());
break;
case MajorType::Other:
switch (item.GetMinor()) {
case MinorType::False:
out << "false";
break;
case MinorType::True:
out << "true";
break;
case MinorType::Null:
out << "null";
break;
case MinorType::Undefined:
out << "undefined";
break;
case MinorType::Float:
std::print(out, "{:.6f}", item.Float());
break;
case MinorType::Double:
std::print(out, "{:.15f}", item.Double());
break;
default:
out << "invalid_value";
break;
}
}
}
}
void Print(std::ostream &out, ConstBuffer buffer)
{
CBOR::Decoder dec(buffer);
Print(out, 0, dec.AsItem());
out << '\n';
}
void Print(std::ostream &out, CBOR::Item item)
{
Print(out, 0, std::move(item));
out << '\n';
}
}

View file

@ -1,7 +1,9 @@
#include "CBOR/Decoder.hpp"
#include "CBOR/Encoder.hpp"
#include "CBOR/Printer.hpp"
#include <array>
#include <cstdint>
#include <iostream>
#include <print>
#include <ranges>
#include <stdexcept>
@ -206,6 +208,9 @@ int main()
SomeStruct result1 = Decode1(std::span<std::uint8_t>(buffer.data(), encodedSize));
SomeStruct result2 = Decode2(std::span<std::uint8_t>(buffer.data(), encodedSize));
std::println("JSON-esque serialization:");
CBOR::Print(std::cout, std::span<std::uint8_t>(buffer.data(), encodedSize));
Compare(expected, result1);
Compare(expected, result2);
std::println("The test has been completed successfully.");