2018-12-30 03:33:15 +01:00
|
|
|
#include "msgpack11.hpp"
|
|
|
|
#include <cassert>
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <limits>
|
|
|
|
#include <array>
|
|
|
|
#include <tuple>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <functional>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
namespace msgpack11 {
|
|
|
|
|
|
|
|
static const int max_depth = 200;
|
|
|
|
|
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
using std::map;
|
|
|
|
using std::make_shared;
|
|
|
|
using std::initializer_list;
|
|
|
|
using std::move;
|
|
|
|
|
|
|
|
/* Helper for representing null - just a do-nothing struct, plus comparison
|
|
|
|
* operators so the helpers in MsgPackValue work. We can't use nullptr_t because
|
|
|
|
* it may not be orderable.
|
|
|
|
*/
|
|
|
|
struct NullStruct {
|
|
|
|
bool operator==(NullStruct) const { return true; }
|
|
|
|
bool operator<(NullStruct) const { return false; }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* MasPackValue
|
|
|
|
*/
|
|
|
|
|
|
|
|
class MsgPackValue {
|
|
|
|
public:
|
|
|
|
virtual bool equals(const MsgPackValue * other) const = 0;
|
|
|
|
virtual bool less(const MsgPackValue * other) const = 0;
|
|
|
|
virtual void dump(std::string &out) const = 0;
|
|
|
|
virtual MsgPack::Type type() const = 0;
|
|
|
|
virtual double number_value() const;
|
|
|
|
virtual float float32_value() const;
|
|
|
|
virtual double float64_value() const;
|
|
|
|
virtual int32_t int_value() const;
|
|
|
|
virtual int8_t int8_value() const;
|
|
|
|
virtual int16_t int16_value() const;
|
|
|
|
virtual int32_t int32_value() const;
|
|
|
|
virtual int64_t int64_value() const;
|
|
|
|
virtual uint8_t uint8_value() const;
|
|
|
|
virtual uint16_t uint16_value() const;
|
|
|
|
virtual uint32_t uint32_value() const;
|
|
|
|
virtual uint64_t uint64_value() const;
|
|
|
|
virtual bool bool_value() const;
|
|
|
|
virtual const std::string &string_value() const;
|
|
|
|
virtual const MsgPack::array &array_items() const;
|
|
|
|
virtual const MsgPack::binary &binary_items() const;
|
|
|
|
virtual const MsgPack &operator[](size_t i) const;
|
|
|
|
virtual const MsgPack::object &object_items() const;
|
|
|
|
virtual const MsgPack &operator[](const std::string &key) const;
|
|
|
|
virtual const MsgPack::extension &extension_items() const;
|
|
|
|
virtual ~MsgPackValue() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Serialization
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
static const union {
|
|
|
|
uint16_t dummy;
|
|
|
|
uint8_t bytes[2];
|
|
|
|
} endian_check_data { 0x0001 };
|
|
|
|
static const bool is_big_endian = endian_check_data.bytes[0] == 0x00;
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
struct EndianConverter {
|
|
|
|
union {
|
|
|
|
T packed;
|
|
|
|
std::array<uint8_t, sizeof(T)> bytes;
|
|
|
|
} value;
|
|
|
|
};
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
void dump_data(T value, std::string &out)
|
|
|
|
{
|
|
|
|
EndianConverter<T> converter;
|
|
|
|
converter.value.packed = value;
|
|
|
|
|
|
|
|
auto f = [&](uint8_t byte) {
|
|
|
|
out.push_back(byte);
|
|
|
|
};
|
|
|
|
|
|
|
|
if(is_big_endian)
|
|
|
|
{
|
|
|
|
std::for_each(converter.value.bytes.begin(), converter.value.bytes.end(), f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::for_each(converter.value.bytes.rbegin(), converter.value.bytes.rend(), f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* MZ HACK: Address additional newer versions of clang complaining when size_t is equivalent to uint32_t
|
|
|
|
*/
|
|
|
|
static void verify_length(size_t len)
|
|
|
|
{
|
|
|
|
constexpr bool size_t_greater_than_uint32_t = sizeof(size_t) > sizeof(uint32_t);
|
|
|
|
|
|
|
|
// Lengths must be 32-bit or less, so only check when size_t can represent values greater than 32-bit
|
|
|
|
if (size_t_greater_than_uint32_t)
|
|
|
|
{
|
|
|
|
static_assert(sizeof(size_t) <= sizeof(uint64_t), "Times changed and size_t grew");
|
|
|
|
if (static_cast<uint64_t>(len) > 0xffffffff)
|
|
|
|
throw std::runtime_error("exceeded maximum data length");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(NullStruct, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xc0);
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(float value, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xca);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(value, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(double value, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xcb);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(value, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(int8_t value, std::string &out) {
|
|
|
|
if( value < -32 )
|
|
|
|
{
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd0);
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
out.push_back(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(int16_t value, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd1);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(value, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(int32_t value, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd2);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(value, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(int64_t value, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd3);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(value, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(uint8_t value, std::string &out) {
|
|
|
|
if(128 <= value)
|
|
|
|
{
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xcc);
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
out.push_back(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(uint16_t value, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xcd);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(value, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(uint32_t value, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xce);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(value, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(uint64_t value, std::string &out) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xcf);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(value, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(bool value, std::string &out) {
|
|
|
|
const uint8_t msgpack_value = (value) ? 0xc3 : 0xc2;
|
|
|
|
out.push_back(msgpack_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(const std::string& value, std::string &out) {
|
|
|
|
size_t const len = value.size();
|
|
|
|
verify_length(len);
|
|
|
|
if(len <= 0x1f)
|
|
|
|
{
|
|
|
|
uint8_t const first_byte = 0xa0 | static_cast<uint8_t>(len);
|
|
|
|
out.push_back(first_byte);
|
|
|
|
}
|
|
|
|
else if(len <= 0xff)
|
|
|
|
{
|
|
|
|
uint8_t const length = static_cast<uint8_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd9);
|
2018-12-30 03:33:15 +01:00
|
|
|
out.push_back(length);
|
|
|
|
}
|
|
|
|
else if(len <= 0xffff)
|
|
|
|
{
|
|
|
|
uint16_t const length = static_cast<uint16_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xda);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t const length = static_cast<uint32_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xdb);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::for_each(std::begin(value), std::end(value), [&out](char v){
|
|
|
|
dump_data(v, out);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(const MsgPack::array& value, std::string &out) {
|
|
|
|
size_t const len = value.size();
|
|
|
|
verify_length(len);
|
|
|
|
if(len <= 15)
|
|
|
|
{
|
|
|
|
uint8_t const first_byte = 0x90 | static_cast<uint8_t>(len);
|
|
|
|
out.push_back(first_byte);
|
|
|
|
}
|
|
|
|
else if(len <= 0xffff)
|
|
|
|
{
|
|
|
|
uint16_t const length = static_cast<uint16_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xdc);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t const length = static_cast<uint32_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xdd);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::for_each(std::begin(value), std::end(value), [&out](MsgPack::array::value_type const& v){
|
|
|
|
v.dump(out);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(const MsgPack::object& value, std::string &out) {
|
|
|
|
size_t const len = value.size();
|
|
|
|
verify_length(len);
|
|
|
|
if(len <= 15)
|
|
|
|
{
|
|
|
|
uint8_t const first_byte = 0x80 | static_cast<uint8_t>(len);
|
|
|
|
out.push_back(first_byte);
|
|
|
|
}
|
|
|
|
else if(len <= 0xffff)
|
|
|
|
{
|
|
|
|
uint16_t const length = static_cast<uint16_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xde);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t const length = static_cast<uint32_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xdf);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::for_each(std::begin(value), std::end(value), [&out](MsgPack::object::value_type const& v){
|
|
|
|
v.first.dump(out);
|
|
|
|
v.second.dump(out);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(const MsgPack::binary& value, std::string &out) {
|
|
|
|
size_t const len = value.size();
|
|
|
|
verify_length(len);
|
|
|
|
if(len <= 0xff)
|
|
|
|
{
|
|
|
|
uint8_t const length = static_cast<uint8_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xc4);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
else if(len <= 0xffff)
|
|
|
|
{
|
|
|
|
uint16_t const length = static_cast<uint16_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xc5);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t const length = static_cast<uint32_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xc6);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::for_each(std::begin(value), std::end(value), [&out](MsgPack::binary::value_type const& v){
|
|
|
|
out.push_back(v);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump(const MsgPack::extension& value, std::string &out) {
|
|
|
|
const uint8_t type = std::get<0>( value );
|
|
|
|
const MsgPack::binary& data = std::get<1>( value );
|
|
|
|
const size_t len = data.size();
|
|
|
|
verify_length(len);
|
|
|
|
|
|
|
|
if(len == 0x01) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd4);
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
else if(len == 0x02) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd5);
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
else if(len == 0x04) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd6);
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
else if(len == 0x08) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd7);
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
else if(len == 0x10) {
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xd8);
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
else if(len <= 0xff) {
|
|
|
|
uint8_t const length = static_cast<uint8_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xc7);
|
2018-12-30 03:33:15 +01:00
|
|
|
out.push_back(length);
|
|
|
|
}
|
|
|
|
else if(len <= 0xffff) {
|
|
|
|
uint16_t const length = static_cast<uint16_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xc8);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
uint32_t const length = static_cast<uint32_t>(len);
|
2019-05-11 06:17:05 +02:00
|
|
|
out.push_back((char) 0xc9);
|
2018-12-30 03:33:15 +01:00
|
|
|
dump_data(length, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
out.push_back(type);
|
|
|
|
std::for_each(std::begin(data), std::end(data), [&out](uint8_t const& v){
|
|
|
|
out.push_back(v);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MsgPack::dump(std::string &out) const {
|
|
|
|
m_ptr->dump(out);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Value wrappers
|
|
|
|
*/
|
|
|
|
|
|
|
|
template <MsgPack::Type tag, typename T>
|
|
|
|
class Value : public MsgPackValue {
|
|
|
|
protected:
|
|
|
|
|
|
|
|
// Constructors
|
|
|
|
explicit Value(const T &value) : m_value(value) {}
|
|
|
|
explicit Value(T &&value) : m_value(move(value)) {}
|
|
|
|
|
|
|
|
// Get type tag
|
|
|
|
MsgPack::Type type() const override {
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Comparisons
|
|
|
|
bool equals(const MsgPackValue * other) const override {
|
|
|
|
bool const is_same_type = tag == other->type();
|
|
|
|
return is_same_type && (m_value == static_cast<const Value<tag, T> *>(other)->m_value);
|
|
|
|
}
|
|
|
|
bool less(const MsgPackValue * other) const override {
|
|
|
|
bool const is_same_type = tag == other->type();
|
|
|
|
bool const is_less_type = tag < other->type();
|
|
|
|
return is_less_type || (is_same_type && (m_value < static_cast<const Value<tag, T> *>(other)->m_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
const T m_value;
|
|
|
|
void dump(std::string &out) const override { msgpack11::dump(m_value, out); }
|
|
|
|
};
|
|
|
|
|
|
|
|
bool equal_uint64_int64( uint64_t uint64_value, int64_t int64_value )
|
|
|
|
{
|
|
|
|
bool const is_positive = 0 <= int64_value;
|
|
|
|
bool const is_leq_int64_max = uint64_value <= std::numeric_limits<int64_t>::max();
|
|
|
|
return is_positive && is_leq_int64_max && ( uint64_value == static_cast<uint64_t>(int64_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool less_uint64_int64( uint64_t uint64_value, int64_t int64_value )
|
|
|
|
{
|
|
|
|
bool const is_positive = 0 <= int64_value;
|
|
|
|
bool const is_leq_int64_max = uint64_value <= std::numeric_limits<int64_t>::max();
|
|
|
|
return is_positive && is_leq_int64_max && ( uint64_value < static_cast<uint64_t>(int64_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool less_int64_uint64( int64_t int64_value, uint64_t uint64_value )
|
|
|
|
{
|
|
|
|
bool const is_negative = int64_value < 0;
|
|
|
|
bool const is_gt_int64_max = std::numeric_limits<int64_t>::max() < uint64_value;
|
|
|
|
return is_negative || is_gt_int64_max || ( static_cast<uint64_t>(int64_value) < uint64_value );
|
|
|
|
}
|
|
|
|
|
|
|
|
template <MsgPack::Type tag, typename T>
|
|
|
|
class NumberValue : public Value<tag, T> {
|
|
|
|
protected:
|
|
|
|
|
|
|
|
// Constructors
|
|
|
|
explicit NumberValue(const T &value) : Value<tag, T>(value) {}
|
|
|
|
explicit NumberValue(T &&value) : Value<tag, T>(move(value)) {}
|
|
|
|
|
|
|
|
bool equals(const MsgPackValue * other) const override {
|
|
|
|
switch( other->type() )
|
|
|
|
{
|
|
|
|
case MsgPack::FLOAT32 : // fall through
|
|
|
|
case MsgPack::FLOAT64 : // fall through
|
|
|
|
case MsgPack::UINT8 : // fall through
|
|
|
|
case MsgPack::UINT16 : // fall through
|
|
|
|
case MsgPack::UINT32 : // fall through
|
|
|
|
case MsgPack::UINT64 : // fall through
|
|
|
|
case MsgPack::INT8 : // fall through
|
|
|
|
case MsgPack::INT16 : // fall through
|
|
|
|
case MsgPack::INT32 : // fall through
|
|
|
|
case MsgPack::INT64 : // fall through
|
|
|
|
{
|
|
|
|
return float64_value() == other->float64_value();
|
|
|
|
} break;
|
|
|
|
default :
|
|
|
|
{
|
|
|
|
return Value<tag,T>::equals( other );
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool less(const MsgPackValue * other) const override {
|
|
|
|
switch( other->type() )
|
|
|
|
{
|
|
|
|
case MsgPack::FLOAT32 : // fall through
|
|
|
|
case MsgPack::FLOAT64 : // fall through
|
|
|
|
case MsgPack::UINT8 : // fall through
|
|
|
|
case MsgPack::UINT16 : // fall through
|
|
|
|
case MsgPack::UINT32 : // fall through
|
|
|
|
case MsgPack::UINT64 : // fall through
|
|
|
|
case MsgPack::INT8 : // fall through
|
|
|
|
case MsgPack::INT16 : // fall through
|
|
|
|
case MsgPack::INT32 : // fall through
|
|
|
|
case MsgPack::INT64 : // fall through
|
|
|
|
{
|
|
|
|
return float64_value() < other->float64_value();
|
|
|
|
} break;
|
|
|
|
default :
|
|
|
|
{
|
|
|
|
return Value<tag,T>::less( other );
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double number_value() const override { return static_cast<double>( Value<tag,T>::m_value ); }
|
|
|
|
float float32_value() const override { return static_cast<float>( Value<tag,T>::m_value ); }
|
|
|
|
double float64_value() const override { return static_cast<double>( Value<tag,T>::m_value ); }
|
|
|
|
int32_t int_value() const override { return static_cast<int32_t>( Value<tag,T>::m_value ); }
|
|
|
|
int8_t int8_value() const override { return static_cast<int8_t>( Value<tag,T>::m_value ); }
|
|
|
|
int16_t int16_value() const override { return static_cast<int16_t>( Value<tag,T>::m_value ); }
|
|
|
|
int32_t int32_value() const override { return static_cast<int32_t>( Value<tag,T>::m_value ); }
|
|
|
|
int64_t int64_value() const override { return static_cast<int64_t>( Value<tag,T>::m_value ); }
|
|
|
|
uint8_t uint8_value() const override { return static_cast<uint8_t>( Value<tag,T>::m_value ); }
|
|
|
|
uint16_t uint16_value() const override { return static_cast<uint16_t>( Value<tag,T>::m_value ); }
|
|
|
|
uint32_t uint32_value() const override { return static_cast<uint32_t>( Value<tag,T>::m_value ); }
|
|
|
|
uint64_t uint64_value() const override { return static_cast<uint64_t>( Value<tag,T>::m_value ); }
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackFloat final : public NumberValue<MsgPack::FLOAT32, float> {
|
|
|
|
public:
|
|
|
|
explicit MsgPackFloat(float value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackDouble final : public NumberValue<MsgPack::FLOAT64, double> {
|
|
|
|
public:
|
|
|
|
explicit MsgPackDouble(double value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackInt8 final : public NumberValue<MsgPack::INT8, int8_t> {
|
|
|
|
public:
|
|
|
|
explicit MsgPackInt8(int8_t value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackInt16 final : public NumberValue<MsgPack::INT16, int16_t> {
|
|
|
|
public:
|
|
|
|
explicit MsgPackInt16(int16_t value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackInt32 final : public NumberValue<MsgPack::INT32, int32_t> {
|
|
|
|
public:
|
|
|
|
explicit MsgPackInt32(int32_t value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackInt64 final : public NumberValue<MsgPack::INT64, int64_t> {
|
|
|
|
bool equals(const MsgPackValue * other) const override
|
|
|
|
{
|
|
|
|
switch( other->type() )
|
|
|
|
{
|
|
|
|
case MsgPack::INT64 :
|
|
|
|
{
|
|
|
|
return int64_value() == other->int64_value();
|
|
|
|
} break;
|
|
|
|
case MsgPack::UINT64 :
|
|
|
|
{
|
|
|
|
return equal_uint64_int64( other->uint64_value(), int64_value() );
|
|
|
|
} break;
|
|
|
|
default :
|
|
|
|
{
|
|
|
|
return NumberValue<MsgPack::INT64, int64_t>::equals( other );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool less(const MsgPackValue * other) const override
|
|
|
|
{
|
|
|
|
switch( other->type() )
|
|
|
|
{
|
|
|
|
case MsgPack::INT64 :
|
|
|
|
{
|
|
|
|
return int64_value() < other->int64_value();
|
|
|
|
} break;
|
|
|
|
case MsgPack::UINT64 :
|
|
|
|
{
|
|
|
|
return less_int64_uint64( int64_value(), other->uint64_value() );
|
|
|
|
} break;
|
|
|
|
default :
|
|
|
|
{
|
|
|
|
return NumberValue<MsgPack::INT64, int64_t>::less( other );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
explicit MsgPackInt64(int64_t value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackUint8 final : public NumberValue<MsgPack::UINT8, uint8_t> {
|
|
|
|
public:
|
|
|
|
explicit MsgPackUint8(uint8_t value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackUint16 final : public NumberValue<MsgPack::UINT16, uint16_t> {
|
|
|
|
public:
|
|
|
|
explicit MsgPackUint16(uint16_t value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackUint32 final : public NumberValue<MsgPack::UINT32, uint32_t> {
|
|
|
|
public:
|
|
|
|
explicit MsgPackUint32(uint32_t value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackUint64 final : public NumberValue<MsgPack::UINT64, uint64_t> {
|
|
|
|
bool equals(const MsgPackValue * other) const override
|
|
|
|
{
|
|
|
|
switch( other->type() )
|
|
|
|
{
|
|
|
|
case MsgPack::INT64 :
|
|
|
|
{
|
|
|
|
return equal_uint64_int64( uint64_value(), other->int64_value() );
|
|
|
|
} break;
|
|
|
|
case MsgPack::UINT64 :
|
|
|
|
{
|
|
|
|
return uint64_value() == other->uint64_value();
|
|
|
|
} break;
|
|
|
|
default :
|
|
|
|
{
|
|
|
|
return NumberValue<MsgPack::UINT64, uint64_t>::equals( other );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool less(const MsgPackValue * other) const override
|
|
|
|
{
|
|
|
|
switch( other->type() )
|
|
|
|
{
|
|
|
|
case MsgPack::INT64 :
|
|
|
|
{
|
|
|
|
return less_uint64_int64( uint64_value(), other->uint64_value() );
|
|
|
|
} break;
|
|
|
|
case MsgPack::UINT64 :
|
|
|
|
{
|
|
|
|
return uint64_value() < other->uint64_value();
|
|
|
|
} break;
|
|
|
|
default :
|
|
|
|
{
|
|
|
|
return NumberValue<MsgPack::UINT64, uint64_t>::less( other );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
explicit MsgPackUint64(uint64_t value) : NumberValue(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackBoolean final : public Value<MsgPack::BOOL, bool> {
|
|
|
|
bool bool_value() const override { return m_value; }
|
|
|
|
public:
|
|
|
|
explicit MsgPackBoolean(bool value) : Value(value) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackString final : public Value<MsgPack::STRING, string> {
|
|
|
|
const string &string_value() const override { return m_value; }
|
|
|
|
public:
|
|
|
|
explicit MsgPackString(const string &value) : Value(value) {}
|
|
|
|
explicit MsgPackString(string &&value) : Value(move(value)) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackArray final : public Value<MsgPack::ARRAY, MsgPack::array> {
|
|
|
|
const MsgPack::array &array_items() const override { return m_value; }
|
|
|
|
const MsgPack & operator[](size_t i) const override;
|
|
|
|
public:
|
|
|
|
explicit MsgPackArray(const MsgPack::array &value) : Value(value) {}
|
|
|
|
explicit MsgPackArray(MsgPack::array &&value) : Value(move(value)) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackBinary final : public Value<MsgPack::BINARY, MsgPack::binary> {
|
|
|
|
const MsgPack::binary &binary_items() const override { return m_value; }
|
|
|
|
public:
|
|
|
|
explicit MsgPackBinary(const MsgPack::binary &value) : Value(value) {}
|
|
|
|
explicit MsgPackBinary(MsgPack::binary &&value) : Value(move(value)) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackObject final : public Value<MsgPack::OBJECT, MsgPack::object> {
|
|
|
|
const MsgPack::object &object_items() const override { return m_value; }
|
|
|
|
const MsgPack & operator[](const string &key) const override;
|
|
|
|
public:
|
|
|
|
explicit MsgPackObject(const MsgPack::object &value) : Value(value) {}
|
|
|
|
explicit MsgPackObject(MsgPack::object &&value) : Value(move(value)) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackExtension final : public Value<MsgPack::EXTENSION, MsgPack::extension> {
|
|
|
|
const MsgPack::extension &extension_items() const override { return m_value; }
|
|
|
|
public:
|
|
|
|
explicit MsgPackExtension(const MsgPack::extension &value) : Value(value) {}
|
|
|
|
explicit MsgPackExtension(MsgPack::extension &&value) : Value(move(value)) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MsgPackNull final : public Value<MsgPack::NUL, NullStruct> {
|
|
|
|
public:
|
|
|
|
MsgPackNull() : Value({}) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Static globals - static-init-safe
|
|
|
|
*/
|
|
|
|
struct Statics {
|
|
|
|
const std::shared_ptr<MsgPackValue> null = make_shared<MsgPackNull>();
|
|
|
|
const std::shared_ptr<MsgPackValue> t = make_shared<MsgPackBoolean>(true);
|
|
|
|
const std::shared_ptr<MsgPackValue> f = make_shared<MsgPackBoolean>(false);
|
|
|
|
const string empty_string;
|
|
|
|
const vector<MsgPack> empty_vector;
|
|
|
|
const map<MsgPack, MsgPack> empty_map;
|
|
|
|
const MsgPack::binary empty_binary;
|
|
|
|
const MsgPack::extension empty_extension;
|
|
|
|
Statics() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const Statics & statics() {
|
|
|
|
static const Statics s {};
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MsgPack & static_null() {
|
|
|
|
// This has to be separate, not in Statics, because MsgPack() accesses statics().null.
|
|
|
|
static const MsgPack msgpack_null;
|
|
|
|
return msgpack_null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Constructors
|
|
|
|
*/
|
|
|
|
|
|
|
|
MsgPack::MsgPack() noexcept : m_ptr(statics().null) {}
|
|
|
|
MsgPack::MsgPack(std::nullptr_t) noexcept : m_ptr(statics().null) {}
|
|
|
|
MsgPack::MsgPack(float value) : m_ptr(make_shared<MsgPackFloat>(value)) {}
|
|
|
|
MsgPack::MsgPack(double value) : m_ptr(make_shared<MsgPackDouble>(value)) {}
|
|
|
|
MsgPack::MsgPack(int8_t value) : m_ptr(make_shared<MsgPackInt8>(value)) {}
|
|
|
|
MsgPack::MsgPack(int16_t value) : m_ptr(make_shared<MsgPackInt16>(value)) {}
|
|
|
|
MsgPack::MsgPack(int32_t value) : m_ptr(make_shared<MsgPackInt32>(value)) {}
|
|
|
|
MsgPack::MsgPack(int64_t value) : m_ptr(make_shared<MsgPackInt64>(value)) {}
|
|
|
|
MsgPack::MsgPack(uint8_t value) : m_ptr(make_shared<MsgPackUint8>(value)) {}
|
|
|
|
MsgPack::MsgPack(uint16_t value) : m_ptr(make_shared<MsgPackUint16>(value)) {}
|
|
|
|
MsgPack::MsgPack(uint32_t value) : m_ptr(make_shared<MsgPackUint32>(value)) {}
|
|
|
|
MsgPack::MsgPack(uint64_t value) : m_ptr(make_shared<MsgPackUint64>(value)) {}
|
|
|
|
MsgPack::MsgPack(bool value) : m_ptr(value ? statics().t : statics().f) {}
|
|
|
|
MsgPack::MsgPack(const string &value) : m_ptr(make_shared<MsgPackString>(value)) {}
|
|
|
|
MsgPack::MsgPack(string &&value) : m_ptr(make_shared<MsgPackString>(move(value))) {}
|
|
|
|
MsgPack::MsgPack(const char * value) : m_ptr(make_shared<MsgPackString>(value)) {}
|
|
|
|
MsgPack::MsgPack(const MsgPack::array &values) : m_ptr(make_shared<MsgPackArray>(values)) {}
|
|
|
|
MsgPack::MsgPack(MsgPack::array &&values) : m_ptr(make_shared<MsgPackArray>(move(values))) {}
|
|
|
|
MsgPack::MsgPack(const MsgPack::object &values) : m_ptr(make_shared<MsgPackObject>(values)) {}
|
|
|
|
MsgPack::MsgPack(MsgPack::object &&values) : m_ptr(make_shared<MsgPackObject>(move(values))) {}
|
|
|
|
MsgPack::MsgPack(const MsgPack::binary &values) : m_ptr(make_shared<MsgPackBinary>(values)) {}
|
|
|
|
MsgPack::MsgPack(MsgPack::binary &&values) : m_ptr(make_shared<MsgPackBinary>(move(values))) {}
|
|
|
|
MsgPack::MsgPack(const MsgPack::extension &values) : m_ptr(make_shared<MsgPackExtension>(values)) {}
|
|
|
|
MsgPack::MsgPack(MsgPack::extension &&values) : m_ptr(make_shared<MsgPackExtension>(move(values))) {}
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Accessors
|
|
|
|
*/
|
|
|
|
|
|
|
|
MsgPack::Type MsgPack::type() const { return m_ptr->type(); }
|
|
|
|
double MsgPack::number_value() const { return m_ptr->float64_value(); }
|
|
|
|
float MsgPack::float32_value() const { return m_ptr->float32_value(); }
|
|
|
|
double MsgPack::float64_value() const { return m_ptr->float64_value(); }
|
|
|
|
int32_t MsgPack::int_value() const { return m_ptr->int32_value(); }
|
|
|
|
int8_t MsgPack::int8_value() const { return m_ptr->int8_value(); }
|
|
|
|
int16_t MsgPack::int16_value() const { return m_ptr->int16_value(); }
|
|
|
|
int32_t MsgPack::int32_value() const { return m_ptr->int32_value(); }
|
|
|
|
int64_t MsgPack::int64_value() const { return m_ptr->int64_value(); }
|
|
|
|
uint8_t MsgPack::uint8_value() const { return m_ptr->uint8_value(); }
|
|
|
|
uint16_t MsgPack::uint16_value() const { return m_ptr->uint16_value(); }
|
|
|
|
uint32_t MsgPack::uint32_value() const { return m_ptr->uint32_value(); }
|
|
|
|
uint64_t MsgPack::uint64_value() const { return m_ptr->uint64_value(); }
|
|
|
|
bool MsgPack::bool_value() const { return m_ptr->bool_value(); }
|
|
|
|
const string & MsgPack::string_value() const { return m_ptr->string_value(); }
|
|
|
|
const vector<MsgPack>& MsgPack::array_items() const { return m_ptr->array_items(); }
|
|
|
|
const MsgPack::binary& MsgPack::binary_items() const { return m_ptr->binary_items(); }
|
|
|
|
const MsgPack::extension& MsgPack::extension_items() const { return m_ptr->extension_items(); }
|
|
|
|
const map<MsgPack, MsgPack> & MsgPack::object_items() const { return m_ptr->object_items(); }
|
|
|
|
const MsgPack & MsgPack::operator[] (size_t i) const { return (*m_ptr)[i]; }
|
|
|
|
const MsgPack & MsgPack::operator[] (const string &key) const { return (*m_ptr)[key]; }
|
|
|
|
|
|
|
|
double MsgPackValue::number_value() const { return 0.0; }
|
|
|
|
float MsgPackValue::float32_value() const { return 0.0f; }
|
|
|
|
double MsgPackValue::float64_value() const { return 0.0; }
|
|
|
|
int32_t MsgPackValue::int_value() const { return 0; }
|
|
|
|
int8_t MsgPackValue::int8_value() const { return 0; }
|
|
|
|
int16_t MsgPackValue::int16_value() const { return 0; }
|
|
|
|
int32_t MsgPackValue::int32_value() const { return 0; }
|
|
|
|
int64_t MsgPackValue::int64_value() const { return 0; }
|
|
|
|
uint8_t MsgPackValue::uint8_value() const { return 0; }
|
|
|
|
uint16_t MsgPackValue::uint16_value() const { return 0; }
|
|
|
|
uint32_t MsgPackValue::uint32_value() const { return 0; }
|
|
|
|
uint64_t MsgPackValue::uint64_value() const { return 0; }
|
|
|
|
bool MsgPackValue::bool_value() const { return false; }
|
|
|
|
const string & MsgPackValue::string_value() const { return statics().empty_string; }
|
|
|
|
const vector<MsgPack> & MsgPackValue::array_items() const { return statics().empty_vector; }
|
|
|
|
const map<MsgPack, MsgPack> & MsgPackValue::object_items() const { return statics().empty_map; }
|
|
|
|
const MsgPack::binary & MsgPackValue::binary_items() const { return statics().empty_binary; }
|
|
|
|
const MsgPack::extension & MsgPackValue::extension_items() const { return statics().empty_extension; }
|
|
|
|
const MsgPack & MsgPackValue::operator[] (size_t) const { return static_null(); }
|
|
|
|
const MsgPack & MsgPackValue::operator[] (const string &) const { return static_null(); }
|
|
|
|
|
|
|
|
const MsgPack & MsgPackObject::operator[] (const string &key) const {
|
|
|
|
auto iter = m_value.find(key);
|
|
|
|
return (iter == m_value.end()) ? static_null() : iter->second;
|
|
|
|
}
|
|
|
|
const MsgPack & MsgPackArray::operator[] (size_t i) const {
|
|
|
|
if (i >= m_value.size()) return static_null();
|
|
|
|
else return m_value[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Comparison
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool MsgPack::operator== (const MsgPack &other) const {
|
|
|
|
return m_ptr->equals(other.m_ptr.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MsgPack::operator< (const MsgPack &other) const {
|
|
|
|
return m_ptr->less(other.m_ptr.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/* MsgPackParser
|
|
|
|
*
|
|
|
|
* Object that tracks all state of an in-progress parse.
|
|
|
|
*/
|
|
|
|
struct MsgPackParser final {
|
|
|
|
|
|
|
|
/* State
|
|
|
|
*/
|
|
|
|
const std::string &buffer;
|
|
|
|
size_t i;
|
|
|
|
string &err;
|
|
|
|
bool failed;
|
|
|
|
|
|
|
|
/* fail(msg, err_ret = MsgPack())
|
|
|
|
*
|
|
|
|
* Mark this parse as failed.
|
|
|
|
*/
|
|
|
|
MsgPack fail(string &&msg) {
|
|
|
|
return fail(move(msg), MsgPack());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T fail(string &&msg, const T err_ret) {
|
|
|
|
if (!failed)
|
|
|
|
err = std::move(msg);
|
|
|
|
failed = true;
|
|
|
|
return err_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t get_first_byte()
|
|
|
|
{
|
|
|
|
if(buffer.size() <= i)
|
|
|
|
{
|
|
|
|
err = "end of buffer.";
|
|
|
|
failed = true;
|
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint8_t first_byte = buffer[i];
|
|
|
|
++i;
|
|
|
|
return first_byte;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::nullptr_t parse_invalid(uint8_t) {
|
|
|
|
err = "invalid first byte.";
|
|
|
|
failed = true;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::nullptr_t parse_nil(uint8_t) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parse_bool(uint8_t first_byte) {
|
|
|
|
return (first_byte == 0xc3);
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
T parse_arith() {
|
|
|
|
EndianConverter<T> converter;
|
|
|
|
for( size_t j = 0; j < sizeof(T); ++j )
|
|
|
|
{
|
|
|
|
converter.value.bytes[j] = buffer[i];
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!is_big_endian)
|
|
|
|
{
|
|
|
|
std::reverse(converter.value.bytes.begin(), converter.value.bytes.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
return converter.value.packed;
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
std::string parse_string_impl(uint8_t, T bytes) {
|
|
|
|
std::string res(&(buffer[i]), &(buffer[i+bytes]));
|
|
|
|
i += bytes;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
std::string parse_string(uint8_t first_byte) {
|
|
|
|
T const bytes = parse_arith<T>();
|
|
|
|
return parse_string_impl<T>(first_byte, bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
MsgPack::array parse_array_impl(T bytes) {
|
|
|
|
MsgPack::array res;
|
|
|
|
for(T j = 0; j < bytes; ++j) {
|
|
|
|
res.emplace_back(parse_msgpack(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
MsgPack::array parse_array() {
|
|
|
|
T const bytes = parse_arith<T>();
|
|
|
|
return parse_array_impl<T>(bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
MsgPack::object parse_object_impl(uint8_t, T bytes) {
|
|
|
|
MsgPack::object res;
|
|
|
|
for(T j = 0; j < bytes; ++j) {
|
|
|
|
MsgPack key = parse_msgpack(0);
|
|
|
|
MsgPack value = parse_msgpack(0);
|
|
|
|
res.insert(std::make_pair(std::move(key), std::move(value)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
MsgPack::object parse_object(uint8_t first_byte) {
|
|
|
|
T const bytes = parse_arith<T>();
|
|
|
|
return parse_object_impl<T>(first_byte, bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
MsgPack::binary parse_binary_impl(T bytes) {
|
|
|
|
MsgPack::binary res;
|
|
|
|
for(T j = 0; j < bytes; ++j) {
|
|
|
|
res.push_back(buffer[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
MsgPack::binary parse_binary() {
|
|
|
|
T const bytes = parse_arith<T>();
|
|
|
|
return parse_binary_impl<T>(bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
MsgPack::extension parse_extension() {
|
|
|
|
const T bytes = parse_arith<T>();
|
|
|
|
const uint8_t type = parse_arith<uint8_t>();
|
|
|
|
const MsgPack::binary data = parse_binary_impl<T>(bytes);
|
|
|
|
return std::make_tuple(type, std::move(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t parse_pos_fixint(uint8_t first_byte) {
|
|
|
|
return first_byte;
|
|
|
|
}
|
|
|
|
|
|
|
|
MsgPack::object parse_fixobject(uint8_t first_byte) {
|
|
|
|
uint8_t const bytes = first_byte & 0x0f;
|
|
|
|
return parse_object_impl<uint8_t>(first_byte, bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
MsgPack::array parse_fixarray(uint8_t first_byte) {
|
|
|
|
uint8_t const bytes = first_byte & 0x0f;
|
|
|
|
return parse_array_impl<uint8_t>(bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string parse_fixstring(uint8_t first_byte) {
|
|
|
|
uint8_t const bytes = first_byte & 0x1f;
|
|
|
|
return parse_string_impl<uint8_t>(first_byte, bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
int8_t parse_neg_fixint(uint8_t first_byte) {
|
|
|
|
return *reinterpret_cast<int8_t*>(&first_byte);
|
|
|
|
}
|
|
|
|
|
|
|
|
MsgPack::extension parse_fixext(uint8_t bytes) {
|
|
|
|
const uint8_t type = parse_arith<uint8_t>();
|
|
|
|
const MsgPack::binary data = parse_binary_impl<uint8_t>(bytes);
|
|
|
|
return std::make_tuple(type, std::move(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
using parser_element_type = std::tuple<uint8_t, uint8_t, std::function< MsgPack(MsgPackParser*, uint8_t) > >;
|
|
|
|
static const std::vector< parser_element_type > parsers;
|
|
|
|
|
|
|
|
/* parse_msgpack()
|
|
|
|
*
|
|
|
|
* Parse a JSON object.
|
|
|
|
*/
|
|
|
|
MsgPack parse_msgpack(int depth) {
|
|
|
|
if (depth > max_depth) {
|
|
|
|
return fail("exceeded maximum nesting depth");
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t first_byte = get_first_byte();
|
|
|
|
if (failed) {
|
|
|
|
return MsgPack();
|
|
|
|
}
|
|
|
|
|
|
|
|
for( auto const& parser : parsers ) {
|
|
|
|
auto beg = std::get<0>(parser);
|
|
|
|
auto end = std::get<1>(parser);
|
|
|
|
if((beg <= first_byte) && (first_byte <= end)) {
|
|
|
|
auto parser_func = std::get<2>(parser);
|
|
|
|
return parser_func(this, first_byte);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return MsgPack();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const std::vector< MsgPackParser::parser_element_type > MsgPackParser::parsers {
|
|
|
|
MsgPackParser::parser_element_type{ 0x00u, 0x7fu, [](MsgPackParser* that, uint8_t first_byte){ return MsgPack(that->parse_pos_fixint(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0x00u, 0x7fu, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_pos_fixint(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0x80u, 0x8fu, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_fixobject(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0x90u, 0x9fu, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_fixarray(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xa0u, 0xbfu, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_fixstring(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc0u, 0xc0u, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_nil(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc1u, 0xc1u, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_invalid(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc2u, 0xc3u, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_bool(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc4u, 0xc4u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_binary<uint8_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc5u, 0xc5u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_binary<uint16_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc6u, 0xc6u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_binary<uint32_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc7u, 0xc7u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_extension<uint8_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc8u, 0xc8u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_extension<uint16_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xc9u, 0xc9u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_extension<uint32_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xcau, 0xcau, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<float>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xcbu, 0xcbu, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<double>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xccu, 0xccu, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<uint8_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xcdu, 0xcdu, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<uint16_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xceu, 0xceu, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<uint32_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xcfu, 0xcfu, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<uint64_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd0u, 0xd0u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<int8_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd1u, 0xd1u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<int16_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd2u, 0xd2u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<int32_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd3u, 0xd3u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_arith<int64_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd4u, 0xd4u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_fixext(1)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd5u, 0xd5u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_fixext(2)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd6u, 0xd6u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_fixext(4)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd7u, 0xd7u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_fixext(8)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd8u, 0xd8u, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_fixext(16)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xd9u, 0xd9u, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_string<uint8_t>(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xdau, 0xdau, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_string<uint16_t>(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xdbu, 0xdbu, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_string<uint32_t>(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xdcu, 0xdcu, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_array<uint16_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xddu, 0xddu, [](MsgPackParser* that, uint8_t) -> MsgPack { return MsgPack(that->parse_array<uint32_t>()); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xdeu, 0xdeu, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_object<uint16_t>(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xdfu, 0xdfu, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_object<uint32_t>(first_byte)); }},
|
|
|
|
MsgPackParser::parser_element_type{ 0xe0u, 0xffu, [](MsgPackParser* that, uint8_t first_byte) -> MsgPack { return MsgPack(that->parse_neg_fixint(first_byte)); }}
|
|
|
|
};
|
|
|
|
|
|
|
|
}//namespace {
|
|
|
|
|
|
|
|
MsgPack MsgPack::parse(const std::string &in, string &err) {
|
|
|
|
MsgPackParser parser { in, 0, err, false };
|
|
|
|
MsgPack result = parser.parse_msgpack(0);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Documented in msgpack.hpp
|
|
|
|
vector<MsgPack> MsgPack::parse_multi(const string &in,
|
|
|
|
std::string::size_type &parser_stop_pos,
|
|
|
|
string &err) {
|
|
|
|
MsgPackParser parser { in, 0, err, false };
|
|
|
|
parser_stop_pos = 0;
|
|
|
|
vector<MsgPack> msgpack_vec;
|
|
|
|
while (parser.i != in.size() && !parser.failed) {
|
|
|
|
msgpack_vec.push_back(parser.parse_msgpack(0));
|
|
|
|
if (!parser.failed)
|
|
|
|
parser_stop_pos = parser.i;
|
|
|
|
}
|
|
|
|
return msgpack_vec;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * *
|
|
|
|
* Shape-checking
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool MsgPack::has_shape(const shape & types, string & err) const {
|
|
|
|
if (!is_object()) {
|
|
|
|
err = "expected MessagePack object";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto & item : types) {
|
|
|
|
if ((*this)[item.first].type() != item.second) {
|
|
|
|
err = "bad type for " + item.first;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace msgpack11
|