|
|
@ -1,5 +1,6 @@ |
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <gp/algorithm/repeat.hpp>
|
|
|
|
#include <gp/bitops.hpp>
|
|
|
|
#include <gp/optional.hpp>
|
|
|
|
#include <gp/pair.hpp>
|
|
|
@ -169,6 +170,49 @@ namespace gp { |
|
|
|
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(*(gp::endian_wrapper<uint16_t, endian::big>*)(src.begin().data)), |
|
|
|
src.begin()+3 |
|
|
|
}; |
|
|
|
} |
|
|
|
case cbor_oths::dword: { |
|
|
|
if(src.size()<5) ERROR; |
|
|
|
return { |
|
|
|
uint32_t(*(gp::endian_wrapper<uint32_t, endian::big>*)(src.begin().data)), |
|
|
|
src.begin()+5 |
|
|
|
}; |
|
|
|
} |
|
|
|
case cbor_oths::qword: { |
|
|
|
if(src.size()<9) ERROR; |
|
|
|
return { |
|
|
|
uint64_t(*(gp::endian_wrapper<uint64_t, endian::big>*)(src.begin().data)), |
|
|
|
src.begin()+9 |
|
|
|
}; |
|
|
|
} |
|
|
|
default: { |
|
|
|
ERROR; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#undef ERROR
|
|
|
|
} |
|
|
|
|
|
|
|
static gp::pair<cbor_value, gp::buffer<std::byte>::associated_iterator> decode(allocator& alloc, gp::buffer<std::byte> src) { |
|
|
|
#define ERROR return {cbor_value{undefined_t{}, alloc}, src.begin()}
|
|
|
|
if(src.size()==0) ERROR; |
|
|
@ -177,67 +221,77 @@ namespace gp { |
|
|
|
switch(discriminant) { |
|
|
|
case cbor_type::uint: |
|
|
|
case cbor_type::nint: { |
|
|
|
if(local <= 23) { |
|
|
|
return {cbor_value{cbor_number{(bool)discriminant, local}, alloc}, src.begin()+1}; |
|
|
|
} else { |
|
|
|
switch((cbor_oths)local) { |
|
|
|
case cbor_oths::byte: { |
|
|
|
if(src.size()<2) ERROR; |
|
|
|
return { |
|
|
|
cbor_value{ |
|
|
|
cbor_number{(bool)discriminant, (uint8_t)*(src.begin()+1)}, |
|
|
|
alloc |
|
|
|
}, |
|
|
|
src.begin()+2 |
|
|
|
}; |
|
|
|
} |
|
|
|
case cbor_oths::word: { |
|
|
|
if(src.size()<3) ERROR; |
|
|
|
return { |
|
|
|
cbor_value{ |
|
|
|
cbor_number{(bool)discriminant, uint16_t(*(gp::endian_wrapper<uint16_t, endian::big>*)(src.begin().data))}, |
|
|
|
alloc |
|
|
|
}, |
|
|
|
src.begin()+3 |
|
|
|
}; |
|
|
|
} |
|
|
|
case cbor_oths::dword: { |
|
|
|
if(src.size()<5) ERROR; |
|
|
|
return { |
|
|
|
cbor_value{ |
|
|
|
cbor_number{(bool)discriminant, uint32_t(*(gp::endian_wrapper<uint32_t, endian::big>*)(src.begin().data))}, |
|
|
|
alloc |
|
|
|
}, |
|
|
|
src.begin()+5 |
|
|
|
}; |
|
|
|
} |
|
|
|
case cbor_oths::qword: { |
|
|
|
if(src.size()<9) ERROR; |
|
|
|
return { |
|
|
|
cbor_value{ |
|
|
|
cbor_number{(bool)discriminant, uint64_t(*(gp::endian_wrapper<uint64_t, endian::big>*)(src.begin().data))}, |
|
|
|
alloc |
|
|
|
}, |
|
|
|
src.begin()+9 |
|
|
|
}; |
|
|
|
} |
|
|
|
default: { |
|
|
|
ERROR; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
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: { |
|
|
|
|
|
|
@ -317,6 +371,7 @@ namespace gp { |
|
|
|
} |
|
|
|
} |
|
|
|
ERROR; |
|
|
|
#undef ERROR
|
|
|
|
} |
|
|
|
|
|
|
|
static auto encode_float(buffer<std::byte> dest, cbor_floating_point& value) { |
|
|
|