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
typedef typename String_type::value_type Char_type;
39
String_type result( 6, '\\' );
43
result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4;
44
result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4;
45
result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4;
46
result[ 2 ] = to_hex_char( c & 0x000F );
51
template< typename Char_type, class String_type >
52
bool add_esc_char( Char_type c, String_type& s )
56
case '"': s += to_str< String_type >( "\\\"" ); return true;
57
case '\\': s += to_str< String_type >( "\\\\" ); return true;
58
case '\b': s += to_str< String_type >( "\\b" ); return true;
59
case '\f': s += to_str< String_type >( "\\f" ); return true;
60
case '\n': s += to_str< String_type >( "\\n" ); return true;
61
case '\r': s += to_str< String_type >( "\\r" ); return true;
62
case '\t': s += to_str< String_type >( "\\t" ); return true;
68
template< class String_type >
69
String_type add_esc_chars( const String_type& s, bool raw_utf8 )
71
typedef typename String_type::const_iterator Iter_type;
72
typedef typename String_type::value_type Char_type;
76
const Iter_type end( s.end() );
78
for( Iter_type i = s.begin(); i != end; ++i )
80
const Char_type c( *i );
82
if( add_esc_char( c, result ) ) continue;
90
const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );
92
if( iswprint( unsigned_c ) )
98
result += non_printable_to_string< String_type >( unsigned_c );
106
template< class Ostream >
107
void append_double( Ostream& os, const double d, const int precision )
109
os << std::showpoint << std::setprecision( precision ) << d;
112
template< class String_type >
113
void erase_and_extract_exponent( String_type& str, String_type& exp )
115
const typename String_type::size_type exp_start= str.find( 'e' );
117
if( exp_start != String_type::npos )
119
exp = str.substr( exp_start );
120
str.erase( exp_start );
124
template< class String_type >
125
typename String_type::size_type find_first_non_zero( const String_type& str )
127
typename String_type::size_type result = str.size() - 1;
129
for( ; result != 0; --result )
131
if( str[ result ] != '0' )
140
template< class String_type >
141
void remove_trailing( String_type& str )
145
erase_and_extract_exponent( str, exp );
147
const typename String_type::size_type first_non_zero = find_first_non_zero( str );
149
if( first_non_zero != 0 )
151
const int offset = str[first_non_zero] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard
152
str.erase( first_non_zero + offset );
158
// this class generates the JSON text,
159
// it keeps track of the indentation level etc.
161
template< class Value_type, class Ostream_type >
164
typedef typename Value_type::Config_type Config_type;
165
typedef typename Config_type::String_type String_type;
166
typedef typename Config_type::Object_type Object_type;
167
typedef typename Config_type::Array_type Array_type;
168
typedef typename String_type::value_type Char_type;
169
typedef typename Object_type::value_type Obj_member_type;
173
Generator( const Value_type& value, Ostream_type& os, unsigned int options )
175
, indentation_level_( 0 )
176
, pretty_( ( options & pretty_print ) != 0 || ( options & single_line_arrays ) != 0 )
177
, raw_utf8_( ( options & raw_utf8 ) != 0 )
178
, remove_trailing_zeros_( ( options & remove_trailing_zeros ) != 0 )
179
, single_line_arrays_( ( options & single_line_arrays ) != 0 )
187
void output( const Value_type& value )
189
switch( value.type() )
191
case obj_type: output( value.get_obj() ); break;
192
case array_type: output( value.get_array() ); break;
193
case str_type: output( value.get_str() ); break;
194
case bool_type: output( value.get_bool() ); break;
195
case real_type: output( value.get_real() ); break;
196
case int_type: output_int( value ); break;
197
case null_type: os_ << "null"; break;
198
default: assert( false );
202
void output( const Object_type& obj )
204
output_array_or_obj( obj, '{', '}' );
207
void output( const Obj_member_type& member )
209
output( Config_type::get_name( member ) ); space();
211
output( Config_type::get_value( member ) );
214
void output_int( const Value_type& value )
216
if( value.is_uint64() )
218
os_ << value.get_uint64();
222
os_ << value.get_int64();
226
void output( const String_type& s )
228
os_ << '"' << add_esc_chars( s, raw_utf8_ ) << '"';
231
void output( bool b )
233
os_ << to_str< String_type >( b ? "true" : "false" );
236
void output( double d )
238
if( remove_trailing_zeros_ )
240
std::basic_ostringstream< Char_type > os;
242
append_double( os, d, 16 ); // note precision is 16 so that we get some trailing space that we can remove,
243
// otherwise, 0.1234 gets converted to "0.12399999..."
245
String_type str = os.str();
247
remove_trailing( str );
253
append_double( os_, d, 17 );
257
static bool contains_composite_elements( const Array_type& arr )
259
for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i )
261
const Value_type& val = *i;
263
if( val.type() == obj_type ||
264
val.type() == array_type )
273
template< class Iter >
274
void output_composite_item( Iter i, Iter last )
284
void output( const Array_type& arr )
286
if( single_line_arrays_ && !contains_composite_elements( arr ) )
290
for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i )
292
output_composite_item( i, arr.end() );
301
output_array_or_obj( arr, '[', ']' );
306
void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char )
308
os_ << start_char; new_line();
310
++indentation_level_;
312
for( typename T::const_iterator i = t.begin(); i != t.end(); ++i )
316
output_composite_item( i, t.end() );
321
--indentation_level_;
323
indent(); os_ << end_char;
328
if( !pretty_ ) return;
330
for( int i = 0; i < indentation_level_; ++i )
338
if( pretty_ ) os_ << ' ';
343
if( pretty_ ) os_ << '\n';
346
Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning
349
int indentation_level_;
352
bool remove_trailing_zeros_;
353
bool single_line_arrays_;
354
boost::io::basic_ios_all_saver< Char_type > ios_saver_; // so that ostream state is reset after control is returned to the caller
357
// writes JSON Value to a stream, e.g.
359
// write_stream( value, os, pretty_print );
361
template< class Value_type, class Ostream_type >
362
void write_stream( const Value_type& value, Ostream_type& os, unsigned int options = 0 )
365
Generator< Value_type, Ostream_type >( value, os, options );
368
// writes JSON Value to a stream, e.g.
370
// const string json_str = write( value, pretty_print );
372
template< class Value_type >
373
typename Value_type::String_type write_string( const Value_type& value, unsigned int options = 0 )
375
typedef typename Value_type::String_type::value_type Char_type;
377
std::basic_ostringstream< Char_type > os;
379
write_stream( value, os, options );