diff --git a/include/gp/enveloppe/cbor.hpp b/include/gp/enveloppe/cbor.hpp index dbc80ac..1a530f8 100644 --- a/include/gp/enveloppe/cbor.hpp +++ b/include/gp/enveloppe/cbor.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -169,6 +170,49 @@ namespace gp { return gp::vector>{alloc}; } + static gp::pair::associated_iterator> decode_integer(gp::buffer 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*)(src.begin().data)), + src.begin()+3 + }; + } + case cbor_oths::dword: { + if(src.size()<5) ERROR; + return { + uint32_t(*(gp::endian_wrapper*)(src.begin().data)), + src.begin()+5 + }; + } + case cbor_oths::qword: { + if(src.size()<9) ERROR; + return { + uint64_t(*(gp::endian_wrapper*)(src.begin().data)), + src.begin()+9 + }; + } + default: { + ERROR; + } + } + } + #undef ERROR + } + static gp::pair::associated_iterator> decode(allocator& alloc, gp::buffer 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*)(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*)(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*)(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 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 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> 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 dest, cbor_floating_point& value) {