♻️ refactored code to split headers
This commit is contained in:
parent
1b54d4a5aa
commit
c772c01a48
4 changed files with 671 additions and 20 deletions
|
@ -90,6 +90,27 @@ class binary_reader
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief create a JSON value from UBJSON input
|
||||||
|
|
||||||
|
@param[in] strict whether to expect the input to be consumed completed
|
||||||
|
@return JSON value created from UBJSON input
|
||||||
|
|
||||||
|
@throw parse_error.110 if input ended unexpectedly or the end of file was
|
||||||
|
not reached when @a strict was set to true
|
||||||
|
@throw parse_error.112 if unsupported byte was read
|
||||||
|
*/
|
||||||
|
BasicJsonType parse_ubjson(const bool strict)
|
||||||
|
{
|
||||||
|
const auto res = parse_ubjson_internal();
|
||||||
|
if (strict)
|
||||||
|
{
|
||||||
|
get_ignore_noop();
|
||||||
|
check_eof(true);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief determine system byte order
|
@brief determine system byte order
|
||||||
|
|
||||||
|
@ -751,6 +772,16 @@ class binary_reader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in] get_char whether a new character should be retrieved from the
|
||||||
|
input (true, default) or whether the last read
|
||||||
|
character should be considered instead
|
||||||
|
*/
|
||||||
|
BasicJsonType parse_ubjson_internal(const bool get_char = true)
|
||||||
|
{
|
||||||
|
return get_ubjson_value(get_char ? get_ignore_noop() : current);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief get next character from the input
|
@brief get next character from the input
|
||||||
|
|
||||||
|
@ -766,6 +797,20 @@ class binary_reader
|
||||||
return (current = ia->get_character());
|
return (current = ia->get_character());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@return character read from the input after ignoring all 'N' entries
|
||||||
|
*/
|
||||||
|
int get_ignore_noop()
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
get();
|
||||||
|
}
|
||||||
|
while (current == 'N');
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@brief read a number from the input
|
@brief read a number from the input
|
||||||
|
|
||||||
|
@ -1051,6 +1096,231 @@ class binary_reader
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief reads a UBJSON string
|
||||||
|
|
||||||
|
This function is either called after reading the 'S' byte explicitly
|
||||||
|
indicating a string, or in case of an object key where the 'S' byte can be
|
||||||
|
left out.
|
||||||
|
|
||||||
|
@param[in] get_char whether a new character should be retrieved from the
|
||||||
|
input (true, default) or whether the last read
|
||||||
|
character should be considered instead
|
||||||
|
|
||||||
|
@return string
|
||||||
|
|
||||||
|
@throw parse_error.110 if input ended
|
||||||
|
@throw parse_error.113 if an unexpected byte is read
|
||||||
|
*/
|
||||||
|
std::string get_ubjson_string(const bool get_char = true)
|
||||||
|
{
|
||||||
|
if (get_char)
|
||||||
|
{
|
||||||
|
get(); // TODO: may we ignore N here?
|
||||||
|
}
|
||||||
|
|
||||||
|
check_eof();
|
||||||
|
|
||||||
|
switch (current)
|
||||||
|
{
|
||||||
|
case 'U':
|
||||||
|
return get_string(get_number<uint8_t>());
|
||||||
|
case 'i':
|
||||||
|
return get_string(get_number<int8_t>());
|
||||||
|
case 'I':
|
||||||
|
return get_string(get_number<int16_t>());
|
||||||
|
case 'l':
|
||||||
|
return get_string(get_number<int32_t>());
|
||||||
|
case 'L':
|
||||||
|
return get_string(get_number<int64_t>());
|
||||||
|
default:
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current;
|
||||||
|
JSON_THROW(parse_error::create(113, chars_read,
|
||||||
|
"expected a UBJSON string; last byte: 0x" + ss.str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief determine the type and size for a container
|
||||||
|
|
||||||
|
In the optimized UBJSON format, a type and a size can be provided to allow
|
||||||
|
for a more compact representation.
|
||||||
|
|
||||||
|
@return pair of the size and the type
|
||||||
|
*/
|
||||||
|
std::pair<std::size_t, int> get_ubjson_size_type()
|
||||||
|
{
|
||||||
|
std::size_t sz = std::string::npos;
|
||||||
|
int tc = 0;
|
||||||
|
|
||||||
|
get_ignore_noop();
|
||||||
|
|
||||||
|
if (current == '$')
|
||||||
|
{
|
||||||
|
tc = get(); // must not ignore 'N', because 'N' maybe the type
|
||||||
|
check_eof();
|
||||||
|
|
||||||
|
get_ignore_noop();
|
||||||
|
if (current != '#')
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current;
|
||||||
|
JSON_THROW(parse_error::create(112, chars_read,
|
||||||
|
"expected '#' after UBJSON type information; last byte: 0x" + ss.str()));
|
||||||
|
}
|
||||||
|
sz = parse_ubjson_internal();
|
||||||
|
}
|
||||||
|
else if (current == '#')
|
||||||
|
{
|
||||||
|
sz = parse_ubjson_internal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(sz, tc);
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicJsonType get_ubjson_value(const int prefix)
|
||||||
|
{
|
||||||
|
switch (prefix)
|
||||||
|
{
|
||||||
|
case std::char_traits<char>::eof(): // EOF
|
||||||
|
JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
|
||||||
|
|
||||||
|
case 'T': // true
|
||||||
|
return true;
|
||||||
|
case 'F': // false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 'Z': // null
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
case 'U':
|
||||||
|
return get_number<uint8_t>();
|
||||||
|
case 'i':
|
||||||
|
return get_number<int8_t>();
|
||||||
|
case 'I':
|
||||||
|
return get_number<int16_t>();
|
||||||
|
case 'l':
|
||||||
|
return get_number<int32_t>();
|
||||||
|
case 'L':
|
||||||
|
return get_number<int64_t>();
|
||||||
|
case 'd':
|
||||||
|
return get_number<float>();
|
||||||
|
case 'D':
|
||||||
|
return get_number<double>();
|
||||||
|
|
||||||
|
case 'C': // char
|
||||||
|
{
|
||||||
|
get();
|
||||||
|
check_eof();
|
||||||
|
if (JSON_UNLIKELY(not(0 <= current and current <= 127)))
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current;
|
||||||
|
JSON_THROW(parse_error::create(113, chars_read,
|
||||||
|
"byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + ss.str()));
|
||||||
|
}
|
||||||
|
return std::string(1, static_cast<char>(current));
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'S': // string
|
||||||
|
return get_ubjson_string();
|
||||||
|
|
||||||
|
case '[': // array
|
||||||
|
return get_ubjson_array();
|
||||||
|
|
||||||
|
case '{': // object
|
||||||
|
return get_ubjson_object();
|
||||||
|
|
||||||
|
default: // anything else
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current;
|
||||||
|
JSON_THROW(parse_error::create(112, chars_read,
|
||||||
|
"error reading UBJSON; last byte: 0x" + ss.str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicJsonType get_ubjson_array()
|
||||||
|
{
|
||||||
|
BasicJsonType result = value_t::array;
|
||||||
|
const auto size_and_type = get_ubjson_size_type();
|
||||||
|
|
||||||
|
if (size_and_type.first != std::string::npos)
|
||||||
|
{
|
||||||
|
if (size_and_type.second != 0)
|
||||||
|
{
|
||||||
|
if (size_and_type.second != 'N')
|
||||||
|
std::generate_n(std::back_inserter(*result.m_value.array),
|
||||||
|
size_and_type.first, [this, size_and_type]()
|
||||||
|
{
|
||||||
|
return get_ubjson_value(size_and_type.second);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::generate_n(std::back_inserter(*result.m_value.array),
|
||||||
|
size_and_type.first, [this]()
|
||||||
|
{
|
||||||
|
return parse_ubjson_internal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (current != ']')
|
||||||
|
{
|
||||||
|
result.push_back(parse_ubjson_internal(false));
|
||||||
|
get_ignore_noop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicJsonType get_ubjson_object()
|
||||||
|
{
|
||||||
|
BasicJsonType result = value_t::object;
|
||||||
|
const auto size_and_type = get_ubjson_size_type();
|
||||||
|
|
||||||
|
if (size_and_type.first != std::string::npos)
|
||||||
|
{
|
||||||
|
if (size_and_type.second != 0)
|
||||||
|
{
|
||||||
|
if (size_and_type.second != 'N')
|
||||||
|
std::generate_n(std::inserter(*result.m_value.object,
|
||||||
|
result.m_value.object->end()),
|
||||||
|
size_and_type.first, [this, size_and_type]()
|
||||||
|
{
|
||||||
|
auto key = get_ubjson_string();
|
||||||
|
auto val = get_ubjson_value(size_and_type.second);
|
||||||
|
return std::make_pair(std::move(key), std::move(val));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::generate_n(std::inserter(*result.m_value.object,
|
||||||
|
result.m_value.object->end()),
|
||||||
|
size_and_type.first, [this]()
|
||||||
|
{
|
||||||
|
auto key = get_ubjson_string();
|
||||||
|
auto val = parse_ubjson_internal();
|
||||||
|
return std::make_pair(std::move(key), std::move(val));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (current != '}')
|
||||||
|
{
|
||||||
|
auto key = get_ubjson_string(false);
|
||||||
|
result[std::move(key)] = parse_ubjson_internal();
|
||||||
|
get_ignore_noop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief check if input ended
|
@brief check if input ended
|
||||||
@throw parse_error.110 if input ended
|
@throw parse_error.110 if input ended
|
||||||
|
|
|
@ -164,23 +164,23 @@ class binary_writer
|
||||||
{
|
{
|
||||||
write_number(static_cast<uint8_t>(0x60 + N));
|
write_number(static_cast<uint8_t>(0x60 + N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFF)
|
else if (N <= (std::numeric_limits<uint8_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0x78));
|
oa->write_character(static_cast<CharType>(0x78));
|
||||||
write_number(static_cast<uint8_t>(N));
|
write_number(static_cast<uint8_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFFFF)
|
else if (N <= (std::numeric_limits<uint16_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0x79));
|
oa->write_character(static_cast<CharType>(0x79));
|
||||||
write_number(static_cast<uint16_t>(N));
|
write_number(static_cast<uint16_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFFFFFFFF)
|
else if (N <= (std::numeric_limits<uint32_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0x7A));
|
oa->write_character(static_cast<CharType>(0x7A));
|
||||||
write_number(static_cast<uint32_t>(N));
|
write_number(static_cast<uint32_t>(N));
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
else if (N <= 0xFFFFFFFFFFFFFFFF)
|
else if (N <= (std::numeric_limits<uint64_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0x7B));
|
oa->write_character(static_cast<CharType>(0x7B));
|
||||||
write_number(static_cast<uint64_t>(N));
|
write_number(static_cast<uint64_t>(N));
|
||||||
|
@ -202,23 +202,23 @@ class binary_writer
|
||||||
{
|
{
|
||||||
write_number(static_cast<uint8_t>(0x80 + N));
|
write_number(static_cast<uint8_t>(0x80 + N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFF)
|
else if (N <= (std::numeric_limits<uint8_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0x98));
|
oa->write_character(static_cast<CharType>(0x98));
|
||||||
write_number(static_cast<uint8_t>(N));
|
write_number(static_cast<uint8_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFFFF)
|
else if (N <= (std::numeric_limits<uint16_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0x99));
|
oa->write_character(static_cast<CharType>(0x99));
|
||||||
write_number(static_cast<uint16_t>(N));
|
write_number(static_cast<uint16_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFFFFFFFF)
|
else if (N <= (std::numeric_limits<uint32_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0x9A));
|
oa->write_character(static_cast<CharType>(0x9A));
|
||||||
write_number(static_cast<uint32_t>(N));
|
write_number(static_cast<uint32_t>(N));
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
else if (N <= 0xFFFFFFFFFFFFFFFF)
|
else if (N <= (std::numeric_limits<uint64_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0x9B));
|
oa->write_character(static_cast<CharType>(0x9B));
|
||||||
write_number(static_cast<uint64_t>(N));
|
write_number(static_cast<uint64_t>(N));
|
||||||
|
@ -241,23 +241,23 @@ class binary_writer
|
||||||
{
|
{
|
||||||
write_number(static_cast<uint8_t>(0xA0 + N));
|
write_number(static_cast<uint8_t>(0xA0 + N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFF)
|
else if (N <= (std::numeric_limits<uint8_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0xB8));
|
oa->write_character(static_cast<CharType>(0xB8));
|
||||||
write_number(static_cast<uint8_t>(N));
|
write_number(static_cast<uint8_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFFFF)
|
else if (N <= (std::numeric_limits<uint16_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0xB9));
|
oa->write_character(static_cast<CharType>(0xB9));
|
||||||
write_number(static_cast<uint16_t>(N));
|
write_number(static_cast<uint16_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFFFFFFFF)
|
else if (N <= (std::numeric_limits<uint32_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0xBA));
|
oa->write_character(static_cast<CharType>(0xBA));
|
||||||
write_number(static_cast<uint32_t>(N));
|
write_number(static_cast<uint32_t>(N));
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
else if (N <= 0xFFFFFFFFFFFFFFFF)
|
else if (N <= (std::numeric_limits<uint64_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0xBB));
|
oa->write_character(static_cast<CharType>(0xBB));
|
||||||
write_number(static_cast<uint64_t>(N));
|
write_number(static_cast<uint64_t>(N));
|
||||||
|
@ -425,19 +425,19 @@ class binary_writer
|
||||||
// fixstr
|
// fixstr
|
||||||
write_number(static_cast<uint8_t>(0xA0 | N));
|
write_number(static_cast<uint8_t>(0xA0 | N));
|
||||||
}
|
}
|
||||||
else if (N <= 255)
|
else if (N <= (std::numeric_limits<uint8_t>::max)())
|
||||||
{
|
{
|
||||||
// str 8
|
// str 8
|
||||||
oa->write_character(static_cast<CharType>(0xD9));
|
oa->write_character(static_cast<CharType>(0xD9));
|
||||||
write_number(static_cast<uint8_t>(N));
|
write_number(static_cast<uint8_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 65535)
|
else if (N <= (std::numeric_limits<uint16_t>::max)())
|
||||||
{
|
{
|
||||||
// str 16
|
// str 16
|
||||||
oa->write_character(static_cast<CharType>(0xDA));
|
oa->write_character(static_cast<CharType>(0xDA));
|
||||||
write_number(static_cast<uint16_t>(N));
|
write_number(static_cast<uint16_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 4294967295)
|
else if (N <= (std::numeric_limits<uint32_t>::max)())
|
||||||
{
|
{
|
||||||
// str 32
|
// str 32
|
||||||
oa->write_character(static_cast<CharType>(0xDB));
|
oa->write_character(static_cast<CharType>(0xDB));
|
||||||
|
@ -460,13 +460,13 @@ class binary_writer
|
||||||
// fixarray
|
// fixarray
|
||||||
write_number(static_cast<uint8_t>(0x90 | N));
|
write_number(static_cast<uint8_t>(0x90 | N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFFFF)
|
else if (N <= (std::numeric_limits<uint16_t>::max)())
|
||||||
{
|
{
|
||||||
// array 16
|
// array 16
|
||||||
oa->write_character(static_cast<CharType>(0xDC));
|
oa->write_character(static_cast<CharType>(0xDC));
|
||||||
write_number(static_cast<uint16_t>(N));
|
write_number(static_cast<uint16_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 0xFFFFFFFF)
|
else if (N <= (std::numeric_limits<uint32_t>::max)())
|
||||||
{
|
{
|
||||||
// array 32
|
// array 32
|
||||||
oa->write_character(static_cast<CharType>(0xDD));
|
oa->write_character(static_cast<CharType>(0xDD));
|
||||||
|
@ -490,13 +490,13 @@ class binary_writer
|
||||||
// fixmap
|
// fixmap
|
||||||
write_number(static_cast<uint8_t>(0x80 | (N & 0xF)));
|
write_number(static_cast<uint8_t>(0x80 | (N & 0xF)));
|
||||||
}
|
}
|
||||||
else if (N <= 65535)
|
else if (N <= (std::numeric_limits<uint16_t>::max)())
|
||||||
{
|
{
|
||||||
// map 16
|
// map 16
|
||||||
oa->write_character(static_cast<CharType>(0xDE));
|
oa->write_character(static_cast<CharType>(0xDE));
|
||||||
write_number(static_cast<uint16_t>(N));
|
write_number(static_cast<uint16_t>(N));
|
||||||
}
|
}
|
||||||
else if (N <= 4294967295)
|
else if (N <= (std::numeric_limits<uint32_t>::max)())
|
||||||
{
|
{
|
||||||
// map 32
|
// map 32
|
||||||
oa->write_character(static_cast<CharType>(0xDF));
|
oa->write_character(static_cast<CharType>(0xDF));
|
||||||
|
@ -517,6 +517,165 @@ class binary_writer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in] j JSON value to serialize
|
||||||
|
@param[in] use_count whether to use '#' prefixes (optimized format)
|
||||||
|
@param[in] use_type whether to use '$' prefixes (optimized format)
|
||||||
|
@param[in] add_prefix whether prefixes need to be used for this value
|
||||||
|
*/
|
||||||
|
void write_ubjson(const BasicJsonType& j, const bool use_count,
|
||||||
|
const bool use_type, const bool add_prefix = true)
|
||||||
|
{
|
||||||
|
switch (j.type())
|
||||||
|
{
|
||||||
|
case value_t::null:
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('Z'));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::boolean:
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
oa->write_character(j.m_value.boolean
|
||||||
|
? static_cast<CharType>('T')
|
||||||
|
: static_cast<CharType>('F'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_integer:
|
||||||
|
{
|
||||||
|
write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_float:
|
||||||
|
{
|
||||||
|
write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::string:
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('S'));
|
||||||
|
}
|
||||||
|
write_number_with_ubjson_prefix(j.m_value.string->size(), true);
|
||||||
|
oa->write_characters(
|
||||||
|
reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
|
||||||
|
j.m_value.string->size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('['));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool prefix_required = true;
|
||||||
|
if (use_type and not j.m_value.array->empty())
|
||||||
|
{
|
||||||
|
assert(use_count);
|
||||||
|
const char first_prefix = ubjson_prefix(j.front());
|
||||||
|
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
||||||
|
[this, first_prefix](const BasicJsonType & v)
|
||||||
|
{
|
||||||
|
return ubjson_prefix(v) == first_prefix;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (same_prefix)
|
||||||
|
{
|
||||||
|
prefix_required = false;
|
||||||
|
oa->write_character(static_cast<CharType>('$'));
|
||||||
|
oa->write_character(static_cast<CharType>(first_prefix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_count)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('#'));
|
||||||
|
write_number_with_ubjson_prefix(j.m_value.array->size(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& el : *j.m_value.array)
|
||||||
|
{
|
||||||
|
write_ubjson(el, use_count, use_type, prefix_required);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not use_count)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>(']'));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('{'));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool prefix_required = true;
|
||||||
|
if (use_type and not j.m_value.object->empty())
|
||||||
|
{
|
||||||
|
assert(use_count);
|
||||||
|
const char first_prefix = ubjson_prefix(j.front());
|
||||||
|
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
||||||
|
[this, first_prefix](const BasicJsonType & v)
|
||||||
|
{
|
||||||
|
return ubjson_prefix(v) == first_prefix;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (same_prefix)
|
||||||
|
{
|
||||||
|
prefix_required = false;
|
||||||
|
oa->write_character(static_cast<CharType>('$'));
|
||||||
|
oa->write_character(static_cast<CharType>(first_prefix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_count)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('#'));
|
||||||
|
write_number_with_ubjson_prefix(j.m_value.object->size(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& el : *j.m_value.object)
|
||||||
|
{
|
||||||
|
write_number_with_ubjson_prefix(el.first.size(), true);
|
||||||
|
oa->write_characters(
|
||||||
|
reinterpret_cast<const CharType*>(el.first.c_str()),
|
||||||
|
el.first.size());
|
||||||
|
write_ubjson(el.second, use_count, use_type, prefix_required);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not use_count)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('}'));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
@brief write a number to output input
|
@brief write a number to output input
|
||||||
|
@ -544,6 +703,195 @@ class binary_writer
|
||||||
oa->write_characters(vec.data(), sizeof(NumberType));
|
oa->write_characters(vec.data(), sizeof(NumberType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
void write_number_with_ubjson_prefix(const NumberType n,
|
||||||
|
const bool add_prefix)
|
||||||
|
{
|
||||||
|
if (std::is_floating_point<NumberType>::value)
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('D')); // float64
|
||||||
|
}
|
||||||
|
write_number(n);
|
||||||
|
}
|
||||||
|
else if (std::is_unsigned<NumberType>::value)
|
||||||
|
{
|
||||||
|
if (n <= (std::numeric_limits<int8_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('i')); // uint8
|
||||||
|
}
|
||||||
|
write_number(static_cast<uint8_t>(n));
|
||||||
|
}
|
||||||
|
else if (n <= (std::numeric_limits<uint8_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('U')); // uint8
|
||||||
|
}
|
||||||
|
write_number(static_cast<uint8_t>(n));
|
||||||
|
}
|
||||||
|
else if (n <= (std::numeric_limits<int16_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('I')); // int16
|
||||||
|
}
|
||||||
|
write_number(static_cast<int16_t>(n));
|
||||||
|
}
|
||||||
|
else if (n <= (std::numeric_limits<int32_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('l')); // int32
|
||||||
|
}
|
||||||
|
write_number(static_cast<int32_t>(n));
|
||||||
|
}
|
||||||
|
else if (n <= (std::numeric_limits<int64_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('L')); // int64
|
||||||
|
}
|
||||||
|
write_number(static_cast<int64_t>(n));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: replace by exception
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('i')); // int8
|
||||||
|
}
|
||||||
|
write_number(static_cast<int8_t>(n));
|
||||||
|
}
|
||||||
|
else if ((std::numeric_limits<uint8_t>::min)() <= n and n <= (std::numeric_limits<uint8_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('U')); // uint8
|
||||||
|
}
|
||||||
|
write_number(static_cast<uint8_t>(n));
|
||||||
|
}
|
||||||
|
else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('I')); // int16
|
||||||
|
}
|
||||||
|
write_number(static_cast<int16_t>(n));
|
||||||
|
}
|
||||||
|
else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('l')); // int32
|
||||||
|
}
|
||||||
|
write_number(static_cast<int32_t>(n));
|
||||||
|
}
|
||||||
|
else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa->write_character(static_cast<CharType>('L')); // int64
|
||||||
|
}
|
||||||
|
write_number(static_cast<int64_t>(n));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: replace by exception
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char ubjson_prefix(const BasicJsonType& j)
|
||||||
|
{
|
||||||
|
switch (j.type())
|
||||||
|
{
|
||||||
|
case value_t::null:
|
||||||
|
return 'Z';
|
||||||
|
|
||||||
|
case value_t::boolean:
|
||||||
|
return j.m_value.boolean ? 'T' : 'F';
|
||||||
|
|
||||||
|
case value_t::number_integer:
|
||||||
|
{
|
||||||
|
if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
|
||||||
|
{
|
||||||
|
return 'i';
|
||||||
|
}
|
||||||
|
else if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
|
||||||
|
{
|
||||||
|
return 'U';
|
||||||
|
}
|
||||||
|
else if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
|
||||||
|
{
|
||||||
|
return 'I';
|
||||||
|
}
|
||||||
|
else if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
|
||||||
|
{
|
||||||
|
return 'l';
|
||||||
|
}
|
||||||
|
else if ((std::numeric_limits<int64_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
|
||||||
|
{
|
||||||
|
return 'L';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)())
|
||||||
|
{
|
||||||
|
return 'i';
|
||||||
|
}
|
||||||
|
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
|
||||||
|
{
|
||||||
|
return 'U';
|
||||||
|
}
|
||||||
|
else if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)())
|
||||||
|
{
|
||||||
|
return 'I';
|
||||||
|
}
|
||||||
|
else if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)())
|
||||||
|
{
|
||||||
|
return 'l';
|
||||||
|
}
|
||||||
|
else if (j.m_value.number_unsigned <= (std::numeric_limits<int64_t>::max)())
|
||||||
|
{
|
||||||
|
return 'L';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_float:
|
||||||
|
return 'D';
|
||||||
|
|
||||||
|
case value_t::string:
|
||||||
|
return 'S';
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return '[';
|
||||||
|
|
||||||
|
case value_t::object:
|
||||||
|
return '{';
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// whether we can assume little endianess
|
/// whether we can assume little endianess
|
||||||
const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
|
const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
|
||||||
|
|
|
@ -6630,6 +6630,26 @@ class basic_json
|
||||||
binary_writer<char>(o).write_msgpack(j);
|
binary_writer<char>(o).write_msgpack(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<uint8_t> to_ubjson(const basic_json& j,
|
||||||
|
const bool use_size = false, const bool use_type = false)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> result;
|
||||||
|
to_ubjson(j, result, use_size, use_type);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o,
|
||||||
|
const bool use_size = false, const bool use_type = false)
|
||||||
|
{
|
||||||
|
binary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
|
||||||
|
const bool use_size = false, const bool use_type = false)
|
||||||
|
{
|
||||||
|
binary_writer<char>(o).write_ubjson(j, use_size, use_type);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief create a JSON value from an input in CBOR format
|
@brief create a JSON value from an input in CBOR format
|
||||||
|
|
||||||
|
@ -6824,6 +6844,19 @@ class basic_json
|
||||||
return binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).parse_msgpack(strict);
|
return binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).parse_msgpack(strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static basic_json from_ubjson(detail::input_adapter i,
|
||||||
|
const bool strict = true)
|
||||||
|
{
|
||||||
|
return binary_reader(i).parse_ubjson(strict);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename A1, typename A2,
|
||||||
|
detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
|
||||||
|
static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true)
|
||||||
|
{
|
||||||
|
return binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).parse_ubjson(strict);
|
||||||
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|
|
@ -6409,7 +6409,7 @@ class binary_writer
|
||||||
write_number(static_cast<uint32_t>(N));
|
write_number(static_cast<uint32_t>(N));
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
else if (N <= (std::numeric_limits<uint32_t>::max)())
|
else if (N <= (std::numeric_limits<uint64_t>::max)())
|
||||||
{
|
{
|
||||||
oa->write_character(static_cast<CharType>(0xBB));
|
oa->write_character(static_cast<CharType>(0xBB));
|
||||||
write_number(static_cast<uint64_t>(N));
|
write_number(static_cast<uint64_t>(N));
|
||||||
|
|
Loading…
Reference in a new issue