SWF_ScriptObject.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. idCVar swf_debugShowAddress( "swf_debugShowAddress", "0", CVAR_BOOL, "shows addresses along with object types when they are serialized" );
  23. /*
  24. ========================
  25. idSWFScriptObject::swfNamedVar_t::~swfNamedVar_t
  26. ========================
  27. */
  28. idSWFScriptObject::swfNamedVar_t::~swfNamedVar_t() {
  29. }
  30. /*
  31. ========================
  32. idSWFScriptObject::swfNamedVar_t::operator=
  33. ========================
  34. */
  35. idSWFScriptObject::swfNamedVar_t & idSWFScriptObject::swfNamedVar_t::operator=( const swfNamedVar_t & other ) {
  36. if ( &other != this ) {
  37. index = other.index;
  38. name = other.name;
  39. hashNext = other.hashNext;
  40. value = other.value;
  41. native = other.native;
  42. flags = other.flags;
  43. }
  44. return *this;
  45. }
  46. /*
  47. ========================
  48. idSWFScriptObject::idSWFScriptObject
  49. ========================
  50. */
  51. idSWFScriptObject::idSWFScriptObject() : prototype( NULL ), refCount( 1 ), noAutoDelete( false ), objectType( SWF_OBJECT_OBJECT ) {
  52. data.sprite = NULL;
  53. data.text = NULL;
  54. Clear();
  55. refCount = 1;
  56. }
  57. /*
  58. ========================
  59. idSWFScriptObject::~idSWFScriptObject
  60. ========================
  61. */
  62. idSWFScriptObject::~idSWFScriptObject() {
  63. if ( prototype != NULL ) {
  64. prototype->Release();
  65. }
  66. }
  67. /*
  68. ========================
  69. idSWFScriptObject::Alloc
  70. ========================
  71. */
  72. idSWFScriptObject * idSWFScriptObject::Alloc() {
  73. return new (TAG_SWF) idSWFScriptObject;
  74. }
  75. /*
  76. ========================
  77. idSWFScriptObject::AddRef
  78. ========================
  79. */
  80. void idSWFScriptObject::AddRef() {
  81. refCount++;
  82. }
  83. /*
  84. ========================
  85. idSWFScriptObject::Release
  86. ========================
  87. */
  88. void idSWFScriptObject::Release() {
  89. if ( --refCount == 0 && !noAutoDelete ) {
  90. delete this;
  91. }
  92. }
  93. /*
  94. ========================
  95. idSWFScriptObject::Clear
  96. ========================
  97. */
  98. void idSWFScriptObject::Clear() {
  99. variables.Clear();
  100. for ( int i = 0; i < VARIABLE_HASH_BUCKETS; i++ ) {
  101. variablesHash[i] = -1;
  102. }
  103. }
  104. /*
  105. ========================
  106. idSWFScriptObject::HasProperty
  107. ========================
  108. */
  109. bool idSWFScriptObject::HasProperty( const char * name ) {
  110. return ( GetVariable( name, false ) != NULL );
  111. }
  112. /*
  113. ========================
  114. idSWFScriptObject::HasValidProperty
  115. ========================
  116. */
  117. bool idSWFScriptObject::HasValidProperty( const char * name ) {
  118. idSWFScriptObject::swfNamedVar_t * const variable = GetVariable( name, false );
  119. if ( variable == NULL ) {
  120. return false;
  121. }
  122. if ( variable->native != NULL ) {
  123. idSWFScriptVar nv = variable->native->Get( this );
  124. if ( nv.IsNULL() || nv.IsUndefined() ) {
  125. return false;
  126. }
  127. } else {
  128. if ( variable->value.IsNULL() || variable->value.IsUndefined() ) {
  129. return false;
  130. }
  131. }
  132. return true;
  133. }
  134. /*
  135. ========================
  136. idSWFScriptObject::Get
  137. ========================
  138. */
  139. idSWFScriptVar idSWFScriptObject::Get( const char * name ) {
  140. swfNamedVar_t * variable = GetVariable( name, false );
  141. if ( variable == NULL ) {
  142. return idSWFScriptVar();
  143. } else {
  144. if ( variable->native ) {
  145. return variable->native->Get( this );
  146. } else {
  147. return variable->value;
  148. }
  149. }
  150. }
  151. /*
  152. ========================
  153. idSWFScriptObject::Get
  154. ========================
  155. */
  156. idSWFScriptVar idSWFScriptObject::Get( int index ) {
  157. swfNamedVar_t * variable = GetVariable( index, false );
  158. if ( variable == NULL ) {
  159. return idSWFScriptVar();
  160. } else {
  161. if ( variable->native ) {
  162. return variable->native->Get( this );
  163. } else {
  164. return variable->value;
  165. }
  166. }
  167. }
  168. /*
  169. ========================
  170. idSWFScriptObject::GetSprite
  171. ========================
  172. */
  173. idSWFSpriteInstance * idSWFScriptObject::GetSprite( int index ) {
  174. idSWFScriptVar var = Get( index );
  175. return var.ToSprite();
  176. }
  177. /*
  178. ========================
  179. idSWFScriptObject::GetSprite
  180. ========================
  181. */
  182. idSWFSpriteInstance * idSWFScriptObject::GetSprite( const char * name ) {
  183. idSWFScriptVar var = Get( name );
  184. return var.ToSprite();
  185. }
  186. /*
  187. ========================
  188. idSWFScriptObject::GetObject
  189. ========================
  190. */
  191. idSWFScriptObject * idSWFScriptObject::GetObject( int index ) {
  192. idSWFScriptVar var = Get( index );
  193. if ( var.IsObject() ) {
  194. return var.GetObject();
  195. }
  196. return NULL;
  197. }
  198. /*
  199. ========================
  200. idSWFScriptObject::GetObject
  201. ========================
  202. */
  203. idSWFScriptObject * idSWFScriptObject::GetObject( const char * name ) {
  204. idSWFScriptVar var = Get( name );
  205. if ( var.IsObject() ) {
  206. return var.GetObject();
  207. }
  208. return NULL;
  209. }
  210. /*
  211. ========================
  212. idSWFScriptObject::GetText
  213. ========================
  214. */
  215. idSWFTextInstance * idSWFScriptObject::GetText( int index ) {
  216. idSWFScriptVar var = Get( index );
  217. if ( var.IsObject() ) {
  218. return var.GetObject()->GetText();
  219. }
  220. return NULL;
  221. }
  222. /*
  223. ========================
  224. idSWFScriptObject::GetText
  225. ========================
  226. */
  227. idSWFTextInstance * idSWFScriptObject::GetText( const char * name ) {
  228. idSWFScriptVar var = Get( name );
  229. if ( var.IsObject() ) {
  230. return var.GetObject()->GetText();
  231. }
  232. return NULL;
  233. }
  234. /*
  235. ========================
  236. idSWFScriptObject::Set
  237. ========================
  238. */
  239. void idSWFScriptObject::Set( const char * name, const idSWFScriptVar & value ) {
  240. if ( objectType == SWF_OBJECT_ARRAY ) {
  241. if ( idStr::Cmp( name, "length" ) == 0 ) {
  242. int newLength = value.ToInteger();
  243. for ( int i = 0; i < variables.Num(); i++ ) {
  244. if ( variables[i].index >= newLength ) {
  245. variables.RemoveIndexFast( i );
  246. i--;
  247. }
  248. }
  249. // rebuild the hash table
  250. for ( int i = 0; i < VARIABLE_HASH_BUCKETS; i++ ) {
  251. variablesHash[i] = -1;
  252. }
  253. for ( int i = 0; i < variables.Num(); i++ ) {
  254. int hash = idStr::Hash( variables[i].name.c_str() ) & ( VARIABLE_HASH_BUCKETS - 1 );
  255. variables[i].hashNext = variablesHash[hash];
  256. variablesHash[hash] = i;
  257. }
  258. } else {
  259. int iName = atoi( name );
  260. if ( iName > 0 || ( iName == 0 && idStr::Cmp( name, "0" ) == 0 ) ) {
  261. swfNamedVar_t * lengthVar = GetVariable( "length", true );
  262. if ( lengthVar->value.ToInteger() <= iName ) {
  263. lengthVar->value = idSWFScriptVar( iName + 1 );
  264. }
  265. }
  266. }
  267. }
  268. swfNamedVar_t * variable = GetVariable( name, true );
  269. if ( variable->native ) {
  270. variable->native->Set( this, value );
  271. } else if ( ( variable->flags & SWF_VAR_FLAG_READONLY ) == 0 ) {
  272. variable->value = value;
  273. }
  274. }
  275. /*
  276. ========================
  277. idSWFScriptObject::Set
  278. ========================
  279. */
  280. void idSWFScriptObject::Set( int index, const idSWFScriptVar & value ) {
  281. if ( index < 0 ) {
  282. extern idCVar swf_debug;
  283. if ( swf_debug.GetBool() ) {
  284. idLib::Printf( "SWF: Trying to set a negative array index.\n" );
  285. }
  286. return;
  287. }
  288. if ( objectType == SWF_OBJECT_ARRAY ) {
  289. swfNamedVar_t * lengthVar = GetVariable( "length", true );
  290. if ( lengthVar->value.ToInteger() <= index ) {
  291. lengthVar->value = idSWFScriptVar( index + 1 );
  292. }
  293. }
  294. swfNamedVar_t * variable = GetVariable( index, true );
  295. if ( variable->native ) {
  296. variable->native->Set( this, value );
  297. } else if ( ( variable->flags & SWF_VAR_FLAG_READONLY ) == 0 ) {
  298. variable->value = value;
  299. }
  300. }
  301. /*
  302. ========================
  303. idSWFScriptObject::SetNative
  304. ========================
  305. */
  306. void idSWFScriptObject::SetNative( const char * name, idSWFScriptNativeVariable * native ) {
  307. swfNamedVar_t * variable = GetVariable( name, true );
  308. variable->flags = SWF_VAR_FLAG_DONTENUM;
  309. variable->native = native;
  310. if ( native->IsReadOnly() ) {
  311. variable->flags |= SWF_VAR_FLAG_READONLY;
  312. }
  313. }
  314. /*
  315. ========================
  316. idSWFScriptObject::DefaultValue
  317. ========================
  318. */
  319. idSWFScriptVar idSWFScriptObject::DefaultValue( bool stringHint ) {
  320. const char * methods[2] = { "toString", "valueOf" };
  321. if ( !stringHint ) {
  322. SwapValues( methods[0], methods[1] );
  323. }
  324. for ( int i = 0; i < 2; i++ ) {
  325. idSWFScriptVar method = Get( methods[i] );
  326. if ( method.IsFunction() ) {
  327. idSWFScriptVar value = method.GetFunction()->Call( this, idSWFParmList() );
  328. if ( !value.IsObject() && !value.IsFunction() ) {
  329. return value;
  330. }
  331. }
  332. }
  333. switch ( objectType ) {
  334. case SWF_OBJECT_OBJECT:
  335. if ( swf_debugShowAddress.GetBool() ) {
  336. return idSWFScriptVar( va( "[object:%p]", this ) );
  337. } else {
  338. return idSWFScriptVar( "[object]" );
  339. }
  340. case SWF_OBJECT_ARRAY:
  341. if ( swf_debugShowAddress.GetBool() ) {
  342. return idSWFScriptVar( va( "[array:%p]", this ) );
  343. } else {
  344. return idSWFScriptVar( "[array]" );
  345. }
  346. case SWF_OBJECT_SPRITE:
  347. if ( data.sprite != NULL ) {
  348. if ( data.sprite->parent == NULL ) {
  349. return idSWFScriptVar( "[_root]" );
  350. } else {
  351. return idSWFScriptVar( va( "[%s]", data.sprite->GetName() ) );
  352. }
  353. } else {
  354. return idSWFScriptVar( "[NULL]" );
  355. }
  356. case SWF_OBJECT_TEXT:
  357. if ( swf_debugShowAddress.GetBool() ) {
  358. return idSWFScriptVar( va( "[edittext:%p]", this ) );
  359. } else {
  360. return idSWFScriptVar( "[edittext]" );
  361. }
  362. }
  363. return idSWFScriptVar( "[unknown]" );
  364. }
  365. /*
  366. ========================
  367. idSWFScriptObject::GetVariable
  368. ========================
  369. */
  370. idSWFScriptObject::swfNamedVar_t * idSWFScriptObject::GetVariable( int index, bool create ) {
  371. for ( int i = 0; i < variables.Num(); i++ ) {
  372. if ( variables[i].index == index ) {
  373. return &variables[i];
  374. }
  375. }
  376. if ( create ) {
  377. swfNamedVar_t * variable = &variables.Alloc();
  378. variable->flags = SWF_VAR_FLAG_NONE;
  379. variable->index = index;
  380. variable->name = va( "%d", index );
  381. variable->native = NULL;
  382. int hash = idStr::Hash( variable->name ) & ( VARIABLE_HASH_BUCKETS - 1 );
  383. variable->hashNext = variablesHash[hash];
  384. variablesHash[hash] = variables.Num() - 1;
  385. return variable;
  386. }
  387. return NULL;
  388. }
  389. /*
  390. ========================
  391. idSWFScriptObject::GetVariable
  392. ========================
  393. */
  394. idSWFScriptObject::swfNamedVar_t * idSWFScriptObject::GetVariable( const char * name, bool create ) {
  395. int hash = idStr::Hash( name ) & ( VARIABLE_HASH_BUCKETS - 1 );
  396. for ( int i = variablesHash[hash]; i >= 0; i = variables[i].hashNext ) {
  397. if ( variables[i].name == name ) {
  398. return &variables[i];
  399. }
  400. }
  401. if ( prototype != NULL ) {
  402. swfNamedVar_t * variable = prototype->GetVariable( name, false );
  403. if ( ( variable != NULL ) && ( variable->native || !create ) ) {
  404. // If the variable is native, we want to pull it from the prototype even if we're going to set it
  405. return variable;
  406. }
  407. }
  408. if ( create ) {
  409. swfNamedVar_t * variable = &variables.Alloc();
  410. variable->flags = SWF_VAR_FLAG_NONE;
  411. variable->index = atoi( name );
  412. if ( variable->index == 0 && idStr::Cmp( name, "0" ) != 0 ) {
  413. variable->index = -1;
  414. }
  415. variable->name = name;
  416. variable->native = NULL;
  417. variable->hashNext = variablesHash[hash];
  418. variablesHash[hash] = variables.Num() - 1;
  419. return variable;
  420. }
  421. return NULL;
  422. }
  423. /*
  424. ========================
  425. idSWFScriptObject::MakeArray
  426. ========================
  427. */
  428. void idSWFScriptObject::MakeArray() {
  429. objectType = SWF_OBJECT_ARRAY;
  430. swfNamedVar_t * variable = GetVariable( "length", true );
  431. variable->value = idSWFScriptVar( 0 );
  432. variable->flags = SWF_VAR_FLAG_DONTENUM;
  433. }
  434. /*
  435. ========================
  436. idSWFScriptObject::GetNestedVar
  437. ========================
  438. */
  439. idSWFScriptVar idSWFScriptObject::GetNestedVar( const char * arg1, const char * arg2, const char * arg3, const char * arg4, const char * arg5, const char * arg6 ) {
  440. const char * const args[] = { arg1, arg2, arg3, arg4, arg5, arg6 };
  441. const int numArgs = sizeof( args ) / sizeof( const char * );
  442. idStaticList< const char *, numArgs > vars;
  443. for ( int i = 0; i < numArgs && args[ i ] != NULL; ++i ) {
  444. vars.Append( args[ i ] );
  445. }
  446. idSWFScriptObject * baseObject = this;
  447. idSWFScriptVar retVal;
  448. for ( int i = 0; i < vars.Num(); ++i ) {
  449. idSWFScriptVar var = baseObject->Get( vars[ i ] );
  450. // when at the end of object path just use the latest value as result
  451. if ( i == vars.Num() - 1 ) {
  452. retVal = var;
  453. break;
  454. }
  455. // encountered variable in path that wasn't an object
  456. if ( !var.IsObject() ) {
  457. retVal = idSWFScriptVar();
  458. break;
  459. }
  460. baseObject = var.GetObject();
  461. }
  462. return retVal;
  463. }
  464. /*
  465. ========================
  466. idSWFScriptObject::GetNestedObj
  467. ========================
  468. */
  469. idSWFScriptObject * idSWFScriptObject::GetNestedObj( const char * arg1, const char * arg2, const char * arg3, const char * arg4, const char * arg5, const char * arg6 ) {
  470. idSWFScriptVar var = GetNestedVar( arg1, arg2, arg3, arg4, arg5, arg6 );
  471. if ( !var.IsObject() ) {
  472. return NULL;
  473. }
  474. return var.GetObject();
  475. }
  476. /*
  477. ========================
  478. idSWFScriptObject::GetNestedSprite
  479. ========================
  480. */
  481. idSWFSpriteInstance * idSWFScriptObject::GetNestedSprite( const char * arg1, const char * arg2, const char * arg3, const char * arg4, const char * arg5, const char * arg6 ) {
  482. idSWFScriptVar var = GetNestedVar( arg1, arg2, arg3, arg4, arg5, arg6 );
  483. return var.ToSprite();
  484. }
  485. /*
  486. ========================
  487. idSWFScriptObject::GetNestedText
  488. ========================
  489. */
  490. idSWFTextInstance * idSWFScriptObject::GetNestedText( const char * arg1, const char * arg2, const char * arg3, const char * arg4, const char * arg5, const char * arg6 ) {
  491. idSWFScriptVar var = GetNestedVar( arg1, arg2, arg3, arg4, arg5, arg6 );
  492. return var.ToText();
  493. }
  494. /*
  495. ========================
  496. idSWFScriptObject::PrintToConsole
  497. ========================
  498. */
  499. void idSWFScriptObject::PrintToConsole() const {
  500. if ( variables.Num() > 0 ) {
  501. idLib::Printf( "%d subelements:\n", variables.Num() );
  502. int maxVarLength = 0;
  503. for ( int i = 0; i < variables.Num(); ++i ) {
  504. const idSWFScriptObject::swfNamedVar_t & nv = variables[ i ];
  505. const int nameLength = idStr::Length( nv.name );
  506. if ( maxVarLength < nameLength ) {
  507. maxVarLength = nameLength;
  508. }
  509. }
  510. maxVarLength += 2; // a little extra padding
  511. const char * const fmt = va( "%%-%ds %%-10s %%-s\n", maxVarLength );
  512. idLib::Printf( fmt, "Name", "Type", "Value" );
  513. idLib::Printf( "------------------------------------------------------------\n" );
  514. for ( int i = 0; i < variables.Num(); ++i ) {
  515. const idSWFScriptObject::swfNamedVar_t & nv = variables[ i ];
  516. idLib::Printf( fmt, nv.name.c_str(), nv.value.TypeOf(),
  517. nv.value.ToString().c_str() );
  518. }
  519. } else {
  520. idLib::Printf( "No subelements\n" );
  521. }
  522. }