diff options
28 files changed, 789 insertions, 419 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index f2a52e92ed..93ab9a4770 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -31,6 +31,8 @@ using namespace boost; using namespace boost::asio; using namespace json_spirit; +static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"}; + static std::string strRPCUserColonPass; // These are created by StartRPCThreads, destroyed in StopRPCThreads @@ -531,7 +533,7 @@ string JSONRPCRequest(const string& strMethod, const Array& params, const Value& request.push_back(Pair("method", strMethod)); request.push_back(Pair("params", params)); request.push_back(Pair("id", id)); - return write_string(Value(request), false) + "\n"; + return write_string(Value(request), raw_utf8) + "\n"; } Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) @@ -549,7 +551,7 @@ Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) string JSONRPCReply(const Value& result, const Value& error, const Value& id) { Object reply = JSONRPCReplyObj(result, error, id); - return write_string(Value(reply), false) + "\n"; + return write_string(Value(reply), raw_utf8) + "\n"; } void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) @@ -980,7 +982,7 @@ static string JSONRPCExecBatch(const Array& vReq) for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) ret.push_back(JSONRPCExecOne(vReq[reqIdx])); - return write_string(Value(ret), false) + "\n"; + return write_string(Value(ret), raw_utf8) + "\n"; } void ServiceConnection(AcceptedConnection *conn) @@ -1282,7 +1284,7 @@ int CommandLineRPC(int argc, char *argv[]) if (error.type() != null_type) { // Error - strPrint = "error: " + write_string(error, false); + strPrint = "error: " + write_string(error, raw_utf8); int code = find_value(error.get_obj(), "code").get_int(); nRet = abs(code); } @@ -1294,7 +1296,7 @@ int CommandLineRPC(int argc, char *argv[]) else if (result.type() == str_type) strPrint = result.get_str(); else - strPrint = write_string(result, true); + strPrint = write_string(result, pretty_print | raw_utf8); } } catch (boost::thread_interrupted) { diff --git a/src/json/LICENSE.txt b/src/json/LICENSE.txt index 797d5363b3..6ed66a2e69 100644 --- a/src/json/LICENSE.txt +++ b/src/json/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2007 - 2009 John W. Wilkinson +Copyright (c) 2007 - 2010 John W. Wilkinson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/src/json/json_spirit.h b/src/json/json_spirit.h index ac1879d5b3..ef442e9fd5 100644 --- a/src/json/json_spirit.h +++ b/src/json/json_spirit.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT #define JSON_SPIRIT -// 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 diff --git a/src/json/json_spirit_error_position.h b/src/json/json_spirit_error_position.h index 17208507df..e2b59b47ae 100644 --- a/src/json/json_spirit_error_position.h +++ b/src/json/json_spirit_error_position.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_ERROR_POSITION #define JSON_SPIRIT_ERROR_POSITION -// 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 @@ -48,7 +48,7 @@ namespace json_spirit return ( reason_ == lhs.reason_ ) && ( line_ == lhs.line_ ) && ( column_ == lhs.column_ ); -} + } } #endif diff --git a/src/json/json_spirit_reader.cpp b/src/json/json_spirit_reader.cpp index aa4f637226..7dea074736 100644 --- a/src/json/json_spirit_reader.cpp +++ b/src/json/json_spirit_reader.cpp @@ -1,137 +1,137 @@ -// 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 #include "json_spirit_reader.h" #include "json_spirit_reader_template.h" using namespace json_spirit; -bool json_spirit::read( const std::string& s, Value& value ) -{ - return read_string( s, value ); -} - -void json_spirit::read_or_throw( const std::string& s, Value& value ) -{ - read_string_or_throw( s, value ); -} - -bool json_spirit::read( std::istream& is, Value& value ) -{ - return read_stream( is, value ); -} - -void json_spirit::read_or_throw( std::istream& is, Value& value ) -{ - read_stream_or_throw( is, value ); -} - -bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) -{ - return read_range( begin, end, value ); -} - -void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) -{ - begin = read_range_or_throw( begin, end, value ); -} - -#ifndef BOOST_NO_STD_WSTRING - -bool json_spirit::read( const std::wstring& s, wValue& value ) -{ - return read_string( s, value ); -} - -void json_spirit::read_or_throw( const std::wstring& s, wValue& value ) -{ - read_string_or_throw( s, value ); -} - -bool json_spirit::read( std::wistream& is, wValue& value ) -{ - return read_stream( is, value ); -} - -void json_spirit::read_or_throw( std::wistream& is, wValue& value ) -{ - read_stream_or_throw( is, value ); -} - -bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) -{ - return read_range( begin, end, value ); -} - -void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) -{ - begin = read_range_or_throw( begin, end, value ); -} +#ifdef JSON_SPIRIT_VALUE_ENABLED + bool json_spirit::read( const std::string& s, Value& value ) + { + return read_string( s, value ); + } + + void json_spirit::read_or_throw( const std::string& s, Value& value ) + { + read_string_or_throw( s, value ); + } + + bool json_spirit::read( std::istream& is, Value& value ) + { + return read_stream( is, value ); + } + + void json_spirit::read_or_throw( std::istream& is, Value& value ) + { + read_stream_or_throw( is, value ); + } + + bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) + { + return read_range( begin, end, value ); + } + + void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) + { + begin = read_range_or_throw( begin, end, value ); + } +#endif +#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) + bool json_spirit::read( const std::wstring& s, wValue& value ) + { + return read_string( s, value ); + } + + void json_spirit::read_or_throw( const std::wstring& s, wValue& value ) + { + read_string_or_throw( s, value ); + } + + bool json_spirit::read( std::wistream& is, wValue& value ) + { + return read_stream( is, value ); + } + + void json_spirit::read_or_throw( std::wistream& is, wValue& value ) + { + read_stream_or_throw( is, value ); + } + + bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) + { + return read_range( begin, end, value ); + } + + void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) + { + begin = read_range_or_throw( begin, end, value ); + } #endif -bool json_spirit::read( const std::string& s, mValue& value ) -{ - return read_string( s, value ); -} - -void json_spirit::read_or_throw( const std::string& s, mValue& value ) -{ - read_string_or_throw( s, value ); -} - -bool json_spirit::read( std::istream& is, mValue& value ) -{ - return read_stream( is, value ); -} - -void json_spirit::read_or_throw( std::istream& is, mValue& value ) -{ - read_stream_or_throw( is, value ); -} - -bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) -{ - return read_range( begin, end, value ); -} - -void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) -{ - begin = read_range_or_throw( begin, end, value ); -} - -#ifndef BOOST_NO_STD_WSTRING - -bool json_spirit::read( const std::wstring& s, wmValue& value ) -{ - return read_string( s, value ); -} - -void json_spirit::read_or_throw( const std::wstring& s, wmValue& value ) -{ - read_string_or_throw( s, value ); -} - -bool json_spirit::read( std::wistream& is, wmValue& value ) -{ - return read_stream( is, value ); -} - -void json_spirit::read_or_throw( std::wistream& is, wmValue& value ) -{ - read_stream_or_throw( is, value ); -} - -bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) -{ - return read_range( begin, end, value ); -} - -void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) -{ - begin = read_range_or_throw( begin, end, value ); -} +#ifdef JSON_SPIRIT_MVALUE_ENABLED + bool json_spirit::read( const std::string& s, mValue& value ) + { + return read_string( s, value ); + } + + void json_spirit::read_or_throw( const std::string& s, mValue& value ) + { + read_string_or_throw( s, value ); + } + + bool json_spirit::read( std::istream& is, mValue& value ) + { + return read_stream( is, value ); + } + + void json_spirit::read_or_throw( std::istream& is, mValue& value ) + { + read_stream_or_throw( is, value ); + } + + bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) + { + return read_range( begin, end, value ); + } + + void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) + { + begin = read_range_or_throw( begin, end, value ); + } +#endif +#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) + bool json_spirit::read( const std::wstring& s, wmValue& value ) + { + return read_string( s, value ); + } + + void json_spirit::read_or_throw( const std::wstring& s, wmValue& value ) + { + read_string_or_throw( s, value ); + } + + bool json_spirit::read( std::wistream& is, wmValue& value ) + { + return read_stream( is, value ); + } + + void json_spirit::read_or_throw( std::wistream& is, wmValue& value ) + { + read_stream_or_throw( is, value ); + } + + bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) + { + return read_range( begin, end, value ); + } + + void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) + { + begin = read_range_or_throw( begin, end, value ); + } #endif diff --git a/src/json/json_spirit_reader.h b/src/json/json_spirit_reader.h index 96494a9789..f0dc5330f2 100644 --- a/src/json/json_spirit_reader.h +++ b/src/json/json_spirit_reader.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_READER #define JSON_SPIRIT_READER -// 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 @@ -18,6 +18,7 @@ namespace json_spirit { // functions to reads a JSON values +#ifdef JSON_SPIRIT_VALUE_ENABLED bool read( const std::string& s, Value& value ); bool read( std::istream& is, Value& value ); bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); @@ -25,9 +26,9 @@ namespace json_spirit void read_or_throw( const std::string& s, Value& value ); void read_or_throw( std::istream& is, Value& value ); void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); +#endif -#ifndef BOOST_NO_STD_WSTRING - +#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) bool read( const std::wstring& s, wValue& value ); bool read( std::wistream& is, wValue& value ); bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); @@ -35,9 +36,9 @@ namespace json_spirit void read_or_throw( const std::wstring& s, wValue& value ); void read_or_throw( std::wistream& is, wValue& value ); void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); - #endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED bool read( const std::string& s, mValue& value ); bool read( std::istream& is, mValue& value ); bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); @@ -45,9 +46,9 @@ namespace json_spirit void read_or_throw( const std::string& s, mValue& value ); void read_or_throw( std::istream& is, mValue& value ); void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); +#endif -#ifndef BOOST_NO_STD_WSTRING - +#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) bool read( const std::wstring& s, wmValue& value ); bool read( std::wistream& is, wmValue& value ); bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); @@ -55,7 +56,6 @@ namespace json_spirit void read_or_throw( const std::wstring& s, wmValue& value ); void read_or_throw( std::wistream& is, wmValue& value ); void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); - #endif } diff --git a/src/json/json_spirit_reader_template.h b/src/json/json_spirit_reader_template.h index 4dec00e6c9..d3d0cecaa5 100644 --- a/src/json/json_spirit_reader_template.h +++ b/src/json/json_spirit_reader_template.h @@ -1,10 +1,14 @@ #ifndef JSON_SPIRIT_READER_TEMPLATE #define JSON_SPIRIT_READER_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_error_position.h" @@ -484,7 +488,7 @@ namespace json_spirit ; string_ - = lexeme_d // this causes white space inside a string to be retained + = lexeme_d // this causes white space and what would appear to be comments inside a string to be retained [ confix_p ( @@ -515,6 +519,44 @@ namespace json_spirit }; template< class Iter_type, class Value_type > + void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) + { + typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; + + const Posn_iter_t posn_begin( begin, end ); + const Posn_iter_t posn_end( end, end ); + + read_range_or_throw( posn_begin, posn_end, value ); + } + + template< class Istream_type > + struct Multi_pass_iters + { + typedef typename Istream_type::char_type Char_type; + typedef std::istream_iterator< Char_type, Char_type > istream_iter; + typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; + + Multi_pass_iters( Istream_type& is ) + { + is.unsetf( std::ios::skipws ); + + begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); + end_ = spirit_namespace::make_multi_pass( istream_iter() ); + } + + Mp_iter begin_; + Mp_iter end_; + }; + + // reads a JSON Value from a pair of input iterators throwing an exception on invalid input, e.g. + // + // string::const_iterator start = str.begin(); + // const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), value ); + // + // The iterator 'next' will point to the character past the + // last one read. + // + template< class Iter_type, class Value_type > Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) { Semantic_actions< Value_type, Iter_type > semantic_actions( value ); @@ -522,7 +564,9 @@ namespace json_spirit const spirit_namespace::parse_info< Iter_type > info = spirit_namespace::parse( begin, end, Json_grammer< Value_type, Iter_type >( semantic_actions ), - spirit_namespace::space_p ); + spirit_namespace::space_p | + spirit_namespace::comment_p("//") | + spirit_namespace::comment_p("/*", "*/") ); if( !info.hit ) { @@ -533,17 +577,14 @@ namespace json_spirit return info.stop; } - template< class Iter_type, class Value_type > - void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) - { - typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; - - const Posn_iter_t posn_begin( begin, end ); - const Posn_iter_t posn_end( end, end ); - - read_range_or_throw( posn_begin, posn_end, value ); - } - + // reads a JSON Value from a pair of input iterators, e.g. + // + // string::const_iterator start = str.begin(); + // const bool success = read_string( start, str.end(), value ); + // + // The iterator 'start' will point to the character past the + // last one read. + // template< class Iter_type, class Value_type > bool read_range( Iter_type& begin, Iter_type end, Value_type& value ) { @@ -559,12 +600,10 @@ namespace json_spirit } } - template< class String_type, class Value_type > - void read_string_or_throw( const String_type& s, Value_type& value ) - { - add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); - } - + // reads a JSON Value from a string, e.g. + // + // const bool success = read_string( str, value ); + // template< class String_type, class Value_type > bool read_string( const String_type& s, Value_type& value ) { @@ -573,25 +612,20 @@ namespace json_spirit return read_range( begin, s.end(), value ); } - template< class Istream_type > - struct Multi_pass_iters + // reads a JSON Value from a string throwing an exception on invalid input, e.g. + // + // read_string_or_throw( is, value ); + // + template< class String_type, class Value_type > + void read_string_or_throw( const String_type& s, Value_type& value ) { - typedef typename Istream_type::char_type Char_type; - typedef std::istream_iterator< Char_type, Char_type > istream_iter; - typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; - - Multi_pass_iters( Istream_type& is ) - { - is.unsetf( std::ios::skipws ); - - begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); - end_ = spirit_namespace::make_multi_pass( istream_iter() ); - } - - Mp_iter begin_; - Mp_iter end_; - }; + add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); + } + // reads a JSON Value from a stream, e.g. + // + // const bool success = read_stream( is, value ); + // template< class Istream_type, class Value_type > bool read_stream( Istream_type& is, Value_type& value ) { @@ -600,6 +634,10 @@ namespace json_spirit return read_range( mp_iters.begin_, mp_iters.end_, value ); } + // reads a JSON Value from a stream throwing an exception on invalid input, e.g. + // + // read_stream_or_throw( is, value ); + // template< class Istream_type, class Value_type > void read_stream_or_throw( Istream_type& is, Value_type& value ) { diff --git a/src/json/json_spirit_stream_reader.h b/src/json/json_spirit_stream_reader.h index 7e59c9adc2..8bbdbc0543 100644 --- a/src/json/json_spirit_stream_reader.h +++ b/src/json/json_spirit_stream_reader.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_READ_STREAM #define JSON_SPIRIT_READ_STREAM -// 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 diff --git a/src/json/json_spirit_utils.h b/src/json/json_spirit_utils.h index 553e3b96a4..a174ac3a98 100644 --- a/src/json/json_spirit_utils.h +++ b/src/json/json_spirit_utils.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_UTILS #define JSON_SPIRIT_UTILS -// 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 @@ -37,9 +37,11 @@ namespace json_spirit } } +#ifdef JSON_SPIRIT_VALUE_ENABLED typedef std::map< std::string, Value > Mapped_obj; +#endif -#ifndef BOOST_NO_STD_WSTRING +#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) typedef std::map< std::wstring, wValue > wMapped_obj; #endif diff --git a/src/json/json_spirit_value.h b/src/json/json_spirit_value.h index 7e83a2a7e3..a5020405d4 100644 --- a/src/json/json_spirit_value.h +++ b/src/json/json_spirit_value.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_VALUE #define JSON_SPIRIT_VALUE -// 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 @@ -21,11 +21,20 @@ #include <boost/shared_ptr.hpp> #include <boost/variant.hpp> +// comment out the value types you don't need to reduce build times and intermediate file sizes +#define JSON_SPIRIT_VALUE_ENABLED +#define JSON_SPIRIT_WVALUE_ENABLED +#define JSON_SPIRIT_MVALUE_ENABLED +#define JSON_SPIRIT_WMVALUE_ENABLED + namespace json_spirit { enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; - static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"}; + static std::string value_type_to_string( Value_type vtype ); + + struct Null{}; + template< class Config > // Config determines whether the value uses std::string or std::wstring and // whether JSON Objects are represented as vectors or maps class Value_impl @@ -49,6 +58,12 @@ namespace json_spirit Value_impl( boost::uint64_t value ); Value_impl( double value ); + template< class Iter > + Value_impl( Iter first, Iter last ); // constructor from containers, e.g. std::vector or std::list + + template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > + Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ); // constructor for compatible variant types + Value_impl( const Value_impl& other ); bool operator==( const Value_impl& lhs ) const; @@ -81,13 +96,32 @@ namespace json_spirit void check_type( const Value_type vtype ) const; - typedef boost::variant< String_type, - boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, - bool, boost::int64_t, double > Variant; + typedef boost::variant< boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, + String_type, bool, boost::int64_t, double, Null, boost::uint64_t > Variant; - Value_type type_; Variant v_; - bool is_uint64_; + + class Variant_converter_visitor : public boost::static_visitor< Variant > + { + public: + + template< typename T, typename A, template< typename, typename > class Cont > + Variant operator()( const Cont< T, A >& cont ) const + { + return Array( cont.begin(), cont.end() ); + } + + Variant operator()( int i ) const + { + return static_cast< boost::int64_t >( i ); + } + + template<class T> + Variant operator()( const T& t ) const + { + return t; + } + }; }; // vector objects @@ -98,6 +132,10 @@ namespace json_spirit typedef typename Config::String_type String_type; typedef typename Config::Value_type Value_type; + Pair_impl() + { + } + Pair_impl( const String_type& name, const Value_type& value ); bool operator==( const Pair_impl& lhs ) const; @@ -106,6 +144,7 @@ namespace json_spirit Value_type value_; }; +#if defined( JSON_SPIRIT_VALUE_ENABLED ) || defined( JSON_SPIRIT_WVALUE_ENABLED ) template< class String > struct Config_vector { @@ -122,30 +161,32 @@ namespace json_spirit return obj.back().value_; } - static String_type get_name( const Pair_type& pair ) + static const String_type& get_name( const Pair_type& pair ) { return pair.name_; } - static Value_type get_value( const Pair_type& pair ) + static const Value_type& get_value( const Pair_type& pair ) { return pair.value_; } }; +#endif // typedefs for ASCII +#ifdef JSON_SPIRIT_VALUE_ENABLED typedef Config_vector< std::string > Config; typedef Config::Value_type Value; typedef Config::Pair_type Pair; typedef Config::Object_type Object; typedef Config::Array_type Array; +#endif // typedefs for Unicode -#ifndef BOOST_NO_STD_WSTRING - +#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) typedef Config_vector< std::wstring > wConfig; typedef wConfig::Value_type wValue; @@ -156,6 +197,7 @@ namespace json_spirit // map objects +#if defined( JSON_SPIRIT_MVALUE_ENABLED ) || defined( JSON_SPIRIT_WMVALUE_ENABLED ) template< class String > struct Config_map { @@ -163,135 +205,134 @@ namespace json_spirit typedef Value_impl< Config_map > Value_type; typedef std::vector< Value_type > Array_type; typedef std::map< String_type, Value_type > Object_type; - typedef typename Object_type::value_type Pair_type; + typedef std::pair< const String_type, Value_type > Pair_type; static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) { return obj[ name ] = value; } - static String_type get_name( const Pair_type& pair ) + static const String_type& get_name( const Pair_type& pair ) { return pair.first; } - static Value_type get_value( const Pair_type& pair ) + static const Value_type& get_value( const Pair_type& pair ) { return pair.second; } }; +#endif // typedefs for ASCII +#ifdef JSON_SPIRIT_MVALUE_ENABLED typedef Config_map< std::string > mConfig; typedef mConfig::Value_type mValue; typedef mConfig::Object_type mObject; typedef mConfig::Array_type mArray; +#endif // typedefs for Unicode -#ifndef BOOST_NO_STD_WSTRING - +#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) typedef Config_map< std::wstring > wmConfig; typedef wmConfig::Value_type wmValue; typedef wmConfig::Object_type wmObject; typedef wmConfig::Array_type wmArray; - #endif /////////////////////////////////////////////////////////////////////////////////////////////// // // implementation + inline bool operator==( const Null&, const Null& ) + { + return true; + } + template< class Config > const Value_impl< Config > Value_impl< Config >::null; template< class Config > Value_impl< Config >::Value_impl() - : type_( null_type ) - , is_uint64_( false ) + : v_( Null() ) { } template< class Config > Value_impl< Config >::Value_impl( const Const_str_ptr value ) - : type_( str_type ) - , v_( String_type( value ) ) - , is_uint64_( false ) + : v_( String_type( value ) ) { } template< class Config > Value_impl< Config >::Value_impl( const String_type& value ) - : type_( str_type ) - , v_( value ) - , is_uint64_( false ) + : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( const Object& value ) - : type_( obj_type ) - , v_( value ) - , is_uint64_( false ) + : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( const Array& value ) - : type_( array_type ) - , v_( value ) - , is_uint64_( false ) + : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( bool value ) - : type_( bool_type ) - , v_( value ) - , is_uint64_( false ) + : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( int value ) - : type_( int_type ) - , v_( static_cast< boost::int64_t >( value ) ) - , is_uint64_( false ) + : v_( static_cast< boost::int64_t >( value ) ) { } template< class Config > Value_impl< Config >::Value_impl( boost::int64_t value ) - : type_( int_type ) - , v_( value ) - , is_uint64_( false ) + : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( boost::uint64_t value ) - : type_( int_type ) - , v_( static_cast< boost::int64_t >( value ) ) - , is_uint64_( true ) + : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( double value ) - : type_( real_type ) - , v_( value ) - , is_uint64_( false ) + : v_( value ) { } template< class Config > Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) - : type_( other.type() ) - , v_( other.v_ ) - , is_uint64_( other.is_uint64_ ) + : v_( other.v_ ) + { + } + + template< class Config > + template< class Iter > + Value_impl< Config >::Value_impl( Iter first, Iter last ) + : v_( Array( first, last ) ) + { + } + + template< class Config > + template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > + Value_impl< Config >::Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ) + : v_( boost::apply_visitor( Variant_converter_visitor(), variant) ) { } @@ -300,9 +341,7 @@ namespace json_spirit { Value_impl tmp( lhs ); - std::swap( type_, tmp.type_ ); std::swap( v_, tmp.v_ ); - std::swap( is_uint64_, tmp.is_uint64_ ); return *this; } @@ -320,13 +359,18 @@ namespace json_spirit template< class Config > Value_type Value_impl< Config >::type() const { - return type_; + if( is_uint64() ) + { + return int_type; + } + + return static_cast< Value_type >( v_.which() ); } template< class Config > bool Value_impl< Config >::is_uint64() const { - return is_uint64_; + return v_.which() == null_type + 1; } template< class Config > @@ -342,8 +386,7 @@ namespace json_spirit { std::ostringstream os; - ///// Bitcoin: Tell the types by name instead of by number - os << "value is type " << Value_type_name[type()] << ", expected " << Value_type_name[vtype]; + os << "get_value< " << value_type_to_string( vtype ) << " > called on " << value_type_to_string( type() ) << " Value"; throw std::runtime_error( os.str() ); } @@ -352,7 +395,7 @@ namespace json_spirit template< class Config > const typename Config::String_type& Value_impl< Config >::get_str() const { - check_type( str_type ); + check_type( str_type ); return *boost::get< String_type >( &v_ ); } @@ -368,7 +411,7 @@ namespace json_spirit template< class Config > const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const { - check_type( array_type ); + check_type( array_type ); return *boost::get< Array >( &v_ ); } @@ -376,7 +419,7 @@ namespace json_spirit template< class Config > bool Value_impl< Config >::get_bool() const { - check_type( bool_type ); + check_type( bool_type ); return boost::get< bool >( v_ ); } @@ -384,7 +427,7 @@ namespace json_spirit template< class Config > int Value_impl< Config >::get_int() const { - check_type( int_type ); + check_type( int_type ); return static_cast< int >( get_int64() ); } @@ -392,7 +435,12 @@ namespace json_spirit template< class Config > boost::int64_t Value_impl< Config >::get_int64() const { - check_type( int_type ); + check_type( int_type ); + + if( is_uint64() ) + { + return static_cast< boost::int64_t >( get_uint64() ); + } return boost::get< boost::int64_t >( v_ ); } @@ -400,9 +448,14 @@ namespace json_spirit template< class Config > boost::uint64_t Value_impl< Config >::get_uint64() const { - check_type( int_type ); + check_type( int_type ); - return static_cast< boost::uint64_t >( get_int64() ); + if( !is_uint64() ) + { + return static_cast< boost::uint64_t >( get_int64() ); + } + + return boost::get< boost::uint64_t >( v_ ); } template< class Config > @@ -414,7 +467,7 @@ namespace json_spirit : static_cast< double >( get_int64() ); } - check_type( real_type ); + check_type( real_type ); return boost::get< double >( v_ ); } @@ -422,7 +475,7 @@ namespace json_spirit template< class Config > typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() { - check_type( obj_type ); + check_type( obj_type ); return *boost::get< Object >( &v_ ); } @@ -430,7 +483,7 @@ namespace json_spirit template< class Config > typename Value_impl< Config >::Array& Value_impl< Config >::get_array() { - check_type( array_type ); + check_type( array_type ); return *boost::get< Array >( &v_ ); } @@ -529,6 +582,24 @@ namespace json_spirit { return internal_::get_value( *this, internal_::Type_to_type< T >() ); } + + static std::string value_type_to_string( const Value_type vtype ) + { + switch( vtype ) + { + case obj_type: return "Object"; + case array_type: return "Array"; + case str_type: return "string"; + case bool_type: return "boolean"; + case int_type: return "integer"; + case real_type: return "real"; + case null_type: return "null"; + } + + assert( false ); + + return "unknown type"; + } } #endif diff --git a/src/json/json_spirit_writer.cpp b/src/json/json_spirit_writer.cpp index d24a632cf3..06d3f21d91 100644 --- a/src/json/json_spirit_writer.cpp +++ b/src/json/json_spirit_writer.cpp @@ -1,95 +1,96 @@ -// 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 #include "json_spirit_writer.h" #include "json_spirit_writer_template.h" -void json_spirit::write( const Value& value, std::ostream& os ) -{ - write_stream( value, os, false ); -} - -void json_spirit::write_formatted( const Value& value, std::ostream& os ) -{ - write_stream( value, os, true ); -} - -std::string json_spirit::write( const Value& value ) -{ - return write_string( value, false ); -} - -std::string json_spirit::write_formatted( const Value& value ) -{ - return write_string( value, true ); -} - -#ifndef BOOST_NO_STD_WSTRING - -void json_spirit::write( const wValue& value, std::wostream& os ) -{ - write_stream( value, os, false ); -} - -void json_spirit::write_formatted( const wValue& value, std::wostream& os ) -{ - write_stream( value, os, true ); -} - -std::wstring json_spirit::write( const wValue& value ) -{ - return write_string( value, false ); -} - -std::wstring json_spirit::write_formatted( const wValue& value ) -{ - return write_string( value, true ); -} - +using namespace json_spirit; + +#ifdef JSON_SPIRIT_VALUE_ENABLED + void json_spirit::write( const Value& value, std::ostream& os, unsigned int options ) + { + write_stream( value, os, options ); + } + std::string json_spirit::write( const Value& value, unsigned int options ) + { + return write_string( value, options ); + } + + void json_spirit::write_formatted( const Value& value, std::ostream& os ) + { + write_stream( value, os, pretty_print ); + } + + std::string json_spirit::write_formatted( const Value& value ) + { + return write_string( value, pretty_print ); + } #endif -void json_spirit::write( const mValue& value, std::ostream& os ) -{ - write_stream( value, os, false ); -} - -void json_spirit::write_formatted( const mValue& value, std::ostream& os ) -{ - write_stream( value, os, true ); -} - -std::string json_spirit::write( const mValue& value ) -{ - return write_string( value, false ); -} - -std::string json_spirit::write_formatted( const mValue& value ) -{ - return write_string( value, true ); -} - -#ifndef BOOST_NO_STD_WSTRING - -void json_spirit::write( const wmValue& value, std::wostream& os ) -{ - write_stream( value, os, false ); -} - -void json_spirit::write_formatted( const wmValue& value, std::wostream& os ) -{ - write_stream( value, os, true ); -} - -std::wstring json_spirit::write( const wmValue& value ) -{ - return write_string( value, false ); -} +#ifdef JSON_SPIRIT_MVALUE_ENABLED + void json_spirit::write( const mValue& value, std::ostream& os, unsigned int options ) + { + write_stream( value, os, options ); + } + + std::string json_spirit::write( const mValue& value, unsigned int options ) + { + return write_string( value, options ); + } + + void json_spirit::write_formatted( const mValue& value, std::ostream& os ) + { + write_stream( value, os, pretty_print ); + } + + std::string json_spirit::write_formatted( const mValue& value ) + { + return write_string( value, pretty_print ); + } +#endif -std::wstring json_spirit::write_formatted( const wmValue& value ) -{ - return write_string( value, true ); -} +#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) + void json_spirit::write( const wValue& value, std::wostream& os, unsigned int options ) + { + write_stream( value, os, options ); + } + + std::wstring json_spirit::write( const wValue& value, unsigned int options ) + { + return write_string( value, options ); + } + + void json_spirit::write_formatted( const wValue& value, std::wostream& os ) + { + write_stream( value, os, pretty_print ); + } + + std::wstring json_spirit::write_formatted( const wValue& value ) + { + return write_string( value, pretty_print ); + } +#endif +#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) + void json_spirit::write_formatted( const wmValue& value, std::wostream& os ) + { + write_stream( value, os, pretty_print ); + } + + std::wstring json_spirit::write_formatted( const wmValue& value ) + { + return write_string( value, pretty_print ); + } + + void json_spirit::write( const wmValue& value, std::wostream& os, unsigned int options ) + { + write_stream( value, os, options ); + } + + std::wstring json_spirit::write( const wmValue& value, unsigned int options ) + { + return write_string( value, options ); + } #endif diff --git a/src/json/json_spirit_writer.h b/src/json/json_spirit_writer.h index 52e14068e7..18c2fd4264 100644 --- a/src/json/json_spirit_writer.h +++ b/src/json/json_spirit_writer.h @@ -1,49 +1,62 @@ #ifndef JSON_SPIRIT_WRITER #define JSON_SPIRIT_WRITER -// 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 <iostream> namespace json_spirit { - // functions to convert JSON Values to text, - // the "formatted" versions add whitespace to format the output nicely + // these functions to convert JSON Values to text - void write ( const Value& value, std::ostream& os ); - void write_formatted( const Value& value, std::ostream& os ); - std::string write ( const Value& value ); - std::string write_formatted( const Value& value ); +#ifdef JSON_SPIRIT_VALUE_ENABLED + void write( const Value& value, std::ostream& os, unsigned int options = 0 ); + std::string write( const Value& value, unsigned int options = 0 ); +#endif -#ifndef BOOST_NO_STD_WSTRING +#ifdef JSON_SPIRIT_MVALUE_ENABLED + void write( const mValue& value, std::ostream& os, unsigned int options = 0 ); + std::string write( const mValue& value, unsigned int options = 0 ); +#endif - void write ( const wValue& value, std::wostream& os ); - void write_formatted( const wValue& value, std::wostream& os ); - std::wstring write ( const wValue& value ); - std::wstring write_formatted( const wValue& value ); +#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) + void write( const wValue& value, std::wostream& os, unsigned int options = 0 ); + std::wstring write( const wValue& value, unsigned int options = 0 ); +#endif +#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) + void write( const wmValue& value, std::wostream& os, unsigned int options = 0 ); + std::wstring write( const wmValue& value, unsigned int options = 0 ); #endif - void write ( const mValue& value, std::ostream& os ); + // these "formatted" versions of the "write" functions are the equivalent of the above functions + // with option "pretty_print" + +#ifdef JSON_SPIRIT_VALUE_ENABLED + void write_formatted( const Value& value, std::ostream& os ); + std::string write_formatted( const Value& value ); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED void write_formatted( const mValue& value, std::ostream& os ); - std::string write ( const mValue& value ); std::string write_formatted( const mValue& value ); +#endif -#ifndef BOOST_NO_STD_WSTRING - - void write ( const wmValue& value, std::wostream& os ); +#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) + void write_formatted( const wValue& value, std::wostream& os ); + std::wstring write_formatted( const wValue& value ); +#endif +#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) void write_formatted( const wmValue& value, std::wostream& os ); - std::wstring write ( const wmValue& value ); std::wstring write_formatted( const wmValue& value ); - #endif } diff --git a/src/json/json_spirit_writer_options.h b/src/json/json_spirit_writer_options.h new file mode 100644 index 0000000000..ac6c57f33c --- /dev/null +++ b/src/json/json_spirit_writer_options.h @@ -0,0 +1,33 @@ +#ifndef JSON_SPIRIT_WRITER_OPTIONS +#define JSON_SPIRIT_WRITER_OPTIONS + +// Copyright John W. Wilkinson 2007 - 2013 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.06 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +namespace json_spirit +{ + enum Output_options{ pretty_print = 0x01, // Add whitespace to format the output nicely. + + raw_utf8 = 0x02, // This prevents non-printable characters from being escapted using "\uNNNN" notation. + // Note, this is an extension to the JSON standard. It disables the escaping of + // non-printable characters allowing UTF-8 sequences held in 8 bit char strings + // to pass through unaltered. + + remove_trailing_zeros = 0x04, + // outputs e.g. "1.200000000000000" as "1.2" + single_line_arrays = 0x08, + // pretty printing except that arrays printed on single lines unless they contain + // composite elements, i.e. objects or arrays + always_escape_nonascii = 0x10, + // all unicode wide characters are escaped, i.e. outputed as "\uXXXX", even if they are + // printable under the current locale, ascii printable chars are not escaped + }; +} + +#endif 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(); } diff --git a/src/main.cpp b/src/main.cpp index a5a0f031af..01a1babc7f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -469,17 +469,28 @@ bool IsStandardTx(const CTransaction& tx, string& reason) return false; } } + + unsigned int nDataOut = 0; + txnouttype whichType; BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (!::IsStandard(txout.scriptPubKey)) { + if (!::IsStandard(txout.scriptPubKey, whichType)) { reason = "scriptpubkey"; return false; } - if (txout.IsDust(CTransaction::nMinRelayTxFee)) { + if (whichType == TX_NULL_DATA) + nDataOut++; + else if (txout.IsDust(CTransaction::nMinRelayTxFee)) { reason = "dust"; return false; } } + // only one OP_RETURN txout is permitted + if (nDataOut > 1) { + reason = "mucho-data"; + return false; + } + return true; } diff --git a/src/net.cpp b/src/net.cpp index dd7bf283a9..d223b3999e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -639,6 +639,9 @@ void CNode::copyStats(CNodeStats &stats) // Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :) stats.dPingTime = (((double)nPingUsecTime) / 1e6); stats.dPingWait = (((double)nPingUsecWait) / 1e6); + + // Leave string empty if addrLocal invalid (not filled in yet) + stats.addrLocal = addrLocal.IsValid() ? addrLocal.ToString() : ""; } #undef X @@ -121,6 +121,7 @@ public: bool fSyncNode; double dPingTime; double dPingWait; + std::string addrLocal; }; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index e7dcdf62a1..e31310c2b6 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -159,7 +159,7 @@ void RPCExecutor::request(const QString &command) else if (result.type() == json_spirit::str_type) strPrint = result.get_str(); else - strPrint = write_string(result, true); + strPrint = write_string(result, json_spirit::pretty_print | json_spirit::raw_utf8); emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); } @@ -173,7 +173,7 @@ void RPCExecutor::request(const QString &command) } catch(std::runtime_error &) // raised when converting to invalid type, i.e. missing code or message { // Show raw JSON object - emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false))); + emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), json_spirit::raw_utf8))); } } catch (std::exception& e) diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 7c9bc46c46..07b71a3c9a 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -66,9 +66,8 @@ SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) : pixPaint.setFont(QFont(font, 10*fontFactor)); pixPaint.drawText(newPixmap.width()-titleTextWidth-paddingRight,paddingTop+titleCopyrightVSpace,copyrightText); - // draw testnet string if -testnet is on - if(QApplication::applicationName().contains(QString("-testnet"))) { - // draw copyright stuff + // draw testnet string if testnet is on + if(TestNet()) { QFont boldFont = QFont(font, 10*fontFactor); boldFont.setWeight(QFont::Bold); pixPaint.setFont(boldFont); diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 7685dec57b..3c92739852 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -66,6 +66,8 @@ Value getpeerinfo(const Array& params, bool fHelp) Object obj; obj.push_back(Pair("addr", stats.addrName)); + if (!(stats.addrLocal.empty())) + obj.push_back(Pair("addrlocal", stats.addrLocal)); obj.push_back(Pair("services", strprintf("%08"PRI64x, stats.nServices))); obj.push_back(Pair("lastsend", (boost::int64_t)stats.nLastSend)); obj.push_back(Pair("lastrecv", (boost::int64_t)stats.nLastRecv)); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index a72c254e76..7aae9ddb73 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -968,6 +968,13 @@ Value listreceivedbyaccount(const Array& params, bool fHelp) return ListReceived(params, true); } +static void MaybePushAddress(Object & entry, const CTxDestination &dest) +{ + CBitcoinAddress addr; + if (addr.Set(dest)) + entry.push_back(Pair("address", addr.ToString())); +} + void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret) { int64 nFee; @@ -986,7 +993,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe { Object entry; entry.push_back(Pair("account", strSentAccount)); - entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString())); + MaybePushAddress(entry, s.first); entry.push_back(Pair("category", "send")); entry.push_back(Pair("amount", ValueFromAmount(-s.second))); entry.push_back(Pair("fee", ValueFromAmount(-nFee))); @@ -1008,7 +1015,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe { Object entry; entry.push_back(Pair("account", account)); - entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString())); + MaybePushAddress(entry, r.first); if (wtx.IsCoinBase()) { if (wtx.GetDepthInMainChain() < 1) diff --git a/src/script.cpp b/src/script.cpp index 4e4e95a678..63f632795a 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -79,6 +79,7 @@ const char* GetTxnOutputType(txnouttype t) case TX_PUBKEYHASH: return "pubkeyhash"; case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; + case TX_NULL_DATA: return "nulldata"; } return NULL; } @@ -220,6 +221,7 @@ const char* GetOpName(opcodetype opcode) // template matching params case OP_PUBKEYHASH : return "OP_PUBKEYHASH"; case OP_PUBKEY : return "OP_PUBKEY"; + case OP_SMALLDATA : return "OP_SMALLDATA"; case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; default: @@ -1204,6 +1206,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi // Sender provides N pubkeys, receivers provides M signatures mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); + + // Empty, provably prunable, data-carrying output + mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA)); } // Shortcut for pay-to-script-hash, which are more constrained than the other types: @@ -1288,6 +1293,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi else break; } + else if (opcode2 == OP_SMALLDATA) + { + // small pushdata, <= 80 bytes + if (vch1.size() > 80) + break; + } else if (opcode1 != opcode2 || vch1 != vch2) { // Others must match exactly @@ -1350,6 +1361,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash switch (whichTypeRet) { case TX_NONSTANDARD: + case TX_NULL_DATA: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); @@ -1381,6 +1393,8 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c { case TX_NONSTANDARD: return -1; + case TX_NULL_DATA: + return 1; case TX_PUBKEY: return 1; case TX_PUBKEYHASH: @@ -1395,10 +1409,9 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c return -1; } -bool IsStandard(const CScript& scriptPubKey) +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) { vector<valtype> vSolutions; - txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; @@ -1457,6 +1470,7 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) switch (whichType) { case TX_NONSTANDARD: + case TX_NULL_DATA: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); @@ -1518,6 +1532,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto vector<valtype> vSolutions; if (!Solver(scriptPubKey, typeRet, vSolutions)) return false; + if (typeRet == TX_NULL_DATA) + return true; if (typeRet == TX_MULTISIG) { @@ -1733,6 +1749,7 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, switch (txType) { case TX_NONSTANDARD: + case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: if (sigs1.size() >= sigs2.size()) return PushAll(sigs1); diff --git a/src/script.h b/src/script.h index d339f7880e..931307007f 100644 --- a/src/script.h +++ b/src/script.h @@ -46,6 +46,7 @@ enum txnouttype TX_PUBKEYHASH, TX_SCRIPTHASH, TX_MULTISIG, + TX_NULL_DATA, }; class CNoDestination { @@ -202,6 +203,7 @@ enum opcodetype // template matching params + OP_SMALLDATA = 0xf9, OP_SMALLINTEGER = 0xfa, OP_PUBKEYS = 0xfb, OP_PUBKEYHASH = 0xfd, @@ -683,7 +685,7 @@ bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet); int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions); -bool IsStandard(const CScript& scriptPubKey); +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CTxDestination &dest); void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys); diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 05675685bd..c435becc61 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -20,7 +20,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + std::string strTest = write_string(tv, raw_utf8); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + std::string strTest = write_string(tv, raw_utf8); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -113,7 +113,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + std::string strTest = write_string(tv, raw_utf8); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + std::string strTest = write_string(tv, raw_utf8); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -240,7 +240,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + std::string strTest = write_string(tv, raw_utf8); if (test.size() < 1) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 7f6f141c62..05309f1a4d 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -133,21 +133,23 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard) for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); + txnouttype whichType; + CScript a_and_b; a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(::IsStandard(a_and_b)); + BOOST_CHECK(::IsStandard(a_and_b, whichType)); CScript a_or_b; a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(::IsStandard(a_or_b)); + BOOST_CHECK(::IsStandard(a_or_b, whichType)); CScript escrow; escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; - BOOST_CHECK(::IsStandard(escrow)); + BOOST_CHECK(::IsStandard(escrow, whichType)); CScript one_of_four; one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG; - BOOST_CHECK(!::IsStandard(one_of_four)); + BOOST_CHECK(!::IsStandard(one_of_four, whichType)); CScript malformed[6]; malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; @@ -158,7 +160,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard) malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey(); for (int i = 0; i < 6; i++) - BOOST_CHECK(!::IsStandard(malformed[i])); + BOOST_CHECK(!::IsStandard(malformed[i], whichType)); } BOOST_AUTO_TEST_CASE(multisig_Solver1) diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 32be914414..079cc49f60 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(script_valid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - string strTest = write_string(tv, false); + string strTest = write_string(tv, raw_utf8); if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(script_invalid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - string strTest = write_string(tv, false); + string strTest = write_string(tv, raw_utf8); if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) { BOOST_ERROR("Bad test: " << strTest); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 416b93ab33..d68ead1cd0 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - string strTest = write_string(tv, false); + string strTest = write_string(tv, raw_utf8); if (test[0].type() == array_type) { if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - string strTest = write_string(tv, false); + string strTest = write_string(tv, raw_utf8); if (test[0].type() == array_type) { if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) @@ -273,6 +273,20 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].scriptPubKey = CScript() << OP_1; BOOST_CHECK(!IsStandardTx(t, reason)); + + // 80-byte TX_NULL_DATA (standard) + t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + BOOST_CHECK(IsStandardTx(t, reason)); + + // 81-byte TX_NULL_DATA (non-standard) + t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); + BOOST_CHECK(!IsStandardTx(t, reason)); + + // Only one TX_NULL_DATA permitted + t.vout.resize(2); + t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + BOOST_CHECK(!IsStandardTx(t, reason)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet.cpp b/src/wallet.cpp index 349498545e..a7a2992bb9 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -654,22 +654,35 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64> >& listReceived, // Sent/received. BOOST_FOREACH(const CTxOut& txout, vout) { + bool fIsMine; + // Only need to handle txouts if AT LEAST one of these is true: + // 1) they debit from us (sent) + // 2) the output is to us (received) + if (nDebit > 0) + { + // Don't report 'change' txouts + if (pwallet->IsChange(txout)) + continue; + fIsMine = pwallet->IsMine(txout); + } + else if (!(fIsMine = pwallet->IsMine(txout))) + continue; + + // In either case, we need to get the destination address CTxDestination address; - vector<unsigned char> vchPubKey; if (!ExtractDestination(txout.scriptPubKey, address)) { LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString().c_str()); + address = CNoDestination(); } - // Don't report 'change' txouts - if (nDebit > 0 && pwallet->IsChange(txout)) - continue; - + // If we are debited by the transaction, add the output as a "sent" entry if (nDebit > 0) listSent.push_back(make_pair(address, txout.nValue)); - if (pwallet->IsMine(txout)) + // If we are receiving the output, add it as a "received" entry + if (fIsMine) listReceived.push_back(make_pair(address, txout.nValue)); } |