|
@ -157,7 +157,7 @@ namespace gp { |
|
|
* @return vector<char>& the same reference that was received for the source |
|
|
* @return vector<char>& the same reference that was received for the source |
|
|
*/ |
|
|
*/ |
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<int64_t>(vector<char>& src, int64_t& value) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<int64_t>(vector<char>& src, int64_t& value) { |
|
|
uint8_t sign = (value<0) ? 0b00100000 : 0; |
|
|
uint8_t sign = (value<0) ? 0b00100000 : 0; |
|
|
auto norm_v = (value<0) ? -value : value; |
|
|
auto norm_v = (value<0) ? -value : value; |
|
|
return push_integer_with_header_as_cbor(src, sign, norm_v); |
|
|
return push_integer_with_header_as_cbor(src, sign, norm_v); |
|
@ -171,12 +171,12 @@ namespace gp { |
|
|
* @return vector<char>& the same reference that was received for the source |
|
|
* @return vector<char>& the same reference that was received for the source |
|
|
*/ |
|
|
*/ |
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<uint64_t>(vector<char>& src, uint64_t& value) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<uint64_t>(vector<char>& src, uint64_t& value) { |
|
|
return push_integer_with_header_as_cbor(src, 0, value); |
|
|
return push_integer_with_header_as_cbor(src, 0, value); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<std::nullptr_t>(vector<char>& src, std::nullptr_t) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<std::nullptr_t>(vector<char>& src, std::nullptr_t) { |
|
|
src.push_back(0b11110110); |
|
|
src.push_back(0b11110110); |
|
|
return src; |
|
|
return src; |
|
|
} |
|
|
} |
|
@ -184,19 +184,19 @@ namespace gp { |
|
|
struct cbor_undefined{}; |
|
|
struct cbor_undefined{}; |
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<cbor_undefined>(vector<char>& src, cbor_undefined) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<cbor_undefined>(vector<char>& src, cbor_undefined) { |
|
|
src.push_back(0b11110111); |
|
|
src.push_back(0b11110111); |
|
|
return src; |
|
|
return src; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<bool>(vector<char>& src, bool value) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<bool>(vector<char>& src, bool value) { |
|
|
src.push_back(0b11110100+(value ? 1 : 0)); |
|
|
src.push_back(0b11110100+(value ? 1 : 0)); |
|
|
return src; |
|
|
return src; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<gp::buffer<char>>(vector<char>& src, gp::buffer<char> value) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<gp::buffer<char>>(vector<char>& src, gp::buffer<char> value) { |
|
|
push_integer_with_header_as_cbor(src, (uint8_t)0b01000000, value.size()); |
|
|
push_integer_with_header_as_cbor(src, (uint8_t)0b01000000, value.size()); |
|
|
for(auto byte : value) { |
|
|
for(auto byte : value) { |
|
|
src.push_back(byte); |
|
|
src.push_back(byte); |
|
@ -213,17 +213,17 @@ namespace gp { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<cbor_array_initiator>(vector<char>& src, cbor_array_initiator value) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<cbor_array_initiator>(vector<char>& src, cbor_array_initiator value) { |
|
|
return push_integer_with_header_as_cbor(src, (uint8_t)0b10000000, value.size); |
|
|
return push_integer_with_header_as_cbor(src, (uint8_t)0b10000000, value.size); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<cbor_associative_array_initiator>(vector<char>& src, cbor_associative_array_initiator value) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<cbor_associative_array_initiator>(vector<char>& src, cbor_associative_array_initiator value) { |
|
|
return push_integer_with_header_as_cbor(src, (uint8_t)0b10100000, value.size); |
|
|
return push_integer_with_header_as_cbor(src, (uint8_t)0b10100000, value.size); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
template<typename First, typename Second> |
|
|
template<typename First, typename Second> |
|
|
vector<char>& push_as_cbor(vector<char>& src, gp::pair<First, Second>& value) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor(vector<char>& src, gp::pair<First, Second>& value) { |
|
|
push_as_cbor<First>(src,value.first); |
|
|
push_as_cbor<First>(src,value.first); |
|
|
return push_as_cbor<Second>(src,value.second); |
|
|
return push_as_cbor<Second>(src,value.second); |
|
|
} |
|
|
} |
|
@ -236,7 +236,7 @@ namespace gp { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
vector<char>& push_as_cbor<cbor_tag_initiator>(vector<char>& src, cbor_tag_initiator value) { |
|
|
|
|
|
|
|
|
kr">inline vector<char>& push_as_cbor<cbor_tag_initiator>(vector<char>& src, cbor_tag_initiator value) { |
|
|
return push_integer_with_header_as_cbor(src, (uint8_t)0b11000000, value.as_integer); |
|
|
return push_integer_with_header_as_cbor(src, (uint8_t)0b11000000, value.as_integer); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -284,18 +284,21 @@ namespace gp { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
gp::pair<gp::optional<int64_t>, parsing_state> read_cbor<int64_t>(parsing_state state) { |
|
|
|
|
|
|
|
|
kr">inline gp::pair<gp::optional<uint64_t>, parsing_state> read_cbor<uint64_t>(parsing_state state) { |
|
|
if(state.size()) return {nullopt, state}; |
|
|
if(state.size()) return {nullopt, state}; |
|
|
auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5); |
|
|
auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5); |
|
|
|
|
|
|
|
|
int64_t sign = type == cbor_type::nint ? -1 : 1; |
|
|
|
|
|
|
|
|
|
|
|
switch(type) { |
|
|
switch(type) { |
|
|
case cbor_type::uint: |
|
|
case cbor_type::uint: |
|
|
|
|
|
{ |
|
|
|
|
|
auto[value, new_state] = pull_arbitrary_integer_from_cbor(state); |
|
|
|
|
|
if(value.has_value()) return {value.value(), new_state}; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
case cbor_type::nint: |
|
|
case cbor_type::nint: |
|
|
{ |
|
|
{ |
|
|
auto[value, new_state] = pull_arbitrary_integer_from_cbor(state); |
|
|
auto[value, new_state] = pull_arbitrary_integer_from_cbor(state); |
|
|
if(value.has_value()) return {value.value() * sign, new_state}; |
|
|
|
|
|
|
|
|
if(value.has_value()) return {o">-value.value(), new_state}; |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
default: |
|
|
default: |
|
@ -303,9 +306,10 @@ namespace gp { |
|
|
} |
|
|
} |
|
|
return {nullopt, state}; |
|
|
return {nullopt, state}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<> |
|
|
template<> |
|
|
gp::pair<gp::optional<uint64_t>, parsing_state> read_cbor<uint64_t>(parsing_state state) { |
|
|
|
|
|
|
|
|
kr">inline gp::pair<gp::optional<int64_t>, parsing_state> read_cbor<int64_t>(parsing_state state) { |
|
|
if(state.size()) return {nullopt, state}; |
|
|
if(state.size()) return {nullopt, state}; |
|
|
auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5); |
|
|
auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5); |
|
|
|
|
|
|
|
@ -316,582 +320,19 @@ namespace gp { |
|
|
if(value.has_value()) return {value.value(), new_state}; |
|
|
if(value.has_value()) return {value.value(), new_state}; |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
default: |
|
|
|
|
|
|
|
|
case cbor_type::nint: |
|
|
|
|
|
{ |
|
|
|
|
|
auto[value, new_state] = pull_arbitrary_integer_from_cbor(state); |
|
|
|
|
|
if( |
|
|
|
|
|
value.has_value() |
|
|
|
|
|
&& value.value() < (uint64_t)std::numeric_limits<int64_t>::max() |
|
|
|
|
|
) { |
|
|
|
|
|
return {-value.value(), new_state}; |
|
|
|
|
|
} |
|
|
break; |
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
default: break; |
|
|
} |
|
|
} |
|
|
return {nullopt, state}; |
|
|
return {nullopt, state}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct cbor_floating_point final { |
|
|
|
|
|
using backing = gp::fixed_variant< |
|
|
|
|
|
ieee754_hf, |
|
|
|
|
|
float, |
|
|
|
|
|
double |
|
|
|
|
|
>; |
|
|
|
|
|
backing contents; |
|
|
|
|
|
|
|
|
|
|
|
cbor_floating_point(backing& p) |
|
|
|
|
|
: contents{p}{} |
|
|
|
|
|
|
|
|
|
|
|
cbor_floating_point(ieee754_hf p) |
|
|
|
|
|
: contents{p}{} |
|
|
|
|
|
|
|
|
|
|
|
cbor_floating_point(float p) |
|
|
|
|
|
: contents{p}{} |
|
|
|
|
|
|
|
|
|
|
|
cbor_floating_point(double p) |
|
|
|
|
|
: contents{p}{} |
|
|
|
|
|
|
|
|
|
|
|
operator ieee754_hf() { |
|
|
|
|
|
return contents.value<ieee754_hf>(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
operator float() { |
|
|
|
|
|
switch(contents.type()) { |
|
|
|
|
|
case backing::alt<ieee754_hf>(): |
|
|
|
|
|
return contents.value<ieee754_hf>(); |
|
|
|
|
|
case backing::alt<float>(): |
|
|
|
|
|
return contents.value<float>(); |
|
|
|
|
|
default: |
|
|
|
|
|
gp_config::assertion(false,"this code should never be reached"); |
|
|
|
|
|
return std::numeric_limits<float>::quiet_NaN(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
operator double() { |
|
|
|
|
|
switch(contents.type()) { |
|
|
|
|
|
case backing::alt<ieee754_hf>(): |
|
|
|
|
|
return contents.value<ieee754_hf>(); |
|
|
|
|
|
case backing::alt<float>(): |
|
|
|
|
|
return contents.value<float>(); |
|
|
|
|
|
case backing::alt<double>(): |
|
|
|
|
|
return contents.value<double>(); |
|
|
|
|
|
default: |
|
|
|
|
|
gp_config::assertion(false,"this code should never be reached"); |
|
|
|
|
|
return std::numeric_limits<double>::quiet_NaN(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct undefined_t final {}; |
|
|
|
|
|
|
|
|
|
|
|
template<typename T> |
|
|
|
|
|
using cbor_composite = gp::fixed_variant< |
|
|
|
|
|
gp::undefined_t, |
|
|
|
|
|
cbor_number, |
|
|
|
|
|
gp::vector<std::byte>, |
|
|
|
|
|
bool, |
|
|
|
|
|
gp::vector<T>, |
|
|
|
|
|
gp::vector<gp::pair<T, T>>, |
|
|
|
|
|
gp::nullopt_t, |
|
|
|
|
|
cbor_floating_point |
|
|
|
|
|
>; |
|
|
|
|
|
|
|
|
|
|
|
class cbor_value { |
|
|
|
|
|
|
|
|
|
|
|
cbor_composite<cbor_value> contents; |
|
|
|
|
|
gp::reference_wrapper<allocator> alloc; |
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
|
|
cbor_value(allocator& alloc_v) |
|
|
|
|
|
: contents() |
|
|
|
|
|
, alloc(alloc_v) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
cbor_value(cbor_number number, allocator& alloc_v) |
|
|
|
|
|
: contents(number) |
|
|
|
|
|
, alloc(alloc_v) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
cbor_value(cbor_composite<cbor_value> val, allocator& alloc_v) |
|
|
|
|
|
: contents(val) |
|
|
|
|
|
, alloc(alloc_v) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
cbor_value(const cbor_value& oth) |
|
|
|
|
|
: contents(oth.contents) |
|
|
|
|
|
, alloc(oth.alloc) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
cbor_value(cbor_value&& oth) |
|
|
|
|
|
: contents(gp::move(oth.contents)) |
|
|
|
|
|
, alloc(gp::move(oth.alloc)) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
cbor_value& operator=(cbor_value& value) { |
|
|
|
|
|
contents = value.contents; |
|
|
|
|
|
alloc = value.alloc; |
|
|
|
|
|
return *this; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cbor_value& operator=(cbor_value&& value) { |
|
|
|
|
|
gp::swap(contents, value.contents); |
|
|
|
|
|
gp::swap(alloc, value.alloc); |
|
|
|
|
|
return *this; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cbor_value& operator=(cbor_composite<cbor_value>& value) { |
|
|
|
|
|
contents = value; |
|
|
|
|
|
return *this; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<typename T> |
|
|
|
|
|
cbor_value& operator=(T& value) { |
|
|
|
|
|
contents = value; |
|
|
|
|
|
return *this; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<typename T> |
|
|
|
|
|
cbor_value& operator=(T&& value) { |
|
|
|
|
|
contents = gp::move(value); |
|
|
|
|
|
return *this; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto new_array() { |
|
|
|
|
|
return gp::vector<cbor_value>{alloc}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto new_object() { |
|
|
|
|
|
return gp::vector<gp::pair<cbor_value, cbor_value>>{alloc}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static gp::pair<uint64_t, gp::buffer<std::byte>::associated_iterator> decode_integer(gp::buffer<std::byte> src) { |
|
|
|
|
|
#define ERROR return {0, src.begin()}
|
|
|
|
|
|
auto local = (uint8_t)0b00011111 & (uint8_t)src[0]; |
|
|
|
|
|
if(local <= 23) { |
|
|
|
|
|
return {local, src.begin()+1}; |
|
|
|
|
|
} else { |
|
|
|
|
|
switch((cbor_oths)local) { |
|
|
|
|
|
case cbor_oths::byte: { |
|
|
|
|
|
if(src.size()<2) ERROR; |
|
|
|
|
|
return { |
|
|
|
|
|
(uint8_t)*(src.begin()+1), |
|
|
|
|
|
src.begin()+2 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::word: { |
|
|
|
|
|
if(src.size()<3) ERROR; |
|
|
|
|
|
return { |
|
|
|
|
|
uint16_t(*(src.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, endian::big>>().begin().data)), |
|
|
|
|
|
src.begin()+3 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::dword: { |
|
|
|
|
|
if(src.size()<5) ERROR; |
|
|
|
|
|
return { |
|
|
|
|
|
uint32_t(*(src.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, endian::big>>().begin().data)), |
|
|
|
|
|
src.begin()+5 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::qword: { |
|
|
|
|
|
if(src.size()<9) ERROR; |
|
|
|
|
|
return { |
|
|
|
|
|
uint64_t(*(src.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, endian::big>>().begin().data)), |
|
|
|
|
|
src.begin()+9 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
default: { |
|
|
|
|
|
ERROR; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
#undef ERROR
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<typename U> |
|
|
|
|
|
bool is_a() { |
|
|
|
|
|
if constexpr ( |
|
|
|
|
|
std::is_same_v<U, uint8_t> |
|
|
|
|
|
|| std::is_same_v<U, uint16_t> |
|
|
|
|
|
|| std::is_same_v<U, uint32_t> |
|
|
|
|
|
|| std::is_same_v<U, uint64_t> |
|
|
|
|
|
|| std::is_same_v<U, int8_t> |
|
|
|
|
|
|| std::is_same_v<U, int16_t> |
|
|
|
|
|
|| std::is_same_v<U, int32_t> |
|
|
|
|
|
|| std::is_same_v<U, int64_t> |
|
|
|
|
|
) { |
|
|
|
|
|
if(contents.is_a<cbor_number>()) |
|
|
|
|
|
{ |
|
|
|
|
|
auto& v = contents.value<cbor_number>(); |
|
|
|
|
|
if(!std::is_signed_v<U> && v.is_negative()) return false; |
|
|
|
|
|
if( |
|
|
|
|
|
std::numeric_limits<int64_t>::max()<v.value |
|
|
|
|
|
&& ( |
|
|
|
|
|
!std::is_same_v<U, uint64_t> |
|
|
|
|
|
|| v.is_negative() |
|
|
|
|
|
) |
|
|
|
|
|
) return false; |
|
|
|
|
|
int64_t signed_v = (v.is_negative() ? -1 : 1 ) * v.value; |
|
|
|
|
|
if( |
|
|
|
|
|
std::numeric_limits<U>::min() <= signed_v |
|
|
|
|
|
&& std::numeric_limits<U>::max() >= signed_v |
|
|
|
|
|
) return true; |
|
|
|
|
|
return false; |
|
|
|
|
|
} else return false; |
|
|
|
|
|
} else if constexpr ( |
|
|
|
|
|
std::is_same_v<U, ieee754_hf> |
|
|
|
|
|
|| std::is_same_v<U, float> |
|
|
|
|
|
|| std::is_same_v<U, double> |
|
|
|
|
|
) { |
|
|
|
|
|
auto& v = contents.value<cbor_floating_point>(); |
|
|
|
|
|
switch(v.contents.type()) { |
|
|
|
|
|
case cbor_floating_point::backing::alt<ieee754_hf>(): |
|
|
|
|
|
return std::is_same_v<U, ieee754_hf>; |
|
|
|
|
|
case cbor_floating_point::backing::alt<float>(): |
|
|
|
|
|
return std::is_same_v<U, float> || std::is_same_v<U, ieee754_hf>; |
|
|
|
|
|
case cbor_floating_point::backing::alt<double>(): |
|
|
|
|
|
return std::is_same_v<U, double> || std::is_same_v<U, float> || std::is_same_v<U, ieee754_hf>; |
|
|
|
|
|
default: |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
return contents.is_a<U>(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<typename U> |
|
|
|
|
|
U get_value() { |
|
|
|
|
|
gp_config::assertion(is_a<U>(), "can't convert value legally"); |
|
|
|
|
|
if constexpr ( |
|
|
|
|
|
std::is_same_v<U, uint8_t> |
|
|
|
|
|
|| std::is_same_v<U, uint16_t> |
|
|
|
|
|
|| std::is_same_v<U, uint32_t> |
|
|
|
|
|
|| std::is_same_v<U, uint64_t> |
|
|
|
|
|
|| std::is_same_v<U, int8_t> |
|
|
|
|
|
|| std::is_same_v<U, int16_t> |
|
|
|
|
|
|| std::is_same_v<U, int32_t> |
|
|
|
|
|
|| std::is_same_v<U, int64_t> |
|
|
|
|
|
) { |
|
|
|
|
|
auto& v = contents.value<cbor_number>(); |
|
|
|
|
|
return (v.is_negative() ? -1 : 1 ) * v.value; |
|
|
|
|
|
} else if constexpr ( |
|
|
|
|
|
std::is_same_v<U, ieee754_hf> |
|
|
|
|
|
|| std::is_same_v<U, float> |
|
|
|
|
|
|| std::is_same_v<U, double> |
|
|
|
|
|
) { |
|
|
|
|
|
auto& v = contents.value<cbor_floating_point>(); |
|
|
|
|
|
return v; |
|
|
|
|
|
} else { |
|
|
|
|
|
return contents.value<U>(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static gp::pair<cbor_value, gp::buffer<std::byte>::associated_iterator> decode(allocator& alloc, gp::buffer<std::byte> src) { |
|
|
|
|
|
#define ERROR return {cbor_value{alloc}, src.begin()}
|
|
|
|
|
|
if(src.size()==0) ERROR; |
|
|
|
|
|
auto discriminant = (cbor_type)(((uint8_t)*src.begin()) >> 5); |
|
|
|
|
|
auto local = uint8_t(((uint8_t)*src.begin()) & 0b00011111); |
|
|
|
|
|
switch(discriminant) { |
|
|
|
|
|
case cbor_type::uint: |
|
|
|
|
|
case cbor_type::nint: { |
|
|
|
|
|
auto nb = decode_integer(src); |
|
|
|
|
|
return {cbor_value{cbor_number{(bool)discriminant, nb.first}, alloc}, nb.second}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_type::bstr: { |
|
|
|
|
|
gp::vector<std::byte> str{alloc}; |
|
|
|
|
|
if(local == 31) { |
|
|
|
|
|
auto sub = src.slice_end(src.size() - 1); |
|
|
|
|
|
if(!sub.size()) ERROR; |
|
|
|
|
|
while((uint8_t)sub[0] && 0b00011111 != 31) { |
|
|
|
|
|
auto len = decode_integer(sub); |
|
|
|
|
|
if(len.second == sub.begin()) ERROR; |
|
|
|
|
|
str.reserve(str.size() + len.first); |
|
|
|
|
|
auto end = (len.second + len.first); |
|
|
|
|
|
if(len.first + (len.second - src.begin()) > src.size()) ERROR; |
|
|
|
|
|
for(auto it = len.second; it != end; it++) { |
|
|
|
|
|
str.push_back(*it); |
|
|
|
|
|
} |
|
|
|
|
|
sub = sub.slice_end(sub.size() - (len.first + (len.second - sub.begin()))); |
|
|
|
|
|
} |
|
|
|
|
|
return {cbor_value{str, alloc}, sub.begin()+1}; |
|
|
|
|
|
} else if(auto len = decode_integer(src); len.second != src.begin()) { |
|
|
|
|
|
str.reserve(len.first); |
|
|
|
|
|
auto end = (len.second + len.first); |
|
|
|
|
|
if(len.first + (len.second - src.begin()) > src.size()) ERROR; |
|
|
|
|
|
for(auto it = len.second; it != end; it++) { |
|
|
|
|
|
str.push_back(*it); |
|
|
|
|
|
} |
|
|
|
|
|
return {cbor_value{str, alloc}, end}; |
|
|
|
|
|
} |
|
|
|
|
|
ERROR; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_type::tstr: { |
|
|
|
|
|
ERROR; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_type::list: { |
|
|
|
|
|
gp::vector<cbor_value> list{alloc}; |
|
|
|
|
|
if(local == 31) { |
|
|
|
|
|
// TODO: Add the indefinite length version
|
|
|
|
|
|
} else if(auto len = decode_integer(src); len.second != src.begin()) { |
|
|
|
|
|
auto sub = src.slice_end(src.size()-(len.second - src.begin())); |
|
|
|
|
|
while(len.first--) { |
|
|
|
|
|
auto tmp = decode(alloc, sub); |
|
|
|
|
|
if(tmp.second == sub.begin()) ERROR; |
|
|
|
|
|
list.push_back(tmp.first); |
|
|
|
|
|
sub = sub.slice_end(sub.size() - (tmp.second - sub.begin())); |
|
|
|
|
|
} |
|
|
|
|
|
return {cbor_value{list, alloc}, sub.begin()}; |
|
|
|
|
|
} |
|
|
|
|
|
ERROR; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_type::hmap: { |
|
|
|
|
|
gp::vector<gp::pair<cbor_value, cbor_value>> list{alloc}; |
|
|
|
|
|
if(local == 31) { |
|
|
|
|
|
// TODO: Add the indefinite length version
|
|
|
|
|
|
} else if(auto len = decode_integer(src); len.second != src.begin()) { |
|
|
|
|
|
auto sub = src.slice_end(src.size()-(len.second - src.begin())); |
|
|
|
|
|
while(len.first--) { |
|
|
|
|
|
auto tmpl = decode(alloc, sub); |
|
|
|
|
|
if(tmpl.second == sub.begin()) ERROR; |
|
|
|
|
|
sub = sub.slice_end(sub.size() - (tmpl.second - sub.begin())); |
|
|
|
|
|
auto tmpr = decode(alloc, sub); |
|
|
|
|
|
if(tmpr.second == sub.begin()) ERROR; |
|
|
|
|
|
list.push_back(gp::make_pair( |
|
|
|
|
|
tmpl.first, |
|
|
|
|
|
tmpr.first |
|
|
|
|
|
)); |
|
|
|
|
|
sub = sub.slice_end(sub.size() - (tmpr.second - sub.begin())); |
|
|
|
|
|
} |
|
|
|
|
|
return {cbor_value{list, alloc}, sub.begin()}; |
|
|
|
|
|
} |
|
|
|
|
|
ERROR; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_type::tags: { |
|
|
|
|
|
// TODO: add tag decoding methods
|
|
|
|
|
|
} |
|
|
|
|
|
case cbor_type::oths: { |
|
|
|
|
|
switch((cbor_oths)local) { |
|
|
|
|
|
case cbor_oths::value_false: { |
|
|
|
|
|
return { |
|
|
|
|
|
cbor_value{ |
|
|
|
|
|
cbor_composite<cbor_value>(false), |
|
|
|
|
|
alloc |
|
|
|
|
|
}, |
|
|
|
|
|
src.begin()+1 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::value_true: { |
|
|
|
|
|
return { |
|
|
|
|
|
cbor_value{ |
|
|
|
|
|
cbor_composite<cbor_value>(true), |
|
|
|
|
|
alloc |
|
|
|
|
|
}, |
|
|
|
|
|
src.begin()+1 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::value_null: { |
|
|
|
|
|
return { |
|
|
|
|
|
cbor_value{ |
|
|
|
|
|
cbor_composite<cbor_value>(nullopt), |
|
|
|
|
|
alloc |
|
|
|
|
|
}, |
|
|
|
|
|
src.begin()+1 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::value_undefined: { |
|
|
|
|
|
return { |
|
|
|
|
|
cbor_value{ |
|
|
|
|
|
cbor_composite<cbor_value>(undefined_t{}), |
|
|
|
|
|
alloc |
|
|
|
|
|
}, |
|
|
|
|
|
src.begin()+1 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::word: { |
|
|
|
|
|
if(src.size()<3) ERROR; |
|
|
|
|
|
return { |
|
|
|
|
|
cbor_value{ |
|
|
|
|
|
cbor_floating_point{ieee754_hf(*(src.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, endian::big>>().begin().data))}, |
|
|
|
|
|
alloc |
|
|
|
|
|
}, |
|
|
|
|
|
src.begin()+3 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::dword: { |
|
|
|
|
|
if(src.size()<5) ERROR; |
|
|
|
|
|
return { |
|
|
|
|
|
cbor_value{ |
|
|
|
|
|
cbor_floating_point{float(*(src.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, endian::big>>().begin().data))}, |
|
|
|
|
|
alloc |
|
|
|
|
|
}, |
|
|
|
|
|
src.begin()+5 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_oths::qword: { |
|
|
|
|
|
if(src.size()<9) ERROR; |
|
|
|
|
|
return { |
|
|
|
|
|
cbor_value{ |
|
|
|
|
|
cbor_floating_point{double(*(src.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, endian::big>>().begin().data))}, |
|
|
|
|
|
alloc |
|
|
|
|
|
}, |
|
|
|
|
|
src.begin()+9 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
default: { |
|
|
|
|
|
ERROR; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
ERROR; |
|
|
|
|
|
#undef ERROR
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static auto encode_float(buffer<std::byte> dest, cbor_floating_point& value) { |
|
|
|
|
|
switch(value.contents.type()) { |
|
|
|
|
|
case cbor_floating_point::backing::alt<ieee754_hf>():{ |
|
|
|
|
|
if(dest.size() < 3) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::word); |
|
|
|
|
|
(dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, gp::endian::big>>())[0] = value.contents.value<ieee754_hf>(); |
|
|
|
|
|
return dest.begin()+3; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_floating_point::backing::alt<float>():{ |
|
|
|
|
|
if(dest.size() < 5) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::dword); |
|
|
|
|
|
(dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, gp::endian::big>>())[0] = value.contents.value<float>(); |
|
|
|
|
|
return dest.begin()+5; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_floating_point::backing::alt<double>():{ |
|
|
|
|
|
if(dest.size() < 9) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::qword); |
|
|
|
|
|
(dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, gp::endian::big>>())[0] = value.contents.value<double>(); |
|
|
|
|
|
return dest.begin()+9; |
|
|
|
|
|
} |
|
|
|
|
|
default: return dest.begin(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static auto encode_length(buffer<std::byte> dest, cbor_type major, uint64_t value) { |
|
|
|
|
|
auto num = value; |
|
|
|
|
|
if(value <= 23) { |
|
|
|
|
|
if(dest.size() < 1) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)major << 5u) + value); |
|
|
|
|
|
return dest.begin()+1; |
|
|
|
|
|
} else if(value <= 255) { |
|
|
|
|
|
if(dest.size() < 2) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::byte); |
|
|
|
|
|
dest[1] = std::byte(value); |
|
|
|
|
|
return dest.begin() + 2; |
|
|
|
|
|
} else if(value <= 65535) { |
|
|
|
|
|
if(dest.size() < 3) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::word); |
|
|
|
|
|
(dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, gp::endian::big>>())[0] = num; |
|
|
|
|
|
return dest.begin()+3; |
|
|
|
|
|
} else if(value <= 4294967295) { |
|
|
|
|
|
if(dest.size() < 5) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::dword); |
|
|
|
|
|
(dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, gp::endian::big>>())[0] = num; |
|
|
|
|
|
return dest.begin()+5; |
|
|
|
|
|
} else { |
|
|
|
|
|
if(dest.size() < 9) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::qword); |
|
|
|
|
|
(dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, gp::endian::big>>())[0] = num; |
|
|
|
|
|
return dest.begin()+9; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto encode(buffer<std::byte> dest) { |
|
|
|
|
|
switch(contents.type()) { |
|
|
|
|
|
case cbor_composite<cbor_value>::alt<undefined_t>(): { |
|
|
|
|
|
if(dest.size() < 1) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_undefined); |
|
|
|
|
|
return dest.begin()+1; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_composite<cbor_value>::alt<cbor_number>(): { |
|
|
|
|
|
auto& ref = contents.value<cbor_number>(); |
|
|
|
|
|
return encode_length( |
|
|
|
|
|
dest, |
|
|
|
|
|
ref.is_negative() ? cbor_type::nint : cbor_type::uint, |
|
|
|
|
|
ref.value |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_composite<cbor_value>::alt<gp::vector<std::byte>>(): { |
|
|
|
|
|
auto& ref = contents.value<gp::vector<std::byte>>(); |
|
|
|
|
|
auto it = encode_length( |
|
|
|
|
|
dest, |
|
|
|
|
|
cbor_type::bstr, |
|
|
|
|
|
ref.size() |
|
|
|
|
|
); |
|
|
|
|
|
if(it == dest.begin()) return it; |
|
|
|
|
|
|
|
|
|
|
|
for(auto a : ref) { |
|
|
|
|
|
*(it++) = a; |
|
|
|
|
|
} |
|
|
|
|
|
return it; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_composite<cbor_value>::alt<bool>(): { |
|
|
|
|
|
if(dest.size() < 1) return dest.begin(); |
|
|
|
|
|
if(contents.value<bool>()) |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_true); |
|
|
|
|
|
else |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_false); |
|
|
|
|
|
return dest.begin()+1; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_composite<cbor_value>::alt<gp::vector<cbor_value>>(): { |
|
|
|
|
|
auto& ary = contents.value<gp::vector<cbor_value>>(); |
|
|
|
|
|
auto it_begin = encode_length(dest, cbor_type::list, ary.size()); |
|
|
|
|
|
if(it_begin == dest.begin()) return dest.begin(); |
|
|
|
|
|
for(auto& elem : ary) { |
|
|
|
|
|
auto slice = dest.slice_end(dest.size() - (it_begin - dest.begin())); |
|
|
|
|
|
auto it = elem.encode(slice); |
|
|
|
|
|
if(it == it_begin) |
|
|
|
|
|
return dest.begin(); |
|
|
|
|
|
it_begin = it; |
|
|
|
|
|
} |
|
|
|
|
|
return it_begin; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_composite<cbor_value>::alt<gp::vector<gp::pair<cbor_value, cbor_value>>>(): { |
|
|
|
|
|
auto& ary = contents.value<gp::vector<gp::pair<cbor_value,cbor_value>>>(); |
|
|
|
|
|
auto it_begin = encode_length(dest, cbor_type::hmap, ary.size()); |
|
|
|
|
|
if(it_begin == dest.begin()) return dest.begin(); |
|
|
|
|
|
|
|
|
|
|
|
for(auto& elem : ary) { |
|
|
|
|
|
auto slice = dest.slice_end(dest.size() - (it_begin - dest.begin())); |
|
|
|
|
|
auto it = elem.first.encode(slice); |
|
|
|
|
|
if(it == it_begin) return dest.begin(); |
|
|
|
|
|
it_begin = it; |
|
|
|
|
|
|
|
|
|
|
|
slice = dest.slice_end(dest.size() - (it_begin - dest.begin())); |
|
|
|
|
|
it = elem.second.encode(slice); |
|
|
|
|
|
if(it == it_begin) return dest.begin(); |
|
|
|
|
|
it_begin = it; |
|
|
|
|
|
} |
|
|
|
|
|
return it_begin; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_composite<cbor_value>::alt<gp::nullopt_t>(): { |
|
|
|
|
|
if(dest.size() < 1) return dest.begin(); |
|
|
|
|
|
dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_null); |
|
|
|
|
|
return dest.begin()+1; |
|
|
|
|
|
} |
|
|
|
|
|
case cbor_composite<cbor_value>::alt<cbor_floating_point>(): { |
|
|
|
|
|
return encode_float(dest, contents.value<cbor_floating_point>()); |
|
|
|
|
|
} |
|
|
|
|
|
default: return dest.begin(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
} |