1 #ifndef JSON_SPIRIT_WRITER_TEMPLATE
2 #define JSON_SPIRIT_WRITER_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_writer_options.h"
18 #include <boost/io/ios_state.hpp>
20 #include "include/ceph_assert.h"
24 inline char to_hex_char( unsigned int c
)
26 ceph_assert( c
<= 0xF );
28 const char ch
= static_cast< char >( c
);
30 if( ch
< 10 ) return '0' + ch
;
35 template< class String_type
>
36 String_type
non_printable_to_string( unsigned int c
)
38 String_type
result( 6, '\\' );
42 result
[ 5 ] = to_hex_char( c
& 0x000F ); c
>>= 4;
43 result
[ 4 ] = to_hex_char( c
& 0x000F ); c
>>= 4;
44 result
[ 3 ] = to_hex_char( c
& 0x000F ); c
>>= 4;
45 result
[ 2 ] = to_hex_char( c
& 0x000F );
50 template< typename Char_type
, class String_type
>
51 bool add_esc_char( Char_type c
, String_type
& s
)
55 case '"': s
+= to_str
< String_type
>( "\\\"" ); return true;
56 case '\\': s
+= to_str
< String_type
>( "\\\\" ); return true;
57 case '\b': s
+= to_str
< String_type
>( "\\b" ); return true;
58 case '\f': s
+= to_str
< String_type
>( "\\f" ); return true;
59 case '\n': s
+= to_str
< String_type
>( "\\n" ); return true;
60 case '\r': s
+= to_str
< String_type
>( "\\r" ); return true;
61 case '\t': s
+= to_str
< String_type
>( "\\t" ); return true;
67 template< class String_type
>
68 String_type
add_esc_chars( const String_type
& s
, bool raw_utf8
)
70 typedef typename
String_type::const_iterator Iter_type
;
71 typedef typename
String_type::value_type Char_type
;
75 const Iter_type
end( s
.end() );
77 for( Iter_type i
= s
.begin(); i
!= end
; ++i
)
79 const Char_type
c( *i
);
81 if( add_esc_char( c
, result
) ) continue;
89 const wint_t unsigned_c( ( c
>= 0 ) ? c
: 256 + c
);
91 if( iswprint( unsigned_c
) )
97 result
+= non_printable_to_string
< String_type
>( unsigned_c
);
105 template< class Ostream
>
106 void append_double( Ostream
& os
, const double d
, const int precision
)
108 os
<< std::showpoint
<< std::setprecision( precision
) << d
;
111 template< class String_type
>
112 void erase_and_extract_exponent( String_type
& str
, String_type
& exp
)
114 const typename
String_type::size_type exp_start
= str
.find( 'e' );
116 if( exp_start
!= String_type::npos
)
118 exp
= str
.substr( exp_start
);
119 str
.erase( exp_start
);
123 template< class String_type
>
124 typename
String_type::size_type
find_first_non_zero( const String_type
& str
)
126 typename
String_type::size_type result
= str
.size() - 1;
128 for( ; result
!= 0; --result
)
130 if( str
[ result
] != '0' )
139 template< class String_type
>
140 void remove_trailing( String_type
& str
)
144 erase_and_extract_exponent( str
, exp
);
146 const typename
String_type::size_type first_non_zero
= find_first_non_zero( str
);
148 if( first_non_zero
!= 0 )
150 const int offset
= str
[first_non_zero
] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard
151 str
.erase( first_non_zero
+ offset
);
157 // this class generates the JSON text,
158 // it keeps track of the indentation level etc.
160 template< class Value_type
, class Ostream_type
>
163 typedef typename
Value_type::Config_type Config_type
;
164 typedef typename
Config_type::String_type String_type
;
165 typedef typename
Config_type::Object_type Object_type
;
166 typedef typename
Config_type::Array_type Array_type
;
167 typedef typename
String_type::value_type Char_type
;
168 typedef typename
Object_type::value_type Obj_member_type
;
172 Generator( const Value_type
& value
, Ostream_type
& os
, unsigned int options
)
174 , indentation_level_( 0 )
175 , pretty_( ( options
& pretty_print
) != 0 || ( options
& single_line_arrays
) != 0 )
176 , raw_utf8_( ( options
& raw_utf8
) != 0 )
177 , remove_trailing_zeros_( ( options
& remove_trailing_zeros
) != 0 )
178 , single_line_arrays_( ( options
& single_line_arrays
) != 0 )
186 void output( const Value_type
& value
)
188 switch( value
.type() )
190 case obj_type
: output( value
.get_obj() ); break;
191 case array_type
: output( value
.get_array() ); break;
192 case str_type
: output( value
.get_str() ); break;
193 case bool_type
: output( value
.get_bool() ); break;
194 case real_type
: output( value
.get_real() ); break;
195 case int_type
: output_int( value
); break;
196 case null_type
: os_
<< "null"; break;
197 default: ceph_assert( false );
201 void output( const Object_type
& obj
)
203 output_array_or_obj( obj
, '{', '}' );
206 void output( const Obj_member_type
& member
)
208 output( Config_type::get_name( member
) ); space();
210 output( Config_type::get_value( member
) );
213 void output_int( const Value_type
& value
)
215 if( value
.is_uint64() )
217 os_
<< value
.get_uint64();
221 os_
<< value
.get_int64();
225 void output( const String_type
& s
)
227 os_
<< '"' << add_esc_chars( s
, raw_utf8_
) << '"';
230 void output( bool b
)
232 os_
<< to_str
< String_type
>( b
? "true" : "false" );
235 void output( double d
)
237 if( remove_trailing_zeros_
)
239 std::basic_ostringstream
< Char_type
> os
;
241 append_double( os
, d
, 16 ); // note precision is 16 so that we get some trailing space that we can remove,
242 // otherwise, 0.1234 gets converted to "0.12399999..."
244 String_type str
= os
.str();
246 remove_trailing( str
);
252 append_double( os_
, d
, 17 );
256 static bool contains_composite_elements( const Array_type
& arr
)
258 for( typename
Array_type::const_iterator i
= arr
.begin(); i
!= arr
.end(); ++i
)
260 const Value_type
& val
= *i
;
262 if( val
.type() == obj_type
||
263 val
.type() == array_type
)
272 template< class Iter
>
273 void output_composite_item( Iter i
, Iter last
)
283 void output( const Array_type
& arr
)
285 if( single_line_arrays_
&& !contains_composite_elements( arr
) )
289 for( typename
Array_type::const_iterator i
= arr
.begin(); i
!= arr
.end(); ++i
)
291 output_composite_item( i
, arr
.end() );
300 output_array_or_obj( arr
, '[', ']' );
305 void output_array_or_obj( const T
& t
, Char_type start_char
, Char_type end_char
)
307 os_
<< start_char
; new_line();
309 ++indentation_level_
;
311 for( typename
T::const_iterator i
= t
.begin(); i
!= t
.end(); ++i
)
315 output_composite_item( i
, t
.end() );
320 --indentation_level_
;
322 indent(); os_
<< end_char
;
327 if( !pretty_
) return;
329 for( int i
= 0; i
< indentation_level_
; ++i
)
337 if( pretty_
) os_
<< ' ';
342 if( pretty_
) os_
<< '\n';
345 Generator
& operator=( const Generator
& ); // to prevent "assignment operator could not be generated" warning
348 int indentation_level_
;
351 bool remove_trailing_zeros_
;
352 bool single_line_arrays_
;
353 boost::io::basic_ios_all_saver
< Char_type
> ios_saver_
; // so that ostream state is reset after control is returned to the caller
356 // writes JSON Value to a stream, e.g.
358 // write_stream( value, os, pretty_print );
360 template< class Value_type
, class Ostream_type
>
361 void write_stream( const Value_type
& value
, Ostream_type
& os
, unsigned int options
= 0 )
364 Generator
< Value_type
, Ostream_type
>( value
, os
, options
);
367 // writes JSON Value to a stream, e.g.
369 // const string json_str = write( value, pretty_print );
371 template< class Value_type
>
372 typename
Value_type::String_type
write_string( const Value_type
& value
, unsigned int options
= 0 )
374 typedef typename
Value_type::String_type::value_type Char_type
;
376 std::basic_ostringstream
< Char_type
> os
;
378 write_stream( value
, os
, options
);