diff --git a/build/premake/premake4.lua b/build/premake/premake4.lua index f489ff05e0..8eee87f00a 100644 --- a/build/premake/premake4.lua +++ b/build/premake/premake4.lua @@ -1021,31 +1021,19 @@ function setup_atlas_projects() setup_atlas_project("AtlasObject", "StaticLib", { -- src - "." + ".", + "../../../third_party/jsonspirit" + },{ -- include + "../../../third_party/jsonspirit" },{ -- extern_libs "boost", "libxml2", - "spidermonkey", "wxwidgets" },{ -- extra_params no_pch = 1 }) - setup_atlas_project("AtlasScript", "StaticLib", - { -- src - "." - },{ -- include - ".." - },{ -- extern_libs - "boost", - "spidermonkey", - "valgrind", - "wxwidgets", - },{ -- extra_params - no_pch = 1 - }) - atlas_src = { "ActorEditor", "CustomControls/Buttons", @@ -1076,8 +1064,7 @@ function setup_atlas_projects() "ScenarioEditor/Tools/Common", } atlas_extra_links = { - "AtlasObject", - "AtlasScript", + "AtlasObject" } atlas_extern_libs = { @@ -1087,7 +1074,6 @@ function setup_atlas_projects() --"ffmpeg", -- disabled for now because it causes too many build difficulties "libxml2", "sdl", -- key definitions - "spidermonkey", "wxwidgets", "zlib", } @@ -1117,10 +1103,6 @@ function setup_atlas_frontend_project (project_name) local target_type = get_main_project_target_type() project_create(project_name, target_type) - project_add_extern_libs({ - "spidermonkey", - }, - target_type) project_add_x11_dirs() local source_root = rootdir.."/source/tools/atlas/AtlasFrontends/" diff --git a/source/third_party/jsonspirit/LICENSE.txt b/source/third_party/jsonspirit/LICENSE.txt new file mode 100644 index 0000000000..e6e3c0f262 --- /dev/null +++ b/source/third_party/jsonspirit/LICENSE.txt @@ -0,0 +1,24 @@ +The MIT License + +Copyright (c) 2007 - 2010 John W. Wilkinson + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/source/third_party/jsonspirit/README.txt b/source/third_party/jsonspirit/README.txt new file mode 100644 index 0000000000..652a997a16 --- /dev/null +++ b/source/third_party/jsonspirit/README.txt @@ -0,0 +1,11 @@ +This separate JSON library is used for Atlas to avoid the SpiderMonkey dependency. +SpiderMonkey is a fully featured JS engine and even though we already use it for the main engine, it's too heavy-weight to use it in Atlas. +The SpiderMonkey API also changes frequently and we hope that the JSON parsing code needs less changes when we use this separate library. + +Get the library from here: +http://www.codeproject.com/Articles/20027/JSON-Spirit-A-C-JSON-Parser-Generator-Implemented + +The currently used version was released on the 23th of May 2013. + +Search for this comment in json_spirit_value.h and uncomment the lines we don't need: +// comment out the value types you don't need to reduce build times and intermediate file sizes diff --git a/source/third_party/jsonspirit/json_spirit_error_position.h b/source/third_party/jsonspirit/json_spirit_error_position.h new file mode 100644 index 0000000000..6a97bf15af --- /dev/null +++ b/source/third_party/jsonspirit/json_spirit_error_position.h @@ -0,0 +1,54 @@ +#ifndef JSON_SPIRIT_ERROR_POSITION +#define JSON_SPIRIT_ERROR_POSITION + +// Copyright John W. Wilkinson 2007 - 2013 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.06 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include + +namespace json_spirit +{ + // 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 diff --git a/source/third_party/jsonspirit/json_spirit_reader_template.h b/source/third_party/jsonspirit/json_spirit_reader_template.h new file mode 100644 index 0000000000..a067970e3b --- /dev/null +++ b/source/third_party/jsonspirit/json_spirit_reader_template.h @@ -0,0 +1,650 @@ +#ifndef JSON_SPIRIT_READER_TEMPLATE +#define JSON_SPIRIT_READER_TEMPLATE + +// Copyright John W. Wilkinson 2007 - 2013 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.06 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "json_spirit_value.h" +#include "json_spirit_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 json_spirit +{ + 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; + } + } + } + + 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_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 ); + } + + 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 i, 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 end ) + { + throw_error( begin, "not a value" ); + } + + static void throw_not_array( Iter_type begin, Iter_type end ) + { + throw_error( begin, "not an array" ); + } + + static void throw_not_object( Iter_type begin, Iter_type end ) + { + throw_error( begin, "not an object" ); + } + + static void throw_not_pair( Iter_type begin, Iter_type end ) + { + throw_error( begin, "not a pair" ); + } + + static void throw_not_colon( Iter_type begin, Iter_type end ) + { + throw_error( begin, "no colon in pair" ); + } + + static void throw_not_string( Iter_type begin, Iter_type end ) + { + 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_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 ) ); + 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_ + = string_[ new_str ] + | number_ + | object_ + | array_ + | str_p( "true" ) [ new_true ] + | str_p( "false" )[ new_false ] + | str_p( "null" ) [ new_null ] + ; + + object_ + = ch_p('{')[ begin_obj ] + >> !members_ + >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] ) + ; + + members_ + = pair_ >> *( ',' >> pair_ ) + ; + + pair_ + = string_[ new_name ] + >> ( ':' | 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_ ) + ; + + 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, + '"' + ) + ] + ; + + number_ + = strict_real_p[ new_real ] + | int64_p [ new_int ] + | uint64_p [ new_uint64 ] + ; + } + + spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_; + + 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 diff --git a/source/third_party/jsonspirit/json_spirit_value.h b/source/third_party/jsonspirit/json_spirit_value.h new file mode 100644 index 0000000000..54501a3395 --- /dev/null +++ b/source/third_party/jsonspirit/json_spirit_value.h @@ -0,0 +1,605 @@ +#ifndef JSON_SPIRIT_VALUE +#define JSON_SPIRIT_VALUE + +// Copyright John W. Wilkinson 2007 - 2013 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.06 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#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 json_spirit +{ + enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; + + static std::string value_type_to_string( Value_type vtype ); + + struct Null{}; + + template< class Config > // Config determines whether the value uses std::string or std::wstring and + // whether JSON Objects are represented as vectors or maps + class Value_impl + { + 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 diff --git a/source/third_party/jsonspirit/json_spirit_writer_options.h b/source/third_party/jsonspirit/json_spirit_writer_options.h new file mode 100644 index 0000000000..b2a85819c2 --- /dev/null +++ b/source/third_party/jsonspirit/json_spirit_writer_options.h @@ -0,0 +1,33 @@ +#ifndef JSON_SPIRIT_WRITER_OPTIONS +#define JSON_SPIRIT_WRITER_OPTIONS + +// Copyright John W. Wilkinson 2007 - 2013 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.06 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +namespace json_spirit +{ + enum Output_options{ pretty_print = 0x01, // Add whitespace to format the output nicely. + + raw_utf8 = 0x02, // This prevents non-printable characters from being escapted using "\uNNNN" notation. + // Note, this is an extension to the JSON standard. It disables the escaping of + // non-printable characters allowing UTF-8 sequences held in 8 bit char strings + // to pass through unaltered. + + remove_trailing_zeros = 0x04, + // outputs e.g. "1.200000000000000" as "1.2" + single_line_arrays = 0x08, + // pretty printing except that arrays printed on single lines unless they contain + // composite elements, i.e. objects or arrays + always_escape_nonascii = 0x10, + // all unicode wide characters are escaped, i.e. outputed as "\uXXXX", even if they are + // printable under the current locale, ascii printable chars are not escaped + }; +} + +#endif diff --git a/source/third_party/jsonspirit/json_spirit_writer_template.h b/source/third_party/jsonspirit/json_spirit_writer_template.h new file mode 100644 index 0000000000..7c1a62b873 --- /dev/null +++ b/source/third_party/jsonspirit/json_spirit_writer_template.h @@ -0,0 +1,387 @@ +#ifndef JSON_SPIRIT_WRITER_TEMPLATE +#define JSON_SPIRIT_WRITER_TEMPLATE + +// Copyright John W. Wilkinson 2007 - 2013 +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.06 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "json_spirit_value.h" +#include "json_spirit_writer_options.h" + +#include +#include +#include +#include + +namespace json_spirit +{ + 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 ) + { + typedef typename String_type::value_type Char_type; + + 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; + } + + template< class Ostream > + void append_double( Ostream& os, const double d, const int precision ) + { + os << std::showpoint << std::setprecision( precision ) << d; + } + + template< class String_type > + void erase_and_extract_exponent( String_type& str, String_type& exp ) + { + const typename String_type::size_type exp_start= str.find( 'e' ); + + if( exp_start != String_type::npos ) + { + exp = str.substr( exp_start ); + str.erase( exp_start ); + } + } + + template< class String_type > + typename String_type::size_type find_first_non_zero( const String_type& str ) + { + typename String_type::size_type result = str.size() - 1; + + for( ; result != 0; --result ) + { + if( str[ result ] != '0' ) + { + break; + } + } + + return result; + } + + template< class String_type > + void remove_trailing( String_type& str ) + { + String_type exp; + + erase_and_extract_exponent( str, exp ); + + const typename String_type::size_type first_non_zero = find_first_non_zero( str ); + + if( first_non_zero != 0 ) + { + const int offset = str[first_non_zero] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard + str.erase( first_non_zero + offset ); + } + + str += exp; + } + + // this class generates the JSON text, + // it keeps track of the indentation level etc. + // + 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, unsigned int options ) + : 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 ) + , remove_trailing_zeros_( ( options & remove_trailing_zeros ) != 0 ) + , single_line_arrays_( ( options & single_line_arrays ) != 0 ) + , ios_saver_( os ) + { + 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 ) + { + if( remove_trailing_zeros_ ) + { + std::basic_ostringstream< Char_type > os; + + append_double( os, d, 16 ); // note precision is 16 so that we get some trailing space that we can remove, + // otherwise, 0.1234 gets converted to "0.12399999..." + + String_type str = os.str(); + + remove_trailing( str ); + + os_ << str; + } + else + { + append_double( os_, d, 17 ); + } + } + + static bool contains_composite_elements( const Array_type& arr ) + { + for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) + { + const Value_type& val = *i; + + if( val.type() == obj_type || + val.type() == array_type ) + { + return true; + } + } + + return false; + } + + template< class Iter > + void output_composite_item( Iter i, Iter last ) + { + output( *i ); + + if( ++i != last ) + { + os_ << ','; + } + } + + void output( const Array_type& arr ) + { + if( single_line_arrays_ && !contains_composite_elements( arr ) ) + { + os_ << '['; space(); + + for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) + { + output_composite_item( i, arr.end() ); + + space(); + } + + os_ << ']'; + } + else + { + output_array_or_obj( arr, '[', ']' ); + } + } + + template< class T > + void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char ) + { + 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 remove_trailing_zeros_; + bool single_line_arrays_; + boost::io::basic_ios_all_saver< Char_type > ios_saver_; // so that ostream state is reset after control is returned to the caller + }; + + // writes JSON Value to a stream, e.g. + // + // write_stream( value, os, pretty_print ); + // + template< class Value_type, class Ostream_type > + void write_stream( const Value_type& value, Ostream_type& os, unsigned int options = 0 ) + { + os << std::dec; + Generator< Value_type, Ostream_type >( value, os, options ); + } + + // writes JSON Value to a stream, e.g. + // + // const string json_str = write( value, pretty_print ); + // + template< class Value_type > + typename Value_type::String_type write_string( const Value_type& value, unsigned int options = 0 ) + { + typedef typename Value_type::String_type::value_type Char_type; + + std::basic_ostringstream< Char_type > os; + + write_stream( value, os, options ); + + return os.str(); + } +} + +#endif diff --git a/source/tools/atlas/AtlasObject/AtlasObject.h b/source/tools/atlas/AtlasObject/AtlasObject.h index 67b2531288..c744dfa107 100644 --- a/source/tools/atlas/AtlasObject/AtlasObject.h +++ b/source/tools/atlas/AtlasObject/AtlasObject.h @@ -29,8 +29,6 @@ class wxString; -typedef struct JSContext JSContext; - ////////////////////////////////////////////////////////////////////////// // Mostly-private bits: @@ -193,7 +191,7 @@ namespace AtlasObject AtObj LoadFromXML(const std::string& xml); // Returns AtObj() on failure - test with AtObj::defined() - AtObj LoadFromJSON(JSContext* cx, const std::string& json); + AtObj LoadFromJSON(const std::string& json); // Returns UTF-8-encoded XML document string. // Returns empty string on failure. @@ -201,7 +199,7 @@ namespace AtlasObject // Returns UTF-8-encoded JSON string. // Returns empty string on failure. - std::string SaveToJSON(JSContext* cx, AtObj& obj); + std::string SaveToJSON(AtObj& obj); AtObj TrimEmptyChildren(AtObj& obj); } diff --git a/source/tools/atlas/AtlasObject/AtlasObjectJS.cpp b/source/tools/atlas/AtlasObject/AtlasObjectJS.cpp index 8b53ead96f..6e25b38af0 100644 --- a/source/tools/atlas/AtlasObject/AtlasObjectJS.cpp +++ b/source/tools/atlas/AtlasObject/AtlasObjectJS.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ #include "AtlasObject.h" #include "AtlasObjectImpl.h" -#include "../AtlasScript/ScriptInterface.h" +#include "JSONSpiritInclude.h" #if defined(_MSC_VER) # pragma warning(disable:4996) // deprecated CRT @@ -28,146 +28,94 @@ #include -static AtSmartPtr ConvertNode(JSContext* cx, jsval node); +static AtSmartPtr ConvertNode(json_spirit::Value node); -AtObj AtlasObject::LoadFromJSON(JSContext* cx, const std::string& json) +AtObj AtlasObject::LoadFromJSON(const std::string& json) { - // Convert UTF8 to UTF16 - wxString jsonW(json.c_str(), wxConvUTF8); - size_t json16len; - wxCharBuffer json16 = wxMBConvUTF16().cWC2MB(jsonW.c_str(), jsonW.Length(), &json16len); - - jsval vp = JSVAL_NULL; - JSONParser* parser = JS_BeginJSONParse(cx, &vp); - if (!parser) - { - wxLogError(_T("ParseJSON failed to begin")); - return AtObj(); - } - - if (!JS_ConsumeJSONText(cx, parser, reinterpret_cast(json16.data()), (uint32)(json16len/2))) - { - wxLogError(_T("ParseJSON failed to consume")); - return AtObj(); - } - - if (!JS_FinishJSONParse(cx, parser, JSVAL_NULL)) - { - wxLogError(_T("ParseJSON failed to finish")); - return AtObj(); - } - + json_spirit::Value rootnode; + json_spirit::read_string(json, rootnode); + AtObj obj; - obj.p = ConvertNode(cx, vp); - + obj.p = ConvertNode(rootnode); return obj; } -// Convert from a jsval to an AtNode -static AtSmartPtr ConvertNode(JSContext* cx, jsval node) +// Convert from a JSON to an AtNode +static AtSmartPtr ConvertNode(json_spirit::Value node) { AtSmartPtr obj (new AtNode()); - - // Non-objects get converted into strings - if (!JSVAL_IS_OBJECT(node)) + + if (node.type() == json_spirit::str_type) { - JSString* str = JS_ValueToString(cx, node); - if (!str) - return obj; // error - size_t valueLen; - const jschar* valueChars = JS_GetStringCharsAndLength(cx, str, &valueLen); - if (!valueChars) - return obj; // error - wxString valueWx(reinterpret_cast(valueChars), wxMBConvUTF16(), valueLen*2); - - obj->value = valueWx.c_str(); - - // Annotate numbers/booleans specially, to allow round-tripping - if (JSVAL_IS_NUMBER(node)) - { - obj->children.insert(AtNode::child_pairtype( - "@number", AtSmartPtr(new AtNode()) - )); - } - else if (JSVAL_IS_BOOLEAN(node)) - { - obj->children.insert(AtNode::child_pairtype( - "@boolean", AtSmartPtr(new AtNode()) - )); - } - - return obj; + obj->value = std::wstring(node.get_str().begin(),node.get_str().end()); } - - JSObject* it = JS_NewPropertyIterator(cx, JSVAL_TO_OBJECT(node)); - if (!it) - return obj; // error - - while (true) + else if (node.type() == json_spirit::int_type || node.type() == json_spirit::real_type) { - jsid idp; - jsval val; - if (! JS_NextProperty(cx, it, &idp) || ! JS_IdToValue(cx, idp, &val)) - return obj; // error - if (val == JSVAL_VOID) - break; // end of iteration - if (! JSVAL_IS_STRING(val)) - continue; // ignore integer properties - - JSString* name = JSVAL_TO_STRING(val); - size_t len; - const jschar* chars = JS_GetStringCharsAndLength(cx, name, &len); - wxString nameWx(reinterpret_cast(chars), wxMBConvUTF16(), len*2); - std::string nameStr(nameWx.ToUTF8().data()); - - jsval vp; - if (!JS_GetPropertyById(cx, JSVAL_TO_OBJECT(node), idp, &vp)) - return obj; // error - - // Unwrap arrays into a special format like <$name>$i0... - // (This assumes arrays aren't nested) - if (JSVAL_IS_OBJECT(vp) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(vp))) - { - AtSmartPtr child(new AtNode()); - child->children.insert(AtNode::child_pairtype( - "@array", AtSmartPtr(new AtNode()) - )); - - jsuint arrayLength; - if (!JS_GetArrayLength(cx, JSVAL_TO_OBJECT(vp), &arrayLength)) - return obj; // error - - for (jsuint i = 0; i < arrayLength; ++i) - { - jsval val; - if (!JS_GetElement(cx, JSVAL_TO_OBJECT(vp), i, &val)) - return obj; // error - - child->children.insert(AtNode::child_pairtype( - "item", ConvertNode(cx, val) - )); - } - - obj->children.insert(AtNode::child_pairtype( - nameStr, child - )); - } + std::wstringstream stream; + if (node.type() == json_spirit::int_type) + stream << node.get_int(); + if (node.type() == json_spirit::real_type) + stream << node.get_real(); + + obj->value = stream.str().c_str(); + obj->children.insert(AtNode::child_pairtype( + "@number", AtSmartPtr(new AtNode()) + )); + } + else if (node.type() == json_spirit::bool_type) + { + if (node.get_bool()) + obj->value = L"true"; else + obj->value = L"false"; + + obj->children.insert(AtNode::child_pairtype( + "@boolean", AtSmartPtr(new AtNode()) + )); + } + else if (node.type() == json_spirit::array_type) + { + obj->children.insert(AtNode::child_pairtype( + "@array", AtSmartPtr(new AtNode()) + )); + + json_spirit::Array nodeChildren = node.get_array(); + json_spirit::Array::iterator itr = nodeChildren.begin(); + + for (; itr != nodeChildren.end(); itr++) { obj->children.insert(AtNode::child_pairtype( - nameStr, ConvertNode(cx, vp) + "item", ConvertNode(*itr) )); } } - + else if (node.type() == json_spirit::obj_type) + { + json_spirit::Object objectProperties = node.get_obj(); + json_spirit::Object::iterator itr = objectProperties.begin(); + for (; itr != objectProperties.end(); itr++) + { + obj->children.insert(AtNode::child_pairtype( + itr->name_, ConvertNode(itr->value_) + )); + } + } + else + { + assert(! "Unimplemented type found when parsing JSON!"); + } + return obj; } -jsval BuildJSVal(JSContext* cx, AtNode::Ptr p) +json_spirit::Value BuildJSONNode(AtNode::Ptr p) { if (!p) - return JSVAL_VOID; + { + json_spirit::Value rval; + return rval; + } // Special case for numbers/booleans to allow round-tripping if (p->children.count("@number")) @@ -178,9 +126,7 @@ jsval BuildJSVal(JSContext* cx, AtNode::Ptr p) double val = 0; str >> val; - jsval rval; - if (!JS_NewNumberValue(cx, val, &rval)) - return JSVAL_VOID; // error + json_spirit::Value rval(val); return rval; } else if (p->children.count("@boolean")) @@ -188,85 +134,54 @@ jsval BuildJSVal(JSContext* cx, AtNode::Ptr p) bool val = false; if (p->value == L"true") val = true; - - return BOOLEAN_TO_JSVAL(val); + + json_spirit::Value rval(val); + return rval; } // If no children, then use the value string instead if (p->children.empty()) { - size_t val16len; - wxCharBuffer val16 = wxMBConvUTF16().cWC2MB(p->value.c_str(), p->value.length(), &val16len); - - JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast(val16.data()), (uint32)(val16len/2)); - if (!str) - return JSVAL_VOID; // error - return STRING_TO_JSVAL(str); + json_spirit::Value rval(std::string(p->value.begin(), p->value.end())); + return rval; } if (p->children.find("@array") != p->children.end()) { - JSObject* obj = JS_NewArrayObject(cx, 0, NULL); - if (!obj) - return JSVAL_VOID; // error + json_spirit::Array rval; // Find the children AtNode::child_maptype::const_iterator lower = p->children.lower_bound("item"); AtNode::child_maptype::const_iterator upper = p->children.upper_bound("item"); - jsint idx = 0; + uint32_t idx = 0; for (AtNode::child_maptype::const_iterator it = lower; it != upper; ++it) { - jsval val = BuildJSVal(cx, it->second); - if (!JS_SetElement(cx, obj, idx, &val)) - return JSVAL_VOID; // error + json_spirit::Value child = BuildJSONNode(it->second); + rval.push_back(child); ++idx; } - return OBJECT_TO_JSVAL(obj); + return rval; } else { - JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL); - if (!obj) - return JSVAL_VOID; // error - + json_spirit::Object rval; + for (AtNode::child_maptype::const_iterator it = p->children.begin(); it != p->children.end(); ++it) { - jsval val = BuildJSVal(cx, it->second); - if (!JS_SetProperty(cx, obj, it->first.c_str(), &val)) - return JSVAL_VOID; // error + json_spirit::Value child = BuildJSONNode(it->second); + rval.push_back(json_spirit::Pair(it->first.c_str(), child)); } - return OBJECT_TO_JSVAL(obj); + return rval; } } -struct Stringifier +std::string AtlasObject::SaveToJSON(AtObj& obj) { - static JSBool callback(const jschar* buf, uint32 len, void* data) - { - wxString textWx(reinterpret_cast(buf), wxMBConvUTF16(), len*2); - std::string textStr(textWx.ToUTF8().data()); - - static_cast(data)->stream << textStr; - return JS_TRUE; - } - - std::stringstream stream; -}; - -std::string AtlasObject::SaveToJSON(JSContext* cx, AtObj& obj) -{ - jsval root = BuildJSVal(cx, obj.p); - - Stringifier str; - if (!JS_Stringify(cx, &root, NULL, JSVAL_VOID, &Stringifier::callback, &str)) - { - wxLogError(_T("SaveToJSON failed")); - return ""; - } - - return str.stream.str(); + json_spirit::Value root = BuildJSONNode(obj.p); + std::string ret = json_spirit::write_string(root, 0); + return ret; } diff --git a/source/tools/atlas/AtlasObject/JSONSpiritInclude.h b/source/tools/atlas/AtlasObject/JSONSpiritInclude.h new file mode 100644 index 0000000000..4d4f7131aa --- /dev/null +++ b/source/tools/atlas/AtlasObject/JSONSpiritInclude.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2014 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + + // We use this special header for including the JSONSpirit header because some tweaking is needed to disable warnings. +#ifndef JSON_SPIRIT_INCLUDE_H +#define JSON_SPIRIT_INCLUDE_H + +#ifdef __GNUC__ +# define GCC_VERSION (__GNUC__*100 + __GNUC_MINOR__) +#else +# define GCC_VERSION 0 +#endif + +#if GCC_VERSION >= 402 // (older GCCs don't support this pragma) +# pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#ifdef _MSC_VER + #pragma warning(disable: 4100) + #pragma warning(disable: 4512) +#endif + +# include "json_spirit_writer_template.h" +# include "json_spirit_reader_template.h" + +#ifdef _MSC_VER + #pragma warning(default: 4100) + #pragma warning(default: 4512) +#endif + +#if GCC_VERSION >= 402 +# pragma GCC diagnostic warning "-Wunused-parameter" +#endif + +#endif // JSON_SPIRIT_INCLUDE_H \ No newline at end of file diff --git a/source/tools/atlas/AtlasScript/NativeWrapper.inl b/source/tools/atlas/AtlasScript/NativeWrapper.inl deleted file mode 100644 index 148c98cc5e..0000000000 --- a/source/tools/atlas/AtlasScript/NativeWrapper.inl +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (C) 2009 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include -#include - -// Set the maximum number of function arguments that can be handled -#define MAX_ARGS 3 - -// (This is included inside the definition of class ScriptInterface) -public: - // Varieties of comma-separated list to fit on the head/tail/whole of another comma-separated list - #define NUMBERED_LIST_TAIL(z, i, data) ,data##i - #define NUMBERED_LIST_HEAD(z, i, data) data##i, - #define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i - // Some other things - #define TYPED_ARGS(z, i, data) , T##i a##i - #define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) return JS_FALSE; - - // List-generating macros, named roughly after their first list item - #define TYPENAME_T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, typename T) - #define TYPENAME_T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, typename T) - #define T0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, T) - #define T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, T) - #define T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, T) - #define T0_A0(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS, ~) - #define A0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, a) - #define A0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, a) - - // Define RegisterFunction - #define OVERLOADS(z, i, data) \ - template \ - void RegisterFunction(const char* name) { \ - Register(name, call, nargs<0 T0_TAIL(z,i)>()); \ - } - - BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~) - #undef OVERLOADS - -private: - // JSNative-compatible function that wraps the function identified in the template argument list - // (Definition comes later, since it depends on some things we haven't defined yet) - #define OVERLOADS(z, i, data) \ - template \ - static JSBool call(JSContext* cx, uintN argc, jsval* vp); - BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~) - #undef OVERLOADS - - // Argument-number counter - #define OVERLOADS(z, i, data) \ - template /* add a dummy parameter so we still compile with 0 template args */ \ - static size_t nargs() { return i; } - BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~) - #undef OVERLOADS - -}; // end of class ScriptInterface, because the following specialised structs - // are not permitted inside non-namespace scopes - - -// ScriptInterface_NativeWrapper::call(cx, rval, fptr, args...) will call fptr(cbdata, args), -// and if T != void then it will store the result in rval: - -// Templated on the return type so void can be handled separately -template -struct ScriptInterface_NativeWrapper { - #define OVERLOADS(z, i, data) \ - template \ - static void call(JSContext* cx, jsval& rval, f fptr T0_A0(z,i)) { \ - rval = ScriptInterface::ToJSVal(cx, fptr(ScriptInterface::GetCallbackData(cx) A0_TAIL(z,i))); \ - } - - BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~) - #undef OVERLOADS -}; - -// Overloaded to ignore the return value from void functions -template <> -struct ScriptInterface_NativeWrapper { - #define OVERLOADS(z, i, data) \ - template \ - static void call(JSContext* cx, jsval& /*rval*/, f fptr T0_A0(z,i)) { \ - fptr(ScriptInterface::GetCallbackData(cx) A0_TAIL(z,i)); \ - } - BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~) - #undef OVERLOADS -}; - -// JSNative-compatible function that wraps the function identified in the template argument list -#define OVERLOADS(z, i, data) \ - template \ - JSBool ScriptInterface::call(JSContext* cx, uintN argc, jsval* vp) { \ - (void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \ - BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ - jsval rval = JSVAL_VOID; \ - ScriptInterface_NativeWrapper::call(cx, rval, fptr A0_TAIL(z,i)); \ - JS_SET_RVAL(cx, vp, rval); \ - return JS_TRUE; \ - } -BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~) -#undef OVERLOADS - -// Clean up our mess -#undef NUMBERED_LIST_TAIL -#undef NUMBERED_LIST_HEAD -#undef NUMBERED_LIST_BALANCED -#undef TYPED_ARGS -#undef CONVERT_ARG -#undef TYPENAME_T0_HEAD -#undef TYPENAME_T0_TAIL -#undef T0 -#undef T0_HEAD -#undef T0_TAIL -#undef T0_A0 -#undef A0 -#undef A0_TAIL diff --git a/source/tools/atlas/AtlasScript/ScriptInterface.cpp b/source/tools/atlas/AtlasScript/ScriptInterface.cpp deleted file mode 100644 index 48a0dc5ab9..0000000000 --- a/source/tools/atlas/AtlasScript/ScriptInterface.cpp +++ /dev/null @@ -1,727 +0,0 @@ -/* Copyright (C) 2011 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include "ScriptInterface.h" - -#include -#ifndef _WIN32 -# include -# include -#endif - -#if defined(_MSC_VER) -# pragma warning(disable:4996) // deprecated CRT -#endif - -#if defined(__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__) >= 402 // (older GCCs don't support this pragma) -# pragma GCC diagnostic ignored "-Wredundant-decls" // triggered by wx/geometry.h -#endif - -#include "wx/wx.h" - -#include "GameInterface/Shareable.h" -#include "GameInterface/Messages.h" - - -#include -#include - -#include "valgrind.h" - -#define FAIL(msg) do { JS_ReportError(cx, msg); return false; } while (false) - -const int RUNTIME_SIZE = 4*1024*1024; // TODO: how much memory is needed? -const int STACK_CHUNK_SIZE = 8192; - -SubmitCommand g_SubmitCommand; // TODO: globals are ugly - -//////////////////////////////////////////////////////////////// - -namespace -{ - template - void ReportError(JSContext* cx, const char* title) - { - // TODO: SetPendingException turns the error into a JS-catchable exception, - // but the error report doesn't say anything useful like the line number, - // so I'm just using ReportError instead for now (and failures are uncatchable - // and will terminate the whole script) - //JS_SetPendingException(cx, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "%s: Unhandled type", title))); -#ifdef _WIN32 - JS_ReportError(cx, "%s: Unhandled type", title); -#else - // Give a more informative message on GCC - int status; - char* name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status); - JS_ReportError(cx, "%s: Unhandled type '%s'", title, name); - free(name); -#endif - } - - // Report runtime errors for unhandled types, so we don't have to bother - // defining all the types in advance. (TODO: at some point we should - // define all the types and then remove this bit so the errors are found - // at link-time.) - template struct FromJSVal - { - static bool Convert(JSContext* cx, jsval WXUNUSED(v), T& WXUNUSED(out)) - { - ReportError(cx, "FromJSVal"); - return false; - } - }; - - template<> struct FromJSVal - { - static bool Convert(JSContext* cx, jsval v, bool& out) - { - JSBool ret; - if (! JS_ValueToBoolean(cx, v, &ret)) return false; - out = (ret ? true : false); - return true; - } - }; - - template<> struct FromJSVal - { - static bool Convert(JSContext* cx, jsval v, float& out) - { - jsdouble ret; - if (! JS_ValueToNumber(cx, v, &ret)) return false; - out = ret; - return true; - } - }; - - template<> struct FromJSVal - { - static bool Convert(JSContext* cx, jsval v, int& out) - { - int32 ret; - if (! JS_ValueToECMAInt32(cx, v, &ret)) return false; - out = ret; - return true; - } - }; - - template<> struct FromJSVal - { - static bool Convert(JSContext* cx, jsval v, size_t& out) - { - uint32 ret; - if (! JS_ValueToECMAUint32(cx, v, &ret)) return false; - out = ret; - return true; - } - }; - - template<> struct FromJSVal - { - static bool Convert(JSContext* WXUNUSED(cx), jsval v, CScriptVal& out) - { - out = v; - return true; - } - }; - - template<> struct FromJSVal - { - static bool Convert(JSContext* cx, jsval v, std::wstring& out) - { - JSString* ret = JS_ValueToString(cx, v); - if (! ret) - FAIL("Argument must be convertible to a string"); - size_t len; - const jschar* ch = JS_GetStringCharsAndLength(cx, ret, &len); - if (! ch) - FAIL("JS_GetStringsCharsAndLength failed"); // probably out of memory - out = std::wstring(ch, ch + len); - return true; - } - }; - - template<> struct FromJSVal - { - static bool Convert(JSContext* cx, jsval v, std::string& out) - { - JSString* ret = JS_ValueToString(cx, v); - if (! ret) - FAIL("Argument must be convertible to a string"); - size_t len = JS_GetStringEncodingLength(cx, ret); - if (len == (size_t)-1) - FAIL("JS_GetStringEncodingLength failed"); - char* ch = JS_EncodeString(cx, ret); // chops off high byte of each jschar - if (! ch) - FAIL("JS_EncodeString failed"); // probably out of memory - out = std::string(ch, ch + len); - JS_free(cx, ch); - return true; - } - }; - - template<> struct FromJSVal - { - static bool Convert(JSContext* cx, jsval v, wxString& out) - { - JSString* ret = JS_ValueToString(cx, v); - size_t len; - if (! ret) - FAIL("Argument must be convertible to a string"); - const jschar* ch = JS_GetStringCharsAndLength(cx, ret, &len); - if (! ch) - FAIL("JS_GetStringsCharsAndLength failed"); // probably out of memory - out = wxString((const char*)ch, wxMBConvUTF16(), len*2); - return true; - } - }; - - template struct FromJSVal > - { - static bool Convert(JSContext* cx, jsval v, std::vector& out) - { - JSObject* obj; - if (! JS_ValueToObject(cx, v, &obj) || obj == NULL || !JS_IsArrayObject(cx, obj)) - FAIL("Argument must be an array"); - jsuint length; - if (! JS_GetArrayLength(cx, obj, &length)) - FAIL("Failed to get array length"); - out.reserve(length); - for (jsuint i = 0; i < length; ++i) - { - jsval el; - if (! JS_GetElement(cx, obj, i, &el)) - FAIL("Failed to read array element"); - T el2; - if (! FromJSVal::Convert(cx, el, el2)) - return false; - out.push_back(el2); - } - return true; - } - }; - - //////////////////////////////////////////////////////////////// - - // Report runtime errors for unhandled types, so we don't have to bother - // defining all the types in advance. (TODO: at some point we should - // define all the types and then remove this bit so the errors are found - // at link-time.) - template struct ToJSVal - { - static jsval Convert(JSContext* cx, const T& WXUNUSED(val)) - { - ReportError(cx, "ToJSVal"); - return JSVAL_VOID; - } - }; - - //////////////////////////////////////////////////////////////// - // Primitive types: - - template<> struct ToJSVal - { - static jsval Convert(JSContext* WXUNUSED(cx), const bool& val) - { - return val ? JSVAL_TRUE : JSVAL_FALSE; - } - }; - - template<> struct ToJSVal - { - static jsval Convert(JSContext* cx, const float& val) - { - jsval rval = JSVAL_VOID; - JS_NewNumberValue(cx, val, &rval); // ignore return value - return rval; - } - }; - - template<> struct ToJSVal - { - static jsval Convert(JSContext* WXUNUSED(cx), const int& val) - { - return INT_TO_JSVAL(val); - } - }; - - template<> struct ToJSVal - { - static jsval Convert(JSContext* cx, const size_t& val) - { - if (val <= JSVAL_INT_MAX) - return INT_TO_JSVAL(val); - jsval rval = JSVAL_VOID; - JS_NewNumberValue(cx, val, &rval); // ignore return value - return rval; - } - }; - - template<> struct ToJSVal - { - static jsval Convert(JSContext* cx, const wxString& val) - { - wxMBConvUTF16 conv; - size_t length; - wxCharBuffer utf16 = conv.cWC2MB(val.c_str(), val.length()+1, &length); - JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast(utf16.data()), length/2); - if (str) - return STRING_TO_JSVAL(str); - else - return JSVAL_VOID; - } - }; - - template<> struct ToJSVal - { - static jsval Convert(JSContext* cx, const std::wstring& val) - { - wxMBConvUTF16 conv; - size_t length; - wxCharBuffer utf16 = conv.cWC2MB(val.c_str(), val.length()+1, &length); - JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast(utf16.data()), length/2); - if (str) - return STRING_TO_JSVAL(str); - else - return JSVAL_VOID; - } - }; - - template<> struct ToJSVal - { - static jsval Convert(JSContext* cx, const std::string& val) - { - JSString* str = JS_NewStringCopyN(cx, val.c_str(), val.length()); - if (str) - return STRING_TO_JSVAL(str); - return JSVAL_VOID; - } - }; - - //////////////////////////////////////////////////////////////// - // Compound types: - - template struct ToJSVal > - { - static jsval Convert(JSContext* cx, const std::vector& val) - { - JSObject* obj = JS_NewArrayObject(cx, 0, NULL); - if (! obj) return JSVAL_VOID; - for (size_t i = 0; i < val.size(); ++i) - { - jsval el = ToJSVal::Convert(cx, val[i]); - JS_SetElement(cx, obj, (jsint)i, &el); - } - return OBJECT_TO_JSVAL(obj); - } - }; - - template struct ToJSVal > - { - static jsval Convert(JSContext* cx, const AtlasMessage::Shareable& val) - { - return ToJSVal::Convert(cx, val._Unwrap()); - } - }; -} - -template bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, T& out) -{ - return ::FromJSVal::Convert(cx, v, out); -} - -template jsval ScriptInterface::ToJSVal(JSContext* cx, const T& v) -{ - return ::ToJSVal::Convert(cx, v); -} - -// Explicit instantiation of functions that would otherwise be unused in this file -// but are required for linking with other files -template bool ScriptInterface::FromJSVal(JSContext*, jsval, std::string&); -template bool ScriptInterface::FromJSVal(JSContext*, jsval, wxString&); -template bool ScriptInterface::FromJSVal(JSContext*, jsval, bool&); -template bool ScriptInterface::FromJSVal(JSContext*, jsval, float&); -template bool ScriptInterface::FromJSVal(JSContext*, jsval, CScriptVal&); -template jsval ScriptInterface::ToJSVal(JSContext*, wxString const&); -template jsval ScriptInterface::ToJSVal(JSContext*, int const&); -template jsval ScriptInterface::ToJSVal(JSContext*, float const&); -template jsval ScriptInterface::ToJSVal >(JSContext*, std::vector const&); -template jsval ScriptInterface::ToJSVal(JSContext*, size_t const&); -template jsval ScriptInterface::ToJSVal >(JSContext*, std::vector const&); - -//////////////////////////////////////////////////////////////// - -struct AtlasScriptInterface_impl -{ - AtlasScriptInterface_impl(); - ~AtlasScriptInterface_impl(); - static JSBool LoadScript(JSContext* cx, const jschar* chars, uintN length, const char* filename, jsval* rval); - void RegisterMessages(JSObject* parent); - void Register(const char* name, JSNative fptr, uintN nargs); - - JSRuntime* m_rt; - JSContext* m_cx; - JSObject* m_glob; // global scope object - JSObject* m_atlas; // Atlas scope object -}; - -namespace -{ - JSClass global_class = { - "global", JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL - }; - - void ErrorReporter(JSContext* WXUNUSED(cx), const char* message, JSErrorReport* report) - { - bool isWarning = JSREPORT_IS_WARNING(report->flags); - wxString logMessage(isWarning ? _T("JavaScript warning: ") : _T("JavaScript error: ")); - if (report->filename) - { - logMessage << wxString::FromAscii(report->filename); - logMessage << _T(" line ") << report->lineno << _T("\n"); - } - logMessage << wxString::FromAscii(message); - if (isWarning) - wxLogWarning(_T("%s"), logMessage.c_str()); - else - wxLogError(_T("%s"), logMessage.c_str()); - // When running under Valgrind, print more information in the error message - VALGRIND_PRINTF_BACKTRACE("->"); - wxPrintf(_T("wxJS %s: %s\n--------\n"), isWarning ? _T("warning") : _T("error"), logMessage.c_str()); - } - - // Functions in the Atlas.* namespace: - - JSBool ForceGC(JSContext* cx, uintN WXUNUSED(argc), jsval* vp) - { - JS_GC(cx); - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; - } - - JSBool LoadScript(JSContext* cx, uintN argc, jsval* vp) - { - if (argc < 2 || !JSVAL_IS_STRING(JS_ARGV(cx, vp)[0]) || !JSVAL_IS_STRING(JS_ARGV(cx, vp)[1])) - return JS_FALSE; - - std::string name; - if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], name)) - return JS_FALSE; - - JSString* code = JSVAL_TO_STRING(JS_ARGV(cx, vp)[1]); - - size_t len; - const jschar* ch = JS_GetStringCharsAndLength(cx, code, &len); - if (!ch) - return JS_FALSE; - - jsval rval = JSVAL_VOID; - if (!AtlasScriptInterface_impl::LoadScript(cx, - ch, (uintN)len, - name.c_str(), &rval)) - return JS_FALSE; - - JS_SET_RVAL(cx, vp, rval); - return JS_TRUE; - } - - // Functions in the global namespace: - - JSBool print(JSContext* cx, uintN argc, jsval* vp) - { - for (uintN i = 0; i < argc; ++i) - { - std::string str; - if (! ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[i], str)) - return JS_FALSE; - printf("%s", str.c_str()); - } - fflush(stdout); - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; - } -} - -AtlasScriptInterface_impl::AtlasScriptInterface_impl() -{ - m_rt = JS_NewRuntime(RUNTIME_SIZE); - assert(m_rt); // TODO: error handling - - m_cx = JS_NewContext(m_rt, STACK_CHUNK_SIZE); - assert(m_cx); - - JS_BeginRequest(m_cx); // if you get linker errors, see the comment in ScriptInterface.h about JS_THREADSAFE - // (TODO: are we using requests correctly? (Probably not; how much does it matter?)) - - JS_SetContextPrivate(m_cx, NULL); - - JS_SetErrorReporter(m_cx, ErrorReporter); - - JS_SetOptions(m_cx, - JSOPTION_STRICT // "warn on dubious practice" - | JSOPTION_XML // "ECMAScript for XML support: parse as a token" - ); - - JS_SetVersion(m_cx, JSVERSION_LATEST); - - m_glob = JS_NewCompartmentAndGlobalObject(m_cx, &global_class, NULL); - JS_InitStandardClasses(m_cx, m_glob); - - JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - - JS_DefineFunction(m_cx, m_glob, "print", ::print, 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - - m_atlas = JS_DefineObject(m_cx, m_glob, "Atlas", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - JS_DefineFunction(m_cx, m_atlas, "ForceGC", ::ForceGC, 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - JS_DefineFunction(m_cx, m_atlas, "LoadScript", ::LoadScript, 2, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - JS_DefineObject(m_cx, m_atlas, "State", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - - RegisterMessages(m_atlas); -} - -AtlasScriptInterface_impl::~AtlasScriptInterface_impl() -{ - JS_EndRequest(m_cx); - JS_DestroyContext(m_cx); - JS_DestroyRuntime(m_rt); -} - -JSBool AtlasScriptInterface_impl::LoadScript(JSContext* cx, const jschar* chars, uintN length, const char* filename, jsval* rval) -{ - JSObject* scriptObj = JS_NewObject(cx, NULL, NULL, NULL); - if (! scriptObj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(scriptObj); - - jsval scriptRval; - JSBool ok = JS_EvaluateUCScript(cx, scriptObj, chars, length, filename, 1, &scriptRval); - if (! ok) - return JS_FALSE; - - return JS_TRUE; -} - -void AtlasScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs) -{ - JS_DefineFunction(m_cx, m_atlas, name, fptr, nargs, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); -} - - -ScriptInterface::ScriptInterface(SubmitCommand submitCommand) - : m(new AtlasScriptInterface_impl()) -{ - g_SubmitCommand = submitCommand; -} - -ScriptInterface::~ScriptInterface() -{ -} - -void ScriptInterface::SetCallbackData(void* cbdata) -{ - JS_SetContextPrivate(m->m_cx, cbdata); -} - -void* ScriptInterface::GetCallbackData(JSContext* cx) -{ - return JS_GetContextPrivate(cx); -} - -void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) -{ - m->Register(name, fptr, (uintN)nargs); -} - -JSContext* ScriptInterface::GetContext() -{ - return m->m_cx; -} - -bool ScriptInterface::AddRoot(jsval* ptr) -{ - return JS_AddValueRoot(m->m_cx, ptr) ? true : false; -} - -bool ScriptInterface::RemoveRoot(jsval* ptr) -{ - return JS_RemoveValueRoot(m->m_cx, ptr) ? true : false; -} - - -bool ScriptInterface::SetValue_(const wxString& name, jsval val) -{ - jsval jsName = ToJSVal(m->m_cx, name); - - const uintN argc = 2; - jsval argv[argc] = { jsName, val }; - jsval rval; - JSBool ok = JS_CallFunctionName(m->m_cx, m->m_glob, "setValue", argc, argv, &rval); - return ok ? true : false; -} - -bool ScriptInterface::GetValue_(const wxString& name, jsval& ret) -{ - jsval jsName = ToJSVal(m->m_cx, name); - - const uintN argc = 1; - jsval argv[argc] = { jsName }; - JSBool ok = JS_CallFunctionName(m->m_cx, m->m_glob, "getValue", argc, argv, &ret); - return ok ? true : false; -} - -bool ScriptInterface::CallFunction(jsval val, const char* name) -{ - jsval jsRet; - std::vector argv; - return CallFunction_(val, name, argv, jsRet); -} - -bool ScriptInterface::CallFunction_(jsval val, const char* name, std::vector& args, jsval& ret) -{ - const uintN argc = (uintN)args.size(); - jsval* argv = NULL; - if (argc) - argv = &args[0]; - wxCHECK(JSVAL_IS_OBJECT(val), false); - JSBool found; - wxCHECK(JS_HasProperty(m->m_cx, JSVAL_TO_OBJECT(val), name, &found), false); - if (! found) - return false; - JSBool ok = JS_CallFunctionName(m->m_cx, JSVAL_TO_OBJECT(val), name, argc, argv, &ret); - return ok ? true : false; -} - -bool ScriptInterface::Eval(const wxString& script) -{ - jsval rval; - JSBool ok = JS_EvaluateScript(m->m_cx, m->m_glob, script.mb_str(), (uintN)script.length(), NULL, 0, &rval); - return ok ? true : false; -} - -bool ScriptInterface::Eval_(const wxString& script, jsval& rval) -{ - JSBool ok = JS_EvaluateScript(m->m_cx, m->m_glob, script.mb_str(), (uintN)script.length(), NULL, 0, &rval); - return ok ? true : false; -} - -void ScriptInterface::LoadScript(const wxString& filename, const wxString& code) -{ - size_t codeLength; - wxMBConvUTF16 conv; - wxCharBuffer codeUTF16 = conv.cWC2MB(code.c_str(), code.length()+1, &codeLength); - jsval rval; - m->LoadScript(m->m_cx, reinterpret_cast(codeUTF16.data()), (uintN)(codeLength/2), filename.ToAscii(), &rval); -} - -//////////////////////////////////////////////////////////////// - -#define TYPE(elem) BOOST_PP_TUPLE_ELEM(2, 0, elem) -#define NAME(elem) BOOST_PP_TUPLE_ELEM(2, 1, elem) -#define MAKE_STR_(s) #s -#define MAKE_STR(s) MAKE_STR_(s) - -#define CONVERT_ARGS(r, data, i, elem) \ - TYPE(elem) a##i; \ - if (! ScriptInterface::FromJSVal< TYPE(elem) >(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) \ - return JS_FALSE; - -#define CONVERT_OUTPUTS(r, data, i, elem) \ - JS_DefineProperty(cx, ret, MAKE_STR(NAME(elem)), ScriptInterface::ToJSVal(cx, q.NAME(elem)), \ - NULL, NULL, JSPROP_ENUMERATE); - -#define ARG_LIST(r, data, i, elem) BOOST_PP_COMMA_IF(i) a##i - -#define MESSAGE(name, vals) \ - JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \ - { \ - (void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \ - BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, vals) \ - g_MessagePasser->Add(SHAREABLE_NEW(m##name, ( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, vals) ))); \ - JS_SET_RVAL(cx, vp, JSVAL_VOID); \ - return JS_TRUE; \ - } - -#define COMMAND(name, merge, vals) \ - JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \ - { \ - (void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \ - BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, vals) \ - g_SubmitCommand(new AtlasMessage::m##name (AtlasMessage::d##name ( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, vals) ))); \ - JS_SET_RVAL(cx, vp, JSVAL_VOID); \ - return JS_TRUE; \ - } - -#define QUERY(name, in_vals, out_vals) \ - JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \ - { \ - (void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \ - BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, in_vals) \ - q##name q = q##name( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, in_vals) ); \ - q.Post(); \ - JSObject* ret = JS_NewObject(cx, NULL, NULL, NULL); \ - if (! ret) return JS_FALSE; \ - JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(ret)); \ - BOOST_PP_SEQ_FOR_EACH_I(CONVERT_OUTPUTS, ~, out_vals) \ - return JS_TRUE; \ - } - -#define MESSAGES_SKIP_SETUP -#define MESSAGES_SKIP_STRUCTS - -// We want to include Messages.h again, with some different definitions, -// so cheat and undefine its include-guard -#undef INCLUDED_MESSAGES - -namespace -{ - using namespace AtlasMessage; - #include "GameInterface/Messages.h" -} - -#undef MESSAGE -#undef COMMAND -#undef QUERY - -void AtlasScriptInterface_impl::RegisterMessages(JSObject* parent) -{ - using namespace AtlasMessage; - - JSObject* obj = JS_DefineObject(m_cx, parent, "Message", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - - #define MESSAGE(name, vals) \ - JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)vals)-1, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - - #define COMMAND(name, merge, vals) \ - JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)vals)-1, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - - #define QUERY(name, in_vals, out_vals) \ - JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)in_vals)-1, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT); - - #undef INCLUDED_MESSAGES - - #include "GameInterface/Messages.h" - - #undef MESSAGE - #undef COMMAND - #undef QUERY -} diff --git a/source/tools/atlas/AtlasScript/ScriptInterface.h b/source/tools/atlas/AtlasScript/ScriptInterface.h deleted file mode 100644 index 7461425cfa..0000000000 --- a/source/tools/atlas/AtlasScript/ScriptInterface.h +++ /dev/null @@ -1,191 +0,0 @@ -/* Copyright (C) 2009 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#include -#include - -#ifdef _WIN32 -# define XP_WIN -# define WIN32 // SpiderMonkey expects this - -// The jsval struct type causes crashes due to weird miscompilation -// issues in (at least) VC2008, so force it to be the less-type-safe -// non-struct type instead -# define JS_NO_JSVAL_JSID_STRUCT_TYPES - -#else - -# define XP_UNIX - -// (See comment in scriptinterface/ScriptTypes.h) -# if defined(DEBUG) && defined(WITH_SYSTEM_MOZJS185) -# define JS_NO_JSVAL_JSID_STRUCT_TYPES -# endif - -#endif // (we don't support XP_OS2 or XP_BEOS) - -#ifdef __GNUC__ -# define GCC_VERSION (__GNUC__*100 + __GNUC_MINOR__) -#else -# define GCC_VERSION 0 -#endif - -#ifdef _MSC_VER -# define MSC_VERSION _MSC_VER -#else -# define MSC_VERSION 0 -#endif - -// Ignore some harmless warnings triggered by jsapi.h -#if GCC_VERSION >= 402 // (older GCCs don't support this pragma) -# pragma GCC diagnostic ignored "-Wunused-parameter" -# pragma GCC diagnostic ignored "-Wredundant-decls" -#endif -#if MSC_VERSION -# pragma warning(push) -# pragma warning(disable:4480) // "nonstandard extension used: specifying underlying type for enum" -# pragma warning(disable:4100) // "unreferenced formal parameter" -#endif - -#include "js/jsapi.h" - -#if MSC_VERSION -# pragma warning(pop) -#endif -#if GCC_VERSION >= 402 -# pragma GCC diagnostic warning "-Wunused-parameter" -# pragma GCC diagnostic warning "-Wredundant-decls" -#endif - -class wxString; - -namespace AtlasMessage { struct mWorldCommand; } -typedef void (*SubmitCommand)(AtlasMessage::mWorldCommand* command); - -struct AtlasScriptInterface_impl; -class ScriptInterface -{ -public: - ScriptInterface(SubmitCommand submitCommand); - ~ScriptInterface(); - void SetCallbackData(void* cbdata); - static void* GetCallbackData(JSContext* cx); - - template bool SetValue(const wxString& name, const T& val); - template bool GetValue(const wxString& name, T& ret); - - bool CallFunction(jsval val, const char* name); - template - bool CallFunction(jsval val, const char* name, const T& a, R& ret); - template - bool CallFunction(jsval val, const char* name, const T& a, const S& b, R& ret); - - bool Eval(const wxString& script); - template bool Eval(const wxString& script, T& ret); - - // Defined elsewhere: - // template - // void RegisterFunction(const char* functionName); - // (NOTE: The return type must be defined as a ToJSVal specialisation - // in ScriptInterface.cpp, else you'll end up with linker errors.) - - void LoadScript(const wxString& filename, const wxString& code); - - // Convert a jsval to a C++ type. (This might trigger GC.) - template static bool FromJSVal(JSContext* cx, jsval val, T& ret); - // Convert a C++ type to a jsval. (This might trigger GC. The return - // value must be rooted if you don't want it to be collected.) - template static jsval ToJSVal(JSContext* cx, const T& val); - - bool AddRoot(jsval* ptr); - bool RemoveRoot(jsval* ptr); - - JSContext* GetContext(); - -private: - bool SetValue_(const wxString& name, jsval val); - bool GetValue_(const wxString& name, jsval& ret); - bool CallFunction_(jsval val, const char* name, std::vector& args, jsval& ret); - bool Eval_(const wxString& name, jsval& ret); - - void Register(const char* name, JSNative fptr, size_t nargs); - std::auto_ptr m; - -// The nasty macro/template bits are split into a separate file so you don't have to look at them -#include "NativeWrapper.inl" - -template -bool ScriptInterface::SetValue(const wxString& name, const T& val) -{ - return SetValue_(name, ToJSVal(GetContext(), val)); -} - -template -bool ScriptInterface::GetValue(const wxString& name, T& ret) -{ - jsval jsRet; - if (! GetValue_(name, jsRet)) return false; - return FromJSVal(GetContext(), jsRet, ret); -} - -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, R& ret) -{ - jsval jsRet; - std::vector argv; - argv.push_back(ToJSVal(GetContext(), a)); - bool ok = CallFunction_(val, name, argv, jsRet); - if (! ok) return false; - return FromJSVal(GetContext(), jsRet, ret); -} - -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, const S& b, R& ret) -{ - jsval jsRet; - std::vector argv; - argv.push_back(ToJSVal(GetContext(), a)); - argv.push_back(ToJSVal(GetContext(), b)); - bool ok = CallFunction_(val, name, argv, jsRet); - if (! ok) return false; - return FromJSVal(GetContext(), jsRet, ret); -} - -template -bool ScriptInterface::Eval(const wxString& script, T& ret) -{ - jsval jsRet; - if (! Eval_(script, jsRet)) return false; - return FromJSVal(GetContext(), jsRet, ret); -} - -/** - * A trivial wrapper around a jsval. Used to avoid template overload ambiguities - * with jsval (which is just an integer), for any code that uses - * ScriptInterface::ToJSVal or ScriptInterface::FromJSVal - */ -class CScriptVal -{ -public: - CScriptVal() : m_Val(JSVAL_VOID) { } - CScriptVal(jsval val) : m_Val(val) { } - - jsval get() const { return m_Val; } - -private: - jsval m_Val; -}; diff --git a/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp b/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp index ff9b5fdb31..29134371d4 100644 --- a/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp +++ b/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp @@ -29,8 +29,6 @@ #include "GameInterface/MessagePasser.h" -#include "AtlasScript/ScriptInterface.h" - #include "wx/config.h" #include "wx/debugrpt.h" #include "wx/file.h" @@ -173,23 +171,9 @@ ATLASDLLIMPEXP void Atlas_ReportError() ///ReportError(); // janwas: disabled until ErrorReporter.cpp compiles } -void ScenarioEditorSubmitCommand(AtlasMessage::mWorldCommand* command) -{ - ScenarioEditor::GetCommandProc().Submit(new WorldCommand(command)); -} - class AtlasDLLApp : public wxApp { public: - AtlasDLLApp() - : m_ScriptInterface(NULL) - { - } - - ~AtlasDLLApp() - { - delete m_ScriptInterface; - } virtual bool OnInit() { @@ -242,8 +226,7 @@ public: } else if (g_InitialWindowType == _T("ScenarioEditor")) { - m_ScriptInterface = new ScriptInterface(&ScenarioEditorSubmitCommand); - frame = new ScenarioEditor(NULL, *m_ScriptInterface); + frame = new ScenarioEditor(NULL); } else { @@ -315,7 +298,6 @@ public: */ private: - ScriptInterface* m_ScriptInterface; bool OpenDirectory(const wxString& dir) { diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp index 57b4734e20..c46754a6a2 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp @@ -40,8 +40,6 @@ #include "GameInterface/MessagePasser.h" #include "GameInterface/Messages.h" -#include "AtlasScript/ScriptInterface.h" - #include "Misc/KeyMap.h" #include "Tools/Common/Tools.h" @@ -358,9 +356,9 @@ END_EVENT_TABLE() static AtlasWindowCommandProc g_CommandProc; AtlasWindowCommandProc& ScenarioEditor::GetCommandProc() { return g_CommandProc; } -ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterface) +ScenarioEditor::ScenarioEditor(wxWindow* parent) : wxFrame(parent, wxID_ANY, _T(""), wxDefaultPosition, wxSize(1024, 768)) -, m_FileHistory(_T("Scenario Editor")), m_ScriptInterface(scriptInterface) +, m_FileHistory(_T("Scenario Editor")) , m_ObjectSettings(g_SelectedObjects, AtlasMessage::eRenderView::GAME) , m_ToolManager(this) { diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h index c3a6b38c81..d978687852 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h @@ -27,12 +27,10 @@ #include "CustomControls/FileHistory/FileHistory.h" #include "SectionLayout.h" -class ScriptInterface; - class ScenarioEditor : public wxFrame { public: - ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterface); + ScenarioEditor(wxWindow* parent); void OnClose(wxCloseEvent& event); void OnTimer(wxTimerEvent& event); void OnIdle(wxIdleEvent& event); @@ -66,7 +64,6 @@ public: static float GetSpeedModifier(); - ScriptInterface& GetScriptInterface() const { return m_ScriptInterface; } Observable& GetObjectSettings() { return m_ObjectSettings; } Observable& GetMapSettings() { return m_MapSettings; } @@ -75,7 +72,6 @@ public: void SelectPage(const wxString& classname) { m_SectionLayout.SelectPage(classname); } private: - ScriptInterface& m_ScriptInterface; ToolManager m_ToolManager; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp index 54ead68284..451711a3a5 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp @@ -25,7 +25,6 @@ #include "CustomControls/SnapSplitterWindow/SnapSplitterWindow.h" #include "ScenarioEditor.h" -#include "AtlasScript/ScriptInterface.h" #include "Sections/Environment/Environment.h" #include "Sections/Map/Map.h" diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp index 55e1d17499..234b1d4776 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp @@ -20,7 +20,6 @@ #include "Map.h" #include "AtlasObject/AtlasObject.h" -#include "AtlasScript/ScriptInterface.h" #include "GameInterface/Messages.h" #include "ScenarioEditor/ScenarioEditor.h" #include "ScenarioEditor/Tools/Common/Tools.h" @@ -186,7 +185,7 @@ void MapSettingsControl::ReadFromEngine() if (!(*qry.settings).empty()) { // Prevent error if there's no map settings to parse - m_MapSettings = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qry.settings); + m_MapSettings = AtlasObject::LoadFromJSON(*qry.settings); } // map name @@ -275,7 +274,7 @@ void MapSettingsControl::SendToEngine() { UpdateSettingsObject(); - std::string json = AtlasObject::SaveToJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), m_MapSettings); + std::string json = AtlasObject::SaveToJSON(m_MapSettings); // TODO: would be nice if we supported undo for settings changes @@ -370,7 +369,7 @@ void MapSidebar::OnFirstDisplay() // Load the map sizes list AtlasMessage::qGetMapSizes qrySizes; qrySizes.Post(); - AtObj sizes = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qrySizes.sizes); + AtObj sizes = AtlasObject::LoadFromJSON(*qrySizes.sizes); wxChoice* sizeChoice = wxDynamicCast(FindWindow(ID_RandomSize), wxChoice); for (AtIter s = sizes["Sizes"]["item"]; s.defined(); ++s) { @@ -388,7 +387,7 @@ void MapSidebar::OnFirstDisplay() scriptChoice->Clear(); for (size_t i = 0; i < scripts.size(); ++i) { - AtObj data = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), scripts[i]); + AtObj data = AtlasObject::LoadFromJSON(scripts[i]); wxString name(data["settings"]["Name"]); scriptChoice->Append(name, new AtObjClientData(*data["settings"])); } @@ -528,7 +527,7 @@ void MapSidebar::OnRandomGenerate(wxCommandEvent& WXUNUSED(evt)) settings.setInt("Seed", wxAtoi(wxDynamicCast(FindWindow(ID_RandomSeed), wxTextCtrl)->GetValue())); - std::string json = AtlasObject::SaveToJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), settings); + std::string json = AtlasObject::SaveToJSON(settings); wxBusyInfo busy(_("Generating map")); wxBusyCursor busyc; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp index 640e3ba7c0..b29e8f2ef1 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp @@ -24,7 +24,6 @@ #include "ScenarioEditor/ScenarioEditor.h" #include "ScenarioEditor/Tools/Common/ObjectSettings.h" #include "ScenarioEditor/Tools/Common/MiscState.h" -#include "AtlasScript/ScriptInterface.h" #include "VariationControl.h" #include "GameInterface/Messages.h" @@ -479,7 +478,7 @@ void ObjectBottomBar::OnFirstDisplay() wxArrayString players; AtlasMessage::qGetPlayerDefaults qryPlayers; qryPlayers.Post(); - AtObj playerData = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qryPlayers.defaults); + AtObj playerData = AtlasObject::LoadFromJSON(*qryPlayers.defaults); AtObj playerDefs = *playerData["PlayerData"]; for (AtIter p = playerDefs["item"]; p.defined(); ++p) { diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp index 1d771f1398..d03f80a187 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp @@ -20,7 +20,6 @@ #include "Player.h" #include "AtlasObject/AtlasObject.h" -#include "AtlasScript/ScriptInterface.h" #include "CustomControls/ColourDialog/ColourDialog.h" #include "ScenarioEditor/ScenarioEditor.h" @@ -591,7 +590,7 @@ void PlayerSettingsControl::CreateWidgets() std::vector civData = *qryCiv.data; for (size_t i = 0; i < civData.size(); ++i) { - AtObj civ = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), civData[i]); + AtObj civ = AtlasObject::LoadFromJSON(civData[i]); civNames.Add(wxString(civ["Name"])); civCodes.Add(wxString(civ["Code"])); } @@ -600,7 +599,7 @@ void PlayerSettingsControl::CreateWidgets() ArrayOfAIData ais(AIData::CompareAIData); AtlasMessage::qGetAIData qryAI; qryAI.Post(); - AtObj aiData = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qryAI.data); + AtObj aiData = AtlasObject::LoadFromJSON(*qryAI.data); for (AtIter a = aiData["AIData"]["item"]; a.defined(); ++a) { ais.Add(new AIData(wxString(a["id"]), wxString(a["data"]["name"]))); @@ -646,7 +645,7 @@ void PlayerSettingsControl::LoadDefaults() { AtlasMessage::qGetPlayerDefaults qryPlayers; qryPlayers.Post(); - AtObj playerData = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qryPlayers.defaults); + AtObj playerData = AtlasObject::LoadFromJSON(*qryPlayers.defaults); m_PlayerDefaults = *playerData["PlayerData"]; } @@ -658,7 +657,7 @@ void PlayerSettingsControl::ReadFromEngine() if (!(*qry.settings).empty()) { // Prevent error if there's no map settings to parse - m_MapSettings = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qry.settings); + m_MapSettings = AtlasObject::LoadFromJSON(*qry.settings); } else { @@ -946,7 +945,7 @@ void PlayerSettingsControl::SendToEngine() { UpdateSettingsObject(); - std::string json = AtlasObject::SaveToJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), m_MapSettings); + std::string json = AtlasObject::SaveToJSON(m_MapSettings); // TODO: would be nice if we supported undo for settings changes diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp index f89ad9f3c4..8d9510ff53 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp @@ -23,7 +23,6 @@ #include "ScenarioEditor/ScenarioEditor.h" #include "ScenarioEditor/Tools/Common/Brushes.h" #include "ScenarioEditor/Tools/Common/MiscState.h" -#include "AtlasScript/ScriptInterface.h" #include "GameInterface/Messages.h" @@ -286,7 +285,7 @@ void TerrainSidebar::OnResizeMap(wxCommandEvent& WXUNUSED(evt)) // Load the map sizes list AtlasMessage::qGetMapSizes qrySizes; qrySizes.Post(); - AtObj sizes = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qrySizes.sizes); + AtObj sizes = AtlasObject::LoadFromJSON(*qrySizes.sizes); for (AtIter s = sizes["Sizes"]["item"]; s.defined(); ++s) { long tiles = 0;