mirror of
https://github.com/pj64team/Project64-Legacy.git
synced 2026-04-01 20:25:43 +00:00
* Switch hex editor to full CUSTOMDRAW - This will allow us to draw with more precision. Especially for selection ranges and editing. * Add basic hex selection * Add ASCII column text selection * Ctrl+C to copy selected memory * Fix moving the window * Fix minor bugs in memory viewer with watchpoints - The colors and underlines were only showing when a watchpoint was disabled. - If the last hex byte in a row was underlined, the entire ASCII section would also be underlined on that row. - Now colors always show when a watchpoint exists. And the byte is underlined only when the watchpoint is enabled. * Fix copying the last line of memory with some selection sizes - This bug prevented the last line of the memory view from being copied to the clipboard when the start of the selection was at a higher column number than the end of the selection. - E.g. when address range 0x8000000c-0x80000023 was selected, it would only copy 0x8000000c-0x8000001f, truncating the last line and missing four selected bytes. * Add memory editor bookmarks * Add missing session files to VS project filters
498 lines
20 KiB
C++
498 lines
20 KiB
C++
#pragma once
|
|
// This file is part of CBOR-lite which is copyright Isode Limited
|
|
// and others and released under a MIT license. For details, see the
|
|
// COPYRIGHT.md file in the top-level folder of the CBOR-lite software
|
|
// distribution.
|
|
|
|
#include <exception>
|
|
#include <iterator>
|
|
#include <string>
|
|
#include <type_traits>
|
|
|
|
namespace CborLite {
|
|
|
|
class Exception : public std::exception {
|
|
public:
|
|
Exception() noexcept {
|
|
}
|
|
virtual ~Exception() noexcept = default;
|
|
|
|
Exception(const char *d) noexcept {
|
|
what_ += std::string(": ") + d;
|
|
}
|
|
|
|
Exception(const std::string &d) noexcept {
|
|
what_ += ": " + d;
|
|
}
|
|
|
|
Exception(const Exception &e) noexcept : what_(e.what_) {
|
|
}
|
|
|
|
Exception(Exception &&e) noexcept : what_(std::move(e.what_)) {
|
|
// Note that e.what_ is not re-initialized to "CBOR Exception" as
|
|
// the moved-from object is not expected to ever be reused.
|
|
}
|
|
|
|
Exception &operator=(const Exception &) = delete;
|
|
Exception &operator=(Exception &&) = delete;
|
|
|
|
virtual const char *what() const noexcept {
|
|
return what_.c_str();
|
|
}
|
|
|
|
private:
|
|
std::string what_ = "CBOR Exception";
|
|
};
|
|
|
|
using Tag = std::uint_fast64_t;
|
|
|
|
namespace Major {
|
|
constexpr Tag unsignedInteger = 0u;
|
|
constexpr Tag negativeInteger = 1u << 5;
|
|
constexpr Tag byteString = 2u << 5;
|
|
constexpr Tag textString = 3u << 5;
|
|
constexpr Tag array = 4u << 5;
|
|
constexpr Tag map = 5u << 5;
|
|
constexpr Tag semantic = 6u << 5;
|
|
constexpr Tag floatingPoint = 7u << 5;
|
|
constexpr Tag simple = 7u << 5;
|
|
constexpr Tag mask = 0xe0u;
|
|
} // namespace Major
|
|
|
|
namespace Minor {
|
|
constexpr Tag length1 = 24u;
|
|
constexpr Tag length2 = 25u;
|
|
constexpr Tag length4 = 26u;
|
|
constexpr Tag length8 = 27u;
|
|
|
|
constexpr Tag False = 20u;
|
|
constexpr Tag True = 21u;
|
|
constexpr Tag null = 22u;
|
|
constexpr Tag undefined = 23u;
|
|
constexpr Tag halfFloat = 25u; // not implemented
|
|
constexpr Tag singleFloat = 26u;
|
|
constexpr Tag doubleFloat = 27u;
|
|
|
|
constexpr Tag dataTime = 0u;
|
|
constexpr Tag epochDataTime = 1u;
|
|
constexpr Tag positiveBignum = 2u;
|
|
constexpr Tag negativeBignum = 3u;
|
|
constexpr Tag decimalFraction = 4u;
|
|
constexpr Tag bigfloat = 5u;
|
|
constexpr Tag convertBase64Url = 21u;
|
|
constexpr Tag convertBase64 = 22u;
|
|
constexpr Tag convertBase16 = 23u;
|
|
constexpr Tag cborEncodedData = 24u;
|
|
constexpr Tag uri = 32u;
|
|
constexpr Tag base64Url = 33u;
|
|
constexpr Tag base64 = 34u;
|
|
constexpr Tag regex = 35u;
|
|
constexpr Tag mimeMessage = 36u;
|
|
constexpr Tag selfDescribeCbor = 55799u;
|
|
|
|
constexpr Tag mask = 0x1fu;
|
|
} // namespace Minor
|
|
|
|
constexpr Tag undefined = Major::semantic + Minor::undefined;
|
|
|
|
using Flags = unsigned;
|
|
namespace Flag {
|
|
constexpr Flags none = 0;
|
|
constexpr Flags requireMinimalEncoding = 1 << 0;
|
|
} // namespace Flag
|
|
|
|
template <typename Type>
|
|
typename std::enable_if<std::is_unsigned<Type>::value, std::size_t>::type length(Type val) {
|
|
if (val < 24) return 0;
|
|
for (std::size_t i = 1; i <= ((sizeof val) >> 1); i <<= 1) {
|
|
if (!(val >> (i << 3))) return i;
|
|
}
|
|
return sizeof val;
|
|
}
|
|
|
|
template <typename Buffer>
|
|
typename std::enable_if<std::is_class<Buffer>::value, std::size_t>::type encodeTagAndAdditional(
|
|
Buffer &buffer, Tag tag, Tag additional) {
|
|
buffer.push_back(static_cast<char>(tag + additional));
|
|
return 1;
|
|
}
|
|
|
|
template <typename InputIterator>
|
|
typename std::enable_if<std::is_class<InputIterator>::value, std::size_t>::type decodeTagAndAdditional(
|
|
InputIterator &pos, InputIterator end, Tag &tag, Tag &additional, Flags = Flag::none) {
|
|
if (pos == end) throw Exception("not enough input");
|
|
auto octet = *(pos++);
|
|
tag = octet & Major::mask;
|
|
additional = octet & Minor::mask;
|
|
return 1;
|
|
}
|
|
|
|
// PJ64: Added type specialization for 64-bit values
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value && std::is_unsigned<Type>::value && sizeof(Type) == 8, std::size_t>::type encodeTagAndValue(
|
|
Buffer &buffer, Tag tag, const Type t) {
|
|
auto len = length(t);
|
|
buffer.reserve(buffer.size() + len + 1);
|
|
|
|
switch (len) {
|
|
case 8:
|
|
encodeTagAndAdditional(buffer, tag, Minor::length8);
|
|
break;
|
|
case 4:
|
|
encodeTagAndAdditional(buffer, tag, Minor::length4);
|
|
break;
|
|
case 2:
|
|
encodeTagAndAdditional(buffer, tag, Minor::length2);
|
|
break;
|
|
case 1:
|
|
encodeTagAndAdditional(buffer, tag, Minor::length1);
|
|
break;
|
|
case 0:
|
|
return encodeTagAndAdditional(buffer, tag, t);
|
|
default:
|
|
throw Exception("too long");
|
|
}
|
|
|
|
switch (len) {
|
|
case 8:
|
|
buffer.push_back((t >> 56) & 0xffU);
|
|
buffer.push_back((t >> 48) & 0xffU);
|
|
buffer.push_back((t >> 40) & 0xffU);
|
|
buffer.push_back((t >> 32) & 0xffU);
|
|
case 4:
|
|
buffer.push_back((t >> 24) & 0xffU);
|
|
buffer.push_back((t >> 16) & 0xffU);
|
|
case 2:
|
|
buffer.push_back((t >> 8) & 0xffU);
|
|
case 1:
|
|
buffer.push_back(t & 0xffU);
|
|
}
|
|
|
|
return 1 + len;
|
|
}
|
|
|
|
// PJ64: Added type specialization for 32-bit values
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value && std::is_unsigned<Type>::value && sizeof(Type) == 4, std::size_t>::type encodeTagAndValue(
|
|
Buffer &buffer, Tag tag, const Type t) {
|
|
auto len = length(t);
|
|
buffer.reserve(buffer.size() + len + 1);
|
|
|
|
switch (len) {
|
|
case 4:
|
|
encodeTagAndAdditional(buffer, tag, Minor::length4);
|
|
break;
|
|
case 2:
|
|
encodeTagAndAdditional(buffer, tag, Minor::length2);
|
|
break;
|
|
case 1:
|
|
encodeTagAndAdditional(buffer, tag, Minor::length1);
|
|
break;
|
|
case 0:
|
|
return encodeTagAndAdditional(buffer, tag, t);
|
|
default:
|
|
throw Exception("too long");
|
|
}
|
|
|
|
switch (len) {
|
|
case 4:
|
|
buffer.push_back((t >> 24) & 0xffU);
|
|
buffer.push_back((t >> 16) & 0xffU);
|
|
case 2:
|
|
buffer.push_back((t >> 8) & 0xffU);
|
|
case 1:
|
|
buffer.push_back(t & 0xffU);
|
|
}
|
|
|
|
return 1 + len;
|
|
}
|
|
|
|
// PJ64: Added type specialization for 64-bit values
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value && std::is_unsigned<Type>::value && sizeof(Type) == 8, std::size_t>::type decodeTagAndValue(
|
|
InputIterator &pos, InputIterator end, Tag &tag, Type &t, Flags flags = Flag::none) {
|
|
if (pos == end) throw Exception("not enough input");
|
|
auto additional = Minor::undefined;
|
|
auto len = decodeTagAndAdditional(pos, end, tag, additional, flags);
|
|
if (additional < Minor::length1) {
|
|
t = additional;
|
|
return len;
|
|
}
|
|
t = 0u;
|
|
switch (additional) {
|
|
case Minor::length8:
|
|
if (std::distance(pos, end) < 8) throw Exception("not enough input");
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 56;
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 48;
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 40;
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 32;
|
|
len += 4;
|
|
if ((flags & Flag::requireMinimalEncoding) && !t) throw Exception("encoding not minimal");
|
|
case Minor::length4:
|
|
if (std::distance(pos, end) < 4) throw Exception("not enough input");
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 24;
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 16;
|
|
len += 2;
|
|
if ((flags & Flag::requireMinimalEncoding) && !t) throw Exception("encoding not minimal");
|
|
case Minor::length2:
|
|
if (std::distance(pos, end) < 2) throw Exception("not enough input");
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 8;
|
|
len++;
|
|
if ((flags & Flag::requireMinimalEncoding) && !t) throw Exception("encoding not minimal");
|
|
case Minor::length1:
|
|
if (std::distance(pos, end) < 1) throw Exception("not enough input");
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++)));
|
|
len++;
|
|
if ((flags & Flag::requireMinimalEncoding) && t < 24) throw Exception("encoding not minimal");
|
|
return len;
|
|
}
|
|
throw Exception("bad additional value");
|
|
}
|
|
|
|
// PJ64: Added type specialization for 32-bit values
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value && std::is_unsigned<Type>::value && sizeof(Type) == 4, std::size_t>::type decodeTagAndValue(
|
|
InputIterator &pos, InputIterator end, Tag &tag, Type &t, Flags flags = Flag::none) {
|
|
if (pos == end) throw Exception("not enough input");
|
|
auto additional = Minor::undefined;
|
|
auto len = decodeTagAndAdditional(pos, end, tag, additional, flags);
|
|
if (additional < Minor::length1) {
|
|
t = additional;
|
|
return len;
|
|
}
|
|
t = 0u;
|
|
switch (additional) {
|
|
case Minor::length4:
|
|
if (std::distance(pos, end) < 4) throw Exception("not enough input");
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 24;
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 16;
|
|
len += 2;
|
|
if ((flags & Flag::requireMinimalEncoding) && !t) throw Exception("encoding not minimal");
|
|
case Minor::length2:
|
|
if (std::distance(pos, end) < 2) throw Exception("not enough input");
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++))) << 8;
|
|
len++;
|
|
if ((flags & Flag::requireMinimalEncoding) && !t) throw Exception("encoding not minimal");
|
|
case Minor::length1:
|
|
if (std::distance(pos, end) < 1) throw Exception("not enough input");
|
|
t |= static_cast<Type>(reinterpret_cast<const unsigned char &>(*(pos++)));
|
|
len++;
|
|
if ((flags & Flag::requireMinimalEncoding) && t < 24) throw Exception("encoding not minimal");
|
|
return len;
|
|
}
|
|
throw Exception("bad additional value");
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value, std::size_t>::type encodeUnsigned(Buffer &buffer, const Type &t) {
|
|
return encodeTagAndValue(buffer, Major::unsignedInteger, t);
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value &&std::is_unsigned<Type>::value && !std::is_const<Type>::value,
|
|
std::size_t>::type
|
|
decodeUnsigned(InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, t, flags);
|
|
if (tag != Major::unsignedInteger) throw Exception("not Unsigned");
|
|
return len;
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value, std::size_t>::type encodeNegative(Buffer &buffer, const Type &t) {
|
|
return encodeTagAndValue(buffer, Major::negativeInteger, t);
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value &&std::is_unsigned<Type>::value && !std::is_const<Type>::value,
|
|
std::size_t>::type
|
|
decodeNegative(InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, t, flags);
|
|
if (tag != Major::negativeInteger) throw Exception("not Unsigned");
|
|
return len;
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value, std::size_t>::type encodeInteger(Buffer &buffer, const Type &t) {
|
|
if (t >= 0) {
|
|
unsigned long long val = t;
|
|
return encodeUnsigned(buffer, val);
|
|
} else {
|
|
unsigned long long val = -t - 1;
|
|
return encodeNegative(buffer, val);
|
|
}
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value &&std::is_signed<Type>::value && !std::is_const<Type>::value,
|
|
std::size_t>::type
|
|
decodeInteger(InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
unsigned long long val;
|
|
auto len = decodeTagAndValue(pos, end, tag, val, flags);
|
|
switch (tag) {
|
|
case Major::unsignedInteger:
|
|
t = val;
|
|
break;
|
|
case Major::negativeInteger:
|
|
t = -1 - static_cast<long long>(val);
|
|
break;
|
|
default:
|
|
throw Exception("not integer");
|
|
}
|
|
return len;
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value &&std::is_same<bool, Type>::value, std::size_t>::type encodeBool(
|
|
Buffer &buffer, const Type &t) {
|
|
return encodeTagAndAdditional(buffer, Major::simple, t ? Minor::True : Minor::False);
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value &&std::is_same<bool, Type>::value && !std::is_const<Type>::value,
|
|
std::size_t>::type
|
|
decodeBool(InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto value = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, value, flags);
|
|
if (tag == Major::simple) {
|
|
if (value == Minor::True) {
|
|
t = true;
|
|
return len;
|
|
} else if (value == Minor::False) {
|
|
t = false;
|
|
return len;
|
|
}
|
|
throw Exception("not Boolean");
|
|
}
|
|
throw Exception("not Simple");
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value, std::size_t>::type encodeBytes(Buffer &buffer, const Type &t) {
|
|
auto len = encodeTagAndValue(buffer, Major::byteString, t.size());
|
|
buffer.insert(std::end(buffer), std::begin(t), std::end(t));
|
|
return len + t.size();
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value && !std::is_const<Type>::value, std::size_t>::type decodeBytes(
|
|
InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto value = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, value, flags);
|
|
if (tag != Major::byteString) throw Exception("not ByteString");
|
|
|
|
auto dist = std::distance(pos, end);
|
|
if (dist < static_cast<decltype(dist)>(value)) throw Exception("not enough input");
|
|
t.insert(std::end(t), pos, pos + value);
|
|
std::advance(pos, value);
|
|
return len + value;
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value &&std::is_unsigned<Type>::value, std::size_t>::type encodeEncodedBytesPrefix(
|
|
Buffer &buffer, const Type &t) {
|
|
auto len = encodeTagAndValue(buffer, Major::semantic, Minor::cborEncodedData);
|
|
return len + encodeTagAndValue(buffer, Major::byteString, t);
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value && !std::is_const<Type>::value, std::size_t>::type
|
|
decodeEncodedBytesPrefix(InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto value = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, value, flags);
|
|
if (tag != Major::semantic || value != Minor::cborEncodedData) {
|
|
throw Exception("not CBOR Encoded Data");
|
|
}
|
|
tag = undefined;
|
|
len += decodeTagAndValue(pos, end, tag, value, flags);
|
|
if (tag != Major::byteString) throw Exception("not ByteString");
|
|
t = value;
|
|
return len;
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value, std::size_t>::type encodeEncodedBytes(Buffer &buffer, const Type &t) {
|
|
auto len = encodeTagAndValue(buffer, Major::semantic, Minor::cborEncodedData);
|
|
return len + encodeBytes(buffer, t);
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value && !std::is_const<Type>::value, std::size_t>::type decodeEncodedBytes(
|
|
InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto value = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, value, flags);
|
|
if (tag != Major::semantic || value != Minor::cborEncodedData) {
|
|
throw Exception("not CBOR Encoded Data");
|
|
}
|
|
return len + decodeBytes(pos, end, t, flags);
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value, std::size_t>::type encodeText(Buffer &buffer, const Type &t) {
|
|
auto len = encodeTagAndValue(buffer, Major::textString, t.size());
|
|
buffer.insert(std::end(buffer), std::begin(t), std::end(t));
|
|
return len + t.size();
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value && !std::is_const<Type>::value, std::size_t>::type decodeText(
|
|
InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto value = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, value, flags);
|
|
if (tag != Major::textString) throw Exception("not TextString");
|
|
|
|
auto dist = std::distance(pos, end);
|
|
if (dist < static_cast<decltype(dist)>(value)) throw Exception("not enough input");
|
|
// PJ64: 32-bit plaform support
|
|
if (sizeof(size_t) == 4 && value > UINT32_MAX) {
|
|
throw Exception("TextString too long for 32-bit platforms");
|
|
}
|
|
t.insert(std::end(t), pos, pos + (size_t)value);
|
|
std::advance(pos, (size_t)value);
|
|
return (size_t)(len + value);
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value &&std::is_unsigned<Type>::value, std::size_t>::type encodeArraySize(
|
|
Buffer &buffer, const Type &t) {
|
|
return encodeTagAndValue(buffer, Major::array, t);
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value && !std::is_const<Type>::value &&std::is_unsigned<Type>::value,
|
|
std::size_t>::type
|
|
decodeArraySize(InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto value = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, value, flags);
|
|
if (tag != Major::array) throw Exception("not Array");
|
|
t = value;
|
|
return len;
|
|
}
|
|
|
|
template <typename Buffer, typename Type>
|
|
typename std::enable_if<std::is_class<Buffer>::value &&std::is_unsigned<Type>::value, std::size_t>::type encodeMapSize(
|
|
Buffer &buffer, const Type &t) {
|
|
return encodeTagAndValue(buffer, Major::map, t);
|
|
}
|
|
|
|
template <typename InputIterator, typename Type>
|
|
typename std::enable_if<std::is_class<InputIterator>::value && !std::is_const<Type>::value &&std::is_unsigned<Type>::value,
|
|
std::size_t>::type
|
|
decodeMapSize(InputIterator &pos, InputIterator end, Type &t, Flags flags = Flag::none) {
|
|
auto tag = undefined;
|
|
auto value = undefined;
|
|
auto len = decodeTagAndValue(pos, end, tag, value, flags);
|
|
if (tag != Major::map) throw Exception("not Map");
|
|
t = value;
|
|
return len;
|
|
}
|
|
|
|
} // namespace CborLite
|