2018-01-10 10:18:31 +01:00
# pragma once
2017-08-14 17:50:24 +02:00
2017-08-14 19:28:01 +02:00
# include <algorithm> // generate_n
# include <array> // array
# include <cassert> // assert
# include <cmath> // ldexp
# include <cstddef> // size_t
# include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
2018-05-31 15:32:21 +02:00
# include <cstdio> // snprintf
2017-08-14 19:28:01 +02:00
# include <cstring> // memcpy
# include <iterator> // back_inserter
# include <limits> // numeric_limits
# include <string> // char_traits, string
# include <utility> // make_pair, move
2017-08-14 17:50:24 +02:00
2018-01-29 11:21:11 +01:00
# include <nlohmann/detail/input/input_adapters.hpp>
2018-03-11 18:47:38 +01:00
# include <nlohmann/detail/input/json_sax.hpp>
2018-01-29 11:21:11 +01:00
# include <nlohmann/detail/exceptions.hpp>
# include <nlohmann/detail/macro_scope.hpp>
# include <nlohmann/detail/value_t.hpp>
2017-08-14 17:50:24 +02:00
namespace nlohmann
{
namespace detail
{
///////////////////
// binary reader //
///////////////////
/*!
2018-03-18 23:00:45 +01:00
@ brief deserialization of CBOR , MessagePack , and UBJSON values
2017-08-14 17:50:24 +02:00
*/
template < typename BasicJsonType >
class binary_reader
{
using number_integer_t = typename BasicJsonType : : number_integer_t ;
using number_unsigned_t = typename BasicJsonType : : number_unsigned_t ;
2018-06-23 10:28:04 +02:00
using number_float_t = typename BasicJsonType : : number_float_t ;
2018-02-01 08:01:01 +01:00
using string_t = typename BasicJsonType : : string_t ;
2018-03-11 18:47:38 +01:00
using json_sax_t = json_sax < BasicJsonType > ;
2017-08-14 17:50:24 +02:00
public :
/*!
@ brief create a binary reader
@ param [ in ] adapter input adapter to read from
*/
explicit binary_reader ( input_adapter_t adapter ) : ia ( std : : move ( adapter ) )
{
assert ( ia ) ;
}
/*!
2018-03-19 22:48:13 +01:00
@ param [ in ] format the binary format to parse
@ param [ in ] sax_ a SAX event processor
2017-08-14 17:50:24 +02:00
@ param [ in ] strict whether to expect the input to be consumed completed
2018-03-19 22:48:13 +01:00
@ return
2017-08-14 17:50:24 +02:00
*/
2018-03-20 22:39:08 +01:00
bool sax_parse ( const input_format_t format ,
json_sax_t * sax_ ,
const bool strict = true )
2017-08-14 17:50:24 +02:00
{
2018-03-19 22:48:13 +01:00
sax = sax_ ;
bool result ;
2017-08-14 17:50:24 +02:00
2018-03-19 22:48:13 +01:00
switch ( format )
2017-08-14 17:50:24 +02:00
{
2018-03-20 22:39:08 +01:00
case input_format_t : : cbor :
2018-03-19 22:48:13 +01:00
result = parse_cbor_internal ( ) ;
break ;
2017-08-14 17:50:24 +02:00
2018-03-20 22:39:08 +01:00
case input_format_t : : msgpack :
2018-03-19 22:48:13 +01:00
result = parse_msgpack_internal ( ) ;
break ;
2018-01-14 10:27:30 +01:00
2018-03-20 22:39:08 +01:00
case input_format_t : : ubjson :
2018-03-19 22:48:13 +01:00
result = parse_ubjson_internal ( ) ;
break ;
2018-03-20 22:39:08 +01:00
default :
assert ( false ) ; // LCOV_EXCL_LINE
2018-03-19 22:48:13 +01:00
}
2018-01-14 10:27:30 +01:00
2018-03-19 22:48:13 +01:00
// strict mode: next byte must be EOF
if ( result and strict )
2018-01-14 10:27:30 +01:00
{
2018-03-20 22:39:08 +01:00
if ( format = = input_format_t : : ubjson )
2018-03-19 22:48:13 +01:00
{
get_ignore_noop ( ) ;
}
else
{
get ( ) ;
}
if ( JSON_UNLIKELY ( current ! = std : : char_traits < char > : : eof ( ) ) )
{
return sax - > parse_error ( chars_read , get_token_string ( ) , parse_error : : create ( 110 , chars_read , " expected end of input " ) ) ;
}
2018-01-14 10:27:30 +01:00
}
2018-03-19 22:48:13 +01:00
2018-03-11 18:47:38 +01:00
return result ;
2018-01-14 10:27:30 +01:00
}
2017-08-14 17:50:24 +02:00
/*!
@ brief determine system byte order
@ return true if and only if system ' s byte order is little endian
@ note from http : //stackoverflow.com/a/1001328/266378
*/
static constexpr bool little_endianess ( int num = 1 ) noexcept
{
return ( * reinterpret_cast < char * > ( & num ) = = 1 ) ;
}
private :
/*!
@ 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
2018-03-18 23:00:45 +01:00
@ return whether a valid CBOR value was passed to the SAX parser
2017-08-14 17:50:24 +02:00
*/
2018-03-18 23:00:45 +01:00
bool parse_cbor_internal ( const bool get_char = true )
2017-08-14 17:50:24 +02:00
{
switch ( get_char ? get ( ) : current )
{
// EOF
case std : : char_traits < char > : : eof ( ) :
2018-03-18 23:00:45 +01:00
return unexpect_eof ( ) ;
2017-08-14 17:50:24 +02:00
// Integer 0x00..0x17 (0..23)
case 0x00 :
case 0x01 :
case 0x02 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x06 :
case 0x07 :
case 0x08 :
case 0x09 :
case 0x0A :
case 0x0B :
case 0x0C :
case 0x0D :
case 0x0E :
case 0x0F :
case 0x10 :
case 0x11 :
case 0x12 :
case 0x13 :
case 0x14 :
case 0x15 :
case 0x16 :
case 0x17 :
2018-03-11 18:47:38 +01:00
return sax - > number_unsigned ( static_cast < number_unsigned_t > ( current ) ) ;
2017-08-14 17:50:24 +02:00
case 0x18 : // Unsigned integer (one-byte uint8_t follows)
2018-03-18 23:00:45 +01:00
{
uint8_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0x19 : // Unsigned integer (two-byte uint16_t follows)
2018-03-18 23:00:45 +01:00
{
uint16_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0x1A : // Unsigned integer (four-byte uint32_t follows)
2018-03-18 23:00:45 +01:00
{
uint32_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0x1B : // Unsigned integer (eight-byte uint64_t follows)
2018-03-18 23:00:45 +01:00
{
uint64_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2017-08-14 17:50:24 +02:00
// Negative integer -1-0x00..-1-0x17 (-1..-24)
case 0x20 :
case 0x21 :
case 0x22 :
case 0x23 :
case 0x24 :
case 0x25 :
case 0x26 :
case 0x27 :
case 0x28 :
case 0x29 :
case 0x2A :
case 0x2B :
case 0x2C :
case 0x2D :
case 0x2E :
case 0x2F :
case 0x30 :
case 0x31 :
case 0x32 :
case 0x33 :
case 0x34 :
case 0x35 :
case 0x36 :
case 0x37 :
2018-03-11 18:47:38 +01:00
return sax - > number_integer ( static_cast < int8_t > ( 0x20 - 1 - current ) ) ;
2017-08-14 17:50:24 +02:00
case 0x38 : // Negative integer (one-byte uint8_t follows)
2018-03-18 23:00:45 +01:00
{
uint8_t number ;
return get_number ( number ) and sax - > number_integer ( static_cast < number_integer_t > ( - 1 ) - number ) ;
}
2017-08-14 17:50:24 +02:00
case 0x39 : // Negative integer -1-n (two-byte uint16_t follows)
2018-03-18 23:00:45 +01:00
{
uint16_t number ;
return get_number ( number ) and sax - > number_integer ( static_cast < number_integer_t > ( - 1 ) - number ) ;
}
2017-08-14 17:50:24 +02:00
case 0x3A : // Negative integer -1-n (four-byte uint32_t follows)
2018-03-18 23:00:45 +01:00
{
uint32_t number ;
return get_number ( number ) and sax - > number_integer ( static_cast < number_integer_t > ( - 1 ) - number ) ;
}
2017-08-14 17:50:24 +02:00
case 0x3B : // Negative integer -1-n (eight-byte uint64_t follows)
2018-03-18 23:00:45 +01:00
{
uint64_t number ;
return get_number ( number ) and sax - > number_integer ( static_cast < number_integer_t > ( - 1 )
- static_cast < number_integer_t > ( number ) ) ;
}
2017-08-14 17:50:24 +02:00
// UTF-8 string (0x00..0x17 bytes follow)
case 0x60 :
case 0x61 :
case 0x62 :
case 0x63 :
case 0x64 :
case 0x65 :
case 0x66 :
case 0x67 :
case 0x68 :
case 0x69 :
case 0x6A :
case 0x6B :
case 0x6C :
case 0x6D :
case 0x6E :
case 0x6F :
case 0x70 :
case 0x71 :
case 0x72 :
case 0x73 :
case 0x74 :
case 0x75 :
case 0x76 :
case 0x77 :
case 0x78 : // UTF-8 string (one-byte uint8_t for n follows)
case 0x79 : // UTF-8 string (two-byte uint16_t for n follow)
case 0x7A : // UTF-8 string (four-byte uint32_t for n follow)
case 0x7B : // UTF-8 string (eight-byte uint64_t for n follow)
case 0x7F : // UTF-8 string (indefinite length)
2018-03-18 23:00:45 +01:00
{
string_t s ;
2018-03-21 20:12:06 +01:00
return get_cbor_string ( s ) and sax - > string ( s ) ;
2018-03-18 23:00:45 +01:00
}
2017-08-14 17:50:24 +02:00
// array (0x00..0x17 data items follow)
case 0x80 :
case 0x81 :
case 0x82 :
case 0x83 :
case 0x84 :
case 0x85 :
case 0x86 :
case 0x87 :
case 0x88 :
case 0x89 :
case 0x8A :
case 0x8B :
case 0x8C :
case 0x8D :
case 0x8E :
case 0x8F :
case 0x90 :
case 0x91 :
case 0x92 :
case 0x93 :
case 0x94 :
case 0x95 :
case 0x96 :
case 0x97 :
2018-03-18 23:00:45 +01:00
return get_cbor_array ( static_cast < std : : size_t > ( current & 0x1F ) ) ;
2017-08-14 17:50:24 +02:00
case 0x98 : // array (one-byte uint8_t for n follows)
2018-03-18 23:00:45 +01:00
{
uint8_t len ;
return get_number ( len ) and get_cbor_array ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0x99 : // array (two-byte uint16_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint16_t len ;
return get_number ( len ) and get_cbor_array ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0x9A : // array (four-byte uint32_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint32_t len ;
return get_number ( len ) and get_cbor_array ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0x9B : // array (eight-byte uint64_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint64_t len ;
return get_number ( len ) and get_cbor_array ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0x9F : // array (indefinite length)
2018-03-18 23:00:45 +01:00
return get_cbor_array ( json_sax_t : : no_limit ) ;
2017-08-14 17:50:24 +02:00
// map (0x00..0x17 pairs of data items follow)
case 0xA0 :
case 0xA1 :
case 0xA2 :
case 0xA3 :
case 0xA4 :
case 0xA5 :
case 0xA6 :
case 0xA7 :
case 0xA8 :
case 0xA9 :
case 0xAA :
case 0xAB :
case 0xAC :
case 0xAD :
case 0xAE :
case 0xAF :
case 0xB0 :
case 0xB1 :
case 0xB2 :
case 0xB3 :
case 0xB4 :
case 0xB5 :
case 0xB6 :
case 0xB7 :
2018-03-18 23:00:45 +01:00
return get_cbor_object ( static_cast < std : : size_t > ( current & 0x1F ) ) ;
2017-08-14 17:50:24 +02:00
case 0xB8 : // map (one-byte uint8_t for n follows)
2018-03-18 23:00:45 +01:00
{
uint8_t len ;
return get_number ( len ) and get_cbor_object ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0xB9 : // map (two-byte uint16_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint16_t len ;
return get_number ( len ) and get_cbor_object ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0xBA : // map (four-byte uint32_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint32_t len ;
return get_number ( len ) and get_cbor_object ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0xBB : // map (eight-byte uint64_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint64_t len ;
return get_number ( len ) and get_cbor_object ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0xBF : // map (indefinite length)
2018-03-18 23:00:45 +01:00
return get_cbor_object ( json_sax_t : : no_limit ) ;
2017-08-14 17:50:24 +02:00
case 0xF4 : // false
2018-03-11 18:47:38 +01:00
return sax - > boolean ( false ) ;
2017-08-14 17:50:24 +02:00
case 0xF5 : // true
2018-03-11 18:47:38 +01:00
return sax - > boolean ( true ) ;
2017-08-14 17:50:24 +02:00
case 0xF6 : // null
2018-03-11 18:47:38 +01:00
return sax - > null ( ) ;
2017-08-14 17:50:24 +02:00
case 0xF9 : // Half-Precision Float (two-byte IEEE 754)
{
const int byte1 = get ( ) ;
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2017-08-14 17:50:24 +02:00
const int byte2 = get ( ) ;
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2017-08-14 17:50:24 +02:00
// code from RFC 7049, Appendix D, Figure 3:
// As half-precision floating-point numbers were only added
// to IEEE 754 in 2008, today's programming platforms often
// still only have limited support for them. It is very
// easy to include at least decoding support for them even
// without such support. An example of a small decoder for
// half-precision floating-point numbers in the C language
// is shown in Fig. 3.
const int half = ( byte1 < < 8 ) + byte2 ;
2018-06-23 17:05:04 +02:00
const double val = [ & half ]
2017-08-14 17:50:24 +02:00
{
2018-06-23 17:05:04 +02:00
const int exp = ( half > > 10 ) & 0x1F ;
const int mant = half & 0x3FF ;
assert ( 0 < = exp and exp < = 32 ) ;
assert ( 0 < = mant and mant < = 1024 ) ;
switch ( exp )
{
case 0 :
return std : : ldexp ( mant , - 24 ) ;
case 31 :
return ( mant = = 0 )
? std : : numeric_limits < double > : : infinity ( )
: std : : numeric_limits < double > : : quiet_NaN ( ) ;
default :
return std : : ldexp ( mant + 1024 , exp - 25 ) ;
}
} ( ) ;
2018-06-23 10:28:04 +02:00
return sax - > number_float ( ( half & 0x8000 ) ! = 0
? static_cast < number_float_t > ( - val )
: static_cast < number_float_t > ( val ) , " " ) ;
2017-08-14 17:50:24 +02:00
}
case 0xFA : // Single-Precision Float (four-byte IEEE 754)
2018-03-18 23:00:45 +01:00
{
float number ;
2018-06-23 10:28:04 +02:00
return get_number ( number ) and sax - > number_float ( static_cast < number_float_t > ( number ) , " " ) ;
2018-03-18 23:00:45 +01:00
}
2017-08-14 17:50:24 +02:00
case 0xFB : // Double-Precision Float (eight-byte IEEE 754)
2018-03-18 23:00:45 +01:00
{
double number ;
2018-06-23 10:28:04 +02:00
return get_number ( number ) and sax - > number_float ( static_cast < number_float_t > ( number ) , " " ) ;
2018-03-18 23:00:45 +01:00
}
2017-08-14 17:50:24 +02:00
default : // anything else (0xFF is handled inside the other types)
{
2018-03-18 23:00:45 +01:00
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 112 , chars_read , " error reading CBOR; last byte: 0x " + last_token ) ) ;
2017-08-14 17:50:24 +02:00
}
}
}
2018-03-18 23:00:45 +01:00
/*!
@ return whether a valid MessagePack value was passed to the SAX parser
*/
bool parse_msgpack_internal ( )
2017-08-14 17:50:24 +02:00
{
switch ( get ( ) )
{
// EOF
case std : : char_traits < char > : : eof ( ) :
2018-03-18 23:00:45 +01:00
return unexpect_eof ( ) ;
2017-08-14 17:50:24 +02:00
// positive fixint
case 0x00 :
case 0x01 :
case 0x02 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x06 :
case 0x07 :
case 0x08 :
case 0x09 :
case 0x0A :
case 0x0B :
case 0x0C :
case 0x0D :
case 0x0E :
case 0x0F :
case 0x10 :
case 0x11 :
case 0x12 :
case 0x13 :
case 0x14 :
case 0x15 :
case 0x16 :
case 0x17 :
case 0x18 :
case 0x19 :
case 0x1A :
case 0x1B :
case 0x1C :
case 0x1D :
case 0x1E :
case 0x1F :
case 0x20 :
case 0x21 :
case 0x22 :
case 0x23 :
case 0x24 :
case 0x25 :
case 0x26 :
case 0x27 :
case 0x28 :
case 0x29 :
case 0x2A :
case 0x2B :
case 0x2C :
case 0x2D :
case 0x2E :
case 0x2F :
case 0x30 :
case 0x31 :
case 0x32 :
case 0x33 :
case 0x34 :
case 0x35 :
case 0x36 :
case 0x37 :
case 0x38 :
case 0x39 :
case 0x3A :
case 0x3B :
case 0x3C :
case 0x3D :
case 0x3E :
case 0x3F :
case 0x40 :
case 0x41 :
case 0x42 :
case 0x43 :
case 0x44 :
case 0x45 :
case 0x46 :
case 0x47 :
case 0x48 :
case 0x49 :
case 0x4A :
case 0x4B :
case 0x4C :
case 0x4D :
case 0x4E :
case 0x4F :
case 0x50 :
case 0x51 :
case 0x52 :
case 0x53 :
case 0x54 :
case 0x55 :
case 0x56 :
case 0x57 :
case 0x58 :
case 0x59 :
case 0x5A :
case 0x5B :
case 0x5C :
case 0x5D :
case 0x5E :
case 0x5F :
case 0x60 :
case 0x61 :
case 0x62 :
case 0x63 :
case 0x64 :
case 0x65 :
case 0x66 :
case 0x67 :
case 0x68 :
case 0x69 :
case 0x6A :
case 0x6B :
case 0x6C :
case 0x6D :
case 0x6E :
case 0x6F :
case 0x70 :
case 0x71 :
case 0x72 :
case 0x73 :
case 0x74 :
case 0x75 :
case 0x76 :
case 0x77 :
case 0x78 :
case 0x79 :
case 0x7A :
case 0x7B :
case 0x7C :
case 0x7D :
case 0x7E :
case 0x7F :
2018-03-11 18:47:38 +01:00
return sax - > number_unsigned ( static_cast < number_unsigned_t > ( current ) ) ;
2017-08-14 17:50:24 +02:00
// fixmap
case 0x80 :
case 0x81 :
case 0x82 :
case 0x83 :
case 0x84 :
case 0x85 :
case 0x86 :
case 0x87 :
case 0x88 :
case 0x89 :
case 0x8A :
case 0x8B :
case 0x8C :
case 0x8D :
case 0x8E :
case 0x8F :
2018-03-18 23:00:45 +01:00
return get_msgpack_object ( static_cast < std : : size_t > ( current & 0x0F ) ) ;
2017-08-14 17:50:24 +02:00
// fixarray
case 0x90 :
case 0x91 :
case 0x92 :
case 0x93 :
case 0x94 :
case 0x95 :
case 0x96 :
case 0x97 :
case 0x98 :
case 0x99 :
case 0x9A :
case 0x9B :
case 0x9C :
case 0x9D :
case 0x9E :
case 0x9F :
2018-03-18 23:00:45 +01:00
return get_msgpack_array ( static_cast < std : : size_t > ( current & 0x0F ) ) ;
2017-08-14 17:50:24 +02:00
// fixstr
case 0xA0 :
case 0xA1 :
case 0xA2 :
case 0xA3 :
case 0xA4 :
case 0xA5 :
case 0xA6 :
case 0xA7 :
case 0xA8 :
case 0xA9 :
case 0xAA :
case 0xAB :
case 0xAC :
case 0xAD :
case 0xAE :
case 0xAF :
case 0xB0 :
case 0xB1 :
case 0xB2 :
case 0xB3 :
case 0xB4 :
case 0xB5 :
case 0xB6 :
case 0xB7 :
case 0xB8 :
case 0xB9 :
case 0xBA :
case 0xBB :
case 0xBC :
case 0xBD :
case 0xBE :
case 0xBF :
2018-03-18 23:00:45 +01:00
{
string_t s ;
2018-03-21 20:12:06 +01:00
return get_msgpack_string ( s ) and sax - > string ( s ) ;
2018-03-18 23:00:45 +01:00
}
2017-08-14 17:50:24 +02:00
case 0xC0 : // nil
2018-03-11 18:47:38 +01:00
return sax - > null ( ) ;
2017-08-14 17:50:24 +02:00
case 0xC2 : // false
2018-03-11 18:47:38 +01:00
return sax - > boolean ( false ) ;
2017-08-14 17:50:24 +02:00
case 0xC3 : // true
2018-03-11 18:47:38 +01:00
return sax - > boolean ( true ) ;
2017-08-14 17:50:24 +02:00
case 0xCA : // float 32
2018-03-18 23:00:45 +01:00
{
float number ;
2018-06-23 10:28:04 +02:00
return get_number ( number ) and sax - > number_float ( static_cast < number_float_t > ( number ) , " " ) ;
2018-03-18 23:00:45 +01:00
}
2017-08-14 17:50:24 +02:00
case 0xCB : // float 64
2018-03-18 23:00:45 +01:00
{
double number ;
2018-06-23 10:28:04 +02:00
return get_number ( number ) and sax - > number_float ( static_cast < number_float_t > ( number ) , " " ) ;
2018-03-18 23:00:45 +01:00
}
2017-08-14 17:50:24 +02:00
case 0xCC : // uint 8
2018-03-18 23:00:45 +01:00
{
uint8_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0xCD : // uint 16
2018-03-18 23:00:45 +01:00
{
uint16_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0xCE : // uint 32
2018-03-18 23:00:45 +01:00
{
uint32_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0xCF : // uint 64
2018-03-18 23:00:45 +01:00
{
uint64_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0xD0 : // int 8
2018-03-18 23:00:45 +01:00
{
int8_t number ;
return get_number ( number ) and sax - > number_integer ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0xD1 : // int 16
2018-03-18 23:00:45 +01:00
{
int16_t number ;
return get_number ( number ) and sax - > number_integer ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0xD2 : // int 32
2018-03-18 23:00:45 +01:00
{
int32_t number ;
return get_number ( number ) and sax - > number_integer ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0xD3 : // int 64
2018-03-18 23:00:45 +01:00
{
int64_t number ;
return get_number ( number ) and sax - > number_integer ( number ) ;
}
2017-08-14 17:50:24 +02:00
case 0xD9 : // str 8
case 0xDA : // str 16
case 0xDB : // str 32
2018-03-18 23:00:45 +01:00
{
string_t s ;
2018-03-21 20:12:06 +01:00
return get_msgpack_string ( s ) and sax - > string ( s ) ;
2018-03-18 23:00:45 +01:00
}
2017-08-14 17:50:24 +02:00
case 0xDC : // array 16
2018-03-18 23:00:45 +01:00
{
uint16_t len ;
return get_number ( len ) and get_msgpack_array ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0xDD : // array 32
2018-03-18 23:00:45 +01:00
{
uint32_t len ;
return get_number ( len ) and get_msgpack_array ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0xDE : // map 16
2018-03-18 23:00:45 +01:00
{
uint16_t len ;
return get_number ( len ) and get_msgpack_object ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
case 0xDF : // map 32
2018-03-18 23:00:45 +01:00
{
uint32_t len ;
return get_number ( len ) and get_msgpack_object ( static_cast < std : : size_t > ( len ) ) ;
}
2017-08-14 17:50:24 +02:00
2018-03-11 18:47:38 +01:00
// negative fixint
2017-08-14 17:50:24 +02:00
case 0xE0 :
case 0xE1 :
case 0xE2 :
case 0xE3 :
case 0xE4 :
case 0xE5 :
case 0xE6 :
case 0xE7 :
case 0xE8 :
case 0xE9 :
case 0xEA :
case 0xEB :
case 0xEC :
case 0xED :
case 0xEE :
case 0xEF :
case 0xF0 :
case 0xF1 :
case 0xF2 :
case 0xF3 :
case 0xF4 :
case 0xF5 :
case 0xF6 :
case 0xF7 :
case 0xF8 :
case 0xF9 :
case 0xFA :
case 0xFB :
case 0xFC :
case 0xFD :
case 0xFE :
case 0xFF :
2018-03-11 18:47:38 +01:00
return sax - > number_integer ( static_cast < int8_t > ( current ) ) ;
2017-08-14 17:50:24 +02:00
default : // anything else
{
2018-03-18 23:00:45 +01:00
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 112 , chars_read , " error reading MessagePack; last byte: 0x " + last_token ) ) ;
2017-08-14 17:50:24 +02:00
}
}
}
2018-01-14 10:27:30 +01:00
/*!
@ 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
2018-03-18 23:00:45 +01:00
@ return whether a valid UBJSON value was passed to the SAX parser
2018-01-14 10:27:30 +01:00
*/
2018-03-18 23:00:45 +01:00
bool parse_ubjson_internal ( const bool get_char = true )
2018-01-14 10:27:30 +01:00
{
2018-03-18 23:00:45 +01:00
return get_ubjson_value ( get_char ? get_ignore_noop ( ) : current ) ;
2018-01-14 10:27:30 +01:00
}
2017-08-14 17:50:24 +02:00
/*!
@ brief get next character from the input
This function provides the interface to the used input adapter . It does
not throw in case the input reached EOF , but returns a - ' ve valued
` std : : char_traits < char > : : eof ( ) ` in that case .
@ return character read from the input
*/
int get ( )
{
+ + chars_read ;
return ( current = ia - > get_character ( ) ) ;
}
2018-01-14 10:27:30 +01:00
/*!
@ return character read from the input after ignoring all ' N ' entries
*/
int get_ignore_noop ( )
{
do
{
get ( ) ;
}
while ( current = = ' N ' ) ;
return current ;
}
2017-08-14 17:50:24 +02:00
/*
@ brief read a number from the input
@ tparam NumberType the type of the number
2018-03-18 23:00:45 +01:00
@ param [ out ] result number of type @ a NumberType
2017-08-14 17:50:24 +02:00
2018-03-18 23:00:45 +01:00
@ return whether conversion completed
2017-08-14 17:50:24 +02:00
@ note This function needs to respect the system ' s endianess , because
2018-03-18 23:00:45 +01:00
bytes in CBOR , MessagePack , and UBJSON are stored in network order
( big endian ) and therefore need reordering on little endian systems .
2017-08-14 17:50:24 +02:00
*/
2018-03-18 23:00:45 +01:00
template < typename NumberType >
bool get_number ( NumberType & result )
2017-08-14 17:50:24 +02:00
{
// step 1: read input into array with system's byte order
std : : array < uint8_t , sizeof ( NumberType ) > vec ;
for ( std : : size_t i = 0 ; i < sizeof ( NumberType ) ; + + i )
{
get ( ) ;
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2017-08-14 17:50:24 +02:00
// reverse byte order prior to conversion if necessary
if ( is_little_endian )
{
vec [ sizeof ( NumberType ) - i - 1 ] = static_cast < uint8_t > ( current ) ;
}
else
{
vec [ i ] = static_cast < uint8_t > ( current ) ; // LCOV_EXCL_LINE
}
}
// step 2: convert array into number of type T and return
std : : memcpy ( & result , vec . data ( ) , sizeof ( NumberType ) ) ;
2018-03-18 23:00:45 +01:00
return true ;
2017-08-14 17:50:24 +02:00
}
/*!
@ brief create a string by reading characters from the input
2018-03-18 23:00:45 +01:00
@ tparam NumberType the type of the number
@ param [ in ] len number of characters to read
@ param [ out ] string created by reading @ a len bytes
@ return whether string creation completed
2017-08-14 17:50:24 +02:00
@ note We can not reserve @ a len bytes for the result , because @ a len
2018-01-28 13:15:03 +01:00
may be too large . Usually , @ ref unexpect_eof ( ) detects the end of
2017-08-14 17:50:24 +02:00
the input before we run out of string memory .
*/
template < typename NumberType >
2018-03-18 23:00:45 +01:00
bool get_string ( const NumberType len , string_t & result )
2017-08-14 17:50:24 +02:00
{
2018-03-18 23:00:45 +01:00
bool success = true ;
std : : generate_n ( std : : back_inserter ( result ) , len , [ this , & success ] ( )
2017-08-14 17:50:24 +02:00
{
get ( ) ;
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
success = false ;
}
2017-08-14 17:50:24 +02:00
return static_cast < char > ( current ) ;
} ) ;
2018-03-18 23:00:45 +01:00
return success ;
2017-08-14 17:50:24 +02:00
}
/*!
@ brief reads a CBOR string
This function first reads starting bytes to determine the expected
string length and then copies this number of bytes into a string .
Additionally , CBOR ' s strings with indefinite lengths are supported .
2018-03-18 23:00:45 +01:00
@ param [ out ] result created string
2017-08-14 17:50:24 +02:00
2018-03-18 23:00:45 +01:00
@ return whether string creation completed
2017-08-14 17:50:24 +02:00
*/
2018-03-18 23:00:45 +01:00
bool get_cbor_string ( string_t & result )
2017-08-14 17:50:24 +02:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2017-08-14 17:50:24 +02:00
switch ( current )
{
// UTF-8 string (0x00..0x17 bytes follow)
case 0x60 :
case 0x61 :
case 0x62 :
case 0x63 :
case 0x64 :
case 0x65 :
case 0x66 :
case 0x67 :
case 0x68 :
case 0x69 :
case 0x6A :
case 0x6B :
case 0x6C :
case 0x6D :
case 0x6E :
case 0x6F :
case 0x70 :
case 0x71 :
case 0x72 :
case 0x73 :
case 0x74 :
case 0x75 :
case 0x76 :
case 0x77 :
2018-03-18 23:00:45 +01:00
{
return get_string ( current & 0x1F , result ) ;
}
2017-08-14 17:50:24 +02:00
case 0x78 : // UTF-8 string (one-byte uint8_t for n follows)
2018-03-18 23:00:45 +01:00
{
uint8_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2017-08-14 17:50:24 +02:00
case 0x79 : // UTF-8 string (two-byte uint16_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint16_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2017-08-14 17:50:24 +02:00
case 0x7A : // UTF-8 string (four-byte uint32_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint32_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2017-08-14 17:50:24 +02:00
case 0x7B : // UTF-8 string (eight-byte uint64_t for n follow)
2018-03-18 23:00:45 +01:00
{
uint64_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2017-08-14 17:50:24 +02:00
case 0x7F : // UTF-8 string (indefinite length)
{
while ( get ( ) ! = 0xFF )
{
2018-03-18 23:00:45 +01:00
string_t chunk ;
if ( not get_cbor_string ( chunk ) )
{
return false ;
}
result . append ( chunk ) ;
2017-08-14 17:50:24 +02:00
}
2018-03-18 23:00:45 +01:00
return true ;
2017-08-14 17:50:24 +02:00
}
default :
{
2018-03-18 23:00:45 +01:00
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 113 , chars_read , " expected a CBOR string; last byte: 0x " + last_token ) ) ;
2017-08-14 17:50:24 +02:00
}
}
}
2018-03-18 23:00:45 +01:00
/*!
@ param [ in ] len the length of the array or json_sax_t : : no_limit for an
array of indefinite size
@ return whether array creation completed
*/
bool get_cbor_array ( const std : : size_t len )
2017-08-14 17:50:24 +02:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not sax - > start_array ( len ) ) )
2017-08-14 17:50:24 +02:00
{
2018-03-11 18:47:38 +01:00
return false ;
}
if ( len ! = json_sax_t : : no_limit )
for ( std : : size_t i = 0 ; i < len ; + + i )
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_cbor_internal ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
}
else
{
while ( get ( ) ! = 0xFF )
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_cbor_internal ( false ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
}
}
return sax - > end_array ( ) ;
2017-08-14 17:50:24 +02:00
}
2018-03-18 23:00:45 +01:00
/*!
@ param [ in ] len the length of the object or json_sax_t : : no_limit for an
object of indefinite size
@ return whether object creation completed
*/
bool get_cbor_object ( const std : : size_t len )
2017-08-14 17:50:24 +02:00
{
2018-03-18 23:00:45 +01:00
if ( not JSON_UNLIKELY ( sax - > start_object ( len ) ) )
2017-08-14 17:50:24 +02:00
{
2018-03-11 18:47:38 +01:00
return false ;
}
2018-03-21 20:12:06 +01:00
string_t key ;
2018-03-11 18:47:38 +01:00
if ( len ! = json_sax_t : : no_limit )
{
for ( std : : size_t i = 0 ; i < len ; + + i )
{
get ( ) ;
2018-03-21 20:12:06 +01:00
if ( JSON_UNLIKELY ( not get_cbor_string ( key ) or not sax - > key ( key ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_cbor_internal ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-21 20:12:06 +01:00
key . clear ( ) ;
2018-03-11 18:47:38 +01:00
}
}
else
{
while ( get ( ) ! = 0xFF )
{
2018-03-21 20:12:06 +01:00
if ( JSON_UNLIKELY ( not get_cbor_string ( key ) or not sax - > key ( key ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_cbor_internal ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-21 20:12:06 +01:00
key . clear ( ) ;
2018-03-11 18:47:38 +01:00
}
}
return sax - > end_object ( ) ;
2017-08-14 17:50:24 +02:00
}
/*!
@ brief reads a MessagePack string
This function first reads starting bytes to determine the expected
string length and then copies this number of bytes into a string .
2018-03-18 23:00:45 +01:00
@ param [ out ] result created string
2017-08-14 17:50:24 +02:00
2018-03-18 23:00:45 +01:00
@ return whether string creation completed
2017-08-14 17:50:24 +02:00
*/
2018-03-18 23:00:45 +01:00
bool get_msgpack_string ( string_t & result )
2017-08-14 17:50:24 +02:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2017-08-14 17:50:24 +02:00
switch ( current )
{
// fixstr
case 0xA0 :
case 0xA1 :
case 0xA2 :
case 0xA3 :
case 0xA4 :
case 0xA5 :
case 0xA6 :
case 0xA7 :
case 0xA8 :
case 0xA9 :
case 0xAA :
case 0xAB :
case 0xAC :
case 0xAD :
case 0xAE :
case 0xAF :
case 0xB0 :
case 0xB1 :
case 0xB2 :
case 0xB3 :
case 0xB4 :
case 0xB5 :
case 0xB6 :
case 0xB7 :
case 0xB8 :
case 0xB9 :
case 0xBA :
case 0xBB :
case 0xBC :
case 0xBD :
case 0xBE :
case 0xBF :
2018-03-18 23:00:45 +01:00
{
return get_string ( current & 0x1F , result ) ;
}
2017-08-14 17:50:24 +02:00
case 0xD9 : // str 8
2018-03-18 23:00:45 +01:00
{
uint8_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2017-08-14 17:50:24 +02:00
case 0xDA : // str 16
2018-03-18 23:00:45 +01:00
{
uint16_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2017-08-14 17:50:24 +02:00
case 0xDB : // str 32
2018-03-18 23:00:45 +01:00
{
uint32_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2017-08-14 17:50:24 +02:00
default :
{
2018-03-18 23:00:45 +01:00
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 113 , chars_read , " expected a MessagePack string; last byte: 0x " + last_token ) ) ;
2017-08-14 17:50:24 +02:00
}
}
}
2018-03-18 23:00:45 +01:00
/*!
@ param [ in ] len the length of the array
@ return whether array creation completed
*/
bool get_msgpack_array ( const std : : size_t len )
2017-08-14 17:50:24 +02:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not sax - > start_array ( len ) ) )
2017-08-14 17:50:24 +02:00
{
2018-03-11 18:47:38 +01:00
return false ;
}
for ( std : : size_t i = 0 ; i < len ; + + i )
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_msgpack_internal ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
}
return sax - > end_array ( ) ;
2017-08-14 17:50:24 +02:00
}
2018-03-18 23:00:45 +01:00
/*!
@ param [ in ] len the length of the object
@ return whether object creation completed
*/
bool get_msgpack_object ( const std : : size_t len )
2017-08-14 17:50:24 +02:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not sax - > start_object ( len ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-21 20:12:06 +01:00
string_t key ;
2018-03-11 18:47:38 +01:00
for ( std : : size_t i = 0 ; i < len ; + + i )
2017-08-14 17:50:24 +02:00
{
get ( ) ;
2018-03-21 20:12:06 +01:00
if ( JSON_UNLIKELY ( not get_msgpack_string ( key ) or not sax - > key ( key ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_msgpack_internal ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-21 20:12:06 +01:00
key . clear ( ) ;
2018-03-11 18:47:38 +01:00
}
return sax - > end_object ( ) ;
2017-08-14 17:50:24 +02:00
}
2018-01-14 10:27:30 +01:00
/*!
@ 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 .
2018-03-18 23:00:45 +01:00
@ param [ out ] result created string
2018-01-14 10:27:30 +01:00
@ 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
2018-03-18 23:00:45 +01:00
@ return whether string creation completed
2018-01-14 10:27:30 +01:00
*/
2018-03-18 23:00:45 +01:00
bool get_ubjson_string ( string_t & result , const bool get_char = true )
2018-01-14 10:27:30 +01:00
{
if ( get_char )
{
get ( ) ; // TODO: may we ignore N here?
}
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2018-01-14 10:27:30 +01:00
switch ( current )
{
case ' U ' :
2018-03-18 23:00:45 +01:00
{
uint8_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2018-01-14 10:27:30 +01:00
case ' i ' :
2018-03-18 23:00:45 +01:00
{
int8_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2018-01-14 10:27:30 +01:00
case ' I ' :
2018-03-18 23:00:45 +01:00
{
int16_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2018-01-14 10:27:30 +01:00
case ' l ' :
2018-03-18 23:00:45 +01:00
{
int32_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2018-01-14 10:27:30 +01:00
case ' L ' :
2018-03-18 23:00:45 +01:00
{
int64_t len ;
return get_number ( len ) and get_string ( len , result ) ;
}
2018-01-14 10:27:30 +01:00
default :
2018-03-18 23:00:45 +01:00
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 113 , chars_read , " expected a UBJSON string; last byte: 0x " + last_token ) ) ;
2018-01-14 10:27:30 +01:00
}
}
2018-03-18 23:00:45 +01:00
/*!
@ param [ out ] result determined size
@ return whether size determination completed
*/
bool get_ubjson_size_value ( std : : size_t & result )
2018-03-11 18:47:38 +01:00
{
switch ( get_ignore_noop ( ) )
{
case ' U ' :
2018-03-18 23:00:45 +01:00
{
uint8_t number ;
if ( JSON_UNLIKELY ( not get_number ( number ) ) )
{
return false ;
}
result = static_cast < std : : size_t > ( number ) ;
return true ;
}
2018-03-11 18:47:38 +01:00
case ' i ' :
2018-03-18 23:00:45 +01:00
{
int8_t number ;
if ( JSON_UNLIKELY ( not get_number ( number ) ) )
{
return false ;
}
result = static_cast < std : : size_t > ( number ) ;
return true ;
}
2018-03-11 18:47:38 +01:00
case ' I ' :
2018-03-18 23:00:45 +01:00
{
int16_t number ;
if ( JSON_UNLIKELY ( not get_number ( number ) ) )
{
return false ;
}
result = static_cast < std : : size_t > ( number ) ;
return true ;
}
2018-03-11 18:47:38 +01:00
case ' l ' :
2018-03-18 23:00:45 +01:00
{
int32_t number ;
if ( JSON_UNLIKELY ( not get_number ( number ) ) )
{
return false ;
}
result = static_cast < std : : size_t > ( number ) ;
return true ;
}
2018-03-11 18:47:38 +01:00
case ' L ' :
2018-03-18 23:00:45 +01:00
{
int64_t number ;
if ( JSON_UNLIKELY ( not get_number ( number ) ) )
{
return false ;
}
result = static_cast < std : : size_t > ( number ) ;
return true ;
}
2018-03-11 18:47:38 +01:00
default :
2018-03-18 23:00:45 +01:00
{
2018-03-20 18:49:10 +01:00
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 113 , chars_read , " byte after '#' must denote a number type; last byte: 0x " + last_token ) ) ;
2018-03-18 23:00:45 +01:00
}
2018-03-11 18:47:38 +01:00
}
}
2018-01-14 10:27:30 +01:00
/*!
@ 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 .
2018-03-18 23:00:45 +01:00
@ param [ out ] result pair of the size and the type
@ return whether pair creation completed
2018-01-14 10:27:30 +01:00
*/
2018-03-18 23:00:45 +01:00
bool get_ubjson_size_type ( std : : pair < std : : size_t , int > & result )
2018-01-14 10:27:30 +01:00
{
2018-03-18 23:00:45 +01:00
result . first = string_t : : npos ; // size
result . second = 0 ; // type
2018-01-14 10:27:30 +01:00
get_ignore_noop ( ) ;
if ( current = = ' $ ' )
{
2018-03-18 23:00:45 +01:00
result . second = get ( ) ; // must not ignore 'N', because 'N' maybe the type
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2018-01-14 10:27:30 +01:00
get_ignore_noop ( ) ;
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( current ! = ' # ' ) )
2018-01-14 10:27:30 +01:00
{
2018-03-20 18:49:10 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2018-03-18 23:00:45 +01:00
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 112 , chars_read , " expected '#' after UBJSON type information; last byte: 0x " + last_token ) ) ;
2018-01-14 10:27:30 +01:00
}
2018-03-18 23:00:45 +01:00
return get_ubjson_size_value ( result . first ) ;
2018-01-14 10:27:30 +01:00
}
else if ( current = = ' # ' )
{
2018-03-18 23:00:45 +01:00
return get_ubjson_size_value ( result . first ) ;
2018-01-14 10:27:30 +01:00
}
2018-03-18 23:00:45 +01:00
return true ;
2018-01-14 10:27:30 +01:00
}
2018-03-18 23:00:45 +01:00
/*!
@ param prefix the previously read or set type prefix
@ return whether value creation completed
*/
bool get_ubjson_value ( const int prefix )
2018-01-14 10:27:30 +01:00
{
switch ( prefix )
{
case std : : char_traits < char > : : eof ( ) : // EOF
2018-03-18 23:00:45 +01:00
return unexpect_eof ( ) ;
2018-01-14 10:27:30 +01:00
case ' T ' : // true
2018-03-11 18:47:38 +01:00
return sax - > boolean ( true ) ;
2018-01-14 10:27:30 +01:00
case ' F ' : // false
2018-03-11 18:47:38 +01:00
return sax - > boolean ( false ) ;
2018-01-14 10:27:30 +01:00
case ' Z ' : // null
2018-03-11 18:47:38 +01:00
return sax - > null ( ) ;
2018-01-14 10:27:30 +01:00
case ' U ' :
2018-03-18 23:00:45 +01:00
{
uint8_t number ;
return get_number ( number ) and sax - > number_unsigned ( number ) ;
}
2018-01-14 10:27:30 +01:00
case ' i ' :
2018-03-18 23:00:45 +01:00
{
int8_t number ;
return get_number ( number ) and sax - > number_integer ( number ) ;
}
2018-01-14 10:27:30 +01:00
case ' I ' :
2018-03-18 23:00:45 +01:00
{
int16_t number ;
return get_number ( number ) and sax - > number_integer ( number ) ;
}
2018-01-14 10:27:30 +01:00
case ' l ' :
2018-03-18 23:00:45 +01:00
{
int32_t number ;
return get_number ( number ) and sax - > number_integer ( number ) ;
}
2018-01-14 10:27:30 +01:00
case ' L ' :
2018-03-18 23:00:45 +01:00
{
int64_t number ;
return get_number ( number ) and sax - > number_integer ( number ) ;
}
2018-01-14 10:27:30 +01:00
case ' d ' :
2018-03-18 23:00:45 +01:00
{
float number ;
2018-06-23 10:28:04 +02:00
return get_number ( number ) and sax - > number_float ( static_cast < number_float_t > ( number ) , " " ) ;
2018-03-18 23:00:45 +01:00
}
2018-01-14 10:27:30 +01:00
case ' D ' :
2018-03-18 23:00:45 +01:00
{
double number ;
2018-06-23 10:28:04 +02:00
return get_number ( number ) and sax - > number_float ( static_cast < number_float_t > ( number ) , " " ) ;
2018-03-18 23:00:45 +01:00
}
2018-01-14 10:27:30 +01:00
case ' C ' : // char
{
get ( ) ;
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not unexpect_eof ( ) ) )
{
return false ;
}
2018-01-14 17:22:06 +01:00
if ( JSON_UNLIKELY ( current > 127 ) )
2018-01-14 10:27:30 +01:00
{
2018-03-18 23:00:45 +01:00
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 113 , chars_read , " byte after 'C' must be in range 0x00..0x7F; last byte: 0x " + last_token ) ) ;
2018-01-14 10:27:30 +01:00
}
2018-03-21 20:12:06 +01:00
string_t s ( 1 , static_cast < char > ( current ) ) ;
return sax - > string ( s ) ;
2018-01-14 10:27:30 +01:00
}
case ' S ' : // string
2018-03-18 23:00:45 +01:00
{
string_t s ;
2018-03-21 20:12:06 +01:00
return get_ubjson_string ( s ) and sax - > string ( s ) ;
2018-03-18 23:00:45 +01:00
}
2018-01-14 10:27:30 +01:00
case ' [ ' : // array
2018-03-18 23:00:45 +01:00
return get_ubjson_array ( ) ;
2018-01-14 10:27:30 +01:00
case ' { ' : // object
2018-03-18 23:00:45 +01:00
return get_ubjson_object ( ) ;
2018-01-14 10:27:30 +01:00
default : // anything else
2018-03-18 23:00:45 +01:00
{
auto last_token = get_token_string ( ) ;
return sax - > parse_error ( chars_read , last_token , parse_error : : create ( 112 , chars_read , " error reading UBJSON; last byte: 0x " + last_token ) ) ;
}
2018-01-14 10:27:30 +01:00
}
}
2018-03-18 23:00:45 +01:00
/*!
@ return whether array creation completed
*/
bool get_ubjson_array ( )
2018-01-14 10:27:30 +01:00
{
2018-03-18 23:00:45 +01:00
std : : pair < std : : size_t , int > size_and_type ;
if ( JSON_UNLIKELY ( not get_ubjson_size_type ( size_and_type ) ) )
{
return false ;
}
2018-01-14 10:27:30 +01:00
2018-02-01 08:01:01 +01:00
if ( size_and_type . first ! = string_t : : npos )
2018-01-14 10:27:30 +01:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not sax - > start_array ( size_and_type . first ) ) )
2018-02-06 22:38:53 +01:00
{
2018-03-11 18:47:38 +01:00
return false ;
2018-02-06 22:38:53 +01:00
}
2018-01-14 10:27:30 +01:00
if ( size_and_type . second ! = 0 )
{
if ( size_and_type . second ! = ' N ' )
2018-02-06 22:38:53 +01:00
{
2018-03-11 18:47:38 +01:00
for ( std : : size_t i = 0 ; i < size_and_type . first ; + + i )
2018-02-06 22:38:53 +01:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not get_ubjson_value ( size_and_type . second ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
}
2018-02-06 22:38:53 +01:00
}
2018-01-14 10:27:30 +01:00
}
else
{
2018-03-11 18:47:38 +01:00
for ( std : : size_t i = 0 ; i < size_and_type . first ; + + i )
2018-01-14 10:27:30 +01:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_ubjson_internal ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
}
2018-01-14 10:27:30 +01:00
}
}
else
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not sax - > start_array ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-01-14 10:27:30 +01:00
while ( current ! = ' ] ' )
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_ubjson_internal ( false ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-01-14 10:27:30 +01:00
get_ignore_noop ( ) ;
}
}
2018-03-11 18:47:38 +01:00
return sax - > end_array ( ) ;
2018-01-14 10:27:30 +01:00
}
2018-03-18 23:00:45 +01:00
/*!
@ return whether object creation completed
*/
bool get_ubjson_object ( )
2018-01-14 10:27:30 +01:00
{
2018-03-18 23:00:45 +01:00
std : : pair < std : : size_t , int > size_and_type ;
if ( JSON_UNLIKELY ( not get_ubjson_size_type ( size_and_type ) ) )
{
return false ;
}
2018-01-14 10:27:30 +01:00
2018-03-21 20:12:06 +01:00
string_t key ;
2018-02-01 08:01:01 +01:00
if ( size_and_type . first ! = string_t : : npos )
2018-01-14 10:27:30 +01:00
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not sax - > start_object ( size_and_type . first ) ) )
2018-02-06 22:38:53 +01:00
{
2018-03-11 18:47:38 +01:00
return false ;
2018-02-06 22:38:53 +01:00
}
2018-01-14 10:27:30 +01:00
if ( size_and_type . second ! = 0 )
{
2018-03-11 18:47:38 +01:00
for ( std : : size_t i = 0 ; i < size_and_type . first ; + + i )
2018-01-14 10:27:30 +01:00
{
2018-03-21 20:12:06 +01:00
if ( JSON_UNLIKELY ( not get_ubjson_string ( key ) or not sax - > key ( key ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not get_ubjson_value ( size_and_type . second ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-21 20:12:06 +01:00
key . clear ( ) ;
2018-03-11 18:47:38 +01:00
}
2018-01-14 10:27:30 +01:00
}
else
{
2018-03-11 18:47:38 +01:00
for ( std : : size_t i = 0 ; i < size_and_type . first ; + + i )
2018-01-14 10:27:30 +01:00
{
2018-03-21 20:12:06 +01:00
if ( JSON_UNLIKELY ( not get_ubjson_string ( key ) or not sax - > key ( key ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_ubjson_internal ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-21 20:12:06 +01:00
key . clear ( ) ;
2018-03-11 18:47:38 +01:00
}
2018-01-14 10:27:30 +01:00
}
}
else
{
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not sax - > start_object ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-01-14 10:27:30 +01:00
while ( current ! = ' } ' )
{
2018-03-21 20:12:06 +01:00
if ( JSON_UNLIKELY ( not get_ubjson_string ( key , false ) or not sax - > key ( key ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-03-18 23:00:45 +01:00
if ( JSON_UNLIKELY ( not parse_ubjson_internal ( ) ) )
2018-03-11 18:47:38 +01:00
{
return false ;
}
2018-01-14 10:27:30 +01:00
get_ignore_noop ( ) ;
2018-03-21 20:12:06 +01:00
key . clear ( ) ;
2018-01-14 10:27:30 +01:00
}
}
2018-03-11 18:47:38 +01:00
return sax - > end_object ( ) ;
2018-01-14 10:27:30 +01:00
}
2018-01-28 13:15:03 +01:00
/*!
2018-03-18 23:00:45 +01:00
@ return whether the last read character is not EOF
2018-01-28 13:15:03 +01:00
*/
2018-03-18 23:00:45 +01:00
bool unexpect_eof ( ) const
2018-01-28 13:15:03 +01:00
{
if ( JSON_UNLIKELY ( current = = std : : char_traits < char > : : eof ( ) ) )
2017-08-14 17:50:24 +02:00
{
2018-03-18 23:00:45 +01:00
return sax - > parse_error ( chars_read , " <end of file> " , parse_error : : create ( 110 , chars_read , " unexpected end of input " ) ) ;
2017-08-14 17:50:24 +02:00
}
2018-03-18 23:00:45 +01:00
return true ;
}
/*!
@ return a string representation of the last read byte
*/
std : : string get_token_string ( ) const
{
2018-05-31 13:27:11 +02:00
char cr [ 3 ] ;
2018-06-23 10:28:04 +02:00
snprintf ( cr , 3 , " %.2hhX " , static_cast < unsigned char > ( current ) ) ;
2018-05-31 13:27:11 +02:00
return std : : string { cr } ;
2017-08-14 17:50:24 +02:00
}
private :
/// input adapter
input_adapter_t ia = nullptr ;
/// the current character
int current = std : : char_traits < char > : : eof ( ) ;
/// the number of characters read
std : : size_t chars_read = 0 ;
/// whether we can assume little endianess
const bool is_little_endian = little_endianess ( ) ;
2018-03-18 23:00:45 +01:00
/// the SAX parser
json_sax_t * sax = nullptr ;
2017-08-14 17:50:24 +02:00
} ;
}
}