Browse Source

Added bytestring parsing as well as part of the array and object decoding

cbor
Ludovic 'Archivist' Lagouardette 3 years ago
parent
commit
39aa87645f
1 changed files with 107 additions and 52 deletions
  1. +107
    -52
      include/gp/enveloppe/cbor.hpp

+ 107
- 52
include/gp/enveloppe/cbor.hpp View File

@ -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) {

Loading…
Cancel
Save