PageRenderTime 5948ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/src/nl/demonsters/debugger/MonsterDebugger.as

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