aboutsummaryrefslogtreecommitdiff
path: root/src/json/json_spirit_writer_template.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/json/json_spirit_writer_template.h')
-rw-r--r--src/json/json_spirit_writer_template.h201
1 files changed, 170 insertions, 31 deletions
diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h
index 28c49ddc64..014d9d4cd0 100644
--- a/src/json/json_spirit_writer_template.h
+++ b/src/json/json_spirit_writer_template.h
@@ -1,16 +1,22 @@
#ifndef JSON_SPIRIT_WRITER_TEMPLATE
#define JSON_SPIRIT_WRITER_TEMPLATE
-// Copyright John W. Wilkinson 2007 - 2009.
+// Copyright John W. Wilkinson 2007 - 2013
// Distributed under the MIT License, see accompanying file LICENSE.txt
-// json spirit version 4.03
+// json spirit version 4.06
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
#include "json_spirit_value.h"
+#include "json_spirit_writer_options.h"
#include <cassert>
#include <sstream>
#include <iomanip>
+#include <boost/io/ios_state.hpp>
namespace json_spirit
{
@@ -60,7 +66,7 @@ namespace json_spirit
}
template< class String_type >
- String_type add_esc_chars( const String_type& s )
+ String_type add_esc_chars( const String_type& s, bool raw_utf8, bool esc_nonascii )
{
typedef typename String_type::const_iterator Iter_type;
typedef typename String_type::value_type Char_type;
@@ -75,21 +81,80 @@ namespace json_spirit
if( add_esc_char( c, result ) ) continue;
- const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );
-
- if( iswprint( unsigned_c ) )
+ if( raw_utf8 )
{
result += c;
}
else
{
- result += non_printable_to_string< String_type >( unsigned_c );
+ const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );
+
+ if( !esc_nonascii && iswprint( unsigned_c ) )
+ {
+ result += c;
+ }
+ else
+ {
+ result += non_printable_to_string< String_type >( unsigned_c );
+ }
+ }
+ }
+
+ return result;
+ }
+
+ template< class Ostream >
+ void append_double( Ostream& os, const double d, const int precision )
+ {
+ os << std::showpoint << std::setprecision( precision ) << d;
+ }
+
+ template< class String_type >
+ void erase_and_extract_exponent( String_type& str, String_type& exp )
+ {
+ const typename String_type::size_type exp_start= str.find( 'e' );
+
+ if( exp_start != String_type::npos )
+ {
+ exp = str.substr( exp_start );
+ str.erase( exp_start );
+ }
+ }
+
+ template< class String_type >
+ typename String_type::size_type find_first_non_zero( const String_type& str )
+ {
+ typename String_type::size_type result = str.size() - 1;
+
+ for( ; result != 0; --result )
+ {
+ if( str[ result ] != '0' )
+ {
+ break;
}
}
return result;
}
+ template< class String_type >
+ void remove_trailing( String_type& str )
+ {
+ String_type exp;
+
+ erase_and_extract_exponent( str, exp );
+
+ const typename String_type::size_type first_non_zero = find_first_non_zero( str );
+
+ if( first_non_zero != 0 )
+ {
+ const int offset = str[first_non_zero] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard
+ str.erase( first_non_zero + offset );
+ }
+
+ str += exp;
+ }
+
// this class generates the JSON text,
// it keeps track of the indentation level etc.
//
@@ -105,10 +170,15 @@ namespace json_spirit
public:
- Generator( const Value_type& value, Ostream_type& os, bool pretty )
+ Generator( const Value_type& value, Ostream_type& os, unsigned int options )
: os_( os )
, indentation_level_( 0 )
- , pretty_( pretty )
+ , pretty_( ( options & pretty_print ) != 0 || ( options & single_line_arrays ) != 0 )
+ , raw_utf8_( ( options & raw_utf8 ) != 0 )
+ , esc_nonascii_( ( options & always_escape_nonascii ) != 0 )
+ , remove_trailing_zeros_( ( options & remove_trailing_zeros ) != 0 )
+ , single_line_arrays_( ( options & single_line_arrays ) != 0 )
+ , ios_saver_( os )
{
output( value );
}
@@ -123,12 +193,8 @@ namespace json_spirit
case array_type: output( value.get_array() ); break;
case str_type: output( value.get_str() ); break;
case bool_type: output( value.get_bool() ); break;
+ case real_type: output( value.get_real() ); break;
case int_type: output_int( value ); break;
-
- /// Bitcoin: Added std::fixed and changed precision from 16 to 8
- case real_type: os_ << std::showpoint << std::fixed << std::setprecision(8)
- << value.get_real(); break;
-
case null_type: os_ << "null"; break;
default: assert( false );
}
@@ -139,11 +205,6 @@ namespace json_spirit
output_array_or_obj( obj, '{', '}' );
}
- void output( const Array_type& arr )
- {
- output_array_or_obj( arr, '[', ']' );
- }
-
void output( const Obj_member_type& member )
{
output( Config_type::get_name( member ) ); space();
@@ -165,7 +226,7 @@ namespace json_spirit
void output( const String_type& s )
{
- os_ << '"' << add_esc_chars( s ) << '"';
+ os_ << '"' << add_esc_chars( s, raw_utf8_, esc_nonascii_ ) << '"';
}
void output( bool b )
@@ -173,6 +234,75 @@ namespace json_spirit
os_ << to_str< String_type >( b ? "true" : "false" );
}
+ void output( double d )
+ {
+ if( remove_trailing_zeros_ )
+ {
+ std::basic_ostringstream< Char_type > os;
+
+ append_double( os, d, 16 ); // note precision is 16 so that we get some trailing space that we can remove,
+ // otherwise, 0.1234 gets converted to "0.12399999..."
+
+ String_type str = os.str();
+
+ remove_trailing( str );
+
+ os_ << str;
+ }
+ else
+ {
+ append_double( os_, d, 17 );
+ }
+ }
+
+ static bool contains_composite_elements( const Array_type& arr )
+ {
+ for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i )
+ {
+ const Value_type& val = *i;
+
+ if( val.type() == obj_type ||
+ val.type() == array_type )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ template< class Iter >
+ void output_composite_item( Iter i, Iter last )
+ {
+ output( *i );
+
+ if( ++i != last )
+ {
+ os_ << ',';
+ }
+ }
+
+ void output( const Array_type& arr )
+ {
+ if( single_line_arrays_ && !contains_composite_elements( arr ) )
+ {
+ os_ << '['; space();
+
+ for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i )
+ {
+ output_composite_item( i, arr.end() );
+
+ space();
+ }
+
+ os_ << ']';
+ }
+ else
+ {
+ output_array_or_obj( arr, '[', ']' );
+ }
+ }
+
template< class T >
void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char )
{
@@ -182,14 +312,9 @@ namespace json_spirit
for( typename T::const_iterator i = t.begin(); i != t.end(); ++i )
{
- indent(); output( *i );
+ indent();
- typename T::const_iterator next = i;
-
- if( ++next != t.end())
- {
- os_ << ',';
- }
+ output_composite_item( i, t.end() );
new_line();
}
@@ -224,22 +349,36 @@ namespace json_spirit
Ostream_type& os_;
int indentation_level_;
bool pretty_;
+ bool raw_utf8_;
+ bool esc_nonascii_;
+ bool remove_trailing_zeros_;
+ bool single_line_arrays_;
+ boost::io::basic_ios_all_saver< Char_type > ios_saver_; // so that ostream state is reset after control is returned to the caller
};
+ // writes JSON Value to a stream, e.g.
+ //
+ // write_stream( value, os, pretty_print );
+ //
template< class Value_type, class Ostream_type >
- void write_stream( const Value_type& value, Ostream_type& os, bool pretty )
+ void write_stream( const Value_type& value, Ostream_type& os, unsigned int options = 0 )
{
- Generator< Value_type, Ostream_type >( value, os, pretty );
+ os << std::dec;
+ Generator< Value_type, Ostream_type >( value, os, options );
}
+ // writes JSON Value to a stream, e.g.
+ //
+ // const string json_str = write( value, pretty_print );
+ //
template< class Value_type >
- typename Value_type::String_type write_string( const Value_type& value, bool pretty )
+ typename Value_type::String_type write_string( const Value_type& value, unsigned int options = 0 )
{
typedef typename Value_type::String_type::value_type Char_type;
std::basic_ostringstream< Char_type > os;
- write_stream( value, os, pretty );
+ write_stream( value, os, options );
return os.str();
}