diff --git a/boost.py b/boost.py index d3c4869..0a23582 100644 --- a/boost.py +++ b/boost.py @@ -54,8 +54,7 @@ def build(bld): from waflib.Configure import conf from waflib.TaskGen import feature, after_method -BOOST_LIBS = ['/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', - '/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] +BOOST_LIBS = ['/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', '/usr/lib/aarch64-linux-gnu', '/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include'] BOOST_VERSION_FILE = 'boost/version.hpp' BOOST_VERSION_CODE = ''' diff --git a/json5_parser/CMakeLists.txt b/json5_parser/CMakeLists.txt index e83fb38..c3d3941 100644 --- a/json5_parser/CMakeLists.txt +++ b/json5_parser/CMakeLists.txt @@ -1,17 +1,17 @@ -SET(JSON_SPIRIT_SRCS -json5_parser_reader.cpp json5_parser_reader.h -json5_parser_value.cpp json5_parser_value.h -json5_parser_writer.cpp json5_parser_writer.h -json5_parser.h -json5_parser_error_position.h -json5_parser_reader_template.h -json5_parser_stream_reader.h -json5_parser_utils.h -json5_parser_writer_options.h -json5_parser_writer_template.h ) - -FIND_PACKAGE(Boost 1.34 REQUIRED) -INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) - -ADD_LIBRARY(json5_parser STATIC ${JSON_SPIRIT_SRCS}) - +SET(JSON_SPIRIT_SRCS +json5_parser_reader.cpp json5_parser_reader.h +json5_parser_value.cpp json5_parser_value.h +json5_parser_writer.cpp json5_parser_writer.h +json5_parser.h +json5_parser_error_position.h +json5_parser_reader_template.h +json5_parser_stream_reader.h +json5_parser_utils.h +json5_parser_writer_options.h +json5_parser_writer_template.h ) + +#FIND_PACKAGE(Boost 1.34 REQUIRED) +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) + +ADD_LIBRARY(json5_parser STATIC ${JSON_SPIRIT_SRCS}) + diff --git a/json5_parser/json5_parser.h b/json5_parser/json5_parser.h index 1f84a48..2ba50c2 100644 --- a/json5_parser/json5_parser.h +++ b/json5_parser/json5_parser.h @@ -1,18 +1,18 @@ -#ifndef JSON_SPIRIT -#define JSON_SPIRIT - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_reader.h" -#include "json5_parser_writer.h" -#include "json5_parser_utils.h" - -#endif +#ifndef JSON_SPIRIT +#define JSON_SPIRIT + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "json5_parser_reader.h" +#include "json5_parser_utils.h" +#include "json5_parser_value.h" +#include "json5_parser_writer.h" + +#endif diff --git a/json5_parser/json5_parser_error_position.h b/json5_parser/json5_parser_error_position.h index 6e0432d..749de77 100644 --- a/json5_parser/json5_parser_error_position.h +++ b/json5_parser/json5_parser_error_position.h @@ -1,54 +1,42 @@ -#ifndef JSON_SPIRIT_ERROR_POSITION -#define JSON_SPIRIT_ERROR_POSITION - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include - -namespace json5_parser -{ - // An Error_position exception is thrown by the "read_or_throw" functions below on finding an error. - // Note the "read_or_throw" functions are around 3 times slower than the standard functions "read" - // functions that return a bool. - // - struct Error_position - { - Error_position(); - Error_position( unsigned int line, unsigned int column, const std::string& reason ); - bool operator==( const Error_position& lhs ) const; - unsigned int line_; - unsigned int column_; - std::string reason_; - }; - - inline Error_position::Error_position() - : line_( 0 ) - , column_( 0 ) - { - } - - inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason ) - : line_( line ) - , column_( column ) - , reason_( reason ) - { - } - - inline bool Error_position::operator==( const Error_position& lhs ) const - { - if( this == &lhs ) return true; - - return ( reason_ == lhs.reason_ ) && - ( line_ == lhs.line_ ) && - ( column_ == lhs.column_ ); - } -} - -#endif +#ifndef JSON_SPIRIT_ERROR_POSITION +#define JSON_SPIRIT_ERROR_POSITION + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include + +namespace json5_parser { +// An Error_position exception is thrown by the "read_or_throw" functions below on +// finding an error. Note the "read_or_throw" functions are around 3 times slower than +// the standard functions "read" functions that return a bool. +// +struct Error_position { + Error_position(); + Error_position(unsigned int line, unsigned int column, const std::string& reason); + bool operator==(const Error_position& lhs) const; + unsigned int line_; + unsigned int column_; + std::string reason_; +}; + +inline Error_position::Error_position() : line_(0), column_(0) {} + +inline Error_position::Error_position(unsigned int line, unsigned int column, + const std::string& reason) + : line_(line), column_(column), reason_(reason) {} + +inline bool Error_position::operator==(const Error_position& lhs) const { + if (this == &lhs) return true; + + return (reason_ == lhs.reason_) && (line_ == lhs.line_) && (column_ == lhs.column_); +} +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_reader.cpp b/json5_parser/json5_parser_reader.cpp index c6adb75..20d6e48 100644 --- a/json5_parser/json5_parser_reader.cpp +++ b/json5_parser/json5_parser_reader.cpp @@ -1,137 +1,121 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_reader.h" -#include "json5_parser_reader_template.h" - -using namespace json5_parser; - -#ifdef JSON_SPIRIT_VALUE_ENABLED - bool json5_parser::read( const std::string& s, Value& value ) - { - return read_string( s, value ); - } - - void json5_parser::read_or_throw( const std::string& s, Value& value ) - { - read_string_or_throw( s, value ); - } - - bool json5_parser::read( std::istream& is, Value& value ) - { - return read_stream( is, value ); - } - - void json5_parser::read_or_throw( std::istream& is, Value& value ) - { - read_stream_or_throw( is, value ); - } - - bool json5_parser::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) - { - return read_range( begin, end, value ); - } - - void json5_parser::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 json5_parser::read( const std::wstring& s, wValue& value ) - { - return read_string( s, value ); - } - - void json5_parser::read_or_throw( const std::wstring& s, wValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json5_parser::read( std::wistream& is, wValue& value ) - { - return read_stream( is, value ); - } - - void json5_parser::read_or_throw( std::wistream& is, wValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json5_parser::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) - { - return read_range( begin, end, value ); - } - - void json5_parser::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) - { - begin = read_range_or_throw( begin, end, value ); - } -#endif - -#ifdef JSON_SPIRIT_MVALUE_ENABLED - bool json5_parser::read( const std::string& s, mValue& value ) - { - return read_string( s, value ); - } - - void json5_parser::read_or_throw( const std::string& s, mValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json5_parser::read( std::istream& is, mValue& value ) - { - return read_stream( is, value ); - } - - void json5_parser::read_or_throw( std::istream& is, mValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json5_parser::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) - { - return read_range( begin, end, value ); - } - - void json5_parser::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 json5_parser::read( const std::wstring& s, wmValue& value ) - { - return read_string( s, value ); - } - - void json5_parser::read_or_throw( const std::wstring& s, wmValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json5_parser::read( std::wistream& is, wmValue& value ) - { - return read_stream( is, value ); - } - - void json5_parser::read_or_throw( std::wistream& is, wmValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json5_parser::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) - { - return read_range( begin, end, value ); - } - - void json5_parser::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) - { - begin = read_range_or_throw( begin, end, value ); - } -#endif +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_reader.h" +#include "json5_parser_reader_template.h" + +using namespace json5_parser; + +#ifdef JSON_SPIRIT_VALUE_ENABLED +bool json5_parser::read(const std::string& s, Value& value) { + return read_string(s, value); +} + +void json5_parser::read_or_throw(const std::string& s, Value& value) { + read_string_or_throw(s, value); +} + +bool json5_parser::read(std::istream& is, Value& value) { + return read_stream(is, value); +} + +void json5_parser::read_or_throw(std::istream& is, Value& value) { + read_stream_or_throw(is, value); +} + +bool json5_parser::read(std::string::const_iterator& begin, + std::string::const_iterator end, Value& value) { + return read_range(begin, end, value); +} + +void json5_parser::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 json5_parser::read(const std::wstring& s, wValue& value) { + return read_string(s, value); +} + +void json5_parser::read_or_throw(const std::wstring& s, wValue& value) { + read_string_or_throw(s, value); +} + +bool json5_parser::read(std::wistream& is, wValue& value) { + return read_stream(is, value); +} + +void json5_parser::read_or_throw(std::wistream& is, wValue& value) { + read_stream_or_throw(is, value); +} + +bool json5_parser::read(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wValue& value) { + return read_range(begin, end, value); +} + +void json5_parser::read_or_throw(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wValue& value) { + begin = read_range_or_throw(begin, end, value); +} +#endif + +#ifdef JSON_SPIRIT_MVALUE_ENABLED +bool json5_parser::read(const std::string& s, mValue& value) { + return read_string(s, value); +} + +void json5_parser::read_or_throw(const std::string& s, mValue& value) { + read_string_or_throw(s, value); +} + +bool json5_parser::read(std::istream& is, mValue& value) { + return read_stream(is, value); +} + +void json5_parser::read_or_throw(std::istream& is, mValue& value) { + read_stream_or_throw(is, value); +} + +bool json5_parser::read(std::string::const_iterator& begin, + std::string::const_iterator end, mValue& value) { + return read_range(begin, end, value); +} + +void json5_parser::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 json5_parser::read(const std::wstring& s, wmValue& value) { + return read_string(s, value); +} + +void json5_parser::read_or_throw(const std::wstring& s, wmValue& value) { + read_string_or_throw(s, value); +} + +bool json5_parser::read(std::wistream& is, wmValue& value) { + return read_stream(is, value); +} + +void json5_parser::read_or_throw(std::wistream& is, wmValue& value) { + read_stream_or_throw(is, value); +} + +bool json5_parser::read(std::wstring::const_iterator& begin, + std::wstring::const_iterator end, wmValue& value) { + return read_range(begin, end, value); +} + +void json5_parser::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/json5_parser/json5_parser_reader.h b/json5_parser/json5_parser_reader.h index 023c18c..b41ad9d 100644 --- a/json5_parser/json5_parser_reader.h +++ b/json5_parser/json5_parser_reader.h @@ -1,62 +1,69 @@ -#ifndef JSON_SPIRIT_READER -#define JSON_SPIRIT_READER - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_error_position.h" -#include - -namespace json5_parser -{ - // 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 ); - - 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 - -#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 ); - - 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 ); - - 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 - -#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 ); - - 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 -} - -#endif +#ifndef JSON_SPIRIT_READER +#define JSON_SPIRIT_READER + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include "json5_parser_error_position.h" +#include "json5_parser_value.h" + +namespace json5_parser { +// 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); + +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 + +#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); + +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); + +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 + +#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); + +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 +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_reader_template.h b/json5_parser/json5_parser_reader_template.h index 557035b..865daf7 100644 --- a/json5_parser/json5_parser_reader_template.h +++ b/json5_parser/json5_parser_reader_template.h @@ -1,701 +1,624 @@ -#ifndef JSON_SPIRIT_READER_TEMPLATE -#define JSON_SPIRIT_READER_TEMPLATE - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_error_position.h" - -#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread - -#include -#include -#include - -#if BOOST_VERSION >= 103800 - #include - #include - #include - #include - #include - #define spirit_namespace boost::spirit::classic -#else - #include - #include - #include - #include - #include - #define spirit_namespace boost::spirit -#endif - -namespace json5_parser -{ - const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >(); - const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >(); - - template< class Iter_type > - bool is_eq( Iter_type first, Iter_type last, const char* c_str ) - { - for( Iter_type i = first; i != last; ++i, ++c_str ) - { - if( *c_str == 0 ) return false; - - if( *i != *c_str ) return false; - } - - return true; - } - - template< class Char_type > - Char_type hex_to_num( const Char_type c ) - { - if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0'; - if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10; - if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10; - return 0; - } - - template< class Char_type, class Iter_type > - Char_type hex_str_to_char( Iter_type& begin ) - { - const Char_type c1( *( ++begin ) ); - const Char_type c2( *( ++begin ) ); - - return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 ); - } - - template< class Char_type, class Iter_type > - Char_type unicode_str_to_char( Iter_type& begin ) - { - const Char_type c1( *( ++begin ) ); - const Char_type c2( *( ++begin ) ); - const Char_type c3( *( ++begin ) ); - const Char_type c4( *( ++begin ) ); - - return ( hex_to_num( c1 ) << 12 ) + - ( hex_to_num( c2 ) << 8 ) + - ( hex_to_num( c3 ) << 4 ) + - hex_to_num( c4 ); - } - - template< class String_type > - void append_esc_char_and_incr_iter( String_type& s, - typename String_type::const_iterator& begin, - typename String_type::const_iterator end ) - { - typedef typename String_type::value_type Char_type; - - const Char_type c2( *begin ); - - switch( c2 ) - { - case 't': s += '\t'; break; - case 'b': s += '\b'; break; - case 'f': s += '\f'; break; - case 'n': s += '\n'; break; - case 'r': s += '\r'; break; - case '\\': s += '\\'; break; - case '/': s += '/'; break; - case '"': s += '"'; break; - case 'x': - { - if( end - begin >= 3 ) // expecting "xHH..." - { - s += hex_str_to_char< Char_type >( begin ); - } - break; - } - case 'u': - { - if( end - begin >= 5 ) // expecting "uHHHH..." - { - s += unicode_str_to_char< Char_type >( begin ); - } - break; - } - case '\n': break; // skip escaped newlines - } - } - - template< class String_type > - String_type substitute_esc_chars( typename String_type::const_iterator begin, - typename String_type::const_iterator end ) - { - typedef typename String_type::const_iterator Iter_type; - - if( end - begin < 2 ) return String_type( begin, end ); - - String_type result; - - result.reserve( end - begin ); - - const Iter_type end_minus_1( end - 1 ); - - Iter_type substr_start = begin; - Iter_type i = begin; - - for( ; i < end_minus_1; ++i ) - { - if( *i == '\\' ) - { - result.append( substr_start, i ); - - ++i; // skip the '\' - - append_esc_char_and_incr_iter( result, i, end ); - - substr_start = i + 1; - } - } - - result.append( substr_start, end ); - - return result; - } - - template< class String_type > - String_type get_str_( typename String_type::const_iterator begin, - typename String_type::const_iterator end ) - { - assert( end - begin >= 2 ); - - typedef typename String_type::const_iterator Iter_type; - - Iter_type str_without_quotes( ++begin ); - Iter_type end_without_quotes( --end ); - - return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes ); - } - - inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end ) - { - return get_str_< std::string >( begin, end ); - } - - inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end ) - { - return get_str_< std::wstring >( begin, end ); - } - - template< class String_type, class Iter_type > - String_type get_str( Iter_type begin, Iter_type end ) - { - const String_type tmp( begin, end ); // convert multipass iterators to string iterators - - return get_str( tmp.begin(), tmp.end() ); - } - - // this class's methods get called by the spirit parse resulting - // in the creation of a JSON object or array - // - // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator - // - template< class Value_type, class Iter_type > - class Semantic_actions - { - public: - - typedef typename Value_type::Config_type Config_type; - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename String_type::value_type Char_type; - - Semantic_actions( Value_type& value ) - : value_( value ) - , current_p_( 0 ) - { - } - - void begin_obj( Char_type c ) - { - assert( c == '{' ); - - begin_compound< Object_type >(); - } - - void end_obj( Char_type c ) - { - assert( c == '}' ); - - end_compound(); - } - - void begin_array( Char_type c ) - { - assert( c == '[' ); - - begin_compound< Array_type >(); - } - - void end_array( Char_type c ) - { - assert( c == ']' ); - - end_compound(); - } - - void new_name( Iter_type begin, Iter_type end ) - { - assert( current_p_->type() == obj_type ); - - name_ = get_str< String_type >( begin, end ); - } - - void new_identifier( Iter_type begin, Iter_type end ) - { - assert( current_p_->type() == obj_type ); - - String_type result; - result.append(begin,end); - name_ = result; - } - - void new_str( Iter_type begin, Iter_type end ) - { - add_to_current( get_str< String_type >( begin, end ) ); - } - - void new_true( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "true" ) ); - - add_to_current( true ); - } - - void new_false( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "false" ) ); - - add_to_current( false ); - } - - void new_null( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "null" ) ); - - add_to_current( Value_type() ); - } - - void new_int( boost::int64_t i ) - { - add_to_current( i ); - } - - void new_uint64( boost::uint64_t ui ) - { - add_to_current( ui ); - } - - void new_real( double d ) - { - add_to_current( d ); - } - - void new_infinity( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "Infinity" ) ); - - add_to_current( std::numeric_limits::infinity() ); - } - - void new_minus_infinity( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "-Infinity" ) ); - - add_to_current( -std::numeric_limits::infinity() ); - } - - private: - - Semantic_actions& operator=( const Semantic_actions& ); - // to prevent "assignment operator could not be generated" warning - - Value_type* add_first( const Value_type& value ) - { - assert( current_p_ == 0 ); - - value_ = value; - current_p_ = &value_; - return current_p_; - } - - template< class Array_or_obj > - void begin_compound() - { - if( current_p_ == 0 ) - { - add_first( Array_or_obj() ); - } - else - { - stack_.push_back( current_p_ ); - - Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place - - current_p_ = add_to_current( new_array_or_obj ); - } - } - - void end_compound() - { - if( current_p_ != &value_ ) - { - current_p_ = stack_.back(); - - stack_.pop_back(); - } - } - - Value_type* add_to_current( const Value_type& value ) - { - if( current_p_ == 0 ) - { - return add_first( value ); - } - else if( current_p_->type() == array_type ) - { - current_p_->get_array().push_back( value ); - - return ¤t_p_->get_array().back(); - } - - assert( current_p_->type() == obj_type ); - - return &Config_type::add( current_p_->get_obj(), name_, value ); - } - - Value_type& value_; // this is the object or array that is being created - Value_type* current_p_; // the child object or array that is currently being constructed - - std::vector< Value_type* > stack_; // previous child objects and arrays - - String_type name_; // of current name/value pair - }; - - template< typename Iter_type > - void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason ) - { - throw Error_position( i.get_position().line, i.get_position().column, reason ); - } - - template< typename Iter_type > - void throw_error( Iter_type , const std::string& reason ) - { - throw reason; - } - - // the spirit grammer - // - template< class Value_type, class Iter_type > - class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > > - { - public: - - typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t; - - Json_grammer( Semantic_actions_t& semantic_actions ) - : actions_( semantic_actions ) - { - } - - static void throw_not_value( Iter_type begin, Iter_type ) - { - throw_error( begin, "not a value" ); - } - - static void throw_not_hex( Iter_type begin, Iter_type ) - { - throw_error( begin, "not a hexadecimal number" ); - } - - static void throw_not_array( Iter_type begin, Iter_type ) - { - throw_error( begin, "not an array" ); - } - - static void throw_not_object( Iter_type begin, Iter_type ) - { - throw_error( begin, "not an object" ); - } - - static void throw_not_pair( Iter_type begin, Iter_type ) - { - throw_error( begin, "not a pair" ); - } - - static void throw_not_colon( Iter_type begin, Iter_type ) - { - throw_error( begin, "no colon in pair" ); - } - - static void throw_not_string( Iter_type begin, Iter_type ) - { - throw_error( begin, "not a string" ); - } - - template< typename ScannerT > - class definition - { - public: - - definition( const Json_grammer& self ) - { - using namespace spirit_namespace; - - typedef typename Value_type::String_type::value_type Char_type; - - // first we convert the semantic action class methods to functors with the - // parameter signature expected by spirit - - typedef boost::function< void( Char_type ) > Char_action; - typedef boost::function< void( Iter_type, Iter_type ) > Str_action; - typedef boost::function< void( double ) > Real_action; - typedef boost::function< void( boost::int64_t ) > Int_action; - typedef boost::function< void( boost::uint64_t ) > Uint64_action; - - Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) ); - Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) ); - Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) ); - Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) ); - Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) ); - Str_action new_identifier( boost::bind( &Semantic_actions_t::new_identifier, &self.actions_, _1, _2 ) ); - Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) ); - Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) ); - Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) ); - Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) ); - Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) ); - Str_action new_infinity ( boost::bind( &Semantic_actions_t::new_infinity, &self.actions_, _1, _2 ) ); - Str_action new_minus_infinity ( boost::bind( &Semantic_actions_t::new_minus_infinity, &self.actions_, _1, _2 ) ); - Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) ); - Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) ); - - // actual grammer - - json_ - = value_ | eps_p[ &throw_not_value ] - ; - - value_ - = single_quoted_string_[ new_str ] - | double_quoted_string_[ new_str ] - | number_ - | object_ - | array_ - | str_p( "true" ) [ new_true ] - | str_p( "false" )[ new_false ] - | str_p( "null" ) [ new_null ] - | (!ch_p('+') >> str_p( "Infinity" ) [ new_infinity ]) - | str_p( "-Infinity" ) [ new_minus_infinity ] - ; - - object_ - = ch_p('{')[ begin_obj ] - >> !members_ - >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] ) - ; - - members_ - = pair_ >> *( ',' >> pair_ ) >> !ch_p(',') - ; - - pair_ - = (double_quoted_string_[ new_name ] | identifier_[ new_identifier ]) - >> ( ':' | eps_p[ &throw_not_colon ] ) - >> ( value_ | eps_p[ &throw_not_value ] ) - ; - - array_ - = ch_p('[')[ begin_array ] - >> !elements_ - >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] ) - ; - - elements_ - = value_ >> *( ',' >> value_ ) >> !ch_p(',') - ; - - double_quoted_string_ - = lexeme_d // this causes white space and what would appear to be comments inside a string to be retained - [ - confix_p - ( - '"', - *lex_escape_ch_p, - '"' - ) - ] - ; - - single_quoted_string_ - = lexeme_d // this causes white space and what would appear to be comments inside a string to be retained - [ - confix_p - ( - '\'', - *lex_escape_ch_p, - '\'' - ) - ] - ; - - identifier_ - = (alpha_p | ch_p('_') | ch_p('$')) >> *(alnum_p | ch_p('_') | ch_p('$')); - - number_ - = ( str_p("0x") >> (hex_p[ new_int ] | eps_p[ &throw_not_hex ] ) ) - | strict_real_p[ new_real ] - | int64_p [ new_int ] - | uint64_p [ new_uint64 ] - ; - } - - spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, single_quoted_string_, double_quoted_string_, number_, identifier_; - - const spirit_namespace::rule< ScannerT >& start() const { return json_; } - }; - - private: - - Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning - - Semantic_actions_t& actions_; - }; - - 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 ); - - 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::comment_p("//") | - spirit_namespace::comment_p("/*", "*/") ); - - if( !info.hit ) - { - assert( false ); // in theory exception should already have been thrown - throw_error( info.stop, "error" ); - } - - return info.stop; - } - - // 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 ) - { - try - { - begin = read_range_or_throw( begin, end, value ); - - return true; - } - catch( ... ) - { - return false; - } - } - - // 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 ) - { - typename String_type::const_iterator begin = s.begin(); - - return read_range( begin, s.end(), value ); - } - - // 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 ) - { - 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 ) - { - Multi_pass_iters< Istream_type > mp_iters( is ); - - 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 ) - { - const Multi_pass_iters< Istream_type > mp_iters( is ); - - add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value ); - } -} - -#endif +#ifndef JSON_SPIRIT_READER_TEMPLATE +#define JSON_SPIRIT_READER_TEMPLATE + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include + +#include "json5_parser_error_position.h" +#include "json5_parser_value.h" + +#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to + // boost.thread + +#include +#include +#include + +#if BOOST_VERSION >= 103800 +#include +#include +#include +#include +#include +#define spirit_namespace boost::spirit::classic +#else +#include +#include +#include +#include +#include +#define spirit_namespace boost::spirit +#endif + +namespace json5_parser { +const spirit_namespace::int_parser int64_p = + spirit_namespace::int_parser(); +const spirit_namespace::uint_parser uint64_p = + spirit_namespace::uint_parser(); + +template +bool is_eq(Iter_type first, Iter_type last, const char* c_str) { + for (Iter_type i = first; i != last; ++i, ++c_str) { + if (*c_str == 0) return false; + + if (*i != *c_str) return false; + } + + return true; +} + +template +Char_type hex_to_num(const Char_type c) { + if ((c >= '0') && (c <= '9')) return c - '0'; + if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10; + if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10; + return 0; +} + +template +Char_type hex_str_to_char(Iter_type& begin) { + const Char_type c1(*(++begin)); + const Char_type c2(*(++begin)); + + return (hex_to_num(c1) << 4) + hex_to_num(c2); +} + +template +Char_type unicode_str_to_char(Iter_type& begin) { + const Char_type c1(*(++begin)); + const Char_type c2(*(++begin)); + const Char_type c3(*(++begin)); + const Char_type c4(*(++begin)); + + return (hex_to_num(c1) << 12) + (hex_to_num(c2) << 8) + (hex_to_num(c3) << 4) + + hex_to_num(c4); +} + +template +void append_esc_char_and_incr_iter(String_type& s, + typename String_type::const_iterator& begin, + typename String_type::const_iterator end) { + typedef typename String_type::value_type Char_type; + + const Char_type c2(*begin); + + switch (c2) { + case 't': + s += '\t'; + break; + case 'b': + s += '\b'; + break; + case 'f': + s += '\f'; + break; + case 'n': + s += '\n'; + break; + case 'r': + s += '\r'; + break; + case '\\': + s += '\\'; + break; + case '/': + s += '/'; + break; + case '"': + s += '"'; + break; + case 'x': { + if (end - begin >= 3) // expecting "xHH..." + { + s += hex_str_to_char(begin); + } + break; + } + case 'u': { + if (end - begin >= 5) // expecting "uHHHH..." + { + s += unicode_str_to_char(begin); + } + break; + } + case '\n': + break; // skip escaped newlines + } +} + +template +String_type substitute_esc_chars(typename String_type::const_iterator begin, + typename String_type::const_iterator end) { + typedef typename String_type::const_iterator Iter_type; + + if (end - begin < 2) return String_type(begin, end); + + String_type result; + + result.reserve(end - begin); + + const Iter_type end_minus_1(end - 1); + + Iter_type substr_start = begin; + Iter_type i = begin; + + for (; i < end_minus_1; ++i) { + if (*i == '\\') { + result.append(substr_start, i); + + ++i; // skip the '\' + + append_esc_char_and_incr_iter(result, i, end); + + substr_start = i + 1; + } + } + + result.append(substr_start, end); + + return result; +} + +template +String_type get_str_(typename String_type::const_iterator begin, + typename String_type::const_iterator end) { + assert(end - begin >= 2); + + typedef typename String_type::const_iterator Iter_type; + + Iter_type str_without_quotes(++begin); + Iter_type end_without_quotes(--end); + + return substitute_esc_chars(str_without_quotes, end_without_quotes); +} + +inline std::string get_str(std::string::const_iterator begin, + std::string::const_iterator end) { + return get_str_(begin, end); +} + +inline std::wstring get_str(std::wstring::const_iterator begin, + std::wstring::const_iterator end) { + return get_str_(begin, end); +} + +template +String_type get_str(Iter_type begin, Iter_type end) { + const String_type tmp(begin, + end); // convert multipass iterators to string iterators + + return get_str(tmp.begin(), tmp.end()); +} + +// this class's methods get called by the spirit parse resulting +// in the creation of a JSON object or array +// +// NB Iter_type could be a std::string iterator, wstring iterator, a position iterator +// or a multipass iterator +// +template +class Semantic_actions { +public: + typedef typename Value_type::Config_type Config_type; + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename String_type::value_type Char_type; + + Semantic_actions(Value_type& value) : value_(value), current_p_(0) {} + + void begin_obj(Char_type c) { + assert(c == '{'); + + begin_compound(); + } + + void end_obj(Char_type c) { + assert(c == '}'); + + end_compound(); + } + + void begin_array(Char_type c) { + assert(c == '['); + + begin_compound(); + } + + void end_array(Char_type c) { + assert(c == ']'); + + end_compound(); + } + + void new_name(Iter_type begin, Iter_type end) { + assert(current_p_->type() == obj_type); + + name_ = get_str(begin, end); + } + + void new_identifier(Iter_type begin, Iter_type end) { + assert(current_p_->type() == obj_type); + + String_type result; + result.append(begin, end); + name_ = boost::algorithm::trim_right_copy(result); + } + + void new_str(Iter_type begin, Iter_type end) { + add_to_current(get_str(begin, end)); + } + + void new_true(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "true")); + + add_to_current(true); + } + + void new_false(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "false")); + + add_to_current(false); + } + + void new_null(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "null")); + + add_to_current(Value_type()); + } + + void new_int(boost::int64_t i) { add_to_current(i); } + + void new_uint64(boost::uint64_t ui) { add_to_current(ui); } + + void new_real(double d) { add_to_current(d); } + + void new_infinity(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "Infinity")); + + add_to_current(std::numeric_limits::infinity()); + } + + void new_minus_infinity(Iter_type begin, Iter_type end) { + assert(is_eq(begin, end, "-Infinity")); + + add_to_current(-std::numeric_limits::infinity()); + } + +private: + Semantic_actions& operator=(const Semantic_actions&); + // to prevent "assignment operator could not be generated" warning + + Value_type* add_first(const Value_type& value) { + assert(current_p_ == 0); + + value_ = value; + current_p_ = &value_; + return current_p_; + } + + template + void begin_compound() { + if (current_p_ == 0) { + add_first(Array_or_obj()); + } else { + stack_.push_back(current_p_); + + Array_or_obj new_array_or_obj; // avoid copy by building new array or + // object in place + + current_p_ = add_to_current(new_array_or_obj); + } + } + + void end_compound() { + if (current_p_ != &value_) { + current_p_ = stack_.back(); + + stack_.pop_back(); + } + } + + Value_type* add_to_current(const Value_type& value) { + if (current_p_ == 0) { + return add_first(value); + } else if (current_p_->type() == array_type) { + current_p_->get_array().push_back(value); + + return ¤t_p_->get_array().back(); + } + + assert(current_p_->type() == obj_type); + + return &Config_type::add(current_p_->get_obj(), name_, value); + } + + Value_type& value_; // this is the object or array that is being created + Value_type* current_p_; // the child object or array that is currently being + // constructed + + std::vector stack_; // previous child objects and arrays + + String_type name_; // of current name/value pair +}; + +template +void throw_error(spirit_namespace::position_iterator i, + const std::string& reason) { + throw Error_position(i.get_position().line, i.get_position().column, reason); +} + +template +void throw_error(Iter_type, const std::string& reason) { + throw reason; +} + +// the spirit grammar +// +template +class Json_grammar + : public spirit_namespace::grammar > { +public: + typedef Semantic_actions Semantic_actions_t; + + Json_grammar(Semantic_actions_t& semantic_actions) : actions_(semantic_actions) {} + + static void throw_not_value(Iter_type begin, Iter_type) { + throw_error(begin, "not a value"); + } + + static void throw_not_hex(Iter_type begin, Iter_type) { + throw_error(begin, "not a hexadecimal number"); + } + + static void throw_not_array(Iter_type begin, Iter_type) { + throw_error(begin, "not an array"); + } + + static void throw_not_object(Iter_type begin, Iter_type) { + throw_error(begin, "not an object"); + } + + static void throw_not_pair(Iter_type begin, Iter_type) { + throw_error(begin, "not a pair"); + } + + static void throw_not_colon(Iter_type begin, Iter_type) { + throw_error(begin, "no colon in pair"); + } + + static void throw_not_string(Iter_type begin, Iter_type) { + throw_error(begin, "not a string"); + } + + template + class definition { + public: + definition(const Json_grammar& self) { + using namespace spirit_namespace; + using namespace boost::placeholders; + + typedef typename Value_type::String_type::value_type Char_type; + + // first we convert the semantic action class methods to functors with the + // parameter signature expected by spirit + + typedef boost::function Char_action; + typedef boost::function Str_action; + typedef boost::function Real_action; + typedef boost::function Int_action; + typedef boost::function Uint64_action; + + Char_action begin_obj( + boost::bind(&Semantic_actions_t::begin_obj, &self.actions_, _1)); + Char_action end_obj( + boost::bind(&Semantic_actions_t::end_obj, &self.actions_, _1)); + Char_action begin_array( + boost::bind(&Semantic_actions_t::begin_array, &self.actions_, _1)); + Char_action end_array( + boost::bind(&Semantic_actions_t::end_array, &self.actions_, _1)); + Str_action new_name( + boost::bind(&Semantic_actions_t::new_name, &self.actions_, _1, _2)); + Str_action new_identifier(boost::bind(&Semantic_actions_t::new_identifier, + &self.actions_, _1, _2)); + Str_action new_str( + boost::bind(&Semantic_actions_t::new_str, &self.actions_, _1, _2)); + Str_action new_true( + boost::bind(&Semantic_actions_t::new_true, &self.actions_, _1, _2)); + Str_action new_false(boost::bind(&Semantic_actions_t::new_false, + &self.actions_, _1, _2)); + Str_action new_null( + boost::bind(&Semantic_actions_t::new_null, &self.actions_, _1, _2)); + Real_action new_real( + boost::bind(&Semantic_actions_t::new_real, &self.actions_, _1)); + Str_action new_infinity(boost::bind(&Semantic_actions_t::new_infinity, + &self.actions_, _1, _2)); + Str_action new_minus_infinity(boost::bind( + &Semantic_actions_t::new_minus_infinity, &self.actions_, _1, _2)); + Int_action new_int( + boost::bind(&Semantic_actions_t::new_int, &self.actions_, _1)); + Uint64_action new_uint64( + boost::bind(&Semantic_actions_t::new_uint64, &self.actions_, _1)); + + // actual grammar + + json_ = value_ | eps_p[&throw_not_value]; + + value_ = single_quoted_string_[new_str] | double_quoted_string_[new_str] | + number_ | object_ | array_ | str_p("true")[new_true] | + str_p("false")[new_false] | str_p("null")[new_null] | + (!ch_p('+') >> str_p("Infinity")[new_infinity]) | + str_p("-Infinity")[new_minus_infinity]; + + object_ = ch_p('{')[begin_obj] >> !members_ >> + (ch_p('}')[end_obj] | eps_p[&throw_not_object]); + + members_ = pair_ >> *(',' >> pair_) >> !ch_p(','); + + pair_ = (double_quoted_string_[new_name] | identifier_[new_identifier]) >> + (':' | eps_p[&throw_not_colon]) >> + (value_ | eps_p[&throw_not_value]); + + array_ = ch_p('[')[begin_array] >> !elements_ >> + (ch_p(']')[end_array] | eps_p[&throw_not_array]); + + elements_ = value_ >> *(',' >> value_) >> !ch_p(','); + + double_quoted_string_ = + lexeme_d // this causes white space and what would appear to be + // comments inside a string to be retained + [confix_p('"', *lex_escape_ch_p, '"')]; + + single_quoted_string_ = + lexeme_d // this causes white space and what would appear to be + // comments inside a string to be retained + [confix_p('\'', *lex_escape_ch_p, '\'')]; + + identifier_ = (alpha_p | ch_p('_') | ch_p('$')) >> + *(alnum_p | ch_p('_') | ch_p('$')); + + number_ = (str_p("0x") >> (hex_p[new_int] | eps_p[&throw_not_hex])) | + strict_real_p[new_real] | int64_p[new_int] | uint64_p[new_uint64]; + } + + spirit_namespace::rule json_, object_, members_, pair_, array_, + elements_, value_, single_quoted_string_, double_quoted_string_, + number_, identifier_; + + const spirit_namespace::rule& start() const { return json_; } + }; + +private: + Json_grammar& operator=(const Json_grammar&); // to prevent "assignment operator + // could not be generated" warning + + Semantic_actions_t& actions_; +}; + +template +void add_posn_iter_and_read_range_or_throw(Iter_type begin, Iter_type end, + Value_type& value) { + typedef spirit_namespace::position_iterator 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 +struct Multi_pass_iters { + typedef typename Istream_type::char_type Char_type; + typedef std::istream_iterator istream_iter; + typedef spirit_namespace::multi_pass 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 +Iter_type read_range_or_throw(Iter_type begin, Iter_type end, Value_type& value) { + Semantic_actions semantic_actions(value); + + const spirit_namespace::parse_info info = spirit_namespace::parse( + begin, end, Json_grammar(semantic_actions), + spirit_namespace::space_p | spirit_namespace::comment_p("//") | + spirit_namespace::comment_p("/*", "*/")); + + if (!info.hit) { + assert(false); // in theory exception should already have been thrown + throw_error(info.stop, "error"); + } + + return info.stop; +} + +// 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 +bool read_range(Iter_type& begin, Iter_type end, Value_type& value) { + try { + begin = read_range_or_throw(begin, end, value); + + return true; + } catch (...) { + return false; + } +} + +// reads a JSON Value from a string, e.g. +// +// const bool success = read_string( str, value ); +// +template +bool read_string(const String_type& s, Value_type& value) { + typename String_type::const_iterator begin = s.begin(); + + return read_range(begin, s.end(), value); +} + +// reads a JSON Value from a string throwing an exception on invalid input, e.g. +// +// read_string_or_throw( is, value ); +// +template +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 stream, e.g. +// +// const bool success = read_stream( is, value ); +// +template +bool read_stream(Istream_type& is, Value_type& value) { + Multi_pass_iters mp_iters(is); + + 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 +void read_stream_or_throw(Istream_type& is, Value_type& value) { + const Multi_pass_iters mp_iters(is); + + add_posn_iter_and_read_range_or_throw(mp_iters.begin_, mp_iters.end_, value); +} +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_stream_reader.h b/json5_parser/json5_parser_stream_reader.h index 39e71ec..d14022e 100644 --- a/json5_parser/json5_parser_stream_reader.h +++ b/json5_parser/json5_parser_stream_reader.h @@ -1,70 +1,56 @@ -#ifndef JSON_SPIRIT_READ_STREAM -#define JSON_SPIRIT_READ_STREAM - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_reader_template.h" - -namespace json5_parser -{ - // these classes allows you to read multiple top level contiguous values from a stream, - // the normal stream read functions have a bug that prevent multiple top level values - // from being read unless they are separated by spaces - - template< class Istream_type, class Value_type > - class Stream_reader - { - public: - - Stream_reader( Istream_type& is ) - : iters_( is ) - { - } - - bool read_next( Value_type& value ) - { - return read_range( iters_.begin_, iters_.end_, value ); - } - - private: - - typedef Multi_pass_iters< Istream_type > Mp_iters; - - Mp_iters iters_; - }; - - template< class Istream_type, class Value_type > - class Stream_reader_thrower - { - public: - - Stream_reader_thrower( Istream_type& is ) - : iters_( is ) - , posn_begin_( iters_.begin_, iters_.end_ ) - , posn_end_( iters_.end_, iters_.end_ ) - { - } - - void read_next( Value_type& value ) - { - posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value ); - } - - private: - - typedef Multi_pass_iters< Istream_type > Mp_iters; - typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t; - - Mp_iters iters_; - Posn_iter_t posn_begin_, posn_end_; - }; -} - -#endif +#ifndef JSON_SPIRIT_READ_STREAM +#define JSON_SPIRIT_READ_STREAM + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "json5_parser_reader_template.h" + +namespace json5_parser { +// these classes allows you to read multiple top level contiguous values from a stream, +// the normal stream read functions have a bug that prevent multiple top level values +// from being read unless they are separated by spaces + +template +class Stream_reader { +public: + Stream_reader(Istream_type& is) : iters_(is) {} + + bool read_next(Value_type& value) { + return read_range(iters_.begin_, iters_.end_, value); + } + +private: + typedef Multi_pass_iters Mp_iters; + + Mp_iters iters_; +}; + +template +class Stream_reader_thrower { +public: + Stream_reader_thrower(Istream_type& is) + : iters_(is), + posn_begin_(iters_.begin_, iters_.end_), + posn_end_(iters_.end_, iters_.end_) {} + + void read_next(Value_type& value) { + posn_begin_ = read_range_or_throw(posn_begin_, posn_end_, value); + } + +private: + typedef Multi_pass_iters Mp_iters; + typedef spirit_namespace::position_iterator Posn_iter_t; + + Mp_iters iters_; + Posn_iter_t posn_begin_, posn_end_; +}; +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_utils.h b/json5_parser/json5_parser_utils.h index f9b814a..331dd22 100644 --- a/json5_parser/json5_parser_utils.h +++ b/json5_parser/json5_parser_utils.h @@ -1,63 +1,56 @@ -#ifndef JSON_SPIRIT_UTILS -#define JSON_SPIRIT_UTILS - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include - -namespace json5_parser -{ - template< class Obj_t, class Map_t > - void obj_to_map( const Obj_t& obj, Map_t& mp_obj ) - { - mp_obj.clear(); - - for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) - { - mp_obj[ i->name_ ] = i->value_; - } - } - - template< class Obj_t, class Map_t > - void map_to_obj( const Map_t& mp_obj, Obj_t& obj ) - { - obj.clear(); - - for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i ) - { - obj.push_back( typename Obj_t::value_type( i->first, i->second ) ); - } - } - -#ifdef JSON_SPIRIT_VALUE_ENABLED - typedef std::map< std::string, Value > Mapped_obj; -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - typedef std::map< std::wstring, wValue > wMapped_obj; -#endif - - template< class Object_type, class String_type > - const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name ) - { - for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i ) - { - if( i->name_ == name ) - { - return i->value_; - } - } - - return Object_type::value_type::Value_type::null; - } -} - -#endif +#ifndef JSON_SPIRIT_UTILS +#define JSON_SPIRIT_UTILS + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include "json5_parser_value.h" + +namespace json5_parser { +template +void obj_to_map(const Obj_t& obj, Map_t& mp_obj) { + mp_obj.clear(); + + for (typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i) { + mp_obj[i->name_] = i->value_; + } +} + +template +void map_to_obj(const Map_t& mp_obj, Obj_t& obj) { + obj.clear(); + + for (typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i) { + obj.push_back(typename Obj_t::value_type(i->first, i->second)); + } +} + +#ifdef JSON_SPIRIT_VALUE_ENABLED +typedef std::map Mapped_obj; +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +typedef std::map wMapped_obj; +#endif + +template +const typename Object_type::value_type::Value_type& find_value( + const Object_type& obj, const String_type& name) { + for (typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i) { + if (i->name_ == name) { + return i->value_; + } + } + + return Object_type::value_type::Value_type::null; +} +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_value.cpp b/json5_parser/json5_parser_value.cpp index e36fb60..be67e15 100644 --- a/json5_parser/json5_parser_value.cpp +++ b/json5_parser/json5_parser_value.cpp @@ -1,6 +1,6 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_value.h" +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_value.h" diff --git a/json5_parser/json5_parser_value.h b/json5_parser/json5_parser_value.h index 0d0a83f..6181cea 100644 --- a/json5_parser/json5_parser_value.h +++ b/json5_parser/json5_parser_value.h @@ -1,605 +1,527 @@ -#ifndef JSON_SPIRIT_VALUE -#define JSON_SPIRIT_VALUE - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// 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 json5_parser -{ - enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; - - static inline 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 - { - public: - - typedef Config Config_type; - typedef typename Config::String_type String_type; - typedef typename Config::Object_type Object; - typedef typename Config::Array_type Array; - typedef typename String_type::const_pointer Const_str_ptr; // eg const char* - - Value_impl(); // creates null value - Value_impl( Const_str_ptr value ); - Value_impl( const String_type& value ); - Value_impl( const Object& value ); - Value_impl( const Array& value ); - Value_impl( bool value ); - Value_impl( int value ); - Value_impl( boost::int64_t value ); - 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; - - Value_impl& operator=( const Value_impl& lhs ); - - Value_type type() const; - - bool is_uint64() const; - bool is_null() const; - - const String_type& get_str() const; - const Object& get_obj() const; - const Array& get_array() const; - bool get_bool() const; - int get_int() const; - boost::int64_t get_int64() const; - boost::uint64_t get_uint64() const; - double get_real() const; - - Object& get_obj(); - Array& get_array(); - - template< typename T > T get_value() const; // example usage: int i = value.get_value< int >(); - // or double d = value.get_value< double >(); - - static const Value_impl null; - - private: - - void check_type( const Value_type vtype ) const; - - typedef boost::variant< boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, - String_type, bool, boost::int64_t, double, Null, boost::uint64_t > Variant; - - Variant v_; - - 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 - Variant operator()( const T& t ) const - { - return t; - } - }; - }; - - // vector objects - - template< class Config > - struct Pair_impl - { - 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; - - String_type name_; - Value_type value_; - }; - -#if defined( JSON_SPIRIT_VALUE_ENABLED ) || defined( JSON_SPIRIT_WVALUE_ENABLED ) - template< class String > - struct Config_vector - { - typedef String String_type; - typedef Value_impl< Config_vector > Value_type; - typedef Pair_impl < Config_vector > Pair_type; - typedef std::vector< Value_type > Array_type; - typedef std::vector< Pair_type > Object_type; - - static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) - { - obj.push_back( Pair_type( name , value ) ); - - return obj.back().value_; - } - - static const String_type& get_name( const Pair_type& pair ) - { - return pair.name_; - } - - 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 - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - typedef Config_vector< std::wstring > wConfig; - - typedef wConfig::Value_type wValue; - typedef wConfig::Pair_type wPair; - typedef wConfig::Object_type wObject; - typedef wConfig::Array_type wArray; -#endif - - // map objects - -#if defined( JSON_SPIRIT_MVALUE_ENABLED ) || defined( JSON_SPIRIT_WMVALUE_ENABLED ) - template< class String > - struct Config_map - { - typedef String String_type; - typedef Value_impl< Config_map > Value_type; - typedef std::vector< Value_type > Array_type; - typedef std::map< String_type, Value_type > Object_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 const String_type& get_name( const Pair_type& pair ) - { - return pair.first; - } - - 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 - -#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() - : v_( Null() ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Const_str_ptr value ) - : v_( String_type( value ) ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const String_type& value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Object& value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Array& value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( bool value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( int value ) - : v_( static_cast< boost::int64_t >( value ) ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( boost::int64_t value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( boost::uint64_t value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( double value ) - : v_( value ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) - : 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) ) - { - } - - template< class Config > - Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs ) - { - Value_impl tmp( lhs ); - - std::swap( v_, tmp.v_ ); - - return *this; - } - - template< class Config > - bool Value_impl< Config >::operator==( const Value_impl& lhs ) const - { - if( this == &lhs ) return true; - - if( type() != lhs.type() ) return false; - - return v_ == lhs.v_; - } - - template< class Config > - Value_type Value_impl< Config >::type() const - { - if( is_uint64() ) - { - return int_type; - } - - return static_cast< Value_type >( v_.which() ); - } - - template< class Config > - bool Value_impl< Config >::is_uint64() const - { - return v_.which() == null_type + 1; - } - - template< class Config > - bool Value_impl< Config >::is_null() const - { - return type() == null_type; - } - - template< class Config > - void Value_impl< Config >::check_type( const Value_type vtype ) const - { - if( type() != vtype ) - { - std::ostringstream os; - - os << "get_value< " << value_type_to_string( vtype ) << " > called on " << value_type_to_string( type() ) << " Value"; - - throw std::runtime_error( os.str() ); - } - } - - template< class Config > - const typename Config::String_type& Value_impl< Config >::get_str() const - { - check_type( str_type ); - - return *boost::get< String_type >( &v_ ); - } - - template< class Config > - const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const - { - check_type( obj_type ); - - return *boost::get< Object >( &v_ ); - } - - template< class Config > - const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const - { - check_type( array_type ); - - return *boost::get< Array >( &v_ ); - } - - template< class Config > - bool Value_impl< Config >::get_bool() const - { - check_type( bool_type ); - - return boost::get< bool >( v_ ); - } - - template< class Config > - int Value_impl< Config >::get_int() const - { - check_type( int_type ); - - return static_cast< int >( get_int64() ); - } - - template< class Config > - boost::int64_t Value_impl< Config >::get_int64() const - { - check_type( int_type ); - - if( is_uint64() ) - { - return static_cast< boost::int64_t >( get_uint64() ); - } - - return boost::get< boost::int64_t >( v_ ); - } - - template< class Config > - boost::uint64_t Value_impl< Config >::get_uint64() const - { - check_type( int_type ); - - if( !is_uint64() ) - { - return static_cast< boost::uint64_t >( get_int64() ); - } - - return boost::get< boost::uint64_t >( v_ ); - } - - template< class Config > - double Value_impl< Config >::get_real() const - { - if( type() == int_type ) - { - return is_uint64() ? static_cast< double >( get_uint64() ) - : static_cast< double >( get_int64() ); - } - - check_type( real_type ); - - return boost::get< double >( v_ ); - } - - template< class Config > - typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() - { - check_type( obj_type ); - - return *boost::get< Object >( &v_ ); - } - - template< class Config > - typename Value_impl< Config >::Array& Value_impl< Config >::get_array() - { - check_type( array_type ); - - return *boost::get< Array >( &v_ ); - } - - template< class Config > - Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value ) - : name_( name ) - , value_( value ) - { - } - - template< class Config > - bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const - { - if( this == &lhs ) return true; - - return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ ); - } - - // converts a C string, ie. 8 bit char array, to a string object - // - template < class String_type > - String_type to_str( const char* c_str ) - { - String_type result; - - for( const char* p = c_str; *p != 0; ++p ) - { - result += *p; - } - - return result; - } - - // - - namespace internal_ - { - template< typename T > - struct Type_to_type - { - }; - - template< class Value > - int get_value( const Value& value, Type_to_type< int > ) - { - return value.get_int(); - } - - template< class Value > - boost::int64_t get_value( const Value& value, Type_to_type< boost::int64_t > ) - { - return value.get_int64(); - } - - template< class Value > - boost::uint64_t get_value( const Value& value, Type_to_type< boost::uint64_t > ) - { - return value.get_uint64(); - } - - template< class Value > - double get_value( const Value& value, Type_to_type< double > ) - { - return value.get_real(); - } - - template< class Value > - typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > ) - { - return value.get_str(); - } - - template< class Value > - typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > ) - { - return value.get_array(); - } - - template< class Value > - typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > ) - { - return value.get_obj(); - } - - template< class Value > - bool get_value( const Value& value, Type_to_type< bool > ) - { - return value.get_bool(); - } - } - - template< class Config > - template< typename T > - T Value_impl< Config >::get_value() const - { - 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 +#ifndef JSON_SPIRIT_VALUE +#define JSON_SPIRIT_VALUE + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include +#include +#include +//#include + +#include +#include +#include +#include +#include +#include + +//using namespace boost::placeholders; + +// 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 json5_parser { +enum Value_type { + obj_type, + array_type, + str_type, + bool_type, + int_type, + real_type, + null_type +}; + +static inline std::string value_type_to_string(Value_type vtype); + +struct Null {}; + +template // Config determines whether the value uses std::string or + // std::wstring and whether JSON Objects are represented as + // vectors or maps +class Value_impl { +public: + typedef Config Config_type; + typedef typename Config::String_type String_type; + typedef typename Config::Object_type Object; + typedef typename Config::Array_type Array; + typedef typename String_type::const_pointer Const_str_ptr; // eg const char* + + Value_impl(); // creates null value + Value_impl(Const_str_ptr value); + Value_impl(const String_type& value); + Value_impl(const Object& value); + Value_impl(const Array& value); + Value_impl(bool value); + Value_impl(int value); + Value_impl(boost::int64_t value); + Value_impl(boost::uint64_t value); + Value_impl(double value); + + template + Value_impl( + Iter first, + Iter last); // constructor from containers, e.g. std::vector or std::list + + template + Value_impl(const boost::variant& + variant); // constructor for compatible variant types + + Value_impl(const Value_impl& other); + + bool operator==(const Value_impl& lhs) const; + + Value_impl& operator=(const Value_impl& lhs); + + Value_type type() const; + + bool is_uint64() const; + bool is_null() const; + + const String_type& get_str() const; + const Object& get_obj() const; + const Array& get_array() const; + bool get_bool() const; + int get_int() const; + boost::int64_t get_int64() const; + boost::uint64_t get_uint64() const; + double get_real() const; + + Object& get_obj(); + Array& get_array(); + + template + T get_value() const; // example usage: int i = value.get_value< int >(); + // or double d = value.get_value< double >(); + + static const Value_impl null; + +private: + void check_type(const Value_type vtype) const; + + typedef boost::variant, + boost::recursive_wrapper, String_type, bool, + boost::int64_t, double, Null, boost::uint64_t> + Variant; + + Variant v_; + + class Variant_converter_visitor : public boost::static_visitor { + public: + template class Cont> + Variant operator()(const Cont& cont) const { + return Array(cont.begin(), cont.end()); + } + + Variant operator()(int i) const { return static_cast(i); } + + template + Variant operator()(const T& t) const { + return t; + } + }; +}; + +// vector objects + +template +struct Pair_impl { + 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; + + String_type name_; + Value_type value_; +}; + +#if defined(JSON_SPIRIT_VALUE_ENABLED) || defined(JSON_SPIRIT_WVALUE_ENABLED) +template +struct Config_vector { + typedef String String_type; + typedef Value_impl Value_type; + typedef Pair_impl Pair_type; + typedef std::vector Array_type; + typedef std::vector Object_type; + + static Value_type& add(Object_type& obj, const String_type& name, + const Value_type& value) { + obj.push_back(Pair_type(name, value)); + + return obj.back().value_; + } + + static const String_type& get_name(const Pair_type& pair) { return pair.name_; } + + 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 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 + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +typedef Config_vector wConfig; + +typedef wConfig::Value_type wValue; +typedef wConfig::Pair_type wPair; +typedef wConfig::Object_type wObject; +typedef wConfig::Array_type wArray; +#endif + +// map objects + +#if defined(JSON_SPIRIT_MVALUE_ENABLED) || defined(JSON_SPIRIT_WMVALUE_ENABLED) +template +struct Config_map { + typedef String String_type; + typedef Value_impl Value_type; + typedef std::vector Array_type; + typedef std::map Object_type; + typedef std::pair Pair_type; + + static Value_type& add(Object_type& obj, const String_type& name, + const Value_type& value) { + return obj[name] = value; + } + + static const String_type& get_name(const Pair_type& pair) { return pair.first; } + + 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 mConfig; + +typedef mConfig::Value_type mValue; +typedef mConfig::Object_type mObject; +typedef mConfig::Array_type mArray; +#endif + +// typedefs for Unicode + +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +typedef Config_map 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 +const Value_impl Value_impl::null; + +template +Value_impl::Value_impl() : v_(Null()) {} + +template +Value_impl::Value_impl(const Const_str_ptr value) : v_(String_type(value)) {} + +template +Value_impl::Value_impl(const String_type& value) : v_(value) {} + +template +Value_impl::Value_impl(const Object& value) : v_(value) {} + +template +Value_impl::Value_impl(const Array& value) : v_(value) {} + +template +Value_impl::Value_impl(bool value) : v_(value) {} + +template +Value_impl::Value_impl(int value) : v_(static_cast(value)) {} + +template +Value_impl::Value_impl(boost::int64_t value) : v_(value) {} + +template +Value_impl::Value_impl(boost::uint64_t value) : v_(value) {} + +template +Value_impl::Value_impl(double value) : v_(value) {} + +template +Value_impl::Value_impl(const Value_impl& other) : v_(other.v_) {} + +template +template +Value_impl::Value_impl(Iter first, Iter last) : v_(Array(first, last)) {} + +template +template +Value_impl::Value_impl( + const boost::variant& variant) + : v_(boost::apply_visitor(Variant_converter_visitor(), variant)) {} + +template +Value_impl& Value_impl::operator=(const Value_impl& lhs) { + Value_impl tmp(lhs); + + std::swap(v_, tmp.v_); + + return *this; +} + +template +bool Value_impl::operator==(const Value_impl& lhs) const { + if (this == &lhs) return true; + + if (type() != lhs.type()) return false; + + return v_ == lhs.v_; +} + +template +Value_type Value_impl::type() const { + if (is_uint64()) { + return int_type; + } + + return static_cast(v_.which()); +} + +template +bool Value_impl::is_uint64() const { + return v_.which() == null_type + 1; +} + +template +bool Value_impl::is_null() const { + return type() == null_type; +} + +template +void Value_impl::check_type(const Value_type vtype) const { + if (type() != vtype) { + std::ostringstream os; + + os << "get_value< " << value_type_to_string(vtype) << " > called on " + << value_type_to_string(type()) << " Value"; + + throw std::runtime_error(os.str()); + } +} + +template +const typename Config::String_type& Value_impl::get_str() const { + check_type(str_type); + + return *boost::get(&v_); +} + +template +const typename Value_impl::Object& Value_impl::get_obj() const { + check_type(obj_type); + + return *boost::get(&v_); +} + +template +const typename Value_impl::Array& Value_impl::get_array() const { + check_type(array_type); + + return *boost::get(&v_); +} + +template +bool Value_impl::get_bool() const { + check_type(bool_type); + + return boost::get(v_); +} + +template +int Value_impl::get_int() const { + check_type(int_type); + + return static_cast(get_int64()); +} + +template +boost::int64_t Value_impl::get_int64() const { + check_type(int_type); + + if (is_uint64()) { + return static_cast(get_uint64()); + } + + return boost::get(v_); +} + +template +boost::uint64_t Value_impl::get_uint64() const { + check_type(int_type); + + if (!is_uint64()) { + return static_cast(get_int64()); + } + + return boost::get(v_); +} + +template +double Value_impl::get_real() const { + if (type() == int_type) { + return is_uint64() ? static_cast(get_uint64()) + : static_cast(get_int64()); + } + + check_type(real_type); + + return boost::get(v_); +} + +template +typename Value_impl::Object& Value_impl::get_obj() { + check_type(obj_type); + + return *boost::get(&v_); +} + +template +typename Value_impl::Array& Value_impl::get_array() { + check_type(array_type); + + return *boost::get(&v_); +} + +template +Pair_impl::Pair_impl(const String_type& name, const Value_type& value) + : name_(name), value_(value) {} + +template +bool Pair_impl::operator==(const Pair_impl& lhs) const { + if (this == &lhs) return true; + + return (name_ == lhs.name_) && (value_ == lhs.value_); +} + +// converts a C string, ie. 8 bit char array, to a string object +// +template +String_type to_str(const char* c_str) { + String_type result; + + for (const char* p = c_str; *p != 0; ++p) { + result += *p; + } + + return result; +} + +// + +namespace internal_ { +template +struct Type_to_type {}; + +template +int get_value(const Value& value, Type_to_type) { + return value.get_int(); +} + +template +boost::int64_t get_value(const Value& value, Type_to_type) { + return value.get_int64(); +} + +template +boost::uint64_t get_value(const Value& value, Type_to_type) { + return value.get_uint64(); +} + +template +double get_value(const Value& value, Type_to_type) { + return value.get_real(); +} + +template +typename Value::String_type get_value(const Value& value, + Type_to_type) { + return value.get_str(); +} + +template +typename Value::Array get_value(const Value& value, + Type_to_type) { + return value.get_array(); +} + +template +typename Value::Object get_value(const Value& value, + Type_to_type) { + return value.get_obj(); +} + +template +bool get_value(const Value& value, Type_to_type) { + return value.get_bool(); +} +} // namespace internal_ + +template +template +T Value_impl::get_value() const { + return internal_::get_value(*this, internal_::Type_to_type()); +} + +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"; +} +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_writer.cpp b/json5_parser/json5_parser_writer.cpp index 9345986..88d2061 100644 --- a/json5_parser/json5_parser_writer.cpp +++ b/json5_parser/json5_parser_writer.cpp @@ -1,96 +1,96 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_writer.h" -#include "json5_parser_writer_template.h" - -using namespace json5_parser; - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void json5_parser::write( const Value& value, std::ostream& os, int options, unsigned int precision_of_doubles ) - { - write_stream( value, os, options, precision_of_doubles ); - } - std::string json5_parser::write( const Value& value, int options, unsigned int precision_of_doubles ) - { - return write_string( value, options, precision_of_doubles ); - } - - void json5_parser::write_formatted( const Value& value, std::ostream& os, unsigned int precision_of_doubles ) - { - write_stream( value, os, pretty_print, precision_of_doubles ); - } - - std::string json5_parser::write_formatted( const Value& value, unsigned int precision_of_doubles ) - { - return write_string( value, pretty_print, precision_of_doubles ); - } -#endif - -#ifdef JSON_SPIRIT_MVALUE_ENABLED - void json5_parser::write( const mValue& value, std::ostream& os, int options, unsigned int precision_of_doubles ) - { - write_stream( value, os, options, precision_of_doubles ); - } - - std::string json5_parser::write( const mValue& value, int options, unsigned int precision_of_doubles ) - { - return write_string( value, options, precision_of_doubles ); - } - - void json5_parser::write_formatted( const mValue& value, std::ostream& os, unsigned int precision_of_doubles ) - { - write_stream( value, os, pretty_print, precision_of_doubles ); - } - - std::string json5_parser::write_formatted( const mValue& value, unsigned int precision_of_doubles ) - { - return write_string( value, pretty_print, precision_of_doubles ); - } -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void json5_parser::write( const wValue& value, std::wostream& os, int options, unsigned int precision_of_doubles ) - { - write_stream( value, os, options, precision_of_doubles ); - } - - std::wstring json5_parser::write( const wValue& value, int options, unsigned int precision_of_doubles ) - { - return write_string( value, options, precision_of_doubles ); - } - - void json5_parser::write_formatted( const wValue& value, std::wostream& os, unsigned int precision_of_doubles ) - { - write_stream( value, os, pretty_print, precision_of_doubles ); - } - - std::wstring json5_parser::write_formatted( const wValue& value, unsigned int precision_of_doubles ) - { - return write_string( value, pretty_print, precision_of_doubles ); - } -#endif - -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void json5_parser::write_formatted( const wmValue& value, std::wostream& os, unsigned int precision_of_doubles ) - { - write_stream( value, os, pretty_print, precision_of_doubles ); - } - - std::wstring json5_parser::write_formatted( const wmValue& value, unsigned int precision_of_doubles ) - { - return write_string( value, pretty_print, precision_of_doubles ); - } - - void json5_parser::write( const wmValue& value, std::wostream& os, int options, unsigned int precision_of_doubles ) - { - write_stream( value, os, options, precision_of_doubles ); - } - - std::wstring json5_parser::write( const wmValue& value, int options, unsigned int precision_of_doubles ) - { - return write_string( value, options, precision_of_doubles ); - } -#endif +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_writer.h" +#include "json5_parser_writer_template.h" + +using namespace json5_parser; + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void json5_parser::write(const Value& value, std::ostream& os, int options, + unsigned int precision_of_doubles) { + write_stream(value, os, options, precision_of_doubles); +} +std::string json5_parser::write(const Value& value, int options, + unsigned int precision_of_doubles) { + return write_string(value, options, precision_of_doubles); +} + +void json5_parser::write_formatted(const Value& value, std::ostream& os, + unsigned int precision_of_doubles) { + write_stream(value, os, pretty_print, precision_of_doubles); +} + +std::string json5_parser::write_formatted(const Value& value, + unsigned int precision_of_doubles) { + return write_string(value, pretty_print, precision_of_doubles); +} +#endif + +#ifdef JSON_SPIRIT_MVALUE_ENABLED +void json5_parser::write(const mValue& value, std::ostream& os, int options, + unsigned int precision_of_doubles) { + write_stream(value, os, options, precision_of_doubles); +} + +std::string json5_parser::write(const mValue& value, int options, + unsigned int precision_of_doubles) { + return write_string(value, options, precision_of_doubles); +} + +void json5_parser::write_formatted(const mValue& value, std::ostream& os, + unsigned int precision_of_doubles) { + write_stream(value, os, pretty_print, precision_of_doubles); +} + +std::string json5_parser::write_formatted(const mValue& value, + unsigned int precision_of_doubles) { + return write_string(value, pretty_print, precision_of_doubles); +} +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void json5_parser::write(const wValue& value, std::wostream& os, int options, + unsigned int precision_of_doubles) { + write_stream(value, os, options, precision_of_doubles); +} + +std::wstring json5_parser::write(const wValue& value, int options, + unsigned int precision_of_doubles) { + return write_string(value, options, precision_of_doubles); +} + +void json5_parser::write_formatted(const wValue& value, std::wostream& os, + unsigned int precision_of_doubles) { + write_stream(value, os, pretty_print, precision_of_doubles); +} + +std::wstring json5_parser::write_formatted(const wValue& value, + unsigned int precision_of_doubles) { + return write_string(value, pretty_print, precision_of_doubles); +} +#endif + +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void json5_parser::write_formatted(const wmValue& value, std::wostream& os, + unsigned int precision_of_doubles) { + write_stream(value, os, pretty_print, precision_of_doubles); +} + +std::wstring json5_parser::write_formatted(const wmValue& value, + unsigned int precision_of_doubles) { + return write_string(value, pretty_print, precision_of_doubles); +} + +void json5_parser::write(const wmValue& value, std::wostream& os, int options, + unsigned int precision_of_doubles) { + write_stream(value, os, options, precision_of_doubles); +} + +std::wstring json5_parser::write(const wmValue& value, int options, + unsigned int precision_of_doubles) { + return write_string(value, options, precision_of_doubles); +} +#endif diff --git a/json5_parser/json5_parser_writer.h b/json5_parser/json5_parser_writer.h index 48874b8..8850067 100644 --- a/json5_parser/json5_parser_writer.h +++ b/json5_parser/json5_parser_writer.h @@ -1,65 +1,78 @@ -#ifndef JSON_SPIRIT_WRITER -#define JSON_SPIRIT_WRITER - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_writer_options.h" -#include - -namespace json5_parser -{ - // these functions to convert JSON Values to text - // note the precision used outputing doubles defaults to 17, - // unless the remove_trailing_zeros option is given in which case the default is 16 - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void write( const Value& value, std::ostream& os, int options = none, unsigned int precision_of_doubles = 0 ); - std::string write( const Value& value, int options = none, unsigned int precision_of_doubles = 0 ); -#endif - -#ifdef JSON_SPIRIT_MVALUE_ENABLED - void write( const mValue& value, std::ostream& os, int options = none, unsigned int precision_of_doubles = 0 ); - std::string write( const mValue& value, int options = none, unsigned int precision_of_doubles = 0 ); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write( const wValue& value, std::wostream& os, int options = none, unsigned int precision_of_doubles = 0 ); - std::wstring write( const wValue& value, int options = none, unsigned int precision_of_doubles = 0 ); -#endif - -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write( const wmValue& value, std::wostream& os, int options = none, unsigned int precision_of_doubles = 0 ); - std::wstring write( const wmValue& value, int options = none, unsigned int precision_of_doubles = 0 ); -#endif - - // 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, unsigned int precision_of_doubles = 0 ); - std::string write_formatted( const Value& value, unsigned int precision_of_doubles = 0 ); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - void write_formatted( const mValue& value, std::ostream& os, unsigned int precision_of_doubles = 0 ); - std::string write_formatted( const mValue& value, unsigned int precision_of_doubles = 0 ); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write_formatted( const wValue& value, std::wostream& os, unsigned int precision_of_doubles = 0 ); - std::wstring write_formatted( const wValue& value, unsigned int precision_of_doubles = 0 ); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write_formatted( const wmValue& value, std::wostream& os, unsigned int precision_of_doubles = 0 ); - std::wstring write_formatted( const wmValue& value, unsigned int precision_of_doubles = 0 ); -#endif -} - -#endif +#ifndef JSON_SPIRIT_WRITER +#define JSON_SPIRIT_WRITER + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include "json5_parser_value.h" +#include "json5_parser_writer_options.h" + +namespace json5_parser { +// these functions to convert JSON Values to text +// note the precision used outputing doubles defaults to 17, +// unless the remove_trailing_zeros option is given in which case the default is 16 + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void write(const Value& value, std::ostream& os, int options = none, + unsigned int precision_of_doubles = 0); +std::string write(const Value& value, int options = none, + unsigned int precision_of_doubles = 0); +#endif + +#ifdef JSON_SPIRIT_MVALUE_ENABLED +void write(const mValue& value, std::ostream& os, int options = none, + unsigned int precision_of_doubles = 0); +std::string write(const mValue& value, int options = none, + unsigned int precision_of_doubles = 0); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void write(const wValue& value, std::wostream& os, int options = none, + unsigned int precision_of_doubles = 0); +std::wstring write(const wValue& value, int options = none, + unsigned int precision_of_doubles = 0); +#endif + +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void write(const wmValue& value, std::wostream& os, int options = none, + unsigned int precision_of_doubles = 0); +std::wstring write(const wmValue& value, int options = none, + unsigned int precision_of_doubles = 0); +#endif + +// 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, + unsigned int precision_of_doubles = 0); +std::string write_formatted(const Value& value, unsigned int precision_of_doubles = 0); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED +void write_formatted(const mValue& value, std::ostream& os, + unsigned int precision_of_doubles = 0); +std::string write_formatted(const mValue& value, unsigned int precision_of_doubles = 0); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void write_formatted(const wValue& value, std::wostream& os, + unsigned int precision_of_doubles = 0); +std::wstring write_formatted(const wValue& value, + unsigned int precision_of_doubles = 0); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void write_formatted(const wmValue& value, std::wostream& os, + unsigned int precision_of_doubles = 0); +std::wstring write_formatted(const wmValue& value, + unsigned int precision_of_doubles = 0); +#endif +} // namespace json5_parser + +#endif diff --git a/json5_parser/json5_parser_writer_options.h b/json5_parser/json5_parser_writer_options.h index 374db46..f858ae2 100644 --- a/json5_parser/json5_parser_writer_options.h +++ b/json5_parser/json5_parser_writer_options.h @@ -1,35 +1,36 @@ -#ifndef JSON_SPIRIT_WRITER_OPTIONS -#define JSON_SPIRIT_WRITER_OPTIONS - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - enum Output_options{ none = 0, // default 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, - // no longer used kept for backwards compatibility - 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 +#ifndef JSON_SPIRIT_WRITER_OPTIONS +#define JSON_SPIRIT_WRITER_OPTIONS + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +enum Output_options { + none = 0, // default 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, + // no longer used kept for backwards compatibility + 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/json5_parser/json5_parser_writer_template.h b/json5_parser/json5_parser_writer_template.h index b9ab62e..23aada9 100644 --- a/json5_parser/json5_parser_writer_template.h +++ b/json5_parser/json5_parser_writer_template.h @@ -1,325 +1,315 @@ -#ifndef JSON_SPIRIT_WRITER_TEMPLATE -#define JSON_SPIRIT_WRITER_TEMPLATE - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json5_parser_value.h" -#include "json5_parser_writer_options.h" - -#include -#include -#include -#include - -namespace json5_parser -{ - inline char to_hex_char( unsigned int c ) - { - assert( c <= 0xF ); - - const char ch = static_cast< char >( c ); - - if( ch < 10 ) return '0' + ch; - - return 'A' - 10 + ch; - } - - template< class String_type > - String_type non_printable_to_string( unsigned int c ) - { - String_type result( 6, '\\' ); - - result[1] = 'u'; - - result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 2 ] = to_hex_char( c & 0x000F ); - - return result; - } - - template< typename Char_type, class String_type > - bool add_esc_char( Char_type c, String_type& s ) - { - switch( c ) - { - case '"': s += to_str< String_type >( "\\\"" ); return true; - case '\\': s += to_str< String_type >( "\\\\" ); return true; - case '\b': s += to_str< String_type >( "\\b" ); return true; - case '\f': s += to_str< String_type >( "\\f" ); return true; - case '\n': s += to_str< String_type >( "\\n" ); return true; - case '\r': s += to_str< String_type >( "\\r" ); return true; - case '\t': s += to_str< String_type >( "\\t" ); return true; - } - - return false; - } - - template< class String_type > - 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; - - String_type result; - - const Iter_type end( s.end() ); - - for( Iter_type i = s.begin(); i != end; ++i ) - { - const Char_type c( *i ); - - if( add_esc_char( c, result ) ) continue; - - if( raw_utf8 ) - { - result += c; - } - else - { - 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; - } - - // this class generates the JSON text, - // it keeps track of the indentation level etc. - // - template< class Value_type, class Ostream_type > - class Generator - { - typedef typename Value_type::Config_type Config_type; - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename String_type::value_type Char_type; - typedef typename Object_type::value_type Obj_member_type; - - public: - - Generator( const Value_type& value, Ostream_type& os, int options, unsigned int precision_of_doubles ) - : os_( os ) - , indentation_level_( 0 ) - , pretty_( ( options & pretty_print ) != 0 || ( options & single_line_arrays ) != 0 ) - , raw_utf8_( ( options & raw_utf8 ) != 0 ) - , esc_nonascii_( ( options & always_escape_nonascii ) != 0 ) - , single_line_arrays_( ( options & single_line_arrays ) != 0 ) - , ios_saver_( os ) - { - if( precision_of_doubles > 0 ) - { - precision_of_doubles_ = precision_of_doubles; - } - else - { - precision_of_doubles_ = ( options & remove_trailing_zeros ) != 0 ? 16 : 17; - } - - output( value ); - } - - private: - - void output( const Value_type& value ) - { - switch( value.type() ) - { - case obj_type: output( value.get_obj() ); break; - 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; - case null_type: os_ << "null"; break; - default: assert( false ); - } - } - - void output( const Object_type& obj ) - { - output_array_or_obj( obj, '{', '}' ); - } - - void output( const Obj_member_type& member ) - { - output( Config_type::get_name( member ) ); space(); - os_ << ':'; space(); - output( Config_type::get_value( member ) ); - } - - void output_int( const Value_type& value ) - { - if( value.is_uint64() ) - { - os_ << value.get_uint64(); - } - else - { - os_ << value.get_int64(); - } - } - - void output( const String_type& s ) - { - os_ << '"' << add_esc_chars( s, raw_utf8_, esc_nonascii_ ) << '"'; - } - - void output( bool b ) - { - os_ << to_str< String_type >( b ? "true" : "false" ); - } - - void output( double d ) - { - os_ << std::setprecision( precision_of_doubles_ ) << d; - } - - 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 ) - { - os_ << start_char; new_line(); - - ++indentation_level_; - - for( typename T::const_iterator i = t.begin(); i != t.end(); ++i ) - { - indent(); - - output_composite_item( i, t.end() ); - - new_line(); - } - - --indentation_level_; - - indent(); os_ << end_char; - } - - void indent() - { - if( !pretty_ ) return; - - for( int i = 0; i < indentation_level_; ++i ) - { - os_ << " "; - } - } - - void space() - { - if( pretty_ ) os_ << ' '; - } - - void new_line() - { - if( pretty_ ) os_ << '\n'; - } - - Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning - - Ostream_type& os_; - int indentation_level_; - bool pretty_; - bool raw_utf8_; - bool esc_nonascii_; - bool single_line_arrays_; - int precision_of_doubles_; - 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, int options = none, unsigned int precision_of_doubles = 0 ) - { - os << std::dec; - Generator< Value_type, Ostream_type >( value, os, options, precision_of_doubles ); - } - - // 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, int options = none, unsigned int precision_of_doubles = 0 ) - { - typedef typename Value_type::String_type::value_type Char_type; - - std::basic_ostringstream< Char_type > os; - - write_stream( value, os, options, precision_of_doubles ); - - return os.str(); - } -} - -#endif +#ifndef JSON_SPIRIT_WRITER_TEMPLATE +#define JSON_SPIRIT_WRITER_TEMPLATE + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include "json5_parser_value.h" +#include "json5_parser_writer_options.h" + +#include +#include +#include +#include + +namespace json5_parser { +inline char to_hex_char(unsigned int c) { + assert(c <= 0xF); + + const char ch = static_cast(c); + + if (ch < 10) return '0' + ch; + + return 'A' - 10 + ch; +} + +template +String_type non_printable_to_string(unsigned int c) { + String_type result(6, '\\'); + + result[1] = 'u'; + + result[5] = to_hex_char(c & 0x000F); + c >>= 4; + result[4] = to_hex_char(c & 0x000F); + c >>= 4; + result[3] = to_hex_char(c & 0x000F); + c >>= 4; + result[2] = to_hex_char(c & 0x000F); + + return result; +} + +template +bool add_esc_char(Char_type c, String_type& s) { + switch (c) { + case '"': + s += to_str("\\\""); + return true; + case '\\': + s += to_str("\\\\"); + return true; + case '\b': + s += to_str("\\b"); + return true; + case '\f': + s += to_str("\\f"); + return true; + case '\n': + s += to_str("\\n"); + return true; + case '\r': + s += to_str("\\r"); + return true; + case '\t': + s += to_str("\\t"); + return true; + } + + return false; +} + +template +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; + + String_type result; + + const Iter_type end(s.end()); + + for (Iter_type i = s.begin(); i != end; ++i) { + const Char_type c(*i); + + if (add_esc_char(c, result)) continue; + + if (raw_utf8) { + result += c; + } else { + const wint_t unsigned_c((c >= 0) ? c : 256 + c); + + if (!esc_nonascii && iswprint(unsigned_c)) { + result += c; + } else { + result += non_printable_to_string(unsigned_c); + } + } + } + + return result; +} + +// this class generates the JSON text, +// it keeps track of the indentation level etc. +// +template +class Generator { + typedef typename Value_type::Config_type Config_type; + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename String_type::value_type Char_type; + typedef typename Object_type::value_type Obj_member_type; + +public: + Generator(const Value_type& value, Ostream_type& os, int options, + unsigned int precision_of_doubles) + : os_(os), + indentation_level_(0), + pretty_((options & pretty_print) != 0 || + (options & single_line_arrays) != 0), + raw_utf8_((options & raw_utf8) != 0), + esc_nonascii_((options & always_escape_nonascii) != 0), + single_line_arrays_((options & single_line_arrays) != 0), + ios_saver_(os) { + if (precision_of_doubles > 0) { + precision_of_doubles_ = precision_of_doubles; + } else { + precision_of_doubles_ = (options & remove_trailing_zeros) != 0 ? 16 : 17; + } + + output(value); + } + +private: + void output(const Value_type& value) { + switch (value.type()) { + case obj_type: + output(value.get_obj()); + break; + 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; + case null_type: + os_ << "null"; + break; + default: + assert(false); + } + } + + void output(const Object_type& obj) { output_array_or_obj(obj, '{', '}'); } + + void output(const Obj_member_type& member) { + output(Config_type::get_name(member)); + space(); + os_ << ':'; + space(); + output(Config_type::get_value(member)); + } + + void output_int(const Value_type& value) { + if (value.is_uint64()) { + os_ << value.get_uint64(); + } else { + os_ << value.get_int64(); + } + } + + void output(const String_type& s) { + os_ << '"' << add_esc_chars(s, raw_utf8_, esc_nonascii_) << '"'; + } + + void output(bool b) { os_ << to_str(b ? "true" : "false"); } + + void output(double d) { os_ << std::setprecision(precision_of_doubles_) << d; } + + 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 + 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 + void output_array_or_obj(const T& t, Char_type start_char, Char_type end_char) { + os_ << start_char; + new_line(); + + ++indentation_level_; + + for (typename T::const_iterator i = t.begin(); i != t.end(); ++i) { + indent(); + + output_composite_item(i, t.end()); + + new_line(); + } + + --indentation_level_; + + indent(); + os_ << end_char; + } + + void indent() { + if (!pretty_) return; + + for (int i = 0; i < indentation_level_; ++i) { + os_ << " "; + } + } + + void space() { + if (pretty_) os_ << ' '; + } + + void new_line() { + if (pretty_) os_ << '\n'; + } + + Generator& operator=(const Generator&); // to prevent "assignment operator could + // not be generated" warning + + Ostream_type& os_; + int indentation_level_; + bool pretty_; + bool raw_utf8_; + bool esc_nonascii_; + bool single_line_arrays_; + int precision_of_doubles_; + boost::io::basic_ios_all_saver 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 +void write_stream(const Value_type& value, Ostream_type& os, int options = none, + unsigned int precision_of_doubles = 0) { + os << std::dec; + Generator(value, os, options, precision_of_doubles); +} + +// writes JSON Value to a stream, e.g. +// +// const string json_str = write( value, pretty_print ); +// +template +typename Value_type::String_type write_string(const Value_type& value, + int options = none, + unsigned int precision_of_doubles = 0) { + typedef typename Value_type::String_type::value_type Char_type; + + std::basic_ostringstream os; + + write_stream(value, os, options, precision_of_doubles); + + return os.str(); +} +} // namespace json5_parser + +#endif diff --git a/json_demo/CMakeLists.txt b/json_demo/CMakeLists.txt index 40332dc..ae55f61 100644 --- a/json_demo/CMakeLists.txt +++ b/json_demo/CMakeLists.txt @@ -1,9 +1,9 @@ -SET(JSON_DEMO_SRCS -json_demo.cpp) - -FIND_PACKAGE(Boost 1.34 REQUIRED) -INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) - -ADD_EXECUTABLE(json_demo ${JSON_DEMO_SRCS}) -TARGET_LINK_LIBRARIES(json_demo json5_parser) - +SET(JSON_DEMO_SRCS +json_demo.cpp) + +#FIND_PACKAGE(Boost 1.34 REQUIRED) +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) + +ADD_EXECUTABLE(json_demo ${JSON_DEMO_SRCS}) +TARGET_LINK_LIBRARIES(json_demo json5_parser) + diff --git a/json_demo/json_demo.cpp b/json_demo/json_demo.cpp index d1ffed7..14fcc36 100644 --- a/json_demo/json_demo.cpp +++ b/json_demo/json_demo.cpp @@ -1,149 +1,128 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -// This demo shows you how to read and write JSON objects and arrays. -// In this demo objects are stored as a vector of name/value pairs. - -#include "json5_parser.h" -#include -#include - -#ifndef JSON_SPIRIT_VALUE_ENABLED -#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled -#endif - -using namespace std; -using namespace json5_parser; - -struct Address -{ - int house_number_; - string road_; - string town_; - string county_; - string country_; -}; - -bool operator==( const Address& a1, const Address& a2 ) -{ - return ( a1.house_number_ == a2.house_number_ ) && - ( a1.road_ == a2.road_ ) && - ( a1.town_ == a2.town_ ) && - ( a1.county_ == a2.county_ ) && - ( a1.country_ == a2.country_ ); -} - -void write_address( Array& a, const Address& addr ) -{ - Object addr_obj; - - addr_obj.push_back( Pair( "house_number", addr.house_number_ ) ); - addr_obj.push_back( Pair( "road", addr.road_ ) ); - addr_obj.push_back( Pair( "town", addr.town_ ) ); - addr_obj.push_back( Pair( "county", addr.county_ ) ); - addr_obj.push_back( Pair( "country", addr.country_ ) ); - - a.push_back( addr_obj ); -} - -Address read_address( const Object& obj ) -{ - Address addr; - - for( Object::size_type i = 0; i != obj.size(); ++i ) - { - const Pair& pair = obj[i]; - - const string& name = pair.name_; - const Value& value = pair.value_; - - if( name == "house_number" ) - { - addr.house_number_ = value.get_int(); - } - else if( name == "road" ) - { - addr.road_ = value.get_str(); - } - else if( name == "town" ) - { - addr.town_ = value.get_str(); - } - else if( name == "county" ) - { - addr.county_ = value.get_str(); - } - else if( name == "country" ) - { - addr.country_ = value.get_str(); - } - else - { - assert( false ); - } - } - - return addr; -} - -void write_addrs( const char* file_name, const Address addrs[] ) -{ - Array addr_array; - - for( int i = 0; i < 5; ++i ) - { - write_address( addr_array, addrs[i] ); - } - - ofstream os( file_name ); - - write_formatted( addr_array, os ); - - os.close(); -} - -vector< Address > read_addrs( const char* file_name ) -{ - ifstream is( file_name ); - - Value value; - - read( is, value ); - - const Array& addr_array = value.get_array(); - - vector< Address > addrs; - - for( unsigned int i = 0; i < addr_array.size(); ++i ) - { - addrs.push_back( read_address( addr_array[i].get_obj() ) ); - } - - return addrs; -} - -int main() -{ - const Address addrs[5] = { { 42, "East Street", "Newtown", "Essex", "England" }, - { 1, "West Street", "Hull", "Yorkshire", "England" }, - { 12, "South Road", "Aberystwyth", "Dyfed", "Wales" }, - { 45, "North Road", "Paignton", "Devon", "England" }, - { 78, "Upper Street", "Ware", "Hertfordshire", "England" } }; - - const char* file_name( "demo.txt" ); - - write_addrs( file_name, addrs ); - - vector< Address > new_addrs = read_addrs( file_name ); - - assert( new_addrs.size() == 5 ); - - for( int i = 0; i < 5; ++i ) - { - assert( new_addrs[i] == addrs[i] ); - } - - return 0; -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +// This demo shows you how to read and write JSON objects and arrays. +// In this demo objects are stored as a vector of name/value pairs. + +#include +#include + +#include "json5_parser.h" + +#ifndef JSON_SPIRIT_VALUE_ENABLED +#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled +#endif + +using namespace std; +using namespace json5_parser; + +struct Address { + int house_number_; + string road_; + string town_; + string county_; + string country_; +}; + +bool operator==(const Address& a1, const Address& a2) { + return (a1.house_number_ == a2.house_number_) && (a1.road_ == a2.road_) && + (a1.town_ == a2.town_) && (a1.county_ == a2.county_) && + (a1.country_ == a2.country_); +} + +void write_address(Array& a, const Address& addr) { + Object addr_obj; + + addr_obj.push_back(Pair("house_number", addr.house_number_)); + addr_obj.push_back(Pair("road", addr.road_)); + addr_obj.push_back(Pair("town", addr.town_)); + addr_obj.push_back(Pair("county", addr.county_)); + addr_obj.push_back(Pair("country", addr.country_)); + + a.push_back(addr_obj); +} + +Address read_address(const Object& obj) { + Address addr; + + for (Object::size_type i = 0; i != obj.size(); ++i) { + const Pair& pair = obj[i]; + + const string& name = pair.name_; + const Value& value = pair.value_; + + if (name == "house_number") { + addr.house_number_ = value.get_int(); + } else if (name == "road") { + addr.road_ = value.get_str(); + } else if (name == "town") { + addr.town_ = value.get_str(); + } else if (name == "county") { + addr.county_ = value.get_str(); + } else if (name == "country") { + addr.country_ = value.get_str(); + } else { + assert(false); + } + } + + return addr; +} + +void write_addrs(const char* file_name, const Address addrs[]) { + Array addr_array; + + for (int i = 0; i < 5; ++i) { + write_address(addr_array, addrs[i]); + } + + ofstream os(file_name); + + write_formatted(addr_array, os); + + os.close(); +} + +vector
read_addrs(const char* file_name) { + ifstream is(file_name); + + Value value; + + read(is, value); + + const Array& addr_array = value.get_array(); + + vector
addrs; + + for (unsigned int i = 0; i < addr_array.size(); ++i) { + addrs.push_back(read_address(addr_array[i].get_obj())); + } + + return addrs; +} + +int main() { + + const Address addrs[5] = {{42, "East Street", "Newtown", "Essex", "England"}, + {1, "West Street", "Hull", "Yorkshire", "England"}, + {12, "South Road", "Aberystwyth", "Dyfed", "Wales"}, + {45, "North Road", "Paignton", "Devon", "England"}, + {78, "Upper Street", "Ware", "Hertfordshire", "England"}}; + + const char* file_name("demo.txt"); + + write_addrs(file_name, addrs); + + vector
new_addrs = read_addrs(file_name); + + assert(new_addrs.size() == 5); + + for (int i = 0; i < 5; ++i) { + assert(new_addrs[i] == addrs[i]); + } + + std::cout << "json_demo tests all passed" << std::endl; + return 0; +} diff --git a/json_headers_only_demo/CMakeLists.txt b/json_headers_only_demo/CMakeLists.txt index 713937f..f7a65fb 100644 --- a/json_headers_only_demo/CMakeLists.txt +++ b/json_headers_only_demo/CMakeLists.txt @@ -1,9 +1,9 @@ -SET(JSON_HEADERS_ONLY_DEMO_SRCS -json_headers_only_demo.cpp) - -FIND_PACKAGE(Boost 1.34 REQUIRED) -INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) - -ADD_EXECUTABLE(json_headers_only_demo ${JSON_HEADERS_ONLY_DEMO_SRCS}) -TARGET_LINK_LIBRARIES(json_headers_only_demo json5_parser) - +SET(JSON_HEADERS_ONLY_DEMO_SRCS +json_headers_only_demo.cpp) + +#FIND_PACKAGE(Boost 1.34 REQUIRED) +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) + +ADD_EXECUTABLE(json_headers_only_demo ${JSON_HEADERS_ONLY_DEMO_SRCS}) +TARGET_LINK_LIBRARIES(json_headers_only_demo json5_parser) + diff --git a/json_headers_only_demo/json_headers_only_demo.cpp b/json_headers_only_demo/json_headers_only_demo.cpp index 87953ac..2faa4ed 100644 --- a/json_headers_only_demo/json_headers_only_demo.cpp +++ b/json_headers_only_demo/json_headers_only_demo.cpp @@ -1,151 +1,134 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -// This demo shows you how to read and write JSON objects and arrays -// using header files only, i.e. not linking to the JSON Spirit object library. -// In this demo objects are stored as a vector of name/value pairs. - -#include "json5_parser_reader_template.h" -#include "json5_parser_writer_template.h" -#include -#include - -#ifndef JSON_SPIRIT_VALUE_ENABLED -#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled -#endif - -using namespace std; -using namespace json5_parser; - -struct Address -{ - int house_number_; - string road_; - string town_; - string county_; - string country_; -}; - -bool operator==( const Address& a1, const Address& a2 ) -{ - return ( a1.house_number_ == a2.house_number_ ) && - ( a1.road_ == a2.road_ ) && - ( a1.town_ == a2.town_ ) && - ( a1.county_ == a2.county_ ) && - ( a1.country_ == a2.country_ ); -} - -void write_address( Array& a, const Address& addr ) -{ - Object addr_obj; - - addr_obj.push_back( Pair( "house_number", addr.house_number_ ) ); - addr_obj.push_back( Pair( "road", addr.road_ ) ); - addr_obj.push_back( Pair( "town", addr.town_ ) ); - addr_obj.push_back( Pair( "county", addr.county_ ) ); - addr_obj.push_back( Pair( "country", addr.country_ ) ); - - a.push_back( addr_obj ); -} - -Address read_address( const Object& obj ) -{ - Address addr; - - for( Object::size_type i = 0; i != obj.size(); ++i ) - { - const Pair& pair = obj[i]; - - const string& name = pair.name_; - const Value& value = pair.value_; - - if( name == "house_number" ) - { - addr.house_number_ = value.get_int(); - } - else if( name == "road" ) - { - addr.road_ = value.get_str(); - } - else if( name == "town" ) - { - addr.town_ = value.get_str(); - } - else if( name == "county" ) - { - addr.county_ = value.get_str(); - } - else if( name == "country" ) - { - addr.country_ = value.get_str(); - } - else - { - assert( false ); - } - } - - return addr; -} - -void write_addrs( const char* file_name, const Address addrs[] ) -{ - Array addr_array; - - for( int i = 0; i < 5; ++i ) - { - write_address( addr_array, addrs[i] ); - } - - ofstream os( file_name ); - - write_stream( Value( addr_array ), os, pretty_print ); // NB need to convert Array to a Value - - os.close(); -} - -vector< Address > read_addrs( const char* file_name ) -{ - ifstream is( file_name ); - - Value value; - - read_stream( is, value ); - - const Array& addr_array = value.get_array(); - - vector< Address > addrs; - - for( unsigned int i = 0; i < addr_array.size(); ++i ) - { - addrs.push_back( read_address( addr_array[i].get_obj() ) ); - } - - return addrs; -} - -int main() -{ - const Address addrs[5] = { { 42, "East Street", "Newtown", "Essex", "England" }, - { 1, "West Street", "Hull", "Yorkshire", "England" }, - { 12, "South Road", "Aberystwyth", "Dyfed", "Wales" }, - { 45, "North Road", "Paignton", "Devon", "England" }, - { 78, "Upper Street", "Ware", "Hertfordshire", "England" } }; - - const char* file_name( "demo.txt" ); - - write_addrs( file_name, addrs ); - - vector< Address > new_addrs = read_addrs( file_name ); - - assert( new_addrs.size() == 5 ); - - for( int i = 0; i < 5; ++i ) - { - assert( new_addrs[i] == addrs[i] ); - } - - return 0; -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +// This demo shows you how to read and write JSON objects and arrays +// using header files only, i.e. not linking to the JSON Spirit object library. +// In this demo objects are stored as a vector of name/value pairs. + +#include +#include +#include + +#include "json5_parser_reader_template.h" +#include "json5_parser_writer_template.h" + +#ifndef JSON_SPIRIT_VALUE_ENABLED +#error Please define JSON_SPIRIT_VALUE_ENABLED for the Value type to be enabled +#endif + +using namespace std; +using namespace json5_parser; + + +struct Address { + int house_number_; + string road_; + string town_; + string county_; + string country_; +}; + +bool operator==(const Address& a1, const Address& a2) { + return (a1.house_number_ == a2.house_number_) && (a1.road_ == a2.road_) && + (a1.town_ == a2.town_) && (a1.county_ == a2.county_) && + (a1.country_ == a2.country_); +} + +void write_address(Array& a, const Address& addr) { + Object addr_obj; + + addr_obj.push_back(Pair("house_number", addr.house_number_)); + addr_obj.push_back(Pair("road", addr.road_)); + addr_obj.push_back(Pair("town", addr.town_)); + addr_obj.push_back(Pair("county", addr.county_)); + addr_obj.push_back(Pair("country", addr.country_)); + + a.push_back(addr_obj); +} + +Address read_address(const Object& obj) { + Address addr; + + for (Object::size_type i = 0; i != obj.size(); ++i) { + const Pair& pair = obj[i]; + + const string& name = pair.name_; + const Value& value = pair.value_; + + if (name == "house_number") { + addr.house_number_ = value.get_int(); + } else if (name == "road") { + addr.road_ = value.get_str(); + } else if (name == "town") { + addr.town_ = value.get_str(); + } else if (name == "county") { + addr.county_ = value.get_str(); + } else if (name == "country") { + addr.country_ = value.get_str(); + } else { + assert(false); + } + } + + return addr; +} + +void write_addrs(const char* file_name, const Address addrs[]) { + Array addr_array; + + for (int i = 0; i < 5; ++i) { + write_address(addr_array, addrs[i]); + } + + ofstream os(file_name); + + write_stream(Value(addr_array), os, + pretty_print); // NB need to convert Array to a Value + + os.close(); +} + +vector
read_addrs(const char* file_name) { + ifstream is(file_name); + + Value value; + + read_stream(is, value); + + const Array& addr_array = value.get_array(); + + vector
addrs; + + for (unsigned int i = 0; i < addr_array.size(); ++i) { + addrs.push_back(read_address(addr_array[i].get_obj())); + } + + return addrs; +} + +int main() { + const Address addrs[5] = {{42, "East Street", "Newtown", "Essex", "England"}, + {1, "West Street", "Hull", "Yorkshire", "England"}, + {12, "South Road", "Aberystwyth", "Dyfed", "Wales"}, + {45, "North Road", "Paignton", "Devon", "England"}, + {78, "Upper Street", "Ware", "Hertfordshire", "England"}}; + + + // Changed from "demo.txt" because tests were failing. NSF weirdness? + const char* file_name("/tmp/json5_demo.txt"); + + write_addrs(file_name, addrs); + + vector
new_addrs = read_addrs(file_name); + + assert(new_addrs.size() == 5); + + for (int i = 0; i < 5; ++i) { + assert(new_addrs[i] == addrs[i]); + } + + std::cout << "json_headers_only_demo tests all passed" << std::endl; + return 0; +} diff --git a/json_map_demo/CMakeLists.txt b/json_map_demo/CMakeLists.txt index 4a7d192..573edcd 100644 --- a/json_map_demo/CMakeLists.txt +++ b/json_map_demo/CMakeLists.txt @@ -1,9 +1,9 @@ -SET(JSON_MAP_DEMO_SRCS -json_map_demo.cpp) - -FIND_PACKAGE(Boost 1.34 REQUIRED) -INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) - -ADD_EXECUTABLE(json_map_demo ${JSON_MAP_DEMO_SRCS}) -TARGET_LINK_LIBRARIES(json_map_demo json5_parser) - +SET(JSON_MAP_DEMO_SRCS +json_map_demo.cpp) + +#FIND_PACKAGE(Boost 1.34 REQUIRED) +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) + +ADD_EXECUTABLE(json_map_demo ${JSON_MAP_DEMO_SRCS}) +TARGET_LINK_LIBRARIES(json_map_demo json5_parser) + diff --git a/json_map_demo/json_map_demo.cpp b/json_map_demo/json_map_demo.cpp index 28778e7..3210e02 100644 --- a/json_map_demo/json_map_demo.cpp +++ b/json_map_demo/json_map_demo.cpp @@ -1,133 +1,121 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -// This demo shows you how to read and write JSON objects and arrays. -// In this demo objects are stored as a map of names to values. - -#include "json5_parser.h" -#include -#include - -#ifndef JSON_SPIRIT_MVALUE_ENABLED -#error Please define JSON_SPIRIT_MVALUE_ENABLED for the mValue type to be enabled -#endif - -using namespace std; -using namespace json5_parser; - -struct Address -{ - int house_number_; - string road_; - string town_; - string county_; - string country_; -}; - -bool operator==( const Address& a1, const Address& a2 ) -{ - return ( a1.house_number_ == a2.house_number_ ) && - ( a1.road_ == a2.road_ ) && - ( a1.town_ == a2.town_ ) && - ( a1.county_ == a2.county_ ) && - ( a1.country_ == a2.country_ ); -} - -void write_address( mArray& a, const Address& addr ) -{ - mObject addr_obj; - - addr_obj[ "house_number" ] = addr.house_number_; - addr_obj[ "road" ] = addr.road_; - addr_obj[ "town" ] = addr.town_; - addr_obj[ "county" ] = addr.county_; - addr_obj[ "country" ] = addr.country_; - - a.push_back( addr_obj ); -} - -const mValue& find_value( const mObject& obj, const string& name ) -{ - mObject::const_iterator i = obj.find( name ); - - assert( i != obj.end() ); - assert( i->first == name ); - - return i->second; -} - -Address read_address( const mObject& obj ) -{ - Address addr; - - addr.house_number_ = find_value( obj, "house_number" ).get_int(); - addr.road_ = find_value( obj, "road" ).get_str(); - addr.town_ = find_value( obj, "town" ).get_str(); - addr.county_ = find_value( obj, "county" ).get_str(); - addr.country_ = find_value( obj, "country" ).get_str(); - - return addr; -} - -void write_addrs( const char* file_name, const Address addrs[] ) -{ - mArray addr_array; - - for( int i = 0; i < 5; ++i ) - { - write_address( addr_array, addrs[i] ); - } - - ofstream os( file_name ); - - write_formatted( addr_array, os ); - - os.close(); -} - -vector< Address > read_addrs( const char* file_name ) -{ - ifstream is( file_name ); - - mValue value; - - read( is, value ); - - const mArray& addr_array = value.get_array(); - - vector< Address > addrs; - - for( vector< Address >::size_type i = 0; i < addr_array.size(); ++i ) - { - addrs.push_back( read_address( addr_array[i].get_obj() ) ); - } - - return addrs; -} - -int main() -{ - const Address addrs[5] = { { 42, "East Street", "Newtown", "Essex", "England" }, - { 1, "West Street", "Hull", "Yorkshire", "England" }, - { 12, "South Road", "Aberystwyth", "Dyfed", "Wales" }, - { 45, "North Road", "Paignton", "Devon", "England" }, - { 78, "Upper Street", "Ware", "Hertfordshire", "England" } }; - - const char* file_name( "demo.txt" ); - - write_addrs( file_name, addrs ); - - vector< Address > new_addrs = read_addrs( file_name ); - - assert( new_addrs.size() == 5 ); - - for( int i = 0; i < 5; ++i ) - { - assert( new_addrs[i] == addrs[i] ); - } - - return 0; -} -; \ No newline at end of file +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +// This demo shows you how to read and write JSON objects and arrays. +// In this demo objects are stored as a map of names to values. + +#include +#include + +#include "json5_parser.h" + +#ifndef JSON_SPIRIT_MVALUE_ENABLED +#error Please define JSON_SPIRIT_MVALUE_ENABLED for the mValue type to be enabled +#endif + +using namespace std; +using namespace json5_parser; + +struct Address { + int house_number_; + string road_; + string town_; + string county_; + string country_; +}; + +bool operator==(const Address& a1, const Address& a2) { + return (a1.house_number_ == a2.house_number_) && (a1.road_ == a2.road_) && + (a1.town_ == a2.town_) && (a1.county_ == a2.county_) && + (a1.country_ == a2.country_); +} + +void write_address(mArray& a, const Address& addr) { + mObject addr_obj; + + addr_obj["house_number"] = addr.house_number_; + addr_obj["road"] = addr.road_; + addr_obj["town"] = addr.town_; + addr_obj["county"] = addr.county_; + addr_obj["country"] = addr.country_; + + a.push_back(addr_obj); +} + +const mValue& find_value(const mObject& obj, const string& name) { + mObject::const_iterator i = obj.find(name); + + assert(i != obj.end()); + assert(i->first == name); + + return i->second; +} + +Address read_address(const mObject& obj) { + Address addr; + + addr.house_number_ = find_value(obj, "house_number").get_int(); + addr.road_ = find_value(obj, "road").get_str(); + addr.town_ = find_value(obj, "town").get_str(); + addr.county_ = find_value(obj, "county").get_str(); + addr.country_ = find_value(obj, "country").get_str(); + + return addr; +} + +void write_addrs(const char* file_name, const Address addrs[]) { + mArray addr_array; + + for (int i = 0; i < 5; ++i) { + write_address(addr_array, addrs[i]); + } + + ofstream os(file_name); + + write_formatted(addr_array, os); + + os.close(); +} + +vector
read_addrs(const char* file_name) { + ifstream is(file_name); + + mValue value; + + read(is, value); + + const mArray& addr_array = value.get_array(); + + vector
addrs; + + for (vector
::size_type i = 0; i < addr_array.size(); ++i) { + addrs.push_back(read_address(addr_array[i].get_obj())); + } + + return addrs; +} + +int main() { + const Address addrs[5] = {{42, "East Street", "Newtown", "Essex", "England"}, + {1, "West Street", "Hull", "Yorkshire", "England"}, + {12, "South Road", "Aberystwyth", "Dyfed", "Wales"}, + {45, "North Road", "Paignton", "Devon", "England"}, + {78, "Upper Street", "Ware", "Hertfordshire", "England"}}; + + const char* file_name("map_demo.txt"); + + write_addrs(file_name, addrs); + + vector
new_addrs = read_addrs(file_name); + + assert(new_addrs.size() == 5); + + for (int i = 0; i < 5; ++i) { + assert(new_addrs[i] == addrs[i]); + } + + std::cout << "json_map_demo tests all passed" << std::endl; + return 0; +}; diff --git a/json_test/CMakeLists.txt b/json_test/CMakeLists.txt index e603f49..b367def 100644 --- a/json_test/CMakeLists.txt +++ b/json_test/CMakeLists.txt @@ -1,15 +1,15 @@ -SET(JSON_TEST_SRCS -json5_parser_reader_test.cpp json5_parser_reader_test.h -json5_parser_stream_reader_test.cpp json5_parser_stream_reader_test.h -json5_parser_utils_test.cpp json5_parser_utils_test.h -json5_parser_value_test.cpp json5_parser_value_test.h -json5_parser_writer_test.cpp json5_parser_writer_test.h -utils_test.cpp utils_test.h -json_test.cpp) - -FIND_PACKAGE(Boost 1.34 REQUIRED) -INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) - -ADD_EXECUTABLE(json_test ${JSON_TEST_SRCS}) -TARGET_LINK_LIBRARIES(json_test json5_parser) - +SET(JSON_TEST_SRCS +json5_parser_reader_test.cpp json5_parser_reader_test.h +json5_parser_stream_reader_test.cpp json5_parser_stream_reader_test.h +json5_parser_utils_test.cpp json5_parser_utils_test.h +json5_parser_value_test.cpp json5_parser_value_test.h +json5_parser_writer_test.cpp json5_parser_writer_test.h +utils_test.cpp utils_test.h +json_test.cpp) + +#FIND_PACKAGE(Boost 1.34 REQUIRED) +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) + +ADD_EXECUTABLE(json_test ${JSON_TEST_SRCS}) +TARGET_LINK_LIBRARIES(json_test json5_parser) + diff --git a/json_test/json5_parser_reader_test.cpp b/json_test/json5_parser_reader_test.cpp index 1137e51..fbbf3e2 100644 --- a/json_test/json5_parser_reader_test.cpp +++ b/json_test/json5_parser_reader_test.cpp @@ -1,925 +1,939 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_reader_test.h" -#include "utils_test.h" -#include "json5_parser_reader.h" -#include "json5_parser_value.h" -#include "json5_parser_writer.h" - -#include -#include -#include -#include -#include - -using namespace json5_parser; -using namespace std; -using namespace boost; -using namespace boost::assign; - -namespace -{ - template< class String_type, class Value_type > - void test_read( const String_type& s, Value_type& value ) - { - // performs both types of read and checks they produce the same value - - read( s, value ); - - Value_type value_2; - - read_or_throw( s, value_2 ); - - assert_eq( value, value_2 ); - } - - template< class Config_type > - struct Test_runner - { - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - typedef typename Config_type::Pair_type Pair_type; - typedef typename String_type::value_type Char_type; - typedef typename String_type::const_iterator Iter_type; - typedef std::basic_istringstream< Char_type > Istringstream_type; - typedef std::basic_istream< Char_type > Istream_type; - - String_type to_str( const char* c_str ) - { - return ::to_str< String_type >( c_str ); - } - - Test_runner() - { - } - - void check_eq( const Object_type& obj_1, const Object_type& obj_2 ) - { - const typename Object_type::size_type size( obj_1.size() ); - - assert_eq( size, obj_2.size() ); - - typename Object_type::const_iterator i1 = obj_1.begin(); - typename Object_type::const_iterator i2 = obj_2.begin(); - - for( ; i1 != obj_1.end(); ++i1, ++i2 ) - { - assert_eq( *i1, *i2 ); - } - } - - void add_value( Object_type& obj, const char* c_name, const Value_type& value ) - { - Config_type::add( obj, to_str( c_name ), value ); - } - - void add_c_str( Object_type& obj, const char* c_name, const char* c_value ) - { - add_value( obj, c_name, to_str( c_value ) ); - } - - void test_syntax( const char* c_str, bool expected_success = true ) - { - const String_type str = to_str( c_str ); - - Value_type value; - - const bool ok = read( str, value ); - - assert_eq( ok, expected_success ); - - try - { - read_or_throw( str, value ); - - assert( expected_success ); - } - catch( ... ) - { - assert( !expected_success ); - } - } - - template< typename Int > - void test_syntax( Int min_int, Int max_int ) - { - ostringstream os; - - os << "[" << min_int << "," << max_int << "]"; - - test_syntax( os.str().c_str() ); - } - - void test_syntax() - { - test_syntax( "{}" ); - test_syntax( "{ }" ); - test_syntax( "{ } " ); - test_syntax( "{ } " ); - test_syntax( "{\"\":\"\"}" ); - test_syntax( "{\"test\":\"123\"}" ); - test_syntax( "{\"test\" : \"123\"}" ); - test_syntax( "{\"testing testing testing\":\"123\"}" ); - test_syntax( "{\"\":\"abc\"}" ); - test_syntax( "{\"abc\":\"\"}" ); - test_syntax( "{\"\":\"\"}" ); - test_syntax( "{\"test\":true}" ); - test_syntax( "{\"test\":false}" ); - test_syntax( "{\"test\":null}" ); - test_syntax( "{\"test1\":\"123\",\"test2\":\"456\"}" ); - test_syntax( "{\"test1\":\"123\",\"test2\":\"456\",\"test3\":\"789\"}" ); - test_syntax( "{\"test1\":{\"test2\":\"123\",\"test3\":\"456\"}}" ); - test_syntax( "{\"test1\":{\"test2\":{\"test3\":\"456\"}}}" ); - test_syntax( "{\"test1\":[\"a\",\"bb\",\"cc\"]}" ); - test_syntax( "{\"test1\":[true,false,null]}" ); - test_syntax( "{\"test1\":[true,\"abc\",{\"a\":\"b\"},{\"d\":false},null]}" ); - test_syntax( "{\"test1\":[1,2,-3]}" ); - test_syntax( "{\"test1\":[1.1,2e4,-1.234e-34]}" ); - test_syntax( "{\n" - "\t\"test1\":\n" - "\t\t{\n" - "\t\t\t\"test2\":\"123\",\n" - "\t\t\t\"test3\":\"456\"\n" - "\t\t}\n" - "}\n" ); - test_syntax( "[]" ); - test_syntax( "[ ]" ); - test_syntax( "[1,2,3]" ); - test_syntax( "[ 1, -2, 3]" ); - test_syntax( "[ 1.2, -2e6, -3e-6 ]" ); - test_syntax( "[ 1.2, \"str\", -3e-6, { \"field\" : \"data\" } ]" ); - - test_syntax( INT_MIN, INT_MAX ); - test_syntax( LLONG_MIN, LLONG_MAX ); - test_syntax( "[1 2 3]", false ); - test_syntax( "[1,\n2,\n3,]"); - test_syntax( "[0xfreedom]",false); - test_syntax( "[0xreefer]",false); - } - - Value_type read_cstr( const char* c_str ) - { - Value_type value; - - test_read( to_str( c_str ), value ); - - return value; - } - - void read_cstr( const char* c_str, Value_type& value ) - { - test_read( to_str( c_str ), value ); - } - - void check_reading( const char* c_str ) - { - Value_type value; - - String_type in_s( to_str( c_str ) ); - - test_read( in_s, value ); - - const String_type result = write_formatted( value ); - - assert_eq( in_s, result ); - } - - template< typename Int > - void check_reading( Int min_int, Int max_int ) - { - ostringstream os; - - os << "[\n" - " " << min_int << ",\n" - " " << max_int << "\n" - "]"; - - check_reading( os.str().c_str() ); - } - - void test_reading() - { - check_reading( "{\n}" ); - - { - Object_type obj; - Value_type value; - - read_cstr( "{\n" - " name1 : 'value \\\n1',\n" - "}", value ); - - add_c_str( obj, "name1", "value 1" ); - - check_eq( value.get_obj(), obj ); - } - - Object_type obj; - Value_type value; - - read_cstr( "{\n" - " \"name 1\" : \"value 1\"\n" - "}", value ); - - add_c_str( obj, "name 1", "value 1" ); - - check_eq( value.get_obj(), obj ); - - read_cstr( "{\"name 1\":\"value 1\",\"name 2\":\"value 2\"}", value ); - - add_c_str( obj, "name 2", "value 2" ); - - check_eq( value.get_obj(), obj ); - - read_cstr( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : \"value 2\",\n" - " \"name 3\" : \"value 3\"\n" - "}", value ); - - add_c_str( obj, "name 3", "value 3" ); - - check_eq( value.get_obj(), obj ); - - check_reading( "{\n" - " \"\" : \"value\",\n" - " \"name\" : \"\"\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : {\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : \"value_4\"\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : {\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : \"value_4\",\n" - " \"name_5\" : {\n" - " \"name_6\" : \"value_6\",\n" - " \"name_7\" : \"value_7\"\n" - " }\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : {\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : {\n" - " \"name_5\" : \"value_5\",\n" - " \"name_6\" : \"value_6\"\n" - " },\n" - " \"name_7\" : \"value_7\"\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : {\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : {\n" - " \"name_5\" : \"value_5\",\n" - " \"name_6\" : \"value_6\"\n" - " },\n" - " \"name_7\" : \"value_7\"\n" - " },\n" - " \"name_8\" : \"value_8\",\n" - " \"name_9\" : {\n" - " \"name_10\" : \"value_10\"\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : {\n" - " \"name 2\" : {\n" - " \"name 3\" : {\n" - " \"name_4\" : {\n" - " \"name_5\" : \"value\"\n" - " }\n" - " }\n" - " }\n" - " }\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : true,\n" - " \"name 3\" : false,\n" - " \"name_4\" : \"value_4\",\n" - " \"name_5\" : true\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : null,\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : null\n" - "}" ); - - check_reading( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : 123,\n" - " \"name 3\" : \"value 3\",\n" - " \"name_4\" : -567\n" - "}" ); - - check_reading( "[\n]" ); - - check_reading( "[\n" - " 1\n" - "]" ); - - check_reading( "[\n" - " 1,\n" - " 1.2,\n" - " \"john]\",\n" - " true,\n" - " false,\n" - " null\n" - "]" ); - - check_reading( "[\n" - " 1,\n" - " [\n" - " 2,\n" - " 3\n" - " ]\n" - "]" ); - - check_reading( "[\n" - " 1,\n" - " [\n" - " 2,\n" - " 3\n" - " ],\n" - " [\n" - " 4,\n" - " [\n" - " 5,\n" - " 6,\n" - " 7\n" - " ]\n" - " ]\n" - "]" ); - - check_reading( "[\n" - " {\n" - " \"name\" : \"value\"\n" - " }\n" - "]" ); - - check_reading( "{\n" - " \"name\" : [\n" - " 1\n" - " ]\n" - "}" ); - - check_reading( "[\n" - " {\n" - " \"name 1\" : \"value\",\n" - " \"name 2\" : [\n" - " 1,\n" - " 2,\n" - " 3\n" - " ]\n" - " }\n" - "]" ); - - check_reading( "{\n" - " \"name 1\" : [\n" - " 1,\n" - " {\n" - " \"name 2\" : \"value 2\"\n" - " }\n" - " ]\n" - "}" ); - - check_reading( "[\n" - " {\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : [\n" - " 1,\n" - " 2,\n" - " {\n" - " \"name 3\" : \"value 3\"\n" - " }\n" - " ]\n" - " }\n" - "]" ); - - check_reading( "{\n" - " \"name 1\" : [\n" - " 1,\n" - " {\n" - " \"name 2\" : [\n" - " 1,\n" - " 2,\n" - " 3\n" - " ]\n" - " }\n" - " ]\n" - "}" ); - - check_reading( INT_MIN, INT_MAX ); - check_reading( LLONG_MIN, LLONG_MAX ); - } - - void test_reading_reals() - { - Value_type value; - - const String_type in_s = to_str( "[1.200000000000000,1.234567890123456e+125,-1.234000000000000e-123," - " 1.000000000000000e-123,1234567890.123456,123,]" ); - - basic_istringstream< Char_type > is( in_s ); - - const bool ok = read( is, value ); - - assert_eq( ok, true ); - assert_eq( value.type(), array_type ); - - const Array_type arr = value.get_array(); - - assert_eq( arr.size(), 6u ); - assert_eq( arr[0].get_real(), 1.2, 1e-16 ); - assert_eq( arr[1].get_real(), 1.234567890123456e+125, 1e+110 ); - assert_eq( arr[2].get_real(), -1.234e-123, 1e+108 ); - assert_eq( arr[3].get_real(), 1e-123, 1e+108 ); - assert_eq( arr[4].get_real(), 1234567890.123456, 1e-7 ); - assert_eq( arr[5].get_real(), 123, 1e-13 ); - } - - void test_from_stream( const char* json_str, bool expected_success, - const Error_position& expected_error ) - { - Value_type value; - - String_type in_s( to_str( json_str ) ); - - basic_istringstream< Char_type > is( in_s ); - - const bool ok = read( is, value ); - - assert_eq( ok, expected_success ); - - if( ok ) - { - assert_eq( in_s, write( value ) ); - } - - try - { - basic_istringstream< Char_type > is( in_s ); - - read_or_throw( is, value ); - - assert_eq( expected_success, true ); - - assert_eq( in_s, write( value ) ); - } - catch( const Error_position error ) - { - assert_eq( error, expected_error ); - } - } - - void test_from_stream() - { - test_from_stream( "[1,2]", true, Error_position() ); - test_from_stream( "\n\n foo", false, Error_position( 3, 2,"not a value" ) ); - } - - void test_escape_chars( const char* json_str, const char* c_str ) - { - Value_type value; - - string s( string( "{\"" ) + json_str + "\" : \"" + json_str + "\"} " ); - - read_cstr( s.c_str(), value ); - - const Pair_type& pair( *value.get_obj().begin() ); - - assert_eq( Config_type::get_name ( pair ), to_str( c_str ) ); - assert_eq( Config_type::get_value( pair ), to_str( c_str ) ); - } - - void test_escape_chars() - { - test_escape_chars( "\\t", "\t"); - test_escape_chars( "a\\t", "a\t" ); - test_escape_chars( "\\tb", "\tb" ); - test_escape_chars( "a\\tb", "a\tb" ); - test_escape_chars( "a\\tb", "a\tb" ); - test_escape_chars( "a123\\tb", "a123\tb" ); - test_escape_chars( "\\t\\n\\\\", "\t\n\\" ); - test_escape_chars( "\\/\\r\\b\\f\\\"", "/\r\b\f\"" ); - test_escape_chars( "\\h\\j\\k", "" ); // invalid esc chars - test_escape_chars( "\\x61\\x62\\x63", "abc" ); - test_escape_chars( "a\\x62c", "abc" ); - test_escape_chars( "\\x01\\x02\\x7F", "\x01\x02\x7F" ); // NB x7F is the greatest char spirit will parse - test_escape_chars( "\\u0061\\u0062\\u0063", "abc" ); - } - - void check_is_null( const char* c_str ) - { - assert_eq( read_cstr( c_str ).type(), null_type ); - } - - template< typename T > - void check_value( const char* c_str, const T& expected_value ) - { - const Value_type v( read_cstr( c_str ) ); - - assert_eq( v.template get_value< T >(), expected_value ); - } - - void test_values() - { - check_value( "1", 1 ); - check_value( "+Infinity", std::numeric_limits::infinity() ); - check_value( "Infinity", std::numeric_limits::infinity() ); - check_value( "-Infinity", -std::numeric_limits::infinity() ); - check_value( "0xfe", 0xfe ); - check_value( "1.5", 1.5 ); - check_value( "\"Test\"", to_str( "Test" ) ); - check_value( "true", true ); - check_value( "false", false ); - check_is_null( "null" ); - } - - void check_read_fails( const char* c_str, int line, int column, const string& reason ) - { - Value_type value; - - try - { - read_cstr( c_str, value ); - - assert( false ); - } - catch( const Error_position posn ) - { - assert_eq( posn, Error_position( line, column, reason ) ); - } - } - - void test_error_cases() - { - check_read_fails( "", 1, 1, "not a value" ); - check_read_fails( "foo", 1, 1, "not a value" ); - check_read_fails( " foo", 1, 2, "not a value" ); - check_read_fails( " foo", 1, 3, "not a value" ); - check_read_fails( "\n\n foo", 3, 2, "not a value" ); - check_read_fails( "!!!", 1, 1, "not a value" ); - check_read_fails( "\"bar", 1, 1, "not a value" ); - check_read_fails( "0xreefer", 1, 3, "not a hexadecimal number" ); - check_read_fails( "bar\"", 1, 1, "not a value" ); - check_read_fails( "[1}", 1, 3, "not an array" ); - check_read_fails( "[1,2?", 1, 5, "not an array" ); - check_read_fails( "[1,2}", 1, 5, "not an array" ); - check_read_fails( "[1;2]", 1, 3, "not an array" ); - check_read_fails( "{\"name\":\"value\"]", 1, 16, "not an object" ); - check_read_fails( "{\"name\",\"value\"}", 1, 8, "no colon in pair" ); - check_read_fails( "{\n1:\"value\"}", 2, 1, "not an object" ); - check_read_fails( "{\n name\":\"value\"}", 2, 7, "no colon in pair" ); - check_read_fails( "{\"name\":foo}", 1, 9, "not a value" ); - check_read_fails( "{\"name\":0xfreedom}", 1, 12, "not an object" ); - check_read_fails( "{\"name\":value\"}", 1, 9, "not a value" ); - check_read_fails( "{'name':\"value\"}", 1, 2, "not an object" ); - } - - typedef vector< int > Ints; - - bool test_read_range( Iter_type& first, Iter_type last, Value_type& value ) - { - Iter_type first_ = first; - - const bool ok = read( first, last, value ); - - try - { - Value_type value_; - - read_or_throw( first_, last, value_ ); - - assert_eq( ok, true ); - assert_eq( value, value_ ); - } - catch( ... ) - { - assert_eq( ok, false ); - } - - return ok; - } - - void check_value_sequence( Iter_type first, Iter_type last, const Ints& expected_values, bool all_input_consumed ) - { - Value_type value; - - for( Ints::size_type i = 0; i < expected_values.size(); ++i ) - { - const bool ok = test_read_range( first, last, value ); - - assert_eq( ok, true ); - - const bool is_last( i == expected_values.size() - 1 ); - - assert_eq( first == last, is_last ? all_input_consumed : false ); - } - - const bool ok = test_read_range( first, last, value ); - - assert_eq( ok, false ); - } - - void check_value_sequence( Istream_type& is, const Ints& expected_values, bool all_input_consumed ) - { - Value_type value; - - for( Ints::size_type i = 0; i < expected_values.size(); ++i ) - { - read_or_throw( is, value ); - - assert_eq( value.get_int(), expected_values[i] ); - - const bool is_last( i == expected_values.size() - 1 ); - - assert_eq( is.eof(), is_last ? all_input_consumed : false ); - } - - try - { - read_or_throw( is, value ); - - assert( false ); - } - catch( ... ) - { - } - - assert_eq( is.eof(), true ); - } - - void check_value_sequence( const char* c_str, const Ints& expected_values, bool all_input_consumed ) - { - const String_type s( to_str( c_str ) ); - - check_value_sequence( s.begin(), s.end(), expected_values, all_input_consumed ); - - Istringstream_type is( s ); - - check_value_sequence( is, expected_values, all_input_consumed ); - } - - void check_array( const Value_type& value, typename Array_type::size_type expected_size ) - { - assert_eq( value.type(), array_type ); - - const Array_type& arr = value.get_array(); - - assert_eq( arr.size(), expected_size ); - - for( typename Array_type::size_type i = 0; i < expected_size; ++i ) - { - const Value_type& val = arr[i]; - - assert_eq( val.type(), int_type ); - assert_eq( val.get_int(), int( i + 1 ) ); - } - } - - void check_reading_array( Iter_type& begin, Iter_type end, typename Array_type::size_type expected_size ) - { - Value_type value; - - test_read_range( begin, end, value ); - - check_array( value, expected_size ); - } - - void check_reading_array( Istream_type& is, typename Array_type::size_type expected_size ) - { - Value_type value; - - read( is, value ); - - check_array( value, expected_size ); - } - - void check_reading_arrays( const char* arrays_str ) - { - const String_type str( to_str( arrays_str ) ); - - Iter_type begin = str.begin(); - const Iter_type end = str.end(); - - check_reading_array( begin, end, 0 ); - check_reading_array( begin, end, 1 ); - check_reading_array( begin, end, 2 ); - check_reading_array( begin, end, 3 ); - - Istringstream_type is( str ); - - check_reading_array( is, 0 ); - check_reading_array( is, 1 ); - check_reading_array( is, 2 ); - check_reading_array( is, 3 ); - } - - void test_sequence_of_values() - { - check_value_sequence( "", Ints(), false ); - check_value_sequence( " ", Ints(), false ); - check_value_sequence( " ", Ints(), false ); - check_value_sequence( " 10 ", list_of( 10 ), false ); - check_value_sequence( " 10 11 ", list_of( 10 )( 11 ), false ); - check_value_sequence( " 10 11 12", list_of( 10 )( 11 )( 12 ), true); - check_value_sequence( "10 11 12", list_of( 10 )( 11 )( 12 ), true); - - // - - check_reading_arrays( "[] [ 1 ] [ 1, 2 ] [ 1, 2, 3 ]" ); - // check_reading_arrays( "[][1][1,2][1,2,3]" ); // fails due to multi_pass iterator bug, - // use stream_reader class instead - } - - void test_uint64( const char* value_str, int expected_int, int64_t expected_int64, uint64_t expected_uint64 ) - { - const Value_type v( read_cstr( value_str ) ); - - assert_eq( v.get_int(), expected_int ); - assert_eq( v.get_int64(), expected_int64 ); - assert_eq( v.get_uint64(), expected_uint64 ); - } - - void test_uint64() - { - test_uint64( "0", 0, 0, 0 ); - test_uint64( "1", 1, 1, 1 ); - test_uint64( "-1", -1, -1, ULLONG_MAX ); - test_uint64( "18446744073709551615", -1, -1, ULLONG_MAX ); - } - - void test_types() - { - Value_type value; - - read( to_str( "[ \"foo\", true, false, 1, 12.3, null ]" ), value ); - - assert_eq( value.type(), array_type ); - - const Array_type& a = value.get_array(); - - assert_eq( a[0].get_str(), to_str( "foo" ) ); - assert_eq( a[1].get_bool(), true ); - assert_eq( a[2].get_bool(), false ); - assert_eq( a[3].get_int(), 1 ); - assert_eq( a[3].get_int64(), 1 ); - assert_eq( a[3].get_uint64(), 1u ); - assert_eq( a[3].get_real(), 1.0 ); - assert_eq( a[4].get_real(), 12.3 ); - assert_eq( a[5].is_null(), true ); - } - - void test_comments() - { - Value_type value_1; - - read_cstr( "{\n" - " \"name 1\" : \"value 1\",\n" - " \"name 2\" : \"value 2 /* not a comment but data */\",\n" - " \"name 3\" : \"value 3 // not a comment but data\"\n" - "}", value_1 ); - - Value_type value_2; - - read_cstr( "{// a comment\n " - " \"name 1\" : /* another comment */ \"value 1\",\n" - " \"name 2\" : \"value 2 /* not a comment but data */\",\n" - " // \"name 2\" : \"value 2\",\n" - " \"name 3\" : \"value 3 // not a comment but data\"\n" - "/* multi\n" - "line\n" - "comment */}", value_2 ); - - assert_eq( value_1, value_2 ); - } - - void run_tests() - { - test_syntax(); - test_reading(); - test_reading_reals(); - test_from_stream(); - test_escape_chars(); - test_values(); - test_error_cases(); - test_sequence_of_values(); - test_uint64(); - test_types(); - test_comments(); - } - }; - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void test_wide_esc_u() - { - wValue value; - - test_read( L"[\"\\uABCD\"]", value ); - - const wstring s( value.get_array()[0].get_str() ); - - assert_eq( s.length(), static_cast< wstring::size_type >( 1u ) ); - assert_eq( s[0], 0xABCD ); - } -#endif - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void test_extended_ascii( const string& s ) - { - Value value; - - test_read( "[\"" + s + "\"]", value ); - - assert_eq( value.get_array()[0].get_str(), "" ); - } - - void test_extended_ascii() - { - test_extended_ascii( "\\u00E4\\u00F6\\u00FC\\u00DF" ); - test_extended_ascii( "" ); - } -#endif -} - -//#include - -void json5_parser::test_reader() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Test_runner< Config >().run_tests(); - test_extended_ascii(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Test_runner< mConfig >().run_tests(); -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wConfig >().run_tests(); - test_wide_esc_u(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wmConfig >().run_tests(); -#endif - -#ifndef _DEBUG - //ifstream ifs( "test.txt" ); - - //string s; - - //getline( ifs, s ); - - //timer t; - - //for( int i = 0; i < 2000; ++i ) - //{ - // Value value; - - // read( s, value ); - //} - - //cout << t.elapsed() << endl; - -// const string so = write( value ); - - //Object obj; - - //for( int i = 0; i < 100000; ++i ) - //{ - // obj.push_back( Pair( "\x01test\x7F", lexical_cast< string >( i ) ) ); - //} - - //const string s = write( obj ); - - //Value value; - - //timer t; - - //read( s, value ); - - //cout << t.elapsed() << endl; - - //cout << "obj size " << value.get_obj().size(); -#endif -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_reader_test.h" +#include "json5_parser_reader.h" +#include "json5_parser_value.h" +#include "json5_parser_writer.h" +#include "utils_test.h" + +#include +#include +#include +#include +#include + +using namespace json5_parser; +using namespace std; +using namespace boost; +using namespace boost::assign; + +namespace { +template +void test_read(const String_type& s, Value_type& value) { + // performs both types of read and checks they produce the same value + + read(s, value); + + Value_type value_2; + + read_or_throw(s, value_2); + + assert_eq(value, value_2); +} + +template +struct Test_runner { + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + typedef typename Config_type::Pair_type Pair_type; + typedef typename String_type::value_type Char_type; + typedef typename String_type::const_iterator Iter_type; + typedef std::basic_istringstream Istringstream_type; + typedef std::basic_istream Istream_type; + + String_type to_str(const char* c_str) { return ::to_str(c_str); } + + Test_runner() {} + + void check_eq(const Object_type& obj_1, const Object_type& obj_2) { + const typename Object_type::size_type size(obj_1.size()); + + assert_eq(size, obj_2.size()); + + typename Object_type::const_iterator i1 = obj_1.begin(); + typename Object_type::const_iterator i2 = obj_2.begin(); + + for (; i1 != obj_1.end(); ++i1, ++i2) { + assert_eq(*i1, *i2); + } + } + + void add_value(Object_type& obj, const char* c_name, const Value_type& value) { + Config_type::add(obj, to_str(c_name), value); + } + + void add_c_str(Object_type& obj, const char* c_name, const char* c_value) { + add_value(obj, c_name, to_str(c_value)); + } + + void test_syntax(const char* c_str, bool expected_success = true) { + const String_type str = to_str(c_str); + + Value_type value; + + const bool ok = read(str, value); + + assert_eq(ok, expected_success); + + try { + read_or_throw(str, value); + + assert(expected_success); + } catch (...) { + assert(!expected_success); + } + } + + template + void test_syntax(Int min_int, Int max_int) { + ostringstream os; + + os << "[" << min_int << "," << max_int << "]"; + + test_syntax(os.str().c_str()); + } + + void test_syntax() { + test_syntax("{}"); + test_syntax("{ }"); + test_syntax("{ } "); + test_syntax("{ } "); + test_syntax("{\"\":\"\"}"); + test_syntax("{\"test\":\"123\"}"); + test_syntax("{\"test\" : \"123\"}"); + test_syntax("{\"testing testing testing\":\"123\"}"); + test_syntax("{\"\":\"abc\"}"); + test_syntax("{\"abc\":\"\"}"); + test_syntax("{\"\":\"\"}"); + test_syntax("{\"test\":true}"); + test_syntax("{\"test\":false}"); + test_syntax("{\"test\":null}"); + test_syntax("{\"test1\":\"123\",\"test2\":\"456\"}"); + test_syntax("{\"test1\":\"123\",\"test2\":\"456\",\"test3\":\"789\"}"); + test_syntax("{\"test1\":{\"test2\":\"123\",\"test3\":\"456\"}}"); + test_syntax("{\"test1\":{\"test2\":{\"test3\":\"456\"}}}"); + test_syntax("{\"test1\":[\"a\",\"bb\",\"cc\"]}"); + test_syntax("{\"test1\":[true,false,null]}"); + test_syntax("{\"test1\":[true,\"abc\",{\"a\":\"b\"},{\"d\":false},null]}"); + test_syntax("{\"test1\":[1,2,-3]}"); + test_syntax("{\"test1\":[1.1,2e4,-1.234e-34]}"); + test_syntax( + "{\n" + "\t\"test1\":\n" + "\t\t{\n" + "\t\t\t\"test2\":\"123\",\n" + "\t\t\t\"test3\":\"456\"\n" + "\t\t}\n" + "}\n"); + test_syntax("[]"); + test_syntax("[ ]"); + test_syntax("[1,2,3]"); + test_syntax("[ 1, -2, 3]"); + test_syntax("[ 1.2, -2e6, -3e-6 ]"); + test_syntax("[ 1.2, \"str\", -3e-6, { \"field\" : \"data\" } ]"); + + test_syntax(INT_MIN, INT_MAX); + test_syntax(LLONG_MIN, LLONG_MAX); + test_syntax("[1 2 3]", false); + test_syntax("[1,\n2,\n3,]"); + test_syntax("[0xfreedom]", false); + test_syntax("[0xreefer]", false); + } + + Value_type read_cstr(const char* c_str) { + Value_type value; + + test_read(to_str(c_str), value); + + return value; + } + + void read_cstr(const char* c_str, Value_type& value) { + test_read(to_str(c_str), value); + } + + void check_reading(const char* c_str) { + Value_type value; + + String_type in_s(to_str(c_str)); + + test_read(in_s, value); + + const String_type result = write_formatted(value); + + assert_eq(in_s, result); + } + + template + void check_reading(Int min_int, Int max_int) { + ostringstream os; + + os << "[\n" + " " + << min_int + << ",\n" + " " + << max_int + << "\n" + "]"; + + check_reading(os.str().c_str()); + } + + void test_reading() { + check_reading("{\n}"); + + { + Object_type obj; + Value_type value; + + read_cstr( + "{\n" + " name1 : 'value \\\n1',\n" + "}", + value); + + add_c_str(obj, "name1", "value 1"); + + check_eq(value.get_obj(), obj); + } + + { + Object_type obj; + Value_type value; + + read_cstr( + "{\n" + " \"name 1\" : \"value 1\"\n" + "}", + value); + + add_c_str(obj, "name 1", "value 1"); + + check_eq(value.get_obj(), obj); + + read_cstr("{\"name 1\":\"value 1\",\"name 2\":\"value 2\"}", value); + + add_c_str(obj, "name 2", "value 2"); + + check_eq(value.get_obj(), obj); + + read_cstr( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : \"value 2\",\n" + " \"name 3\" : \"value 3\"\n" + "}", + value); + + add_c_str(obj, "name 3", "value 3"); + + check_eq(value.get_obj(), obj); + } + + { + Object_type obj; + Value_type value; + + read_cstr( + "{\n" + " name 1 : \"value 1\"\n" + "}", + value); + + add_c_str(obj, "name 1", "value 1"); + check_eq(value.get_obj(), obj); + } + + check_reading( + "{\n" + " \"\" : \"value\",\n" + " \"name\" : \"\"\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : {\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : \"value_4\"\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : {\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : \"value_4\",\n" + " \"name_5\" : {\n" + " \"name_6\" : \"value_6\",\n" + " \"name_7\" : \"value_7\"\n" + " }\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : {\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : {\n" + " \"name_5\" : \"value_5\",\n" + " \"name_6\" : \"value_6\"\n" + " },\n" + " \"name_7\" : \"value_7\"\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : {\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : {\n" + " \"name_5\" : \"value_5\",\n" + " \"name_6\" : \"value_6\"\n" + " },\n" + " \"name_7\" : \"value_7\"\n" + " },\n" + " \"name_8\" : \"value_8\",\n" + " \"name_9\" : {\n" + " \"name_10\" : \"value_10\"\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : {\n" + " \"name 2\" : {\n" + " \"name 3\" : {\n" + " \"name_4\" : {\n" + " \"name_5\" : \"value\"\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : true,\n" + " \"name 3\" : false,\n" + " \"name_4\" : \"value_4\",\n" + " \"name_5\" : true\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : null,\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : null\n" + "}"); + + check_reading( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : 123,\n" + " \"name 3\" : \"value 3\",\n" + " \"name_4\" : -567\n" + "}"); + + check_reading("[\n]"); + + check_reading( + "[\n" + " 1\n" + "]"); + + check_reading( + "[\n" + " 1,\n" + " 1.2,\n" + " \"john]\",\n" + " true,\n" + " false,\n" + " null\n" + "]"); + + check_reading( + "[\n" + " 1,\n" + " [\n" + " 2,\n" + " 3\n" + " ]\n" + "]"); + + check_reading( + "[\n" + " 1,\n" + " [\n" + " 2,\n" + " 3\n" + " ],\n" + " [\n" + " 4,\n" + " [\n" + " 5,\n" + " 6,\n" + " 7\n" + " ]\n" + " ]\n" + "]"); + + check_reading( + "[\n" + " {\n" + " \"name\" : \"value\"\n" + " }\n" + "]"); + + check_reading( + "{\n" + " \"name\" : [\n" + " 1\n" + " ]\n" + "}"); + + check_reading( + "[\n" + " {\n" + " \"name 1\" : \"value\",\n" + " \"name 2\" : [\n" + " 1,\n" + " 2,\n" + " 3\n" + " ]\n" + " }\n" + "]"); + + check_reading( + "{\n" + " \"name 1\" : [\n" + " 1,\n" + " {\n" + " \"name 2\" : \"value 2\"\n" + " }\n" + " ]\n" + "}"); + + check_reading( + "[\n" + " {\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : [\n" + " 1,\n" + " 2,\n" + " {\n" + " \"name 3\" : \"value 3\"\n" + " }\n" + " ]\n" + " }\n" + "]"); + + check_reading( + "{\n" + " \"name 1\" : [\n" + " 1,\n" + " {\n" + " \"name 2\" : [\n" + " 1,\n" + " 2,\n" + " 3\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + check_reading(INT_MIN, INT_MAX); + check_reading(LLONG_MIN, LLONG_MAX); + } + + void test_reading_reals() { + Value_type value; + + const String_type in_s = to_str( + "[1.200000000000000,1.234567890123456e+125,-1.234000000000000e-123," + " 1.000000000000000e-123,1234567890.123456,123,]"); + + basic_istringstream is(in_s); + + const bool ok = read(is, value); + + assert_eq(ok, true); + assert_eq(value.type(), array_type); + + const Array_type arr = value.get_array(); + + assert_eq(arr.size(), 6u); + assert_eq(arr[0].get_real(), 1.2, 1e-16); + assert_eq(arr[1].get_real(), 1.234567890123456e+125, 1e+110); + assert_eq(arr[2].get_real(), -1.234e-123, 1e+108); + assert_eq(arr[3].get_real(), 1e-123, 1e+108); + assert_eq(arr[4].get_real(), 1234567890.123456, 1e-7); + assert_eq(arr[5].get_real(), 123, 1e-13); + } + + void test_from_stream(const char* json_str, bool expected_success, + const Error_position& expected_error) { + Value_type value; + + String_type in_s(to_str(json_str)); + + basic_istringstream is(in_s); + + const bool ok = read(is, value); + + assert_eq(ok, expected_success); + + if (ok) { + assert_eq(in_s, write(value)); + } + + try { + basic_istringstream is(in_s); + + read_or_throw(is, value); + + assert_eq(expected_success, true); + + assert_eq(in_s, write(value)); + } catch (const Error_position error) { + assert_eq(error, expected_error); + } + } + + void test_from_stream() { + test_from_stream("[1,2]", true, Error_position()); + test_from_stream("\n\n foo", false, Error_position(3, 2, "not a value")); + } + + void test_escape_chars(const char* json_str, const char* c_str) { + Value_type value; + + string s(string("{\"") + json_str + "\" : \"" + json_str + "\"} "); + + read_cstr(s.c_str(), value); + + const Pair_type& pair(*value.get_obj().begin()); + + assert_eq(Config_type::get_name(pair), to_str(c_str)); + assert_eq(Config_type::get_value(pair), to_str(c_str)); + } + + void test_escape_chars() { + test_escape_chars("\\t", "\t"); + test_escape_chars("a\\t", "a\t"); + test_escape_chars("\\tb", "\tb"); + test_escape_chars("a\\tb", "a\tb"); + test_escape_chars("a\\tb", "a\tb"); + test_escape_chars("a123\\tb", "a123\tb"); + test_escape_chars("\\t\\n\\\\", "\t\n\\"); + test_escape_chars("\\/\\r\\b\\f\\\"", "/\r\b\f\""); + test_escape_chars("\\h\\j\\k", ""); // invalid esc chars + test_escape_chars("\\x61\\x62\\x63", "abc"); + test_escape_chars("a\\x62c", "abc"); + test_escape_chars( + "\\x01\\x02\\x7F", + "\x01\x02\x7F"); // NB x7F is the greatest char spirit will parse + test_escape_chars("\\u0061\\u0062\\u0063", "abc"); + } + + void check_is_null(const char* c_str) { + assert_eq(read_cstr(c_str).type(), null_type); + } + + template + void check_value(const char* c_str, const T& expected_value) { + const Value_type v(read_cstr(c_str)); + + assert_eq(v.template get_value(), expected_value); + } + + void test_values() { + check_value("1", 1); + check_value("+Infinity", std::numeric_limits::infinity()); + check_value("Infinity", std::numeric_limits::infinity()); + check_value("-Infinity", -std::numeric_limits::infinity()); + check_value("0xfe", 0xfe); + check_value("1.5", 1.5); + check_value("\"Test\"", to_str("Test")); + check_value("true", true); + check_value("false", false); + check_is_null("null"); + } + + void check_read_fails(const char* c_str, int line, int column, + const string& reason) { + Value_type value; + + try { + read_cstr(c_str, value); + + assert(false); + } catch (const Error_position posn) { + assert_eq(posn, Error_position(line, column, reason)); + } + } + + void test_error_cases() { + check_read_fails("", 1, 1, "not a value"); + check_read_fails("foo", 1, 1, "not a value"); + check_read_fails(" foo", 1, 2, "not a value"); + check_read_fails(" foo", 1, 3, "not a value"); + check_read_fails("\n\n foo", 3, 2, "not a value"); + check_read_fails("!!!", 1, 1, "not a value"); + check_read_fails("\"bar", 1, 1, "not a value"); + check_read_fails("0xreefer", 1, 3, "not a hexadecimal number"); + check_read_fails("bar\"", 1, 1, "not a value"); + check_read_fails("[1}", 1, 3, "not an array"); + check_read_fails("[1,2?", 1, 5, "not an array"); + check_read_fails("[1,2}", 1, 5, "not an array"); + check_read_fails("[1;2]", 1, 3, "not an array"); + check_read_fails("{\"name\":\"value\"]", 1, 16, "not an object"); + check_read_fails("{\"name\",\"value\"}", 1, 8, "no colon in pair"); + check_read_fails("{\n1:\"value\"}", 2, 1, "not an object"); + check_read_fails("{\n name\":\"value\"}", 2, 7, "no colon in pair"); + check_read_fails("{\"name\":foo}", 1, 9, "not a value"); + check_read_fails("{\"name\":0xfreedom}", 1, 12, "not an object"); + check_read_fails("{\"name\":value\"}", 1, 9, "not a value"); + check_read_fails("{'name':\"value\"}", 1, 2, "not an object"); + } + + typedef vector Ints; + + bool test_read_range(Iter_type& first, Iter_type last, Value_type& value) { + Iter_type first_ = first; + + const bool ok = read(first, last, value); + + try { + Value_type value_; + + read_or_throw(first_, last, value_); + + assert_eq(ok, true); + assert_eq(value, value_); + } catch (...) { + assert_eq(ok, false); + } + + return ok; + } + + void check_value_sequence(Iter_type first, Iter_type last, + const Ints& expected_values, bool all_input_consumed) { + Value_type value; + + for (Ints::size_type i = 0; i < expected_values.size(); ++i) { + const bool ok = test_read_range(first, last, value); + + assert_eq(ok, true); + + const bool is_last(i == expected_values.size() - 1); + + assert_eq(first == last, is_last ? all_input_consumed : false); + } + + const bool ok = test_read_range(first, last, value); + + assert_eq(ok, false); + } + + void check_value_sequence(Istream_type& is, const Ints& expected_values, + bool all_input_consumed) { + Value_type value; + + for (Ints::size_type i = 0; i < expected_values.size(); ++i) { + read_or_throw(is, value); + + assert_eq(value.get_int(), expected_values[i]); + + const bool is_last(i == expected_values.size() - 1); + + assert_eq(is.eof(), is_last ? all_input_consumed : false); + } + + try { + read_or_throw(is, value); + + assert(false); + } catch (...) { + } + + assert_eq(is.eof(), true); + } + + void check_value_sequence(const char* c_str, const Ints& expected_values, + bool all_input_consumed) { + const String_type s(to_str(c_str)); + + check_value_sequence(s.begin(), s.end(), expected_values, all_input_consumed); + + Istringstream_type is(s); + + check_value_sequence(is, expected_values, all_input_consumed); + } + + void check_array(const Value_type& value, + typename Array_type::size_type expected_size) { + assert_eq(value.type(), array_type); + + const Array_type& arr = value.get_array(); + + assert_eq(arr.size(), expected_size); + + for (typename Array_type::size_type i = 0; i < expected_size; ++i) { + const Value_type& val = arr[i]; + + assert_eq(val.type(), int_type); + assert_eq(val.get_int(), int(i + 1)); + } + } + + void check_reading_array(Iter_type& begin, Iter_type end, + typename Array_type::size_type expected_size) { + Value_type value; + + test_read_range(begin, end, value); + + check_array(value, expected_size); + } + + void check_reading_array(Istream_type& is, + typename Array_type::size_type expected_size) { + Value_type value; + + read(is, value); + + check_array(value, expected_size); + } + + void check_reading_arrays(const char* arrays_str) { + const String_type str(to_str(arrays_str)); + + Iter_type begin = str.begin(); + const Iter_type end = str.end(); + + check_reading_array(begin, end, 0); + check_reading_array(begin, end, 1); + check_reading_array(begin, end, 2); + check_reading_array(begin, end, 3); + + Istringstream_type is(str); + + check_reading_array(is, 0); + is.unget(); + check_reading_array(is, 1); + is.unget(); + check_reading_array(is, 2); + is.unget(); + check_reading_array(is, 3); + } + + void test_sequence_of_values() { + check_value_sequence("", Ints(), false); + check_value_sequence(" ", Ints(), false); + check_value_sequence(" ", Ints(), false); + check_value_sequence(" 10 ", list_of(10), false); + check_value_sequence(" 10 11 ", list_of(10)(11), false); + check_value_sequence(" 10 11 12", list_of(10)(11)(12), true); + check_value_sequence("10 11 12", list_of(10)(11)(12), true); + + // Note: check_reading_arrays() expects exactly this list of arrays. + check_reading_arrays("[] [ 1 ] [ 1, 2 ] [ 1, 2, 3 ]"); + check_reading_arrays("[][1][1,2][1,2,3]"); + } + + void test_uint64(const char* value_str, int expected_int, int64_t expected_int64, + uint64_t expected_uint64) { + const Value_type v(read_cstr(value_str)); + + assert_eq(v.get_int(), expected_int); + assert_eq(v.get_int64(), expected_int64); + assert_eq(v.get_uint64(), expected_uint64); + } + + void test_uint64() { + test_uint64("0", 0, 0, 0); + test_uint64("1", 1, 1, 1); + test_uint64("-1", -1, -1, ULLONG_MAX); + test_uint64("18446744073709551615", -1, -1, ULLONG_MAX); + } + + void test_types() { + Value_type value; + + read(to_str("[ \"foo\", true, false, 1, 12.3, null ]"), value); + + assert_eq(value.type(), array_type); + + const Array_type& a = value.get_array(); + + assert_eq(a[0].get_str(), to_str("foo")); + assert_eq(a[1].get_bool(), true); + assert_eq(a[2].get_bool(), false); + assert_eq(a[3].get_int(), 1); + assert_eq(a[3].get_int64(), 1); + assert_eq(a[3].get_uint64(), 1u); + assert_eq(a[3].get_real(), 1.0); + assert_eq(a[4].get_real(), 12.3); + assert_eq(a[5].is_null(), true); + } + + void test_comments() { + Value_type value_1; + + read_cstr( + "{\n" + " \"name 1\" : \"value 1\",\n" + " \"name 2\" : \"value 2 /* not a comment but data */\",\n" + " \"name 3\" : \"value 3 // not a comment but data\"\n" + "}", + value_1); + + Value_type value_2; + + read_cstr( + "{// a comment\n " + " \"name 1\" : /* another comment */ \"value 1\",\n" + " \"name 2\" : \"value 2 /* not a comment but data */\",\n" + " // \"name 2\" : \"value 2\",\n" + " \"name 3\" : \"value 3 // not a comment but data\"\n" + "/* multi\n" + "line\n" + "comment */}", + value_2); + + assert_eq(value_1, value_2); + } + + void run_tests() { + std::cout << " before test_syntax()" << std::endl; + test_syntax(); + std::cout << " before test_reading()" << std::endl; + test_reading(); + std::cout << " before test_reading_reals()" << std::endl; + test_reading_reals(); + std::cout << " before test_from_stream()" << std::endl; + test_from_stream(); + std::cout << " before test_escape_chars()" << std::endl; + test_escape_chars(); + std::cout << " before test_values()" << std::endl; + test_values(); + std::cout << " before test_error_cases()" << std::endl; + test_error_cases(); + std::cout << " before test_sequence_of_values()" << std::endl; + test_sequence_of_values(); + std::cout << " before test_uint64()" << std::endl; + test_uint64(); + std::cout << " before test_types()" << std::endl; + test_types(); + std::cout << " before test_comments()" << std::endl; + test_comments(); + } +}; + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void test_wide_esc_u() { + wValue value; + + test_read(L"[\"\\uABCD\"]", value); + + const wstring s(value.get_array()[0].get_str()); + + assert_eq(s.length(), static_cast(1u)); + assert_eq(s[0], 0xABCD); +} +#endif + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void test_extended_ascii(const string& s) { + Value value; + + test_read("[\"" + s + "\"]", value); + + assert_eq(value.get_array()[0].get_str(), ""); +} + +void test_extended_ascii() { + test_extended_ascii("\\u00E4\\u00F6\\u00FC\\u00DF"); + test_extended_ascii(""); +} +#endif +} // namespace + +//#include + +void json5_parser::test_reader() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + std::cout << " JSON_SPIRIT_VALUE_ENABLED" << std::endl; + Test_runner().run_tests(); + test_extended_ascii(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + std::cout << " JSON_SPIRIT_MVALUE_ENABLED" << std::endl; + Test_runner().run_tests(); +#endif +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + std::cout << " defined(JSON_SPIRIT_WVALUE_ENABLED) && " + "!defined(BOOST_NO_STD_WSTRING)" + << std::endl; + Test_runner().run_tests(); + test_wide_esc_u(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + std::cout << " defined(JSON_SPIRIT_WMVALUE_ENABLED) && " + "!defined(BOOST_NO_STD_WSTRING)" + << std::endl; + Test_runner().run_tests(); +#endif + +#ifndef _DEBUG + // ifstream ifs( "test.txt" ); + + // string s; + + // getline( ifs, s ); + + // timer t; + + // for( int i = 0; i < 2000; ++i ) + //{ + // Value value; + + // read( s, value ); + //} + + // cout << t.elapsed() << endl; + + // const string so = write( value ); + + // Object obj; + + // for( int i = 0; i < 100000; ++i ) + //{ + // obj.push_back( Pair( "\x01test\x7F", lexical_cast< string >( i ) ) ); + //} + + // const string s = write( obj ); + + // Value value; + + // timer t; + + // read( s, value ); + + // cout << t.elapsed() << endl; + + // cout << "obj size " << value.get_obj().size(); +#endif +} diff --git a/json_test/json5_parser_reader_test.h b/json_test/json5_parser_reader_test.h index 02542f9..2896798 100644 --- a/json_test/json5_parser_reader_test.h +++ b/json_test/json5_parser_reader_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_READER_TEST -#define JSON_SPIRIT_READER_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_reader(); -} - -#endif +#ifndef JSON_SPIRIT_READER_TEST +#define JSON_SPIRIT_READER_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_reader(); +} + +#endif diff --git a/json_test/json5_parser_stream_reader_test.cpp b/json_test/json5_parser_stream_reader_test.cpp index 359b9d0..9638980 100644 --- a/json_test/json5_parser_stream_reader_test.cpp +++ b/json_test/json5_parser_stream_reader_test.cpp @@ -1,137 +1,120 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_stream_reader_test.h" -#include "utils_test.h" -#include "json5_parser_stream_reader.h" - -#include -#include - -using namespace json5_parser; -using namespace std; -using namespace boost; -using namespace boost::assign; - -namespace -{ - template< class Config_type > - struct Test_runner - { - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - typedef typename Config_type::Pair_type Pair_type; - typedef typename String_type::value_type Char_type; - typedef typename String_type::const_iterator Iter_type; - typedef std::basic_istringstream< Char_type > Istringstream_type; - typedef std::basic_istream< Char_type > Istream_type; - - String_type to_str( const char* c_str ) - { - return ::to_str< String_type >( c_str ); - } - - Test_runner() - { - } - - void check_stream_reader( Stream_reader< Istream_type, Value_type >& reader, const vector< int >& expected_result ) - { - Value_type v; - const bool ok = reader.read_next( v ); - assert_eq( ok, true ); - assert_eq( v.type(), array_type ); - assert_eq( v.get_array().size(), expected_result.size() ); - for( vector< int >::size_type i = 0; i < v.get_array().size(); ++i ) - { - assert_eq( v.get_array()[i], expected_result[i] ); - } - } - - void check_stream_read_or_throw( Stream_reader_thrower< Istream_type, Value_type >& reader, const vector< int >& expected_result ) - { - Value_type v; - - try - { - reader.read_next( v ); - assert_eq( v.type(), array_type ); - assert_eq( v.get_array().size(), expected_result.size() ); - for( vector< int >::size_type i = 0; i < v.get_array().size(); ++i ) - { - assert_eq( v.get_array()[i], expected_result[i] ); - } - } - catch( ... ) - { - assert( false ); - } - } - - void test_stream_reader( const char* s ) - { - { - Istringstream_type is( to_str( s ) ); - - Stream_reader< Istream_type, Value_type > reader( is ); - - check_stream_reader( reader, vector< int >() ); - check_stream_reader( reader, list_of( 1 ) ); - check_stream_reader( reader, list_of( 1 )( 2 ) ); - check_stream_reader( reader, list_of( 1 )( 2 )( 3 ) ); - - Value_type v; - const bool ok = reader.read_next( v ); - assert_eq( ok, false ); - } - { - Istringstream_type is( to_str( s ) ); - - Stream_reader_thrower< Istream_type, Value_type > reader( is ); - - check_stream_read_or_throw( reader, vector< int >() ); - check_stream_read_or_throw( reader, list_of( 1 ) ); - check_stream_read_or_throw( reader, list_of( 1 )( 2 ) ); - check_stream_read_or_throw( reader, list_of( 1 )( 2 )( 3 ) ); - - try - { - Value_type v; - reader.read_next( v ); - assert( false ); - } - catch( ... ) - { - } - } - } - - void run_tests() - { - test_stream_reader( "[][1][1,2][1,2,3]" ); - test_stream_reader( "[] [1] [1,2] [1,2,3]" ); - test_stream_reader( " [] [1] [1,2] [1,2,3] " ); - } - }; -} - -void json5_parser::test_stream_reader() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Test_runner< Config >().run_tests(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Test_runner< mConfig >().run_tests(); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wConfig >().run_tests(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wmConfig >().run_tests(); -#endif -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_stream_reader_test.h" +#include "json5_parser_stream_reader.h" +#include "utils_test.h" + +#include +#include + +using namespace json5_parser; +using namespace std; +using namespace boost; +using namespace boost::assign; + +namespace { +template +struct Test_runner { + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + typedef typename Config_type::Pair_type Pair_type; + typedef typename String_type::value_type Char_type; + typedef typename String_type::const_iterator Iter_type; + typedef std::basic_istringstream Istringstream_type; + typedef std::basic_istream Istream_type; + + String_type to_str(const char* c_str) { return ::to_str(c_str); } + + Test_runner() {} + + void check_stream_reader(Stream_reader& reader, + const vector& expected_result) { + Value_type v; + const bool ok = reader.read_next(v); + assert_eq(ok, true); + assert_eq(v.type(), array_type); + assert_eq(v.get_array().size(), expected_result.size()); + for (vector::size_type i = 0; i < v.get_array().size(); ++i) { + assert_eq(v.get_array()[i], expected_result[i]); + } + } + + void check_stream_read_or_throw( + Stream_reader_thrower& reader, + const vector& expected_result) { + Value_type v; + + try { + reader.read_next(v); + assert_eq(v.type(), array_type); + assert_eq(v.get_array().size(), expected_result.size()); + for (vector::size_type i = 0; i < v.get_array().size(); ++i) { + assert_eq(v.get_array()[i], expected_result[i]); + } + } catch (...) { + assert(false); + } + } + + void test_stream_reader(const char* s) { + { + Istringstream_type is(to_str(s)); + + Stream_reader reader(is); + + check_stream_reader(reader, vector()); + check_stream_reader(reader, list_of(1)); + check_stream_reader(reader, list_of(1)(2)); + check_stream_reader(reader, list_of(1)(2)(3)); + + Value_type v; + const bool ok = reader.read_next(v); + assert_eq(ok, false); + } + { + Istringstream_type is(to_str(s)); + + Stream_reader_thrower reader(is); + + check_stream_read_or_throw(reader, vector()); + check_stream_read_or_throw(reader, list_of(1)); + check_stream_read_or_throw(reader, list_of(1)(2)); + check_stream_read_or_throw(reader, list_of(1)(2)(3)); + + try { + Value_type v; + reader.read_next(v); + assert(false); + } catch (...) { + } + } + } + + void run_tests() { + test_stream_reader("[][1][1,2][1,2,3]"); + test_stream_reader("[] [1] [1,2] [1,2,3]"); + test_stream_reader(" [] [1] [1,2] [1,2,3] "); + } +}; +} // namespace + +void json5_parser::test_stream_reader() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Test_runner().run_tests(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + Test_runner().run_tests(); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); +#endif +} diff --git a/json_test/json5_parser_stream_reader_test.h b/json_test/json5_parser_stream_reader_test.h index 1b9f102..495db4c 100644 --- a/json_test/json5_parser_stream_reader_test.h +++ b/json_test/json5_parser_stream_reader_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_STREAM_READER_TEST -#define JSON_SPIRIT_STREAM_READER_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_stream_reader(); -} - -#endif +#ifndef JSON_SPIRIT_STREAM_READER_TEST +#define JSON_SPIRIT_STREAM_READER_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_stream_reader(); +} + +#endif diff --git a/json_test/json5_parser_utils_test.cpp b/json_test/json5_parser_utils_test.cpp index e5ee9c3..bf62b4b 100644 --- a/json_test/json5_parser_utils_test.cpp +++ b/json_test/json5_parser_utils_test.cpp @@ -1,143 +1,131 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_utils_test.h" -#include "utils_test.h" -#include "json5_parser_utils.h" - -#include - -using namespace json5_parser; -using namespace std; -using namespace boost::assign; - -namespace -{ - template< class Obj_t, class Map_t > - struct Test_runner - { - typedef typename Map_t::key_type String_type; - typedef typename Obj_t::value_type Pair_type; - typedef typename Pair_type::Value_type Value_type; - - String_type to_str( const char* c_str ) - { - return ::to_str< String_type >( c_str ); - } - - void assert_equal( const Obj_t& obj, const Map_t& mp_obj ) - { - typename Obj_t::size_type obj_size = obj.size(); - typename Map_t::size_type map_size = mp_obj.size(); - - assert_eq( obj_size, map_size ); - - for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) - { - assert_eq( mp_obj.find( i->name_ )->second, i->value_ ); - } - } - - void check_obj_to_map( const Obj_t& obj ) - { - Map_t mp_obj; - - obj_to_map( obj, mp_obj ); - - assert_equal( obj, mp_obj ); - } - - void check_map_cleared() - { - Map_t mp_obj; - - mp_obj[ to_str( "del" ) ] = to_str( "me" ); - - obj_to_map( Obj_t(), mp_obj ); - - assert_eq( mp_obj.size(), 0u ); - } - - void check_map_to_obj( const Map_t& mp_obj ) - { - Obj_t obj; - - map_to_obj( mp_obj, obj ); - - assert_equal( obj, mp_obj ); - } - - void check_obj_cleared() - { - Obj_t obj; - - obj.push_back( Pair_type( to_str( "del" ), to_str( "me" ) ) ); - - map_to_obj( Map_t(), obj ); - - assert_eq( obj.size(), 0u ); - } - - void test_obj_to_map() - { - check_obj_to_map( Obj_t() ); - check_obj_to_map( list_of( Pair_type( to_str( "a" ), 1 ) ) ); - check_obj_to_map( list_of( Pair_type( to_str( "a" ), 1 ) )( Pair_type( to_str( "b" ), 2 ) ) ); - check_obj_to_map( list_of( Pair_type( to_str( "a" ), 1 ) )( Pair_type( to_str( "b" ), 2 ) )( Pair_type( to_str( "c" ), 3 ) ) ); - check_map_cleared(); - - check_map_to_obj( Map_t() ); - check_map_to_obj( map_list_of( to_str( "a" ), 1 ) ); - check_map_to_obj( map_list_of( to_str( "a" ), 1 )( to_str( "b" ), 2 ) ); - check_map_to_obj( map_list_of( to_str( "a" ), 1 )( to_str( "b" ), 2 )( to_str( "c" ), 3 ) ); - check_obj_cleared(); - } - - void check_find( const Obj_t& obj, const char* name, const Value_type& expected_result ) - { - const Value_type& result = find_value( obj, to_str( name ) ); - - assert_eq( result, expected_result ); - } - - void test_find() - { - check_find( Obj_t(), "not there", Value_type::null ); - - const Obj_t obj_1 = list_of( Pair_type( to_str( "a" ), 1 ) ); - - check_find( obj_1, "not there", Value_type::null ); - check_find( obj_1, "a", 1 ); - - const Obj_t obj_2 = list_of( Pair_type( to_str( "a" ), 1 ) )( Pair_type( to_str( "ab" ), 2 ) ); - - check_find( obj_2, "a", 1 ); - check_find( obj_2, "ab", 2 ); - - const Obj_t obj_3 = list_of( Pair_type( to_str( "a" ), 1 ) )( Pair_type( to_str( "ab" ), 2 ) )( Pair_type( to_str( "abc" ), 3 ) ); - - check_find( obj_3, "a", 1 ); - check_find( obj_3, "ab", 2 ); - check_find( obj_3, "abc", 3 ); - } - - void run_tests() - { - test_obj_to_map(); - test_find(); - } - }; -} - -void json5_parser::test_utils() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Test_runner< Object, Mapped_obj >().run_tests(); -#endif - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wObject, wMapped_obj >().run_tests(); -#endif -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_utils_test.h" +#include "json5_parser_utils.h" +#include "utils_test.h" + +#include + +using namespace json5_parser; +using namespace std; +using namespace boost::assign; + +namespace { +template +struct Test_runner { + typedef typename Map_t::key_type String_type; + typedef typename Obj_t::value_type Pair_type; + typedef typename Pair_type::Value_type Value_type; + + String_type to_str(const char* c_str) { return ::to_str(c_str); } + + void assert_equal(const Obj_t& obj, const Map_t& mp_obj) { + typename Obj_t::size_type obj_size = obj.size(); + typename Map_t::size_type map_size = mp_obj.size(); + + assert_eq(obj_size, map_size); + + for (typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i) { + assert_eq(mp_obj.find(i->name_)->second, i->value_); + } + } + + void check_obj_to_map(const Obj_t& obj) { + Map_t mp_obj; + + obj_to_map(obj, mp_obj); + + assert_equal(obj, mp_obj); + } + + void check_map_cleared() { + Map_t mp_obj; + + mp_obj[to_str("del")] = to_str("me"); + + obj_to_map(Obj_t(), mp_obj); + + assert_eq(mp_obj.size(), 0u); + } + + void check_map_to_obj(const Map_t& mp_obj) { + Obj_t obj; + + map_to_obj(mp_obj, obj); + + assert_equal(obj, mp_obj); + } + + void check_obj_cleared() { + Obj_t obj; + + obj.push_back(Pair_type(to_str("del"), to_str("me"))); + + map_to_obj(Map_t(), obj); + + assert_eq(obj.size(), 0u); + } + + void test_obj_to_map() { + check_obj_to_map(Obj_t()); + check_obj_to_map(list_of(Pair_type(to_str("a"), 1))); + check_obj_to_map(list_of(Pair_type(to_str("a"), 1))(Pair_type(to_str("b"), 2))); + check_obj_to_map(list_of(Pair_type(to_str("a"), 1))(Pair_type(to_str("b"), 2))( + Pair_type(to_str("c"), 3))); + check_map_cleared(); + + check_map_to_obj(Map_t()); + check_map_to_obj(map_list_of(to_str("a"), 1)); + check_map_to_obj(map_list_of(to_str("a"), 1)(to_str("b"), 2)); + check_map_to_obj(map_list_of(to_str("a"), 1)(to_str("b"), 2)(to_str("c"), 3)); + check_obj_cleared(); + } + + void check_find(const Obj_t& obj, const char* name, + const Value_type& expected_result) { + const Value_type& result = find_value(obj, to_str(name)); + + assert_eq(result, expected_result); + } + + void test_find() { + check_find(Obj_t(), "not there", Value_type::null); + + const Obj_t obj_1 = list_of(Pair_type(to_str("a"), 1)); + + check_find(obj_1, "not there", Value_type::null); + check_find(obj_1, "a", 1); + + const Obj_t obj_2 = + list_of(Pair_type(to_str("a"), 1))(Pair_type(to_str("ab"), 2)); + + check_find(obj_2, "a", 1); + check_find(obj_2, "ab", 2); + + const Obj_t obj_3 = list_of(Pair_type(to_str("a"), 1))( + Pair_type(to_str("ab"), 2))(Pair_type(to_str("abc"), 3)); + + check_find(obj_3, "a", 1); + check_find(obj_3, "ab", 2); + check_find(obj_3, "abc", 3); + } + + void run_tests() { + test_obj_to_map(); + test_find(); + } +}; +} // namespace + +void json5_parser::test_utils() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Test_runner().run_tests(); +#endif + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); +#endif +} diff --git a/json_test/json5_parser_utils_test.h b/json_test/json5_parser_utils_test.h index 7c80523..fb07418 100644 --- a/json_test/json5_parser_utils_test.h +++ b/json_test/json5_parser_utils_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_UTILS_TEST -#define JSON_SPIRIT_UTILS_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_utils(); -} - -#endif +#ifndef JSON_SPIRIT_UTILS_TEST +#define JSON_SPIRIT_UTILS_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_utils(); +} + +#endif diff --git a/json_test/json5_parser_value_test.cpp b/json_test/json5_parser_value_test.cpp index 63eec79..5c650a4 100644 --- a/json_test/json5_parser_value_test.cpp +++ b/json_test/json5_parser_value_test.cpp @@ -1,529 +1,533 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_value_test.h" -#include "utils_test.h" -#include "json5_parser_value.h" -#include -#include -#include -#include - -using namespace json5_parser; -using namespace std; -using namespace boost; -using namespace boost::assign; - -namespace -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - - const int64_t max_int64 = integer_traits< int64_t >::max(); - const uint64_t max_uint64 = integer_traits< uint64_t >::max(); - - void test_obj_value() - { - const Pair p1( "name1", "value1" ); - const Pair p3( "name3", "value3" ); - - Object obj_1; obj_1.push_back( p1 ); - Object obj_2; obj_2.push_back( p1 ); - Object obj_3; obj_3.push_back( p3 ); - - Value v1( obj_1 ); - Value v2( obj_2 ); - Value v3( obj_3 ); - - assert_eq( v1.type(), obj_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - assert_eq( v1.get_obj(), obj_1 ); - assert_eq( v3.get_obj(), obj_3 ); - } - - void test_array_value() - { - Array array_1; array_1.push_back( 1 ); array_1.push_back( "2" ); - Array array_2; array_2.push_back( 1 ); array_2.push_back( "2" ); - Array array_3; array_3.push_back( 1 ); array_3.push_back( "X" ); - - Value v1( array_1 ); - Value v2( array_2 ); - Value v3( array_3 ); - - assert_eq( v1.type(), array_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - assert_eq( v1.get_array(), array_1 ); - assert_eq( v3.get_array(), array_3 ); - } - - void test_bool_value() - { - Value v1( true ); - Value v2( true ); - Value v3( false ); - - assert_eq( v1.type(), bool_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - assert( v1.get_bool() ); - assert( !v3.get_bool() ); - } - - void test_int_value() - { - Value v1( 1 ); - Value v2( 1 ); - Value v3( INT_MAX ); - - assert_eq( v1.type(), int_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - unsigned int uint_max = INT_MAX; - - assert_eq( v1.get_int(), 1 ); - assert_eq( v1.get_int64(), 1 ); - assert_eq( v1.get_uint64(), 1u ); - assert_eq( v3.get_int(), INT_MAX ); - assert_eq( v3.get_int64(), INT_MAX ); - assert_eq( v3.get_uint64(), uint_max ); - - Value v4( max_int64 ); - - assert_eq( v4.get_int64(), max_int64 ); - assert_eq( v4.get_uint64(), static_cast< uint64_t >( max_int64 ) ); - - const uint64_t max_int64_plus_1 = max_int64 + uint64_t( 1 ); - - Value v5( max_int64_plus_1 ); - - assert_eq( v5.get_uint64(), max_int64_plus_1 ); - - Value v6( max_uint64 ); - - assert_eq( v6.get_uint64(), max_uint64 ); - - Value v7( 0 ); - - assert_eq( v7.get_int(), 0 ); - assert_eq( v7.get_int64(), 0 ); - assert_eq( v7.get_uint64(), 0u ); - - Value v8( -1 ); - - assert_eq( v8.get_int(), -1 ); - assert_eq( v8.get_int64(), -1 ); - assert_eq( v8.get_uint64(), max_uint64 ); - } - - void test_real_value() - { - Value v1( 1.0 ); - Value v2( 1.0 ); - Value v3( 2.0 ); - - assert_eq( v1.type(), real_type ); - assert_eq ( v1, v2 ); - assert_neq( v1, v3 ); - - assert_eq( v1.get_real(), 1.0 ); - assert_eq( v3.get_real(), 2.0 ); - } - - void test_null_value() - { - Value v1; - Value v2; - - assert_eq( v1.type(), null_type ); - assert_eq( v1.is_null(), true ); - assert_eq( v1, v2 ); - assert_eq( v1.is_null(), true ); - assert_eq( Value( 1 ).is_null(), false ); - } - - template< typename T > - void test_get_value( const T& t ) - { - assert_eq( Value( t ).get_value< T >(), t ); - } - - void test_get_value() - { - test_get_value( 123 ); - test_get_value( max_int64 ); - test_get_value( 1.23 ); - test_get_value( true ); - test_get_value( false ); - test_get_value( string( "test" ) ); - - Array a; a.push_back( 1 ); a.push_back( "2" ); - - test_get_value( a ); - - Object obj; obj.push_back( Pair( "name1", "value1" ) ); - - test_get_value( obj ); - } - - void assert_array_eq( const Value& v, const Array& a ) - { - assert_eq( v.get_array(), a ); - } - - void assert_obj_eq( const Value& v, const Object& obj ) - { - assert_eq( v.get_obj(), obj ); - } - - template< typename T > - void check_copy( const T& t ) - { - const Value v1( t ); - const Value v2( v1 ); - Value v3; - v3 = v1; - - assert_eq( v1, v2 ); - assert_eq( v1, v3 ); - - assert_eq( v2.get_value< T >(), t ); - assert_eq( v3.get_value< T >(), t ); - - assert_eq( v1.is_uint64(), v2.is_uint64() ); - assert_eq( v1.is_uint64(), v3.is_uint64() ); - } - - void check_copying_null() - { - const Value v1; - const Value v2( v1 ); - Value v3; - v3 = v1; - - assert_eq( v2.type(), null_type ); - assert_eq( v3.type(), null_type ); - } - - void test_copying() - { - { - const Array array_1 = list_of(1)(2); - - Value v1( array_1 ); - const Value v2( v1 ); - - assert_array_eq( v1, array_1 ); - assert_array_eq( v2, array_1 ); - - v1.get_array()[0] = 3; - - assert_array_eq( v1, list_of(3)(2) ); - assert_array_eq( v2, array_1 ); - } - { - const Object obj_1 = list_of( Pair( "a", 1 ) )( Pair( "b", 2 ) ); - - Value v1( obj_1 ); - Value v2; - - v2 = v1; - - assert_obj_eq( v1, obj_1 ); - assert_obj_eq( v2, obj_1 ); - - v1.get_obj()[0] = Pair( "c", 3 ); - - assert_obj_eq( v1, list_of( Pair( "c", 3 ) )( Pair( "b", 2 ) ) ); - assert_obj_eq( v2, obj_1 ); - } - { - check_copy( 1 ); - check_copy( 2.0 ); - check_copy( max_int64 ); - check_copy( max_uint64 ); - check_copy( string("test") ); - check_copy( true ); - check_copy( false ); - const Array array_1 = list_of(1)(2); - check_copy( array_1 ); - const Object obj_1 = list_of( Pair( "a", 1 ) )( Pair( "b", 2 ) ); - check_copy( obj_1 ); - check_copying_null(); - } - } - - void test_obj_map_implemention() - { -#ifdef JSON_SPIRIT_MVALUE_ENABLED - mObject obj; - - obj[ "name 1" ] = 1; - obj[ "name 2" ] = "two"; - - assert_eq( obj.size(), 2u ); - - assert_eq( obj.find( "name 1" )->second.get_int(), 1 ); - assert_eq( obj.find( "name 2" )->second.get_str(), "two" ); -#endif - } - - template< typename Int > - void check_an_int_is_a_real( Int i, bool expected_result ) - { - assert_eq( Value( i ).is_uint64(), expected_result ); - } - - void test_is_uint64() - { - check_an_int_is_a_real( 1, false ); - check_an_int_is_a_real( static_cast< int64_t >( 1 ), false ); - check_an_int_is_a_real( static_cast< uint64_t >( 1 ), true ); - } - - template< typename Int > - void check_an_int_is_a_real( Int i, double expected_result ) - { - assert_eq( Value( i ).get_real(), expected_result ); - } - - void test_an_int_is_a_real() - { - check_an_int_is_a_real( -1, -1.0 ); - check_an_int_is_a_real( 0, 0.0 ); - check_an_int_is_a_real( 1, 1.0 ); - check_an_int_is_a_real( max_int64, 9223372036854775800.0 ); - check_an_int_is_a_real( max_uint64, 18446744073709552000.0 ); - } - - template< typename T > - void check_wrong_type_exceptions( const Value& v, const string& requested_type_name, const string& actual_type_name ) - { - try - { - v.get_value< T >(); - - assert( false ); - } - catch( const runtime_error& e ) - { - ostringstream os; - - os << "get_value< " << requested_type_name << " > called on " << actual_type_name << " Value"; - - assert_eq( e.what(), os.str() ); - } - } - - template< typename T > - void check_wrong_type_exceptions( const string& requested_type_name ) - { - Value v; - - assert_eq( v.type(), null_type ); - - check_wrong_type_exceptions< T >( v, requested_type_name, "null" ); - } - - void test_wrong_type_exceptions() - { - check_wrong_type_exceptions< Object >( "Object" ); - check_wrong_type_exceptions< Array >( "Array" ); - check_wrong_type_exceptions< string >( "string" ); - check_wrong_type_exceptions< bool >( "boolean"); - check_wrong_type_exceptions< boost::int64_t >( "integer" ); - check_wrong_type_exceptions< int >( "integer" ); - check_wrong_type_exceptions< double >( "real" ); - - Value v( "string" ); - - assert_eq( v.type(), str_type ); - - check_wrong_type_exceptions< double >( v, "real", "string" ); - } -#endif - - template< class Config_type > - class Container_constructor_runner - { - public: - - Container_constructor_runner() - { - vector< double > vd = list_of( 1.2 )( 1.3 ); test_container_constructor( vd ); - vector< int > vi = list_of( 1 ); test_container_constructor( vi ); - vi = list_of( 1 )( 2 ); test_container_constructor( vi ); - vi = list_of( 1 )( 2 )( 3 ); test_container_constructor( vi ); - list< double > ld = list_of( 1.2 )( 1.3 ); test_container_constructor( ld ); - list< int > li = list_of( 1 ); test_container_constructor( li ); - li = list_of( 1 )( 2 ); test_container_constructor( li ); - li = list_of( 1 )( 2 )( 3 ); test_container_constructor( li ); - } - - private: - - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - - template< class Cont > - void test_container_constructor( const Cont& cont ) - { - typedef typename Cont::value_type Cont_value_type; - const Value_type val( cont.begin(), cont.end() ); - const Array_type& arr = val.get_array(); - Cont result; - for( unsigned int i = 0; i < arr.size(); ++i ) - { - result.push_back( arr[i].template get_value< Cont_value_type>() ); - } - assert_eq( result, cont ); - } - }; - - void test_container_constructor() - { -#ifdef JSON_SPIRIT_VALUE_ENABLED - Container_constructor_runner< Config >(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Container_constructor_runner< mConfig >(); -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Container_constructor_runner< wConfig >(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Container_constructor_runner< wmConfig >(); -#endif - } - - template< class Config_type > - class Variant_constructor_runner - { - public: - - Variant_constructor_runner() - { - test_variant_constructor< variant< int, double > >( 1.23 ); - test_variant_constructor< variant< int, double > >( 123 ); - test_variant_constructor< variant< int, double, String_type > >( to_str< String_type >( "foo" ) ); - test_variant_constructor< variant< int, double, String_type, bool > >( true ); - test_variant_constructor< variant< int, double, String_type, bool, boost::int64_t > >( boost::int64_t( 123 ) ); - test_variant_constructor< variant< int, double, String_type, bool, boost::uint64_t > >( boost::uint64_t( 123 ) ); - - { - variant< int, Null > variant = Null(); - const Value_type val( variant ); - assert( val.is_null() ); - } - - vector< double > vd = list_of( 1.2 )( 1.3 ); test_variant_array_constructor< double > ( vd ); - vector< int > vi = list_of( 1 ); test_variant_array_constructor< int >( vi ); - vi = list_of( 1 )( 2 ); test_variant_array_constructor< int >( vi ); - vi = list_of( 1 )( 2 )( 3 ); test_variant_array_constructor< int >( vi ); - list< double > ld = list_of( 1.2 )( 1.3 ); test_variant_array_constructor< double >( ld ); - list< int > li = list_of( 1 ); test_variant_array_constructor< int >( li ); - li = list_of( 1 )( 2 ); test_variant_array_constructor< int >( li ); - li = list_of( 1 )( 2 )( 3 ); test_variant_array_constructor< int >( li ); - } - - private: - - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - - template< class Variant_t, typename T > - void test_variant_constructor( const T& t ) - { - const Variant_t variant( t ); - const Value_type val( variant ); - assert_eq( val.template get_value< T >(), t ); - } - - template< typename T, typename A, template< typename, typename > class Cont > - void test_variant_array_constructor( const Cont< T, A >& cont ) - { - const variant< int, Cont< T, A > > variant = cont; - const Value_type val( variant ); - const Array_type& arr = val.get_array(); - Cont< T, A > result; - for( unsigned int i = 0; i < arr.size(); ++i ) - { - result.push_back( arr[i].template get_value< T >() ); - } - assert_eq( result, cont ); - } - }; - - void test_variant_constructor() - { -#ifdef JSON_SPIRIT_VALUE_ENABLED - Variant_constructor_runner< Config >(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Variant_constructor_runner< mConfig >(); - -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Variant_constructor_runner< wConfig >(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Variant_constructor_runner< wmConfig >(); -#endif - } -} - -void json5_parser::test_value() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Object obj; - Value value_str ( "value" ); - Value value_obj ( obj ); - Value value_bool( true ); - - Value value_str_2 ( string( "value" ) ); - Value value_obj_2 ( obj ); - Value value_bool_2( false ); - - const char* str( "value" ); - Value value_str_2b ( str ); - - assert_eq( value_str, value_str ); - assert_eq( value_str, value_str_2 ); - assert_eq( value_str, value_str_2b ); - assert_eq( value_obj, value_obj ); - assert_eq( value_obj, value_obj_2 ); - assert_neq( value_str, value_obj ); - assert_neq( value_str, value_bool ); - - Object obj_2; - obj_2.push_back( Pair( "name", value_str ) ); - Value value_str_3( "xxxxx" ); - Value value_obj_3( obj_2 ); - - assert_neq( value_str, value_str_3 ); - assert_neq( value_obj, value_obj_3 ); - - test_obj_value(); - test_array_value(); - test_bool_value(); - test_int_value(); - test_real_value(); - test_null_value(); - test_get_value(); - test_copying(); - test_obj_map_implemention(); - test_is_uint64(); - test_an_int_is_a_real(); - test_wrong_type_exceptions(); -#endif - test_container_constructor(); - test_variant_constructor(); -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_value_test.h" +#include +#include +#include +#include +#include "json5_parser_value.h" +#include "utils_test.h" + +using namespace json5_parser; +using namespace std; +using namespace boost; +using namespace boost::assign; + +namespace { +#ifdef JSON_SPIRIT_VALUE_ENABLED + +const int64_t max_int64 = integer_traits::max(); +const uint64_t max_uint64 = integer_traits::max(); + +void test_obj_value() { + const Pair p1("name1", "value1"); + const Pair p3("name3", "value3"); + + Object obj_1; + obj_1.push_back(p1); + Object obj_2; + obj_2.push_back(p1); + Object obj_3; + obj_3.push_back(p3); + + Value v1(obj_1); + Value v2(obj_2); + Value v3(obj_3); + + assert_eq(v1.type(), obj_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + assert_eq(v1.get_obj(), obj_1); + assert_eq(v3.get_obj(), obj_3); +} + +void test_array_value() { + Array array_1; + array_1.push_back(1); + array_1.push_back("2"); + Array array_2; + array_2.push_back(1); + array_2.push_back("2"); + Array array_3; + array_3.push_back(1); + array_3.push_back("X"); + + Value v1(array_1); + Value v2(array_2); + Value v3(array_3); + + assert_eq(v1.type(), array_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + assert_eq(v1.get_array(), array_1); + assert_eq(v3.get_array(), array_3); +} + +void test_bool_value() { + Value v1(true); + Value v2(true); + Value v3(false); + + assert_eq(v1.type(), bool_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + assert(v1.get_bool()); + assert(!v3.get_bool()); +} + +void test_int_value() { + Value v1(1); + Value v2(1); + Value v3(INT_MAX); + + assert_eq(v1.type(), int_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + unsigned int uint_max = INT_MAX; + + assert_eq(v1.get_int(), 1); + assert_eq(v1.get_int64(), 1); + assert_eq(v1.get_uint64(), 1u); + assert_eq(v3.get_int(), INT_MAX); + assert_eq(v3.get_int64(), INT_MAX); + assert_eq(v3.get_uint64(), uint_max); + + Value v4(max_int64); + + assert_eq(v4.get_int64(), max_int64); + assert_eq(v4.get_uint64(), static_cast(max_int64)); + + const uint64_t max_int64_plus_1 = max_int64 + uint64_t(1); + + Value v5(max_int64_plus_1); + + assert_eq(v5.get_uint64(), max_int64_plus_1); + + Value v6(max_uint64); + + assert_eq(v6.get_uint64(), max_uint64); + + Value v7(0); + + assert_eq(v7.get_int(), 0); + assert_eq(v7.get_int64(), 0); + assert_eq(v7.get_uint64(), 0u); + + Value v8(-1); + + assert_eq(v8.get_int(), -1); + assert_eq(v8.get_int64(), -1); + assert_eq(v8.get_uint64(), max_uint64); +} + +void test_real_value() { + Value v1(1.0); + Value v2(1.0); + Value v3(2.0); + + assert_eq(v1.type(), real_type); + assert_eq(v1, v2); + assert_neq(v1, v3); + + assert_eq(v1.get_real(), 1.0); + assert_eq(v3.get_real(), 2.0); +} + +void test_null_value() { + Value v1; + Value v2; + + assert_eq(v1.type(), null_type); + assert_eq(v1.is_null(), true); + assert_eq(v1, v2); + assert_eq(v1.is_null(), true); + assert_eq(Value(1).is_null(), false); +} + +template +void test_get_value(const T& t) { + assert_eq(Value(t).get_value(), t); +} + +void test_get_value() { + test_get_value(123); + test_get_value(max_int64); + test_get_value(1.23); + test_get_value(true); + test_get_value(false); + test_get_value(string("test")); + + Array a; + a.push_back(1); + a.push_back("2"); + + test_get_value(a); + + Object obj; + obj.push_back(Pair("name1", "value1")); + + test_get_value(obj); +} + +void assert_array_eq(const Value& v, const Array& a) { assert_eq(v.get_array(), a); } + +void assert_obj_eq(const Value& v, const Object& obj) { assert_eq(v.get_obj(), obj); } + +template +void check_copy(const T& t) { + const Value v1(t); + const Value v2(v1); + Value v3; + v3 = v1; + + assert_eq(v1, v2); + assert_eq(v1, v3); + + assert_eq(v2.get_value(), t); + assert_eq(v3.get_value(), t); + + assert_eq(v1.is_uint64(), v2.is_uint64()); + assert_eq(v1.is_uint64(), v3.is_uint64()); +} + +void check_copying_null() { + const Value v1; + const Value v2(v1); + Value v3; + v3 = v1; + + assert_eq(v2.type(), null_type); + assert_eq(v3.type(), null_type); +} + +void test_copying() { + { + const Array array_1 = list_of(1)(2); + + Value v1(array_1); + const Value v2(v1); + + assert_array_eq(v1, array_1); + assert_array_eq(v2, array_1); + + v1.get_array()[0] = 3; + + assert_array_eq(v1, list_of(3)(2)); + assert_array_eq(v2, array_1); + } + { + const Object obj_1 = list_of(Pair("a", 1))(Pair("b", 2)); + + Value v1(obj_1); + Value v2; + + v2 = v1; + + assert_obj_eq(v1, obj_1); + assert_obj_eq(v2, obj_1); + + v1.get_obj()[0] = Pair("c", 3); + + assert_obj_eq(v1, list_of(Pair("c", 3))(Pair("b", 2))); + assert_obj_eq(v2, obj_1); + } + { + check_copy(1); + check_copy(2.0); + check_copy(max_int64); + check_copy(max_uint64); + check_copy(string("test")); + check_copy(true); + check_copy(false); + const Array array_1 = list_of(1)(2); + check_copy(array_1); + const Object obj_1 = list_of(Pair("a", 1))(Pair("b", 2)); + check_copy(obj_1); + check_copying_null(); + } +} + +void test_obj_map_implemention() { +#ifdef JSON_SPIRIT_MVALUE_ENABLED + mObject obj; + + obj["name 1"] = 1; + obj["name 2"] = "two"; + + assert_eq(obj.size(), 2u); + + assert_eq(obj.find("name 1")->second.get_int(), 1); + assert_eq(obj.find("name 2")->second.get_str(), "two"); +#endif +} + +template +void check_an_int_is_a_real(Int i, bool expected_result) { + assert_eq(Value(i).is_uint64(), expected_result); +} + +void test_is_uint64() { + check_an_int_is_a_real(1, false); + check_an_int_is_a_real(static_cast(1), false); + check_an_int_is_a_real(static_cast(1), true); +} + +template +void check_an_int_is_a_real(Int i, double expected_result) { + assert_eq(Value(i).get_real(), expected_result); +} + +void test_an_int_is_a_real() { + check_an_int_is_a_real(-1, -1.0); + check_an_int_is_a_real(0, 0.0); + check_an_int_is_a_real(1, 1.0); + check_an_int_is_a_real(max_int64, 9223372036854775800.0); + check_an_int_is_a_real(max_uint64, 18446744073709552000.0); +} + +template +void check_wrong_type_exceptions(const Value& v, const string& requested_type_name, + const string& actual_type_name) { + try { + v.get_value(); + + assert(false); + } catch (const runtime_error& e) { + ostringstream os; + + os << "get_value< " << requested_type_name << " > called on " + << actual_type_name << " Value"; + + assert_eq(e.what(), os.str()); + } +} + +template +void check_wrong_type_exceptions(const string& requested_type_name) { + Value v; + + assert_eq(v.type(), null_type); + + check_wrong_type_exceptions(v, requested_type_name, "null"); +} + +void test_wrong_type_exceptions() { + check_wrong_type_exceptions("Object"); + check_wrong_type_exceptions("Array"); + check_wrong_type_exceptions("string"); + check_wrong_type_exceptions("boolean"); + check_wrong_type_exceptions("integer"); + check_wrong_type_exceptions("integer"); + check_wrong_type_exceptions("real"); + + Value v("string"); + + assert_eq(v.type(), str_type); + + check_wrong_type_exceptions(v, "real", "string"); +} +#endif + +template +class Container_constructor_runner { +public: + Container_constructor_runner() { + vector vd = list_of(1.2)(1.3); + test_container_constructor(vd); + + vector vi = list_of(1); + test_container_constructor(vi); + + vector vi2 = list_of(1)(2); + test_container_constructor(vi2); + + vector vi3 = list_of(1)(2)(3); + test_container_constructor(vi3); + + list ld = list_of(1.2)(1.3); + test_container_constructor(ld); + + list li = list_of(1); + test_container_constructor(li); + + list li2 = list_of(1)(2); + test_container_constructor(li2); + + list li3 = list_of(1)(2)(3); + test_container_constructor(li3); + } + +private: + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + + template + void test_container_constructor(const Cont& cont) { + typedef typename Cont::value_type Cont_value_type; + const Value_type val(cont.begin(), cont.end()); + const Array_type& arr = val.get_array(); + Cont result; + for (unsigned int i = 0; i < arr.size(); ++i) { + result.push_back(arr[i].template get_value()); + } + assert_eq(result, cont); + } +}; + +void test_container_constructor() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Container_constructor_runner(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + Container_constructor_runner(); +#endif +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Container_constructor_runner(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Container_constructor_runner(); +#endif +} + +template +class Variant_constructor_runner { +public: + Variant_constructor_runner() { + test_variant_constructor >(1.23); + test_variant_constructor >(123); + test_variant_constructor >( + to_str("foo")); + test_variant_constructor >(true); + test_variant_constructor< + variant >( + boost::int64_t(123)); + test_variant_constructor< + variant >( + boost::uint64_t(123)); + + { + variant variant = Null(); + const Value_type val(variant); + assert(val.is_null()); + } + + vector vd = list_of(1.2)(1.3); + test_variant_array_constructor(vd); + + vector vi = list_of(1); + test_variant_array_constructor(vi); + + vector vi2 = list_of(1)(2); + test_variant_array_constructor(vi2); + + vector vi3 = list_of(1)(2)(3); + test_variant_array_constructor(vi3); + + list ld = list_of(1.2)(1.3); + test_variant_array_constructor(ld); + + list li = list_of(1); + test_variant_array_constructor(li); + + list li2 = list_of(1)(2); + test_variant_array_constructor(li2); + + list li3 = list_of(1)(2)(3); + test_variant_array_constructor(li3); + } + +private: + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + + template + void test_variant_constructor(const T& t) { + const Variant_t variant(t); + const Value_type val(variant); + assert_eq(val.template get_value(), t); + } + + template class Cont> + void test_variant_array_constructor(const Cont& cont) { + const variant > variant = cont; + const Value_type val(variant); + const Array_type& arr = val.get_array(); + Cont result; + for (unsigned int i = 0; i < arr.size(); ++i) { + result.push_back(arr[i].template get_value()); + } + assert_eq(result, cont); + } +}; + +void test_variant_constructor() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Variant_constructor_runner(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + Variant_constructor_runner(); + +#endif +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Variant_constructor_runner(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Variant_constructor_runner(); +#endif +} +} // namespace + +void json5_parser::test_value() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Object obj; + Value value_str("value"); + Value value_obj(obj); + Value value_bool(true); + + Value value_str_2(string("value")); + Value value_obj_2(obj); + Value value_bool_2(false); + + const char* str("value"); + Value value_str_2b(str); + + assert_eq(value_str, value_str); + assert_eq(value_str, value_str_2); + assert_eq(value_str, value_str_2b); + assert_eq(value_obj, value_obj); + assert_eq(value_obj, value_obj_2); + assert_neq(value_str, value_obj); + assert_neq(value_str, value_bool); + + Object obj_2; + obj_2.push_back(Pair("name", value_str)); + Value value_str_3("xxxxx"); + Value value_obj_3(obj_2); + + assert_neq(value_str, value_str_3); + assert_neq(value_obj, value_obj_3); + + test_obj_value(); + test_array_value(); + test_bool_value(); + test_int_value(); + test_real_value(); + test_null_value(); + test_get_value(); + test_copying(); + test_obj_map_implemention(); + test_is_uint64(); + test_an_int_is_a_real(); + test_wrong_type_exceptions(); +#endif + test_container_constructor(); + test_variant_constructor(); +} diff --git a/json_test/json5_parser_value_test.h b/json_test/json5_parser_value_test.h index a9c1391..3751d7d 100644 --- a/json_test/json5_parser_value_test.h +++ b/json_test/json5_parser_value_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_VALUE_TEST -#define JSON_SPIRIT_VALUE_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_value(); -} - -#endif +#ifndef JSON_SPIRIT_VALUE_TEST +#define JSON_SPIRIT_VALUE_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_value(); +} + +#endif diff --git a/json_test/json5_parser_writer_test.cpp b/json_test/json5_parser_writer_test.cpp index 34395a2..46f7fb7 100644 --- a/json_test/json5_parser_writer_test.cpp +++ b/json_test/json5_parser_writer_test.cpp @@ -1,788 +1,783 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_writer_test.h" -#include "utils_test.h" -#include "json5_parser_writer.h" -#include "json5_parser_value.h" - -#include -#include - -using namespace json5_parser; -using namespace std; -using namespace boost; - -namespace -{ - const int64_t max_int64 = integer_traits< int64_t >::max(); - const uint64_t max_uint64 = integer_traits< uint64_t >::max(); - - template< class Config_type > - struct Test_runner - { - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename Config_type::Value_type Value_type; - typedef typename String_type::value_type Char_type; - typedef typename String_type::const_iterator Iter_type; - typedef std::basic_ostream< Char_type > Ostream_type; - - String_type to_str( const char* c_str ) - { - return ::to_str< String_type >( c_str ); - } - - String_type zero_str() - { -#ifdef WIN32 - return to_str( "0.00000000000000000" ); -#else - return to_str( "0.0000000000000000" ); -#endif - } - - void add_value( Object_type& obj, const char* c_name, const Value_type& value ) - { - Config_type::add( obj, to_str( c_name ), value ); - } - - void add_c_str( Object_type& obj, const char* c_name, const char* c_value ) - { - add_value( obj, c_name, to_str( c_value ) ); - } - - void check_eq( const Value_type& value, const String_type& expected_result ) - { - assert_eq( write( value ), expected_result ); - } - - void check_eq( const Value_type& value, const char* expected_result ) - { - check_eq( value, to_str( expected_result ) ); - } - - void check_eq_pretty( const Value_type& value, const char* expected_result ) - { - assert_eq( write_formatted( value ), to_str( expected_result ) ); - assert_eq( write( value, pretty_print ), to_str( expected_result ) ); - } - - void check_eq_single_line_arrays( const Value_type& value, const char* expected_result ) - { - assert_eq( write( value, single_line_arrays ), to_str( expected_result ) ); - } - - void check_eq( const Value_type& value, const String_type& expected_result , Output_options options ) - { - assert_eq( write( value, options ), expected_result ); - } - - void check_eq( const Value_type& value, const char* expected_result, Output_options options ) - { - check_eq( value, to_str( expected_result ), options ); - } - - void test_empty_obj() - { - check_eq( Object_type(), "{}" ); - check_eq_pretty( Object_type(), "{\n}" ); - } - - void test_obj_with_one_member() - { - Object_type obj; - - add_c_str( obj, "name", "value" ); - - check_eq ( obj, "{\"name\":\"value\"}" ); - check_eq_pretty( obj, "{\n" - " \"name\" : \"value\"\n" - "}" ); - } - - void test_obj_with_two_members() - { - Object_type obj; - - add_c_str( obj, "name_1", "value_1" ); - add_c_str( obj, "name_2", "value_2" ); - - check_eq( obj, "{\"name_1\":\"value_1\",\"name_2\":\"value_2\"}" ); - - check_eq_pretty( obj, "{\n" - " \"name_1\" : \"value_1\",\n" - " \"name_2\" : \"value_2\"\n" - "}" ); - } - - void test_obj_with_three_members() - { - Object_type obj; - - add_c_str( obj, "name_1", "value_1" ); - add_c_str( obj, "name_2", "value_2" ); - add_c_str( obj, "name_3", "value_3" ); - - check_eq( obj, "{\"name_1\":\"value_1\",\"name_2\":\"value_2\",\"name_3\":\"value_3\"}" ); - - check_eq_pretty( obj, "{\n" - " \"name_1\" : \"value_1\",\n" - " \"name_2\" : \"value_2\",\n" - " \"name_3\" : \"value_3\"\n" - "}" ); - } - - void test_obj_with_one_empty_child_obj() - { - Object_type child; - - Object_type root; - - add_value( root, "child", child ); - - check_eq( root, "{\"child\":{}}" ); - - check_eq_pretty( root, "{\n" - " \"child\" : {\n" - " }\n" - "}" ); - } - - void test_obj_with_one_child_obj() - { - Object_type child; - - add_c_str( child, "name_2", "value_2" ); - - Object_type root; - - add_value( root, "child", child ); - add_c_str( root, "name_1", "value_1" ); - - check_eq( root, "{\"child\":{\"name_2\":\"value_2\"},\"name_1\":\"value_1\"}" ); - - check_eq_pretty( root, "{\n" - " \"child\" : {\n" - " \"name_2\" : \"value_2\"\n" - " },\n" - " \"name_1\" : \"value_1\"\n" - "}" ); - } - - void test_obj_with_grandchild_obj() - { - Object_type child_1; add_c_str( child_1, "name_1", "value_1" ); - Object_type child_2; - Object_type child_3; add_c_str( child_3, "name_3", "value_3" ); - - add_value( child_2, "grandchild", child_3 ); - add_c_str( child_2, "name_2", "value_2" ); - - Object_type root; - - add_value( root, "child_1", child_1 ); - add_value( root, "child_2", child_2 ); - add_c_str( root, "name_a", "value_a" ); - add_c_str( root, "name_b", "value_b" ); - - check_eq( root, "{\"child_1\":{\"name_1\":\"value_1\"}," - "\"child_2\":{\"grandchild\":{\"name_3\":\"value_3\"},\"name_2\":\"value_2\"}," - "\"name_a\":\"value_a\"," - "\"name_b\":\"value_b\"}" ); - - check_eq_pretty( root, "{\n" - " \"child_1\" : {\n" - " \"name_1\" : \"value_1\"\n" - " },\n" - " \"child_2\" : {\n" - " \"grandchild\" : {\n" - " \"name_3\" : \"value_3\"\n" - " },\n" - " \"name_2\" : \"value_2\"\n" - " },\n" - " \"name_a\" : \"value_a\",\n" - " \"name_b\" : \"value_b\"\n" - "}" ); - } - - void test_objs_with_bool_pairs() - { - Object_type obj; - - add_value( obj, "name_1", true ); - add_value( obj, "name_2", false ); - add_value( obj, "name_3", true ); - - check_eq( obj, "{\"name_1\":true,\"name_2\":false,\"name_3\":true}" ); - } - - void test_objs_with_int_pairs() - { - Object_type obj; - - add_value( obj, "name_1", 11 ); - add_value( obj, "name_2", INT_MAX ); - add_value( obj, "name_3", max_int64 ); - - ostringstream os; - - os << "{\"name_1\":11,\"name_2\":" << INT_MAX << ",\"name_3\":" << max_int64 << "}"; - - check_eq( obj, os.str().c_str() ); - } - - void test_objs_with_real_pairs() - { - Object_type obj; - - add_value( obj, "name_1", 0.0 ); - add_value( obj, "name_2", 1.234567890123456789e-108 ); - add_value( obj, "name_3", -1234567890.123456789 ); - add_value( obj, "name_4", -1.2e-126 ); - - check_eq( obj, to_str( "{\"name_1\":0," - "\"name_2\":1.2345678901234567e-108," - "\"name_3\":-1234567890.1234567," - "\"name_4\":-1.2e-126}" ) ); - } - - void test_objs_with_null_pairs() - { - Object_type obj; - - add_value( obj, "name_1", Value_type::null ); - add_value( obj, "name_2", Value_type::null ); - add_value( obj, "name_3", Value_type::null ); - - check_eq( obj, "{\"name_1\":null,\"name_2\":null,\"name_3\":null}" ); - } - - void test_empty_array() - { - check_eq( Array_type(), "[]" ); - check_eq_pretty( Array_type(), "[\n" - "]" ); - check_eq_single_line_arrays( Array_type(), "[ ]" ); - } - - void test_array_with_one_member() - { - Array_type arr; - - arr.push_back( to_str( "value" ) ); - - check_eq ( arr, "[\"value\"]" ); - check_eq_pretty( arr, "[\n" - " \"value\"\n" - "]" ); - check_eq_single_line_arrays( arr, "[ \"value\" ]" ); - } - - void test_array_with_two_members() - { - Array_type arr; - - arr.push_back( to_str( "value_1" ) ); - arr.push_back( 1 ); - - check_eq ( arr, "[\"value_1\",1]" ); - check_eq_pretty( arr, "[\n" - " \"value_1\",\n" - " 1\n" - "]" ); - check_eq_single_line_arrays( arr, "[ \"value_1\", 1 ]" ); - } - - void test_array_with_n_members() - { - Array_type arr; - - arr.push_back( to_str( "value_1" ) ); - arr.push_back( 123 ); - arr.push_back( 123.456 ); - arr.push_back( true ); - arr.push_back( false ); - arr.push_back( Value_type() ); - - check_eq ( arr, "[\"value_1\",123,123.456,true,false,null]" ); - check_eq_pretty( arr, "[\n" - " \"value_1\",\n" - " 123,\n" - " 123.456,\n" - " true,\n" - " false,\n" - " null\n" - "]" ); - check_eq_single_line_arrays( arr, "[ \"value_1\", 123, 123.456, true, false, null ]" ); - } - - void test_array_with_one_empty_child_array() - { - Array_type arr; - - arr.push_back( Array_type() ); - - check_eq ( arr, "[[]]" ); - check_eq_pretty( arr, "[\n" - " [\n" - " ]\n" - "]" ); - check_eq_single_line_arrays( arr, "[\n" - " [ ]\n" - "]" ); - } - - void test_array_with_one_child_array() - { - Array_type child; - - child.push_back( 2 ); - - Array_type root; - - root.push_back( 1 ); - root.push_back( child ); - - check_eq ( root, "[1,[2]]" ); - check_eq_pretty( root, "[\n" - " 1,\n" - " [\n" - " 2\n" - " ]\n" - "]" ); - check_eq_single_line_arrays( root, "[\n" - " 1,\n" - " [ 2 ]\n" - "]" ); - } - - void test_array_with_grandchild_array() - { - Array_type child_1; child_1.push_back( 11 ); - Array_type child_2; child_2.push_back( 22 ); - Array_type child_3; child_3.push_back( 33 ); - - child_2.push_back( child_3 ); - - Array_type root; - - root.push_back( 1); - root.push_back( child_1 ); - root.push_back( child_2 ); - root.push_back( 2 ); - - check_eq ( root, "[1,[11],[22,[33]],2]" ); - check_eq_pretty( root, "[\n" - " 1,\n" - " [\n" - " 11\n" - " ],\n" - " [\n" - " 22,\n" - " [\n" - " 33\n" - " ]\n" - " ],\n" - " 2\n" - "]" ); - check_eq_single_line_arrays( root, "[\n" - " 1,\n" - " [ 11 ],\n" - " [\n" - " 22,\n" - " [ 33 ]\n" - " ],\n" - " 2\n" - "]" ); - } - - void test_array_and_objs() - { - Array_type a; - - a.push_back( 11 ); - - Object_type obj; - - add_value( obj, "a", 1 ); - - a.push_back( obj ); - - check_eq ( a, "[11,{\"a\":1}]" ); - check_eq_pretty( a, "[\n" - " 11,\n" - " {\n" - " \"a\" : 1\n" - " }\n" - "]" ); - check_eq_single_line_arrays( a, "[\n" - " 11,\n" - " {\n" - " \"a\" : 1\n" - " }\n" - "]" ); - - add_value( obj, "b", 2 ); - - a.push_back( 22 ); - a.push_back( 33 ); - a.push_back( obj ); - - check_eq ( a, "[11,{\"a\":1},22,33,{\"a\":1,\"b\":2}]" ); - check_eq_pretty( a, "[\n" - " 11,\n" - " {\n" - " \"a\" : 1\n" - " },\n" - " 22,\n" - " 33,\n" - " {\n" - " \"a\" : 1,\n" - " \"b\" : 2\n" - " }\n" - "]" ); - check_eq_single_line_arrays( a, "[\n" - " 11,\n" - " {\n" - " \"a\" : 1\n" - " },\n" - " 22,\n" - " 33,\n" - " {\n" - " \"a\" : 1,\n" - " \"b\" : 2\n" - " }\n" - "]" ); - } - - void test_obj_and_arrays() - { - Object_type obj; - - add_value( obj, "a", 1 ); - - Array_type a; - - a.push_back( 11 ); - a.push_back( 12 ); - - add_value( obj, "b", a ); - - check_eq ( obj, "{\"a\":1,\"b\":[11,12]}" ); - check_eq_pretty( obj, "{\n" - " \"a\" : 1,\n" - " \"b\" : [\n" - " 11,\n" - " 12\n" - " ]\n" - "}" ); - check_eq_single_line_arrays( obj, "{\n" - " \"a\" : 1,\n" - " \"b\" : [ 11, 12 ]\n" - "}" ); - - a.push_back( obj ); - - add_value( obj, "c", a ); - - check_eq ( obj, "{\"a\":1,\"b\":[11,12],\"c\":[11,12,{\"a\":1,\"b\":[11,12]}]}" ); - check_eq_pretty( obj, "{\n" - " \"a\" : 1,\n" - " \"b\" : [\n" - " 11,\n" - " 12\n" - " ],\n" - " \"c\" : [\n" - " 11,\n" - " 12,\n" - " {\n" - " \"a\" : 1,\n" - " \"b\" : [\n" - " 11,\n" - " 12\n" - " ]\n" - " }\n" - " ]\n" - "}" ); - check_eq_single_line_arrays( obj, "{\n" - " \"a\" : 1,\n" - " \"b\" : [ 11, 12 ],\n" - " \"c\" : [\n" - " 11,\n" - " 12,\n" - " {\n" - " \"a\" : 1,\n" - " \"b\" : [ 11, 12 ]\n" - " }\n" - " ]\n" - "}" ); - } - - void test_escape_char( const char* esc_str_in, const char* esc_str_out, Output_options options = none ) - { - Object_type obj; - - const string name_str( string( esc_str_in ) + "name" ); - - add_value( obj, name_str.c_str(), to_str( "value" ) + to_str( esc_str_in ) ); - - const string out_str( string( "{\"" ) + esc_str_out + "name\":\"value" + esc_str_out + "\"}" ); - - check_eq( obj, out_str.c_str(), options ); - } - - void test_escape_chars() - { - test_escape_char( "\r", "\\r" ); - test_escape_char( "\n", "\\n" ); - test_escape_char( "\t", "\\t" ); - test_escape_char( "\f", "\\f" ); - test_escape_char( "\b", "\\b" ); - test_escape_char( "\"", "\\\"" ); - test_escape_char( "\\", "\\\\" ); - test_escape_char( "\x01", "\\u0001" ); - test_escape_char( "\x12", "\\u0012" ); - test_escape_char( "\x7F", "\\u007F" ); - } - - void test_disabling_nonprintable_esc_chars() - { - test_escape_char( "\t", "\\t", raw_utf8 ); - test_escape_char( "\x01", "\x01", raw_utf8 ); - test_escape_char( "\x01\x12", "\x01\x12", raw_utf8 ); - } - - void test_to_stream() - { - basic_ostringstream< Char_type > os; - - Array_type arr; - - arr.push_back( 111 ); - arr.push_back( 222 ); - - os << hex; // the code should handle this, i.e. output decimal - - write( arr, os ); - - assert_eq( os.str(), to_str( "[111,222]" ) ); - } - - void test_values() - { - check_eq( 123, "123" ); - check_eq( 1.234, "1.234" ); - check_eq( to_str( "abc" ), "\"abc\"" ); - check_eq( false, "false" ); - check_eq( Value_type::null, "null" ); - } - - void test_uint64() - { - check_eq( Value_type( 0 ), "0" ); - check_eq( Value_type( int64_t( 0 ) ), "0" ); - check_eq( Value_type( uint64_t( 0 ) ), "0" ); - - check_eq( Value_type( 1 ), "1" ); - check_eq( Value_type( int64_t( 1 ) ), "1" ); - check_eq( Value_type( uint64_t( 1 ) ), "1" ); - - check_eq( Value_type( -1 ), "-1" ); - check_eq( Value_type( int64_t( -1 ) ), "-1" ); - - check_eq( Value_type( max_int64 ), "9223372036854775807" ); - check_eq( Value_type( uint64_t( max_int64 ) ), "9223372036854775807" ); - - check_eq( Value_type( max_uint64 ), "18446744073709551615" ); - } - - void test_ios_state_saved() - { - basic_ostringstream< Char_type > os; - - os << 0.123456789; - - Array_type arr; - - arr.push_back( 0.123456789 ); - - write( arr, os ); - - os << 0.123456789; - - assert_eq( os.str(), to_str( "0.123457" - "[0.123456789]" - "0.123457" ) ); - } - - void check_remove_trailing_zeros( const double value, const String_type& expected_str_with, const String_type& expected_str_without ) - { - check_eq( value, expected_str_with, none ); - check_eq( value, expected_str_without, remove_trailing_zeros ); - } - - void check_remove_trailing_zeros( const double value, const char* expected_str_with, const char* expected_str_without ) - { - check_remove_trailing_zeros( value, to_str( expected_str_with ), to_str( expected_str_without ) ); - } - - void test_remove_trailing_zeros() - { -#ifdef WIN32 - const String_type exp = to_str( "099" ); -#else - const String_type exp = to_str( "99" ); -#endif - check_remove_trailing_zeros( 0.0, "0", "0" ); - check_remove_trailing_zeros( 1.2, "1.2", "1.2" ); - check_remove_trailing_zeros( 0.123456789, "0.123456789", "0.123456789" ); - check_remove_trailing_zeros( 1.2e-99, to_str( "1.2e-" ) + exp, to_str( "1.2e-" ) + exp ); - check_remove_trailing_zeros( 1.23456789e99, to_str( "1.2345678900000001e+" ) + exp, to_str( "1.23456789e+" ) + exp ); - } - - void check_precision_of_doubles( unsigned int precision, const char* expected_result_1, const char* expected_result_2 = 0 ) - { - Value_type val = 0.1234567890123456789; - assert_eq( write( val, none, precision ), to_str( expected_result_1 ) ); - if( !expected_result_2 ) - { - expected_result_2 = expected_result_1; - } - assert_eq( write( val, remove_trailing_zeros, precision ), to_str( expected_result_2 ) ); - } - - void check_precision_of_doubles( const char* expected_result_1, const char* expected_result_2 ) - { - Value_type val = 0.1234567890123456789; - assert_eq( write( val, none ), to_str( expected_result_1 ) ); - assert_eq( write( val, remove_trailing_zeros ), to_str( expected_result_2 ) ); - } - - void test_precision_of_doubles() - { - // default is 17, or 16 for remove_trailing_zeros flag - check_precision_of_doubles( "0.12345678901234568", "0.1234567890123457" ); - check_precision_of_doubles( 0, "0.12345678901234568", "0.1234567890123457" ); - - // specified override is used with or without remove_trailing_zeros flag - check_precision_of_doubles( 9, "0.123456789" ); - check_precision_of_doubles( 6, "0.123457" ); - check_precision_of_doubles( 1, "0.1" ); - } - - void test_multiple_options() - { - Value value; - write(value, always_escape_nonascii | pretty_print ); - } - - void run_tests() - { - test_empty_obj(); - test_obj_with_one_member(); - test_obj_with_two_members(); - test_obj_with_three_members(); - test_obj_with_one_empty_child_obj(); - test_obj_with_one_child_obj(); - test_obj_with_grandchild_obj(); - test_objs_with_bool_pairs(); - test_objs_with_int_pairs(); - test_objs_with_real_pairs(); - test_objs_with_null_pairs(); - test_empty_array(); - test_array_with_one_member(); - test_array_with_two_members(); - test_array_with_n_members(); - test_array_with_one_empty_child_array(); - test_array_with_one_child_array(); - test_array_with_grandchild_array(); - test_array_and_objs(); - test_obj_and_arrays(); - test_escape_chars(); - test_disabling_nonprintable_esc_chars(); - test_to_stream(); - test_values(); - test_uint64(); - test_ios_state_saved(); - test_remove_trailing_zeros(); - test_precision_of_doubles(); - test_multiple_options(); - } - }; - -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void test_always_esc_nonascii() - { - if( iswprint( L'\x05DE' ) ) - { - const wstring s( L"\x05DE\x05E9\x05EA\x05DE\x05E9" ); - - wArray arr( 1, s ); - - const wstring foo = arr[0].get_str(); - - const wstring json_raw = write( arr ); - - assert_eq( json_raw, L"[\"" + s + L"\"]" ); - - const wstring json_escaped = write( arr, always_escape_nonascii ); - - assert_eq( json_escaped, L"[\"\\u05DE\\u05E9\\u05EA\\u05DE\\u05E9\"]" ); - } - } - - void test_wide_esc_u( wchar_t c, const wstring& result) - { - const wstring s( 1, c ); - - wArray arr( 1, s ); - - assert_eq( write( arr ), L"[\"\\u" + result + L"\"]" ); - } - - void test_wide_esc_u() - { - test_wide_esc_u( 0xABCD, L"ABCD" ); - test_wide_esc_u( 0xFFFF, L"FFFF" ); - } -#endif - - bool is_printable( char c ) - { - const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); - - return iswprint( unsigned_c ) != 0; - } - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void test_extended_ascii() - { - const string expeced_result( is_printable( '\xE4' ) ? "[\"\xE4\xF6\xFC\xDF\"]" : "[\"\\u00E4\\u00F6\\u00FC\\u00DF\"]" ); - - assert_eq( write( Array( 1, "\xE4\xF6\xFC\xDF" ) ), expeced_result ); - } -#endif -} - -void json5_parser::test_writer() -{ -#ifdef JSON_SPIRIT_VALUE_ENABLED - Test_runner< Config >().run_tests(); - test_extended_ascii(); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - Test_runner< mConfig >().run_tests(); -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wConfig >().run_tests(); - test_wide_esc_u(); - test_always_esc_nonascii(); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - Test_runner< wmConfig >().run_tests(); -#endif -} +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_writer_test.h" +#include "json5_parser_value.h" +#include "json5_parser_writer.h" +#include "utils_test.h" + +#include +#include + +using namespace json5_parser; +using namespace std; +using namespace boost; + +namespace { +const int64_t max_int64 = integer_traits::max(); +const uint64_t max_uint64 = integer_traits::max(); + +template +struct Test_runner { + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename Config_type::Value_type Value_type; + typedef typename String_type::value_type Char_type; + typedef typename String_type::const_iterator Iter_type; + typedef std::basic_ostream Ostream_type; + + String_type to_str(const char* c_str) { return ::to_str(c_str); } + + String_type zero_str() { +#ifdef WIN32 + return to_str("0.00000000000000000"); +#else + return to_str("0.0000000000000000"); +#endif + } + + void add_value(Object_type& obj, const char* c_name, const Value_type& value) { + Config_type::add(obj, to_str(c_name), value); + } + + void add_c_str(Object_type& obj, const char* c_name, const char* c_value) { + add_value(obj, c_name, to_str(c_value)); + } + + void check_eq(const Value_type& value, const String_type& expected_result) { + assert_eq(write(value), expected_result); + } + + void check_eq(const Value_type& value, const char* expected_result) { + check_eq(value, to_str(expected_result)); + } + + void check_eq_pretty(const Value_type& value, const char* expected_result) { + assert_eq(write_formatted(value), to_str(expected_result)); + assert_eq(write(value, pretty_print), to_str(expected_result)); + } + + void check_eq_single_line_arrays(const Value_type& value, + const char* expected_result) { + assert_eq(write(value, single_line_arrays), to_str(expected_result)); + } + + void check_eq(const Value_type& value, const String_type& expected_result, + Output_options options) { + assert_eq(write(value, options), expected_result); + } + + void check_eq(const Value_type& value, const char* expected_result, + Output_options options) { + check_eq(value, to_str(expected_result), options); + } + + void test_empty_obj() { + check_eq(Object_type(), "{}"); + check_eq_pretty(Object_type(), "{\n}"); + } + + void test_obj_with_one_member() { + Object_type obj; + + add_c_str(obj, "name", "value"); + + check_eq(obj, "{\"name\":\"value\"}"); + check_eq_pretty(obj, + "{\n" + " \"name\" : \"value\"\n" + "}"); + } + + void test_obj_with_two_members() { + Object_type obj; + + add_c_str(obj, "name_1", "value_1"); + add_c_str(obj, "name_2", "value_2"); + + check_eq(obj, "{\"name_1\":\"value_1\",\"name_2\":\"value_2\"}"); + + check_eq_pretty(obj, + "{\n" + " \"name_1\" : \"value_1\",\n" + " \"name_2\" : \"value_2\"\n" + "}"); + } + + void test_obj_with_three_members() { + Object_type obj; + + add_c_str(obj, "name_1", "value_1"); + add_c_str(obj, "name_2", "value_2"); + add_c_str(obj, "name_3", "value_3"); + + check_eq(obj, + "{\"name_1\":\"value_1\",\"name_2\":\"value_2\",\"name_3\":\"value_" + "3\"}"); + + check_eq_pretty(obj, + "{\n" + " \"name_1\" : \"value_1\",\n" + " \"name_2\" : \"value_2\",\n" + " \"name_3\" : \"value_3\"\n" + "}"); + } + + void test_obj_with_one_empty_child_obj() { + Object_type child; + + Object_type root; + + add_value(root, "child", child); + + check_eq(root, "{\"child\":{}}"); + + check_eq_pretty(root, + "{\n" + " \"child\" : {\n" + " }\n" + "}"); + } + + void test_obj_with_one_child_obj() { + Object_type child; + + add_c_str(child, "name_2", "value_2"); + + Object_type root; + + add_value(root, "child", child); + add_c_str(root, "name_1", "value_1"); + + check_eq(root, "{\"child\":{\"name_2\":\"value_2\"},\"name_1\":\"value_1\"}"); + + check_eq_pretty(root, + "{\n" + " \"child\" : {\n" + " \"name_2\" : \"value_2\"\n" + " },\n" + " \"name_1\" : \"value_1\"\n" + "}"); + } + + void test_obj_with_grandchild_obj() { + Object_type child_1; + add_c_str(child_1, "name_1", "value_1"); + Object_type child_2; + Object_type child_3; + add_c_str(child_3, "name_3", "value_3"); + + add_value(child_2, "grandchild", child_3); + add_c_str(child_2, "name_2", "value_2"); + + Object_type root; + + add_value(root, "child_1", child_1); + add_value(root, "child_2", child_2); + add_c_str(root, "name_a", "value_a"); + add_c_str(root, "name_b", "value_b"); + + check_eq(root, + "{\"child_1\":{\"name_1\":\"value_1\"}," + "\"child_2\":{\"grandchild\":{\"name_3\":\"value_3\"},\"name_2\":" + "\"value_2\"}," + "\"name_a\":\"value_a\"," + "\"name_b\":\"value_b\"}"); + + check_eq_pretty(root, + "{\n" + " \"child_1\" : {\n" + " \"name_1\" : \"value_1\"\n" + " },\n" + " \"child_2\" : {\n" + " \"grandchild\" : {\n" + " \"name_3\" : \"value_3\"\n" + " },\n" + " \"name_2\" : \"value_2\"\n" + " },\n" + " \"name_a\" : \"value_a\",\n" + " \"name_b\" : \"value_b\"\n" + "}"); + } + + void test_objs_with_bool_pairs() { + Object_type obj; + + add_value(obj, "name_1", true); + add_value(obj, "name_2", false); + add_value(obj, "name_3", true); + + check_eq(obj, "{\"name_1\":true,\"name_2\":false,\"name_3\":true}"); + } + + void test_objs_with_int_pairs() { + Object_type obj; + + add_value(obj, "name_1", 11); + add_value(obj, "name_2", INT_MAX); + add_value(obj, "name_3", max_int64); + + ostringstream os; + + os << "{\"name_1\":11,\"name_2\":" << INT_MAX << ",\"name_3\":" << max_int64 + << "}"; + + check_eq(obj, os.str().c_str()); + } + + void test_objs_with_real_pairs() { + Object_type obj; + + add_value(obj, "name_1", 0.0); + add_value(obj, "name_2", 1.234567890123456789e-108); + add_value(obj, "name_3", -1234567890.123456789); + add_value(obj, "name_4", -1.2e-126); + + check_eq(obj, to_str("{\"name_1\":0," + "\"name_2\":1.2345678901234567e-108," + "\"name_3\":-1234567890.1234567," + "\"name_4\":-1.2e-126}")); + } + + void test_objs_with_null_pairs() { + Object_type obj; + + add_value(obj, "name_1", Value_type::null); + add_value(obj, "name_2", Value_type::null); + add_value(obj, "name_3", Value_type::null); + + check_eq(obj, "{\"name_1\":null,\"name_2\":null,\"name_3\":null}"); + } + + void test_empty_array() { + check_eq(Array_type(), "[]"); + check_eq_pretty(Array_type(), + "[\n" + "]"); + check_eq_single_line_arrays(Array_type(), "[ ]"); + } + + void test_array_with_one_member() { + Array_type arr; + + arr.push_back(to_str("value")); + + check_eq(arr, "[\"value\"]"); + check_eq_pretty(arr, + "[\n" + " \"value\"\n" + "]"); + check_eq_single_line_arrays(arr, "[ \"value\" ]"); + } + + void test_array_with_two_members() { + Array_type arr; + + arr.push_back(to_str("value_1")); + arr.push_back(1); + + check_eq(arr, "[\"value_1\",1]"); + check_eq_pretty(arr, + "[\n" + " \"value_1\",\n" + " 1\n" + "]"); + check_eq_single_line_arrays(arr, "[ \"value_1\", 1 ]"); + } + + void test_array_with_n_members() { + Array_type arr; + + arr.push_back(to_str("value_1")); + arr.push_back(123); + arr.push_back(123.456); + arr.push_back(true); + arr.push_back(false); + arr.push_back(Value_type()); + + check_eq(arr, "[\"value_1\",123,123.456,true,false,null]"); + check_eq_pretty(arr, + "[\n" + " \"value_1\",\n" + " 123,\n" + " 123.456,\n" + " true,\n" + " false,\n" + " null\n" + "]"); + check_eq_single_line_arrays(arr, + "[ \"value_1\", 123, 123.456, true, false, null ]"); + } + + void test_array_with_one_empty_child_array() { + Array_type arr; + + arr.push_back(Array_type()); + + check_eq(arr, "[[]]"); + check_eq_pretty(arr, + "[\n" + " [\n" + " ]\n" + "]"); + check_eq_single_line_arrays(arr, + "[\n" + " [ ]\n" + "]"); + } + + void test_array_with_one_child_array() { + Array_type child; + + child.push_back(2); + + Array_type root; + + root.push_back(1); + root.push_back(child); + + check_eq(root, "[1,[2]]"); + check_eq_pretty(root, + "[\n" + " 1,\n" + " [\n" + " 2\n" + " ]\n" + "]"); + check_eq_single_line_arrays(root, + "[\n" + " 1,\n" + " [ 2 ]\n" + "]"); + } + + void test_array_with_grandchild_array() { + Array_type child_1; + child_1.push_back(11); + Array_type child_2; + child_2.push_back(22); + Array_type child_3; + child_3.push_back(33); + + child_2.push_back(child_3); + + Array_type root; + + root.push_back(1); + root.push_back(child_1); + root.push_back(child_2); + root.push_back(2); + + check_eq(root, "[1,[11],[22,[33]],2]"); + check_eq_pretty(root, + "[\n" + " 1,\n" + " [\n" + " 11\n" + " ],\n" + " [\n" + " 22,\n" + " [\n" + " 33\n" + " ]\n" + " ],\n" + " 2\n" + "]"); + check_eq_single_line_arrays(root, + "[\n" + " 1,\n" + " [ 11 ],\n" + " [\n" + " 22,\n" + " [ 33 ]\n" + " ],\n" + " 2\n" + "]"); + } + + void test_array_and_objs() { + Array_type a; + + a.push_back(11); + + Object_type obj; + + add_value(obj, "a", 1); + + a.push_back(obj); + + check_eq(a, "[11,{\"a\":1}]"); + check_eq_pretty(a, + "[\n" + " 11,\n" + " {\n" + " \"a\" : 1\n" + " }\n" + "]"); + check_eq_single_line_arrays(a, + "[\n" + " 11,\n" + " {\n" + " \"a\" : 1\n" + " }\n" + "]"); + + add_value(obj, "b", 2); + + a.push_back(22); + a.push_back(33); + a.push_back(obj); + + check_eq(a, "[11,{\"a\":1},22,33,{\"a\":1,\"b\":2}]"); + check_eq_pretty(a, + "[\n" + " 11,\n" + " {\n" + " \"a\" : 1\n" + " },\n" + " 22,\n" + " 33,\n" + " {\n" + " \"a\" : 1,\n" + " \"b\" : 2\n" + " }\n" + "]"); + check_eq_single_line_arrays(a, + "[\n" + " 11,\n" + " {\n" + " \"a\" : 1\n" + " },\n" + " 22,\n" + " 33,\n" + " {\n" + " \"a\" : 1,\n" + " \"b\" : 2\n" + " }\n" + "]"); + } + + void test_obj_and_arrays() { + Object_type obj; + + add_value(obj, "a", 1); + + Array_type a; + + a.push_back(11); + a.push_back(12); + + add_value(obj, "b", a); + + check_eq(obj, "{\"a\":1,\"b\":[11,12]}"); + check_eq_pretty(obj, + "{\n" + " \"a\" : 1,\n" + " \"b\" : [\n" + " 11,\n" + " 12\n" + " ]\n" + "}"); + check_eq_single_line_arrays(obj, + "{\n" + " \"a\" : 1,\n" + " \"b\" : [ 11, 12 ]\n" + "}"); + + a.push_back(obj); + + add_value(obj, "c", a); + + check_eq(obj, "{\"a\":1,\"b\":[11,12],\"c\":[11,12,{\"a\":1,\"b\":[11,12]}]}"); + check_eq_pretty(obj, + "{\n" + " \"a\" : 1,\n" + " \"b\" : [\n" + " 11,\n" + " 12\n" + " ],\n" + " \"c\" : [\n" + " 11,\n" + " 12,\n" + " {\n" + " \"a\" : 1,\n" + " \"b\" : [\n" + " 11,\n" + " 12\n" + " ]\n" + " }\n" + " ]\n" + "}"); + check_eq_single_line_arrays(obj, + "{\n" + " \"a\" : 1,\n" + " \"b\" : [ 11, 12 ],\n" + " \"c\" : [\n" + " 11,\n" + " 12,\n" + " {\n" + " \"a\" : 1,\n" + " \"b\" : [ 11, 12 ]\n" + " }\n" + " ]\n" + "}"); + } + + void test_escape_char(const char* esc_str_in, const char* esc_str_out, + Output_options options = none) { + Object_type obj; + + const string name_str(string(esc_str_in) + "name"); + + add_value(obj, name_str.c_str(), to_str("value") + to_str(esc_str_in)); + + const string out_str(string("{\"") + esc_str_out + "name\":\"value" + + esc_str_out + "\"}"); + + check_eq(obj, out_str.c_str(), options); + } + + void test_escape_chars() { + test_escape_char("\r", "\\r"); + test_escape_char("\n", "\\n"); + test_escape_char("\t", "\\t"); + test_escape_char("\f", "\\f"); + test_escape_char("\b", "\\b"); + test_escape_char("\"", "\\\""); + test_escape_char("\\", "\\\\"); + test_escape_char("\x01", "\\u0001"); + test_escape_char("\x12", "\\u0012"); + test_escape_char("\x7F", "\\u007F"); + } + + void test_disabling_nonprintable_esc_chars() { + test_escape_char("\t", "\\t", raw_utf8); + test_escape_char("\x01", "\x01", raw_utf8); + test_escape_char("\x01\x12", "\x01\x12", raw_utf8); + } + + void test_to_stream() { + basic_ostringstream os; + + Array_type arr; + + arr.push_back(111); + arr.push_back(222); + + os << hex; // the code should handle this, i.e. output decimal + + write(arr, os); + + assert_eq(os.str(), to_str("[111,222]")); + } + + void test_values() { + check_eq(123, "123"); + check_eq(1.234, "1.234"); + check_eq(to_str("abc"), "\"abc\""); + check_eq(false, "false"); + check_eq(Value_type::null, "null"); + } + + void test_uint64() { + check_eq(Value_type(0), "0"); + check_eq(Value_type(int64_t(0)), "0"); + check_eq(Value_type(uint64_t(0)), "0"); + + check_eq(Value_type(1), "1"); + check_eq(Value_type(int64_t(1)), "1"); + check_eq(Value_type(uint64_t(1)), "1"); + + check_eq(Value_type(-1), "-1"); + check_eq(Value_type(int64_t(-1)), "-1"); + + check_eq(Value_type(max_int64), "9223372036854775807"); + check_eq(Value_type(uint64_t(max_int64)), "9223372036854775807"); + + check_eq(Value_type(max_uint64), "18446744073709551615"); + } + + void test_ios_state_saved() { + basic_ostringstream os; + + os << 0.123456789; + + Array_type arr; + + arr.push_back(0.123456789); + + write(arr, os); + + os << 0.123456789; + + assert_eq(os.str(), to_str("0.123457" + "[0.123456789]" + "0.123457")); + } + + void check_remove_trailing_zeros(const double value, + const String_type& expected_str_with, + const String_type& expected_str_without) { + check_eq(value, expected_str_with, none); + check_eq(value, expected_str_without, remove_trailing_zeros); + } + + void check_remove_trailing_zeros(const double value, const char* expected_str_with, + const char* expected_str_without) { + check_remove_trailing_zeros(value, to_str(expected_str_with), + to_str(expected_str_without)); + } + + void test_remove_trailing_zeros() { +#ifdef WIN32 + const String_type exp = to_str("099"); +#else + const String_type exp = to_str("99"); +#endif + check_remove_trailing_zeros(0.0, "0", "0"); + check_remove_trailing_zeros(1.2, "1.2", "1.2"); + check_remove_trailing_zeros(0.123456789, "0.123456789", "0.123456789"); + check_remove_trailing_zeros(1.2e-99, to_str("1.2e-") + exp, + to_str("1.2e-") + exp); + check_remove_trailing_zeros(1.23456789e99, to_str("1.2345678900000001e+") + exp, + to_str("1.23456789e+") + exp); + } + + void check_precision_of_doubles(unsigned int precision, + const char* expected_result_1, + const char* expected_result_2 = 0) { + Value_type val = 0.1234567890123456789; + assert_eq(write(val, none, precision), to_str(expected_result_1)); + if (!expected_result_2) { + expected_result_2 = expected_result_1; + } + assert_eq(write(val, remove_trailing_zeros, precision), + to_str(expected_result_2)); + } + + void check_precision_of_doubles(const char* expected_result_1, + const char* expected_result_2) { + Value_type val = 0.1234567890123456789; + assert_eq(write(val, none), to_str(expected_result_1)); + assert_eq(write(val, remove_trailing_zeros), to_str(expected_result_2)); + } + + void test_precision_of_doubles() { + // default is 17, or 16 for remove_trailing_zeros flag + check_precision_of_doubles("0.12345678901234568", "0.1234567890123457"); + check_precision_of_doubles(0, "0.12345678901234568", "0.1234567890123457"); + + // specified override is used with or without remove_trailing_zeros flag + check_precision_of_doubles(9, "0.123456789"); + check_precision_of_doubles(6, "0.123457"); + check_precision_of_doubles(1, "0.1"); + } + + void test_multiple_options() { + Value value; + write(value, always_escape_nonascii | pretty_print); + } + + void run_tests() { + test_empty_obj(); + test_obj_with_one_member(); + test_obj_with_two_members(); + test_obj_with_three_members(); + test_obj_with_one_empty_child_obj(); + test_obj_with_one_child_obj(); + test_obj_with_grandchild_obj(); + test_objs_with_bool_pairs(); + test_objs_with_int_pairs(); + test_objs_with_real_pairs(); + test_objs_with_null_pairs(); + test_empty_array(); + test_array_with_one_member(); + test_array_with_two_members(); + test_array_with_n_members(); + test_array_with_one_empty_child_array(); + test_array_with_one_child_array(); + test_array_with_grandchild_array(); + test_array_and_objs(); + test_obj_and_arrays(); + test_escape_chars(); + test_disabling_nonprintable_esc_chars(); + test_to_stream(); + test_values(); + test_uint64(); + test_ios_state_saved(); + test_remove_trailing_zeros(); + test_precision_of_doubles(); + test_multiple_options(); + } +}; + +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) +void test_always_esc_nonascii() { + if (iswprint(L'\x05DE')) { + const wstring s(L"\x05DE\x05E9\x05EA\x05DE\x05E9"); + + wArray arr(1, s); + + const wstring foo = arr[0].get_str(); + + const wstring json_raw = write(arr); + + assert_eq(json_raw, L"[\"" + s + L"\"]"); + + const wstring json_escaped = write(arr, always_escape_nonascii); + + assert_eq(json_escaped, L"[\"\\u05DE\\u05E9\\u05EA\\u05DE\\u05E9\"]"); + } +} + +void test_wide_esc_u(wchar_t c, const wstring& result) { + const wstring s(1, c); + + wArray arr(1, s); + + assert_eq(write(arr), L"[\"\\u" + result + L"\"]"); +} + +void test_wide_esc_u() { + test_wide_esc_u(0xABCD, L"ABCD"); + test_wide_esc_u(0xFFFF, L"FFFF"); +} +#endif + +bool is_printable(char c) { + const wint_t unsigned_c((c >= 0) ? c : 256 + c); + + return iswprint(unsigned_c) != 0; +} + +#ifdef JSON_SPIRIT_VALUE_ENABLED +void test_extended_ascii() { + const string expeced_result(is_printable('\xE4') + ? "[\"\xE4\xF6\xFC\xDF\"]" + : "[\"\\u00E4\\u00F6\\u00FC\\u00DF\"]"); + + assert_eq(write(Array(1, "\xE4\xF6\xFC\xDF")), expeced_result); +} +#endif +} // namespace + +void json5_parser::test_writer() { +#ifdef JSON_SPIRIT_VALUE_ENABLED + Test_runner().run_tests(); + test_extended_ascii(); +#endif +#ifdef JSON_SPIRIT_MVALUE_ENABLED + Test_runner().run_tests(); +#endif +#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); + test_wide_esc_u(); + test_always_esc_nonascii(); +#endif +#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING) + Test_runner().run_tests(); +#endif +} diff --git a/json_test/json5_parser_writer_test.h b/json_test/json5_parser_writer_test.h index 3c9bb77..b1caf5c 100644 --- a/json_test/json5_parser_writer_test.h +++ b/json_test/json5_parser_writer_test.h @@ -1,18 +1,17 @@ -#ifndef JSON_SPIRIT_WRITER_TEST -#define JSON_SPIRIT_WRITER_TEST - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json5_parser -{ - void test_writer(); -} - -#endif +#ifndef JSON_SPIRIT_WRITER_TEST +#define JSON_SPIRIT_WRITER_TEST + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +namespace json5_parser { +void test_writer(); +} + +#endif diff --git a/json_test/json_test.cpp b/json_test/json_test.cpp index 6d63fbe..ebfb89b 100644 --- a/json_test/json_test.cpp +++ b/json_test/json_test.cpp @@ -1,29 +1,32 @@ -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "json5_parser_value_test.h" -#include "json5_parser_writer_test.h" -#include "json5_parser_reader_test.h" -#include "json5_parser_stream_reader_test.h" -#include "json5_parser_utils_test.h" - -#include -#include - -using namespace std; -using namespace json5_parser; - -int main() -{ - test_value(); - test_writer(); - test_reader(); - test_stream_reader(); - test_utils(); - - cout << "all tests passed" << endl << endl; - return 0; -} - +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "json5_parser_reader_test.h" +#include "json5_parser_stream_reader_test.h" +#include "json5_parser_utils_test.h" +#include "json5_parser_value_test.h" +#include "json5_parser_writer_test.h" + +#include +#include + +using namespace std; +using namespace json5_parser; + +int main() { + std::cout << "before test_value()" << std::endl; + test_value(); + std::cout << "before test_writer()" << std::endl; + test_writer(); + std::cout << "before test_reader()" << std::endl; + test_reader(); + std::cout << "before test_stream_reader()" << std::endl; + test_stream_reader(); + std::cout << "before test_utils()" << std::endl; + test_utils(); + + std::cout << "json_test tests all passed" << std::endl; + return 0; +} diff --git a/json_test/utils_test.cpp b/json_test/utils_test.cpp index 73cac15..3ddc599 100644 --- a/json_test/utils_test.cpp +++ b/json_test/utils_test.cpp @@ -1,15 +1,14 @@ -// Copyright John W. Wilkinson 2011 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#include "utils_test.h" - -void assert_eq( const double d1, const double d2, const double abs_error ) -{ - const double err = fabs( d1 - d2 ); - - if( err <= abs_error ) return; - - assert( false ); -} +// Copyright John W. Wilkinson 2011 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#include "utils_test.h" + +void assert_eq(const double d1, const double d2, const double abs_error) { + const double err = fabs(d1 - d2); + + if (err <= abs_error) return; + + assert(false); +} diff --git a/json_test/utils_test.h b/json_test/utils_test.h index 9f65731..e2364c0 100644 --- a/json_test/utils_test.h +++ b/json_test/utils_test.h @@ -1,36 +1,34 @@ -#ifndef JSON_SPIRIT_TEST_UTILS -#define JSON_SPIRIT_TEST_UTILS - -// Copyright John W. Wilkinson 2007 - 2014 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.08 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include -#include - -// these functions allow you to inspect the values that caused a test to fail - -template< class T1, class T2 > -void assert_eq( const T1& t1, const T2& t2 ) -{ - if( t1 == t2 ) return; - - assert( false ); -} - -template< class T1, class T2 > -void assert_neq( const T1& t1, const T2& t2 ) -{ - if( !(t1 == t2) ) return; - - assert( false ); -} - -void assert_eq( const double d1, const double d2, const double abs_error ); - -#endif +#ifndef JSON_SPIRIT_TEST_UTILS +#define JSON_SPIRIT_TEST_UTILS + +// Copyright John W. Wilkinson 2007 - 2014 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.08 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include +#include + +// these functions allow you to inspect the values that caused a test to fail + +template +void assert_eq(const T1& t1, const T2& t2) { + if (t1 == t2) return; + + assert(false); +} + +template +void assert_neq(const T1& t1, const T2& t2) { + if (!(t1 == t2)) return; + + assert(false); +} + +void assert_eq(const double d1, const double d2, const double abs_error); + +#endif diff --git a/waf b/waf deleted file mode 100755 index fa386e2..0000000 Binary files a/waf and /dev/null differ diff --git a/waf b/waf new file mode 120000 index 0000000..b2369c5 --- /dev/null +++ b/waf @@ -0,0 +1 @@ +waf-2.0.23 \ No newline at end of file diff --git a/waf-1.7.13 b/waf-1.7.13 new file mode 100755 index 0000000..fa386e2 Binary files /dev/null and b/waf-1.7.13 differ diff --git a/waf-2.0.23 b/waf-2.0.23 new file mode 100755 index 0000000..b4c9008 --- /dev/null +++ b/waf-2.0.23 @@ -0,0 +1,173 @@ +#!/usr/bin/env python +# encoding: latin-1 +# Thomas Nagy, 2005-2018 +# +""" +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +""" + +import os, sys, inspect + +VERSION="2.0.23" +REVISION="7dbdd0b348178777c338c9a31f6218a5" +GIT="c0d5ac00f8315586cdcb227cef500329f00aaa44" +INSTALL='' +C1='#2' +C2='#1' +C3='#-' +cwd = os.getcwd() +join = os.path.join + + +WAF='waf' +def b(x): + return x +if sys.hexversion>0x300000f: + WAF='waf3' + def b(x): + return x.encode() + +def err(m): + print(('\033[91mError: %s\033[0m' % m)) + sys.exit(1) + +def unpack_wafdir(dir, src): + f = open(src,'rb') + c = 'corrupt archive (%d)' + while 1: + line = f.readline() + if not line: err('run waf-light from a folder containing waflib') + if line == b('#==>\n'): + txt = f.readline() + if not txt: err(c % 1) + if f.readline() != b('#<==\n'): err(c % 2) + break + if not txt: err(c % 3) + txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00')) + + import shutil, tarfile + try: shutil.rmtree(dir) + except OSError: pass + try: + for x in ('Tools', 'extras'): + os.makedirs(join(dir, 'waflib', x)) + except OSError: + err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir) + + os.chdir(dir) + tmp = 't.bz2' + t = open(tmp,'wb') + try: t.write(txt) + finally: t.close() + + try: + t = tarfile.open(tmp) + except: + try: + os.system('bunzip2 t.bz2') + t = tarfile.open('t') + tmp = 't' + except: + os.chdir(cwd) + try: shutil.rmtree(dir) + except OSError: pass + err("Waf cannot be unpacked, check that bzip2 support is present") + + try: + for x in t: t.extract(x) + finally: + t.close() + + for x in ('Tools', 'extras'): + os.chmod(join('waflib',x), 493) + + if sys.hexversion<0x300000f: + sys.path = [join(dir, 'waflib')] + sys.path + import fixpy2 + fixpy2.fixdir(dir) + + os.remove(tmp) + os.chdir(cwd) + + try: dir = unicode(dir, 'mbcs') + except: pass + try: + from ctypes import windll + windll.kernel32.SetFileAttributesW(dir, 2) + except: + pass + +def test(dir): + try: + os.stat(join(dir, 'waflib')) + return os.path.abspath(dir) + except OSError: + pass + +def find_lib(): + src = os.path.abspath(inspect.getfile(inspect.getmodule(err))) + base, name = os.path.split(src) + + #devs use $WAFDIR + w=test(os.environ.get('WAFDIR', '')) + if w: return w + + #waf-light + if name.endswith('waf-light'): + w = test(base) + if w: return w + for dir in sys.path: + if test(dir): + return dir + err('waf-light requires waflib -> export WAFDIR=/folder') + + dirname = '%s-%s-%s' % (WAF, VERSION, REVISION) + for i in (INSTALL,'/usr','/usr/local','/opt'): + w = test(i + '/lib/' + dirname) + if w: return w + + #waf-local + dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname) + w = test(dir) + if w: return w + + #unpack + unpack_wafdir(dir, src) + return dir + +wafdir = find_lib() +sys.path.insert(0, wafdir) + +if __name__ == '__main__': + + from waflib import Scripting + Scripting.waf_entry_point(cwd, VERSION, wafdir) + +#==> +#BZh91AY&SY1a&#-Pe(,0M0b<{eЀ#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-:KVFv#2J6gۻt6[6MmF;}]]kZۺO[{ ٳn{nhݷeR=8v{2͹kCM|:[6opȾ#-Oc@QӀ#(ݝ`m뽤t}5i#-uݻG6{`)zSJ#-@E*R9#2$#-P:4UZz{Gzٽޙ^nɘjlZeJkGO#-۽e[޸g]wqRIom{{Oewe__=^= z:0%hYZk'v{[^{n`СxѬ6ZdTS#-( ̗USx#1eS{kqQ}k>3҉#-#-֖muԺ}{;]ym=}/zܡ}|+/ʹuqק oq+Qml[v-s]mӻ̓/{˻{n^c}juí:>aOѭňzioq۷Sk{=}foq1Wl^펯0>ܞO#-}]}ץx$#2H\Lk7kC.BA1:UޘnW]=]-#Bf#-#-wyD#-#-/zr;콙#6}{jwwFn;H{zg}wRSit0}3oD3޽{׺k|[DfzQr]]<}޲wa6{s^uqYăjVP{:we]׷^ xWeWtj㷛ӹzT#-4΢cm{w:8;\;x§uy͌ġ}^ztgЧ[vݵziΏ N{yw|#-9fյ#-וyq7ؕ#2ZHVݜۜ{4mL4U;۝Nꓥ×#13Xӽ1{Zo^;=Wޯ{ϻo F7>^ƻuy7;wwۏO㼣M_-]M&@#-@&FɣC@M?4Ҁ OSA䙈 M@#- LC$d#-#-#-#-#- bh2i15)*yOҞ)jڙ#-#-#-#-#-#- =R!h&bz{CJzzhCC@#-Gh#-#-#-#-#-"HBh#-@Fi1M=4#1#-#-4#-21#-Q@@#- zT)eO)Pd#-@#-#-U/5+1$ |jݦ&FLF(T$Gb#-wt+@3S+2g0.o#ciw/Oj! R0&d)dxʧ+.V0vʱ5>#xJ@ZxXDF串p ``#2Z+mb6mlUI E:N$F$rX 튔EKAPU 2(HS2d,fjf"h"m3Pc RiE6l(LA(jj5Fmi"4KD!HJh$#-5,h`i*m"dZ)e[D BHlLFfc5Pd#1)E %a-#Jmlm6VѦbK3!4D2ɶm4ԔlZl͔&b(*"iE2(6B#hhBI*"#2b6!PH,@2#$!X!fI# )ee3 i,E,ɱ,e!#FҚ`RdQI&&$%D4d$X&e- f Q͈&#ZMIea"IIX*!$J4H` !F(L3cFRjHb iM$"H[b2F̒3bdE(͑&U4Đ)HlX $iJd%Ȧb l XbjIeAF4)&beMY)2&iQ0IAF&R 1`dXLPF2fe-DLjE1#2Dfƅ#2TE"$$cc*iňHRf`Rͦ؈Djd2#2CDR4EM,ԩJJh6FLdȦY#)!H,UhM)i5Dc`LF4*4"mBi2E"d,ȂSd1J"L66X K&2* XR$cc1 2RXYJ&EM(ZhII$2ɲ#)E,ѥ15e"$4J5S4e214fDEh5),f)4,QiHQM(B4mtBT" 1Qح)M5-!j6MFDai2F`%Iȃ134d1))j6d ŋ S-,ɐ&TlHSe,RS#2lfjdEledJe6URd[dh Me-!TbCQFJVMdjEHkD$mbj6hZLQLM14-4m15[$XDRֲC!2k&*F$"i$Vԫ6)MRT,+SHҩdLbВMe#1MeebTi"BƈaL D#1 BѪ QC&M&M%DeE6RA"f%#2J6i i#6I#cd)SL#21#11$d#!4LQJdRP5BT4 JBj-"ͨQ)$ hRE0MIXE,-4) Ě4Yda, jE54ECF)6b)-F#!&@4ؒ2)6I RaId&1M(idF3D $(MF&LBM%$$EEbљl4i$Сd(6(Vid3(b$lD[FjQ&,( RjA B1R6JiB4ILjb2EJ*cI"ɢ)BԢ̔ISbQ*F*dlY5FŚQl+֓"[&*IL)Qa`(4Im$50A2`BJl͉*ed244QAQDjJŲX1h& "4ZYhj$Ze(Ml!j6Ƥ""R#l56*ŴjJUZ&mH5Q*TҬmFIQ f-F+iQQJVf*I52VœlѣXRcFѫmՊDʅDĔF*HhѱM$ژc$FضŦj1eRɶ jM5bh(ё#1Rjo;vlQTI$Im,l{OD&k7)*miE̴_V/JFgsm^v77^nu>m1E'VE7ڳK9a,K#2I$mA??^dg˯'mɌXH_74Ju8gBj?evjŧlNI-I勲rrX?l٩8QhZ!II #dMɍl~47wHLo\үRYA&HYeS\RJH#Mt#-c38#2Pܲ3znhlAL^,0qز w }ۙ4Yt\ɯ&)-)>dzo_VkA;][E0›Bd咬4Dϗ11؞j%?͹r,NN["M+{Ϟ͗7bRSo״1#- ֭l6w^lsES+t^;llOu6Pk+-ȦWȶu.nmBd<|s>6Lf=4vh_;k{۔Ft##1 HzeaۮhMu;GJ̔et9̏[oWt1iu#^sqrjł)G֓Ohƕiu=%MOM,X#2*C#-nҚ )p3ƾ@:?- 6rfLuBY[dl집^~+(2)iD1pq-k#œG'V65ף6&/z3(fV9=;PW}|YH)ɨ>~s=ۻ[&$EQHNBʝɺgFѣBRYm6GƂJ:[2ŔҠwKg~x\/]h٘IP#M+e#2i*Q]Tƈb1A9G,t>!klJ0TTMtehUbZLqW͕7e]iBTTQWL͑dDiGDPaLֶjϽ$![QJ+aCP;] I+^e5Z A~:F;KH~|>8499q#11K0܆%[ ;~㎙L*"sMՆS_mGSN^<=98Q94}Jr;}pu0!it?Xף]|r_4ꅙw`ҟfIC?,Y VԀpBy=-%mEa)3eF^,z*G p:a#[C./̗0t"m#1h5v*F]ǁzU2>l<p"G]dmmLZ$:#cG4Hi:#+PF:E&}ٞvC}X#1 `8FW_fSr#10(Nv3L~Y=g b<R:I2\q.{ϩ,8`=jP4ovpoB9dkrmǨEƽ]nC=6|Z5aSו)FswEw+^{5ZU|#2)˾cT @^ǡ*L yZۍo/[1É ̋e>ؾi[w25^/!*n4WOٿ.RYTNLYP:ZPPNm(7+]}}]Mi Ja>еTE”Tϕr~|Tj+aGR|(ES>lv߿[InC_Y>sչY$OknFx*F5e!ުy8O6S!jz@J[FSJ.]{#m* ҊV'؝j'6ʴOb\Rv/B>?\ Aq#-˨#҆ `098I /NP4QHXE':r-|74c>ގ7DYTN{NБ(<צk8S;?[u2 y=skCjJb)ج7îpv^/FZև|\TGX^rEԒμ/H"")C m쪤<ݥbRhrHطP*#1ͮS">0ȊŊTQΥ DFKύ=!tCDh,I YV˂¤X#14oW,#-@% h#󹚲^!)'.:o1>>!??7tWwrrsY,-|'U㯢;eFÃN=:$ Чej#ܯ1/q [kŢ;CT*D,L}uT;ng z%G6"IDo]9M;aA8Hcr#16 9܊SRϦ H+67ĶSb!ܭvჿRf(PS.O}y^=uv|1G] #1@yFluƜXȘZ1ƲCݵYxh֣DhTTNpCN% 9D9өuꢇmuVFzU/76=,cy^\`˳K|q+wpuI#Z=sazFK4CџF7v:ߒ_Ť\鵚_'eͿ|CidBn##lJ#2sR4ř"{r6uTG(4X Te; 1$V@dR#DT1Ԁ:9R(,4č3=f].ylcV~хb?g3d[ EX)c$E kc|dbrKNzXs3#2 +&j|#2xE\dymqKzvud#2/x@lj9ݶC<#1ӂf0⺒c ^];8ŋqVBnjuJf*D94̰+5OLI ,ڪn7'3#6Hqox6uga>~#1Usf]|У$IDmyȹև/-"QD@zmG1as=<'>(f7@adyQk#-EDL <Q9k-]=wZe"35%#2U2ߑh W5v물,Q#e|gPꔰbI$i#2't̅6#-'n_ON%w5йB6/Kٓ`B"6Ư /#dIzW% in-b;{#eJcfέVgWT$3Yc0kn)VnԬu3M%.l)kZC$3T^fn5#1sp{k\(ۭNl;S)rj̮?m/#1o1o8e:)do6hжFAxkh[hܦo6LlT'8EikGlبX?OL)sد*3ʝ/ykSq(ŨAHoh=KRoF.#Pd{pH.]Ũs÷#2]75hΕD.{%=W/F(5#;D9_y%0Ij[J3NMT9OxcHIeSy֚]"Vm\~[ >@uޯ-6h]d~Mr'߸X(׬(dogÇhiA^3lJYko첊LtZ(a85#1*!= !Ԫ#1ͪÃIΉ^aمXIȅOnd!\9N3t>{lxA(j=#2\ڶӑK48F@h#2fY5Zj֙c^bSߴqۋȤ&X HE^l-kUeľ6N{Ym{i(R)1P^ۖ\3kNJNbDghjw嶔: omr-R P$Qky qFٹL~{Ϫ|_,H}}:yo:&8~rPhʗ̰mߧ*}$Fʁ/<}ܐfH.'Uw|[>M=Æ{y$*j .##-aI3p#18h!ш 0#1f2wZpiWf,`R;/ G1h}4s2eҝ<`u^#1XNźiDbyg(t_iE-y.F/.=:I^NǤҜ4j~ou?vhĜU4KD[鷏e +#-4IC0`| +MɿF㧽jCIε{Oz4z\.TVwG8Ld*#-Kp##xMD|w"#1ŻP 4#-y՘~Pc4uXHqdn4ÓU?ׯo?h8싐H[\(( z :NUwSMH=rH.qQq|"J)?0բɤ[Mw4~^ @̢nҝ_fN`OQ ! ğL@ a#! #-$'oVw卣`vܻ #1cc 2#-@?ӌ#2Lo#-C"JHu(&.wU DR}U7##- TpTX O <1DGP気Wll-(#-VOqPo#2kC, ]%Þ,F9h}\}i }t|kRjcc;4Rf0SM>U\t)3/驟uOOc슻`0l$iwPk mK/2eOsrBd:[3#1qr,GG 7ϣP}x ^#7ئcѓ;Krvdjbg_zupmuQFP\$55AXBY9E\Fb>bi#1 AQݏ"s !!XM%FB(qF!@Yc=ƒ EyzyK8&di%#1bGn~LbJQ;f3t#-X1OF\(7)ɚ{O䭪@=W,]b"8#2Թ{  ^6kp[g* f=>Wi n|&ҕ2ԧ-`y=F5q{m ~e>{A4׮[H8ۨ9CK y'L&)#2#1˩kU9-ʯ((^Sq#|w m=+BE l<5#2Žib[#85S 4#2`#1~H5ٝ>:{?##-1s,9`Z'Ƀ2"ooNiƲ†17ƄNIwSnqMLYj0;Ƚ}xHmmy'Ujue;30Msmp>i$UBiY̨uPY֡1u5V!Uj: 2r4C,C Y(6HAh 5z ާNuCR}x# 0ud#-N_0efeRh,a#IfTQY{ԜKUkAuhM%I(k[F#23-b=cJ4y>3:2(uy!jN#8sy#1bn=>ty3 #C!L97[#2ġ̺-us.ܨQ' czcv!#V:;ɽ:w+coF1Tl[,#1ϟO5엟[ftn5<⬲me>%{q&=t8&abʆ?e,ٟ;%>3SSgC\*5% s5CsDc^8x=#2͖2_]Kv.wu`#G7Hۖ!?͞[LE|y_9^Ѹ01ЛiRH6#1SXSF(ʍ{3ۂbh4\JDq#-6 H N5Plxwj>0َ.Z4HFõW>UzJ);I0FJnԯh? v#1l < ņ+s=EP_mnnԼR˱!}E#2*2-¯2uAO7&#(d@@;gMeC*a t"}~};,dδР$|zkTj;Ͽ䥧`p+:a eI?h­#7͚yx/cZ4ۮ&*8BFzIS᎖bJ☦J(Bwʼb&a0eA2l0uX$qR"wHH>x 9XLs]_}"iУNy'#1&y<42@ 6K|[a#ۤɎ4$;>)͙n$"ص7 hz&`p.`cc[t.V"v/){l7nLice~ԉؘ̼|sb3ӎ7;5l+cBf#1]reZHQBU QCZpٲL8Z!'d8+S!9_TbD*l?f#1B[f)yw0}X`n#-&H:G֚'~(L2uM`IX_>'_v AOLj8+E^LYMn*AjJۖo`C/L7Dz[UMB!()o.-/íCQ?-d\>[Zi,QlFzZmId& 3eK8MlUQFҊhTI?'Xҿ߷8nzɆ8dmv ,PXTR* @I)R Wt/bkSWKF'×ܤ|i>:##29bnȤ(O0"Y4J:3#'&@(AU#1ү#-"aTUS!<v~Z{vFlF'Y(iAX!~S_/$~`r}jDC7گ.c8=cGo틀 9o/klU\kX8~(*q.Bƛg_],jwh~6~X Lovθ$mUHU#2z$?0c€Kޡpվ뭢j1P (+p`3er cRC~-:ݛmR](2t\_ >2. ** 1 =6qv Q}GMbq#c?1 =<(#2.0|^e#b)qPdL]A] $-)[q*FH tFK#TX#-صEVuke둇q?oHKb''%=-k(]ޠ~!:$5KVZg|g?bv$S{KTMxh25%}#-]ҀvHs@%ʼW $'}i#11 J TM_#-^.Lr>SκW('3 b+uih9b@bPB#-ZAB-#EED{ Rszy>}]{xKFb: UKDZ!DRoT:żWߟii٭7V}~L:wp(}GlT:}SRe}UKUz,`]5CAK)Z꯭޶Enf߷Xݳ-ՈX Zh.p?j[u<17k7!_rqiovsly喏t{vǃhТXKVo#2Y1>{0x=CO_K} qH#1Ϲ{3wO>*>>?Mr!< 5JmZ׺-gϯ]%m}0͆^=85U4ѵ|dm|-Z>cDv=o\C(ݱ˵c:$V3#-}ٮ])/P6r)9WvU΂^]>x7xۤѯO)1]YS3<ƿiQyaLˆ,ovQ6#1/_|mݳwn#2sCƺбvUǟMRD8;DXh[11it{?GxJx e^߸=ɇ6#=N8zU_۲6|P؊ﮟ^~nC(S;B/@`rwok/ؠ2@xx}2pU4dGZTR}iϊ_6\2t.m؞o7]g㥵m:?2wbv=#1jiUP#ee9|{7 ߚ+wz}I}`pwul|VJYXINpTX\ʟ7}fȩ@# ;)dj_*WX9ez}?ih]-8Om2ѪQ;1͋K~ZДQB099DX?|r^ag㛯#2ͽ.Qyv)~+?dZL9Y:;ufO~<o'/j?o5O/_^]_xwupKG1E,^^ͮBfN_ (3r<]U=x(\v5ct?5;k@D}S>j>qߏ|lԷ]#1B_7Gwٓק:!u}4'?-"c=Y(4|8#1{bVÿ˼p#-UhI_#Sjg?h)vFfxcغK[OU~3=[HmXn=}UVD}LO'}@/2A=-]_I$!%'i(յE/23kKwyoMե|Y1x|AagNcw6+8t ś|6hZv:>D*}T)8:JU/uhЂiG6}JiuZcӻMS-͑2fq`{s|O#-/`r_xvMK\,/iWz-X=jv$nۂM3B*=ԭT8j0X & #2Jf&c56*hi'oG|L1~+S<& =a5G%u޽NBu!alar(eA(u_OS88G^Gbh1"GGJfm IAH(TQ&Fը,MمUTU@J*fiQըϛL~YtdowA!E]FK#2njeu?#?t_ٰK=*}]1wO>`o;οל;#1]1s|VT&ꮗ|*[mecWj $ow.=~٧ѧQ,$AW#1#-p/QMjߓӫ'p~~z$^o_=ްeNk C7MPTԥ]My+5pog"mƿʯGuB,/uz%0=5hq_;cFmxUբEm(dR+Far*Cvҭ7z̥Q&5׭נt`ZONE1J Gakhh@e;n0SCUZڌF0DV7FpmdI7#2F5ېMȠ`B#1Qfbpuںl611fD3#2ΕE> ;Bx [ZXJc?#-\oK#2kSyhlbbeCN"GDtdHA(6ESh##2*1H!!'Khl#21$Jb H{ ~qa(NUT7Vc'u'Fh2_;y:?Ix_;O`QKthz}O\=g#**_uy"X{3\\QzA=ɰQJTh!<=2 H~R3MqOʽUj㪳WχCpe8~/ &~Cb|]gϹg|0#^U) Tnt؈mƈ#1= 7=7+k}PYN͓:1i}dGe)ua!\}1UMB_:/ֽR0ː*镞z!U($٬[heU4%#-u?їM%і( ݉YCFFdk>Ny~#{~hy^ ˢ$H#6̈=(R0 i KCۦR6kOZ,[W2ajViVEXf h#qTS3 (4Ej,&-/؈L{#[VuYo ߯@V5Ja jFʘYsdX1HȺ% jEfޭ:m6,鸙D63h2@PL&#-Z7rƣ-oFVF#1ut(%lҬeɶ*=SѣAݏn0C^e]w u끹(Ik V߅NМ#x8$tAb'~m :˓#1^uJH#/5BРhcŘd/YM8a#2y{sq8"2ӿb=4Ǐ?(xiBtz3?<bŅUO•T@/WHԎqqť%N9U]:R7Sq;Y:EA1!Dg{l=qzM7BvGlf" iHۍˆDCiޫzh㧼b WFQDOU)t&ϺM[1@|t>PALmENsHKK҃93Ŋ#2|kjmYۆXC~6?lY#2AT8p@Q}Ͷ3U\(L6860&Ì޳BLRr8;\;$3 #2|_Ĉam犁'W`=6V&sGMeuv7jHpm!& HHc,_>F:Ƶ-#-ƼP>QcV+UZL]IK*Nj;c`om;F2iJ-8Mk]+I(5#2#GFFK~6uQuvwPVM%*78(6]qq(5#1k[r+V;B'F)9;6TZfP;5KM1dፑXe '91#2A䓜lQHK]naZu `my&֤ȃ#1e{V6&-g[3hM_y*q=s^NII*JC1OGi/_~NX7Za8!U6#1}#1%dIF6$,5\m4b-TM^"R".f哽FrI5Q&㨇RVLCLe/ZFUB@␲||†LHT>D*}B`0&FtEs_`0c&/taNٽuçw/+#2Lj-,Sv~:Ki!>CЉgnqX#1ԏM_}biRYQTe*mX7Hr*L#27'm^YtNWd:/VRͲc pFiU|,nÄg* L(Ŕ:gMP_Okc֯ -[AJ6E;҃(;te4su %;Qc3X vdzksOJ%闕kMuӅƎO'0Ɋ:PjuO]hgqSgq='=5)7Q쬃X,cm|)M{ o1g%q/G_ݺݣL!Ե80]I 9G)+w%8#1FR/(?7sGTNnQ 9,=UDyΏZVۃ+ů=c][|#1U_1 28|.zߛ򯢍#1VۀqBlq@P<K28w01!Sb PWi]uܗ\p 08'h #-!!(#21VƍG+;hJ8*& >%RYpP+r y]A.X 9yos&ǡ8.}TusEZ!owp|Mb F8{`BtfθO2?=s7 ď^qBU>SP7x"ner(AF%6L[2;BZ#24d[pP{>ǿտ3t|G^nJwoYLDU;;Q vEx1 |ﻮ6]滷N+EIEbVR ([;_mtGIRN4ew\P݋5(>BޚNќTCpM_=x噺yB5ьNyLjoLk.˞N=_t&aY7ϒ 8y#2E6rhϬ^g[{7jhKѷC[-ux <jif#Yׂ1a\1M?KZQMvڟ;╏#27_f4Ɍq^nM2s=^3'?&(~ ]NcB9~Q8672{[uY4bG6‚HcA9:vßL ԅ?V/`"8ǀu飢M,ͱHʙ`Z)U̅.Cx=8!1ȣ 3"нĽvwbl -r<0Ywnr=ӆ;-=F0h\%B[iӮOU/;d&Gyݧ#1d#11YfCM|#1U`Ɏ"߇c0$1|Vޞf08# t EdV;99~ܻx)kǃٚORtK`ETjްQDT}mq߳2#25ε{Cjo(Vxfᯗ^Sސ\'R!ًhf;C;N* r4+2Ӄ>Q9\`>۬nqFד;7Z%XpvG&2U a/*tƭzA!T`A+%s,M#s뮊V-V>QET <ωՒ'lļpHUVoec3 ɴm ٬jwr jrGE/A!\jl>bE#2!si+UKgnM,M#2յ^}xBBHӔ,<>w9K#2M9շA#s`Oa~sP8s5鉏CFBΎ6|Z< z'#PF*0W{UF%6z~!/Kcjьs;ۉڕ|."vd$Gd]..EEp;94oOK|܅գ;L= ::(~%ڑHIj/W=}㩮0kO<%ŁOg)Uxmt0Kx*VfFVۛ[hr$޴:#CcDOtߚ"7Q0t>_at-b$LȂ߯ǭ:DX\愦5 6/-Į$Ҷ|ļkgX3qSghOF9;bOpoc'UD$ϕ-O``20j⚛?qMW[6zta*} 6EOmµ-^#2 ΩƐJUC6!H$oJwKRs>RaEnzSEˎ!O!$t|g@eٍ44ʖܴsj +$uT]u<:rNIKM$Wѝ0b$Qd0;5rе:MnsWXtF͍s#2{ZHA9&UU1},%gX'g(a!B$#1+j"8ϓ0o-e#29梩u|]Cu!qʞ!\M|~ފmq#~H#2<~H̲x!]=][J^TF!N#1r_ߧbS<U F5c o!uYe)gjێ㇛5&gPk;ZsÉDmyL?q^Ngդ:8덺5c"+-L2̮Mj# "DֳstjGLA#1:D&/Ϯ靶dVMreVѵK KM)U;,= xSg>O1]\Aع'j*hl/u|bw0 #23Qц*&R<XO, u`L_o٪LKRQ6hf2ngsT$Xr=ްRc^+ZmH% ?}$$n!i)#1nB#1 sT-(r"dF.oܱGKwڳGcۍA |{eպuh>$hU:f-r)p·f@p(@3y'"%k,J ͵MΗخsn4seM)g(eP\ k2;P G?QWhUW% M h&F&}#13Rd/alGN&X8m7fuAǹ]2ׇC&r[0g=bh7HOmUc꒴w@9RcTkimb :#2mjIf%ZlP{nZ}Qg䷷\љ~kvQZ!mNd[ƄVMrpo rH,#21C~iɃO]l'OOd Js_tHcs{5.ߡ%j{p2WUr#1!:֘@embTvaXRUU 7R*,ga.W40G<س2A#ۭ߿޸jgt[zLE;<Ϡu+s #2# < P{@dI?-UfRDcyeO}kR?*tl*8̵R$*/c 9n4aK&{0:D2iOL;-;9"WG][`,>7$9η9|a%tOE׏ꍷ~M#lFhқrMbf!\ACht[qv ^w7ڎh*fAs}51ZWB^JUM^p!L!ŸUӫEUe}+F!~0ckdT#2f=)h=Xfg~CA-En$HLM__Y=c'jN[:B*.)F(= 66M1@|]f.s۞(::l=~|Yw'ൔ8+=kӵ؋5j+k$3RLv+2HR+ rيmdYy:6as}9ڣ̈́k6"*rHE@#ިɦ:c7[7u 49ѹg f5C3v=!Zl\^2q6ɇt%,tFn_\T Rz |'+}loE}B;G 83h+(ju)9&Bul)@QpoOu-)* ç4Н셥^[?5!p99E}Jf#-4lVܴ AWX\д99kCvYބCXK uvFL$Px}DywP>o>x:b3`<9Ko,w="<DBN#2үE\D͋RNw^hB-L зUr7bQTxCs:i8]m#-ƜULfi#w)T[ǛYr~Ziq L$cfnj绣D-8}r!eg]0^2VOM*b7{b>|#1X،`! A (e\pr?>k/۔jɽDRq5,l:El7 "%U>wVn%8bPC(Cpt<4שU=}胠/`mk1B+6Xrsy |v_.2o$#1䲤W3&8fZX,eٽ>I hdYKon'%F/+Q Q`sqG5]nAq$s=>Ӭ?,; =>o}v"_ 4dRRZ"B_ЊMW0w9Mj~95'JbO5ohq`FZڮ@mmpkefõFctmFhMr k^Ga^#m#1#2ul*(%.QayFSA#-q3r9 1X}9#1rT<5]q~ʨ<B1F!#2Ha v#2$#-?@9GC'S^X $8@".@@>\4O72rH<P @rR=#-Sկ#-cG9xN\cQT<#29^ )Yʻ8)0~>F:s}؟:/>d*T:DYqqaE@RBBUSD;N=mulJ"0o"c' <%P#@q>ROA}#1h+ g($8PҀ5?]U#2'+s**#2>d҉n̡`W{{ (켬#ѭSp AP#1xJ#-|G&kMJ/H$wY8+Bb;B˖k  fSQ#-rP\ ܠXt@äB=TLdG&(r,#-!n`Eu؅,"jKA[&TE5),dEI:\tQPY#2/ace(lJ4.tXAİ"YT$*Gt#24(4*=`@PKޙ Wr5x]#1$ڛrn Ufߜ^{=j~zp)\uU2p️уVtde;68#16lTx4XC); +F3s ddOCdGV[kj:ɦ.%8L/U]^`NUΙy&\}天DE5MbӍXHj~ h_#-6uA &ǁ`;&$!S4f̔ŏ8$f EUTe@$hKmnx'takg=7%*vnT34_:"1"(p*dP!(+iןN#2jMH"Bvheϥ#2]ЛD\i*Hla54+qtvappX#10P{H6*i!`ԀFv5(nC}sI?7ʛYIߩ29OcBz#[0 m4#cdgvdzdb+NlS#-;K"U~+7eVJbսJ5o%ʵIF ,'3U_GϦIzF. F*(Qj6xIyz@+#1-7@Â\!{!r&x) 5ʲ@by&_6!GF )|;ǍC<'tsH-hE_[_ׂ@^wL)dx7O#մk5JsFT9WlQIIoWksTJ2@Z"Tlսﶵ/ر`̅$HU(:MtJ:k;zߠxv`#V&0B"#2@Y%(9ҎgL%#2VFE F 22U!7yqFtԁ=gff@(#2=LW#1N<ϳEMUc>G^1`BJC]x3/7vjRJe0TP Ӿj/@{|8aWoB"cɨ4 p~(!Cb=w-S-Oc%F=6ӶD)@m\#D=8~Q01C=rgBmV.(;. ݍb7ηsKf }>-voY-N{+|j}wN>Qζ{^E︸ه}QuNPѷ 9:|{,Im$>,$v!׻7B(\L* ;mB$ӗk]SJDy>%$U^ Pپ/ `;c Ra39x78 *Zh~ݔ1!4He:n tMDَ%}/곬t։ΎX* {'icLB"YPOi$!#-6><*]rm[♰#5ǯ\4\qeԮX=bPe~*ulD?]/fA~N}bl6ǐH$I?̶]̯D@cW]Kd7k3Ŧ,k^>RtCb<'|7]G(ʂDC(boO4inOUk,V;H#1PQ{ӷ'BΤRuڹiDi6mI)6־^sd 3G|7OZyVxaUd8΀`>,`^-j15V8;>eP#-P׍K-<*x,Ԕl~u7aX:0!!ޕ:#1v(ʼn3XnNG`b7&$g/a  cgĤKO?fPa@UѰ#Z~(:0`(@P#-}k;?ǃrOV Aҷ'v/eWȖx32}V'_§en{lp)qE;qNuY_܋;~{#-ŝDjd݊4 ߟd&-Vdt)FH)#1r<+#1n✼wڲD#uaHk!)'_·]%|_,Th?l( p[^x"i DO_o_KQQu'**4EE>oƕNp [UӋ8>+349#2Ă "w ^Z'ĺ2$#.]8L[Oߋ|dEP IC?|ss*}-{q$#Ig|;9cH0iS!?2P!mܡi)_?g?1k9 e5J]ԩڷu_4&BT*E:6&ΠC&#b`$X'KTAQeμ?7 #-Cstb$ ,L˖߭#-!%qYD-5lifɰa6C{ps?76>T(ŸD+ODK#2=Mcﶴ'#1YNʦ1EGݷe†zʩ KtDH@H!#)(rOΞ\^.X>Wg)F$'1P0/#ygesc&el?|4HDz ȹÆ^rU-]+UGANU'Y-|WK03pDO *H<\::8y`YwR?%춹\|d%7z,*>!СE@#--n&GJř[c)pHNΪ}&c>ҿG#2过 TK,.]O  {PhƐ,zJ#-#-s?P^O.XMe;eӰ ,G aEu={#-E ?rz;m^'祑zy%}#1C#-@2AwD2SwCs_̀@#-+d1-qX#-yŹ39#-{}7޻"#-΃j4BՁՌ1IPfģ2zvmC֞~eWOhxeCTg2 FC(>xBe4#-6UHBmǣFh6'&#-`2YUӜZ#2x;N!G7@A!BBd@7>uo!iv9ǝoT?݂=CX`۹u_*lX閬&3qԼL~2g#-f=3sZ7=*\}[Pt|<5Bl#-vU(/t#-Z~D?z̻u`O%jP_nb'^u#1mi_Mv2}c/@#-@b^|;[;eAb@6Fvc1uYW^.t5pxq*4B$3W^P#-;֢ϭpa#- w>b;@=0,)"-aR{Njz檴`ۨ]cRpkQSN褑掗.?_{Ӣ՜\ofQ} wZkV<ֽ3g܃Jm1LDU2wIJQUMy6؇^Ec҈[?[WYqfD.^!!yKyxCufҕ%u6>MKES0a#2(5q#2SP$G)\<`eCPTfPF82}7_ka`+ZXF#-ïc?eVǞ#2ߏ_X(9>Of2 }`ı!#1[-3+Z 隈0Rdi^QY|WDٵGOw}!)he6dv=6UZW+K -+h~X5J]vĺBIA#N~ڜr\1c2cG1V͙rJy{o=9t;:3y=X3;h(ɉ_}f8\[Ekv=A~+ |yLz䧈SW5ߖ,2X~K' ^/MNǕx#1}Q.oly$E{CmF7o̮h ߪAK=hj7Β?O9<6ڊmTZ}\ Xձ#2`]*'y0;͝8ޝ~zsCLH%ȵڝG}j{_]Fٜ_zv"lgH/Tӳl{l(N5bq ІS.t%nOf#XaJr{oi}}'#2ÒIBLy߸[ѫU/(beWHs_c9#2=*P#2Cm/{Jmی+X6k)F/=~Is*T< ,YZB#2'6y,/Y4Nq+~0l{|dD۟""N]8o4Y.E42r+ܦҾ1aN"{#kq۸A[mgTŮ#2`98.)Sx^.);κǦd񨟓0xiws!'B[=BWkIgM#G^ H:sX3kF(p KclϽX.!Ԅ#\o?!-sR/7'ywVު2&D14'ufDΩm&#2W|3V3'[}!cATkw|T"xwY1ˆ#2r@(h[To`!XQBr yg5ܪ{( mcA5c |l8>ьNWEݽ@Be#N<;_\ߵD{9-9ڄy9N] Z# pN)| z}x 8җwKނl<2$$QqNQA݈ԻL8;ol;Agq~F=)8q~>٣ρ7ʽ8uChM*ɆzN2/g/l?#13#1#ϤQ9ɇ/!G$;PP4=Z~xOs̛z^O;谉)d!7b>7m? k$~NǤlW>ϳ:I à\#0Wh<"/TyJ1]xi)ؼi'Sf8P`|Զ Q*AF}1$T"~$#1YqrA@f#-+ 54 =;p>޲)q,&IO# zeO$>hf) #1OxBDbE\yw;9q34Ƚ4otj;#2`Mjê#-~(T:~̏J7Z~X88iTbP]C9Pjg\d;$9* k34{tx: %#-,aebT:q#-jR}=jnCE#-}zT)AY`A#2K_Is6 P!DA&N0#2#zY*Mt tl,tgg2jbON@2q7&-#2SmLzP>:Q8w76NWU(~'q>D;#]jQ%x.-\mcЪjQR?#,3|;rџqeYj~ieu'ݘe;gTO sQАyA@Ǘ `Ic04mTԯmߓWIyC?hӶQBT#( 'U|R8^M#1ۖ<`?EJhDp͓èM<ӪnU[EmځA/o5\xj#1ȅЋe["Bc VǮhh$~5E Qg֥||BJD*2iy(ZOo{onX(u.R#ܕ‹>I-CQ{>oztm>:{+mb_\AR(]{bȤ^?YɄ&?fVls;ز8"#F{)G]cNWL?$#2׳IXL9<'휇( oT!ؠT>(SHV#2%夬1^#UeM73vnu _놩x/7n9p8gN"4fفBQ#158.Os;8{$e*[墫eVNۤnyYi,'d #1}(FOONN/8J&c޸A$]TG\ˈ2Ӝ~*Eۑ"c|T<2V3#x#2^ƠKYՎ7 CqՇzv~6Gy#Ze됝}K#2tDZ#1WLK犫[E=/+A6)~NZYh#nCDmO].7ֈ\Gtttrj-s1W(9|Ni(s#<$.zhyWVa(#-|)hfKR^Ϧ2J00`Si)#2W+KA0 <}#2#1s# $yWj@;l߯e"W;G73^+r5S#-^;<X@eVf#tҿ tñZA%9kbTΫ;ˁxMr>_s^#Sw%03ZEw/{U>)ZvV/$rDHXw_-TpRH(X.}*) [ׇ~^N扟?vǥT/lϽr]}Z#1ՎGRjpwe`"Y#RF0.dY Dr r9#VfV,v_!m]%,eXO%B*3k*L-tt`ԫ5j#2B 40ȅȡACkFnW_Oh0"g9%ws@,Mǝ9$WsH]$X6#2$LVΈ;Ũ"48Qw"z0]^LFӓ7.%bE.f">M~J'fUuD5dK}Vc*cBy-ciNdi>XlL,l#荳:Ε;"mnZUAeEMb'˵jۈ .;%CTp'a7)bGnȉIQ:<6[%z ?`ouJG0ga/yUU}p?S#-"(U(R,`-3_@|hIxP X  2H#1UB_Ke_T;EڍE.``ş[=^OnwXmY?P(a8 v 8#246p"f'.bW9}(&-AaBɞo}JR#1Z9wUN2kG{ܝgTa|}nA/4#1#+Q_a_w;,/r iC h\wے#-jP5u_zz?ђ kHt}הqV®q|t1f ws_߻whS삹"8%#2#-W2phOO+Yi8X52Q E:GL30}ۡ&!Ph4;!m%7i%>Ҷ_vv  0ƞA_wVkU,)rmn #-jv ҁ>V(IY >̗#2XPd@|<Nb#1? #1e%0)K~OJ^/78S(SR"哏wXke#1jhr Zq MdHUUNI$:ܹ#n1Lj{!Mx\?{̸=)2 o:22ӡfAivd2Kjm}?`}EB#/#-?>͏t'% .e\l|tAF c'ׅWJ#1gp'#1;t:^hD4d&B?#1sH4P"]n75^ܚю0#2DIy#1"`Q?\6ׅR?bRŇٜU^2IpdEM4DA&P4ܩF0à32l90;w H̪šR&_Pf5^ArC봐C`goX[FEjI"8(.d?;Aܷ}r9*P%q#2J?n0²~V8@fdn"EG;j1-.Xf]dmffT!>r[CTF2JD4Yy$IXLԖy-f7V`ax˨cX@z#1#1kz)nXd{uc@(Ƣf/o_wf59i$zD_Kș-2I}MXͿ$nqH;ܟ5ѓM"J*!NAW]*00(E,nʳ}Ehz}>9Sרx:޻F"*Y5Nhcbq{|s MCi ;-:]5B#2MLqg&I#1^j>y'W,DiĴAGWہzm6N_O?u;"/Sᒛo Xc#}:Ϲ6F+0?EN3v7(#27)DKf7p`y ywǑ#2T-{ ?{B>D~D#1g#1mS#1dOy!8{5W߀ԸcgUJ*JRDS|HhC>7#-٪YPP |ΔOnϛ\{Jhyé?Aԝ^I X-2b'ޤ CQKFA; Yf0k ܬxw]/v`G ,[xSh0#-#sՇ ]==s(Df>'#-9!>J]`@|ۼD:>"<#-$dj?zX"Dgxh=~N{3:yOE67rXhkiϣ$VA~೪u<dP e~-A@:DH?&@}E 启ɩo+X~[Ϻ U[bbFI$ _X&!V+ ]4d>?֯I>S;B:|!i9XQ=gǓk*.Z?|lØv8\: !^o;C##2_q+;O3>Ax]>@;sN90XŇ}w9u2il<>%YUң% ?S98νy8DX#WRq֡CJOg!yA$U,ן7m70F=lpa.x=eu&ڛzL*$ZЫFIwyN#1ː)]Av(Tt@>>Ph^o`v`u@<{ƽчKh )SjEy|~~=aR7Z'K{*"&$ ʤ_Hl9CUqb*ΛH#-obJ )*F=g|`sEri|̄O:oI/D5h?{mJ=P@^"rq3F;OA2AF POIdEԨOQHK5yK՜%OsgA (C(T->/0c>Z[Q`7S,:LJ#-ͻt~"PkLh_[H7r 7b\~bTej#-#1X f`~ kA*n#-@Y)dE".% F*AJ*"9 $8tM@FOM~aȚ >*sX1K-o*U/UڝNCmO`~lS3P٩bY():3 0bgZun{OЇfHz3JH+oPާkî6!FFoy[\VL6T& [w^yB#1Sl-a(bY_WXS,S=yWGO0dH>)g7FR9w7?f)A5w!b #D(̂` jC! _J9)ak1<(LntK~ZFB6h;7}q#-6R#2;#-y:Fygukۚ. 4l-*K첏QK'ov /I.{"~6)#2(߽`>'!'%I(;};w)ۧQ![fXq}G{B$?rVGt*3&jB!k6IVI$}z}wɺ;kR)@]C{pKHQAETϟ*)7{(GaDs'$/g^#-۵HT!6`HD{@=w{~GvdF;:RԟPCC'ϽSHS,a]cp%dþ bz \I^~{f#1ďf_#-PC2??RS?3adk4QDAJEQ;3Bo#2r=E +;TiX QXp#1QB%N$$"KC@RȁNi#2|z\jBP:mUR!qpb~wlj`\z @ #1g = ߟ{zBo. S#2 =]< nMGNΧ;I%h?ep#5vDH`ؑyGS@>3I.2IT9;Q:Kgק]n*Gە%9pc9Wmi;6^sT4:)i$mRz#CÙ:гFDUfUQ-"8;9NvӴ،"(%?nuPn)=#-_{#23׏L' II_kd#2)rĀLMf#-?J}On-4u#s#PIg?~{~-\T=]X&5ZMrcooh9osF`r^#1eq>#-!?UvoMxK0N|)MP L`vHieDLnfH#27oX!(4$H|<\ !`#;R`]L}ߝ#1,'>zJ뵇zM=?#- 2!K$zwa|N(#-50۷݄x'o=TkᴨHII!]^7:g#/z΋ma=jQQEV17\D$0R$r/OZC0?Ja'm =vvD#14-슴3gP`6 u.*U #&L@H-'bO׆\~ga"y|g։T7ոS^t(Mg)b?/(BoP~?#-ٖ׺HcW ɐ섉"2qjͰ{Jk02#-{;McGrVΖ F$q&󰨡Ƌ(q"d(9 P 8CƮ̩PO#cj"Xl?`{r1 R$`:\."Ax+0{ܖ?^9g؇ q?#-J._K_rv1d<7¹IV DHSt̶O)Nͷl#o/eRdȂ$Bem <9B:xjai*f)\a+*MC43Rt*Bcaj10~݈Q-1j * 1zS.3~W3.%Q=Z-r `٬< $(C>E~%3Oݺa!#2koΟ+gaU+`/C Q̒t:5U*9&tB(/|n#=$T"%嶜W.|'|k\Nt#-O΃Ͼu@TU`n-=@/"iJ<t͏"qF']~}|_Tj2ݢܴcCO~v[}6#2 #-@#1x#2 shl@VIGbT 7g;H=gPJޝbiCL3L\gfá?҇/ ?A7D$˗t̛d?'"CǗןO3h3n#W0&3uM6m#-<6J|Nk=[eԙLpu;f,2P]S}MBD|.Zw=ciw|šky!ҌT<#2;_+"6ƸPp=( vzw#1d/*ozx`FM_4CGC LT>1Ks4v~vzH~r֌%AUG@ C[ k/4s*>۵nAEcb%9#1= Wg q(V#2[ð˲mWQ4GJ b/UX'}ǣ邯8q`gkVppQG67/uZ6cS@~<@NkD0r>b?L{kw턋> &NxD|&j#2Q'}e8ԾB+CV.60PtCzEoAzƇB»(Fui~-?z\U)#1! (%mڇfu@u /ս̵ZTqЩa*cs³o:G3gm|2^s!ukISaٲ{;gq+޵ٜ4-[J=>./$ƽ4E5ۮcʱNlrvv鋂2w՘opʾwsws&e]]239b2ozkST!n"F&AklԐ)8ѬNZ{+tS#2PQ;T C#1q[GU?#2#-A>O񏠻Kюt#2!x|c? {$LgWr3]2+?N>wƛYSD['%%_2t>OC]u6fyF#2ѷYvfTX4W9UaHp2#-bjpZ"lҢDZrmB;V3d@.( #2/vg3ӋZbhD'Vzqh!8uAfHTX[FH/^~zv 0N#1A7#! =>cAQbx3 #2ueɫm(~#?c}T}ABH p^U%dg^IR2* h 4B^o HU2R3ͼLwY#1v򱵟yu~Ī%r}JJ65h)N2Ouk#-`TPtb}۰yQX+;{>¤\_gUgC怰m"d$qC{q[j4azͽz- g]xx3r&Hc`;wmϸmU ni锗r!˅`u.a[~r@C\,ycSySqL`,ݴG.v;LJ#1+ʉQ϶쳤%^!;]$4558G׳O hw߳Kzq]wcJV4{o:{c<-!u /9)z35z8AuhBR:?#1u 3tn(޷9c͏5[TжY(#2E)n[; 5rKxWhu/h׿gٸ8e3=fIs0G #<ǻᯇ;/qvdwaDKK#1]yLR}1s3oE(Dr#1^@+1(}Aèq3Ӽb =H͹}Q{Ft!hbׁv#`g f^2\<fhQimum<yQr.;|2R2o(nDJmeA/@uC313̏#1B*Xr{#2hMmn]d LF- lӀQbiRqytZ[#2lnl#-!y@Ynt#lr+7GZgHv߇veUIiemfutOx3=FChYCS8G+}95Gsid%#2nBih>IwP%,h ^4{+#2]nԍJ,!25.!bΒ[sHƶg6|kP奕 e#1dӒCG)AkotcC~^d#22h -npIF#2!تn+Tjegh5B@-7))ѭ@qh`4ucc.\,XzkP=V%O2(J(Hk2fdqDGhm䋠itv$H&f \Qn-#-6tUk@ptd4wECX`Xbu:+ς:@P{phȖ[!fDHDlbyV&7nn8ۀ6 Tu#1Y)t]#2o~M3v.VY)F.wrXJS}GYiñ2M}B:l7M(zQN%%9NF,#-gp8q[&ᨡrGX!"u.FD $UTl#1:lPΚ0M4 G8UyNWpq*#-;@!}0nW#-X chl3oJwd=GP$M;C#uW2}Zݑy[XW3 6ڽ{ }+,y;PRri(,}2yv#-}͛0{1.u=C#1/>DCxn|~ͤLEC[OٛaCٵ0$zBf>fۻt:Bz" H}z:D6?˭mdM'Xvc=oX`؝eGJU)noovz;((Q7puӵϯSuy ^SvΨ9omr.#2Hz!WQf[i'x A>Q{u[kS](f!qVQ%P CDzE@~}a"@&MR1+{wQ&[v$A%0"j@XW jVt>NJ6$$KZy}V]arn60Z X3鄍"#1{{0󕑕Y}>9Rra>7D_ J*A  { XL<&yg+E+sҼN2<4My*/"pD< bn=UB#-A!)#-"2p|DRD Xhd@N&9?0'IKp.3DJ> (FZR{aY[k@'Z54H I !bue>k"EJI1oWvzbQA%Qmy.nwW7,ݣ_.n^4E!QɎc`3#hdekzH!@mMs<$OPVNA;Cx^OoEnEEtVw6u/9xsLXCDo7 ɮ[q>.<|=۴v;C !ybhU=MhT#2@Z8.ȃE}YrQyWķh{RGVk;U}\; paQ.a#27( hYt2TBE7(뻅D@AA5a'LB(ZhVY+Vm͒f•2`TCQP)>Ͼx5A59#-$ Jp#-y^/Pa:iF\"od CN|.$ T#HqS $=zPB|#dwyA`☪ʢ`v#-Bz#? Q@ ,(UT2>F㫫dMN(^(m GoݦQO X1al!̠V- L_Q u'.sy@q$`fCs gx {e"@˿lN݄)2%́ovA%O'%F?o#(t#2#2ю@4B(ba5K0މ|PbN(#2C.278#2N'(AY{>w/<4nq}<->Wl?<G%#1ʼiNgeSb^ew7 1@Woo`@ 댋؇}em)M3hG&#޹0mݽijho#1#*8U*Ar_᛻5gl Ӡ m .9؁PYAbdDFOIQPy#-1>S"{9+5[whY2ƚ*#1(D>‌WwkCEX_tP Eby;7v/eӞpMPb7qBM=id0p5g] ;T:(#-K 2@#-#-#̂)R|s.ؿ3)^#-@dݶ(upxfP8!ٺ!+$#2 uaW n#-U+7 }zc1[ OyEߟ=N1\^:*^#&#17ҍU ;ְ:<=tjxv<(mY4%B0.Qۇ>5Zbǹ6#1ۦ:~xTq̐=4 K`ྛlɶvj ;z7~56|ZڷeǏrNZ #2A "ŀ)8Oho_+bsaצ#-YbdSdƁ#1ps{Il0 7B'>Z}PT>pr7#-J#>iI"&__t͎,KvpҼ=/4Z0C:퉩VU RM3۹+mP'Lrտ3еxWGP>r5{vq}=) B,5<{-CU}>̾~݆nfuxgsbX9Љ`=6Kٟ$Հ8i}H@m1׸fܱ1P4ls/Pv ȋUR"!>{䉜G3R)/dF ; Ϫf/ϩle @#~gf28sӡ66.5c^=䴁ǦM$';=Ӂs6KvuON9U$"Wq'?aYbt`ʇ+I:Q~}Yי"N(DﮗK\GN"ٛfn9vȦrv#-+R;C0_#-bo*F[fUiM{H'4'R>2TkxnE.ڀ"TcM7BJbJHE%(6J%! ΰy#2Xn%D(s:+#1cj+F_/fsabEx4WoחZk,d.lp:k;d&(`S'\DP ijMť1sJy" _ImUUSIw ND{6Qcn. #2#2`xP9㮮^*ŌP#"n46E$L߆@εL$8jͼkzy#2@؊Z&P*#-tZ9LQD^}XlhX"E3^utʦ*qϫqI!YiZQ'(oӓ7ZsX`#g:yz{^BФTM޻o=_HM˹sp:X^6M3H@ɜoddS?ճlr9nqKI#buȑ@-nM6Qx 3@CaJTKut )L;BH#pK5Qz 5Zt%^EA@@Ȝ_e{> < #̰$#-#2A׬,Ѥfb2l. #H`Ș`3KZ#caL7,d-%$6-5)LL BMD2+o.eAP#V*&/yh#1b,ddBk1X|# @\FEّʥi.e]vH]zoM!I8ZGY%"m|<}/7Sa$nqX#1)ac'HC-&#2TH4;Z@d #1hZA,rd8t-S#-fudܿ/0" `beKLsשw~uGK  pp7DYO(VMBsRFYYD*Ɔ4CA4S•bĜv"(SW;IE.B$x=>vH.cf!0ɻ/յ6*3!cE}4aDO L=4ķh<0dYC*;C #2M_a#-*Ijn(2_) +V[jF)6uJka=xfY]}6*IT/ YTL T,2xQ#2\zHc] ;mwfAbYHǒ3ʰiM'cѨ`)"?7} 7k4g4˓4Fvp.c4Hʽ :P-5Ԅ-SQ-e"Fnh/}]WDXS`(nF9`#2֮L?lV>-<2[%$/T3vKb&T"ĉ1e4FnH ޽.\wOLf<Z vy7xG9͋M8n2{ijՆ阄Јȡ$*$D Lp_KeYJ9-UAXI.#1ĥ qJDMCsAAa% fnh4QD7Mi)M`I`鉉e8QTR@i"m.]xjd%RhCAز ŀY+VəhyK|!wSS&sMH/&cVgPbf"QFЍc#;1\#1B@x~&,~Xw#2q#0:h%mKOTa_@Xʇ:xG`3EH".D$@jȜ}8K{k2r\R>FLv:)>#1w1(F^a:MID&)-tʗN, 2I+Fmk>)4+.b$리(˶?mS>^O㍳*0h'~;j0m[R[d`:[3#1t"KBu#1`zHKF`X,bdېEl#-Syv>JaBXPE#1&3ҒCEia#-J*:UR Xb#-YV#co0ߥ&%)P$ xa#$C~ێC]/0M*&9aT,=Yߍݗ'r) $:fzHJoO֜ 3lhtqts/⨌^v47C'ʸ#12<0ҩ+1`#2B`|@z>#2 )mh[^*5rն5kolj"D4.{Rt !(Vb_3JR#-~:xms5st>pF`#A)2idfRa-i jPM(Q,k߷(d֓IDV#2d3$fTPĥCwQE#2D)%%0AD(ɒ5Dd)24iLcIMEoG7ɷłdU50CoCa?yQ'q*7#2eG8LUea9c!q$K#1#14czK #-b3}N vSEF?E~&7birO'3 9lWj=ZU#:FS|w.vc [gxi'_}oPۊ2:#10/PW\e_%3#2't&1#235h6KL$&}?az-X6A)PSi<4TnqEF))$Sթ)ɥsۂmq9{+P~;SWSiOrāpbGBm@G ^blCvG;D!]o7+]vEѢb!LpIGkU1-.D/m>1Jx nkw%FrWMխ'kWATM?(-lf8XBfEԮycF0va}yG8\OxھMo%e $vQ+1-/YӇ:whג]mw3FWbTrCs/ pZ4!0xwn#1?;Ǿ]1gifPcQF &}h$0`E$ڏG@#2'M?'Nƭlv gy;;l}~1%Ƃq{êu*Hg/xT"$"#-5ϟY<e=ؔxW i=`%kTwzD M(-<6rAUٱRWմbDtue g>zd#1f#7j%CNhtX 9_ԝ^4tw}NIdY}LԦ&y>mёa\kR1-ֆٓTPz” Q.posYi30W>ًӤujfZf^lfԺHb84j(L"UkXP mΖL›WVMC3s}7LZRqkY.N0n y~Mlu_0E;STzK#2jf[CՙH#2'S;:ܱkuκ#1.S06{P#INVKΣQblP,lkC3'xLƠ}$ O3Ĉyr4߸Y:n 2Z1=]ƙGAӤ>#1Y5V\0N{d Ï,;$5ΌX!\u#140`,"du;m^3:/$g}n@upB텴ց=,Y?9@íRPɬ `vu?D]Qe=:MQR؇jll:TX0ai51zz⳶`z" v68ӕyxęe[wk38o[Ft8ElxX6#1 !?[Is)eZU9,PFvƇ593Hr5\sf ی{CQ|\d8}^I =7A֙Ս&1u&<= pkfM(}m%m@K#B RK]i-k$i"奅AAzaEPXiSW(m\*raEJXVo}m{#)!L j66g9㜕'ubJ]%4:߄:-f^3r (E&`F:P6D>idcRNLܢ7L:8FMb䦽dڨ#-@ie#2qu¥ǠP̧]bT.n 0M4vEí'#-.\ PN7szH ͝a&YN |ҢCgKћᣦ>u\y#1\+lŨ$d!L6m3 8I١ա#Y֋M!#2y}e3IC\Ć}@XPbއYN~| ohoS)AXգrLoƆ7׃uU6uublz)&2S8O/ R=:%)(#1ink-ff3kn]111yku8Yժ5WaG'TgMGYj#-L@9ik& SxN=[0mp2 !:H=Խ*mBpN 53Sii.To^M;ٚ,j6^oLyY=19ZoK2-ݥ/E[nrm3d}&Б "Gq,^ IodKeT}vuu4tP)QIIAJ=Xȁ tf'CJ"t@#-a݋OQOP/#2 m#t02,OsZO_A~I# #X#])*+#d0 -û#1ұp$4@gys( Ac4&RNR`25djfe24҂[%3j"ݚvVS%#2# i"23SdtvNI-"S#1['2`Rqf d5eR#1XsL%q~SlN)H=d'ϚUbx\Pu짒6у:8D Q prle K؃v,Sdw"6'{ UPffk`(!`hF80F nhg4g.3hn#1 jKUN bE6LJII4dpjs iu7.et]#1aL,44)3 WvXQv;%H`m#-NM,7:EF$#b ݼH "kMMȚ.QR kQaD6rRIՌ0KR-~u/oh$#-q;!tnI-oW[`+׶ *#-)vZ{rx1t?\,O;eU& P{%iOpq] u,ťkFw[.k*Í#|8XE0@Cq*G\'IeKZrCCk! 47a7u% exnX!Ս#-M9\SymB<8rbH$c(B%H湩LY7U#-Bȼ<Ev B~=i!0Z!&k!kkJJ2ir!D="M>YrPzͪW/*r1veMlO/nNTx2X(ҘUN#-q?^#-9 !r(`DZEz(|L' /܍^8d?7'lOɎ[2!gfiZLPOB0@cK.'Bh M1ȅ4bޢUJh.9\ZRgH#4"j4x1"[󷗐\b^zo$k~{zVDlUcFkFIDL`3-lX}?D(Tv'x{yiZ*w)]q&A.ú#-;=N Dׅ %cX"+Q@G(m[6n;ݎǪI8K֠0`׫@.H_,{#-"F+Ƞ#;EDWz#1 )-b"bkh#1MM.-WnNs&;4*D4cfBFbIU %@B-Ab#1ThN]Xn6+F(-Gp0~]l&Lp;v$wgFb 9E$P&5ъHVV#1>d\mKf98J .q=}l7;VƄAB|PD¤A6۷Wk 1!5tE,i2D͌DĹ!@8#-ZPRIMQZ#2#2T#]`3myG̪F߶[^%5XQ(0HtS#1SC5meZ?0nAlA]fsҘG"쬻]vVōQmXV˵--S4> OMq*12V!5?KZ)}W[㥳W n5VVuVoj9l9VW"ɽ4M2eZR,Ni6PۡԵQ*J"hd65ɄM$iLi[xR@e0qfmG#1I{tprDSNDIeRn.h͸t8P1mN."طg͢)]Q1&܈h5)a=`C8ۧ E2±J|&-M 315ędgU3d0%Ol ɲ!ej^Nen&=\dV\C]sУl ( g/!Ňt51b H6yZJMKy5Zmbwgyɘ ;LR$ȁ)qT" P i@dDr@lBZ**Hvv%mX]# ֏o˭/r0_Fi0oNA\-je2+@RDd5᧷]:#=4\Txn7:ۆ݄B.DU9q:c|bZ C&$B`w?6lx3ݟbL8o\rEDSXLloht=7bw#--(~0T/c]Oͭ'(qPeCB߬* K`FmD5dQ-$ʣ$YC-Y&5j&M)m&6-")Y,JU,ځJ3񮰦՚f6cLIQSDȭJmB_si^ݻ*b(2#2fҌ֤֔1UZ}.D߻d"X+[l$Mk[ZZ4TRyxRZm6PMXmm&vթmb];t݋f͵1hd2Avw 꾔n5I1:P Ya%6hH9˦G#22u#-I_P[R(KP}Fݗ75#1N|•QRgJ pM28E}`~E1Sޒqݶӳ\x zUjV7bbM<Â3l(nؑe?R>B.r)gpl@ҫYsߡv&p*/P.F©)i[cB}6Ƴ& x%g87rͨ Ζ_#1F&Y#P̵}a‘X%WK{{vb]#-mU2N"QRR+r'8#2t("2! D"'6ܿ)nZ2f,"O|dV#-Y;+s8e%Pn#k͕{,cf3z&[C>" t+zy4 MS`,;`Ib"rYE%"qZ"BY.µbm"F1ˑ#21AQ)#2T `h{CRMn @M zu6Sp:hPXA# /,"An"!LbqK U"IL*c)#1qHߥI #--Un.s%J!##1!6N 8n#1f=#F+GJ7gxןϙ^3pgx0'M;}{7%1nn{zC0 X#2(-AXAKꭢlkX?o:Qb I0RA":捱4q)䓝3#2VZ|]j[|4Uj[mrkiQIf!`v2b7 5o,I+*e@ ^!R5_Zb A!B7[i#2|zE+>Va8ƑnbHhT ILdш*WϞً~#2_JS XIS ~2&¤id-,0d URMJJO-DVCCpP!0=p[Ca׮u36Af.KшU Tr-oy!31EAN'#2 ^ʝS4Z5$&N8GQVZ`J~N~UD=9J^P'e\fzLݭ_Pp@EBC-*8J&&M1@eFdPA ?_ F]p%@SK^#1k(XNt#-Ą$y@L=hG McsLC}8U3kJ%ؔއ$TB;Dt6|Qx~+^#1촴QwNlM6&W$wDI9:ŵ.DP]l#-<(%V"^LYv1v35{u< ʫڻB&;@Ci: @rfP\/Q#-(ukP(#H4 PEx`PduQŢP.,ե&ӎ76ZmYw5O}IHR*ZDI4uԛ3U1"kHADL78\N\UT)I3h`nz3D By1gaxs!*oZh/!ߪ&{׼Gۡ>|8׋ u#]F\h̎NRGewh?ؘ 8Ҏ7yzAZW)PNM;{p݌<1!"ON-вMdRf>уA,uOZ!BӾ%٣H?;IfA9yr6-2 ެBdcJUTJ˭kORӻqHM\^K̵yɷ,Q@EM,9$CQSnI܇D䀌˳C|gNw\i0;Ċv@=5~Ľ/kY͐RO͡)6ֽZ5dګ#0 X*JLl#--BhF2-jFU4ii.mĖFb6ʷ#"k_Tx\%PF _ʴUKim1QPآ#Ҕ<omxZ?_&v"sxa\b(x뫁G˹tͦciD!(Uh5#1CBcSɵPލe'X5Zޣ$: eeFޫ}9`:d[#1$,Ŭ S8g叿#-0#2t\ m :{FaA$@*Gla\~S`;,7DY D_& m&F#1=Il0}#2G'k:@ PHQ+# pf!#1#2,<㷨exOࢬI|9QPsB"HC]f\^ިoG\3шYPG8r@~a:B@8Aτ))O_P'[_diݵmfA**TE`(^#PD$B "5 f}Nk3.?d[̅#2-X#u'QX6yV!&(u7$칡ZXNڪJ-R(ZJEp(]F&+?W.,K ry@_ |m{|A4m W%"!('R'y"HI:Nϳ"JQH!H֚?kXɦK: XR#2gG-4tHFh*>#ZeC@ h2^rV#-" AM$QC ]B;DiW;gLHv#bYdȂL[R2 ޡL -F̬FBjcUFQT|Zjhŷ"#1T*ZQ@`Z{5ʱmo&ͥF01rǶ,#jIeD3a--`Rd 7 6ȫ#2p´XCU&X9:#1mĕmbݝۚ\ՍwE并+oR[(6dF*‘^6jLgI1N,f0AΤ]Ya#M\5;wCH\rCXtjֶeaݪj8*HQĻ}k`ӹhud 0>[mҤTE{LȚMf75jh41#CՉt1 ו{ޯxxhϚ#2=ao'i(KB $,V_ͫNn^kcReWmiQ&KźJƱEUu+FsuKM5JZ7V-J *?d}Xw#2l ,b$"?xX#1*)g]#1_w䆇IZ(R~vJF2A#1A HݺhfӦζO>~h71?|rxު$*ЅAQ_;u)Rʮk6̈+XlTzŊ$hFdLDh#2KX10Ԛ&ijqUڽ$#-(E=a#:-J˨MI`(b!vb"05#2\#-$CL,e$/,ipq#بȳ6S #20+$?e8L2oXr[l'~@C4Kfg;L@zi}%d]ZNt{vFBq.*.2j&C8 N#8b޺**>a(#-naH#1\{@lz.;t aW$-RU(" JTcj׼Uk)WQ5!!x#-n;x1.Wt~@Ÿ^L!}ύ8!w$GgtĹiZ{%=4fka5n*y0Hb! 1bd:\7$H0Јh#&Č0a`(mJb9'z*$IhTUGNG@7n6a(tzV30@K EJjh(naj-5! `eߣf4pl s/S<0gQUɳn HěGGk RıO쒀i/I v|JQM e`#26HJK34OAD1ͷ><'13p,q5FLrgf?BY2"Gv&$lOsgR}'֞>٠뎦J?nAΠ_ $TXEefjkijMhS_WDhS-,#1[̵6EbcmVYZ̶ZťTڙU&ت4d-O}o]9nbB&W=N_ʔBT:j]Mk\#2.*Y?| 2)dX <'@7Q#Q#2j,@ 2#-x$XObw2O*(4*#iʣ@(d~DBB|\1lC$N#-Nq@J"#-|@'D6#y!Ą[AE*@?<[DnHƕ=O0b<ǁzn߻ ]Y$4#;ZpF) e+Sx2.e4ff`8G/.*3T4.k#2|oTDg2E/Zvo:ZkZB.q.lOa#-'C7y#- b6]4 Y$kAB#2PP68`nV;Մcj"$44I$0l,X*xOtl(!~E?egled~\}qOOM j6OrNK\`ΦVMtGF*ADQ=vm>m}&Jz#-nsvn4 9+S: L }~jwM*6iVMu"PX;1LOϕ3M#-2O03f ~N4㔥014׾HB8.7AT!eR"{n#1fMkߋ&7#CӀX["$c+ i%cax}LKIqF1kVy0fLUi bj@Qdta-Ԋ*cuhF&(}#-DByւ))QyzRX&^:o7#1LPSB7/C0Ђ#2Ĩ(B\iU9xAzMlA":aAzKk۫tP%1T$I͠O5'K:!oZw_ޝeo{6V*LD4aJ66(- 4#2L#2S}g؀x#15tԲP)/p-CEd*ciMH\fg'%E ͐ RYX"A@P ay{)to.S%!wy#2Ј,U#2AHCz]2%ـG95@c#1.)cY+[aal!<2%}#2ʟKiR\er(z~ݚ#-HRfmlT*(4#1rc}g%׿.jrI]iARPet[uAjYAH$+4G?#-rHʼnɛ 7#-cpvvGʃMQRx:"ɜAۗɢGS,-ZA/aV]TSĺ+njB~9Br,1rsU:qs~1}ik_:yr-[PPY)$gC#-PR@1BC"+J#-R*&·ǼL#-Y;]=s#-#1|l2ۄ#2+߮0O4y :y#-2@,"ryhQ'gRD{weV[Z#-]~4l2li8H~>f<ԩ  )lWty]bMɶ&K/`BDTJ1 Pguf `ƅݾH< (6W1`Gob ƀHX jD2g›w{o]ecwE.鼚\2/q*WA`H&UcVQrQsw[j8Pr"*=}ֳVBM̥9up;M>9e%V>qtJ+T-d1 vI{!WoUx6ѩ«ȶ #1Iൾkq{!@]0 vǁ]traX jP"7 #r# \p88DY!lb}:rØŌX=^û&a26#1`qKh <陂)fiMA=ȥ{}[bH$/unv_]Nv;52<{O3_=8[ C2&ͽgPTGUGႝ!p6=}#2N0~"b!d%]-.JZʝ0O^A0>wi:sy䃉eSZȾ$3o/:Qrܥ,o ;#wH_ąOarL #`„U*78O/rL;LzQ,r r&6HM>kͽ#1v#1#2Z/~[~7T!~[%iΣuX,XFLu$,EE ``ؠ'bH0!iLPofK>D A!.2ʐq|]/cMJ@)7lLTV &#p"P TVSmnںd-4W)vo,•5[-my77Q @JV5 9[\$9k)&_Rnl )uITUa!})vo+jM͎3 cƃa-S# ɜ#1 tCCbE,4#1qA#-D| smxṇ#vez{4#1x&red!dgrׁpERz 7c-笯W 1$o<ΓƾWv4U#1@yJF?Fk&1 p]bA!HTU_EQ!GKK ȡW?So_?Wp_buE|Le w>]#2rlv,6JB#1klL/H~Y{@Z$*mk_z.#mlAAX Zip0];`R×4fpx\bdXwZ5(b#?XDy%FMM#.:J\E#+<:^RI'Z fsͻŶˆ9h솹"& ̌PiL <[ hoG 4:{-6/Cx,Fxܽ:[mt!p<ˡ1JL#23LHIҶהe՚_{sHh >,#3-ؒn7B*yjCd??%O?]!hwn[43`tb̐j=4=zlWvƓս6KBjlſߵ뮘% gRDJ_=Vdף:]D)ceE. "1@5eB\_`bD*Vm5#2 Ď=V3.DFq#1 ̪MZPvgKS1xb @qI0MT B(Obzۜ`Xd3vT;O.-R<[VczQGXfx:-2wûk8Mr,Z#-f/  #291>?mu۩~A{6nQ >t6vSVS?}Re&1T*]hفuEFD :#2 MIڍBILlaRapPiґ33Xhk6,hB_{*#1QfZ&2K-ȃ\5:#`dq=[GihʘD#-H11#C@ghk}##1^ȟ`TEDB,#-5ҮoȳdJUΓ#͆M3P6R7WH*llJPh9وAZ 2)AvX==Ycn#1dZS#1 }-B`8aO#1'2m67#&Y`ģ[#-eaM x#2]nՊzE!jr8i͙KFvq>V%<5fуδ.i\6Ɩٍ1*<1#2XPCt 6 m#1S2#F5AzhgP;[n#Y ݡ%}畅1s{xxqҺ>5ƆŦy9a]2bɆy08aL$ZoMjIN)x֤0I\VXiP*ةB-Ml&`űxa#}=oK!wB]8d YV[pVo&|%}<ᆐE@ h B#2#1.P) D)D ]@0DFA!DPHF*(.Ӣa(Sd&O, H?,?wlBFԈڭ..Yiaz,lc]̓MBbA1H4id8w&GiJ;])˛ǟװ$ק!Ɋge[ØTDI]hŒa0ȟ;6wme>-kJ뇣+fUq K&b]s4I$kΉ#2/hH;.E#2>a#2&6g-c!ɊzL)+j֥!lOez!\phq}0U-[QKo>tԘHD^"F#26 P@$Y ,I_?m%n\?ynE}T (X@/1O1'd#2dŭͪ[%BNRX3#(a(Iƕ" p ɑ? \+td̓5m\X>*˼UDF>\ɫlͬ'9ƗTnU)1a cmlթJ q#2D3VkTchT…I%TBBb2#-f!oU)/XF. #-->Fac#2 =dۘ׳;D!y?Adsa`s8#1V3̙M Qf5%ݻO ;m}魪[_VpUH M<>D uPQt?PE }>WɇEsTTcNA@~[-]>߭Lxm(p6?M&8oÆUQK3Du4n#2 Јa8 zbg3/|:0}l!) 4&!QU14YE#-غ"Xt,B"#-L˲DC4b9&K`ȰyD_ 5{/=@J;>HשT79lޭ`gĪt$Uf>'|v~U*5tUݶ[k#2 p#2P#1/s}VUWYILd?-팋"/-k ;F\pҎ^CbSydM$Rxvd͌7A+scwלɸG:+H^-TsMye*ёm]6ѩKnSfY,+wwtnݙ\KFs*:ʋFV)#Dl#-#1R {#-#H"@w4P={ !z?UܒE}ym+PTSuN) o=PЯ]~&(!R~j(?/^gy>#-8XF1TXĆѹP"Td*?V0u9YL@dՊաKC-ozj#2RT,D) `:qLϗ;Jf 1%fRr.#2hR֫!#vmA!>EՁ@:1E!$|gsќ,hZG?P wfi*Oa|F#1IY%#2Kuunn+\KX a„%0(D@#1M[TlԄW@#2#1c0f+M#11UaPQmyEW*KrI,a2;6*슙'XPU|I*U`?-$.*j#-.fl$_VѦXiFCv$(S#2AhLHĒcZ*ޭ˩p h$ l6 WR~.cGMED!#2C̬=abVEDAՉ`=aPP&iP4`D$5K>#14~0y17NjPR #1TEU9?L2H1Lһz횷-Wo5-PE:YՉE'WØkt;s ,SS!DMp:6sd)#2ŴBV8冃_La9g;!KdKv0$I#L+ǃQS1쐊В_1l#-qWCg#]Gx|PJl+ݦyhuL#!OWhw܃#2ڍwOT@GiӀ(dT@B" =4Uc"C DC!QN٢e)vž^!,O\wF#2),3FZmߙsaS`~g}uX_V)uA_dEQ{8KYopV]L51t\z0#-HhTwء[r摷1(Ծ+Ѯm{sU#2b8b}DۿyTj^kVغy$LdUC#1xYLmiq)38R#1D#-adƍ-!c?xHW b :ti gx(<NDZ9nah0}$Fwdp6f/qP\LSp,ڶ+hB㜏cCԿؚ>=SE5&1++#OBHl1c$ [#1lֱZc&F*iv>ݐȲsH;3d:H4Bē6>h1ӵ)旷zͳ`_WI7]J3d-^϶9@Ѽ#13]7@Xݥ_s#KK0:7#1} ;cIJqLB X ٌ#1 E]/gMd.H[4B!@6R}h#-몚AKӿ=ervډU ~Q<8ndwp?O>3O,WT.YW/vm/k|ͩ`zRPDAm"#- IQLsԱtY&ah$KISqKP*HcsO>]L25mY8^nc~x:VfG_#2eI[$[֫p~F/֛Ɓm!`*Ĉ2n4mY_̄n!ª;B`@UPAoY@knxy}N${ŏ C! N~AdY&I#-|R4{(}@?+#-Q$D$H(w/Wڃp炤{k=iS#-qcwKz6L[ .6<>wr1rqI@Y24bϩ4A^E9V@vR (IL~Uqrrϳ"zn9(Y6{:s+ZQ;CU,|1X#-j{[c=uj:@7<l;Ѕ1V9\־~ee$^zAFJZ#wm hFDtbYC`iИ 56;R8z((#13ͷŸy#1hc_"(\ELgCF|DXcK|Wɑv`?T']uawJo)`T%xCzNv\NUggpok 8\AruX1vŸ%z4 )Cr=~V !/ *T9I#uLoxW8KhB`ӂz6FRXpC=ء$Ed}ީ#Pb *$B!LhC^>d*))Q[RjΘ~U .'Yv_%FA}h%>;_i :\rWtM]F-5K5iJD$P"l[H#-:.k/ :| 2 MZ#-HWz'@&љFT3f ($ƉF"4ҤdhRl2*#22rsdٓ0I)h#tJ';iDW#2 Ål8D#iDg DC#- 5!0%?a=L!ʕ5NA Se*(ehUjQ77ZV9?/mL4'[LA4#/]g1.`-MUNB7TRznO"20<515MvU.l!4c'kaHNJƃ:~PRp" ~u0Ϲƴe&lux$L&wΣ>d*#1IOވYlJ2Ri`RZbfڼTkTmguJm7WZyCk3[qcYC#21&1;/B*%*FIjdL`F֊ɩ5U\hJ#9quW:^ ʃ!YR Eirèi-knqH܉.c.&ڦNwF\MZ 00#2Tr!S`jGHFC"FJۊ7*xІb Bw3SSeq"4&+oE^˼!yYEU{y! ڣ`3 DCd#8Bm68#$[ji6iLj0ҚccX(0jlOCrXQ:UJKvaeuB#1'XQ*FHT+evinJ*[%TaU`ң .j%)Oq*A)V("ۦ#1QcSOyl2-\s<64a7n1+Z5Z dd LF:pcc4 rF{f,l%DpIm:(hjJ#1膚,őB0qx8B ټ1CԔ*8ۘ0O#24LJQ%G:81`KVQM*-й( tI 5G gF d# _D y3#2ئm#emVBDiv8HRS\Pɑ&UC-f +rׯ;j񬻪^B#2cFt-R8x#1dӃ bhT"m#1,,)FRQ7fl%7kb:QaXfi/I(0bQHD5qen#1n`LnDDayQ]~gZoq,(WRfV#1]#-czƢ*"CQ_6$&p@V[m2"ijcwN`H\Tj\0 b\c(P#2$,IQAdT!P[A`h#-i&Ċ*=7wowLZWB~)G"#1R!5'#-DmE Sf6Y2huVYD?@JxzItثi܎<2,P ;#2?~Xz!7Gj0Or@D#- B$b1RzE KzS|a4'7]>8J\ B,I%}sT`(ic;4ACGedX5#]]6])ZE\Ca`9=4HMi$?Rː:Ss].ZBfAADG8޺/kaoQBfڛgy,kd7/͊򷆷 u 0|^z ӡl+ }gDTB9O׉ex(a(Cȑ%gA&h?~_ذXPė(W!&š9kڇ2@^˿˼P8~O#-loo+-We}5f[~ZG]$,]p 7O`!y$Px}i1m~'> 31_it[rz#1#-e#2T7wMk-:O>8NY["5rPGb ,"*KgԝPکIUFWαUVXi3v%e!]5F7:DukXE$P!HhCPUIJ3X[Ei-ͭؖշ2#1FmmVCXۛIʭ͝r,mj Q+j,KpD8É9睂z" (ȣ3^k|31+0xzEu$B(o4Di({D #2oªy?(#2׿"E]$2PR(V ʯJaHJIBHD$>?#}P+,bd25 0#-#m۵hkk-):y&B]ޅEU~,ImJD?>Q #:Gp= xuv[V %(z"eyR#-;f_O` HrVMt_eH(z큛#-2"e5m)jflJPK$eICjJ+6RS&ѡJDZmEiS*V-h6BM#2f}5Ik2l# )mT|/ X"U#2qC)`G po27b4yR@TҀ"Q1n6FAX1-a"#2@`i KQ#2)Xh2TQ@T`H|B@}ŝRЀKD]t;Z~^S-("!bB chC7@M%_ B3~/gZ\E*W"@/nllkTE&0f?Su44 -d!\ܢXhD(AL\"Uc3E8R(6U#n> ;T4O9pfW[.JfP]rѵhZp:·Z?H "̑ƴ#1C6ʔe퇴 l"!Ge*"fGlb+u=XQQKF{8SWR)fh&"jUR.UwN$O$;B,<*&dr# X}vt~;/X~ pPzvL_s7N^B}ixp犢}=Ip訨hD S#ҋ` M͆jm_GWq r]ڣ]u\ʨJ\?x#Mf$r@mqWofh1'ZV')bQ$覓st .m)MF')]۳z]⚭]N3nN4{yKP>7$NHlal;vء)=#2{3~ܿuj-|Ju>̱g֓N-R㳨CA:*n謄y*^GW{K2MRzT.nn_dƛ=c1:gHE&~ulEGӊ-u,87CC(!r&Sq\Ԯ>c&A31o#1\pׇGcLJxcȻ5$CgrsByo,pѾa& q_6z707%k9]Fb|++d]oQx[qwb73vXqXic0t&PK3bgV #1G0MS{ )N?~HjG.PPt1fJeީtvь3z8Q>8ğئ`Wb4wbAd,KKXn] p6#5M36r8E&<#1Kx^C8StB:Q G4U%5C4qҀ#1aSfTl!C)Op`{H^+kfBx\-hSn(9$88rbP(Ul  "#1+ a}S߽8] ub("rG>27q:J5SACl3d眽c+*fA.f]UM0򆳔(j}M`#-@AJժifyw5\ [k,*2pLWʕ3J}vdymI8:ms],?(vYLTGT1Rғ߬sQB(J"jiߌE*~s؁l[Oh> 8!kJچ#1rrqaw~B`8]>*tBT<3E9[F/KEZyނkdvxwuJkZ-;hF|km^Qء~%@vhiVkQ-29ys83D^[)Xd;2ѝcMXu鉻\!jm;vW#1`5eOn=LsGcF:Wqг!w;۞%Ѫ`Nq^%3Ͷ FoLɣ[(sq yH﷌yN#yfˬx)oX1ibn X=#16msxfkF:COHŒ\LfO6t֜hĕf#upJY ǓA,Pd$)*2ʠ+ƞw$Kȑ`B&n1n9Q5MƤXKLh \T{g@Njw[ z$z1iPRɀd4ĊaүJabnF;ۯc/MJie܌F!!XֵLp\y'[#1jǩ9eohDQ%\T548/6YC.(-T2L-~[Zv0;ĬRͅ@e C(Lq4ƌ{⮱W;Q Uq9YTW24)Yzل˩D M#1Xm)v #t]M95JG(#2Qg1=릞DuB4gAƣPh *P FSC .-yd6r@ehȩQFL`sU"05C7c.ۺ#2~OB)0lSI眖!ѬPѴMT6+<Ѳfc*)`0ހcL"Nr#1VFq#BZmWX h3B։339QUo)Ӿ*7=!ҳm4@=[GW( (X׫A_-$u)#14b78cMA@=6alS!vH#10ՌKE}V ƙ2R͝jhT H<ՂZm3slֈZ F ֦)I@ZXpED+k1#1ec׃3#2Qf1l3cU{ʪv̇#TJ;Ku#1s獰~է+M 0"a'C!ҖTbА<>˦$?3)*vc65p#1![v~A=ޢ})i8YX Ll#2Hx?@k@PVb#1 ~ . F#-1g&ssfq?4Ny䣬PlR<gnj߿}wW܍7tɄE*#U*229шv{+Üz/Q757EvQD,P'<:zCFO"|ނa ^HdM6RUڦRե5d#2#h(6((WCf#-5y">_ߟ$!#%jkl(2cƐ-jV)lڱIFؒhТ*6C64ԍ)6IF)!%DhcM5-!LR"MZIa$dA$$#-᧑\@z=C؆BeAvW~$!Ȁ';8]f%vX*%-H@ڈ!l6I$lmHvg VSzkpC%߁(2#21XMwoMv[ãrF"U1 w.;*U)C:Gf?#1M4(@s/ O&@X#-66RZƏkMJH΅!Q0B(U*%.w#!GJjj4?½%gp*#4F~]ht%b9I-`䉱0l-L rB+@6lxRXZLH/>I-C4K*#2yo:koi^RoL60M0Q;3PQ. a#-!`СGLԥAy6OY̕tYlStI-M솑RQb75hۚ݅&bnZMvG.!`3g6#xmbJ%L&XC=hhN3đAB R]P #2' BE ȷ$$GM`s#-M4L)\tn)iXHl1+~gØ3z#1z$#!?"d셄o cpu:Q 5T:o`CHO"Y0Lmmjfa~'#-}89<~|$0e>1TD9^$͊{dS#-t '[v2>c35\'#1#-R*lfL~;n>#-9My~_,mI@}^ľTCR'߂\tO823>^u!6yd*hHaeMwg#-9C{3ecg|x_#-O/NB#EA/U\ye)^=sDR1*);(r ȶd#e}(imX;Kxvmw aDU]0?LNUL4240S8&#-!M&vfD@@5) H!QTNr$|rkFt I4CGt+.@N28dB#2(Zi9Ѐ^À4.}KCd\TURۧ=#1ۭJnֽ,rHn`"iM,"qn$B!0l GH`ژ0:8Ã9I*$m65D0HRq:6ހҡo^{oGn(]uGF`&-t3ZL+t0e^~UoY8;f'a)2m,$P\(fZRV2љrY#1&Ƅ˒b9dnaS^M) WMH;5M.0S9A'X\t.|BiYs(tR0^F $cR 1ñ+;`Vb}2!垈HFhz8̫ <8%8g2٣ *pH̍X3W5kyt!|߼g#a[&&7 %&3`Ħ,>9n,-˜dִzcvTBRBY7[t` #1p+,'щL׀g}ix$3@̷gnՠ#2@RhZF6#12+Us (CBB1^jÃC;amSA\ koL2CgFl\U:3M7 a1(ouY![l&].\uLL&抨65#-ha`1evRS_;$0#2h89玽n> 0!fCnq #2fT,.0fhL2 4TR)"'I1mcjE= %@ ABD`j*PEx~ޭy|~Yj!LqJPi#Z0T1`aMrdzWԢѵ|0m_89IC5F#1x3b[:V#-5Z*=/A7C9w(^Ed#-88T"k%Ԡvh'VaǮhޚd<Upw%Fdw*De"diې?#2Q-#1y菼"Țdߓ#XtݼqOɭ+pD1PC5h¢Br _fn[4W۝xnhyYg-1չ[-VE쏱Q*2RG0#-l uߓCK )PBGdUS"1BThJ D79 n7p#2VX"#˻[$2IEMNbD6fH $H06B#2AvaHXi#ԭ! F@z&<dPi[nRx h1EC04Vfȳ"88OWgl}a1xlxֈAt[>M1#1XFFLR|1<#P$xähU+D2S#26&I(,$% \7ړmO6s}vs속UFUS֦,E~٠5DgԚ=d,X[#2q`wvܵ}JeVK1#2#[3>ӅӔd#1 8P%=H)y䐁#2ӕ.LHz(Řmw~6+F+{skʌʸ0')HH2DOmڊJ-fִ&4"*8","b$P`W@؍" `P#-ᗫ"B!tD"&wy'M.ovdF Ba#-D{x0}lUbp4ڬ("*H b;]})I"7L#-9p]bbNtJ1F/NEJZ!(…<@A#1*m ēaY.UZ((Gj$Lbr K^+nRQd,*K4g#1P3:$#1G\dhK Hnh\Bjmvr<òwȂ.jϿ`,0Chk}3PJ2P_d^ciSmqQ ` M b϶e-!5,*,C脊#2`1640h_M s8XXXpr2?ǃ$Dža_CCX.2ۑFnn9\r33nĤΦ(W#2{OзRk/zhL#7PPugt$TSа*P)C:Dq%YޯzF+d#2#"DmͤԒLbJPU[hMT֘mZ+WtDb(w#1=Ŋy~x(êpDP\绞mH"Ϩف|yunm{;&DTS#-! FC>m`QSkA#2642D(~4E{jrl-<aI"j=L8Ք]b|色W77gE&;jeК5|q!:#2j7NU\я¶5FVR፶f܀#-PYkb- V, &ֆN$ XD_@2K1YAبփZbZagfLeeaNO.HH&dW5H@R#2"?dH8#-<'XwՋĺexTNO !##CG4*X:'PW3I% QQo ˴${҆@iD rH:O3{bG?Fsclm#1n9-T<DuAf/me^_M`HddxL4"D`F*$m$2l*%t#2,FrC-VmQQjR)H#2m'c{3꾐 SԠtd#-(Iu#=!a IH,MW5NAFcSQUM4mN%/kx&ޚU^5JZ{F9FSȈStPo~illk YThّV*e';IJTvRhE@$DMWy>癇\'!Pd2ː۶ 1> h"99|OXc}^V{TxJj@O7<`Lo!P(b1HBY?4 A mjdHE:@P^!BSlh("!$hD&ړJMRvWPkA)#1J.))VEea_Ҩ~xgb1H>3iQ%dBٚN9_6 "\Ho6 r^?8}2h.>(!E#-jHyԍ0-SLJdj)lbMo~6aQe@ ]Me!T4* :#B&zqF`8j|.wة"!d #1CThJe $"J<ogvҲ6~@с#1KQL5V:]|1Iw$ȫmiGl3"LD9`7Q}hoofSE*[l+kkkmMoJ*-7feW\ݵsȳjƚ&wWw[IchV@U#1V$JN.CrDMi^חjMIUZuuyZJ2e-yvE3[.5)fE7ւ[i ٢ 4.TM>`hٞ-S$#2|Q1zLfPRe A#1Ic#-`ptNX46p,_qB"<;z1Xovoq6)uF{q!nx#cԉS-٬M0F0fa됧aݷA(^&7I5:Spٶ/t.N@]ÃkWIYw]*O]ocr-8ː(Ģqf󂛔kLZԒ`^Cim^h{ӴMȁBnYBG5D+mwĝujWeoMs)MEG+nr?$ W#1#-X%8֐C,SNa67@@KR-)! LUBQdj"*v+VmAbKmc4҈/6t[FWNbU#278pt6'G#2#160aL;<-,E ))Z fa]x !y#-Pl~&Nx~'F1BG_p + 9C"2V#1~OaH#2OKB*?@Y4ʂG(٤7T;(W&JB{sp{S3XzcfBlT&_#-#-{'gw~?_; ]>g|U_?m?~a /GP+AYw) #2GV)N*"x V̋6#2@*ȤRh`RUwQ$&f|Vʷ #-QݐjB ML^D m#2xeBIvܙ !B۩?Ǒ^A:03nBGql·er=CLC2*ڼPQ`$0XHtA#1hwH ×;dފvlx3iZlrݗ,6P*f,$IHb=y 1#-厄3?#10u)zבA!gZtlJw{"ur_L Ոh3^$i IqacFU1].`AHIz{p`#-fֱJd#Q "IEqO~ۘ\Z4ncP4@b,)1wN|7jf#-s2k.\*PdGh_ͅ ID$ R ַ#-` S{gbX1d_'y;; *.#1#1:Q:FB LjJlkY3[FmDŅS_;ڪ|:t!")ȇ UKQVJ/.꽞;T5 ӣ_[Ms#k5ULF"%^>i:o&؅h<0wPaP>#-!\jnQ05噫w#-aJN3R5/bhɎf٨$>,5Ez«n$#Ykz͖є7cn/ʴhŶ[ƼV#1o1h6+zQjަT6{UZwv m#-\9!Ȥ`AS#$^YS\@v;\nYdSw!q!4n5«ŏTs#2P=atؼh5,H㘥=Z=HGc/2 (zPȢŊr;%#2TXY-Z-_qbl5@OY E$#-\~Yh6E!xuzz珔emZ~׬@o{bEx?#- 0q5I@QdpہN*,= h *[a-]٠W՘gϣ~ 4Nx}QS=>Rbo=O}?Ghg̤RsSK ~lYVo{c-:iz*4 3 q%>pDy?p:Wo)}5\.2`þG6;hVV?9bo1yl%xFDm9 0rV&HK}<bEV!쐖OwT8ǧx)91CoDzZ_0?iO?0)„~wP +#<== +#-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEECzlystnjLqtCPS4PIr4MYv+/pUgFAmG5Pz0ACgkQIr4MYv+/\npUiZBA/+PH1uI+xWcT67oY7I5kcHxmriqgaV2vskG9AdNzPIRgJ24xYNR6KcZVDD\nrPiKjAfo2YgdLyglXxYttEg7t1QTXZDLnEf/19AoCwyQDqf+GstOtmEEYVRluavW\nwykb6FfR/ivth3UZ9Qb2ZREIQq3CpKfoz+IcHTECrGTbQEmUtR9pBTxhne2K0Bgo\nTz+aIIMePIVBn/8rRwja59D1P4PabvkaSGwyGtX2wdeDIhJnN3Ak8RoBw/xm+rpG\nCyZVLks6m2LFqN8MvJacytKlaNTgGN+QIjYlEDqQispyxi2TKOMl9hThQ8ZrYByl\nHaLnVGJgqJJpvnsymUORRRUtNYrKw+tIpizwjCltLBf1eFk2M62qCZaNr3aRvKKz\n9X1i4tQFKqSfZeKxeAo6C/AnnTQ5y4FWvkjDveZZmAe5x9LCoJ+5DjXQaEBC9X/x\nl7RhvMnrXF5Bhom67DaHaemc9Ul2qlPD8Q2LjgQbis74TCGtXtb2dWorGtsVtOMt\nSc/9hAizDp2Hw0O0d+dqFHJ45VrVYgk0tmIwOQMAeSGKtqggzajkfxUQIDGUMbRR\n43FYzxp8YcdVtQ0XVsj0/8VejiDct5YNSJLY2glxhBt6yHrNHdxBCgP5eOggErOL\nSs8mHWtqaglcLRchx6+6HgfemqCiERxmZAvTtzsWW/0eBYRbn6Q=\n=BMpA\n-----END PGP SIGNATURE-----\n diff --git a/wscript b/wscript index 8017a38..cc52cae 100644 --- a/wscript +++ b/wscript @@ -8,7 +8,7 @@ def configure(conf): conf.check_boost(lib='system thread') def build(bld): - default_flags=['-Wall', '-Wextra', '-Ofast'] + default_flags=['-Wall', '-Wextra', '-O3'] # default_flags=['-Wall', '-Wextra', '-g'] use_packages=['BOOST'] includes=['json5_parser']