PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Server/SWXPHP/2.00/php/core/swx/SwxAS3Assembler.php

http://swx-format.googlecode.com/
PHP | 618 lines | 469 code | 122 blank | 27 comment | 29 complexity | 4da66dca44090bcd0dc339a58fde99da MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
  1. <?php
  2. include_once('core/swx/as3/datatypes.php');
  3. include_once('core/swx/as3/swfHeader.php');
  4. include_once('core/swx/as3/tag.php');
  5. include_once('core/swx/as3/tags.php');
  6. include_once('core/swx/as3/method_info.php');
  7. include_once('core/swx/as3/class_info.php');
  8. include_once('core/swx/as3/script_info.php');
  9. include_once('core/swx/as3/instance_info.php');
  10. include_once('core/swx/as3/method_body_info.php');
  11. include_once('core/swx/as3/avm2_instructions.php');
  12. include_once('core/swx/as3/traits_info.php');
  13. include_once('core/swx/as3/namespace.php');
  14. include_once('core/swx/as3/multiname.php');
  15. include_once('core/swx/as3/abcFile.php');
  16. include_once('core/swx/as3/asmUtility.php');
  17. include_once('core/swx/as3/constantPool.php');
  18. include_once("core/swx/as3/abcArray.php");
  19. // PHP 5 compatibility layer for PHP 4
  20. require_once('lib/str_split.php');
  21. class SwxAS3Assembler
  22. {
  23. var $header;
  24. var $tags;
  25. var $datastack;
  26. var $stackcounter = 0;
  27. var $maxstack = 0;
  28. var $data = '';
  29. var $currentABC = null;
  30. var $utility;
  31. var $url = '';
  32. function SwxAS3Assembler()
  33. {
  34. $this->header = new swfHeader();
  35. $this->tags = array();
  36. $this->tags[] = new FileAttributesTag();
  37. $this->datastack = array();
  38. $this->utility = new asmUtility();
  39. }
  40. function dump()
  41. {
  42. echo "Dumping:<br/>";
  43. echo $this->header->dump();
  44. foreach($this->tags as $tag)
  45. $tag->dump();
  46. }
  47. function compile($compressionLevel=0)
  48. {
  49. $this->header->setCompressed($compressionLevel>0);
  50. $data = '';
  51. foreach($this->tags as $tag)
  52. $data .= $tag->getTagContent();
  53. $header = $this->header->getPacked();
  54. $len = strlen($header)+strlen($data);
  55. $this->header->filelength->set($len);
  56. $data = $this->header->getPacked() . $data;
  57. if ($compressionLevel > 0)
  58. {
  59. $compressionStartTime = $this->microtime_float();
  60. // The first eight bytes are uncompressed
  61. $uncompressedBytes = substr($data, 0, 8);
  62. // Remove first eight bytes
  63. $data = substr_replace($data, '', 0, 8);
  64. // Compress the rest of the SWF
  65. $data = gzcompress($data, $compressionLevel);
  66. // Add the uncompressed header
  67. $data = $uncompressedBytes . $data;
  68. $compressionDuration = $this->microtime_float() - $compressionStartTime;
  69. if (LOG_ALL) error_log('[SWX] PROFILING: SWF compression took ' . $compressionDuration . ' seconds.');
  70. // Stats
  71. $compressedSize = strlen($data);
  72. if (LOG_ALL) error_log('[SWX] INFO Compressed size of SWF: ' . $compressedSize . ' bytes.');
  73. }
  74. $this->data = $data;
  75. }
  76. function writeToFile($file)
  77. {
  78. $fp = fopen($file, 'w');
  79. fwrite($fp, $this->data);
  80. fclose($fp);
  81. }
  82. function hexdump ($data = null, $htmloutput = true, $uppercase = false, $return = false)
  83. {
  84. if ($data==null)
  85. $data = $this->data;
  86. // Init
  87. $hexi = '';
  88. $ascii = '';
  89. $dump = ($htmloutput === true) ? '<pre>' : '';
  90. $offset = 0;
  91. $len = strlen($data);
  92. // Upper or lower case hexidecimal
  93. $x = ($uppercase === false) ? 'x' : 'X';
  94. // Iterate string
  95. for ($i = $j = 0; $i < $len; $i++)
  96. {
  97. // Convert to hexidecimal
  98. $hexi .= sprintf("%02$x ", ord($data[$i]));
  99. // Replace non-viewable bytes with '.'
  100. if (ord($data[$i]) >= 32) {
  101. $ascii .= ($htmloutput === true) ?
  102. htmlentities($data[$i]) :
  103. $data[$i];
  104. } else {
  105. $ascii .= '.';
  106. }
  107. // Add extra column spacing
  108. if ($j === 7) {
  109. $hexi .= ' ';
  110. $ascii .= ' ';
  111. }
  112. // Add row
  113. if (++$j === 16 || $i === $len - 1) {
  114. // Join the hexi / ascii output
  115. $dump .= sprintf("%04$x %-49s %s", $offset, $hexi, $ascii);
  116. // Reset vars
  117. $hexi = $ascii = '';
  118. $offset += 16;
  119. $j = 0;
  120. // Add newline
  121. if ($i !== $len - 1) {
  122. $dump .= "\n";
  123. }
  124. }
  125. }
  126. // Finish dump
  127. $dump .= $htmloutput === true ?
  128. '</pre>' :
  129. '';
  130. $dump .= "\n";
  131. // Output method
  132. if ($return === false) {
  133. echo $dump;
  134. } else {
  135. return $dump;
  136. }
  137. }
  138. function writeSwf($data, $debug = false, $compressionLevel = 4, $url = '')
  139. {
  140. $this->url = $url;
  141. $this->prepareContent($data, 'result', $debug);
  142. $this->compile($compressionLevel);
  143. $nonFatalErrors = trim(ob_get_contents());
  144. @ob_end_clean();
  145. if (strlen($nonFatalErrors) > 0) echo $nonFatalErrors;
  146. else {
  147. header('Content-Type: application/swf;');
  148. header('Content-Disposition: inline; filename="data.swf"');
  149. header('Content-Length: ' . strlen($this->data));
  150. echo $this->data;
  151. }
  152. }
  153. function prepareContent(&$data, $varname = 'result', $debug=false)
  154. {
  155. $abc = new DoAbc(kDoAbcLazyInitializeFlag);
  156. $abcFile = &$abc->abcFile;
  157. $this->currentABC = &$abc;
  158. $stringpool = &$abcFile->constant_pool->string;
  159. $stringpool->add(new UTF8String(''),'_blank_');
  160. $stringpool->add(new UTF8String('swxResponse'),'swxResponse');
  161. $stringpool->add(new UTF8String('flash.display'),'flash.display');
  162. $stringpool->add(new UTF8String('MovieClip'),'MovieClip');
  163. $stringpool->add(new UTF8String("$varname"),"$varname");
  164. $stringpool->add(new UTF8String('Object'),'Object');
  165. $stringpool->add(new UTF8String('flash.events'),'flash.events');
  166. $stringpool->add(new UTF8String('EventDispatcher'),'EventDispatcher');
  167. $stringpool->add(new UTF8String('DisplayObject'),'DisplayObject');
  168. $stringpool->add(new UTF8String('InteractiveObject'),'InteractiveObject');
  169. $stringpool->add(new UTF8String('DisplayObjectContainer'),'DisplayObjectContainer');
  170. $stringpool->add(new UTF8String('Sprite'),'Sprite');
  171. $namespacepool = &$abcFile->constant_pool->namespace;
  172. $namespacepool->add(new namespace_info(CONSTANT_PackageNamespace,$stringpool->getIndexOf('_blank_')),'*');
  173. $namespacepool->add(new namespace_info(CONSTANT_PackageNamespace,$stringpool->getIndexOf('flash.display')),'flash.display');
  174. $namespacepool->add(new namespace_info(CONSTANT_ProtectedNamespace,$stringpool->getIndexOf('swxResponse')),'swxResponse');
  175. $namespacepool->add(new namespace_info(CONSTANT_PackageInternalNs,$stringpool->getIndexOf('_blank_')),'_blank_');
  176. $namespacepool->add(new namespace_info(CONSTANT_PackageNamespace,$stringpool->getIndexOf('flash.events')),'flash.events');
  177. $multinamepool = &$abcFile->constant_pool->multiname;
  178. $multinamepool->addQname('*','swxResponse',$abcFile->constant_pool);
  179. $multinamepool->addQname('flash.display','MovieClip',$abcFile->constant_pool);
  180. $multinamepool->addQname('*',"$varname",$abcFile->constant_pool);
  181. $multinamepool->addQname('*','Object',$abcFile->constant_pool);
  182. $multinamepool->addQname('flash.events','EventDispatcher',$abcFile->constant_pool);
  183. $multinamepool->addQname('flash.display','DisplayObject',$abcFile->constant_pool);
  184. $multinamepool->addQname('flash.display','InteractiveObject',$abcFile->constant_pool);
  185. $multinamepool->addQname('flash.display','DisplayObjectContainer',$abcFile->constant_pool);
  186. $multinamepool->addQname('flash.display','Sprite',$abcFile->constant_pool);
  187. $method = &$abcFile->method;
  188. $method->add(new method_info(CONSTANT_AnonymousMethod, CONSTANT_ReturnAny, array(), NO_FLAG),'staticinitializer');
  189. $method->add(new method_info(CONSTANT_AnonymousMethod, CONSTANT_ReturnAny, array(), NO_FLAG),'constructor');
  190. $method->add(new method_info(CONSTANT_AnonymousMethod, CONSTANT_ReturnAny, array(), NO_FLAG),'scriptinit');
  191. $instance = &$abcFile->instance;
  192. $instance->add( new instance_info(
  193. $multinamepool->getIndexOf('*:swxResponse'),
  194. $multinamepool->getIndexOf('flash.display:MovieClip'),
  195. CONSTANT_ClassProtectedNs | CONSTANT_ClassSealed,
  196. $namespacepool->getIndexOf('swxResponse'),
  197. array(),
  198. $method->getIndexOf('constructor'),
  199. array(
  200. $this->utility->makeSlot($multinamepool->getIndexOf("*:$varname"),0,0,0,0)
  201. )
  202. ));
  203. $class = &$abcFile->class;
  204. $class->add (new class_info(
  205. $method->getIndexOf('staticinitializer'),
  206. array()
  207. ),'swxResponse');
  208. $script = &$abcFile->script;
  209. $script->add (new script_info(
  210. $method->getIndexOf('scriptinit'),
  211. array(
  212. $this->utility->makeClass($multinamepool->getIndexOf('*:swxResponse'),/*slot_id*/1,$class->getIndexOf('swxResponse'))
  213. )
  214. ));
  215. $this->mainABCFile = &$abcFile;
  216. $this->createDataOperations($data);
  217. if ($this->url!='')
  218. {
  219. $stringpool->add(new UTF8String('flash.system'),'flash.system');
  220. $stringpool->add(new UTF8String('Security'),'Security');
  221. $stringpool->add(new UTF8String($this->url),$this->url);
  222. $stringpool->add(new UTF8String('allowDomain'),'allowDomain');
  223. $namespacepool->add(new namespace_info(CONSTANT_PackageNamespace,$stringpool->getIndexOf('flash.system')),'flash.system');
  224. $multinamepool->addQname('flash.system','Security',$abcFile->constant_pool);
  225. $multinamepool->addQname('*','allowDomain',$abcFile->constant_pool);
  226. $instructions = array(
  227. new instruction(op_getlocal0),
  228. new instruction(op_pushscope),
  229. $this->utility->getlex($multinamepool->getIndexOf('flash.system:Security')),
  230. new instruction(op_pushstring, new U30($stringpool->getIndexOf($this->url))),
  231. $this->utility->callpropvoid($multinamepool->getIndexOf('*:allowDomain'),1),
  232. new instruction(op_returnvoid)
  233. );
  234. $max_stack = 2;
  235. }
  236. else
  237. {
  238. $instructions = array(
  239. new instruction(op_getlocal0),
  240. new instruction(op_pushscope),
  241. new instruction(op_returnvoid)
  242. );
  243. $max_stack = 1;
  244. }
  245. $method_body = &$abcFile->method_body;
  246. $method_body->add(
  247. new method_body_info( /* $method, $max_stack, $local_count, $init_scope_depth, $max_scope_depth, $code, $exceptions, $traits */
  248. $method->getIndexOf('staticinitializer'),$max_stack,1,9,10,
  249. $instructions,
  250. array(),
  251. array()
  252. )
  253. );
  254. if ($debug)
  255. {
  256. $stringpool->add(new UTF8String('flash.net'),'flash.net');
  257. $stringpool->add(new UTF8String('LocalConnection'),'LocalConnection');
  258. $stringpool->add(new UTF8String('debug'),'debug');
  259. $stringpool->add(new UTF8String('send'),'send');
  260. $stringpool->add(new UTF8String('x'),'x'); // Wrap root object in another for the analyzer
  261. $stringpool->add(new UTF8String('_swxDebugger'),'_swxDebugger');
  262. $namespacepool->add(new namespace_info(CONSTANT_PackageNamespace,$stringpool->getIndexOf('flash.net')),'flash.net');
  263. $multinamepool->addQname('flash.net','LocalConnection',$abcFile->constant_pool);
  264. $multinamepool->addQname('*','send',$abcFile->constant_pool);
  265. $constructor_maxstack_offset = 4;
  266. $constructor_local_count = 2;
  267. }
  268. else
  269. {
  270. // No debug
  271. $constructor_maxstack_offset = 2;
  272. $constructor_local_count = 1;
  273. }
  274. $method_body->add(
  275. new method_body_info(
  276. //$method->getIndexOf('constructor'),$this->maxstack+2,1,10,11,
  277. $method->getIndexOf('constructor'),$this->maxstack+$constructor_maxstack_offset,$constructor_local_count,10,11,
  278. array_merge(
  279. array(
  280. new instruction(op_getlocal0),
  281. new instruction(op_pushscope),
  282. $this->utility->findproperty($multinamepool->getIndexOf("*:$varname")),
  283. ),
  284. $this->datastack,
  285. array_merge(
  286. array(
  287. $this->utility->initproperty($multinamepool->getIndexOf("*:$varname")),
  288. new instruction(op_getlocal0),
  289. $this->utility->constructsuper(0),
  290. ),
  291. $debug ? array(
  292. // Debug is on: write the LocalConnection call.
  293. $this->utility->findpropstrict($multinamepool->getIndexOf('flash.net:LocalConnection')),
  294. $this->utility->constructprop($multinamepool->getIndexOf('flash.net:LocalConnection'), 0),
  295. $this->utility->coerce($multinamepool->getIndexOf('flash.net:LocalConnection')),
  296. new instruction(op_setlocal1),
  297. new instruction(op_getlocal1),
  298. new instruction(op_pushstring, new U30($stringpool->getIndexOf('_swxDebugger'))),
  299. new instruction(op_pushstring, new U30($stringpool->getIndexOf('debug'))),
  300. // Wrap the result in an object -- this is what the analyzer expects
  301. // (it fails on simple datatypes). Calling the attribute x for brevity
  302. // as it doesn't matter what it's called.
  303. new instruction(op_pushstring, new U30($stringpool->getIndexOf('x'))),
  304. $this->utility->getlex($multinamepool->getIndexOf("*:$varname")),
  305. $this->utility->newobject(1),
  306. $this->utility->callpropvoid($multinamepool->getIndexOf('*:send'),3),
  307. ): array(),
  308. array(
  309. new instruction(op_returnvoid)
  310. )
  311. )
  312. ),
  313. array(),
  314. array()
  315. )
  316. );
  317. $method_body->add(
  318. new method_body_info(
  319. $method->getIndexOf('scriptinit'),2,1,1,9,
  320. array(
  321. new instruction(op_getlocal0),
  322. new instruction(op_pushscope),
  323. new instruction(op_getscopeobject,new U8(0)),
  324. $this->utility->getlex($multinamepool->getIndexOf('*:Object')),
  325. new instruction(op_pushscope),
  326. $this->utility->getlex($multinamepool->getIndexOf('flash.events:EventDispatcher')),
  327. new instruction(op_pushscope),
  328. $this->utility->getlex($multinamepool->getIndexOf('flash.display:DisplayObject')),
  329. new instruction(op_pushscope),
  330. $this->utility->getlex($multinamepool->getIndexOf('flash.display:InteractiveObject')),
  331. new instruction(op_pushscope),
  332. $this->utility->getlex($multinamepool->getIndexOf('flash.display:DisplayObjectContainer')),
  333. new instruction(op_pushscope),
  334. $this->utility->getlex($multinamepool->getIndexOf('flash.display:Sprite')),
  335. new instruction(op_pushscope),
  336. $this->utility->getlex($multinamepool->getIndexOf('flash.display:MovieClip')),
  337. new instruction(op_pushscope),
  338. $this->utility->getlex($multinamepool->getIndexOf('flash.display:MovieClip')),
  339. $this->utility->newclass($class->getIndexOf('swxResponse')),
  340. new instruction(op_popscope),
  341. new instruction(op_popscope),
  342. new instruction(op_popscope),
  343. new instruction(op_popscope),
  344. new instruction(op_popscope),
  345. new instruction(op_popscope),
  346. new instruction(op_popscope),
  347. $this->utility->initproperty($multinamepool->getIndexOf('*:swxResponse')),
  348. new instruction(op_returnvoid)
  349. ),
  350. array(),
  351. array()
  352. )
  353. );
  354. $this->tags[] = $abc;
  355. /* this tag seems necessary for flash to start interpreting the content. without it no error, but no 'result' */
  356. $symbolclass = new SymbolClass();
  357. $symbolclass->addSymbol(0,"swxResponse");
  358. $this->tags[] = $symbolclass;
  359. $this->tags[] = new ShowFrame();
  360. $this->tags[] = new EndTag();
  361. }
  362. function createDataOperations(&$data)
  363. {
  364. if ($data===NULL)
  365. $this->createDataOperations_NULL();
  366. elseif (is_integer($data))
  367. $this->createDataOperations_integer($data);
  368. elseif (is_string($data))
  369. $this->createDataOperations_string($data);
  370. elseif (is_bool($data))
  371. $this->createDataOperations_boolean($data);
  372. elseif (is_double($data))
  373. $this->createDataOperations_double($data);
  374. elseif (is_array($data))
  375. $this->createDataOperations_array($data);
  376. elseif (is_object($data))
  377. $this->createDataOperations_object($data);
  378. else
  379. trigger_error('Unhandled data type ('.gettype($data).')', E_USER_ERROR);
  380. }
  381. function createDataOperations_integer(&$data)
  382. {
  383. if ($data <= 255 && $data >=0)
  384. {
  385. $this->stackCounterPlus();
  386. $this->datastack[]= new instruction(op_pushbyte, new U8($data));
  387. }
  388. else
  389. {
  390. $index = $this->mainABCFile->constant_pool->integer->getIndexOf($data);
  391. if ($index === FALSE)
  392. {
  393. $index = $this->mainABCFile->constant_pool->integer->add(new S32($data),$data);
  394. }
  395. $this->stackCounterPlus();
  396. $this->datastack[]= new instruction(op_pushint, new U30($index));
  397. }
  398. }
  399. function createDataOperations_boolean(&$data)
  400. {
  401. $this->stackCounterPlus();
  402. if ($data===TRUE)
  403. $this->datastack[]= new instruction(op_pushtrue);
  404. else
  405. $this->datastack[]= new instruction(op_pushfalse);
  406. }
  407. function createDataOperations_NULL()
  408. {
  409. $this->stackCounterPlus();
  410. $this->datastack[]= new instruction(op_pushnull);
  411. }
  412. function createDataOperations_double(&$data)
  413. {
  414. $this->stackCounterPlus();
  415. $index = $this->mainABCFile->constant_pool->double->getIndexOf('dbl_'.$data);
  416. if ($index === FALSE)
  417. {
  418. $index = $this->mainABCFile->constant_pool->double->add(new D64($data),'dbl_'.$data);
  419. }
  420. $this->stackCounterPlus();
  421. $this->datastack[]= new instruction(op_pushdouble, new U30($index));
  422. }
  423. function createDataOperations_string(&$data)
  424. {
  425. $index = $this->mainABCFile->constant_pool->string->getIndexOf($data);
  426. if ($index === FALSE)
  427. {
  428. $index = $this->mainABCFile->constant_pool->string->add(new UTF8String($data),$data);
  429. }
  430. $this->stackCounterPlus();
  431. $this->datastack[]= new instruction(op_pushstring, new U30($index));
  432. }
  433. function createDataOperations_array(&$data)
  434. {
  435. $arrCount = count($data);
  436. // Determine array type
  437. $keys = array_keys($data);
  438. if ($arrCount == 0)
  439. {
  440. $this->stackCounterPlus(1); // the empty array's pointer will be pushed into the stack
  441. $this->datastack[] = new instruction(op_newarray,new U30(0));
  442. }
  443. elseif (is_integer($keys[0]) == 'integer')
  444. {
  445. foreach($data as $item)
  446. {
  447. $this->createDataOperations($item);
  448. }
  449. $this->stackCounterMinus($arrCount-1); // all elements popped, array pointer pushed
  450. $this->datastack[] = new instruction(op_newarray,new U30($arrCount));
  451. }
  452. else
  453. {
  454. $this->createDataOperations_object($data);
  455. }
  456. }
  457. function createDataOperations_object(&$data)
  458. {
  459. $props_count = 0;
  460. foreach($data as $key => $value)
  461. {
  462. $keyindex = $this->mainABCFile->constant_pool->string->getIndexOf($key);
  463. if ($keyindex === FALSE)
  464. {
  465. $keyindex = $this->mainABCFile->constant_pool->string->add(new UTF8String($key),$key);
  466. }
  467. $this->stackCounterPlus();
  468. $this->datastack[] = new instruction(op_pushstring, new U30($keyindex));
  469. $this->createDataOperations($value);
  470. $props_count++;
  471. }
  472. $this->stackCounterMinus(($props_count*2)-1); // props_count x 2 (1 property/value pair) popped, object pointer pushed
  473. $this->datastack[] = new instruction(op_newobject,new U30($props_count));
  474. }
  475. /** Count maximum amount of entries ever add on the stack when building operations list to rebuild result **/
  476. function stackCounterPlus()
  477. {
  478. $this->stackcounter++;
  479. if ($this->stackcounter>$this->maxstack)
  480. $this->maxstack = $this->stackcounter;
  481. }
  482. function stackCounterMinus($amount=1)
  483. {
  484. $this->stackcounter-=$amount;
  485. }
  486. function stackCounterClear()
  487. {
  488. $this->stackcounter = 0;
  489. }
  490. function microtime_float()
  491. {
  492. list($usec, $sec) = explode(" ", microtime());
  493. return ((float)$usec + (float)$sec);
  494. }
  495. }
  496. ?>