Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / json_spirit / json_spirit_reader_template.h
1 #ifndef JSON_SPIRIT_READER_TEMPLATE\r
2 #define JSON_SPIRIT_READER_TEMPLATE\r
3 \r
4 //          Copyright John W. Wilkinson 2007 - 2011\r
5 // Distributed under the MIT License, see accompanying file LICENSE.txt\r
6 \r
7 // json spirit version 4.05\r
8 \r
9 #if defined(_MSC_VER) && (_MSC_VER >= 1020)\r
10 # pragma once\r
11 #endif\r
12 \r
13 #include "json_spirit_value.h"\r
14 #include "json_spirit_error_position.h"\r
15 \r
16 #include "common/utf8.h"\r
17 \r
18 #define BOOST_SPIRIT_THREADSAFE  // uncomment for multithreaded use, requires linking to boost.thread\r
19 \r
20 #include <boost/bind.hpp>\r
21 #include <boost/function.hpp>\r
22 #include <boost/version.hpp>\r
23 \r
24 #if BOOST_VERSION >= 103800\r
25     #include <boost/spirit/include/classic_core.hpp>\r
26     #include <boost/spirit/include/classic_confix.hpp>\r
27     #include <boost/spirit/include/classic_escape_char.hpp>\r
28     #include <boost/spirit/include/classic_multi_pass.hpp>\r
29     #include <boost/spirit/include/classic_position_iterator.hpp>\r
30     #define spirit_namespace boost::spirit::classic\r
31 #else\r
32     #include <boost/spirit/core.hpp>\r
33     #include <boost/spirit/utility/confix.hpp>\r
34     #include <boost/spirit/utility/escape_char.hpp>\r
35     #include <boost/spirit/iterator/multi_pass.hpp>\r
36     #include <boost/spirit/iterator/position_iterator.hpp>\r
37     #define spirit_namespace boost::spirit\r
38 #endif\r
39 \r
40 namespace json_spirit\r
41 {\r
42     const spirit_namespace::int_parser < boost::int64_t >  int64_p  = spirit_namespace::int_parser < boost::int64_t  >();\r
43     const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >();\r
44 \r
45     template< class Iter_type >\r
46     bool is_eq( Iter_type first, Iter_type last, const char* c_str )\r
47     {\r
48         for( Iter_type i = first; i != last; ++i, ++c_str )\r
49         {\r
50             if( *c_str == 0 ) return false;\r
51 \r
52             if( *i != *c_str ) return false;\r
53         }\r
54 \r
55         return true;\r
56     }\r
57 \r
58     template< class Char_type >\r
59     Char_type hex_to_num( const Char_type c )\r
60     {\r
61         if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0';\r
62         if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10;\r
63         if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10;\r
64         return 0;\r
65     }\r
66 \r
67     template< class Char_type, class Iter_type >\r
68     Char_type hex_str_to_char( Iter_type& begin )\r
69     {\r
70         const Char_type c1( *( ++begin ) );\r
71         const Char_type c2( *( ++begin ) );\r
72 \r
73         return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 );\r
74     }       \r
75 \r
76     template< class String_type, class Iter_type >\r
77     String_type unicode_str_to_utf8( Iter_type& begin );\r
78 \r
79     template<>\r
80     std::string unicode_str_to_utf8( std::string::const_iterator & begin )\r
81     {\r
82         typedef std::string::value_type Char_type;\r
83 \r
84         const Char_type c1( *( ++begin ) );\r
85         const Char_type c2( *( ++begin ) );\r
86         const Char_type c3( *( ++begin ) );\r
87         const Char_type c4( *( ++begin ) );\r
88 \r
89         unsigned long uc = ( hex_to_num( c1 ) << 12 ) + \r
90                            ( hex_to_num( c2 ) <<  8 ) + \r
91                            ( hex_to_num( c3 ) <<  4 ) + \r
92                            hex_to_num( c4 );\r
93 \r
94         unsigned char buf[7];  // MAX_UTF8_SZ is 6 (see src/common/utf8.c)\r
95         int r = encode_utf8(uc, buf);\r
96         if (r >= 0) {\r
97             return std::string(reinterpret_cast<char *>(buf), r);\r
98         }\r
99         return std::string("_");\r
100     }\r
101 \r
102     template< class String_type >\r
103     void append_esc_char_and_incr_iter( String_type& s, \r
104                                         typename String_type::const_iterator& begin, \r
105                                         typename String_type::const_iterator end )\r
106     {\r
107         typedef typename String_type::value_type Char_type;\r
108              \r
109         const Char_type c2( *begin );\r
110 \r
111         switch( c2 )\r
112         {\r
113             case 't':  s += '\t'; break;\r
114             case 'b':  s += '\b'; break;\r
115             case 'f':  s += '\f'; break;\r
116             case 'n':  s += '\n'; break;\r
117             case 'r':  s += '\r'; break;\r
118             case '\\': s += '\\'; break;\r
119             case '/':  s += '/';  break;\r
120             case '"':  s += '"';  break;\r
121             case 'x':  \r
122             {\r
123                 if( end - begin >= 3 )  //  expecting "xHH..."\r
124                 {\r
125                     s += hex_str_to_char< Char_type >( begin );  \r
126                 }\r
127                 break;\r
128             }\r
129             case 'u':  \r
130             {\r
131                 if( end - begin >= 5 )  //  expecting "uHHHH..."\r
132                 {\r
133                     s += unicode_str_to_utf8< String_type >( begin );\r
134                 }\r
135                 break;\r
136             }\r
137         }\r
138     }\r
139 \r
140     template< class String_type >\r
141     String_type substitute_esc_chars( typename String_type::const_iterator begin, \r
142                                    typename String_type::const_iterator end )\r
143     {\r
144         typedef typename String_type::const_iterator Iter_type;\r
145 \r
146         if( end - begin < 2 ) return String_type( begin, end );\r
147 \r
148         String_type result;\r
149         \r
150         result.reserve( end - begin );\r
151 \r
152         const Iter_type end_minus_1( end - 1 );\r
153 \r
154         Iter_type substr_start = begin;\r
155         Iter_type i = begin;\r
156 \r
157         for( ; i < end_minus_1; ++i )\r
158         {\r
159             if( *i == '\\' )\r
160             {\r
161                 result.append( substr_start, i );\r
162 \r
163                 ++i;  // skip the '\'\r
164              \r
165                 append_esc_char_and_incr_iter( result, i, end );\r
166 \r
167                 substr_start = i + 1;\r
168             }\r
169         }\r
170 \r
171         result.append( substr_start, end );\r
172 \r
173         return result;\r
174     }\r
175 \r
176     template< class String_type >\r
177     String_type get_str_( typename String_type::const_iterator begin, \r
178                        typename String_type::const_iterator end )\r
179     {\r
180         assert( end - begin >= 2 );\r
181 \r
182         typedef typename String_type::const_iterator Iter_type;\r
183 \r
184         Iter_type str_without_quotes( ++begin );\r
185         Iter_type end_without_quotes( --end );\r
186 \r
187         return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes );\r
188     }\r
189 \r
190     inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end )\r
191     {\r
192         return get_str_< std::string >( begin, end );\r
193     }\r
194 \r
195 // Need this guard else it tries to instantiate unicode_str_to_utf8 with a\r
196 // std::wstring, which isn't presently implemented\r
197 #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING )\r
198     inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end )\r
199     {\r
200         return get_str_< std::wstring >( begin, end );\r
201     }\r
202 #endif\r
203 \r
204     template< class String_type, class Iter_type >\r
205     String_type get_str( Iter_type begin, Iter_type end )\r
206     {\r
207         const String_type tmp( begin, end );  // convert multipass iterators to string iterators\r
208 \r
209         return get_str( tmp.begin(), tmp.end() );\r
210     }\r
211 \r
212     // this class's methods get called by the spirit parse resulting\r
213     // in the creation of a JSON object or array\r
214     //\r
215     // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator\r
216     //\r
217     template< class Value_type, class Iter_type >\r
218     class Semantic_actions \r
219     {\r
220     public:\r
221 \r
222         typedef typename Value_type::Config_type Config_type;\r
223         typedef typename Config_type::String_type String_type;\r
224         typedef typename Config_type::Object_type Object_type;\r
225         typedef typename Config_type::Array_type Array_type;\r
226         typedef typename String_type::value_type Char_type;\r
227 \r
228         Semantic_actions( Value_type& value )\r
229         :   value_( value )\r
230         ,   current_p_( 0 )\r
231         {\r
232         }\r
233 \r
234         void begin_obj( Char_type c )\r
235         {\r
236             assert( c == '{' );\r
237 \r
238             begin_compound< Object_type >();\r
239         }\r
240 \r
241         void end_obj( Char_type c )\r
242         {\r
243             assert( c == '}' );\r
244 \r
245             end_compound();\r
246         }\r
247 \r
248         void begin_array( Char_type c )\r
249         {\r
250             assert( c == '[' );\r
251      \r
252             begin_compound< Array_type >();\r
253         }\r
254 \r
255         void end_array( Char_type c )\r
256         {\r
257             assert( c == ']' );\r
258 \r
259             end_compound();\r
260         }\r
261 \r
262         void new_name( Iter_type begin, Iter_type end )\r
263         {\r
264             assert( current_p_->type() == obj_type );\r
265 \r
266             name_ = get_str< String_type >( begin, end );\r
267         }\r
268 \r
269         void new_str( Iter_type begin, Iter_type end )\r
270         {\r
271             add_to_current( get_str< String_type >( begin, end ) );\r
272         }\r
273 \r
274         void new_true( Iter_type begin, Iter_type end )\r
275         {\r
276             assert( is_eq( begin, end, "true" ) );\r
277 \r
278             add_to_current( true );\r
279         }\r
280 \r
281         void new_false( Iter_type begin, Iter_type end )\r
282         {\r
283             assert( is_eq( begin, end, "false" ) );\r
284 \r
285             add_to_current( false );\r
286         }\r
287 \r
288         void new_null( Iter_type begin, Iter_type end )\r
289         {\r
290             assert( is_eq( begin, end, "null" ) );\r
291 \r
292             add_to_current( Value_type() );\r
293         }\r
294 \r
295         void new_int( boost::int64_t i )\r
296         {\r
297             add_to_current( i );\r
298         }\r
299 \r
300         void new_uint64( boost::uint64_t ui )\r
301         {\r
302             add_to_current( ui );\r
303         }\r
304 \r
305         void new_real( double d )\r
306         {\r
307             add_to_current( d );\r
308         }\r
309 \r
310     private:\r
311 \r
312         Semantic_actions& operator=( const Semantic_actions& ); \r
313                                     // to prevent "assignment operator could not be generated" warning\r
314 \r
315         Value_type* add_first( const Value_type& value )\r
316         {\r
317             assert( current_p_ == 0 );\r
318 \r
319             value_ = value;\r
320             current_p_ = &value_;\r
321             return current_p_;\r
322         }\r
323 \r
324         template< class Array_or_obj >\r
325         void begin_compound()\r
326         {\r
327             if( current_p_ == 0 )\r
328             {\r
329                 add_first( Array_or_obj() );\r
330             }\r
331             else\r
332             {\r
333                 stack_.push_back( current_p_ );\r
334 \r
335                 Array_or_obj new_array_or_obj;   // avoid copy by building new array or object in place\r
336 \r
337                 current_p_ = add_to_current( new_array_or_obj );\r
338             }\r
339         }\r
340 \r
341         void end_compound()\r
342         {\r
343             if( current_p_ != &value_ )\r
344             {\r
345                 current_p_ = stack_.back();\r
346                 \r
347                 stack_.pop_back();\r
348             }    \r
349         }\r
350 \r
351         Value_type* add_to_current( const Value_type& value )\r
352         {\r
353             if( current_p_ == 0 )\r
354             {\r
355                 return add_first( value );\r
356             }\r
357             else if( current_p_->type() == array_type )\r
358             {\r
359                 current_p_->get_array().push_back( value );\r
360 \r
361                 return &current_p_->get_array().back(); \r
362             }\r
363             \r
364             assert( current_p_->type() == obj_type );\r
365 \r
366             return &Config_type::add( current_p_->get_obj(), name_, value );\r
367         }\r
368 \r
369         Value_type& value_;             // this is the object or array that is being created\r
370         Value_type* current_p_;         // the child object or array that is currently being constructed\r
371 \r
372         std::vector< Value_type* > stack_;   // previous child objects and arrays\r
373 \r
374         String_type name_;              // of current name/value pair\r
375     };\r
376 \r
377     template< typename Iter_type >\r
378     void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason )\r
379     {\r
380         throw Error_position( i.get_position().line, i.get_position().column, reason );\r
381     }\r
382 \r
383     template< typename Iter_type >\r
384     void throw_error( Iter_type i, const std::string& reason )\r
385     {\r
386        throw reason;\r
387     }\r
388 \r
389     // the spirit grammer \r
390     //\r
391     template< class Value_type, class Iter_type >\r
392     class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > >\r
393     {\r
394     public:\r
395 \r
396         typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t;\r
397 \r
398         Json_grammer( Semantic_actions_t& semantic_actions )\r
399         :   actions_( semantic_actions )\r
400         {\r
401         }\r
402 \r
403         static void throw_not_value( Iter_type begin, Iter_type end )\r
404         {\r
405             throw_error( begin, "not a value" );\r
406         }\r
407 \r
408         static void throw_not_array( Iter_type begin, Iter_type end )\r
409         {\r
410             throw_error( begin, "not an array" );\r
411         }\r
412 \r
413         static void throw_not_object( Iter_type begin, Iter_type end )\r
414         {\r
415             throw_error( begin, "not an object" );\r
416         }\r
417 \r
418         static void throw_not_pair( Iter_type begin, Iter_type end )\r
419         {\r
420             throw_error( begin, "not a pair" );\r
421         }\r
422 \r
423         static void throw_not_colon( Iter_type begin, Iter_type end )\r
424         {\r
425             throw_error( begin, "no colon in pair" );\r
426         }\r
427 \r
428         static void throw_not_string( Iter_type begin, Iter_type end )\r
429         {\r
430             throw_error( begin, "not a string" );\r
431         }\r
432 \r
433         template< typename ScannerT >\r
434         class definition\r
435         {\r
436         public:\r
437 \r
438             definition( const Json_grammer& self )\r
439             {\r
440                 using namespace spirit_namespace;\r
441 \r
442                 typedef typename Value_type::String_type::value_type Char_type;\r
443 \r
444                 // first we convert the semantic action class methods to functors with the \r
445                 // parameter signature expected by spirit\r
446 \r
447                 typedef boost::function< void( Char_type )            > Char_action;\r
448                 typedef boost::function< void( Iter_type, Iter_type ) > Str_action;\r
449                 typedef boost::function< void( double )               > Real_action;\r
450                 typedef boost::function< void( boost::int64_t )       > Int_action;\r
451                 typedef boost::function< void( boost::uint64_t )      > Uint64_action;\r
452 \r
453                 Char_action   begin_obj  ( boost::bind( &Semantic_actions_t::begin_obj,   &self.actions_, _1 ) );\r
454                 Char_action   end_obj    ( boost::bind( &Semantic_actions_t::end_obj,     &self.actions_, _1 ) );\r
455                 Char_action   begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) );\r
456                 Char_action   end_array  ( boost::bind( &Semantic_actions_t::end_array,   &self.actions_, _1 ) );\r
457                 Str_action    new_name   ( boost::bind( &Semantic_actions_t::new_name,    &self.actions_, _1, _2 ) );\r
458                 Str_action    new_str    ( boost::bind( &Semantic_actions_t::new_str,     &self.actions_, _1, _2 ) );\r
459                 Str_action    new_true   ( boost::bind( &Semantic_actions_t::new_true,    &self.actions_, _1, _2 ) );\r
460                 Str_action    new_false  ( boost::bind( &Semantic_actions_t::new_false,   &self.actions_, _1, _2 ) );\r
461                 Str_action    new_null   ( boost::bind( &Semantic_actions_t::new_null,    &self.actions_, _1, _2 ) );\r
462                 Real_action   new_real   ( boost::bind( &Semantic_actions_t::new_real,    &self.actions_, _1 ) );\r
463                 Int_action    new_int    ( boost::bind( &Semantic_actions_t::new_int,     &self.actions_, _1 ) );\r
464                 Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64,  &self.actions_, _1 ) );\r
465 \r
466                 // actual grammer\r
467 \r
468                 json_\r
469                     = value_ | eps_p[ &throw_not_value ]\r
470                     ;\r
471 \r
472                 value_\r
473                     = string_[ new_str ] \r
474                     | number_ \r
475                     | object_ \r
476                     | array_ \r
477                     | str_p( "true" ) [ new_true  ] \r
478                     | str_p( "false" )[ new_false ] \r
479                     | str_p( "null" ) [ new_null  ]\r
480                     ;\r
481 \r
482                 object_ \r
483                     = ch_p('{')[ begin_obj ]\r
484                     >> !members_\r
485                     >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] )\r
486                     ;\r
487 \r
488                 members_\r
489                     = pair_ >> *( ',' >> pair_  | ch_p(',') )\r
490                     ;\r
491 \r
492                 pair_\r
493                     = string_[ new_name ]\r
494                     >> ( ':' | eps_p[ &throw_not_colon ] )\r
495                     >> ( value_ | eps_p[ &throw_not_value ] )\r
496                     ;\r
497 \r
498                 array_\r
499                     = ch_p('[')[ begin_array ]\r
500                     >> !elements_\r
501                     >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] )\r
502                     ;\r
503 \r
504                 elements_\r
505                     = value_ >> *( ',' >> value_ | ch_p(',') )\r
506                     ;\r
507 \r
508                 string_ \r
509                     = lexeme_d // this causes white space inside a string to be retained\r
510                       [\r
511                           confix_p\r
512                           ( \r
513                               '"', \r
514                               *lex_escape_ch_p,\r
515                               '"'\r
516                           ) \r
517                       ]\r
518                     ;\r
519 \r
520                 number_\r
521                     = strict_real_p[ new_real   ] \r
522                     | int64_p      [ new_int    ]\r
523                     | uint64_p     [ new_uint64 ]\r
524                     ;\r
525             }\r
526 \r
527             spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_;\r
528 \r
529             const spirit_namespace::rule< ScannerT >& start() const { return json_; }\r
530         };\r
531 \r
532     private:\r
533 \r
534         Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning\r
535 \r
536         Semantic_actions_t& actions_;\r
537     };\r
538 \r
539     template< class Iter_type, class Value_type >\r
540     void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )\r
541     {\r
542         typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t;\r
543 \r
544         const Posn_iter_t posn_begin( begin, end );\r
545         const Posn_iter_t posn_end( end, end );\r
546      \r
547         read_range_or_throw( posn_begin, posn_end, value );\r
548     }\r
549 \r
550     template< class Istream_type >\r
551     struct Multi_pass_iters\r
552     {\r
553         typedef typename Istream_type::char_type Char_type;\r
554         typedef std::istream_iterator< Char_type, Char_type > istream_iter;\r
555         typedef spirit_namespace::multi_pass< istream_iter > Mp_iter;\r
556 \r
557         Multi_pass_iters( Istream_type& is )\r
558         {\r
559             is.unsetf( std::ios::skipws );\r
560 \r
561             begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) );\r
562             end_   = spirit_namespace::make_multi_pass( istream_iter() );\r
563         }\r
564 \r
565         Mp_iter begin_;\r
566         Mp_iter end_;\r
567     };\r
568 \r
569     // reads a JSON Value from a pair of input iterators throwing an exception on invalid input, e.g.\r
570     //\r
571     // string::const_iterator start = str.begin();\r
572     // const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), value );\r
573     //\r
574     // The iterator 'next' will point to the character past the \r
575     // last one read.\r
576     //\r
577     template< class Iter_type, class Value_type >\r
578     Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )\r
579     {\r
580         Semantic_actions< Value_type, Iter_type > semantic_actions( value );\r
581      \r
582         const spirit_namespace::parse_info< Iter_type > info = \r
583                             spirit_namespace::parse( begin, end, \r
584                                                     Json_grammer< Value_type, Iter_type >( semantic_actions ), \r
585                                                     spirit_namespace::space_p );\r
586 \r
587         if( !info.hit )\r
588         {\r
589             assert( false ); // in theory exception should already have been thrown\r
590             throw_error( info.stop, "error" );\r
591         }\r
592 \r
593         return info.stop;\r
594     }\r
595 \r
596     // reads a JSON Value from a pair of input iterators, e.g.\r
597     //\r
598     // string::const_iterator start = str.begin();\r
599     // const bool success = read_string( start, str.end(), value );\r
600     //\r
601     // The iterator 'start' will point to the character past the \r
602     // last one read.\r
603     //\r
604     template< class Iter_type, class Value_type >\r
605     bool read_range( Iter_type& begin, Iter_type end, Value_type& value )\r
606     {\r
607         try\r
608         {\r
609             begin = read_range_or_throw( begin, end, value );\r
610 \r
611             return true;\r
612         }\r
613         catch( ... )\r
614         {\r
615             return false;\r
616         }\r
617     }\r
618 \r
619     // reads a JSON Value from a string, e.g.\r
620     //\r
621     // const bool success = read_string( str, value );\r
622     //\r
623     template< class String_type, class Value_type >\r
624     bool read_string( const String_type& s, Value_type& value )\r
625     {\r
626         typename String_type::const_iterator begin = s.begin();\r
627 \r
628         return read_range( begin, s.end(), value );\r
629     }\r
630 \r
631     // reads a JSON Value from a string throwing an exception on invalid input, e.g.\r
632     //\r
633     // read_string_or_throw( is, value );\r
634     //\r
635     template< class String_type, class Value_type >\r
636     void read_string_or_throw( const String_type& s, Value_type& value )\r
637     {\r
638         add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value );\r
639     }\r
640 \r
641     // reads a JSON Value from a stream, e.g.\r
642     //\r
643     // const bool success = read_stream( is, value );\r
644     //\r
645     template< class Istream_type, class Value_type >\r
646     bool read_stream( Istream_type& is, Value_type& value )\r
647     {\r
648         Multi_pass_iters< Istream_type > mp_iters( is );\r
649 \r
650         return read_range( mp_iters.begin_, mp_iters.end_, value );\r
651     }\r
652 \r
653     // reads a JSON Value from a stream throwing an exception on invalid input, e.g.\r
654     //\r
655     // read_stream_or_throw( is, value );\r
656     //\r
657     template< class Istream_type, class Value_type >\r
658     void read_stream_or_throw( Istream_type& is, Value_type& value )\r
659     {\r
660         const Multi_pass_iters< Istream_type > mp_iters( is );\r
661 \r
662         add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value );\r
663     }\r
664 }\r
665 \r
666 #endif\r