PageRenderTime 135ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/examples/FlexDemo/src/framework/debug/MonsterDebugger.as

https://github.com/talltyler/ASTRID
ActionScript | 1605 lines | 1086 code | 198 blank | 321 comment | 262 complexity | 43c56fe9816cd573a277ede5a907b06f MD5 | raw file
  1. /**
  2. *
  3. * This is the client code that needs to be implemented into a
  4. * Flash, AIR or FLEX application to collect debug information
  5. * in De MonsterDebugger.
  6. *
  7. * Be aware that any traces made to De MonsterDebugger may
  8. * be viewed by others. De Monster Debugger is intended to be
  9. * used to debug unpublished Flash, AIR of FLEX applications in
  10. * the environment that they will be used in as a final product.
  11. * Please make sure that you do not send any debug material to
  12. * the debugger from a live running application.
  13. *
  14. * Use at your own risk.
  15. *
  16. * @author Ferdi Koomen
  17. * @company De Monsters
  18. * @link http://www.deMonsterDebugger.com
  19. * @version 2.04
  20. *
  21. *
  22. * Special thanks to Arjan van Wijk from MediaMonks.nl
  23. *
  24. *
  25. * Copyright 2009, De Monsters
  26. *
  27. * This program is free software: you can redistribute it and/or modify
  28. * it under the terms of the GNU General Public License as published by
  29. * the Free Software Foundation, either version 3 of the License, or
  30. * (at your option) any later version.
  31. *
  32. * This program is distributed in the hope that it will be useful,
  33. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  34. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  35. * GNU Lesser General Public License for more details.
  36. *
  37. * You should have received a copy of the GNU Lesser General Public License
  38. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  39. *
  40. */
  41. package framework.debug
  42. {
  43. import flash.display.Bitmap;
  44. import flash.display.BitmapData;
  45. import flash.display.DisplayObject;
  46. import flash.display.DisplayObjectContainer;
  47. import flash.display.Sprite;
  48. import flash.events.AsyncErrorEvent;
  49. import flash.events.SecurityErrorEvent;
  50. import flash.events.StatusEvent;
  51. import flash.events.TimerEvent;
  52. import flash.events.Event;
  53. import flash.net.LocalConnection;
  54. import flash.geom.Rectangle;
  55. import flash.utils.ByteArray;
  56. import flash.utils.Timer;
  57. import flash.utils.getTimer;
  58. import flash.utils.describeType;
  59. import flash.system.System;
  60. public class MonsterDebugger
  61. {
  62. // Singleton instance
  63. private static var instance:MonsterDebugger = null;
  64. // Connections
  65. private var lineOut:LocalConnection;
  66. private var lineIn:LocalConnection;
  67. // Connection names
  68. private const LINE_OUT :String = "_debuggerRed";
  69. private const LINE_IN :String = "_debuggerBlue";
  70. // The allow domain for the local connection
  71. // * = Allow communication with all domains
  72. private const ALLOWED_DOMAIN :String = "*";
  73. // Error colors
  74. public static const COLOR_NORMAL :uint = 0x111111;
  75. public static const COLOR_ERROR :uint = 0xFF0000;
  76. public static const COLOR_WARNING :uint = 0xFF3300;
  77. // Commands
  78. private const COMMAND_HELLO :String = "HELLO";
  79. private const COMMAND_ROOT :String = "ROOT";
  80. private const COMMAND_BASE :String = "BASE";
  81. private const COMMAND_TRACE :String = "TRACE";
  82. private const COMMAND_INSPECT :String = "INSPECT";
  83. private const COMMAND_GET_OBJECT :String = "GET_OBJECT";
  84. private const COMMAND_GET_DISPLAYOBJECT :String = "GET_DISPLAYOBJECT";
  85. private const COMMAND_GET_PROPERTIES :String = "GET_PROPERTIES";
  86. private const COMMAND_GET_FUNCTIONS :String = "GET_FUNCTIONS";
  87. private const COMMAND_SET_PROPERTY :String = "SET_PROPERTY";
  88. private const COMMAND_CALL_METHOD :String = "CALL_METHOD";
  89. private const COMMAND_SHOW_HIGHLIGHT :String = "SHOW_HIGHLIGHT";
  90. private const COMMAND_HIDE_HIGHLIGHT :String = "HIDE_HIGHLIGHT";
  91. private const COMMAND_CLEAR_TRACES :String = "CLEAR_TRACES";
  92. private const COMMAND_MONITOR :String = "MONITOR";
  93. private const COMMAND_SNAPSHOT :String = "SNAPSHOT";
  94. private const COMMAND_NOTFOUND :String = "NOTFOUND";
  95. // Types
  96. private const TYPE_VOID :String = "void";
  97. private const TYPE_ARRAY :String = "Array";
  98. private const TYPE_BOOLEAN :String = "Boolean";
  99. private const TYPE_NUMBER :String = "Number";
  100. private const TYPE_OBJECT :String = "Object";
  101. private const TYPE_VECTOR :String = "Vector";
  102. private const TYPE_STRING :String = "String";
  103. private const TYPE_BITMAP :String = "Bitmap";
  104. private const TYPE_BITMAPDATA :String = "BitmapData";
  105. private const TYPE_INT :String = "int";
  106. private const TYPE_UINT :String = "uint";
  107. private const TYPE_XML :String = "XML";
  108. private const TYPE_XMLLIST :String = "XMLList";
  109. private const TYPE_XMLNODE :String = "XMLNode";
  110. private const TYPE_XMLVALUE :String = "XMLValue";
  111. private const TYPE_XMLATTRIBUTE :String = "XMLAttribute";
  112. private const TYPE_METHOD :String = "MethodClosure";
  113. private const TYPE_FUNCTION :String = "Function";
  114. private const TYPE_BYTEARRAY :String = "ByteArray";
  115. private const TYPE_WARNING :String = "Warning";
  116. private const TYPE_DISPLAYOBJECT :String = "DisplayObject";
  117. // Access types
  118. private const ACCESS_VARIABLE :String = "variable";
  119. private const ACCESS_CONSTANT :String = "constant";
  120. private const ACCESS_ACCESSOR :String = "accessor";
  121. private const ACCESS_METHOD :String = "method";
  122. // Permission types
  123. private const PERMISSION_READWRITE :String = "readwrite";
  124. private const PERMISSION_READONLY :String = "readonly";
  125. private const PERMISSION_WRITEONLY :String = "writeonly";
  126. // Icon types
  127. private const ICON_DEFAULT :String = "iconDefault";
  128. private const ICON_ROOT :String = "iconRoot";
  129. private const ICON_WARNING :String = "iconWarning";
  130. private const ICON_VARIABLE :String = "iconVariable";
  131. private const ICON_VARIABLE_READONLY :String = "iconVariableReadonly";
  132. private const ICON_VARIABLE_WRITEONLY :String = "iconVariableWriteonly";
  133. private const ICON_XMLNODE :String = "iconXMLNode";
  134. private const ICON_XMLVALUE :String = "iconXMLValue";
  135. private const ICON_XMLATTRIBUTE :String = "iconXMLAttribute";
  136. private const ICON_FUNCTION :String = "iconFunction";
  137. // Highlight color and border thickness
  138. private const HIGHLIGHT_COLOR :uint = 0xFFFF00;
  139. private const HIGHLIGHT_BORDER :int = 4;
  140. // Max local connection package size
  141. private const MAX_PACKAGE_BYTES :int = 40000;
  142. // Version
  143. private const VERSION:Number = 2.04;
  144. // The root of the application
  145. private var root:Object = null;
  146. // Highlight display object
  147. private var highlight:Sprite = null;
  148. // Timer for the monitor
  149. private var monitor:Timer;
  150. private var monitorTime:uint;
  151. private var monitorFrames:uint;
  152. private var monitorSprite:Sprite;
  153. // Enabled / disabled
  154. public var _enabled:Boolean = true;
  155. /**
  156. * Constructor
  157. * The target can also be a static function
  158. * @param target: The root of the application
  159. */
  160. public function MonsterDebugger(target:Object = null)
  161. {
  162. super();
  163. // Check if the debugger has already been initialized
  164. if (instance == null)
  165. {
  166. // Save the instance
  167. instance = this;
  168. // Setup line out
  169. lineOut = new LocalConnection();
  170. lineOut.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
  171. lineOut.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
  172. lineOut.addEventListener(StatusEvent.STATUS, statusHandler);
  173. // Setup line in
  174. lineIn = new LocalConnection();
  175. lineIn.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
  176. lineIn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
  177. lineIn.addEventListener(StatusEvent.STATUS, statusHandler);
  178. lineIn.allowDomain(ALLOWED_DOMAIN);
  179. lineIn.client = this;
  180. // Setup the fps and memory listeners
  181. monitorTime = getTimer();
  182. monitorFrames = 0;
  183. monitorSprite = new Sprite();
  184. monitorSprite.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
  185. monitor = new Timer(500);
  186. monitor.addEventListener(TimerEvent.TIMER, monitorHandler);
  187. monitor.start();
  188. try {
  189. lineIn.connect(LINE_IN);
  190. } catch(error:ArgumentError) {
  191. // Do nothing
  192. }
  193. }
  194. // Save the root
  195. // Send the first message
  196. if (target != MonsterDebugger.singletonCheck) {
  197. instance.root = target;
  198. instance.send({text:COMMAND_HELLO, version:VERSION});
  199. }
  200. }
  201. /**
  202. * This function is called from the AIR application
  203. * @param data: A compressed object containing the commands
  204. */
  205. public function onReceivedData(data:ByteArray):void
  206. {
  207. if (enabled)
  208. {
  209. //Variables for the commands
  210. var object:*;
  211. var method:Function;
  212. var xml:XML;
  213. // Uncompress the item data
  214. data.uncompress();
  215. // Read the command from the data
  216. var command:Object = data.readObject();
  217. // Do the actions
  218. switch(command["text"])
  219. {
  220. // Save the domain
  221. case COMMAND_HELLO:
  222. send({text:COMMAND_HELLO, version:VERSION});
  223. break;
  224. // Get the base of the application
  225. case COMMAND_ROOT:
  226. object = getObject("", 0);
  227. if (object != null) {
  228. xml = XML(parseObject(object, "", command["functions"], 1, 2));
  229. send({text:COMMAND_ROOT, xml:xml});
  230. if (isDisplayObject(object)) {
  231. xml = XML(parseDisplayObject(object, "", command["functions"], 1, 2));
  232. send({text:COMMAND_BASE, xml:xml});
  233. }
  234. }
  235. break;
  236. // Return the parsed object
  237. case COMMAND_GET_OBJECT:
  238. object = getObject(command["target"], 0);
  239. if (object != null) {
  240. xml = XML(parseObject(object, command["target"], command["functions"], 1, 2));
  241. send({text:COMMAND_GET_OBJECT, xml:xml});
  242. }
  243. break;
  244. // Return the parsed object
  245. case COMMAND_GET_DISPLAYOBJECT:
  246. object = getObject(command["target"], 0);
  247. if (object != null) {
  248. if (isDisplayObject(object)) {
  249. xml = XML(parseDisplayObject(object, command["target"], command["functions"], 1, 2));
  250. send({text:COMMAND_GET_DISPLAYOBJECT, xml:xml});
  251. }
  252. }
  253. break;
  254. // Return a list of functions
  255. case COMMAND_GET_PROPERTIES:
  256. object = getObject(command["target"], 0);
  257. if (object != null) {
  258. xml = XML(parseObject(object, command["target"], false, 1, 1));
  259. send({text:COMMAND_GET_PROPERTIES, xml:xml});
  260. }
  261. break;
  262. // Return a list of functions
  263. case COMMAND_GET_FUNCTIONS:
  264. object = getObject(command["target"], 0);
  265. if (object != null) {
  266. xml = XML(getFunctions(object, command["target"]));
  267. send({text:COMMAND_GET_FUNCTIONS, xml:xml});
  268. }
  269. break;
  270. // Adjust a property and return the value
  271. case COMMAND_SET_PROPERTY:
  272. object = getObject(command["target"], 1);
  273. if (object != null) {
  274. try {
  275. object[command["name"]] = command["value"];
  276. send({text:COMMAND_SET_PROPERTY, value:object[command["name"]]});
  277. } catch (error1:Error) {
  278. send({text:COMMAND_NOTFOUND, target:command["target"]});
  279. break;
  280. }
  281. }
  282. break;
  283. // Call a method and return the answer
  284. case COMMAND_CALL_METHOD:
  285. method = getObject(command["target"], 0);
  286. if (method != null) {
  287. if (command["returnType"] == TYPE_VOID) {
  288. method.apply(this, command["arguments"]);
  289. } else {
  290. object = method.apply(this, command["arguments"]);
  291. xml = XML(parseObject(object, "", false, 1, 4));
  292. send({text:COMMAND_CALL_METHOD, id:command["id"], xml:xml});
  293. }
  294. }
  295. break;
  296. // Remove and add a new highlight if posible
  297. case COMMAND_SHOW_HIGHLIGHT:
  298. if (highlight != null) {
  299. try {
  300. highlight.parent.removeChild(highlight);
  301. highlight = null;
  302. } catch(error2:Error) {
  303. //
  304. }
  305. }
  306. object = getObject(command["target"], 0);
  307. if (isDisplayObject(object) && isDisplayObject(object["parent"])) {
  308. var bounds:Rectangle = object.getBounds(object["parent"]);
  309. highlight = new Sprite();
  310. highlight.x = 0;
  311. highlight.y = 0;
  312. highlight.graphics.beginFill(0, 0);
  313. highlight.graphics.lineStyle(HIGHLIGHT_BORDER, HIGHLIGHT_COLOR);
  314. highlight.graphics.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
  315. highlight.graphics.endFill();
  316. highlight.mouseChildren = false;
  317. highlight.mouseEnabled = false;
  318. try {
  319. object["parent"].addChild(highlight);
  320. } catch(error3:Error) {
  321. highlight = null;
  322. }
  323. }
  324. break;
  325. // Remove the highlight
  326. case COMMAND_HIDE_HIGHLIGHT:
  327. if (highlight != null) {
  328. try {
  329. highlight.parent.removeChild(highlight);
  330. highlight = null;
  331. } catch(error4:Error) {
  332. //
  333. }
  334. }
  335. break;
  336. }
  337. }
  338. }
  339. /**
  340. * The actual send function
  341. * @param data: The raw uncompressed data to send
  342. */
  343. private function send(data:Object):void
  344. {
  345. if (enabled)
  346. {
  347. // Compress the data
  348. var item:ByteArray = new ByteArray();
  349. item.writeObject(data);
  350. item.compress();
  351. // Array to hold the data packages
  352. var dataPackages:Array = new Array();
  353. // Counter for the loops
  354. var i:int = 0;
  355. // Check if the data should be splitted
  356. // The max size for localconnection = 40kb = 40960b
  357. // We use 960b for the package definition
  358. if (item.length > MAX_PACKAGE_BYTES)
  359. {
  360. // Save the length
  361. var bytesAvailable:int = item.length;
  362. var offset:int = 0;
  363. // Calculate the total package count
  364. var total:int = Math.ceil(item.length / MAX_PACKAGE_BYTES);
  365. // Loop through the bytes / chunks
  366. for (i = 0; i < total; i++)
  367. {
  368. // Set the length to read
  369. var length:int = bytesAvailable;
  370. if (length > MAX_PACKAGE_BYTES) {
  371. length = MAX_PACKAGE_BYTES;
  372. }
  373. // Read a chunk of data
  374. var tmp:ByteArray = new ByteArray();
  375. tmp.writeBytes(item, offset, length);
  376. // Create a data package
  377. dataPackages.push({total:total, nr:(i + 1), bytes:tmp});
  378. // Update the bytes available and offset
  379. bytesAvailable -= length;
  380. offset += length;
  381. }
  382. }
  383. else
  384. {
  385. // The data size is under 40kb, so just send one package
  386. dataPackages.push({total:1, nr:1, bytes:item});
  387. }
  388. // send the data packages through the line out
  389. for (i = 0; i < dataPackages.length; i++) {
  390. try {
  391. lineOut.send(LINE_OUT, "onReceivedData", dataPackages[i]);
  392. } catch (error:Error) {
  393. break;
  394. }
  395. }
  396. }
  397. }
  398. /**
  399. * Set another target in the or window
  400. * @param target: The target to display in the or
  401. */
  402. public static function inspect(target:Object):void
  403. {
  404. // Check if the debugger has been enabled
  405. if (instance != null && target != null)
  406. {
  407. // Set the new root
  408. instance.root = target;
  409. // Parse the new target
  410. // Send the new XML
  411. var object:* = instance.getObject("", 0);
  412. if (object != null) {
  413. var xml:XML = XML(instance.parseObject(object, "", false, 1, 2));
  414. instance.send({text:instance.COMMAND_INSPECT, xml:xml});
  415. if (instance.isDisplayObject(object)) {
  416. xml = XML(instance.parseDisplayObject(object, "", false, 1, 2));
  417. instance.send({text:instance.COMMAND_BASE, xml:xml});
  418. }
  419. }
  420. }
  421. }
  422. /**
  423. * Static snapshot function
  424. * @param target: The target from where the snapshot is called
  425. * @param object: The object to snapshot
  426. * @param color: The color in the interface
  427. */
  428. public static function snapshot(target:DisplayObject, color:uint = 0x111111):void
  429. {
  430. if (instance == null) instance = new MonsterDebugger(MonsterDebugger.singletonCheck);
  431. if (MonsterDebugger.enabled) instance.snapshotInternal(target, color);
  432. }
  433. /**
  434. * Private snapshot function
  435. * @param target: The target from where the snapshot is called
  436. * @param object: The object to snapshot
  437. * @param color: The color in the interface
  438. */
  439. private function snapshotInternal(target:DisplayObject, color:uint = 0x111111):void
  440. {
  441. if (enabled)
  442. {
  443. // Create the bitmapdata
  444. var bitmapData:BitmapData = new BitmapData(target.width||1, target.height||1);
  445. bitmapData.draw(target);
  446. // Write the bitmap in the bytearray
  447. var bytes:ByteArray = bitmapData.getPixels(new Rectangle(0, 0, target.width||1, target.height||1));
  448. //Create a send object
  449. send({text:COMMAND_SNAPSHOT, date:new Date(), target:String(target), bytes:bytes, width:target.width||1, height:target.height||1, color:color});
  450. // Clear the data
  451. bitmapData.dispose();
  452. bytes = null;
  453. }
  454. }
  455. /**
  456. * Static trace function
  457. * @param target: The target from where the trace is called
  458. * @param object: The object to trace
  459. * @param color: The color of the trace in the interface
  460. * @parem functions: Include or exclude the functions
  461. * @param depth: The maximum depth of the trace
  462. */
  463. public static function trace(target:Object, object:*, color:uint = 0x111111, functions:Boolean = false, depth:int = 4):void
  464. {
  465. if (instance == null) instance = new MonsterDebugger(MonsterDebugger.singletonCheck);
  466. if (MonsterDebugger.enabled) instance.traceInternal(target, object, color, functions, depth);
  467. }
  468. /**
  469. * Private trace function
  470. * @param target: The target from where the trace is called
  471. * @param object: The object to trace
  472. * @param color: The color of the trace in the interface
  473. * @parem functions: Include or exclude the functions
  474. * @param depth: The maximum depth of the trace
  475. */
  476. private function traceInternal(target:Object, object:*, color:uint = 0x111111, functions:Boolean = false, depth:int = 4):void
  477. {
  478. if (enabled)
  479. {
  480. // Get the object information
  481. var xml:XML = XML(parseObject(object, "", functions, 1, depth));
  482. //Create a send object
  483. send({text:COMMAND_TRACE, date:new Date(), target:String(target), xml:xml, color:color});
  484. }
  485. }
  486. /**
  487. * Static clear traces function
  488. * This clears the traces in the application
  489. */
  490. public static function clearTraces():void
  491. {
  492. if (instance == null) instance = new MonsterDebugger(MonsterDebugger.singletonCheck);
  493. if (MonsterDebugger.enabled) instance.clearTracesInternal();
  494. }
  495. /**
  496. * Private clear traces function
  497. * This clears the traces in the application
  498. */
  499. private function clearTracesInternal():void
  500. {
  501. if (enabled)
  502. {
  503. //Create a send object
  504. send({text:COMMAND_CLEAR_TRACES});
  505. }
  506. }
  507. /**
  508. * Check if an object is drawable displayobject
  509. * @param object: The object to check
  510. */
  511. private function isDisplayObject(object:*):Boolean
  512. {
  513. return (object is DisplayObject || object is DisplayObjectContainer);
  514. }
  515. /**
  516. * Return an object
  517. * @param target: A point seperated path to the object
  518. * @param parent: Number of parents
  519. */
  520. private function getObject(target:String = "", parent:int = 0):*
  521. {
  522. // Object to return
  523. var object:* = instance.root;
  524. // Check if the path is not empty
  525. if (target != "")
  526. {
  527. // Split the path
  528. var splitted:Array = target.split(".");
  529. // Loop through the array
  530. for (var i:int = 0; i < splitted.length - parent; i++)
  531. {
  532. // Check if the string isn't empty
  533. if (splitted[i] != "")
  534. {
  535. try
  536. {
  537. // Check if we should call the XML children function()
  538. // Or the getChildAt function
  539. // If not: Just update the path to the object
  540. if (splitted[i] == "children()")
  541. {
  542. object = object.children();
  543. }
  544. else if (splitted[i].indexOf("getChildAt(") == 0)
  545. {
  546. var index:Number = splitted[i].substring(11, splitted[i].indexOf(")", 11));
  547. object = DisplayObjectContainer(object).getChildAt(index);
  548. }
  549. else
  550. {
  551. object = object[splitted[i]];
  552. }
  553. }
  554. catch (error:ReferenceError)
  555. {
  556. // The object is not found
  557. send({text:COMMAND_NOTFOUND, target:target});
  558. break;
  559. }
  560. }
  561. }
  562. }
  563. // Return the object
  564. return object;
  565. }
  566. /**
  567. * Get the functions of an object
  568. * @param object: The object to parse
  569. * @param target: A point seperated path to the object
  570. */
  571. private function getFunctions(object:*, target:String = ""):String
  572. {
  573. // The return string
  574. var xml:String = "";
  575. // Create the opening node
  576. xml += createNode("root");
  577. try
  578. {
  579. // Get the descriptor
  580. var description:XML = describeType(object);
  581. var type:String = parseType(description.@name);
  582. var childType:String = "";
  583. var childName:String = "";
  584. var childTarget:String = "";
  585. var methods:XMLList = description..method;
  586. var methodsArr:Array = new Array();
  587. var returnType:String;
  588. var parameters:XMLList;
  589. var args:Array;
  590. var argsString:String;
  591. var optional:Boolean = false;
  592. var double:Boolean = false;
  593. var i:int = 0;
  594. var n:int = 0;
  595. // Create the head node
  596. xml += createNode("node", {icon:ICON_DEFAULT, label:"(" + type + ")", target:target});
  597. // Save the methods
  598. // Filter out doubles (this should not happen though)
  599. for (i = 0; i < methods.length(); i++) {
  600. for (n = 0; n < methodsArr.length; n++) {
  601. if (methodsArr[n].name == methods[i].@name) {
  602. double = true;
  603. break;
  604. }
  605. }
  606. if (!double) {
  607. methodsArr.push({name:methods[i].@name, xml:methods[i], access:ACCESS_METHOD});
  608. }
  609. }
  610. // Sort the nodes
  611. methodsArr.sortOn("name");
  612. // Loop through the methods
  613. for (i = 0; i < methodsArr.length; i++)
  614. {
  615. // Save the type
  616. childType = TYPE_FUNCTION;
  617. childName = methodsArr[i].xml.@name;
  618. childTarget = target + "." + childName;
  619. // Save the function info
  620. // Parameters, arguments, return type, etc
  621. returnType = parseType(methodsArr[i].xml.@returnType);
  622. parameters = methodsArr[i].xml..parameter;
  623. args = new Array();
  624. argsString = "";
  625. optional = false;
  626. // Create the parameters
  627. for (n = 0; n < parameters.length(); n++)
  628. {
  629. // Optional parameters should start with a bracket
  630. if (parameters[n].@optional == "true" && !optional){
  631. optional = true;
  632. args.push("[");
  633. }
  634. // Push the parameter
  635. args.push(parseType(parameters[n].@type));
  636. }
  637. // The optional bracket is needed
  638. if (optional) {
  639. args.push("]");
  640. }
  641. // Create the arguments string
  642. argsString = args.join(", ");
  643. argsString = argsString.replace("[, ", "[");
  644. argsString = argsString.replace(", ]", "]");
  645. // Create the node
  646. xml += createNode("node", {
  647. icon: ICON_FUNCTION,
  648. label: childName + "(" + argsString + "):" + returnType,
  649. args: argsString,
  650. name: childName,
  651. type: TYPE_FUNCTION,
  652. access: ACCESS_METHOD,
  653. returnType: returnType,
  654. target: childTarget
  655. });
  656. // Loop through the parameters
  657. for (n = 0; n < parameters.length(); n++)
  658. {
  659. // Create the node
  660. xml += createNode("parameter", {
  661. type: parseType(parameters[n].@type),
  662. index: parameters[n].@index,
  663. optional: parameters[n].@optional
  664. }, true);
  665. }
  666. // Close the function node
  667. xml += createNode("/node");
  668. }
  669. // Create the head node
  670. xml += createNode("/node");
  671. }
  672. catch (error:Error)
  673. {
  674. // The object is not found
  675. var msg:String = "";
  676. msg += createNode("root");
  677. msg += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Not found", name:"Not found"}, true);
  678. msg += createNode("/root");
  679. send({text:COMMAND_NOTFOUND, target:target, xml:XML(msg)});
  680. }
  681. // Create a closing node
  682. xml += createNode("/root");
  683. // Return the xml
  684. return xml;
  685. }
  686. /**
  687. * Parse an object
  688. * @param object: The object to parse
  689. * @param target: A point seperated path to the object
  690. * @param functions: Include or exclude functions
  691. * @param currentDepth: The current trace depth
  692. * @param maxDepth:: The maximum trace depth
  693. */
  694. private function parseObject(object:*, target:String = "", functions:Boolean = false, currentDepth:int = 1, maxDepth:int = 4):String
  695. {
  696. // Variables needed in the loops
  697. var xml:String = "";
  698. var childType:String = "";
  699. var childName:String = "";
  700. var childTarget:String = "";
  701. var description:XML = new XML();
  702. var type:String = "";
  703. var base:String = "";
  704. var isXML:Boolean = false;
  705. var isXMLString:XML;
  706. var i:int = 0;
  707. var n:int = 0;
  708. // Check if the max trace depth is reached
  709. if (maxDepth == -1 || currentDepth <= maxDepth)
  710. {
  711. // Create the opening node if needed
  712. if (currentDepth == 1) xml += createNode("root");
  713. try
  714. {
  715. // Get the descriptor
  716. description = describeType(object);
  717. type = parseType(description.@name);
  718. base = parseType(description.@base);
  719. if (functions && base == TYPE_FUNCTION)
  720. {
  721. // Trace an empty function
  722. xml += createNode("node", {
  723. icon: ICON_FUNCTION,
  724. label: "(Function)",
  725. name: "",
  726. type: TYPE_FUNCTION,
  727. value: "",
  728. target: target,
  729. access: ACCESS_VARIABLE,
  730. permission: PERMISSION_READWRITE
  731. }, true);
  732. }
  733. else if (type == TYPE_ARRAY || type == TYPE_VECTOR)
  734. {
  735. // Add data description if needed
  736. if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
  737. // Create the length property
  738. // The only property of the array
  739. xml += createNode("node", {
  740. icon: ICON_VARIABLE,
  741. label: "length" + " (" + TYPE_UINT + ") = " + object["length"],
  742. name: "length",
  743. type: TYPE_UINT,
  744. value: object["length"],
  745. target: target + "." + "length",
  746. access: ACCESS_VARIABLE,
  747. permission: PERMISSION_READONLY
  748. }, true);
  749. // Get and sort the properties
  750. var keys:Array = new Array();
  751. for (var key:* in object) {
  752. keys.push(key);
  753. }
  754. keys.sort();
  755. // Loop through the array
  756. for (i = 0; i < keys.length; i++)
  757. {
  758. // Save the type
  759. childType = parseType(describeType(object[keys[i]]).@name);
  760. childTarget = target + "." + String(keys[i]);
  761. // Check if we can create a single string or a new node
  762. if (childType == TYPE_STRING || childType == TYPE_BOOLEAN || childType == TYPE_NUMBER || childType == TYPE_INT || childType == TYPE_UINT || childType == TYPE_FUNCTION)
  763. {
  764. isXML = false;
  765. isXMLString = new XML();
  766. // Check if the string is a XML string
  767. if (childType == TYPE_STRING) {
  768. try {
  769. isXMLString = new XML(object[keys[i]]);
  770. if (!isXMLString.hasSimpleContent() && isXMLString.children().length() > 0) isXML = true;
  771. } catch(error1:TypeError) {}
  772. }
  773. try {
  774. if (!isXML) {
  775. xml += createNode("node", {
  776. icon: ICON_VARIABLE,
  777. label: "[" + keys[i] + "] (" + childType + ") = " + printObject(object[keys[i]], childType),
  778. name: "[" + keys[i] + "]",
  779. type: childType,
  780. value: printObject(object[keys[i]], childType),
  781. target: childTarget,
  782. access: ACCESS_VARIABLE,
  783. permission: PERMISSION_READWRITE
  784. }, true);
  785. } else {
  786. xml += createNode("node", {
  787. icon: ICON_VARIABLE,
  788. label: "[" + keys[i] + "] (" + childType + ")",
  789. name: "[" + keys[i] + "]",
  790. type: childType,
  791. value: "",
  792. target: childTarget,
  793. access: ACCESS_VARIABLE,
  794. permission: PERMISSION_READWRITE
  795. }, false);
  796. xml += parseXML(isXMLString, childTarget + "." + "cildren()", currentDepth, maxDepth);
  797. xml += createNode("/node");
  798. }
  799. } catch(error2:Error) {}
  800. }
  801. else
  802. {
  803. xml += createNode("node", {
  804. icon: ICON_VARIABLE,
  805. label: "[" + keys[i] + "] (" + childType + ")",
  806. name: "[" + keys[i] + "]",
  807. type: childType,
  808. value: "",
  809. target: childTarget,
  810. access: ACCESS_VARIABLE,
  811. permission: PERMISSION_READWRITE
  812. });
  813. try
  814. {
  815. // Try to parse the object
  816. xml += parseObject(object[keys[i]], childTarget, functions, currentDepth + 1, maxDepth);
  817. }
  818. catch(error3:Error)
  819. {
  820. // If this fails add a warning message for the user
  821. xml += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Unreadable", name:"Unreadable"}, true);
  822. }
  823. xml += createNode("/node");
  824. }
  825. }
  826. // Close data description if needed
  827. if (currentDepth == 1) xml += createNode("/node");
  828. }
  829. else if (type == TYPE_OBJECT)
  830. {
  831. // Add data description if needed
  832. if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
  833. // Get and sort the properties
  834. var properties:Array = new Array();
  835. for (var prop:* in object) {
  836. properties.push(prop);
  837. }
  838. properties.sort();
  839. // Loop through the array
  840. for (i = 0; i < properties.length; i++)
  841. {
  842. // Save the type
  843. childType = parseType(describeType(object[properties[i]]).@name);
  844. childTarget = target + "." + properties[i];
  845. // Check if we can create a single string or a new node
  846. if (childType == TYPE_STRING || childType == TYPE_BOOLEAN || childType == TYPE_NUMBER || childType == TYPE_INT || childType == TYPE_UINT || childType == TYPE_FUNCTION)
  847. {
  848. isXML = false;
  849. isXMLString = new XML();
  850. // Check if the string is a XML string
  851. if (childType == TYPE_STRING) {
  852. try {
  853. isXMLString = new XML(object[properties[i]]);
  854. if (!isXMLString.hasSimpleContent() && isXMLString.children().length() > 0) isXML = true;
  855. } catch(error4:TypeError) {}
  856. }
  857. try {
  858. if (!isXML) {
  859. xml += createNode("node", {
  860. icon: ICON_VARIABLE,
  861. label: properties[i] + " (" + childType + ") = " + printObject(object[properties[i]], childType),
  862. name: properties[i],
  863. type: childType,
  864. value: printObject(object[properties[i]], childType),
  865. target: childTarget,
  866. access: ACCESS_VARIABLE,
  867. permission: PERMISSION_READWRITE
  868. }, true);
  869. } else {
  870. xml += createNode("node", {
  871. icon: ICON_VARIABLE,
  872. label: properties[i] + " (" + childType + ")",
  873. name: properties[i],
  874. type: childType,
  875. value: "",
  876. target: childTarget,
  877. access: ACCESS_VARIABLE,
  878. permission: PERMISSION_READWRITE
  879. }, false);
  880. xml += parseXML(isXMLString, childTarget + "." + "cildren()", currentDepth, maxDepth);
  881. xml += createNode("/node");
  882. }
  883. } catch(error5:Error) {}
  884. }
  885. else
  886. {
  887. xml += createNode("node", {
  888. icon: ICON_VARIABLE,
  889. label: properties[i] + " (" + childType + ")",
  890. name: properties[i],
  891. type: childType,
  892. value: "",
  893. target: childTarget,
  894. access: ACCESS_VARIABLE,
  895. permission: PERMISSION_READWRITE
  896. });
  897. try
  898. {
  899. // Try to parse the object
  900. xml += parseObject(object[properties[i]], childTarget, functions, currentDepth + 1, maxDepth);
  901. }
  902. catch(error6:Error)
  903. {
  904. // If this fails add a warning message for the user
  905. xml += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Unreadable", name:"Unreadable"}, true);
  906. }
  907. xml += createNode("/node");
  908. }
  909. }
  910. // Close data description if needed
  911. if (currentDepth == 1) xml += createNode("/node");
  912. }
  913. else if (type == TYPE_XML)
  914. {
  915. // Add data description if needed
  916. if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
  917. // Parse the XML
  918. xml += parseXML(object, target + "." + "cildren()", currentDepth, maxDepth);
  919. // Close data description if needed
  920. if (currentDepth == 1) xml += createNode("/node");
  921. }
  922. else if (type == TYPE_XMLLIST)
  923. {
  924. // Add data description if needed
  925. if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
  926. // Create the length property
  927. // The only property of the array
  928. xml += createNode("node", {
  929. icon: ICON_VARIABLE,
  930. label: "length" + " (" + TYPE_UINT + ") = " + object.length(),
  931. name: "length",
  932. type: TYPE_UINT,
  933. value: object.length(),
  934. target: target + "." + "length",
  935. access: ACCESS_VARIABLE,
  936. permission: PERMISSION_READONLY
  937. }, true);
  938. // Loop through the xml nodes
  939. for (i = 0; i < object.length(); i++)
  940. {
  941. xml += parseXML(object[i], target + "." + String(i) + ".children()", currentDepth, maxDepth);
  942. }
  943. // Close data description if needed
  944. if (currentDepth == 1) xml += createNode("/node");
  945. }
  946. else if (type == TYPE_STRING || type == TYPE_BOOLEAN || type == TYPE_NUMBER || type == TYPE_INT || type == TYPE_UINT)
  947. {
  948. isXML = false;
  949. isXMLString = new XML();
  950. // Check if the string is a XML string
  951. if (type == TYPE_STRING) {
  952. try {
  953. isXMLString = new XML(object);
  954. if (!isXMLString.hasSimpleContent() && isXMLString.children().length() > 0) isXML = true;
  955. } catch(error7:TypeError) {}
  956. }
  957. try {
  958. if (!isXML) {
  959. xml += createNode("node", {
  960. icon: ICON_VARIABLE,
  961. label: "(" + type + ") = " + printObject(object, type),
  962. name: "",
  963. type: type,
  964. value: printObject(object, type),
  965. target: target,
  966. access: ACCESS_VARIABLE,
  967. permission: PERMISSION_READWRITE
  968. }, true);
  969. } else {
  970. xml += createNode("node", {
  971. icon: ICON_VARIABLE,
  972. label: "(" + type + ")",
  973. name: "",
  974. type: type,
  975. value: "",
  976. target: target,
  977. access: ACCESS_VARIABLE,
  978. permission: PERMISSION_READWRITE
  979. }, false);
  980. xml += parseXML(isXMLString, target + "." + "cildren()", currentDepth, maxDepth);
  981. xml += createNode("/node");
  982. }
  983. } catch(error8:Error) {}
  984. }
  985. else
  986. {
  987. // Add data description if needed
  988. if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
  989. // Get the data
  990. var variables:XMLList = description..variable;
  991. var accessors:XMLList = description..accessor;
  992. var constants:XMLList = description..constant;
  993. var methods:XMLList = description..method;
  994. var variablesArr:Array = new Array();
  995. var methodsArr:Array = new Array();
  996. var double:Boolean = false;
  997. var permission:String = "";
  998. var icon:String = "";
  999. // Save the variables
  1000. double = false;
  1001. for (i = 0; i < variables.length(); i++) {
  1002. for (n = 0; n < variablesArr.length; n++) {
  1003. if (variablesArr[n].name == variables[i].@name) {
  1004. double = true;
  1005. break;
  1006. }
  1007. }
  1008. if (!double) {
  1009. variablesArr.push({name:variables[i].@name, xml:variables[i], access:ACCESS_VARIABLE});
  1010. }
  1011. }
  1012. // Save the accessors
  1013. double = false;
  1014. for (i = 0; i < accessors.length(); i++) {
  1015. for (n = 0; n < variablesArr.length; n++) {
  1016. if (variablesArr[n].name == accessors[i].@name) {
  1017. double = true;
  1018. break;
  1019. }
  1020. }
  1021. if (!double) {
  1022. variablesArr.push({name:accessors[i].@name, xml:accessors[i], access:ACCESS_ACCESSOR});
  1023. }
  1024. }
  1025. // Save the constants
  1026. double = false;
  1027. for (i = 0; i < constants.length(); i++) {
  1028. for (n = 0; n < variablesArr.length; n++) {
  1029. if (variablesArr[n].name == constants[i].@name) {
  1030. double = true;
  1031. break;
  1032. }
  1033. }
  1034. if (!double) {
  1035. variablesArr.push({name:constants[i].@name, xml:constants[i], access:ACCESS_CONSTANT});
  1036. }
  1037. }
  1038. // Save the methods
  1039. double = false;
  1040. for (i = 0; i < methods.length(); i++) {
  1041. for (n = 0; n < methodsArr.length; n++) {
  1042. if (methodsArr[n].name == methods[i].@name) {
  1043. double = true;
  1044. break;
  1045. }
  1046. }
  1047. if (!double) {
  1048. methodsArr.push({name:methods[i].@name, xml:methods[i], access:ACCESS_METHOD});
  1049. }
  1050. }
  1051. // Sort the nodes
  1052. variablesArr.sortOn("name");
  1053. methodsArr.sortOn("name");
  1054. // VARIABLES
  1055. for (i = 0; i < variablesArr.length; i++)
  1056. {
  1057. // Save the type
  1058. childType = parseType(variablesArr[i].xml.@type);
  1059. childName = variablesArr[i].xml.@name;
  1060. childTarget = target + "." + childName;
  1061. // Save the permission and icon
  1062. permission = PERMISSION_READWRITE;
  1063. icon = ICON_VARIABLE;
  1064. // Check for read / write permissions
  1065. if (variablesArr[i].access == ACCESS_CONSTANT) {
  1066. // Constant
  1067. permission = PERMISSION_READONLY;
  1068. icon = ICON_VARIABLE_READONLY;
  1069. }
  1070. if (variablesArr[i].xml.@access == PERMISSION_READONLY) {
  1071. // Only a getter
  1072. permission = PERMISSION_READONLY;
  1073. icon = ICON_VARIABLE_READONLY;
  1074. }
  1075. if (variablesArr[i].xml.@access == PERMISSION_WRITEONLY) {
  1076. // Only a setter
  1077. permission = PERMISSION_WRITEONLY;
  1078. icon = ICON_VARIABLE_WRITEONLY;
  1079. }
  1080. // Don't include write only accessor
  1081. if (permission != PERMISSION_WRITEONLY)
  1082. {
  1083. // Check if we can create a single string or a new node
  1084. if (childType == TYPE_STRING || childType == TYPE_BOOLEAN || childType == TYPE_NUMBER || childType == TYPE_INT || childType == TYPE_UINT || childType == TYPE_FUNCTION)
  1085. {
  1086. isXML = false;
  1087. isXMLString = new XML();
  1088. // Check if the string is a XML string
  1089. if (childType == TYPE_STRING) {
  1090. try {
  1091. isXMLString = new XML(object[childName]);
  1092. if (!isXMLString.hasSimpleContent() && isXMLString.children().length() > 0) isXML = true;
  1093. } catch(error9:TypeError) {}
  1094. }
  1095. try {
  1096. if (!isXML) {
  1097. xml += createNode("node", {
  1098. icon: icon,
  1099. label: childName + " (" + childType + ") = " + printObject(object[childName], childType),
  1100. name: childName,
  1101. type: childType,
  1102. value: printObject(object[childName], childType),
  1103. target: childTarget,
  1104. access: variablesArr[i].access,
  1105. permission: permission
  1106. }, true);
  1107. } else {
  1108. xml += createNode("node", {
  1109. icon: icon,
  1110. label: childName + " (" + childType + ")",
  1111. name: childName,
  1112. type: childType,
  1113. value: "",
  1114. target: childTarget,
  1115. access: variablesArr[i].access,
  1116. permission: permission
  1117. }, false);
  1118. xml += parseXML(isXMLString, childTarget + "." + "cildren()", currentDepth, maxDepth);
  1119. xml += createNode("/node");
  1120. }
  1121. } catch(error10:Error) {}
  1122. }
  1123. else
  1124. {
  1125. xml += createNode("node", {
  1126. icon: icon,
  1127. label: childName + " (" + childType + ")",
  1128. name: childName,
  1129. type: childType,
  1130. target: childTarget,
  1131. access: variablesArr[i].access,
  1132. permission: permission
  1133. });
  1134. try
  1135. {
  1136. // Try to parse the object
  1137. xml += parseObject(object[childName], childTarget, functions, currentDepth + 1, maxDepth);
  1138. }
  1139. catch(error11:Error)
  1140. {
  1141. // If this fails add a warning message for the user
  1142. xml += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Unreadable", name:"Unreadable"}, true);
  1143. }
  1144. xml += createNode("/node");
  1145. }
  1146. }
  1147. }
  1148. // METHODS
  1149. if (functions)
  1150. {
  1151. for (i = 0; i < methodsArr.length; i++)
  1152. {
  1153. // Save the type
  1154. childType = TYPE_FUNCTION;
  1155. childName = methodsArr[i].xml.@name;
  1156. childTarget = target + "." + childName;
  1157. // Save the parameters
  1158. var returnType:String = parseType(methodsArr[i].xml.@returnType);
  1159. var parameters:XMLList = methodsArr[i].xml..parameter;
  1160. var args:Array = new Array();
  1161. // Create the parameters
  1162. for (n = 0; n < parameters.length(); n++) {
  1163. args.push(parseType(parameters[n].@type));
  1164. }
  1165. // Create the node
  1166. xml += createNode("node", {
  1167. icon: ICON_FUNCTION,
  1168. label: childName + "(" + args.join(", ") + "):" + returnType,
  1169. args: args.join(", "),
  1170. name: childName,
  1171. type: TYPE_FUNCTION,
  1172. access: variablesArr[i].access,
  1173. returnType: returnType,
  1174. target: childTarget
  1175. }, true);
  1176. }
  1177. }
  1178. // Close data description if needed
  1179. if (currentDepth == 1) xml += createNode("/node");
  1180. }
  1181. }
  1182. catch (error12:Error)
  1183. {
  1184. // The object is not found
  1185. var msg:String = "";
  1186. msg += createNode("root");
  1187. msg += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Not found", name:"Not found"}, true);
  1188. msg += createNode("/root");
  1189. send({text:COMMAND_NOTFOUND, target:target, xml:XML(msg)});
  1190. }
  1191. // Create a closing node if needed
  1192. if (currentDepth == 1) xml += createNode("/root");
  1193. }
  1194. //Return the xml
  1195. return xml;
  1196. }
  1197. /**
  1198. * Parse a display object
  1199. * @param object: The object to parse
  1200. * @param target: A point seperated path to the object
  1201. * @param functions: Include or exclude functions
  1202. * @param currentDepth: The current trace depth
  1203. * @param maxDepth:: The maximum trace depth
  1204. */
  1205. private function parseDisplayObject(object:*, target:String = "", functions:Boolean = false, currentDepth:int = 1, maxDepth:int = 4):String
  1206. {
  1207. // Variables needed in the loops
  1208. var xml:String = "";
  1209. var childs:Array;
  1210. var child:DisplayObject;
  1211. var childType:String = "";
  1212. var childIcon:String = "";
  1213. var childName:String = "";
  1214. var childTarget:String = "";
  1215. var childChildren:String = "";
  1216. var i:int = 0;
  1217. var n:int = 0;
  1218. // Check if the max trace depth is reached
  1219. if (maxDepth == -1 || currentDepth <= maxDepth)
  1220. {
  1221. // Create the opening node if needed
  1222. if (currentDepth == 1) xml += createNode("root");
  1223. try
  1224. {
  1225. // Add data description if needed
  1226. if (currentDepth == 1) {
  1227. var ojectName:String = DisplayObject(object).name;
  1228. if (ojectName == null || ojectName == "null") {
  1229. ojectName = "DisplayObject";
  1230. }
  1231. xml += createNode("node", {icon:ICON_ROOT, label:"(" + ojectName + ")", target:target});
  1232. }
  1233. // Get the childs
  1234. childs = new Array();
  1235. for (i = 0; i < DisplayObjectContainer(object).numChildren; i++) {
  1236. childs.push(DisplayObjectContainer(object).getChildAt(i));
  1237. }
  1238. // Loop through the array
  1239. for (i = 0; i < childs.length; i++)
  1240. {
  1241. // Save the child properties
  1242. child = childs[i];
  1243. childName = describeType(child).@name;
  1244. childType = parseType(childName);
  1245. childTarget = target + "." + "getChildAt(" + i + ")";
  1246. childIcon = child is DisplayObjectContainer ? ICON_ROOT : ICON_VARIABLE;
  1247. childChildren = child is DisplayObjectContainer ? String(DisplayObjectContainer(child).numChildren) : ""
  1248. // Create the node
  1249. xml += createNode("node", {
  1250. icon: childIcon,
  1251. label: child.name + " (" + childType + ") " + childChildren,
  1252. name: child.name,
  1253. type: childType,
  1254. value: printObject(child, childType),
  1255. target: childTarget,
  1256. access: ACCESS_VARIABLE,
  1257. permission: PERMISSION_READWRITE
  1258. });
  1259. try
  1260. {
  1261. // Try to parse the object
  1262. xml += parseDisplayObject(child, childTarget, functions, currentDepth + 1, maxDepth);
  1263. }
  1264. catch(error13:Error)
  1265. {
  1266. // If this fails add a warning message for the user
  1267. xml += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Unreadable", name:"Unreadable"}, true);
  1268. }
  1269. xml += createNode("/node");
  1270. }
  1271. // Create a closing node if needed
  1272. if (currentDepth == 1) xml += createNode("/node");
  1273. }
  1274. catch (error14:Error)
  1275. {
  1276. // The object is not found
  1277. var msg:String = "";
  1278. msg += createNode("root");
  1279. msg += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Not found", name:"Not found"}, true);
  1280. msg += createNode("/root");
  1281. send({text:COMMAND_NOTFOUND, target:target, xml:XML(msg)});
  1282. }
  1283. // Create a closing node if needed
  1284. if (currentDepth == 1) xml += createNode("/root");
  1285. }
  1286. //Return the xml
  1287. return xml;
  1288. }
  1289. /**
  1290. * Parse a XML node
  1291. * @param node: The xml to parse
  1292. * @param target: A point seperated path to the object
  1293. * @param currentDepth: The current trace depth
  1294. * @param maxDepth:: The maximum trace depth
  1295. */
  1296. private function parseXML(node:*, target:String = "", currentDepth:int = 1, maxDepth:int = -1):String
  1297. {
  1298. // Create a return string
  1299. var xml:String = "";
  1300. var i:int = 0;
  1301. // Check if the maximum trace depth is reached
  1302. if (maxDepth == -1 || currentDepth <= maxDepth)
  1303. {
  1304. // Check if the user traced an attribute
  1305. if (target.indexOf("@") != -1)
  1306. {
  1307. // Display a single attribute
  1308. xml += createNode("node", {
  1309. icon: ICON_XMLATTRIBUTE,
  1310. label: node,
  1311. name: "",
  1312. type: TYPE_XMLATTRIBUTE,
  1313. value: node,
  1314. target: target,
  1315. access: ACCESS_VARIABLE,
  1316. permission: PERMISSION_READWRITE
  1317. }, true);
  1318. }
  1319. else if (node.name() == null)
  1320. {
  1321. // Only a text value
  1322. xml += createNode("node", {
  1323. icon: ICON_XMLVALUE,
  1324. label: "(" + TYPE_XMLVALUE + ") = " + printObject(node, TYPE_XMLVALUE),
  1325. name: "",
  1326. type: TYPE_XMLVALUE,
  1327. value: printObject(node, TYPE_XMLVALUE),
  1328. target: target,
  1329. access: ACCESS_VARIABLE,
  1330. permission: PERMISSION_READWRITE
  1331. }, true);
  1332. }
  1333. else if (node.hasSimpleContent())
  1334. {
  1335. // Node with one text value and possible attributes
  1336. xml += createNode("node", {
  1337. icon: ICON_XMLNODE,
  1338. label: node.name() + " (" + TYPE_XMLNODE + ")",
  1339. name: node.name(),
  1340. type: TYPE_XMLNODE,
  1341. value: "",
  1342. target: target,
  1343. access: ACCESS_VARIABLE,
  1344. permission: PERMISSION_READWRITE
  1345. });
  1346. // Only a text value
  1347. if (node != "") {
  1348. xml += createNode("node", {
  1349. icon: ICON_XMLVALUE,
  1350. label: "(" + TYPE_XMLVALUE + ") = " + printObject(node, TYPE_XMLVALUE),
  1351. name: "",
  1352. type: TYPE_XMLVALUE,
  1353. value: printObject(node, TYPE_XMLVALUE),
  1354. target: target,
  1355. access: ACCESS_VARIABLE,
  1356. permission: PERMISSION_READWRITE
  1357. }, true);
  1358. }
  1359. // Loop through the arrributes
  1360. for (i = 0; i < node.attributes().length(); i++)
  1361. {
  1362. xml += createNode("node", {
  1363. icon: ICON_XMLATTRIBUTE,
  1364. label: "@" + node.attributes()[i].name() + " (" + TYPE_XMLATTRIBUTE + ") = " + node.attributes()[i],
  1365. name: "",
  1366. type: TYPE_XMLATTRIBUTE,
  1367. value: node.attributes()[i],
  1368. target: target + "." + "@" + node.attributes()[i].name(),
  1369. access: ACCESS_VARIABLE,
  1370. permission: PERMISSION_READWRITE
  1371. }, true);
  1372. }
  1373. // Close the node
  1374. xml += createNode("/node");
  1375. }
  1376. else
  1377. {
  1378. // Node with children and attributes
  1379. // This node has no value due to the children
  1380. xml += createNode("node", {
  1381. icon: ICON_XMLNODE,
  1382. label: node.name() + " (" + TYPE_XMLNODE + ")",
  1383. name: node.name(),
  1384. type: TYPE_XMLNODE,
  1385. value: "",
  1386. target: target,
  1387. access: ACCESS_VARIABLE,
  1388. permission: PERMISSION_READWRITE
  1389. });
  1390. // Loop through the arrributes
  1391. for (i = 0; i < node.attributes().length(); i++)
  1392. {
  1393. xml += createNode("node", {
  1394. icon: ICON_XMLATTRIBUTE,
  1395. label: "@" + node.attributes()[i].name() + " (" + TYPE_XMLATTRIBUTE + ") = " + node.attributes()[i],
  1396. name: "",
  1397. type: TYPE_XMLATTRIBUTE,
  1398. value: node.attributes()[i],
  1399. target: target + "." + "@" + node.attributes()[i].name(),
  1400. access: ACCESS_VARIABLE,
  1401. permission: PERMISSION_READWRITE
  1402. }, true);
  1403. }
  1404. // Loop through children
  1405. for (i = 0; i < node.children().length(); i++)
  1406. {
  1407. var childTarget:String = target + "." + "children()" + "." + i;