|
|
@ -93,6 +93,258 @@ namespace gp { |
|
|
|
return (float)*this; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T> |
|
|
|
vector<char>& push_as_cbor(vector<char>&, T); |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
vector<char>& push_as_cbor(vector<char>&, T&); |
|
|
|
|
|
|
|
inline vector<char>& push_integer_with_header_as_cbor(vector<char>& src, uint8_t header, uint64_t value) { |
|
|
|
auto norm_v = (value<0) ? -value : value; |
|
|
|
if(norm_v <= 23) { |
|
|
|
src.push_back(header+norm_v); |
|
|
|
} else if(norm_v < (1ll<<8ll)) { |
|
|
|
src.push_back(header+24); |
|
|
|
src.push_back(norm_v); |
|
|
|
} else if(norm_v < (1ll<<16ll)) { |
|
|
|
endian_wrapper<uint16_t, endian::big> wrapper = norm_v; |
|
|
|
src.push_back(header+25); |
|
|
|
for(auto byte : wrapper.bytes) { |
|
|
|
src.push_back(byte); |
|
|
|
} |
|
|
|
} else if(norm_v < (1ll<<32ll)) { |
|
|
|
endian_wrapper<uint32_t, endian::big> wrapper = norm_v; |
|
|
|
src.push_back(header+26); |
|
|
|
for(auto byte : wrapper.bytes) { |
|
|
|
src.push_back(byte); |
|
|
|
} |
|
|
|
} else { |
|
|
|
endian_wrapper<uint64_t, endian::big> wrapper = norm_v; |
|
|
|
src.push_back(header+27); |
|
|
|
for(auto byte : wrapper.bytes) { |
|
|
|
src.push_back(byte); |
|
|
|
} |
|
|
|
} |
|
|
|
return src; |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Pushes an integer as CBOR on the vector |
|
|
|
* |
|
|
|
* @param src the vector on which the push happens |
|
|
|
* @param value the value to push, can be signed |
|
|
|
* @return vector<char>& the same reference that was received for the source |
|
|
|
*/ |
|
|
|
template<> |
|
|
|
vector<char>& push_as_cbor<int64_t>(vector<char>& src, int64_t& value) { |
|
|
|
uint8_t sign = (value<0) ? 0b00100000 : 0; |
|
|
|
auto norm_v = (value<0) ? -value : value; |
|
|
|
return push_integer_with_header_as_cbor(src, sign, norm_v); |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Pushes an unsigned integer as CBOR on the vector |
|
|
|
* |
|
|
|
* @param src the vector on which the push happens |
|
|
|
* @param value the value to push, cannot be signed |
|
|
|
* @return vector<char>& the same reference that was received for the source |
|
|
|
*/ |
|
|
|
template<> |
|
|
|
vector<char>& push_as_cbor<uint64_t>(vector<char>& src, uint64_t& value) { |
|
|
|
return push_integer_with_header_as_cbor(src, 0, value); |
|
|
|
} |
|
|
|
|
|
|
|
template<> |
|
|
|
vector<char>& push_as_cbor<std::nullptr_t>(vector<char>& src, std::nullptr_t) { |
|
|
|
src.push_back(0b11110110); |
|
|
|
return src; |
|
|
|
} |
|
|
|
|
|
|
|
struct cbor_undefined{}; |
|
|
|
|
|
|
|
template<> |
|
|
|
vector<char>& push_as_cbor<cbor_undefined>(vector<char>& src, cbor_undefined) { |
|
|
|
src.push_back(0b11110111); |
|
|
|
return src; |
|
|
|
} |
|
|
|
|
|
|
|
template<> |
|
|
|
vector<char>& push_as_cbor<bool>(vector<char>& src, bool value) { |
|
|
|
src.push_back(0b11110100+(value ? 1 : 0)); |
|
|
|
return src; |
|
|
|
} |
|
|
|
|
|
|
|
template<> |
|
|
|
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()); |
|
|
|
for(auto byte : value) { |
|
|
|
src.push_back(byte); |
|
|
|
} |
|
|
|
return src; |
|
|
|
} |
|
|
|
|
|
|
|
struct cbor_array_initiator { |
|
|
|
size_t size; |
|
|
|
}; |
|
|
|
|
|
|
|
struct cbor_associative_array_initiator { |
|
|
|
size_t size; |
|
|
|
}; |
|
|
|
|
|
|
|
template<> |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
template<> |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
template<typename First, typename Second> |
|
|
|
vector<char>& push_as_cbor(vector<char>& src, gp::pair<First, Second>& value) { |
|
|
|
push_as_cbor<First>(src,value.first); |
|
|
|
return push_as_cbor<Second>(src,value.second); |
|
|
|
} |
|
|
|
|
|
|
|
struct cbor_tag_initiator { |
|
|
|
union { |
|
|
|
size_t as_integer; |
|
|
|
cbor_tags tag; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
template<> |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
using parsing_state = gp::buffer<char>; |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
gp::pair<gp::optional<T>, parsing_state> read_cbor(parsing_state state); |
|
|
|
|
|
|
|
inline gp::pair<gp::optional<uint64_t>, parsing_state> pull_arbitrary_integer_from_cbor(parsing_state state) { |
|
|
|
auto local = (uint8_t)0b00011111 & (uint8_t)*state.begin(); |
|
|
|
if(local <= 23) { |
|
|
|
return {*state.begin(), {state.begin()+1, state.end()}}; |
|
|
|
} else { |
|
|
|
switch((cbor_oths)local) { |
|
|
|
case cbor_oths::byte: { |
|
|
|
if(state.size() < 2) return {nullopt, state}; |
|
|
|
return {*(state.begin()+1), {state.begin()+2, state.end()}}; |
|
|
|
} |
|
|
|
case cbor_oths::word: { |
|
|
|
if(state.size() < 3) return {nullopt, state}; |
|
|
|
return { |
|
|
|
uint16_t(*(state.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, endian::big>>().begin().data)), |
|
|
|
{state.begin()+3, state.end()} |
|
|
|
}; |
|
|
|
} |
|
|
|
case cbor_oths::dword: { |
|
|
|
if(state.size() < 5) return {nullopt, state}; |
|
|
|
return { |
|
|
|
uint32_t(*(state.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, endian::big>>().begin().data)), |
|
|
|
{state.begin()+5, state.end()} |
|
|
|
}; |
|
|
|
} |
|
|
|
case cbor_oths::qword: { |
|
|
|
if(state.size() < 9) return {nullopt, state}; |
|
|
|
return { |
|
|
|
uint64_t(*(state.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, endian::big>>().begin().data)), |
|
|
|
{state.begin()+9, state.end()} |
|
|
|
}; |
|
|
|
} |
|
|
|
default: { |
|
|
|
return {nullopt, state}; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template<> |
|
|
|
gp::pair<gp::optional<int64_t>, parsing_state> read_cbor<int64_t>(parsing_state state) { |
|
|
|
if(state.size()) return {nullopt, state}; |
|
|
|
auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5); |
|
|
|
|
|
|
|
int64_t sign = type == cbor_type::nint ? -1 : 1; |
|
|
|
|
|
|
|
switch(type) { |
|
|
|
case cbor_type::uint: |
|
|
|
case cbor_type::nint: |
|
|
|
{ |
|
|
|
auto[value, new_state] = pull_arbitrary_integer_from_cbor(state); |
|
|
|
if(value.has_value()) return {value.value() * sign, new_state}; |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
return {nullopt, state}; |
|
|
|
} |
|
|
|
|
|
|
|
template<> |
|
|
|
gp::pair<gp::optional<uint64_t>, parsing_state> read_cbor<uint64_t>(parsing_state state) { |
|
|
|
if(state.size()) return {nullopt, state}; |
|
|
|
auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5); |
|
|
|
|
|
|
|
switch(type) { |
|
|
|
case cbor_type::uint: |
|
|
|
{ |
|
|
|
auto[value, new_state] = pull_arbitrary_integer_from_cbor(state); |
|
|
|
if(value.has_value()) return {value.value(), new_state}; |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
return {nullopt, state}; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct cbor_floating_point final { |
|
|
|
using backing = gp::fixed_variant< |
|
|
|