Ticket #2434: RemoveAtlasScriptInterfaceDep_v1.1.diff
File RemoveAtlasScriptInterfaceDep_v1.1.diff, 111.1 KB (added by , 10 years ago) |
---|
-
build/premake/premake4.lua
1021 1021 1022 1022 setup_atlas_project("AtlasObject", "StaticLib", 1023 1023 { -- src 1024 "." 1024 ".", 1025 "../../../third_party/jsonspirit" 1026 1025 1027 },{ -- include 1028 "../../../third_party/jsonspirit" 1026 1029 },{ -- extern_libs 1027 1030 "boost", 1028 1031 "libxml2", 1029 "spidermonkey",1030 1032 "wxwidgets" 1031 1033 },{ -- extra_params 1032 1034 no_pch = 1 1033 1035 }) 1034 1036 1035 setup_atlas_project("AtlasScript", "StaticLib",1036 { -- src1037 "."1038 },{ -- include1039 ".."1040 },{ -- extern_libs1041 "boost",1042 "spidermonkey",1043 "valgrind",1044 "wxwidgets",1045 },{ -- extra_params1046 no_pch = 11047 })1048 1049 1037 atlas_src = { 1050 1038 "ActorEditor", 1051 1039 "CustomControls/Buttons", … … 1076 1064 "ScenarioEditor/Tools/Common", 1077 1065 } 1078 1066 atlas_extra_links = { 1079 "AtlasObject", 1080 "AtlasScript", 1067 "AtlasObject" 1081 1068 } 1082 1069 1083 1070 atlas_extern_libs = { … … 1087 1074 --"ffmpeg", -- disabled for now because it causes too many build difficulties 1088 1075 "libxml2", 1089 1076 "sdl", -- key definitions 1090 "spidermonkey",1091 1077 "wxwidgets", 1092 1078 "zlib", 1093 1079 } … … 1117 1103 1118 1104 local target_type = get_main_project_target_type() 1119 1105 project_create(project_name, target_type) 1120 project_add_extern_libs({1121 "spidermonkey",1122 },1123 target_type)1124 1106 project_add_x11_dirs() 1125 1107 1126 1108 local source_root = rootdir.."/source/tools/atlas/AtlasFrontends/" -
source/third_party/jsonspirit/LICENSE.txt
1 The MIT License 2 3 Copyright (c) 2007 - 2010 John W. Wilkinson 4 5 Permission is hereby granted, free of charge, to any person 6 obtaining a copy of this software and associated documentation 7 files (the "Software"), to deal in the Software without 8 restriction, including without limitation the rights to use, 9 copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the 11 Software is furnished to do so, subject to the following 12 conditions: 13 14 The above copyright notice and this permission notice shall be 15 included in all copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 OTHER DEALINGS IN THE SOFTWARE. -
source/third_party/jsonspirit/README.txt
1 This separate JSON library is used for Atlas to avoid the SpiderMonkey dependency. 2 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. 3 The SpiderMonkey API also changes frequently and we hope that the JSON parsing code needs less changes when we use this separate library. 4 5 Get the library from here: 6 http://www.codeproject.com/Articles/20027/JSON-Spirit-A-C-JSON-Parser-Generator-Implemented 7 8 The currently used version was released on the 23th of May 2013. -
source/third_party/jsonspirit/json_spirit_error_position.h
1 #ifndef JSON_SPIRIT_ERROR_POSITION 2 #define JSON_SPIRIT_ERROR_POSITION 3 4 // Copyright John W. Wilkinson 2007 - 2013 5 // Distributed under the MIT License, see accompanying file LICENSE.txt 6 7 // json spirit version 4.06 8 9 #if defined(_MSC_VER) && (_MSC_VER >= 1020) 10 # pragma once 11 #endif 12 13 #include <string> 14 15 namespace json_spirit 16 { 17 // An Error_position exception is thrown by the "read_or_throw" functions below on finding an error. 18 // Note the "read_or_throw" functions are around 3 times slower than the standard functions "read" 19 // functions that return a bool. 20 // 21 struct Error_position 22 { 23 Error_position(); 24 Error_position( unsigned int line, unsigned int column, const std::string& reason ); 25 bool operator==( const Error_position& lhs ) const; 26 unsigned int line_; 27 unsigned int column_; 28 std::string reason_; 29 }; 30 31 inline Error_position::Error_position() 32 : line_( 0 ) 33 , column_( 0 ) 34 { 35 } 36 37 inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason ) 38 : line_( line ) 39 , column_( column ) 40 , reason_( reason ) 41 { 42 } 43 44 inline bool Error_position::operator==( const Error_position& lhs ) const 45 { 46 if( this == &lhs ) return true; 47 48 return ( reason_ == lhs.reason_ ) && 49 ( line_ == lhs.line_ ) && 50 ( column_ == lhs.column_ ); 51 } 52 } 53 54 #endif -
source/third_party/jsonspirit/json_spirit_reader_template.h
1 #ifndef JSON_SPIRIT_READER_TEMPLATE 2 #define JSON_SPIRIT_READER_TEMPLATE 3 4 // Copyright John W. Wilkinson 2007 - 2013 5 // Distributed under the MIT License, see accompanying file LICENSE.txt 6 7 // json spirit version 4.06 8 9 #if defined(_MSC_VER) && (_MSC_VER >= 1020) 10 # pragma once 11 #endif 12 13 #include "json_spirit_value.h" 14 #include "json_spirit_error_position.h" 15 16 //#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread 17 18 #include <boost/bind.hpp> 19 #include <boost/function.hpp> 20 #include <boost/version.hpp> 21 22 #if BOOST_VERSION >= 103800 23 #include <boost/spirit/include/classic_core.hpp> 24 #include <boost/spirit/include/classic_confix.hpp> 25 #include <boost/spirit/include/classic_escape_char.hpp> 26 #include <boost/spirit/include/classic_multi_pass.hpp> 27 #include <boost/spirit/include/classic_position_iterator.hpp> 28 #define spirit_namespace boost::spirit::classic 29 #else 30 #include <boost/spirit/core.hpp> 31 #include <boost/spirit/utility/confix.hpp> 32 #include <boost/spirit/utility/escape_char.hpp> 33 #include <boost/spirit/iterator/multi_pass.hpp> 34 #include <boost/spirit/iterator/position_iterator.hpp> 35 #define spirit_namespace boost::spirit 36 #endif 37 38 namespace json_spirit 39 { 40 const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >(); 41 const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >(); 42 43 template< class Iter_type > 44 bool is_eq( Iter_type first, Iter_type last, const char* c_str ) 45 { 46 for( Iter_type i = first; i != last; ++i, ++c_str ) 47 { 48 if( *c_str == 0 ) return false; 49 50 if( *i != *c_str ) return false; 51 } 52 53 return true; 54 } 55 56 template< class Char_type > 57 Char_type hex_to_num( const Char_type c ) 58 { 59 if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0'; 60 if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10; 61 if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10; 62 return 0; 63 } 64 65 template< class Char_type, class Iter_type > 66 Char_type hex_str_to_char( Iter_type& begin ) 67 { 68 const Char_type c1( *( ++begin ) ); 69 const Char_type c2( *( ++begin ) ); 70 71 return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 ); 72 } 73 74 template< class Char_type, class Iter_type > 75 Char_type unicode_str_to_char( Iter_type& begin ) 76 { 77 const Char_type c1( *( ++begin ) ); 78 const Char_type c2( *( ++begin ) ); 79 const Char_type c3( *( ++begin ) ); 80 const Char_type c4( *( ++begin ) ); 81 82 return ( hex_to_num( c1 ) << 12 ) + 83 ( hex_to_num( c2 ) << 8 ) + 84 ( hex_to_num( c3 ) << 4 ) + 85 hex_to_num( c4 ); 86 } 87 88 template< class String_type > 89 void append_esc_char_and_incr_iter( String_type& s, 90 typename String_type::const_iterator& begin, 91 typename String_type::const_iterator end ) 92 { 93 typedef typename String_type::value_type Char_type; 94 95 const Char_type c2( *begin ); 96 97 switch( c2 ) 98 { 99 case 't': s += '\t'; break; 100 case 'b': s += '\b'; break; 101 case 'f': s += '\f'; break; 102 case 'n': s += '\n'; break; 103 case 'r': s += '\r'; break; 104 case '\\': s += '\\'; break; 105 case '/': s += '/'; break; 106 case '"': s += '"'; break; 107 case 'x': 108 { 109 if( end - begin >= 3 ) // expecting "xHH..." 110 { 111 s += hex_str_to_char< Char_type >( begin ); 112 } 113 break; 114 } 115 case 'u': 116 { 117 if( end - begin >= 5 ) // expecting "uHHHH..." 118 { 119 s += unicode_str_to_char< Char_type >( begin ); 120 } 121 break; 122 } 123 } 124 } 125 126 template< class String_type > 127 String_type substitute_esc_chars( typename String_type::const_iterator begin, 128 typename String_type::const_iterator end ) 129 { 130 typedef typename String_type::const_iterator Iter_type; 131 132 if( end - begin < 2 ) return String_type( begin, end ); 133 134 String_type result; 135 136 result.reserve( end - begin ); 137 138 const Iter_type end_minus_1( end - 1 ); 139 140 Iter_type substr_start = begin; 141 Iter_type i = begin; 142 143 for( ; i < end_minus_1; ++i ) 144 { 145 if( *i == '\\' ) 146 { 147 result.append( substr_start, i ); 148 149 ++i; // skip the '\' 150 151 append_esc_char_and_incr_iter( result, i, end ); 152 153 substr_start = i + 1; 154 } 155 } 156 157 result.append( substr_start, end ); 158 159 return result; 160 } 161 162 template< class String_type > 163 String_type get_str_( typename String_type::const_iterator begin, 164 typename String_type::const_iterator end ) 165 { 166 assert( end - begin >= 2 ); 167 168 typedef typename String_type::const_iterator Iter_type; 169 170 Iter_type str_without_quotes( ++begin ); 171 Iter_type end_without_quotes( --end ); 172 173 return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes ); 174 } 175 176 inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end ) 177 { 178 return get_str_< std::string >( begin, end ); 179 } 180 181 inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end ) 182 { 183 return get_str_< std::wstring >( begin, end ); 184 } 185 186 template< class String_type, class Iter_type > 187 String_type get_str( Iter_type begin, Iter_type end ) 188 { 189 const String_type tmp( begin, end ); // convert multipass iterators to string iterators 190 191 return get_str( tmp.begin(), tmp.end() ); 192 } 193 194 // this class's methods get called by the spirit parse resulting 195 // in the creation of a JSON object or array 196 // 197 // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator 198 // 199 template< class Value_type, class Iter_type > 200 class Semantic_actions 201 { 202 public: 203 204 typedef typename Value_type::Config_type Config_type; 205 typedef typename Config_type::String_type String_type; 206 typedef typename Config_type::Object_type Object_type; 207 typedef typename Config_type::Array_type Array_type; 208 typedef typename String_type::value_type Char_type; 209 210 Semantic_actions( Value_type& value ) 211 : value_( value ) 212 , current_p_( 0 ) 213 { 214 } 215 216 void begin_obj( Char_type c ) 217 { 218 assert( c == '{' ); 219 220 begin_compound< Object_type >(); 221 } 222 223 void end_obj( Char_type c ) 224 { 225 assert( c == '}' ); 226 227 end_compound(); 228 } 229 230 void begin_array( Char_type c ) 231 { 232 assert( c == '[' ); 233 234 begin_compound< Array_type >(); 235 } 236 237 void end_array( Char_type c ) 238 { 239 assert( c == ']' ); 240 241 end_compound(); 242 } 243 244 void new_name( Iter_type begin, Iter_type end ) 245 { 246 assert( current_p_->type() == obj_type ); 247 248 name_ = get_str< String_type >( begin, end ); 249 } 250 251 void new_str( Iter_type begin, Iter_type end ) 252 { 253 add_to_current( get_str< String_type >( begin, end ) ); 254 } 255 256 void new_true( Iter_type begin, Iter_type end ) 257 { 258 assert( is_eq( begin, end, "true" ) ); 259 260 add_to_current( true ); 261 } 262 263 void new_false( Iter_type begin, Iter_type end ) 264 { 265 assert( is_eq( begin, end, "false" ) ); 266 267 add_to_current( false ); 268 } 269 270 void new_null( Iter_type begin, Iter_type end ) 271 { 272 assert( is_eq( begin, end, "null" ) ); 273 274 add_to_current( Value_type() ); 275 } 276 277 void new_int( boost::int64_t i ) 278 { 279 add_to_current( i ); 280 } 281 282 void new_uint64( boost::uint64_t ui ) 283 { 284 add_to_current( ui ); 285 } 286 287 void new_real( double d ) 288 { 289 add_to_current( d ); 290 } 291 292 private: 293 294 Semantic_actions& operator=( const Semantic_actions& ); 295 // to prevent "assignment operator could not be generated" warning 296 297 Value_type* add_first( const Value_type& value ) 298 { 299 assert( current_p_ == 0 ); 300 301 value_ = value; 302 current_p_ = &value_; 303 return current_p_; 304 } 305 306 template< class Array_or_obj > 307 void begin_compound() 308 { 309 if( current_p_ == 0 ) 310 { 311 add_first( Array_or_obj() ); 312 } 313 else 314 { 315 stack_.push_back( current_p_ ); 316 317 Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place 318 319 current_p_ = add_to_current( new_array_or_obj ); 320 } 321 } 322 323 void end_compound() 324 { 325 if( current_p_ != &value_ ) 326 { 327 current_p_ = stack_.back(); 328 329 stack_.pop_back(); 330 } 331 } 332 333 Value_type* add_to_current( const Value_type& value ) 334 { 335 if( current_p_ == 0 ) 336 { 337 return add_first( value ); 338 } 339 else if( current_p_->type() == array_type ) 340 { 341 current_p_->get_array().push_back( value ); 342 343 return ¤t_p_->get_array().back(); 344 } 345 346 assert( current_p_->type() == obj_type ); 347 348 return &Config_type::add( current_p_->get_obj(), name_, value ); 349 } 350 351 Value_type& value_; // this is the object or array that is being created 352 Value_type* current_p_; // the child object or array that is currently being constructed 353 354 std::vector< Value_type* > stack_; // previous child objects and arrays 355 356 String_type name_; // of current name/value pair 357 }; 358 359 template< typename Iter_type > 360 void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason ) 361 { 362 throw Error_position( i.get_position().line, i.get_position().column, reason ); 363 } 364 365 template< typename Iter_type > 366 void throw_error( Iter_type i, const std::string& reason ) 367 { 368 throw reason; 369 } 370 371 // the spirit grammer 372 // 373 template< class Value_type, class Iter_type > 374 class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > > 375 { 376 public: 377 378 typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t; 379 380 Json_grammer( Semantic_actions_t& semantic_actions ) 381 : actions_( semantic_actions ) 382 { 383 } 384 385 static void throw_not_value( Iter_type begin, Iter_type end ) 386 { 387 throw_error( begin, "not a value" ); 388 } 389 390 static void throw_not_array( Iter_type begin, Iter_type end ) 391 { 392 throw_error( begin, "not an array" ); 393 } 394 395 static void throw_not_object( Iter_type begin, Iter_type end ) 396 { 397 throw_error( begin, "not an object" ); 398 } 399 400 static void throw_not_pair( Iter_type begin, Iter_type end ) 401 { 402 throw_error( begin, "not a pair" ); 403 } 404 405 static void throw_not_colon( Iter_type begin, Iter_type end ) 406 { 407 throw_error( begin, "no colon in pair" ); 408 } 409 410 static void throw_not_string( Iter_type begin, Iter_type end ) 411 { 412 throw_error( begin, "not a string" ); 413 } 414 415 template< typename ScannerT > 416 class definition 417 { 418 public: 419 420 definition( const Json_grammer& self ) 421 { 422 using namespace spirit_namespace; 423 424 typedef typename Value_type::String_type::value_type Char_type; 425 426 // first we convert the semantic action class methods to functors with the 427 // parameter signature expected by spirit 428 429 typedef boost::function< void( Char_type ) > Char_action; 430 typedef boost::function< void( Iter_type, Iter_type ) > Str_action; 431 typedef boost::function< void( double ) > Real_action; 432 typedef boost::function< void( boost::int64_t ) > Int_action; 433 typedef boost::function< void( boost::uint64_t ) > Uint64_action; 434 435 Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) ); 436 Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) ); 437 Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) ); 438 Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) ); 439 Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) ); 440 Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) ); 441 Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) ); 442 Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) ); 443 Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) ); 444 Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) ); 445 Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) ); 446 Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) ); 447 448 // actual grammer 449 450 json_ 451 = value_ | eps_p[ &throw_not_value ] 452 ; 453 454 value_ 455 = string_[ new_str ] 456 | number_ 457 | object_ 458 | array_ 459 | str_p( "true" ) [ new_true ] 460 | str_p( "false" )[ new_false ] 461 | str_p( "null" ) [ new_null ] 462 ; 463 464 object_ 465 = ch_p('{')[ begin_obj ] 466 >> !members_ 467 >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] ) 468 ; 469 470 members_ 471 = pair_ >> *( ',' >> pair_ ) 472 ; 473 474 pair_ 475 = string_[ new_name ] 476 >> ( ':' | eps_p[ &throw_not_colon ] ) 477 >> ( value_ | eps_p[ &throw_not_value ] ) 478 ; 479 480 array_ 481 = ch_p('[')[ begin_array ] 482 >> !elements_ 483 >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] ) 484 ; 485 486 elements_ 487 = value_ >> *( ',' >> value_ ) 488 ; 489 490 string_ 491 = lexeme_d // this causes white space and what would appear to be comments inside a string to be retained 492 [ 493 confix_p 494 ( 495 '"', 496 *lex_escape_ch_p, 497 '"' 498 ) 499 ] 500 ; 501 502 number_ 503 = strict_real_p[ new_real ] 504 | int64_p [ new_int ] 505 | uint64_p [ new_uint64 ] 506 ; 507 } 508 509 spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_; 510 511 const spirit_namespace::rule< ScannerT >& start() const { return json_; } 512 }; 513 514 private: 515 516 Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning 517 518 Semantic_actions_t& actions_; 519 }; 520 521 template< class Iter_type, class Value_type > 522 void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) 523 { 524 typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; 525 526 const Posn_iter_t posn_begin( begin, end ); 527 const Posn_iter_t posn_end( end, end ); 528 529 read_range_or_throw( posn_begin, posn_end, value ); 530 } 531 532 template< class Istream_type > 533 struct Multi_pass_iters 534 { 535 typedef typename Istream_type::char_type Char_type; 536 typedef std::istream_iterator< Char_type, Char_type > istream_iter; 537 typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; 538 539 Multi_pass_iters( Istream_type& is ) 540 { 541 is.unsetf( std::ios::skipws ); 542 543 begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); 544 end_ = spirit_namespace::make_multi_pass( istream_iter() ); 545 } 546 547 Mp_iter begin_; 548 Mp_iter end_; 549 }; 550 551 // reads a JSON Value from a pair of input iterators throwing an exception on invalid input, e.g. 552 // 553 // string::const_iterator start = str.begin(); 554 // const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), value ); 555 // 556 // The iterator 'next' will point to the character past the 557 // last one read. 558 // 559 template< class Iter_type, class Value_type > 560 Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) 561 { 562 Semantic_actions< Value_type, Iter_type > semantic_actions( value ); 563 564 const spirit_namespace::parse_info< Iter_type > info = 565 spirit_namespace::parse( begin, end, 566 Json_grammer< Value_type, Iter_type >( semantic_actions ), 567 spirit_namespace::space_p | 568 spirit_namespace::comment_p("//") | 569 spirit_namespace::comment_p("/*", "*/") ); 570 571 if( !info.hit ) 572 { 573 assert( false ); // in theory exception should already have been thrown 574 throw_error( info.stop, "error" ); 575 } 576 577 return info.stop; 578 } 579 580 // reads a JSON Value from a pair of input iterators, e.g. 581 // 582 // string::const_iterator start = str.begin(); 583 // const bool success = read_string( start, str.end(), value ); 584 // 585 // The iterator 'start' will point to the character past the 586 // last one read. 587 // 588 template< class Iter_type, class Value_type > 589 bool read_range( Iter_type& begin, Iter_type end, Value_type& value ) 590 { 591 try 592 { 593 begin = read_range_or_throw( begin, end, value ); 594 595 return true; 596 } 597 catch( ... ) 598 { 599 return false; 600 } 601 } 602 603 // reads a JSON Value from a string, e.g. 604 // 605 // const bool success = read_string( str, value ); 606 // 607 template< class String_type, class Value_type > 608 bool read_string( const String_type& s, Value_type& value ) 609 { 610 typename String_type::const_iterator begin = s.begin(); 611 612 return read_range( begin, s.end(), value ); 613 } 614 615 // reads a JSON Value from a string throwing an exception on invalid input, e.g. 616 // 617 // read_string_or_throw( is, value ); 618 // 619 template< class String_type, class Value_type > 620 void read_string_or_throw( const String_type& s, Value_type& value ) 621 { 622 add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); 623 } 624 625 // reads a JSON Value from a stream, e.g. 626 // 627 // const bool success = read_stream( is, value ); 628 // 629 template< class Istream_type, class Value_type > 630 bool read_stream( Istream_type& is, Value_type& value ) 631 { 632 Multi_pass_iters< Istream_type > mp_iters( is ); 633 634 return read_range( mp_iters.begin_, mp_iters.end_, value ); 635 } 636 637 // reads a JSON Value from a stream throwing an exception on invalid input, e.g. 638 // 639 // read_stream_or_throw( is, value ); 640 // 641 template< class Istream_type, class Value_type > 642 void read_stream_or_throw( Istream_type& is, Value_type& value ) 643 { 644 const Multi_pass_iters< Istream_type > mp_iters( is ); 645 646 add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value ); 647 } 648 } 649 650 #endif -
source/third_party/jsonspirit/json_spirit_value.h
1 #ifndef JSON_SPIRIT_VALUE 2 #define JSON_SPIRIT_VALUE 3 4 // Copyright John W. Wilkinson 2007 - 2013 5 // Distributed under the MIT License, see accompanying file LICENSE.txt 6 7 // json spirit version 4.06 8 9 #if defined(_MSC_VER) && (_MSC_VER >= 1020) 10 # pragma once 11 #endif 12 13 #include <vector> 14 #include <map> 15 #include <string> 16 #include <cassert> 17 #include <sstream> 18 #include <stdexcept> 19 #include <boost/config.hpp> 20 #include <boost/cstdint.hpp> 21 #include <boost/shared_ptr.hpp> 22 #include <boost/variant.hpp> 23 24 // comment out the value types you don't need to reduce build times and intermediate file sizes 25 #define JSON_SPIRIT_VALUE_ENABLED 26 #define JSON_SPIRIT_WVALUE_ENABLED 27 #define JSON_SPIRIT_MVALUE_ENABLED 28 #define JSON_SPIRIT_WMVALUE_ENABLED 29 30 namespace json_spirit 31 { 32 enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; 33 34 static std::string value_type_to_string( Value_type vtype ); 35 36 struct Null{}; 37 38 template< class Config > // Config determines whether the value uses std::string or std::wstring and 39 // whether JSON Objects are represented as vectors or maps 40 class Value_impl 41 { 42 public: 43 44 typedef Config Config_type; 45 typedef typename Config::String_type String_type; 46 typedef typename Config::Object_type Object; 47 typedef typename Config::Array_type Array; 48 typedef typename String_type::const_pointer Const_str_ptr; // eg const char* 49 50 Value_impl(); // creates null value 51 Value_impl( Const_str_ptr value ); 52 Value_impl( const String_type& value ); 53 Value_impl( const Object& value ); 54 Value_impl( const Array& value ); 55 Value_impl( bool value ); 56 Value_impl( int value ); 57 Value_impl( boost::int64_t value ); 58 Value_impl( boost::uint64_t value ); 59 Value_impl( double value ); 60 61 template< class Iter > 62 Value_impl( Iter first, Iter last ); // constructor from containers, e.g. std::vector or std::list 63 64 template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > 65 Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ); // constructor for compatible variant types 66 67 Value_impl( const Value_impl& other ); 68 69 bool operator==( const Value_impl& lhs ) const; 70 71 Value_impl& operator=( const Value_impl& lhs ); 72 73 Value_type type() const; 74 75 bool is_uint64() const; 76 bool is_null() const; 77 78 const String_type& get_str() const; 79 const Object& get_obj() const; 80 const Array& get_array() const; 81 bool get_bool() const; 82 int get_int() const; 83 boost::int64_t get_int64() const; 84 boost::uint64_t get_uint64() const; 85 double get_real() const; 86 87 Object& get_obj(); 88 Array& get_array(); 89 90 template< typename T > T get_value() const; // example usage: int i = value.get_value< int >(); 91 // or double d = value.get_value< double >(); 92 93 static const Value_impl null; 94 95 private: 96 97 void check_type( const Value_type vtype ) const; 98 99 typedef boost::variant< boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, 100 String_type, bool, boost::int64_t, double, Null, boost::uint64_t > Variant; 101 102 Variant v_; 103 104 class Variant_converter_visitor : public boost::static_visitor< Variant > 105 { 106 public: 107 108 template< typename T, typename A, template< typename, typename > class Cont > 109 Variant operator()( const Cont< T, A >& cont ) const 110 { 111 return Array( cont.begin(), cont.end() ); 112 } 113 114 Variant operator()( int i ) const 115 { 116 return static_cast< boost::int64_t >( i ); 117 } 118 119 template<class T> 120 Variant operator()( const T& t ) const 121 { 122 return t; 123 } 124 }; 125 }; 126 127 // vector objects 128 129 template< class Config > 130 struct Pair_impl 131 { 132 typedef typename Config::String_type String_type; 133 typedef typename Config::Value_type Value_type; 134 135 Pair_impl() 136 { 137 } 138 139 Pair_impl( const String_type& name, const Value_type& value ); 140 141 bool operator==( const Pair_impl& lhs ) const; 142 143 String_type name_; 144 Value_type value_; 145 }; 146 147 #if defined( JSON_SPIRIT_VALUE_ENABLED ) || defined( JSON_SPIRIT_WVALUE_ENABLED ) 148 template< class String > 149 struct Config_vector 150 { 151 typedef String String_type; 152 typedef Value_impl< Config_vector > Value_type; 153 typedef Pair_impl < Config_vector > Pair_type; 154 typedef std::vector< Value_type > Array_type; 155 typedef std::vector< Pair_type > Object_type; 156 157 static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) 158 { 159 obj.push_back( Pair_type( name , value ) ); 160 161 return obj.back().value_; 162 } 163 164 static const String_type& get_name( const Pair_type& pair ) 165 { 166 return pair.name_; 167 } 168 169 static const Value_type& get_value( const Pair_type& pair ) 170 { 171 return pair.value_; 172 } 173 }; 174 #endif 175 176 // typedefs for ASCII 177 178 #ifdef JSON_SPIRIT_VALUE_ENABLED 179 typedef Config_vector< std::string > Config; 180 181 typedef Config::Value_type Value; 182 typedef Config::Pair_type Pair; 183 typedef Config::Object_type Object; 184 typedef Config::Array_type Array; 185 #endif 186 187 // typedefs for Unicode 188 189 #if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) 190 typedef Config_vector< std::wstring > wConfig; 191 192 typedef wConfig::Value_type wValue; 193 typedef wConfig::Pair_type wPair; 194 typedef wConfig::Object_type wObject; 195 typedef wConfig::Array_type wArray; 196 #endif 197 198 // map objects 199 200 #if defined( JSON_SPIRIT_MVALUE_ENABLED ) || defined( JSON_SPIRIT_WMVALUE_ENABLED ) 201 template< class String > 202 struct Config_map 203 { 204 typedef String String_type; 205 typedef Value_impl< Config_map > Value_type; 206 typedef std::vector< Value_type > Array_type; 207 typedef std::map< String_type, Value_type > Object_type; 208 typedef std::pair< const String_type, Value_type > Pair_type; 209 210 static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) 211 { 212 return obj[ name ] = value; 213 } 214 215 static const String_type& get_name( const Pair_type& pair ) 216 { 217 return pair.first; 218 } 219 220 static const Value_type& get_value( const Pair_type& pair ) 221 { 222 return pair.second; 223 } 224 }; 225 #endif 226 227 // typedefs for ASCII 228 229 #ifdef JSON_SPIRIT_MVALUE_ENABLED 230 typedef Config_map< std::string > mConfig; 231 232 typedef mConfig::Value_type mValue; 233 typedef mConfig::Object_type mObject; 234 typedef mConfig::Array_type mArray; 235 #endif 236 237 // typedefs for Unicode 238 239 #if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) 240 typedef Config_map< std::wstring > wmConfig; 241 242 typedef wmConfig::Value_type wmValue; 243 typedef wmConfig::Object_type wmObject; 244 typedef wmConfig::Array_type wmArray; 245 #endif 246 247 /////////////////////////////////////////////////////////////////////////////////////////////// 248 // 249 // implementation 250 251 inline bool operator==( const Null&, const Null& ) 252 { 253 return true; 254 } 255 256 template< class Config > 257 const Value_impl< Config > Value_impl< Config >::null; 258 259 template< class Config > 260 Value_impl< Config >::Value_impl() 261 : v_( Null() ) 262 { 263 } 264 265 template< class Config > 266 Value_impl< Config >::Value_impl( const Const_str_ptr value ) 267 : v_( String_type( value ) ) 268 { 269 } 270 271 template< class Config > 272 Value_impl< Config >::Value_impl( const String_type& value ) 273 : v_( value ) 274 { 275 } 276 277 template< class Config > 278 Value_impl< Config >::Value_impl( const Object& value ) 279 : v_( value ) 280 { 281 } 282 283 template< class Config > 284 Value_impl< Config >::Value_impl( const Array& value ) 285 : v_( value ) 286 { 287 } 288 289 template< class Config > 290 Value_impl< Config >::Value_impl( bool value ) 291 : v_( value ) 292 { 293 } 294 295 template< class Config > 296 Value_impl< Config >::Value_impl( int value ) 297 : v_( static_cast< boost::int64_t >( value ) ) 298 { 299 } 300 301 template< class Config > 302 Value_impl< Config >::Value_impl( boost::int64_t value ) 303 : v_( value ) 304 { 305 } 306 307 template< class Config > 308 Value_impl< Config >::Value_impl( boost::uint64_t value ) 309 : v_( value ) 310 { 311 } 312 313 template< class Config > 314 Value_impl< Config >::Value_impl( double value ) 315 : v_( value ) 316 { 317 } 318 319 template< class Config > 320 Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) 321 : v_( other.v_ ) 322 { 323 } 324 325 template< class Config > 326 template< class Iter > 327 Value_impl< Config >::Value_impl( Iter first, Iter last ) 328 : v_( Array( first, last ) ) 329 { 330 } 331 332 template< class Config > 333 template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > 334 Value_impl< Config >::Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ) 335 : v_( boost::apply_visitor( Variant_converter_visitor(), variant) ) 336 { 337 } 338 339 template< class Config > 340 Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs ) 341 { 342 Value_impl tmp( lhs ); 343 344 std::swap( v_, tmp.v_ ); 345 346 return *this; 347 } 348 349 template< class Config > 350 bool Value_impl< Config >::operator==( const Value_impl& lhs ) const 351 { 352 if( this == &lhs ) return true; 353 354 if( type() != lhs.type() ) return false; 355 356 return v_ == lhs.v_; 357 } 358 359 template< class Config > 360 Value_type Value_impl< Config >::type() const 361 { 362 if( is_uint64() ) 363 { 364 return int_type; 365 } 366 367 return static_cast< Value_type >( v_.which() ); 368 } 369 370 template< class Config > 371 bool Value_impl< Config >::is_uint64() const 372 { 373 return v_.which() == null_type + 1; 374 } 375 376 template< class Config > 377 bool Value_impl< Config >::is_null() const 378 { 379 return type() == null_type; 380 } 381 382 template< class Config > 383 void Value_impl< Config >::check_type( const Value_type vtype ) const 384 { 385 if( type() != vtype ) 386 { 387 std::ostringstream os; 388 389 os << "get_value< " << value_type_to_string( vtype ) << " > called on " << value_type_to_string( type() ) << " Value"; 390 391 throw std::runtime_error( os.str() ); 392 } 393 } 394 395 template< class Config > 396 const typename Config::String_type& Value_impl< Config >::get_str() const 397 { 398 check_type( str_type ); 399 400 return *boost::get< String_type >( &v_ ); 401 } 402 403 template< class Config > 404 const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const 405 { 406 check_type( obj_type ); 407 408 return *boost::get< Object >( &v_ ); 409 } 410 411 template< class Config > 412 const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const 413 { 414 check_type( array_type ); 415 416 return *boost::get< Array >( &v_ ); 417 } 418 419 template< class Config > 420 bool Value_impl< Config >::get_bool() const 421 { 422 check_type( bool_type ); 423 424 return boost::get< bool >( v_ ); 425 } 426 427 template< class Config > 428 int Value_impl< Config >::get_int() const 429 { 430 check_type( int_type ); 431 432 return static_cast< int >( get_int64() ); 433 } 434 435 template< class Config > 436 boost::int64_t Value_impl< Config >::get_int64() const 437 { 438 check_type( int_type ); 439 440 if( is_uint64() ) 441 { 442 return static_cast< boost::int64_t >( get_uint64() ); 443 } 444 445 return boost::get< boost::int64_t >( v_ ); 446 } 447 448 template< class Config > 449 boost::uint64_t Value_impl< Config >::get_uint64() const 450 { 451 check_type( int_type ); 452 453 if( !is_uint64() ) 454 { 455 return static_cast< boost::uint64_t >( get_int64() ); 456 } 457 458 return boost::get< boost::uint64_t >( v_ ); 459 } 460 461 template< class Config > 462 double Value_impl< Config >::get_real() const 463 { 464 if( type() == int_type ) 465 { 466 return is_uint64() ? static_cast< double >( get_uint64() ) 467 : static_cast< double >( get_int64() ); 468 } 469 470 check_type( real_type ); 471 472 return boost::get< double >( v_ ); 473 } 474 475 template< class Config > 476 typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() 477 { 478 check_type( obj_type ); 479 480 return *boost::get< Object >( &v_ ); 481 } 482 483 template< class Config > 484 typename Value_impl< Config >::Array& Value_impl< Config >::get_array() 485 { 486 check_type( array_type ); 487 488 return *boost::get< Array >( &v_ ); 489 } 490 491 template< class Config > 492 Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value ) 493 : name_( name ) 494 , value_( value ) 495 { 496 } 497 498 template< class Config > 499 bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const 500 { 501 if( this == &lhs ) return true; 502 503 return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ ); 504 } 505 506 // converts a C string, ie. 8 bit char array, to a string object 507 // 508 template < class String_type > 509 String_type to_str( const char* c_str ) 510 { 511 String_type result; 512 513 for( const char* p = c_str; *p != 0; ++p ) 514 { 515 result += *p; 516 } 517 518 return result; 519 } 520 521 // 522 523 namespace internal_ 524 { 525 template< typename T > 526 struct Type_to_type 527 { 528 }; 529 530 template< class Value > 531 int get_value( const Value& value, Type_to_type< int > ) 532 { 533 return value.get_int(); 534 } 535 536 template< class Value > 537 boost::int64_t get_value( const Value& value, Type_to_type< boost::int64_t > ) 538 { 539 return value.get_int64(); 540 } 541 542 template< class Value > 543 boost::uint64_t get_value( const Value& value, Type_to_type< boost::uint64_t > ) 544 { 545 return value.get_uint64(); 546 } 547 548 template< class Value > 549 double get_value( const Value& value, Type_to_type< double > ) 550 { 551 return value.get_real(); 552 } 553 554 template< class Value > 555 typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > ) 556 { 557 return value.get_str(); 558 } 559 560 template< class Value > 561 typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > ) 562 { 563 return value.get_array(); 564 } 565 566 template< class Value > 567 typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > ) 568 { 569 return value.get_obj(); 570 } 571 572 template< class Value > 573 bool get_value( const Value& value, Type_to_type< bool > ) 574 { 575 return value.get_bool(); 576 } 577 } 578 579 template< class Config > 580 template< typename T > 581 T Value_impl< Config >::get_value() const 582 { 583 return internal_::get_value( *this, internal_::Type_to_type< T >() ); 584 } 585 586 static std::string value_type_to_string( const Value_type vtype ) 587 { 588 switch( vtype ) 589 { 590 case obj_type: return "Object"; 591 case array_type: return "Array"; 592 case str_type: return "string"; 593 case bool_type: return "boolean"; 594 case int_type: return "integer"; 595 case real_type: return "real"; 596 case null_type: return "null"; 597 } 598 599 assert( false ); 600 601 return "unknown type"; 602 } 603 } 604 605 #endif -
source/third_party/jsonspirit/json_spirit_writer_options.h
1 #ifndef JSON_SPIRIT_WRITER_OPTIONS 2 #define JSON_SPIRIT_WRITER_OPTIONS 3 4 // Copyright John W. Wilkinson 2007 - 2013 5 // Distributed under the MIT License, see accompanying file LICENSE.txt 6 7 // json spirit version 4.06 8 9 #if defined(_MSC_VER) && (_MSC_VER >= 1020) 10 # pragma once 11 #endif 12 13 namespace json_spirit 14 { 15 enum Output_options{ pretty_print = 0x01, // Add whitespace to format the output nicely. 16 17 raw_utf8 = 0x02, // This prevents non-printable characters from being escapted using "\uNNNN" notation. 18 // Note, this is an extension to the JSON standard. It disables the escaping of 19 // non-printable characters allowing UTF-8 sequences held in 8 bit char strings 20 // to pass through unaltered. 21 22 remove_trailing_zeros = 0x04, 23 // outputs e.g. "1.200000000000000" as "1.2" 24 single_line_arrays = 0x08, 25 // pretty printing except that arrays printed on single lines unless they contain 26 // composite elements, i.e. objects or arrays 27 always_escape_nonascii = 0x10, 28 // all unicode wide characters are escaped, i.e. outputed as "\uXXXX", even if they are 29 // printable under the current locale, ascii printable chars are not escaped 30 }; 31 } 32 33 #endif -
source/third_party/jsonspirit/json_spirit_writer_template.h
1 #ifndef JSON_SPIRIT_WRITER_TEMPLATE 2 #define JSON_SPIRIT_WRITER_TEMPLATE 3 4 // Copyright John W. Wilkinson 2007 - 2013 5 // Distributed under the MIT License, see accompanying file LICENSE.txt 6 7 // json spirit version 4.06 8 9 #if defined(_MSC_VER) && (_MSC_VER >= 1020) 10 # pragma once 11 #endif 12 13 #include "json_spirit_value.h" 14 #include "json_spirit_writer_options.h" 15 16 #include <cassert> 17 #include <sstream> 18 #include <iomanip> 19 #include <boost/io/ios_state.hpp> 20 21 namespace json_spirit 22 { 23 inline char to_hex_char( unsigned int c ) 24 { 25 assert( c <= 0xF ); 26 27 const char ch = static_cast< char >( c ); 28 29 if( ch < 10 ) return '0' + ch; 30 31 return 'A' - 10 + ch; 32 } 33 34 template< class String_type > 35 String_type non_printable_to_string( unsigned int c ) 36 { 37 typedef typename String_type::value_type Char_type; 38 39 String_type result( 6, '\\' ); 40 41 result[1] = 'u'; 42 43 result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4; 44 result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4; 45 result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4; 46 result[ 2 ] = to_hex_char( c & 0x000F ); 47 48 return result; 49 } 50 51 template< typename Char_type, class String_type > 52 bool add_esc_char( Char_type c, String_type& s ) 53 { 54 switch( c ) 55 { 56 case '"': s += to_str< String_type >( "\\\"" ); return true; 57 case '\\': s += to_str< String_type >( "\\\\" ); return true; 58 case '\b': s += to_str< String_type >( "\\b" ); return true; 59 case '\f': s += to_str< String_type >( "\\f" ); return true; 60 case '\n': s += to_str< String_type >( "\\n" ); return true; 61 case '\r': s += to_str< String_type >( "\\r" ); return true; 62 case '\t': s += to_str< String_type >( "\\t" ); return true; 63 } 64 65 return false; 66 } 67 68 template< class String_type > 69 String_type add_esc_chars( const String_type& s, bool raw_utf8, bool esc_nonascii ) 70 { 71 typedef typename String_type::const_iterator Iter_type; 72 typedef typename String_type::value_type Char_type; 73 74 String_type result; 75 76 const Iter_type end( s.end() ); 77 78 for( Iter_type i = s.begin(); i != end; ++i ) 79 { 80 const Char_type c( *i ); 81 82 if( add_esc_char( c, result ) ) continue; 83 84 if( raw_utf8 ) 85 { 86 result += c; 87 } 88 else 89 { 90 const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); 91 92 if( !esc_nonascii && iswprint( unsigned_c ) ) 93 { 94 result += c; 95 } 96 else 97 { 98 result += non_printable_to_string< String_type >( unsigned_c ); 99 } 100 } 101 } 102 103 return result; 104 } 105 106 template< class Ostream > 107 void append_double( Ostream& os, const double d, const int precision ) 108 { 109 os << std::showpoint << std::setprecision( precision ) << d; 110 } 111 112 template< class String_type > 113 void erase_and_extract_exponent( String_type& str, String_type& exp ) 114 { 115 const typename String_type::size_type exp_start= str.find( 'e' ); 116 117 if( exp_start != String_type::npos ) 118 { 119 exp = str.substr( exp_start ); 120 str.erase( exp_start ); 121 } 122 } 123 124 template< class String_type > 125 typename String_type::size_type find_first_non_zero( const String_type& str ) 126 { 127 typename String_type::size_type result = str.size() - 1; 128 129 for( ; result != 0; --result ) 130 { 131 if( str[ result ] != '0' ) 132 { 133 break; 134 } 135 } 136 137 return result; 138 } 139 140 template< class String_type > 141 void remove_trailing( String_type& str ) 142 { 143 String_type exp; 144 145 erase_and_extract_exponent( str, exp ); 146 147 const typename String_type::size_type first_non_zero = find_first_non_zero( str ); 148 149 if( first_non_zero != 0 ) 150 { 151 const int offset = str[first_non_zero] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard 152 str.erase( first_non_zero + offset ); 153 } 154 155 str += exp; 156 } 157 158 // this class generates the JSON text, 159 // it keeps track of the indentation level etc. 160 // 161 template< class Value_type, class Ostream_type > 162 class Generator 163 { 164 typedef typename Value_type::Config_type Config_type; 165 typedef typename Config_type::String_type String_type; 166 typedef typename Config_type::Object_type Object_type; 167 typedef typename Config_type::Array_type Array_type; 168 typedef typename String_type::value_type Char_type; 169 typedef typename Object_type::value_type Obj_member_type; 170 171 public: 172 173 Generator( const Value_type& value, Ostream_type& os, unsigned int options ) 174 : os_( os ) 175 , indentation_level_( 0 ) 176 , pretty_( ( options & pretty_print ) != 0 || ( options & single_line_arrays ) != 0 ) 177 , raw_utf8_( ( options & raw_utf8 ) != 0 ) 178 , esc_nonascii_( ( options & always_escape_nonascii ) != 0 ) 179 , remove_trailing_zeros_( ( options & remove_trailing_zeros ) != 0 ) 180 , single_line_arrays_( ( options & single_line_arrays ) != 0 ) 181 , ios_saver_( os ) 182 { 183 output( value ); 184 } 185 186 private: 187 188 void output( const Value_type& value ) 189 { 190 switch( value.type() ) 191 { 192 case obj_type: output( value.get_obj() ); break; 193 case array_type: output( value.get_array() ); break; 194 case str_type: output( value.get_str() ); break; 195 case bool_type: output( value.get_bool() ); break; 196 case real_type: output( value.get_real() ); break; 197 case int_type: output_int( value ); break; 198 case null_type: os_ << "null"; break; 199 default: assert( false ); 200 } 201 } 202 203 void output( const Object_type& obj ) 204 { 205 output_array_or_obj( obj, '{', '}' ); 206 } 207 208 void output( const Obj_member_type& member ) 209 { 210 output( Config_type::get_name( member ) ); space(); 211 os_ << ':'; space(); 212 output( Config_type::get_value( member ) ); 213 } 214 215 void output_int( const Value_type& value ) 216 { 217 if( value.is_uint64() ) 218 { 219 os_ << value.get_uint64(); 220 } 221 else 222 { 223 os_ << value.get_int64(); 224 } 225 } 226 227 void output( const String_type& s ) 228 { 229 os_ << '"' << add_esc_chars( s, raw_utf8_, esc_nonascii_ ) << '"'; 230 } 231 232 void output( bool b ) 233 { 234 os_ << to_str< String_type >( b ? "true" : "false" ); 235 } 236 237 void output( double d ) 238 { 239 if( remove_trailing_zeros_ ) 240 { 241 std::basic_ostringstream< Char_type > os; 242 243 append_double( os, d, 16 ); // note precision is 16 so that we get some trailing space that we can remove, 244 // otherwise, 0.1234 gets converted to "0.12399999..." 245 246 String_type str = os.str(); 247 248 remove_trailing( str ); 249 250 os_ << str; 251 } 252 else 253 { 254 append_double( os_, d, 17 ); 255 } 256 } 257 258 static bool contains_composite_elements( const Array_type& arr ) 259 { 260 for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) 261 { 262 const Value_type& val = *i; 263 264 if( val.type() == obj_type || 265 val.type() == array_type ) 266 { 267 return true; 268 } 269 } 270 271 return false; 272 } 273 274 template< class Iter > 275 void output_composite_item( Iter i, Iter last ) 276 { 277 output( *i ); 278 279 if( ++i != last ) 280 { 281 os_ << ','; 282 } 283 } 284 285 void output( const Array_type& arr ) 286 { 287 if( single_line_arrays_ && !contains_composite_elements( arr ) ) 288 { 289 os_ << '['; space(); 290 291 for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) 292 { 293 output_composite_item( i, arr.end() ); 294 295 space(); 296 } 297 298 os_ << ']'; 299 } 300 else 301 { 302 output_array_or_obj( arr, '[', ']' ); 303 } 304 } 305 306 template< class T > 307 void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char ) 308 { 309 os_ << start_char; new_line(); 310 311 ++indentation_level_; 312 313 for( typename T::const_iterator i = t.begin(); i != t.end(); ++i ) 314 { 315 indent(); 316 317 output_composite_item( i, t.end() ); 318 319 new_line(); 320 } 321 322 --indentation_level_; 323 324 indent(); os_ << end_char; 325 } 326 327 void indent() 328 { 329 if( !pretty_ ) return; 330 331 for( int i = 0; i < indentation_level_; ++i ) 332 { 333 os_ << " "; 334 } 335 } 336 337 void space() 338 { 339 if( pretty_ ) os_ << ' '; 340 } 341 342 void new_line() 343 { 344 if( pretty_ ) os_ << '\n'; 345 } 346 347 Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning 348 349 Ostream_type& os_; 350 int indentation_level_; 351 bool pretty_; 352 bool raw_utf8_; 353 bool esc_nonascii_; 354 bool remove_trailing_zeros_; 355 bool single_line_arrays_; 356 boost::io::basic_ios_all_saver< Char_type > ios_saver_; // so that ostream state is reset after control is returned to the caller 357 }; 358 359 // writes JSON Value to a stream, e.g. 360 // 361 // write_stream( value, os, pretty_print ); 362 // 363 template< class Value_type, class Ostream_type > 364 void write_stream( const Value_type& value, Ostream_type& os, unsigned int options = 0 ) 365 { 366 os << std::dec; 367 Generator< Value_type, Ostream_type >( value, os, options ); 368 } 369 370 // writes JSON Value to a stream, e.g. 371 // 372 // const string json_str = write( value, pretty_print ); 373 // 374 template< class Value_type > 375 typename Value_type::String_type write_string( const Value_type& value, unsigned int options = 0 ) 376 { 377 typedef typename Value_type::String_type::value_type Char_type; 378 379 std::basic_ostringstream< Char_type > os; 380 381 write_stream( value, os, options ); 382 383 return os.str(); 384 } 385 } 386 387 #endif -
source/tools/atlas/AtlasObject/AtlasObject.h
29 29 30 30 class wxString; 31 31 32 typedef struct JSContext JSContext;33 34 32 ////////////////////////////////////////////////////////////////////////// 35 33 // Mostly-private bits: 36 34 … … 193 191 AtObj LoadFromXML(const std::string& xml); 194 192 195 193 // Returns AtObj() on failure - test with AtObj::defined() 196 AtObj LoadFromJSON( JSContext* cx,const std::string& json);194 AtObj LoadFromJSON(const std::string& json); 197 195 198 196 // Returns UTF-8-encoded XML document string. 199 197 // Returns empty string on failure. … … 201 199 202 200 // Returns UTF-8-encoded JSON string. 203 201 // Returns empty string on failure. 204 std::string SaveToJSON( JSContext* cx,AtObj& obj);202 std::string SaveToJSON(AtObj& obj); 205 203 206 204 AtObj TrimEmptyChildren(AtObj& obj); 207 205 } -
source/tools/atlas/AtlasObject/AtlasObjectJS.cpp
1 /* Copyright (C) 201 1Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 18 18 #include "AtlasObject.h" 19 19 #include "AtlasObjectImpl.h" 20 20 21 #include " ../AtlasScript/ScriptInterface.h"21 #include "JSONSpiritInclude.h" 22 22 23 23 #if defined(_MSC_VER) 24 24 # pragma warning(disable:4996) // deprecated CRT … … 28 28 29 29 #include <sstream> 30 30 31 static AtSmartPtr<AtNode> ConvertNode( JSContext* cx, jsvalnode);31 static AtSmartPtr<AtNode> ConvertNode(json_spirit::Value node); 32 32 33 AtObj AtlasObject::LoadFromJSON( JSContext* cx,const std::string& json)33 AtObj AtlasObject::LoadFromJSON(const std::string& json) 34 34 { 35 // Convert UTF8 to UTF16 36 wxString jsonW(json.c_str(), wxConvUTF8); 37 size_t json16len; 38 wxCharBuffer json16 = wxMBConvUTF16().cWC2MB(jsonW.c_str(), jsonW.Length(), &json16len); 35 json_spirit::Value rootnode; 36 json_spirit::read_string(json, rootnode); 37 38 AtObj obj; 39 obj.p = ConvertNode(rootnode); 40 return obj; 41 } 39 42 40 jsval vp = JSVAL_NULL; 41 JSONParser* parser = JS_BeginJSONParse(cx, &vp); 42 if (!parser) 43 // Convert from a JSON to an AtNode 44 static AtSmartPtr<AtNode> ConvertNode(json_spirit::Value node) 45 { 46 AtSmartPtr<AtNode> obj (new AtNode()); 47 48 if (node.type() == json_spirit::str_type) 43 49 { 44 wxLogError(_T("ParseJSON failed to begin")); 45 return AtObj(); 50 obj->value = std::wstring(node.get_str().begin(),node.get_str().end()); 46 51 } 47 48 if (!JS_ConsumeJSONText(cx, parser, reinterpret_cast<const jschar*>(json16.data()), (uint32)(json16len/2))) 52 else if (node.type() == json_spirit::int_type || node.type() == json_spirit::real_type) 49 53 { 50 wxLogError(_T("ParseJSON failed to consume")); 51 return AtObj(); 54 std::wstringstream stream; 55 if (node.type() == json_spirit::int_type) 56 stream << node.get_int(); 57 if (node.type() == json_spirit::real_type) 58 stream << node.get_real(); 59 60 obj->value = stream.str().c_str(); 61 obj->children.insert(AtNode::child_pairtype( 62 "@number", AtSmartPtr<AtNode>(new AtNode()) 63 )); 52 64 } 53 54 if (!JS_FinishJSONParse(cx, parser, JSVAL_NULL)) 65 else if (node.type() == json_spirit::bool_type) 55 66 { 56 wxLogError(_T("ParseJSON failed to finish")); 57 return AtObj(); 67 if (node.get_bool()) 68 obj->value = L"true"; 69 else 70 obj->value = L"false"; 71 72 obj->children.insert(AtNode::child_pairtype( 73 "@boolean", AtSmartPtr<AtNode>(new AtNode()) 74 )); 58 75 } 59 60 AtObj obj; 61 obj.p = ConvertNode(cx, vp); 62 63 return obj; 64 } 65 66 // Convert from a jsval to an AtNode 67 static AtSmartPtr<AtNode> ConvertNode(JSContext* cx, jsval node) 68 { 69 AtSmartPtr<AtNode> obj (new AtNode()); 70 71 // Non-objects get converted into strings 72 if (!JSVAL_IS_OBJECT(node)) 76 else if (node.type() == json_spirit::array_type) 73 77 { 74 JSString* str = JS_ValueToString(cx, node); 75 if (!str) 76 return obj; // error 77 size_t valueLen; 78 const jschar* valueChars = JS_GetStringCharsAndLength(cx, str, &valueLen); 79 if (!valueChars) 80 return obj; // error 81 wxString valueWx(reinterpret_cast<const char*>(valueChars), wxMBConvUTF16(), valueLen*2); 78 //AtSmartPtr<AtNode> child(new AtNode()); 79 obj->children.insert(AtNode::child_pairtype( 80 "@array", AtSmartPtr<AtNode>(new AtNode()) 81 )); 82 82 83 obj->value = valueWx.c_str();84 85 // Annotate numbers/booleans specially, to allow round-tripping86 if (JSVAL_IS_NUMBER(node))83 json_spirit::Array nodeChildren = node.get_array(); 84 json_spirit::Array::iterator itr = nodeChildren.begin(); 85 86 for (; itr != nodeChildren.end(); itr++) 87 87 { 88 88 obj->children.insert(AtNode::child_pairtype( 89 " @number", AtSmartPtr<AtNode>(new AtNode())89 "item", ConvertNode(*itr) 90 90 )); 91 91 } 92 else if (JSVAL_IS_BOOLEAN(node))93 {94 obj->children.insert(AtNode::child_pairtype(95 "@boolean", AtSmartPtr<AtNode>(new AtNode())96 ));97 }98 99 return obj;100 92 } 101 102 JSObject* it = JS_NewPropertyIterator(cx, JSVAL_TO_OBJECT(node)); 103 if (!it) 104 return obj; // error 105 106 while (true) 93 else if (node.type() == json_spirit::obj_type) 107 94 { 108 jsid idp; 109 jsval val; 110 if (! JS_NextProperty(cx, it, &idp) || ! JS_IdToValue(cx, idp, &val)) 111 return obj; // error 112 if (val == JSVAL_VOID) 113 break; // end of iteration 114 if (! JSVAL_IS_STRING(val)) 115 continue; // ignore integer properties 116 117 JSString* name = JSVAL_TO_STRING(val); 118 size_t len; 119 const jschar* chars = JS_GetStringCharsAndLength(cx, name, &len); 120 wxString nameWx(reinterpret_cast<const char*>(chars), wxMBConvUTF16(), len*2); 121 std::string nameStr(nameWx.ToUTF8().data()); 122 123 jsval vp; 124 if (!JS_GetPropertyById(cx, JSVAL_TO_OBJECT(node), idp, &vp)) 125 return obj; // error 126 127 // Unwrap arrays into a special format like <$name><item>$i0</item><item>... 128 // (This assumes arrays aren't nested) 129 if (JSVAL_IS_OBJECT(vp) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(vp))) 95 json_spirit::Object objectProperties = node.get_obj(); 96 json_spirit::Object::iterator itr = objectProperties.begin(); 97 for (; itr != objectProperties.end(); itr++) 130 98 { 131 AtSmartPtr<AtNode> child(new AtNode());132 child->children.insert(AtNode::child_pairtype(133 "@array", AtSmartPtr<AtNode>(new AtNode())134 ));135 136 jsuint arrayLength;137 if (!JS_GetArrayLength(cx, JSVAL_TO_OBJECT(vp), &arrayLength))138 return obj; // error139 140 for (jsuint i = 0; i < arrayLength; ++i)141 {142 jsval val;143 if (!JS_GetElement(cx, JSVAL_TO_OBJECT(vp), i, &val))144 return obj; // error145 146 child->children.insert(AtNode::child_pairtype(147 "item", ConvertNode(cx, val)148 ));149 }150 151 99 obj->children.insert(AtNode::child_pairtype( 152 nameStr, child100 itr->name_, ConvertNode(itr->value_) 153 101 )); 154 102 } 155 else156 {157 obj->children.insert(AtNode::child_pairtype(158 nameStr, ConvertNode(cx, vp)159 ));160 }161 103 } 162 104 else 105 { 106 assert(! "Unimplemented type found when parsing JSON!"); 107 } 108 163 109 return obj; 164 110 } 165 111 166 112 167 js val BuildJSVal(JSContext* cx,AtNode::Ptr p)113 json_spirit::Value BuildJSONNode(AtNode::Ptr p) 168 114 { 169 115 if (!p) 170 return JSVAL_VOID; 116 { 117 json_spirit::Value rval; 118 return rval; 119 } 171 120 172 121 // Special case for numbers/booleans to allow round-tripping 173 122 if (p->children.count("@number")) … … 178 127 double val = 0; 179 128 str >> val; 180 129 181 jsval rval; 182 if (!JS_NewNumberValue(cx, val, &rval)) 183 return JSVAL_VOID; // error 130 json_spirit::Value rval(val); 184 131 return rval; 185 132 } 186 133 else if (p->children.count("@boolean")) … … 188 135 bool val = false; 189 136 if (p->value == L"true") 190 137 val = true; 191 192 return BOOLEAN_TO_JSVAL(val); 138 139 json_spirit::Value rval(val); 140 return rval; 193 141 } 194 142 195 143 // If no children, then use the value string instead 196 144 if (p->children.empty()) 197 145 { 198 size_t val16len; 199 wxCharBuffer val16 = wxMBConvUTF16().cWC2MB(p->value.c_str(), p->value.length(), &val16len); 200 201 JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast<const jschar*>(val16.data()), (uint32)(val16len/2)); 202 if (!str) 203 return JSVAL_VOID; // error 204 return STRING_TO_JSVAL(str); 146 json_spirit::Value rval(p->value.c_str()); 147 return rval; 205 148 } 206 149 207 150 if (p->children.find("@array") != p->children.end()) 208 151 { 209 JSObject* obj = JS_NewArrayObject(cx, 0, NULL); 210 if (!obj) 211 return JSVAL_VOID; // error 152 json_spirit::Array rval; 212 153 213 154 // Find the <item> children 214 155 AtNode::child_maptype::const_iterator lower = p->children.lower_bound("item"); 215 156 AtNode::child_maptype::const_iterator upper = p->children.upper_bound("item"); 216 157 217 jsint idx = 0;158 uint idx = 0; 218 159 for (AtNode::child_maptype::const_iterator it = lower; it != upper; ++it) 219 160 { 220 jsval val = BuildJSVal(cx, it->second); 221 if (!JS_SetElement(cx, obj, idx, &val)) 222 return JSVAL_VOID; // error 161 json_spirit::Value child = BuildJSONNode(it->second); 162 rval.push_back(child); 223 163 224 164 ++idx; 225 165 } 226 166 227 return OBJECT_TO_JSVAL(obj);167 return rval; 228 168 } 229 169 else 230 170 { 231 JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL); 232 if (!obj) 233 return JSVAL_VOID; // error 234 171 json_spirit::Object rval; 172 235 173 for (AtNode::child_maptype::const_iterator it = p->children.begin(); it != p->children.end(); ++it) 236 174 { 237 jsval val = BuildJSVal(cx, it->second); 238 if (!JS_SetProperty(cx, obj, it->first.c_str(), &val)) 239 return JSVAL_VOID; // error 175 json_spirit::Value child = BuildJSONNode(it->second); 176 rval.push_back(json_spirit::Pair(it->first.c_str(), child)); 240 177 } 241 178 242 return OBJECT_TO_JSVAL(obj);179 return rval; 243 180 } 244 181 } 245 182 246 st ruct Stringifier183 std::string AtlasObject::SaveToJSON(AtObj& obj) 247 184 { 248 static JSBool callback(const jschar* buf, uint32 len, void* data) 249 { 250 wxString textWx(reinterpret_cast<const char*>(buf), wxMBConvUTF16(), len*2); 251 std::string textStr(textWx.ToUTF8().data()); 252 253 static_cast<Stringifier*>(data)->stream << textStr; 254 return JS_TRUE; 255 } 256 257 std::stringstream stream; 258 }; 259 260 std::string AtlasObject::SaveToJSON(JSContext* cx, AtObj& obj) 261 { 262 jsval root = BuildJSVal(cx, obj.p); 263 264 Stringifier str; 265 if (!JS_Stringify(cx, &root, NULL, JSVAL_VOID, &Stringifier::callback, &str)) 266 { 267 wxLogError(_T("SaveToJSON failed")); 268 return ""; 269 } 270 271 return str.stream.str(); 185 json_spirit::Value root = BuildJSONNode(obj.p); 186 std::string ret = json_spirit::write_string(root, 0); 187 return ret; 272 188 } -
source/tools/atlas/AtlasScript/NativeWrapper.inl
1 /* Copyright (C) 2009 Wildfire Games.2 * This file is part of 0 A.D.3 *4 * 0 A.D. is free software: you can redistribute it and/or modify5 * it under the terms of the GNU General Public License as published by6 * the Free Software Foundation, either version 2 of the License, or7 * (at your option) any later version.8 *9 * 0 A.D. is distributed in the hope that it will be useful,10 * but WITHOUT ANY WARRANTY; without even the implied warranty of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12 * GNU General Public License for more details.13 *14 * You should have received a copy of the GNU General Public License15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.16 */17 18 #include <boost/preprocessor/punctuation/comma_if.hpp>19 #include <boost/preprocessor/repetition/repeat.hpp>20 21 // Set the maximum number of function arguments that can be handled22 #define MAX_ARGS 323 24 // (This is included inside the definition of class ScriptInterface)25 public:26 // Varieties of comma-separated list to fit on the head/tail/whole of another comma-separated list27 #define NUMBERED_LIST_TAIL(z, i, data) ,data##i28 #define NUMBERED_LIST_HEAD(z, i, data) data##i,29 #define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i30 // Some other things31 #define TYPED_ARGS(z, i, data) , T##i a##i32 #define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal<T##i>(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) return JS_FALSE;33 34 // List-generating macros, named roughly after their first list item35 #define TYPENAME_T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, typename T)36 #define TYPENAME_T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, typename T)37 #define T0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, T)38 #define T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, T)39 #define T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, T)40 #define T0_A0(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS, ~)41 #define A0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, a)42 #define A0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, a)43 44 // Define RegisterFunction<TR, T0..., f>45 #define OVERLOADS(z, i, data) \46 template <typename TR, TYPENAME_T0_HEAD(z,i) TR (*fptr) ( void* T0_TAIL(z,i) )> \47 void RegisterFunction(const char* name) { \48 Register(name, call<TR, T0_HEAD(z,i) fptr>, nargs<0 T0_TAIL(z,i)>()); \49 }50 51 BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~)52 #undef OVERLOADS53 54 private:55 // JSNative-compatible function that wraps the function identified in the template argument list56 // (Definition comes later, since it depends on some things we haven't defined yet)57 #define OVERLOADS(z, i, data) \58 template <typename TR, TYPENAME_T0_HEAD(z,i) TR (*fptr) ( void* T0_TAIL(z,i) )> \59 static JSBool call(JSContext* cx, uintN argc, jsval* vp);60 BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~)61 #undef OVERLOADS62 63 // Argument-number counter64 #define OVERLOADS(z, i, data) \65 template <int dummy TYPENAME_T0_TAIL(z,i)> /* add a dummy parameter so we still compile with 0 template args */ \66 static size_t nargs() { return i; }67 BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~)68 #undef OVERLOADS69 70 }; // end of class ScriptInterface, because the following specialised structs71 // are not permitted inside non-namespace scopes72 73 74 // ScriptInterface_NativeWrapper<T>::call(cx, rval, fptr, args...) will call fptr(cbdata, args),75 // and if T != void then it will store the result in rval:76 77 // Templated on the return type so void can be handled separately78 template <typename TR>79 struct ScriptInterface_NativeWrapper {80 #define OVERLOADS(z, i, data) \81 template<TYPENAME_T0_HEAD(z,i) typename f> \82 static void call(JSContext* cx, jsval& rval, f fptr T0_A0(z,i)) { \83 rval = ScriptInterface::ToJSVal<TR>(cx, fptr(ScriptInterface::GetCallbackData(cx) A0_TAIL(z,i))); \84 }85 86 BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~)87 #undef OVERLOADS88 };89 90 // Overloaded to ignore the return value from void functions91 template <>92 struct ScriptInterface_NativeWrapper<void> {93 #define OVERLOADS(z, i, data) \94 template<TYPENAME_T0_HEAD(z,i) typename f> \95 static void call(JSContext* cx, jsval& /*rval*/, f fptr T0_A0(z,i)) { \96 fptr(ScriptInterface::GetCallbackData(cx) A0_TAIL(z,i)); \97 }98 BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~)99 #undef OVERLOADS100 };101 102 // JSNative-compatible function that wraps the function identified in the template argument list103 #define OVERLOADS(z, i, data) \104 template <typename TR, TYPENAME_T0_HEAD(z,i) TR (*fptr) ( void* T0_TAIL(z,i) )> \105 JSBool ScriptInterface::call(JSContext* cx, uintN argc, jsval* vp) { \106 (void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \107 BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \108 jsval rval = JSVAL_VOID; \109 ScriptInterface_NativeWrapper<TR>::call(cx, rval, fptr A0_TAIL(z,i)); \110 JS_SET_RVAL(cx, vp, rval); \111 return JS_TRUE; \112 }113 BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~)114 #undef OVERLOADS115 116 // Clean up our mess117 #undef NUMBERED_LIST_TAIL118 #undef NUMBERED_LIST_HEAD119 #undef NUMBERED_LIST_BALANCED120 #undef TYPED_ARGS121 #undef CONVERT_ARG122 #undef TYPENAME_T0_HEAD123 #undef TYPENAME_T0_TAIL124 #undef T0125 #undef T0_HEAD126 #undef T0_TAIL127 #undef T0_A0128 #undef A0129 #undef A0_TAIL -
source/tools/atlas/AtlasScript/ScriptInterface.cpp
1 /* Copyright (C) 2011 Wildfire Games.2 * This file is part of 0 A.D.3 *4 * 0 A.D. is free software: you can redistribute it and/or modify5 * it under the terms of the GNU General Public License as published by6 * the Free Software Foundation, either version 2 of the License, or7 * (at your option) any later version.8 *9 * 0 A.D. is distributed in the hope that it will be useful,10 * but WITHOUT ANY WARRANTY; without even the implied warranty of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12 * GNU General Public License for more details.13 *14 * You should have received a copy of the GNU General Public License15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.16 */17 18 #include "ScriptInterface.h"19 20 #include <cassert>21 #ifndef _WIN3222 # include <typeinfo>23 # include <cxxabi.h>24 #endif25 26 #if defined(_MSC_VER)27 # pragma warning(disable:4996) // deprecated CRT28 #endif29 30 #if defined(__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__) >= 402 // (older GCCs don't support this pragma)31 # pragma GCC diagnostic ignored "-Wredundant-decls" // triggered by wx/geometry.h32 #endif33 34 #include "wx/wx.h"35 36 #include "GameInterface/Shareable.h"37 #include "GameInterface/Messages.h"38 39 40 #include <boost/preprocessor/punctuation/comma_if.hpp>41 #include <boost/preprocessor/repetition/repeat.hpp>42 43 #include "valgrind.h"44 45 #define FAIL(msg) do { JS_ReportError(cx, msg); return false; } while (false)46 47 const int RUNTIME_SIZE = 4*1024*1024; // TODO: how much memory is needed?48 const int STACK_CHUNK_SIZE = 8192;49 50 SubmitCommand g_SubmitCommand; // TODO: globals are ugly51 52 ////////////////////////////////////////////////////////////////53 54 namespace55 {56 template<typename T>57 void ReportError(JSContext* cx, const char* title)58 {59 // TODO: SetPendingException turns the error into a JS-catchable exception,60 // but the error report doesn't say anything useful like the line number,61 // so I'm just using ReportError instead for now (and failures are uncatchable62 // and will terminate the whole script)63 //JS_SetPendingException(cx, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "%s: Unhandled type", title)));64 #ifdef _WIN3265 JS_ReportError(cx, "%s: Unhandled type", title);66 #else67 // Give a more informative message on GCC68 int status;69 char* name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);70 JS_ReportError(cx, "%s: Unhandled type '%s'", title, name);71 free(name);72 #endif73 }74 75 // Report runtime errors for unhandled types, so we don't have to bother76 // defining all the types in advance. (TODO: at some point we should77 // define all the types and then remove this bit so the errors are found78 // at link-time.)79 template<typename T> struct FromJSVal80 {81 static bool Convert(JSContext* cx, jsval WXUNUSED(v), T& WXUNUSED(out))82 {83 ReportError<T>(cx, "FromJSVal");84 return false;85 }86 };87 88 template<> struct FromJSVal<bool>89 {90 static bool Convert(JSContext* cx, jsval v, bool& out)91 {92 JSBool ret;93 if (! JS_ValueToBoolean(cx, v, &ret)) return false;94 out = (ret ? true : false);95 return true;96 }97 };98 99 template<> struct FromJSVal<float>100 {101 static bool Convert(JSContext* cx, jsval v, float& out)102 {103 jsdouble ret;104 if (! JS_ValueToNumber(cx, v, &ret)) return false;105 out = ret;106 return true;107 }108 };109 110 template<> struct FromJSVal<int>111 {112 static bool Convert(JSContext* cx, jsval v, int& out)113 {114 int32 ret;115 if (! JS_ValueToECMAInt32(cx, v, &ret)) return false;116 out = ret;117 return true;118 }119 };120 121 template<> struct FromJSVal<size_t>122 {123 static bool Convert(JSContext* cx, jsval v, size_t& out)124 {125 uint32 ret;126 if (! JS_ValueToECMAUint32(cx, v, &ret)) return false;127 out = ret;128 return true;129 }130 };131 132 template<> struct FromJSVal<CScriptVal>133 {134 static bool Convert(JSContext* WXUNUSED(cx), jsval v, CScriptVal& out)135 {136 out = v;137 return true;138 }139 };140 141 template<> struct FromJSVal<std::wstring>142 {143 static bool Convert(JSContext* cx, jsval v, std::wstring& out)144 {145 JSString* ret = JS_ValueToString(cx, v);146 if (! ret)147 FAIL("Argument must be convertible to a string");148 size_t len;149 const jschar* ch = JS_GetStringCharsAndLength(cx, ret, &len);150 if (! ch)151 FAIL("JS_GetStringsCharsAndLength failed"); // probably out of memory152 out = std::wstring(ch, ch + len);153 return true;154 }155 };156 157 template<> struct FromJSVal<std::string>158 {159 static bool Convert(JSContext* cx, jsval v, std::string& out)160 {161 JSString* ret = JS_ValueToString(cx, v);162 if (! ret)163 FAIL("Argument must be convertible to a string");164 size_t len = JS_GetStringEncodingLength(cx, ret);165 if (len == (size_t)-1)166 FAIL("JS_GetStringEncodingLength failed");167 char* ch = JS_EncodeString(cx, ret); // chops off high byte of each jschar168 if (! ch)169 FAIL("JS_EncodeString failed"); // probably out of memory170 out = std::string(ch, ch + len);171 JS_free(cx, ch);172 return true;173 }174 };175 176 template<> struct FromJSVal<wxString>177 {178 static bool Convert(JSContext* cx, jsval v, wxString& out)179 {180 JSString* ret = JS_ValueToString(cx, v);181 size_t len;182 if (! ret)183 FAIL("Argument must be convertible to a string");184 const jschar* ch = JS_GetStringCharsAndLength(cx, ret, &len);185 if (! ch)186 FAIL("JS_GetStringsCharsAndLength failed"); // probably out of memory187 out = wxString((const char*)ch, wxMBConvUTF16(), len*2);188 return true;189 }190 };191 192 template<typename T> struct FromJSVal<std::vector<T> >193 {194 static bool Convert(JSContext* cx, jsval v, std::vector<T>& out)195 {196 JSObject* obj;197 if (! JS_ValueToObject(cx, v, &obj) || obj == NULL || !JS_IsArrayObject(cx, obj))198 FAIL("Argument must be an array");199 jsuint length;200 if (! JS_GetArrayLength(cx, obj, &length))201 FAIL("Failed to get array length");202 out.reserve(length);203 for (jsuint i = 0; i < length; ++i)204 {205 jsval el;206 if (! JS_GetElement(cx, obj, i, &el))207 FAIL("Failed to read array element");208 T el2;209 if (! FromJSVal<T>::Convert(cx, el, el2))210 return false;211 out.push_back(el2);212 }213 return true;214 }215 };216 217 ////////////////////////////////////////////////////////////////218 219 // Report runtime errors for unhandled types, so we don't have to bother220 // defining all the types in advance. (TODO: at some point we should221 // define all the types and then remove this bit so the errors are found222 // at link-time.)223 template<typename T> struct ToJSVal224 {225 static jsval Convert(JSContext* cx, const T& WXUNUSED(val))226 {227 ReportError<T>(cx, "ToJSVal");228 return JSVAL_VOID;229 }230 };231 232 ////////////////////////////////////////////////////////////////233 // Primitive types:234 235 template<> struct ToJSVal<bool>236 {237 static jsval Convert(JSContext* WXUNUSED(cx), const bool& val)238 {239 return val ? JSVAL_TRUE : JSVAL_FALSE;240 }241 };242 243 template<> struct ToJSVal<float>244 {245 static jsval Convert(JSContext* cx, const float& val)246 {247 jsval rval = JSVAL_VOID;248 JS_NewNumberValue(cx, val, &rval); // ignore return value249 return rval;250 }251 };252 253 template<> struct ToJSVal<int>254 {255 static jsval Convert(JSContext* WXUNUSED(cx), const int& val)256 {257 return INT_TO_JSVAL(val);258 }259 };260 261 template<> struct ToJSVal<size_t>262 {263 static jsval Convert(JSContext* cx, const size_t& val)264 {265 if (val <= JSVAL_INT_MAX)266 return INT_TO_JSVAL(val);267 jsval rval = JSVAL_VOID;268 JS_NewNumberValue(cx, val, &rval); // ignore return value269 return rval;270 }271 };272 273 template<> struct ToJSVal<wxString>274 {275 static jsval Convert(JSContext* cx, const wxString& val)276 {277 wxMBConvUTF16 conv;278 size_t length;279 wxCharBuffer utf16 = conv.cWC2MB(val.c_str(), val.length()+1, &length);280 JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast<jschar*>(utf16.data()), length/2);281 if (str)282 return STRING_TO_JSVAL(str);283 else284 return JSVAL_VOID;285 }286 };287 288 template<> struct ToJSVal<std::wstring>289 {290 static jsval Convert(JSContext* cx, const std::wstring& val)291 {292 wxMBConvUTF16 conv;293 size_t length;294 wxCharBuffer utf16 = conv.cWC2MB(val.c_str(), val.length()+1, &length);295 JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast<jschar*>(utf16.data()), length/2);296 if (str)297 return STRING_TO_JSVAL(str);298 else299 return JSVAL_VOID;300 }301 };302 303 template<> struct ToJSVal<std::string>304 {305 static jsval Convert(JSContext* cx, const std::string& val)306 {307 JSString* str = JS_NewStringCopyN(cx, val.c_str(), val.length());308 if (str)309 return STRING_TO_JSVAL(str);310 return JSVAL_VOID;311 }312 };313 314 ////////////////////////////////////////////////////////////////315 // Compound types:316 317 template<typename T> struct ToJSVal<std::vector<T> >318 {319 static jsval Convert(JSContext* cx, const std::vector<T>& val)320 {321 JSObject* obj = JS_NewArrayObject(cx, 0, NULL);322 if (! obj) return JSVAL_VOID;323 for (size_t i = 0; i < val.size(); ++i)324 {325 jsval el = ToJSVal<T>::Convert(cx, val[i]);326 JS_SetElement(cx, obj, (jsint)i, &el);327 }328 return OBJECT_TO_JSVAL(obj);329 }330 };331 332 template<typename T> struct ToJSVal<AtlasMessage::Shareable<T> >333 {334 static jsval Convert(JSContext* cx, const AtlasMessage::Shareable<T>& val)335 {336 return ToJSVal<T>::Convert(cx, val._Unwrap());337 }338 };339 }340 341 template<typename T> bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, T& out)342 {343 return ::FromJSVal<T>::Convert(cx, v, out);344 }345 346 template<typename T> jsval ScriptInterface::ToJSVal(JSContext* cx, const T& v)347 {348 return ::ToJSVal<T>::Convert(cx, v);349 }350 351 // Explicit instantiation of functions that would otherwise be unused in this file352 // but are required for linking with other files353 template bool ScriptInterface::FromJSVal<std::string>(JSContext*, jsval, std::string&);354 template bool ScriptInterface::FromJSVal<wxString>(JSContext*, jsval, wxString&);355 template bool ScriptInterface::FromJSVal<bool>(JSContext*, jsval, bool&);356 template bool ScriptInterface::FromJSVal<float>(JSContext*, jsval, float&);357 template bool ScriptInterface::FromJSVal<CScriptVal>(JSContext*, jsval, CScriptVal&);358 template jsval ScriptInterface::ToJSVal<wxString>(JSContext*, wxString const&);359 template jsval ScriptInterface::ToJSVal<int>(JSContext*, int const&);360 template jsval ScriptInterface::ToJSVal<float>(JSContext*, float const&);361 template jsval ScriptInterface::ToJSVal<std::vector<int> >(JSContext*, std::vector<int> const&);362 template jsval ScriptInterface::ToJSVal<size_t>(JSContext*, size_t const&);363 template jsval ScriptInterface::ToJSVal<std::vector<wxString> >(JSContext*, std::vector<wxString> const&);364 365 ////////////////////////////////////////////////////////////////366 367 struct AtlasScriptInterface_impl368 {369 AtlasScriptInterface_impl();370 ~AtlasScriptInterface_impl();371 static JSBool LoadScript(JSContext* cx, const jschar* chars, uintN length, const char* filename, jsval* rval);372 void RegisterMessages(JSObject* parent);373 void Register(const char* name, JSNative fptr, uintN nargs);374 375 JSRuntime* m_rt;376 JSContext* m_cx;377 JSObject* m_glob; // global scope object378 JSObject* m_atlas; // Atlas scope object379 };380 381 namespace382 {383 JSClass global_class = {384 "global", JSCLASS_GLOBAL_FLAGS,385 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,386 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,387 NULL, NULL, NULL, NULL,388 NULL, NULL, NULL, NULL389 };390 391 void ErrorReporter(JSContext* WXUNUSED(cx), const char* message, JSErrorReport* report)392 {393 bool isWarning = JSREPORT_IS_WARNING(report->flags);394 wxString logMessage(isWarning ? _T("JavaScript warning: ") : _T("JavaScript error: "));395 if (report->filename)396 {397 logMessage << wxString::FromAscii(report->filename);398 logMessage << _T(" line ") << report->lineno << _T("\n");399 }400 logMessage << wxString::FromAscii(message);401 if (isWarning)402 wxLogWarning(_T("%s"), logMessage.c_str());403 else404 wxLogError(_T("%s"), logMessage.c_str());405 // When running under Valgrind, print more information in the error message406 VALGRIND_PRINTF_BACKTRACE("->");407 wxPrintf(_T("wxJS %s: %s\n--------\n"), isWarning ? _T("warning") : _T("error"), logMessage.c_str());408 }409 410 // Functions in the Atlas.* namespace:411 412 JSBool ForceGC(JSContext* cx, uintN WXUNUSED(argc), jsval* vp)413 {414 JS_GC(cx);415 JS_SET_RVAL(cx, vp, JSVAL_VOID);416 return JS_TRUE;417 }418 419 JSBool LoadScript(JSContext* cx, uintN argc, jsval* vp)420 {421 if (argc < 2 || !JSVAL_IS_STRING(JS_ARGV(cx, vp)[0]) || !JSVAL_IS_STRING(JS_ARGV(cx, vp)[1]))422 return JS_FALSE;423 424 std::string name;425 if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], name))426 return JS_FALSE;427 428 JSString* code = JSVAL_TO_STRING(JS_ARGV(cx, vp)[1]);429 430 size_t len;431 const jschar* ch = JS_GetStringCharsAndLength(cx, code, &len);432 if (!ch)433 return JS_FALSE;434 435 jsval rval = JSVAL_VOID;436 if (!AtlasScriptInterface_impl::LoadScript(cx,437 ch, (uintN)len,438 name.c_str(), &rval))439 return JS_FALSE;440 441 JS_SET_RVAL(cx, vp, rval);442 return JS_TRUE;443 }444 445 // Functions in the global namespace:446 447 JSBool print(JSContext* cx, uintN argc, jsval* vp)448 {449 for (uintN i = 0; i < argc; ++i)450 {451 std::string str;452 if (! ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[i], str))453 return JS_FALSE;454 printf("%s", str.c_str());455 }456 fflush(stdout);457 JS_SET_RVAL(cx, vp, JSVAL_VOID);458 return JS_TRUE;459 }460 }461 462 AtlasScriptInterface_impl::AtlasScriptInterface_impl()463 {464 m_rt = JS_NewRuntime(RUNTIME_SIZE);465 assert(m_rt); // TODO: error handling466 467 m_cx = JS_NewContext(m_rt, STACK_CHUNK_SIZE);468 assert(m_cx);469 470 JS_BeginRequest(m_cx); // if you get linker errors, see the comment in ScriptInterface.h about JS_THREADSAFE471 // (TODO: are we using requests correctly? (Probably not; how much does it matter?))472 473 JS_SetContextPrivate(m_cx, NULL);474 475 JS_SetErrorReporter(m_cx, ErrorReporter);476 477 JS_SetOptions(m_cx,478 JSOPTION_STRICT // "warn on dubious practice"479 | JSOPTION_XML // "ECMAScript for XML support: parse <!-- --> as a token"480 );481 482 JS_SetVersion(m_cx, JSVERSION_LATEST);483 484 m_glob = JS_NewCompartmentAndGlobalObject(m_cx, &global_class, NULL);485 JS_InitStandardClasses(m_cx, m_glob);486 487 JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);488 489 JS_DefineFunction(m_cx, m_glob, "print", ::print, 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);490 491 m_atlas = JS_DefineObject(m_cx, m_glob, "Atlas", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);492 JS_DefineFunction(m_cx, m_atlas, "ForceGC", ::ForceGC, 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);493 JS_DefineFunction(m_cx, m_atlas, "LoadScript", ::LoadScript, 2, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);494 JS_DefineObject(m_cx, m_atlas, "State", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);495 496 RegisterMessages(m_atlas);497 }498 499 AtlasScriptInterface_impl::~AtlasScriptInterface_impl()500 {501 JS_EndRequest(m_cx);502 JS_DestroyContext(m_cx);503 JS_DestroyRuntime(m_rt);504 }505 506 JSBool AtlasScriptInterface_impl::LoadScript(JSContext* cx, const jschar* chars, uintN length, const char* filename, jsval* rval)507 {508 JSObject* scriptObj = JS_NewObject(cx, NULL, NULL, NULL);509 if (! scriptObj)510 return JS_FALSE;511 *rval = OBJECT_TO_JSVAL(scriptObj);512 513 jsval scriptRval;514 JSBool ok = JS_EvaluateUCScript(cx, scriptObj, chars, length, filename, 1, &scriptRval);515 if (! ok)516 return JS_FALSE;517 518 return JS_TRUE;519 }520 521 void AtlasScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs)522 {523 JS_DefineFunction(m_cx, m_atlas, name, fptr, nargs, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);524 }525 526 527 ScriptInterface::ScriptInterface(SubmitCommand submitCommand)528 : m(new AtlasScriptInterface_impl())529 {530 g_SubmitCommand = submitCommand;531 }532 533 ScriptInterface::~ScriptInterface()534 {535 }536 537 void ScriptInterface::SetCallbackData(void* cbdata)538 {539 JS_SetContextPrivate(m->m_cx, cbdata);540 }541 542 void* ScriptInterface::GetCallbackData(JSContext* cx)543 {544 return JS_GetContextPrivate(cx);545 }546 547 void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs)548 {549 m->Register(name, fptr, (uintN)nargs);550 }551 552 JSContext* ScriptInterface::GetContext()553 {554 return m->m_cx;555 }556 557 bool ScriptInterface::AddRoot(jsval* ptr)558 {559 return JS_AddValueRoot(m->m_cx, ptr) ? true : false;560 }561 562 bool ScriptInterface::RemoveRoot(jsval* ptr)563 {564 return JS_RemoveValueRoot(m->m_cx, ptr) ? true : false;565 }566 567 568 bool ScriptInterface::SetValue_(const wxString& name, jsval val)569 {570 jsval jsName = ToJSVal(m->m_cx, name);571 572 const uintN argc = 2;573 jsval argv[argc] = { jsName, val };574 jsval rval;575 JSBool ok = JS_CallFunctionName(m->m_cx, m->m_glob, "setValue", argc, argv, &rval);576 return ok ? true : false;577 }578 579 bool ScriptInterface::GetValue_(const wxString& name, jsval& ret)580 {581 jsval jsName = ToJSVal(m->m_cx, name);582 583 const uintN argc = 1;584 jsval argv[argc] = { jsName };585 JSBool ok = JS_CallFunctionName(m->m_cx, m->m_glob, "getValue", argc, argv, &ret);586 return ok ? true : false;587 }588 589 bool ScriptInterface::CallFunction(jsval val, const char* name)590 {591 jsval jsRet;592 std::vector<jsval> argv;593 return CallFunction_(val, name, argv, jsRet);594 }595 596 bool ScriptInterface::CallFunction_(jsval val, const char* name, std::vector<jsval>& args, jsval& ret)597 {598 const uintN argc = (uintN)args.size();599 jsval* argv = NULL;600 if (argc)601 argv = &args[0];602 wxCHECK(JSVAL_IS_OBJECT(val), false);603 JSBool found;604 wxCHECK(JS_HasProperty(m->m_cx, JSVAL_TO_OBJECT(val), name, &found), false);605 if (! found)606 return false;607 JSBool ok = JS_CallFunctionName(m->m_cx, JSVAL_TO_OBJECT(val), name, argc, argv, &ret);608 return ok ? true : false;609 }610 611 bool ScriptInterface::Eval(const wxString& script)612 {613 jsval rval;614 JSBool ok = JS_EvaluateScript(m->m_cx, m->m_glob, script.mb_str(), (uintN)script.length(), NULL, 0, &rval);615 return ok ? true : false;616 }617 618 bool ScriptInterface::Eval_(const wxString& script, jsval& rval)619 {620 JSBool ok = JS_EvaluateScript(m->m_cx, m->m_glob, script.mb_str(), (uintN)script.length(), NULL, 0, &rval);621 return ok ? true : false;622 }623 624 void ScriptInterface::LoadScript(const wxString& filename, const wxString& code)625 {626 size_t codeLength;627 wxMBConvUTF16 conv;628 wxCharBuffer codeUTF16 = conv.cWC2MB(code.c_str(), code.length()+1, &codeLength);629 jsval rval;630 m->LoadScript(m->m_cx, reinterpret_cast<jschar*>(codeUTF16.data()), (uintN)(codeLength/2), filename.ToAscii(), &rval);631 }632 633 ////////////////////////////////////////////////////////////////634 635 #define TYPE(elem) BOOST_PP_TUPLE_ELEM(2, 0, elem)636 #define NAME(elem) BOOST_PP_TUPLE_ELEM(2, 1, elem)637 #define MAKE_STR_(s) #s638 #define MAKE_STR(s) MAKE_STR_(s)639 640 #define CONVERT_ARGS(r, data, i, elem) \641 TYPE(elem) a##i; \642 if (! ScriptInterface::FromJSVal< TYPE(elem) >(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) \643 return JS_FALSE;644 645 #define CONVERT_OUTPUTS(r, data, i, elem) \646 JS_DefineProperty(cx, ret, MAKE_STR(NAME(elem)), ScriptInterface::ToJSVal(cx, q.NAME(elem)), \647 NULL, NULL, JSPROP_ENUMERATE);648 649 #define ARG_LIST(r, data, i, elem) BOOST_PP_COMMA_IF(i) a##i650 651 #define MESSAGE(name, vals) \652 JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \653 { \654 (void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \655 BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, vals) \656 g_MessagePasser->Add(SHAREABLE_NEW(m##name, ( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, vals) ))); \657 JS_SET_RVAL(cx, vp, JSVAL_VOID); \658 return JS_TRUE; \659 }660 661 #define COMMAND(name, merge, vals) \662 JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \663 { \664 (void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \665 BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, vals) \666 g_SubmitCommand(new AtlasMessage::m##name (AtlasMessage::d##name ( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, vals) ))); \667 JS_SET_RVAL(cx, vp, JSVAL_VOID); \668 return JS_TRUE; \669 }670 671 #define QUERY(name, in_vals, out_vals) \672 JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \673 { \674 (void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \675 BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, in_vals) \676 q##name q = q##name( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, in_vals) ); \677 q.Post(); \678 JSObject* ret = JS_NewObject(cx, NULL, NULL, NULL); \679 if (! ret) return JS_FALSE; \680 JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(ret)); \681 BOOST_PP_SEQ_FOR_EACH_I(CONVERT_OUTPUTS, ~, out_vals) \682 return JS_TRUE; \683 }684 685 #define MESSAGES_SKIP_SETUP686 #define MESSAGES_SKIP_STRUCTS687 688 // We want to include Messages.h again, with some different definitions,689 // so cheat and undefine its include-guard690 #undef INCLUDED_MESSAGES691 692 namespace693 {694 using namespace AtlasMessage;695 #include "GameInterface/Messages.h"696 }697 698 #undef MESSAGE699 #undef COMMAND700 #undef QUERY701 702 void AtlasScriptInterface_impl::RegisterMessages(JSObject* parent)703 {704 using namespace AtlasMessage;705 706 JSObject* obj = JS_DefineObject(m_cx, parent, "Message", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);707 708 #define MESSAGE(name, vals) \709 JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)vals)-1, \710 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);711 712 #define COMMAND(name, merge, vals) \713 JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)vals)-1, \714 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);715 716 #define QUERY(name, in_vals, out_vals) \717 JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)in_vals)-1, \718 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);719 720 #undef INCLUDED_MESSAGES721 722 #include "GameInterface/Messages.h"723 724 #undef MESSAGE725 #undef COMMAND726 #undef QUERY727 } -
source/tools/atlas/AtlasScript/ScriptInterface.h
1 /* Copyright (C) 2009 Wildfire Games.2 * This file is part of 0 A.D.3 *4 * 0 A.D. is free software: you can redistribute it and/or modify5 * it under the terms of the GNU General Public License as published by6 * the Free Software Foundation, either version 2 of the License, or7 * (at your option) any later version.8 *9 * 0 A.D. is distributed in the hope that it will be useful,10 * but WITHOUT ANY WARRANTY; without even the implied warranty of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12 * GNU General Public License for more details.13 *14 * You should have received a copy of the GNU General Public License15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.16 */17 18 #include <memory>19 #include <vector>20 21 #ifdef _WIN3222 # define XP_WIN23 # define WIN32 // SpiderMonkey expects this24 25 // The jsval struct type causes crashes due to weird miscompilation26 // issues in (at least) VC2008, so force it to be the less-type-safe27 // non-struct type instead28 # define JS_NO_JSVAL_JSID_STRUCT_TYPES29 30 #else31 32 # define XP_UNIX33 34 // (See comment in scriptinterface/ScriptTypes.h)35 # if defined(DEBUG) && defined(WITH_SYSTEM_MOZJS185)36 # define JS_NO_JSVAL_JSID_STRUCT_TYPES37 # endif38 39 #endif // (we don't support XP_OS2 or XP_BEOS)40 41 #ifdef __GNUC__42 # define GCC_VERSION (__GNUC__*100 + __GNUC_MINOR__)43 #else44 # define GCC_VERSION 045 #endif46 47 #ifdef _MSC_VER48 # define MSC_VERSION _MSC_VER49 #else50 # define MSC_VERSION 051 #endif52 53 // Ignore some harmless warnings triggered by jsapi.h54 #if GCC_VERSION >= 402 // (older GCCs don't support this pragma)55 # pragma GCC diagnostic ignored "-Wunused-parameter"56 # pragma GCC diagnostic ignored "-Wredundant-decls"57 #endif58 #if MSC_VERSION59 # pragma warning(push)60 # pragma warning(disable:4480) // "nonstandard extension used: specifying underlying type for enum"61 # pragma warning(disable:4100) // "unreferenced formal parameter"62 #endif63 64 #include "js/jsapi.h"65 66 #if MSC_VERSION67 # pragma warning(pop)68 #endif69 #if GCC_VERSION >= 40270 # pragma GCC diagnostic warning "-Wunused-parameter"71 # pragma GCC diagnostic warning "-Wredundant-decls"72 #endif73 74 class wxString;75 76 namespace AtlasMessage { struct mWorldCommand; }77 typedef void (*SubmitCommand)(AtlasMessage::mWorldCommand* command);78 79 struct AtlasScriptInterface_impl;80 class ScriptInterface81 {82 public:83 ScriptInterface(SubmitCommand submitCommand);84 ~ScriptInterface();85 void SetCallbackData(void* cbdata);86 static void* GetCallbackData(JSContext* cx);87 88 template <typename T> bool SetValue(const wxString& name, const T& val);89 template <typename T> bool GetValue(const wxString& name, T& ret);90 91 bool CallFunction(jsval val, const char* name);92 template <typename T, typename R>93 bool CallFunction(jsval val, const char* name, const T& a, R& ret);94 template <typename T, typename S, typename R>95 bool CallFunction(jsval val, const char* name, const T& a, const S& b, R& ret);96 97 bool Eval(const wxString& script);98 template <typename T> bool Eval(const wxString& script, T& ret);99 100 // Defined elsewhere:101 // template <TR, T0..., TR (*fptr) (void* cbdata, T0...)>102 // void RegisterFunction(const char* functionName);103 // (NOTE: The return type must be defined as a ToJSVal<TR> specialisation104 // in ScriptInterface.cpp, else you'll end up with linker errors.)105 106 void LoadScript(const wxString& filename, const wxString& code);107 108 // Convert a jsval to a C++ type. (This might trigger GC.)109 template <typename T> static bool FromJSVal(JSContext* cx, jsval val, T& ret);110 // Convert a C++ type to a jsval. (This might trigger GC. The return111 // value must be rooted if you don't want it to be collected.)112 template <typename T> static jsval ToJSVal(JSContext* cx, const T& val);113 114 bool AddRoot(jsval* ptr);115 bool RemoveRoot(jsval* ptr);116 117 JSContext* GetContext();118 119 private:120 bool SetValue_(const wxString& name, jsval val);121 bool GetValue_(const wxString& name, jsval& ret);122 bool CallFunction_(jsval val, const char* name, std::vector<jsval>& args, jsval& ret);123 bool Eval_(const wxString& name, jsval& ret);124 125 void Register(const char* name, JSNative fptr, size_t nargs);126 std::auto_ptr<AtlasScriptInterface_impl> m;127 128 // The nasty macro/template bits are split into a separate file so you don't have to look at them129 #include "NativeWrapper.inl"130 131 template <typename T>132 bool ScriptInterface::SetValue(const wxString& name, const T& val)133 {134 return SetValue_(name, ToJSVal(GetContext(), val));135 }136 137 template <typename T>138 bool ScriptInterface::GetValue(const wxString& name, T& ret)139 {140 jsval jsRet;141 if (! GetValue_(name, jsRet)) return false;142 return FromJSVal(GetContext(), jsRet, ret);143 }144 145 template <typename T, typename R>146 bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, R& ret)147 {148 jsval jsRet;149 std::vector<jsval> argv;150 argv.push_back(ToJSVal(GetContext(), a));151 bool ok = CallFunction_(val, name, argv, jsRet);152 if (! ok) return false;153 return FromJSVal(GetContext(), jsRet, ret);154 }155 156 template <typename T, typename S, typename R>157 bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, const S& b, R& ret)158 {159 jsval jsRet;160 std::vector<jsval> argv;161 argv.push_back(ToJSVal(GetContext(), a));162 argv.push_back(ToJSVal(GetContext(), b));163 bool ok = CallFunction_(val, name, argv, jsRet);164 if (! ok) return false;165 return FromJSVal(GetContext(), jsRet, ret);166 }167 168 template <typename T>169 bool ScriptInterface::Eval(const wxString& script, T& ret)170 {171 jsval jsRet;172 if (! Eval_(script, jsRet)) return false;173 return FromJSVal(GetContext(), jsRet, ret);174 }175 176 /**177 * A trivial wrapper around a jsval. Used to avoid template overload ambiguities178 * with jsval (which is just an integer), for any code that uses179 * ScriptInterface::ToJSVal or ScriptInterface::FromJSVal180 */181 class CScriptVal182 {183 public:184 CScriptVal() : m_Val(JSVAL_VOID) { }185 CScriptVal(jsval val) : m_Val(val) { }186 187 jsval get() const { return m_Val; }188 189 private:190 jsval m_Val;191 }; -
source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp
29 29 30 30 #include "GameInterface/MessagePasser.h" 31 31 32 #include "AtlasScript/ScriptInterface.h"33 34 32 #include "wx/config.h" 35 33 #include "wx/debugrpt.h" 36 34 #include "wx/file.h" … … 173 171 ///ReportError(); // janwas: disabled until ErrorReporter.cpp compiles 174 172 } 175 173 176 void ScenarioEditorSubmitCommand(AtlasMessage::mWorldCommand* command)177 {178 ScenarioEditor::GetCommandProc().Submit(new WorldCommand(command));179 }180 181 174 class AtlasDLLApp : public wxApp 182 175 { 183 176 public: 184 AtlasDLLApp()185 : m_ScriptInterface(NULL)186 {187 }188 189 ~AtlasDLLApp()190 {191 delete m_ScriptInterface;192 }193 177 194 178 virtual bool OnInit() 195 179 { … … 242 226 } 243 227 else if (g_InitialWindowType == _T("ScenarioEditor")) 244 228 { 245 m_ScriptInterface = new ScriptInterface(&ScenarioEditorSubmitCommand); 246 frame = new ScenarioEditor(NULL, *m_ScriptInterface); 229 frame = new ScenarioEditor(NULL); 247 230 } 248 231 else 249 232 { … … 315 298 */ 316 299 317 300 private: 318 ScriptInterface* m_ScriptInterface;319 301 320 302 bool OpenDirectory(const wxString& dir) 321 303 { -
source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp
40 40 #include "GameInterface/MessagePasser.h" 41 41 #include "GameInterface/Messages.h" 42 42 43 #include "AtlasScript/ScriptInterface.h"44 45 43 #include "Misc/KeyMap.h" 46 44 47 45 #include "Tools/Common/Tools.h" … … 358 356 static AtlasWindowCommandProc g_CommandProc; 359 357 AtlasWindowCommandProc& ScenarioEditor::GetCommandProc() { return g_CommandProc; } 360 358 361 ScenarioEditor::ScenarioEditor(wxWindow* parent , ScriptInterface& scriptInterface)359 ScenarioEditor::ScenarioEditor(wxWindow* parent) 362 360 : wxFrame(parent, wxID_ANY, _T(""), wxDefaultPosition, wxSize(1024, 768)) 363 , m_FileHistory(_T("Scenario Editor")) , m_ScriptInterface(scriptInterface)361 , m_FileHistory(_T("Scenario Editor")) 364 362 , m_ObjectSettings(g_SelectedObjects, AtlasMessage::eRenderView::GAME) 365 363 , m_ToolManager(this) 366 364 { -
source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h
27 27 #include "CustomControls/FileHistory/FileHistory.h" 28 28 #include "SectionLayout.h" 29 29 30 class ScriptInterface;31 32 30 class ScenarioEditor : public wxFrame 33 31 { 34 32 public: 35 ScenarioEditor(wxWindow* parent , ScriptInterface& scriptInterface);33 ScenarioEditor(wxWindow* parent); 36 34 void OnClose(wxCloseEvent& event); 37 35 void OnTimer(wxTimerEvent& event); 38 36 void OnIdle(wxIdleEvent& event); … … 66 64 67 65 static float GetSpeedModifier(); 68 66 69 ScriptInterface& GetScriptInterface() const { return m_ScriptInterface; }70 67 Observable<ObjectSettings>& GetObjectSettings() { return m_ObjectSettings; } 71 68 Observable<AtObj>& GetMapSettings() { return m_MapSettings; } 72 69 … … 75 72 void SelectPage(const wxString& classname) { m_SectionLayout.SelectPage(classname); } 76 73 77 74 private: 78 ScriptInterface& m_ScriptInterface;79 75 80 76 ToolManager m_ToolManager; 81 77 -
source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp
25 25 #include "CustomControls/SnapSplitterWindow/SnapSplitterWindow.h" 26 26 27 27 #include "ScenarioEditor.h" 28 #include "AtlasScript/ScriptInterface.h"29 28 30 29 #include "Sections/Environment/Environment.h" 31 30 #include "Sections/Map/Map.h" -
source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp
20 20 #include "Map.h" 21 21 22 22 #include "AtlasObject/AtlasObject.h" 23 #include "AtlasScript/ScriptInterface.h"24 23 #include "GameInterface/Messages.h" 25 24 #include "ScenarioEditor/ScenarioEditor.h" 26 25 #include "ScenarioEditor/Tools/Common/Tools.h" … … 186 185 if (!(*qry.settings).empty()) 187 186 { 188 187 // Prevent error if there's no map settings to parse 189 m_MapSettings = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),*qry.settings);188 m_MapSettings = AtlasObject::LoadFromJSON(*qry.settings); 190 189 } 191 190 192 191 // map name … … 275 274 { 276 275 UpdateSettingsObject(); 277 276 278 std::string json = AtlasObject::SaveToJSON(m_ ScenarioEditor.GetScriptInterface().GetContext(), m_MapSettings);277 std::string json = AtlasObject::SaveToJSON(m_MapSettings); 279 278 280 279 // TODO: would be nice if we supported undo for settings changes 281 280 … … 370 369 // Load the map sizes list 371 370 AtlasMessage::qGetMapSizes qrySizes; 372 371 qrySizes.Post(); 373 AtObj sizes = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),*qrySizes.sizes);372 AtObj sizes = AtlasObject::LoadFromJSON(*qrySizes.sizes); 374 373 wxChoice* sizeChoice = wxDynamicCast(FindWindow(ID_RandomSize), wxChoice); 375 374 for (AtIter s = sizes["Sizes"]["item"]; s.defined(); ++s) 376 375 { … … 388 387 scriptChoice->Clear(); 389 388 for (size_t i = 0; i < scripts.size(); ++i) 390 389 { 391 AtObj data = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),scripts[i]);390 AtObj data = AtlasObject::LoadFromJSON(scripts[i]); 392 391 wxString name(data["settings"]["Name"]); 393 392 scriptChoice->Append(name, new AtObjClientData(*data["settings"])); 394 393 } … … 528 527 529 528 settings.setInt("Seed", wxAtoi(wxDynamicCast(FindWindow(ID_RandomSeed), wxTextCtrl)->GetValue())); 530 529 531 std::string json = AtlasObject::SaveToJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),settings);530 std::string json = AtlasObject::SaveToJSON(settings); 532 531 533 532 wxBusyInfo busy(_("Generating map")); 534 533 wxBusyCursor busyc; -
source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp
24 24 #include "ScenarioEditor/ScenarioEditor.h" 25 25 #include "ScenarioEditor/Tools/Common/ObjectSettings.h" 26 26 #include "ScenarioEditor/Tools/Common/MiscState.h" 27 #include "AtlasScript/ScriptInterface.h"28 27 #include "VariationControl.h" 29 28 30 29 #include "GameInterface/Messages.h" … … 479 478 wxArrayString players; 480 479 AtlasMessage::qGetPlayerDefaults qryPlayers; 481 480 qryPlayers.Post(); 482 AtObj playerData = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),*qryPlayers.defaults);481 AtObj playerData = AtlasObject::LoadFromJSON(*qryPlayers.defaults); 483 482 AtObj playerDefs = *playerData["PlayerData"]; 484 483 for (AtIter p = playerDefs["item"]; p.defined(); ++p) 485 484 { -
source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp
20 20 #include "Player.h" 21 21 22 22 #include "AtlasObject/AtlasObject.h" 23 #include "AtlasScript/ScriptInterface.h"24 23 #include "CustomControls/ColourDialog/ColourDialog.h" 25 24 #include "ScenarioEditor/ScenarioEditor.h" 26 25 … … 591 590 std::vector<std::string> civData = *qryCiv.data; 592 591 for (size_t i = 0; i < civData.size(); ++i) 593 592 { 594 AtObj civ = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),civData[i]);593 AtObj civ = AtlasObject::LoadFromJSON(civData[i]); 595 594 civNames.Add(wxString(civ["Name"])); 596 595 civCodes.Add(wxString(civ["Code"])); 597 596 } … … 600 599 ArrayOfAIData ais(AIData::CompareAIData); 601 600 AtlasMessage::qGetAIData qryAI; 602 601 qryAI.Post(); 603 AtObj aiData = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),*qryAI.data);602 AtObj aiData = AtlasObject::LoadFromJSON(*qryAI.data); 604 603 for (AtIter a = aiData["AIData"]["item"]; a.defined(); ++a) 605 604 { 606 605 ais.Add(new AIData(wxString(a["id"]), wxString(a["data"]["name"]))); … … 646 645 { 647 646 AtlasMessage::qGetPlayerDefaults qryPlayers; 648 647 qryPlayers.Post(); 649 AtObj playerData = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),*qryPlayers.defaults);648 AtObj playerData = AtlasObject::LoadFromJSON(*qryPlayers.defaults); 650 649 m_PlayerDefaults = *playerData["PlayerData"]; 651 650 } 652 651 … … 658 657 if (!(*qry.settings).empty()) 659 658 { 660 659 // Prevent error if there's no map settings to parse 661 m_MapSettings = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),*qry.settings);660 m_MapSettings = AtlasObject::LoadFromJSON(*qry.settings); 662 661 } 663 662 else 664 663 { … … 946 945 { 947 946 UpdateSettingsObject(); 948 947 949 std::string json = AtlasObject::SaveToJSON(m_ ScenarioEditor.GetScriptInterface().GetContext(), m_MapSettings);948 std::string json = AtlasObject::SaveToJSON(m_MapSettings); 950 949 951 950 // TODO: would be nice if we supported undo for settings changes 952 951 -
source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp
23 23 #include "ScenarioEditor/ScenarioEditor.h" 24 24 #include "ScenarioEditor/Tools/Common/Brushes.h" 25 25 #include "ScenarioEditor/Tools/Common/MiscState.h" 26 #include "AtlasScript/ScriptInterface.h"27 26 28 27 #include "GameInterface/Messages.h" 29 28 … … 286 285 // Load the map sizes list 287 286 AtlasMessage::qGetMapSizes qrySizes; 288 287 qrySizes.Post(); 289 AtObj sizes = AtlasObject::LoadFromJSON( m_ScenarioEditor.GetScriptInterface().GetContext(),*qrySizes.sizes);288 AtObj sizes = AtlasObject::LoadFromJSON(*qrySizes.sizes); 290 289 for (AtIter s = sizes["Sizes"]["item"]; s.defined(); ++s) 291 290 { 292 291 long tiles = 0;