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"
19 #include <boost/io/ios_state.hpp>
23 inline char to_hex_char( unsigned int c
)
27 const char ch
= static_cast< char >( c
);
29 if( ch
< 10 ) return '0' + ch
;
34 template< class String_type
>
35 String_type
non_printable_to_string( unsigned int c
)
37 String_type
result( 6, '\\' );
41 result
[ 5 ] = to_hex_char( c
& 0x000F ); c
>>= 4;
42 result
[ 4 ] = to_hex_char( c
& 0x000F ); c
>>= 4;
43 result
[ 3 ] = to_hex_char( c
& 0x000F ); c
>>= 4;
44 result
[ 2 ] = to_hex_char( c
& 0x000F );
49 template< typename Char_type
, class String_type
>
50 bool add_esc_char( Char_type c
, String_type
& s
)
54 case '"': s
+= to_str
< String_type
>( "\\\"" ); return true;
55 case '\\': s
+= to_str
< String_type
>( "\\\\" ); return true;
56 case '\b': s
+= to_str
< String_type
>( "\\b" ); return true;
57 case '\f': s
+= to_str
< String_type
>( "\\f" ); return true;
58 case '\n': s
+= to_str
< String_type
>( "\\n" ); return true;
59 case '\r': s
+= to_str
< String_type
>( "\\r" ); return true;
60 case '\t': s
+= to_str
< String_type
>( "\\t" ); return true;
66 template< class String_type
>
67 String_type
add_esc_chars( const String_type
& s
, bool raw_utf8
)
69 typedef typename
String_type::const_iterator Iter_type
;
70 typedef typename
String_type::value_type Char_type
;
74 const Iter_type
end( s
.end() );
76 for( Iter_type i
= s
.begin(); i
!= end
; ++i
)
78 const Char_type
c( *i
);
80 if( add_esc_char( c
, result
) ) continue;
88 const wint_t unsigned_c( ( c
>= 0 ) ? c
: 256 + c
);
90 if( iswprint( unsigned_c
) )
96 result
+= non_printable_to_string
< String_type
>( unsigned_c
);
104 template< class Ostream
>
105 void append_double( Ostream
& os
, const double d
, const int precision
)
107 os
<< std::showpoint
<< std::setprecision( precision
) << d
;
110 template< class String_type
>
111 void erase_and_extract_exponent( String_type
& str
, String_type
& exp
)
113 const typename
String_type::size_type exp_start
= str
.find( 'e' );
115 if( exp_start
!= String_type::npos
)
117 exp
= str
.substr( exp_start
);
118 str
.erase( exp_start
);
122 template< class String_type
>
123 typename
String_type::size_type
find_first_non_zero( const String_type
& str
)
125 typename
String_type::size_type result
= str
.size() - 1;
127 for( ; result
!= 0; --result
)
129 if( str
[ result
] != '0' )
138 template< class String_type
>
139 void remove_trailing( String_type
& str
)
143 erase_and_extract_exponent( str
, exp
);
145 const typename
String_type::size_type first_non_zero
= find_first_non_zero( str
);
147 if( first_non_zero
!= 0 )
149 const int offset
= str
[first_non_zero
] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard
150 str
.erase( first_non_zero
+ offset
);
156 // this class generates the JSON text,
157 // it keeps track of the indentation level etc.
159 template< class Value_type
, class Ostream_type
>
162 typedef typename
Value_type::Config_type Config_type
;
163 typedef typename
Config_type::String_type String_type
;
164 typedef typename
Config_type::Object_type Object_type
;
165 typedef typename
Config_type::Array_type Array_type
;
166 typedef typename
String_type::value_type Char_type
;
167 typedef typename
Object_type::value_type Obj_member_type
;
171 Generator( const Value_type
& value
, Ostream_type
& os
, unsigned int options
)
173 , indentation_level_( 0 )
174 , pretty_( ( options
& pretty_print
) != 0 || ( options
& single_line_arrays
) != 0 )
175 , raw_utf8_( ( options
& raw_utf8
) != 0 )
176 , remove_trailing_zeros_( ( options
& remove_trailing_zeros
) != 0 )
177 , single_line_arrays_( ( options
& single_line_arrays
) != 0 )
185 void output( const Value_type
& value
)
187 switch( value
.type() )
189 case obj_type
: output( value
.get_obj() ); break;
190 case array_type
: output( value
.get_array() ); break;
191 case str_type
: output( value
.get_str() ); break;
192 case bool_type
: output( value
.get_bool() ); break;
193 case real_type
: output( value
.get_real() ); break;
194 case int_type
: output_int( value
); break;
195 case null_type
: os_
<< "null"; break;
196 default: assert( false );
200 void output( const Object_type
& obj
)
202 output_array_or_obj( obj
, '{', '}' );
205 void output( const Obj_member_type
& member
)
207 output( Config_type::get_name( member
) ); space();
209 output( Config_type::get_value( member
) );
212 void output_int( const Value_type
& value
)
214 if( value
.is_uint64() )
216 os_
<< value
.get_uint64();
220 os_
<< value
.get_int64();
224 void output( const String_type
& s
)
226 os_
<< '"' << add_esc_chars( s
, raw_utf8_
) << '"';
229 void output( bool b
)
231 os_
<< to_str
< String_type
>( b
? "true" : "false" );
234 void output( double d
)
236 if( remove_trailing_zeros_
)
238 std::basic_ostringstream
< Char_type
> os
;
240 append_double( os
, d
, 16 ); // note precision is 16 so that we get some trailing space that we can remove,
241 // otherwise, 0.1234 gets converted to "0.12399999..."
243 String_type str
= os
.str();
245 remove_trailing( str
);
251 append_double( os_
, d
, 17 );
255 static bool contains_composite_elements( const Array_type
& arr
)
257 for( typename
Array_type::const_iterator i
= arr
.begin(); i
!= arr
.end(); ++i
)
259 const Value_type
& val
= *i
;
261 if( val
.type() == obj_type
||
262 val
.type() == array_type
)
271 template< class Iter
>
272 void output_composite_item( Iter i
, Iter last
)
282 void output( const Array_type
& arr
)
284 if( single_line_arrays_
&& !contains_composite_elements( arr
) )
288 for( typename
Array_type::const_iterator i
= arr
.begin(); i
!= arr
.end(); ++i
)
290 output_composite_item( i
, arr
.end() );
299 output_array_or_obj( arr
, '[', ']' );
304 void output_array_or_obj( const T
& t
, Char_type start_char
, Char_type end_char
)
306 os_
<< start_char
; new_line();
308 ++indentation_level_
;
310 for( typename
T::const_iterator i
= t
.begin(); i
!= t
.end(); ++i
)
314 output_composite_item( i
, t
.end() );
319 --indentation_level_
;
321 indent(); os_
<< end_char
;
326 if( !pretty_
) return;
328 for( int i
= 0; i
< indentation_level_
; ++i
)
336 if( pretty_
) os_
<< ' ';
341 if( pretty_
) os_
<< '\n';
344 Generator
& operator=( const Generator
& ); // to prevent "assignment operator could not be generated" warning
347 int indentation_level_
;
350 bool remove_trailing_zeros_
;
351 bool single_line_arrays_
;
352 boost::io::basic_ios_all_saver
< Char_type
> ios_saver_
; // so that ostream state is reset after control is returned to the caller
355 // writes JSON Value to a stream, e.g.
357 // write_stream( value, os, pretty_print );
359 template< class Value_type
, class Ostream_type
>
360 void write_stream( const Value_type
& value
, Ostream_type
& os
, unsigned int options
= 0 )
363 Generator
< Value_type
, Ostream_type
>( value
, os
, options
);
366 // writes JSON Value to a stream, e.g.
368 // const string json_str = write( value, pretty_print );
370 template< class Value_type
>
371 typename
Value_type::String_type
write_string( const Value_type
& value
, unsigned int options
= 0 )
373 typedef typename
Value_type::String_type::value_type Char_type
;
375 std::basic_ostringstream
< Char_type
> os
;
377 write_stream( value
, os
, options
);