1 #ifndef JSON_SPIRIT_READER_TEMPLATE
2 #define JSON_SPIRIT_READER_TEMPLATE
4 // Copyright John W. Wilkinson 2007 - 2011
5 // Distributed under the MIT License, see accompanying file LICENSE.txt
7 // json spirit version 4.05
9 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
13 #include "json_spirit_value.h"
14 #include "json_spirit_error_position.h"
16 #include "common/utf8.h"
18 #define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread
20 #include <boost/bind/bind.hpp>
21 #include <boost/function.hpp>
22 #include <boost/version.hpp>
23 #include <boost/spirit/include/classic_core.hpp>
24 #include <boost/spirit/include/classic_confix.hpp>
25 #include <boost/spirit/include/classic_escape_char.hpp>
26 #include <boost/spirit/include/classic_multi_pass.hpp>
27 #include <boost/spirit/include/classic_position_iterator.hpp>
29 #include "include/ceph_assert.h"
33 namespace spirit_namespace
= boost::spirit::classic
;
35 const spirit_namespace::int_parser
< boost::int64_t > int64_p
= spirit_namespace::int_parser
< boost::int64_t >();
36 const spirit_namespace::uint_parser
< boost::uint64_t > uint64_p
= spirit_namespace::uint_parser
< boost::uint64_t >();
38 template< class Iter_type
>
39 bool is_eq( Iter_type first
, Iter_type last
, const char* c_str
)
41 for( Iter_type i
= first
; i
!= last
; ++i
, ++c_str
)
43 if( *c_str
== 0 ) return false;
45 if( *i
!= *c_str
) return false;
51 template< class Char_type
>
52 Char_type
hex_to_num( const Char_type c
)
54 if( ( c
>= '0' ) && ( c
<= '9' ) ) return c
- '0';
55 if( ( c
>= 'a' ) && ( c
<= 'f' ) ) return c
- 'a' + 10;
56 if( ( c
>= 'A' ) && ( c
<= 'F' ) ) return c
- 'A' + 10;
60 template< class Char_type
, class Iter_type
>
61 Char_type
hex_str_to_char( Iter_type
& begin
)
63 const Char_type
c1( *( ++begin
) );
64 const Char_type
c2( *( ++begin
) );
66 return ( hex_to_num( c1
) << 4 ) + hex_to_num( c2
);
69 template< class String_type
, class Iter_type
>
70 String_type
unicode_str_to_utf8( Iter_type
& begin
);
73 std::string
unicode_str_to_utf8( std::string::const_iterator
& begin
)
75 typedef std::string::value_type Char_type
;
77 const Char_type
c1( *( ++begin
) );
78 const Char_type
c2( *( ++begin
) );
79 const Char_type
c3( *( ++begin
) );
80 const Char_type
c4( *( ++begin
) );
82 unsigned long uc
= ( hex_to_num( c1
) << 12 ) +
83 ( hex_to_num( c2
) << 8 ) +
84 ( hex_to_num( c3
) << 4 ) +
87 unsigned char buf
[7]; // MAX_UTF8_SZ is 6 (see src/common/utf8.c)
88 int r
= encode_utf8(uc
, buf
);
90 return std::string(reinterpret_cast<char *>(buf
), r
);
92 return std::string("_");
95 template< class String_type
>
96 void append_esc_char_and_incr_iter( String_type
& s
,
97 typename
String_type::const_iterator
& begin
,
98 typename
String_type::const_iterator end
)
100 typedef typename
String_type::value_type Char_type
;
102 const Char_type
c2( *begin
);
106 case 't': s
+= '\t'; break;
107 case 'b': s
+= '\b'; break;
108 case 'f': s
+= '\f'; break;
109 case 'n': s
+= '\n'; break;
110 case 'r': s
+= '\r'; break;
111 case '\\': s
+= '\\'; break;
112 case '/': s
+= '/'; break;
113 case '"': s
+= '"'; break;
116 if( end
- begin
>= 3 ) // expecting "xHH..."
118 s
+= hex_str_to_char
< Char_type
>( begin
);
124 if( end
- begin
>= 5 ) // expecting "uHHHH..."
126 s
+= unicode_str_to_utf8
< String_type
>( begin
);
133 template< class String_type
>
134 String_type
substitute_esc_chars( typename
String_type::const_iterator begin
,
135 typename
String_type::const_iterator end
)
137 typedef typename
String_type::const_iterator Iter_type
;
139 if( end
- begin
< 2 ) return String_type( begin
, end
);
143 result
.reserve( end
- begin
);
145 const Iter_type
end_minus_1( end
- 1 );
147 Iter_type substr_start
= begin
;
150 for( ; i
< end_minus_1
; ++i
)
154 result
.append( substr_start
, i
);
158 append_esc_char_and_incr_iter( result
, i
, end
);
160 substr_start
= i
+ 1;
164 result
.append( substr_start
, end
);
169 template< class String_type
>
170 String_type
get_str_( typename
String_type::const_iterator begin
,
171 typename
String_type::const_iterator end
)
173 ceph_assert( end
- begin
>= 2 );
175 typedef typename
String_type::const_iterator Iter_type
;
177 Iter_type
str_without_quotes( ++begin
);
178 Iter_type
end_without_quotes( --end
);
180 return substitute_esc_chars
< String_type
>( str_without_quotes
, end_without_quotes
);
183 inline std::string
get_str( std::string::const_iterator begin
, std::string::const_iterator end
)
185 return get_str_
< std::string
>( begin
, end
);
188 // Need this guard else it tries to instantiate unicode_str_to_utf8 with a
189 // std::wstring, which isn't presently implemented
190 #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING )
191 inline std::wstring
get_str( std::wstring::const_iterator begin
, std::wstring::const_iterator end
)
193 return get_str_
< std::wstring
>( begin
, end
);
197 template< class String_type
, class Iter_type
>
198 String_type
get_str( Iter_type begin
, Iter_type end
)
200 const String_type
tmp( begin
, end
); // convert multipass iterators to string iterators
202 return get_str( tmp
.begin(), tmp
.end() );
205 using namespace boost::placeholders
;
207 // this class's methods get called by the spirit parse resulting
208 // in the creation of a JSON object or array
210 // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator
212 template< class Value_type
, class Iter_type
>
213 class Semantic_actions
217 typedef typename
Value_type::Config_type Config_type
;
218 typedef typename
Config_type::String_type String_type
;
219 typedef typename
Config_type::Object_type Object_type
;
220 typedef typename
Config_type::Array_type Array_type
;
221 typedef typename
String_type::value_type Char_type
;
223 Semantic_actions( Value_type
& value
)
229 void begin_obj( Char_type c
)
231 ceph_assert( c
== '{' );
233 begin_compound
< Object_type
>();
236 void end_obj( Char_type c
)
238 ceph_assert( c
== '}' );
243 void begin_array( Char_type c
)
245 ceph_assert( c
== '[' );
247 begin_compound
< Array_type
>();
250 void end_array( Char_type c
)
252 ceph_assert( c
== ']' );
257 void new_name( Iter_type begin
, Iter_type end
)
259 ceph_assert( current_p_
->type() == obj_type
);
261 name_
= get_str
< String_type
>( begin
, end
);
264 void new_str( Iter_type begin
, Iter_type end
)
266 add_to_current( get_str
< String_type
>( begin
, end
) );
269 void new_true( Iter_type begin
, Iter_type end
)
271 ceph_assert( is_eq( begin
, end
, "true" ) );
273 add_to_current( true );
276 void new_false( Iter_type begin
, Iter_type end
)
278 ceph_assert( is_eq( begin
, end
, "false" ) );
280 add_to_current( false );
283 void new_null( Iter_type begin
, Iter_type end
)
285 ceph_assert( is_eq( begin
, end
, "null" ) );
287 add_to_current( Value_type() );
290 void new_int( boost::int64_t i
)
295 void new_uint64( boost::uint64_t ui
)
297 add_to_current( ui
);
300 void new_real( double d
)
307 Semantic_actions
& operator=( const Semantic_actions
& );
308 // to prevent "assignment operator could not be generated" warning
310 Value_type
* add_first( const Value_type
& value
)
312 ceph_assert( current_p_
== 0 );
315 current_p_
= &value_
;
319 template< class Array_or_obj
>
320 void begin_compound()
322 if( current_p_
== 0 )
324 add_first( Array_or_obj() );
328 stack_
.push_back( current_p_
);
330 Array_or_obj new_array_or_obj
; // avoid copy by building new array or object in place
332 current_p_
= add_to_current( new_array_or_obj
);
338 if( current_p_
!= &value_
)
340 current_p_
= stack_
.back();
346 Value_type
* add_to_current( const Value_type
& value
)
348 if( current_p_
== 0 )
350 return add_first( value
);
352 else if( current_p_
->type() == array_type
)
354 current_p_
->get_array().push_back( value
);
356 return ¤t_p_
->get_array().back();
359 ceph_assert( current_p_
->type() == obj_type
);
361 return &Config_type::add( current_p_
->get_obj(), name_
, value
);
364 Value_type
& value_
; // this is the object or array that is being created
365 Value_type
* current_p_
; // the child object or array that is currently being constructed
367 std::vector
< Value_type
* > stack_
; // previous child objects and arrays
369 String_type name_
; // of current name/value pair
372 template< typename Iter_type
>
373 void throw_error( spirit_namespace::position_iterator
< Iter_type
> i
, const std::string
& reason
)
375 throw Error_position( i
.get_position().line
, i
.get_position().column
, reason
);
378 template< typename Iter_type
>
379 void throw_error( Iter_type i
, const std::string
& reason
)
384 // the spirit grammar
386 template< class Value_type
, class Iter_type
>
387 class Json_grammer
: public spirit_namespace::grammar
< Json_grammer
< Value_type
, Iter_type
> >
391 typedef Semantic_actions
< Value_type
, Iter_type
> Semantic_actions_t
;
393 Json_grammer( Semantic_actions_t
& semantic_actions
)
394 : actions_( semantic_actions
)
398 static void throw_not_value( Iter_type begin
, Iter_type end
)
400 throw_error( begin
, "not a value" );
403 static void throw_not_array( Iter_type begin
, Iter_type end
)
405 throw_error( begin
, "not an array" );
408 static void throw_not_object( Iter_type begin
, Iter_type end
)
410 throw_error( begin
, "not an object" );
413 static void throw_not_pair( Iter_type begin
, Iter_type end
)
415 throw_error( begin
, "not a pair" );
418 static void throw_not_colon( Iter_type begin
, Iter_type end
)
420 throw_error( begin
, "no colon in pair" );
423 static void throw_not_string( Iter_type begin
, Iter_type end
)
425 throw_error( begin
, "not a string" );
428 template< typename ScannerT
>
433 definition( const Json_grammer
& self
)
435 using namespace spirit_namespace
;
437 typedef typename
Value_type::String_type::value_type Char_type
;
439 // first we convert the semantic action class methods to functors with the
440 // parameter signature expected by spirit
442 typedef boost::function
< void( Char_type
) > Char_action
;
443 typedef boost::function
< void( Iter_type
, Iter_type
) > Str_action
;
444 typedef boost::function
< void( double ) > Real_action
;
445 typedef boost::function
< void( boost::int64_t ) > Int_action
;
446 typedef boost::function
< void( boost::uint64_t ) > Uint64_action
;
448 Char_action
begin_obj ( boost::bind( &Semantic_actions_t::begin_obj
, &self
.actions_
, _1
) );
449 Char_action
end_obj ( boost::bind( &Semantic_actions_t::end_obj
, &self
.actions_
, _1
) );
450 Char_action
begin_array( boost::bind( &Semantic_actions_t::begin_array
, &self
.actions_
, _1
) );
451 Char_action
end_array ( boost::bind( &Semantic_actions_t::end_array
, &self
.actions_
, _1
) );
452 Str_action
new_name ( boost::bind( &Semantic_actions_t::new_name
, &self
.actions_
, _1
, _2
) );
453 Str_action
new_str ( boost::bind( &Semantic_actions_t::new_str
, &self
.actions_
, _1
, _2
) );
454 Str_action
new_true ( boost::bind( &Semantic_actions_t::new_true
, &self
.actions_
, _1
, _2
) );
455 Str_action
new_false ( boost::bind( &Semantic_actions_t::new_false
, &self
.actions_
, _1
, _2
) );
456 Str_action
new_null ( boost::bind( &Semantic_actions_t::new_null
, &self
.actions_
, _1
, _2
) );
457 Real_action
new_real ( boost::bind( &Semantic_actions_t::new_real
, &self
.actions_
, _1
) );
458 Int_action
new_int ( boost::bind( &Semantic_actions_t::new_int
, &self
.actions_
, _1
) );
459 Uint64_action
new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64
, &self
.actions_
, _1
) );
464 = value_
| eps_p
[ &throw_not_value
]
472 | str_p( "true" ) [ new_true
]
473 | str_p( "false" )[ new_false
]
474 | str_p( "null" ) [ new_null
]
478 = ch_p('{')[ begin_obj
]
480 >> ( ch_p('}')[ end_obj
] | eps_p
[ &throw_not_object
] )
484 = pair_
>> *( ',' >> pair_
| ch_p(',') )
488 = string_
[ new_name
]
489 >> ( ':' | eps_p
[ &throw_not_colon
] )
490 >> ( value_
| eps_p
[ &throw_not_value
] )
494 = ch_p('[')[ begin_array
]
496 >> ( ch_p(']')[ end_array
] | eps_p
[ &throw_not_array
] )
500 = value_
>> *( ',' >> value_
| ch_p(',') )
504 = lexeme_d
// this causes white space inside a string to be retained
516 = strict_real_p
[ new_real
]
517 | int64_p
[ new_int
]
518 | uint64_p
[ new_uint64
]
522 spirit_namespace::rule
< ScannerT
> json_
, object_
, members_
, pair_
, array_
, elements_
, value_
, string_
, number_
;
524 const spirit_namespace::rule
< ScannerT
>& start() const { return json_
; }
529 Json_grammer
& operator=( const Json_grammer
& ); // to prevent "assignment operator could not be generated" warning
531 Semantic_actions_t
& actions_
;
534 template< class Iter_type
, class Value_type
>
535 void add_posn_iter_and_read_range_or_throw( Iter_type begin
, Iter_type end
, Value_type
& value
)
537 typedef spirit_namespace::position_iterator
< Iter_type
> Posn_iter_t
;
539 const Posn_iter_t
posn_begin( begin
, end
);
540 const Posn_iter_t
posn_end( end
, end
);
542 read_range_or_throw( posn_begin
, posn_end
, value
);
545 template< class Istream_type
>
546 struct Multi_pass_iters
548 typedef typename
Istream_type::char_type Char_type
;
549 typedef std::istream_iterator
< Char_type
, Char_type
> istream_iter
;
550 typedef spirit_namespace::multi_pass
< istream_iter
> Mp_iter
;
552 Multi_pass_iters( Istream_type
& is
)
554 is
.unsetf( std::ios::skipws
);
556 begin_
= spirit_namespace::make_multi_pass( istream_iter( is
) );
557 end_
= spirit_namespace::make_multi_pass( istream_iter() );
564 // reads a JSON Value from a pair of input iterators throwing an exception on invalid input, e.g.
566 // string::const_iterator start = str.begin();
567 // const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), value );
569 // The iterator 'next' will point to the character past the
572 template< class Iter_type
, class Value_type
>
573 Iter_type
read_range_or_throw( Iter_type begin
, Iter_type end
, Value_type
& value
)
575 Semantic_actions
< Value_type
, Iter_type
> semantic_actions( value
);
577 const spirit_namespace::parse_info
< Iter_type
> info
=
578 spirit_namespace::parse( begin
, end
,
579 Json_grammer
< Value_type
, Iter_type
>( semantic_actions
),
580 spirit_namespace::space_p
);
584 ceph_assert( false ); // in theory exception should already have been thrown
585 throw_error( info
.stop
, "error" );
591 // reads a JSON Value from a pair of input iterators, e.g.
593 // string::const_iterator start = str.begin();
594 // const bool success = read_string( start, str.end(), value );
596 // The iterator 'start' will point to the character past the
599 template< class Iter_type
, class Value_type
>
600 bool read_range( Iter_type
& begin
, Iter_type end
, Value_type
& value
)
604 begin
= read_range_or_throw( begin
, end
, value
);
614 // reads a JSON Value from a string, e.g.
616 // const bool success = read_string( str, value );
618 template< class String_type
, class Value_type
>
619 bool read_string( const String_type
& s
, Value_type
& value
)
621 typename
String_type::const_iterator begin
= s
.begin();
623 return read_range( begin
, s
.end(), value
);
626 // reads a JSON Value from a string throwing an exception on invalid input, e.g.
628 // read_string_or_throw( is, value );
630 template< class String_type
, class Value_type
>
631 void read_string_or_throw( const String_type
& s
, Value_type
& value
)
633 add_posn_iter_and_read_range_or_throw( s
.begin(), s
.end(), value
);
636 // reads a JSON Value from a stream, e.g.
638 // const bool success = read_stream( is, value );
640 template< class Istream_type
, class Value_type
>
641 bool read_stream( Istream_type
& is
, Value_type
& value
)
643 Multi_pass_iters
< Istream_type
> mp_iters( is
);
645 return read_range( mp_iters
.begin_
, mp_iters
.end_
, value
);
648 // reads a JSON Value from a stream throwing an exception on invalid input, e.g.
650 // read_stream_or_throw( is, value );
652 template< class Istream_type
, class Value_type
>
653 void read_stream_or_throw( Istream_type
& is
, Value_type
& value
)
655 const Multi_pass_iters
< Istream_type
> mp_iters( is
);
657 add_posn_iter_and_read_range_or_throw( mp_iters
.begin_
, mp_iters
.end_
, value
);