diff options
author | Gavin Andresen <gavinandresen@gmail.com> | 2013-10-22 01:20:02 -0700 |
---|---|---|
committer | Gavin Andresen <gavinandresen@gmail.com> | 2013-10-22 01:20:02 -0700 |
commit | 125bdead3e9be9a6ce23129409612a4d8501980b (patch) | |
tree | 9b87499106f280a32edab404351c5b7e3835e046 /src/json/json_spirit_writer_template.h | |
parent | 8435f7b8ee2521d11364f400cf63e9fb3f2c8a7d (diff) | |
parent | 2ecb7555a9df1e843fd25f588819e4ca1d94b266 (diff) | |
download | bitcoin-125bdead3e9be9a6ce23129409612a4d8501980b.tar.xz |
Merge pull request #2740 from constantined/constantined
UTF-8 support for JSON-RPC
Diffstat (limited to 'src/json/json_spirit_writer_template.h')
-rw-r--r-- | src/json/json_spirit_writer_template.h | 201 |
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(); } |