/src/nl/demonsters/debugger/MonsterDebugger.as
ActionScript | 1914 lines | 1265 code | 244 blank | 405 comment | 317 complexity | 88b508eaa3171a1799548bcd66df6c09 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /**
- *
- * This is the client code that needs to be implemented into a
- * Flash, FLEX or AIR application to collect debug information
- * in De MonsterDebugger.
- *
- * Be aware that any traces made to De MonsterDebugger may
- * be viewed by others. De MonsterDebugger is intended to be
- * used to debug Flash, FLEX or AIR applications in a protective
- * environment that they will not be used in the final launch.
- * Please make sure that you do not send any debug material to
- * the debugger from a live running application.
- *
- * Use at your own risk.
- *
- * @author Ferdi Koomen, Joost Harts
- * @company De Monsters
- * @link http://www.deMonsterDebugger.com
- * @version 2.5.1 (stable)
- *
- *
- * Special thanks to Arjan van Wijk and Thijs Broerse from MediaMonks.nl
- *
- *
- * Copyright 2009, De Monsters
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-
- package nl.demonsters.debugger
- {
-
- import flash.display.BitmapData;
- import flash.display.DisplayObject;
- import flash.display.DisplayObjectContainer;
- import flash.display.Sprite;
- import flash.events.AsyncErrorEvent;
- import flash.events.SecurityErrorEvent;
- import flash.events.StatusEvent;
- import flash.events.TimerEvent;
- import flash.events.Event;
- import flash.net.LocalConnection;
- import flash.geom.Rectangle;
- import flash.utils.ByteArray;
- import flash.utils.Timer;
- import flash.utils.describeType;
- import flash.system.System;
-
-
- public class MonsterDebugger
- {
-
- // Singleton instance
- private static var instance:MonsterDebugger = null;
-
-
- // Connections
- private var lineOut:LocalConnection;
- private var lineIn:LocalConnection;
-
-
- // Connection names
- private const LINE_OUT :String = "_debuggerRed";
- private const LINE_IN :String = "_debuggerBlue";
-
-
- // The allow domain for the local connection
- // * = Allow communication with all domains
- private const ALLOWED_DOMAIN :String = "*";
-
-
- // Error colors
- public static const COLOR_NORMAL :uint = 0x111111;
- public static const COLOR_ERROR :uint = 0xFF0000;
- public static const COLOR_WARNING :uint = 0xFF3300;
-
-
- // Commands
- private const COMMAND_HELLO :String = "HELLO";
- private const COMMAND_HELLO_RESPONSE :String = "HELLO_RESPONSE";
- private const COMMAND_ROOT :String = "ROOT";
- private const COMMAND_BASE :String = "BASE";
- private const COMMAND_TRACE :String = "TRACE";
- private const COMMAND_INSPECT :String = "INSPECT";
- private const COMMAND_GET_OBJECT :String = "GET_OBJECT";
- private const COMMAND_GET_DISPLAYOBJECT :String = "GET_DISPLAYOBJECT";
- private const COMMAND_GET_PROPERTIES :String = "GET_PROPERTIES";
- private const COMMAND_GET_FUNCTIONS :String = "GET_FUNCTIONS";
- private const COMMAND_SET_PROPERTY :String = "SET_PROPERTY";
- private const COMMAND_CALL_METHOD :String = "CALL_METHOD";
- private const COMMAND_SHOW_HIGHLIGHT :String = "SHOW_HIGHLIGHT";
- private const COMMAND_HIDE_HIGHLIGHT :String = "HIDE_HIGHLIGHT";
- private const COMMAND_CLEAR_TRACES :String = "CLEAR_TRACES";
- private const COMMAND_MONITOR :String = "MONITOR";
- private const COMMAND_SNAPSHOT :String = "SNAPSHOT";
- private const COMMAND_NOTFOUND :String = "NOTFOUND";
-
-
- // Types
- private const TYPE_VOID :String = "void";
- private const TYPE_ARRAY :String = "Array";
- private const TYPE_BOOLEAN :String = "Boolean";
- private const TYPE_NUMBER :String = "Number";
- private const TYPE_OBJECT :String = "Object";
- private const TYPE_VECTOR :String = "Vector";
- private const TYPE_STRING :String = "String";
- private const TYPE_INT :String = "int";
- private const TYPE_UINT :String = "uint";
- private const TYPE_XML :String = "XML";
- private const TYPE_XMLLIST :String = "XMLList";
- private const TYPE_XMLNODE :String = "XMLNode";
- private const TYPE_XMLVALUE :String = "XMLValue";
- private const TYPE_XMLATTRIBUTE :String = "XMLAttribute";
- private const TYPE_METHOD :String = "MethodClosure";
- private const TYPE_FUNCTION :String = "Function";
- private const TYPE_BYTEARRAY :String = "ByteArray";
- private const TYPE_WARNING :String = "Warning";
-
-
- // Access types
- private const ACCESS_VARIABLE :String = "variable";
- private const ACCESS_CONSTANT :String = "constant";
- private const ACCESS_ACCESSOR :String = "accessor";
- private const ACCESS_METHOD :String = "method";
-
-
- // Permission types
- private const PERMISSION_READWRITE :String = "readwrite";
- private const PERMISSION_READONLY :String = "readonly";
- private const PERMISSION_WRITEONLY :String = "writeonly";
-
-
- // Icon types
- private const ICON_DEFAULT :String = "iconDefault";
- private const ICON_ROOT :String = "iconRoot";
- private const ICON_WARNING :String = "iconWarning";
- private const ICON_VARIABLE :String = "iconVariable";
- private const ICON_VARIABLE_READONLY :String = "iconVariableReadonly";
- private const ICON_VARIABLE_WRITEONLY :String = "iconVariableWriteonly";
- private const ICON_XMLNODE :String = "iconXMLNode";
- private const ICON_XMLVALUE :String = "iconXMLValue";
- private const ICON_XMLATTRIBUTE :String = "iconXMLAttribute";
- private const ICON_FUNCTION :String = "iconFunction";
-
-
- // Highlight color and border
- protected const HIGHLIGHT_COLOR :uint = 0xFFFF00;
- protected const HIGHLIGHT_BORDER :int = 4;
-
-
- // Max local connection package size
- // Max buffer size
- protected const MAX_PACKAGE_BYTES :int = 40000;
- protected const MAX_BUFFER_SIZE :int = 500;
-
-
- // Version
- protected const VERSION :Number = 2.51;
-
-
- // FPS interval timer
- protected const FPS_UPDATE :int = 500;
-
-
- // The root of the application
- protected var root:Object = null;
-
-
- // Highlight display object
- protected var highlight:Sprite = null;
-
-
- // Message buffer
- protected var buffer:Array = new Array();
-
-
- // Timer for the monitor
- protected var monitor:Timer;
- protected var monitorTime:Number;
- protected var monitorStart:Number;
- protected var monitorFrames:uint;
- protected var monitorSprite:Sprite;
-
-
- // Enabled / disabled
- protected var isEnabled:Boolean = true;
- protected var isConnected:Boolean = false;
-
-
- // Debugger for the debugger ;-)
- //
- // var debugger:MonsterDebugger = new MonsterDebugger(this);
- // debugger.logger = function(...args):void {
- // trace(args);
- // };
- public var logger:Function;
-
-
- /**
- * Constructor
- * The target can also be a static function
- * @param target: The root of the application
- */
- public function MonsterDebugger(target:Object = null)
- {
- // Check if the debugger has already been initialized
- if (instance == null)
- {
- // Save the instance
- instance = this;
-
- // Setup line out
- lineOut = new LocalConnection();
- lineOut.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler, false, 0, true);
- lineOut.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, false, 0, true);
- lineOut.addEventListener(StatusEvent.STATUS, statusHandler, false, 0, true);
-
- // Setup line in
- lineIn = new LocalConnection();
- lineIn.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler, false, 0, true);
- lineIn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, false, 0, true);
- lineIn.addEventListener(StatusEvent.STATUS, statusHandler, false, 0, true);
- lineIn.allowDomain(ALLOWED_DOMAIN);
- lineIn.client = this;
-
- // Setup the fps and memory listeners
- monitorTime = new Date().time;
- monitorStart = new Date().time;
- monitorFrames = 0;
- monitorSprite = new Sprite();
- monitorSprite.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 0, true);
- monitor = new Timer(FPS_UPDATE);
- monitor.addEventListener(TimerEvent.TIMER, monitorHandler, false, 0, true);
- monitor.start();
-
- try {
- lineIn.connect(LINE_IN);
- } catch(error:ArgumentError) {
- // Do nothing
- }
-
- }
-
- // Save the root
- // Send the first message
- instance.root = target;
- instance.send({text:COMMAND_HELLO, version:VERSION});
- }
-
-
- /**
- * This function is called from the AIR application
- * @param data: A compressed object containing the commands
- */
- public function onReceivedData(data:ByteArray):void
- {
- if (isEnabled)
- {
- //Variables for the commands
- var object:*;
- var method:Function;
- var xml:XML;
-
- // Uncompress the item data
- data.uncompress();
-
- // Read the command from the data
- var command:Object = data.readObject();
-
- // Do the actions
- switch(command["text"])
- {
- // Save the domain
- case COMMAND_HELLO:
- isConnected = true;
- send({text:COMMAND_HELLO, version:VERSION});
- break;
-
- // Send the buffer
- case COMMAND_HELLO_RESPONSE:
- isConnected = true;
- sendBuffer();
- break;
-
- // Get the base of the application
- case COMMAND_ROOT:
- object = getObject("", 0);
- if (object != null) {
- xml = XML(parseObject(object, "", command["functions"], 1, 2));
- send({text:COMMAND_ROOT, xml:xml});
- if (isDisplayObject(object)) {
- xml = XML(parseDisplayObject(object, "", command["functions"], 1, 2));
- send({text:COMMAND_BASE, xml:xml});
- }
- }
- break;
-
- // Return the parsed object
- case COMMAND_GET_OBJECT:
- object = getObject(command["target"], 0);
- if (object != null) {
- xml = XML(parseObject(object, command["target"], command["functions"], 1, 2));
- send({text:COMMAND_GET_OBJECT, xml:xml});
- }
- break;
-
- // Return the parsed object
- case COMMAND_GET_DISPLAYOBJECT:
- object = getObject(command["target"], 0);
- if (object != null) {
- if (isDisplayObject(object)) {
- xml = XML(parseDisplayObject(object, command["target"], command["functions"], 1, 2));
- send({text:COMMAND_GET_DISPLAYOBJECT, xml:xml});
- }
- }
- break;
-
- // Return a list of functions
- case COMMAND_GET_PROPERTIES:
- object = getObject(command["target"], 0);
- if (object != null) {
- xml = XML(parseObject(object, command["target"], false, 1, 1));
- send({text:COMMAND_GET_PROPERTIES, xml:xml});
- }
- break;
-
- // Return a list of functions
- case COMMAND_GET_FUNCTIONS:
- object = getObject(command["target"], 0);
- if (object != null) {
- xml = XML(getFunctions(object, command["target"]));
- send({text:COMMAND_GET_FUNCTIONS, xml:xml});
- }
- break;
-
- // Adjust a property and return the value
- case COMMAND_SET_PROPERTY:
- object = getObject(command["target"], 1);
- if (object != null) {
- try {
- object[command["name"]] = command["value"];
- send({text:COMMAND_SET_PROPERTY, value:object[command["name"]]});
- } catch (error:Error) {
- send({text:COMMAND_NOTFOUND, target:command["target"]});
- break;
- }
- }
- break;
-
- // Call a method and return the answer
- case COMMAND_CALL_METHOD:
- method = getObject(command["target"], 0);
- if (method != null) {
- if (command["returnType"] == TYPE_VOID) {
- method.apply(this, command["arguments"]);
- } else {
- object = method.apply(this, command["arguments"]);
- xml = XML(parseObject(object, "", false, 1, 4));
- send({text:COMMAND_CALL_METHOD, id:command["id"], xml:xml});
- }
- }
- break;
-
- // Remove and add a new highlight if posible
- case COMMAND_SHOW_HIGHLIGHT:
- if (highlight != null) {
- try {
- highlight.parent.removeChild(highlight);
- highlight = null;
- } catch(error:Error) {
- //
- }
- }
- object = getObject(command["target"], 0);
- if (isDisplayObject(object) && isDisplayObject(object["parent"])) {
- var bounds:Rectangle = object.getBounds(object["parent"]);
- highlight = new Sprite();
- highlight.x = 0;
- highlight.y = 0;
- highlight.graphics.beginFill(0, 0);
- highlight.graphics.lineStyle(HIGHLIGHT_BORDER, HIGHLIGHT_COLOR);
- highlight.graphics.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
- highlight.graphics.endFill();
- highlight.mouseChildren = false;
- highlight.mouseEnabled = false;
- try {
- object["parent"].addChild(highlight);
- } catch(error:Error) {
- highlight = null;
- }
- }
- break;
-
- // Remove the highlight
- case COMMAND_HIDE_HIGHLIGHT:
- if (highlight != null) {
- try {
- highlight.parent.removeChild(highlight);
- highlight = null;
- } catch(error:Error) {
- //
- }
- }
- break;
- }
- }
- }
-
-
- /**
- * The actual send function
- * @param data: The raw uncompressed data to send
- */
- protected function send(data:Object):void
- {
- if (isEnabled)
- {
- // Compress the data
- var item:ByteArray = new ByteArray();
- item.writeObject(data);
- item.compress();
-
- // Array to hold the data packages
- var dataPackages:Array = new Array();
-
- // Counter for the loops
- var i:int = 0;
-
- // Check if the data should be splitted
- // The max size for localconnection = 40kb = 40960b
- // We use 960b for the package definition
- if (item.length > MAX_PACKAGE_BYTES)
- {
- // Save the length
- var bytesAvailable:int = item.length;
- var offset:int = 0;
-
- // Calculate the total package count
- var total:int = Math.ceil(item.length / MAX_PACKAGE_BYTES);
-
- // Loop through the bytes / chunks
- for (i = 0; i < total; i++)
- {
- // Set the length to read
- var length:int = bytesAvailable;
- if (length > MAX_PACKAGE_BYTES) {
- length = MAX_PACKAGE_BYTES;
- }
-
- // Read a chunk of data
- var tmp:ByteArray = new ByteArray();
- tmp.writeBytes(item, offset, length);
-
- // Create a data package
- dataPackages.push({total:total, nr:(i + 1), bytes:tmp});
-
- // Update the bytes available and offset
- bytesAvailable -= length;
- offset += length;
- }
- }
- else
- {
- // The data size is under 40kb, so just send one package
- dataPackages.push({total:1, nr:1, bytes:item});
- }
-
- // send the data packages through the line out
- for (i = 0; i < dataPackages.length; i++) {
- try {
- lineOut.send(LINE_OUT, "onReceivedData", dataPackages[i]);
- } catch (error:Error) {
- break;
- }
- }
- }
- }
-
-
- /**
- * Send data to the buffer
- * @param data: The raw uncompressed data to send
- */
- protected function sendToBuffer(obj:Object):void
- {
- buffer.push(obj);
- if (buffer.length > MAX_BUFFER_SIZE) buffer.shift();
- }
-
-
- /**
- * Send the buffer to the flex app
- */
- protected function sendBuffer():void
- {
- if (buffer.length > 0) {
- while (buffer.length != 0) {
- send(buffer.shift());
- }
- }
- }
-
-
- /**
- * Set another target in the or window
- * @param target: The target to display in the or
- */
- public static function inspect(target:Object):void
- {
- // Check if the debugger has been enabled
- if (instance != null && target != null)
- {
- // Set the new root
- instance.root = target;
-
- // Parse the new target
- // Send the new XML
- var object:* = instance.getObject("", 0);
- if (object != null) {
- var xml:XML = XML(instance.parseObject(object, "", false, 1, 2));
- var obj:Object = {text:instance.COMMAND_INSPECT, xml:xml};
- if (instance.isConnected) {
- instance.send(obj);
- } else {
- instance.sendToBuffer(obj);
- }
- if (instance.isDisplayObject(object)) {
- xml = XML(instance.parseDisplayObject(object, "", false, 1, 2));
- obj = {text:instance.COMMAND_BASE, xml:xml};
- if (instance.isConnected) {
- instance.send(obj);
- } else {
- instance.sendToBuffer(obj);
- }
- }
- }
- }
- }
-
-
- /**
- * Static snapshot function
- * @param target: The target from where the snapshot is called
- * @param object: The object to snapshot
- * @param color: The color in the interface
- */
- public static function snapshot(target:DisplayObject, color:uint = 0x111111):void
- {
- if (instance == null) instance = new MonsterDebugger(null);
- if (MonsterDebugger.enabled) instance.snapshotInternal(target, color);
- }
-
-
- /**
- * Private snapshot function
- * @param target: The target from where the snapshot is called
- * @param object: The object to snapshot
- * @param color: The color in the interface
- */
- protected function snapshotInternal(target:DisplayObject, color:uint = 0x111111):void
- {
- if (isEnabled)
- {
- // Create the bitmapdata
- var bitmapData:BitmapData = new BitmapData(target.width, target.height);
- bitmapData.draw(target);
-
- // Write the bitmap in the bytearray
- var bytes:ByteArray = bitmapData.getPixels(new Rectangle(0, 0, target.width, target.height));
-
- // Get memory
- var memory:uint = System.totalMemory;
-
- //Create a send object
- var obj:Object = {text:COMMAND_SNAPSHOT, date:new Date(), target:String(target), bytes:bytes, width:target.width, height:target.height, color:color, memory:memory};
- if (isConnected) {
- send(obj);
- } else {
- sendToBuffer(obj);
- }
-
- // Clear the data
- bitmapData.dispose();
- bytes = null;
- }
- }
-
-
- /**
- * Static trace function
- * @param target: The target from where the trace is called
- * @param object: The object to trace
- * @param color: The color of the trace in the interface
- * @parem functions: Include or exclude the functions
- * @param depth: The maximum depth of the trace
- */
- public static function trace(target:Object, object:*, color:uint = 0x111111, functions:Boolean = false, depth:int = 4):void
- {
- if (instance == null) instance = new MonsterDebugger(target);
- if (MonsterDebugger.enabled) instance.traceInternal(target, object, color, functions, depth);
- }
-
-
- /**
- * Private trace function
- * @param target: The target from where the trace is called
- * @param object: The object to trace
- * @param color: The color of the trace in the interface
- * @parem functions: Include or exclude the functions
- * @param depth: The maximum depth of the trace
- */
- protected function traceInternal(target:Object, object:*, color:uint = 0x111111, functions:Boolean = false, depth:int = 4):void
- {
- if (isEnabled)
- {
- // Get the object information
- var xml:XML = XML(parseObject(object, "", functions, 1, depth));
-
- // Get memory
- var memory:uint = System.totalMemory;
-
- //Create a send object
- var obj:Object = {text:COMMAND_TRACE, date:new Date(), target:String(target), xml:xml, color:color, memory:memory};
- if (isConnected) {
- send(obj);
- } else {
- sendToBuffer(obj);
- }
- }
- }
-
-
- /**
- * Static clear traces function
- * This clears the traces in the application
- */
- public static function clearTraces():void
- {
- if (instance == null) instance = new MonsterDebugger(null);
- if (MonsterDebugger.enabled) instance.clearTracesInternal();
- }
-
-
- /**
- * Private clear traces function
- * This clears the traces in the application
- */
- protected function clearTracesInternal():void
- {
- //Create a send object
- if (isEnabled) {
- var obj:Object = {text:COMMAND_CLEAR_TRACES};
- if (isConnected) {
- send(obj);
- } else {
- sendToBuffer(obj);
- }
- }
- }
-
-
- /**
- * Check if an object is drawable displayobject
- * @param object: The object to check
- */
- protected function isDisplayObject(object:*):Boolean
- {
- return (object is DisplayObject || object is DisplayObjectContainer);
- }
-
-
- /**
- * Return an object
- * @param target: A point seperated path to the object
- * @param parent: Number of parents
- */
- protected function getObject(target:String = "", parent:int = 0):*
- {
- // Object to return
- var object:* = instance.root;
-
- // Check if the path is not empty
- if (target != "")
- {
- // Split the path
- var splitted:Array = target.split(".");
-
- // Loop through the array
- for (var i:int = 0; i < splitted.length - parent; i++)
- {
- // Check if the string isn't empty
- if (splitted[i] != "")
- {
- try
- {
- // Check if we should call the XML children function()
- // Or the getChildAt function
- // If not: Just update the path to the object
- if (splitted[i] == "children()") {
- object = object.children();
- } else if (splitted[i].indexOf("getChildAt(") == 0) {
- var index:Number = splitted[i].substring(11, splitted[i].indexOf(")", 11));
- object = DisplayObjectContainer(object).getChildAt(index);
- } else {
- object = object[splitted[i]];
- }
- }
- catch (error:ReferenceError)
- {
- // The object is not found
- var obj:Object = {text:COMMAND_NOTFOUND, target:target};
- if (isConnected) {
- send(obj);
- } else {
- sendToBuffer(obj);
- }
- break;
- }
- }
- }
- }
-
- // Return the object
- return object;
- }
-
-
- /**
- * Get the functions of an object
- * @param object: The object to parse
- * @param target: A point seperated path to the object
- */
- protected function getFunctions(object:*, target:String = ""):String
- {
- // The return string
- var xml:String = "";
-
- // Create the opening node
- xml += createNode("root");
-
- try
- {
- // Get the descriptor
- var description:XML = describeType(object);
- var type:String = parseType(description.@name);
- var childType:String = "";
- var childName:String = "";
- var childTarget:String = "";
- var methods:XMLList = description..method;
- var methodsArr:Array = new Array();
- var returnType:String;
- var parameters:XMLList;
- var args:Array;
- var argsString:String;
- var optional:Boolean = false;
- var double:Boolean = false;
- var i:int = 0;
- var n:int = 0;
-
- // Create the head node
- xml += createNode("node", {icon:ICON_DEFAULT, label:"(" + type + ")", target:target});
-
- // Save the methods
- // Filter out doubles (this should not happen though)
- for (i = 0; i < methods.length(); i++) {
- for (n = 0; n < methodsArr.length; n++) {
- if (methodsArr[n].name == methods[i].@name) {
- double = true;
- break;
- }
- }
- if (!double) {
- methodsArr.push({name:methods[i].@name, xml:methods[i], access:ACCESS_METHOD});
- }
- }
-
- // Sort the nodes
- methodsArr.sortOn("name");
-
- // Loop through the methods
- for (i = 0; i < methodsArr.length; i++)
- {
- // Save the type
- childType = TYPE_FUNCTION;
- childName = methodsArr[i].xml.@name;
- childTarget = target + "." + childName;
-
- // Save the function info
- // Parameters, arguments, return type, etc
- returnType = parseType(methodsArr[i].xml.@returnType);
- parameters = methodsArr[i].xml..parameter;
- args = new Array();
- argsString = "";
- optional = false;
-
- // Create the parameters
- for (n = 0; n < parameters.length(); n++)
- {
- // Optional parameters should start with a bracket
- if (parameters[n].@optional == "true" && !optional){
- optional = true;
- args.push("[");
- }
-
- // Push the parameter
- args.push(parseType(parameters[n].@type));
- }
-
- // The optional bracket is needed
- if (optional) {
- args.push("]");
- }
-
- // Create the arguments string
- argsString = args.join(", ");
- argsString = argsString.replace("[, ", "[");
- argsString = argsString.replace(", ]", "]");
-
- // Create the node
- xml += createNode("node", {
- icon: ICON_FUNCTION,
- label: childName + "(" + argsString + "):" + returnType,
- args: argsString,
- name: childName,
- type: TYPE_FUNCTION,
- access: ACCESS_METHOD,
- returnType: returnType,
- target: childTarget
- });
-
-
- // Loop through the parameters
- for (n = 0; n < parameters.length(); n++)
- {
- // Create the node
- xml += createNode("parameter", {
- type: parseType(parameters[n].@type),
- index: parameters[n].@index,
- optional: parameters[n].@optional
- }, true);
- }
-
- // Close the function node
- xml += createNode("/node");
- }
-
- // Create the head node
- xml += createNode("/node");
- }
- catch (error:Error)
- {
- // The object is not found
- var msg:String = "";
- msg += createNode("root");
- msg += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Not found", name:"Not found"}, true);
- msg += createNode("/root");
- var obj:Object = {text:COMMAND_NOTFOUND, target:target, xml:XML(msg)};
- if (isConnected) {
- send(obj);
- } else {
- sendToBuffer(obj);
- }
- }
-
- // Create a closing node
- xml += createNode("/root");
-
- // Return the xml
- return xml;
- }
-
-
- /**
- * Parse an object
- * @param object: The object to parse
- * @param target: A point seperated path to the object
- * @param functions: Include or exclude functions
- * @param currentDepth: The current trace depth
- * @param maxDepth:: The maximum trace depth
- */
- protected function parseObject(object:*, target:String = "", functions:Boolean = false, currentDepth:int = 1, maxDepth:int = 4):String
- {
- // Variables needed in the loops
- var xml:String = "";
- var childType:String = "";
- var childName:String = "";
- var childTarget:String = "";
- var description:XML = new XML();
- var type:String = "";
- var base:String = "";
- var isXML:Boolean = false;
- var isXMLString:XML;
- var i:int = 0;
- var n:int = 0;
-
- // Check if the max trace depth is reached
- if (maxDepth == -1 || currentDepth <= maxDepth)
- {
- // Create the opening node if needed
- if (currentDepth == 1) xml += createNode("root");
-
- try
- {
- // Get the descriptor
- description = describeType(object);
- type = parseType(description.@name);
- base = parseType(description.@base);
-
-
- if (functions && base == TYPE_FUNCTION)
- {
- // Trace an empty function
- xml += createNode("node", {
- icon: ICON_FUNCTION,
- label: "(Function)",
- name: "",
- type: TYPE_FUNCTION,
- value: "",
- target: target,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- }, true);
- }
-
-
- else if (type == TYPE_ARRAY || type == TYPE_VECTOR)
- {
- // Add data description if needed
- if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
-
- // Create the length property
- // The only property of the array
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: "length" + " (" + TYPE_UINT + ") = " + object["length"],
- name: "length",
- type: TYPE_UINT,
- value: object["length"],
- target: target + "." + "length",
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READONLY
- }, true);
-
- // Get and sort the properties
- var keys:Array = new Array();
- for (var key:* in object) {
- keys.push(key);
- }
- keys.sort();
-
- // Loop through the array
- for (i = 0; i < keys.length; i++)
- {
- // Save the type
- childType = parseType(describeType(object[keys[i]]).@name);
- childTarget = target + "." + String(keys[i]);
-
- // Check if we can create a single string or a new node
- if (childType == TYPE_STRING || childType == TYPE_BOOLEAN || childType == TYPE_NUMBER || childType == TYPE_INT || childType == TYPE_UINT || childType == TYPE_FUNCTION)
- {
- isXML = false;
- isXMLString = new XML();
-
- // Check if the string is a XML string
- if (childType == TYPE_STRING) {
- try {
- isXMLString = new XML(object[keys[i]]);
- if (!isXMLString.hasSimpleContent() && isXMLString.children().length() > 0) isXML = true;
- } catch(error:TypeError) {}
- }
-
- try {
- if (!isXML) {
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: "[" + keys[i] + "] (" + childType + ") = " + printObject(object[keys[i]], childType),
- name: "[" + keys[i] + "]",
- type: childType,
- value: printObject(object[keys[i]], childType),
- target: childTarget,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- }, true);
- } else {
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: "[" + keys[i] + "] (" + childType + ")",
- name: "[" + keys[i] + "]",
- type: childType,
- value: "",
- target: childTarget,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- }, false);
- xml += parseXML(isXMLString, childTarget + "." + "cildren()", currentDepth, maxDepth);
- xml += createNode("/node");
- }
- } catch(error:Error) {}
- }
- else
- {
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: "[" + keys[i] + "] (" + childType + ")",
- name: "[" + keys[i] + "]",
- type: childType,
- value: "",
- target: childTarget,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- });
- try
- {
- // Try to parse the object
- xml += parseObject(object[keys[i]], childTarget, functions, currentDepth + 1, maxDepth);
- }
- catch(error:Error)
- {
- // If this fails add a warning message for the user
- xml += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Unreadable", name:"Unreadable"}, true);
- }
- xml += createNode("/node");
- }
- }
-
- // Close data description if needed
- if (currentDepth == 1) xml += createNode("/node");
- }
-
-
- else if (type == TYPE_OBJECT)
- {
- // Add data description if needed
- if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
-
- // Get and sort the properties
- var properties:Array = new Array();
- for (var prop:* in object) {
- properties.push(prop);
- }
- properties.sort();
-
- // Loop through the array
- for (i = 0; i < properties.length; i++)
- {
- // Save the type
- childType = parseType(describeType(object[properties[i]]).@name);
- childTarget = target + "." + properties[i];
-
- // Check if we can create a single string or a new node
- if (childType == TYPE_STRING || childType == TYPE_BOOLEAN || childType == TYPE_NUMBER || childType == TYPE_INT || childType == TYPE_UINT || childType == TYPE_FUNCTION)
- {
- isXML = false;
- isXMLString = new XML();
-
- // Check if the string is a XML string
- if (childType == TYPE_STRING) {
- try {
- isXMLString = new XML(object[properties[i]]);
- if (!isXMLString.hasSimpleContent() && isXMLString.children().length() > 0) isXML = true;
- } catch(error:TypeError) {}
- }
-
- try {
- if (!isXML) {
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: properties[i] + " (" + childType + ") = " + printObject(object[properties[i]], childType),
- name: properties[i],
- type: childType,
- value: printObject(object[properties[i]], childType),
- target: childTarget,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- }, true);
- } else {
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: properties[i] + " (" + childType + ")",
- name: properties[i],
- type: childType,
- value: "",
- target: childTarget,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- }, false);
- xml += parseXML(isXMLString, childTarget + "." + "cildren()", currentDepth, maxDepth);
- xml += createNode("/node");
- }
- } catch(error:Error) {}
- }
- else
- {
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: properties[i] + " (" + childType + ")",
- name: properties[i],
- type: childType,
- value: "",
- target: childTarget,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- });
- try
- {
- // Try to parse the object
- xml += parseObject(object[properties[i]], childTarget, functions, currentDepth + 1, maxDepth);
- }
- catch(error:Error)
- {
- // If this fails add a warning message for the user
- xml += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Unreadable", name:"Unreadable"}, true);
- }
- xml += createNode("/node");
- }
- }
-
- // Close data description if needed
- if (currentDepth == 1) xml += createNode("/node");
- }
-
-
- else if (type == TYPE_XML)
- {
- // Add data description if needed
- if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
-
- // Parse the XML
- xml += parseXML(object, target + "." + "cildren()", currentDepth, maxDepth);
-
- // Close data description if needed
- if (currentDepth == 1) xml += createNode("/node");
- }
-
-
- else if (type == TYPE_XMLLIST)
- {
- // Add data description if needed
- if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
-
- // Create the length property
- // The only property of the array
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: "length" + " (" + TYPE_UINT + ") = " + object.length(),
- name: "length",
- type: TYPE_UINT,
- value: object.length(),
- target: target + "." + "length",
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READONLY
- }, true);
-
- // Loop through the xml nodes
- for (i = 0; i < object.length(); i++)
- {
- xml += parseXML(object[i], target + "." + String(i) + ".children()", currentDepth, maxDepth);
- }
-
- // Close data description if needed
- if (currentDepth == 1) xml += createNode("/node");
- }
-
-
- else if (type == TYPE_STRING || type == TYPE_BOOLEAN || type == TYPE_NUMBER || type == TYPE_INT || type == TYPE_UINT)
- {
- isXML = false;
- isXMLString = new XML();
-
- // Check if the string is a XML string
- if (type == TYPE_STRING) {
- try {
- isXMLString = new XML(object);
- if (!isXMLString.hasSimpleContent() && isXMLString.children().length() > 0) isXML = true;
- } catch(error:TypeError) {}
- }
-
- try {
- if (!isXML) {
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: "(" + type + ") = " + printObject(object, type),
- name: "",
- type: type,
- value: printObject(object, type),
- target: target,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- }, true);
- } else {
- xml += createNode("node", {
- icon: ICON_VARIABLE,
- label: "(" + type + ")",
- name: "",
- type: type,
- value: "",
- target: target,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- }, false);
- xml += parseXML(isXMLString, target + "." + "cildren()", currentDepth, maxDepth);
- xml += createNode("/node");
- }
- } catch(error:Error) {}
- }
-
-
- else
- {
- // Add data description if needed
- if (currentDepth == 1) xml += createNode("node", {icon:ICON_ROOT, label:"(" + type + ")", target:target});
-
- // Get the data
- var variables:XMLList = description..variable;
- var accessors:XMLList = description..accessor;
- var constants:XMLList = description..constant;
- var methods:XMLList = description..method;
- var variablesArr:Array = new Array();
- var methodsArr:Array = new Array();
- var double:Boolean = false;
- var permission:String = "";
- var icon:String = "";
-
- // Save the variables
- double = false;
- for (i = 0; i < variables.length(); i++) {
- for (n = 0; n < variablesArr.length; n++) {
- if (variablesArr[n].name == variables[i].@name) {
- double = true;
- break;
- }
- }
- if (!double) {
- variablesArr.push({name:variables[i].@name, xml:variables[i], access:ACCESS_VARIABLE});
- }
- }
-
- // Save the accessors
- double = false;
- for (i = 0; i < accessors.length(); i++) {
- for (n = 0; n < variablesArr.length; n++) {
- if (variablesArr[n].name == accessors[i].@name) {
- double = true;
- break;
- }
- }
- if (!double) {
- variablesArr.push({name:accessors[i].@name, xml:accessors[i], access:ACCESS_ACCESSOR});
- }
- }
-
- // Save the constants
- double = false;
- for (i = 0; i < constants.length(); i++) {
- for (n = 0; n < variablesArr.length; n++) {
- if (variablesArr[n].name == constants[i].@name) {
- double = true;
- break;
- }
- }
- if (!double) {
- variablesArr.push({name:constants[i].@name, xml:constants[i], access:ACCESS_CONSTANT});
- }
- }
-
- // Save the methods
- double = false;
- for (i = 0; i < methods.length(); i++) {
- for (n = 0; n < methodsArr.length; n++) {
- if (methodsArr[n].name == methods[i].@name) {
- double = true;
- break;
- }
- }
- if (!double) {
- methodsArr.push({name:methods[i].@name, xml:methods[i], access:ACCESS_METHOD});
- }
- }
-
- // Sort the nodes
- variablesArr.sortOn("name");
- methodsArr.sortOn("name");
-
-
- // VARIABLES
- for (i = 0; i < variablesArr.length; i++)
- {
- // Save the type
- childType = parseType(variablesArr[i].xml.@type);
- childName = variablesArr[i].xml.@name;
- childTarget = target + "." + childName;
-
- // Save the permission and icon
- permission = PERMISSION_READWRITE;
- icon = ICON_VARIABLE;
-
- // Check for read / write permissions
- if (variablesArr[i].access == ACCESS_CONSTANT) {
- // Constant
- permission = PERMISSION_READONLY;
- icon = ICON_VARIABLE_READONLY;
- }
- if (variablesArr[i].xml.@access == PERMISSION_READONLY) {
- // Only a getter
- permission = PERMISSION_READONLY;
- icon = ICON_VARIABLE_READONLY;
- }
- if (variablesArr[i].xml.@access == PERMISSION_WRITEONLY) {
- // Only a setter
- permission = PERMISSION_WRITEONLY;
- icon = ICON_VARIABLE_WRITEONLY;
- }
-
- // Don't include write only accessor
- if (permission != PERMISSION_WRITEONLY)
- {
- // Check if we can create a single string or a new node
- if (childType == TYPE_STRING || childType == TYPE_BOOLEAN || childType == TYPE_NUMBER || childType == TYPE_INT || childType == TYPE_UINT || childType == TYPE_FUNCTION)
- {
- isXML = false;
- isXMLString = new XML();
-
- // Check if the string is a XML string
- if (childType == TYPE_STRING) {
- try {
- isXMLString = new XML(object[childName]);
- if (!isXMLString.hasSimpleContent() && isXMLString.children().length() > 0) isXML = true;
- } catch(error:TypeError) {}
- }
-
- try {
- if (!isXML) {
- xml += createNode("node", {
- icon: icon,
- label: childName + " (" + childType + ") = " + printObject(object[childName], childType),
- name: childName,
- type: childType,
- value: printObject(object[childName], childType),
- target: childTarget,
- access: variablesArr[i].access,
- permission: permission
- }, true);
- } else {
- xml += createNode("node", {
- icon: icon,
- label: childName + " (" + childType + ")",
- name: childName,
- type: childType,
- value: "",
- target: childTarget,
- access: variablesArr[i].access,
- permission: permission
- }, false);
- xml += parseXML(isXMLString, childTarget + "." + "cildren()", currentDepth, maxDepth);
- xml += createNode("/node");
- }
- } catch(error:Error) {}
- }
- else
- {
- xml += createNode("node", {
- icon: icon,
- label: childName + " (" + childType + ")",
- name: childName,
- type: childType,
- target: childTarget,
- access: variablesArr[i].access,
- permission: permission
- });
- try
- {
- // Try to parse the object
- xml += parseObject(object[childName], childTarget, functions, currentDepth + 1, maxDepth);
- }
- catch(error:Error)
- {
- // If this fails add a warning message for the user
- xml += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Unreadable", name:"Unreadable"}, true);
- }
- xml += createNode("/node");
- }
- }
- }
-
-
- // METHODS
- if (functions)
- {
- for (i = 0; i < methodsArr.length; i++)
- {
- // Save the type
- childType = TYPE_FUNCTION;
- childName = methodsArr[i].xml.@name;
- childTarget = target + "." + childName;
-
- // Save the parameters
- var returnType:String = parseType(methodsArr[i].xml.@returnType);
- var parameters:XMLList = methodsArr[i].xml..parameter;
- var args:Array = new Array();
-
- // Create the parameters
- for (n = 0; n < parameters.length(); n++) {
- args.push(parseType(parameters[n].@type));
- }
-
- // Create the node
- xml += createNode("node", {
- icon: ICON_FUNCTION,
- label: childName + "(" + args.join(", ") + "):" + returnType,
- args: args.join(", "),
- name: childName,
- type: TYPE_FUNCTION,
- access: variablesArr[i].access,
- returnType: returnType,
- target: childTarget
- }, true);
- }
- }
-
- // Close data description if needed
- if (currentDepth == 1) xml += createNode("/node");
- }
- }
- catch (error:Error)
- {
- // The object is not found
- var msg:String = "";
- msg += createNode("root");
- msg += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Not found", name:"Not found"}, true);
- msg += createNode("/root");
- var obj:Object = {text:COMMAND_NOTFOUND, target:target, xml:XML(msg)};
- if (isConnected) {
- send(obj);
- } else {
- sendToBuffer(obj);
- }
- }
-
- // Create a closing node if needed
- if (currentDepth == 1) xml += createNode("/root");
- }
-
- //Return the xml
- return xml;
- }
-
-
- /**
- * Parse a display object
- * @param object: The object to parse
- * @param target: A point seperated path to the object
- * @param functions: Include or exclude functions
- * @param currentDepth: The current trace depth
- * @param maxDepth:: The maximum trace depth
- */
- protected function parseDisplayObject(object:*, target:String = "", functions:Boolean = false, currentDepth:int = 1, maxDepth:int = 4):String
- {
- // Variables needed in the loops
- var xml:String = "";
- var childs:Array;
- var child:DisplayObject;
- var childType:String = "";
- var childIcon:String = "";
- var childName:String = "";
- var childTarget:String = "";
- var childChildren:String = "";
- var i:int = 0;
-
- // Check if the max trace depth is reached
- if (maxDepth == -1 || currentDepth <= maxDepth)
- {
- // Create the opening node if needed
- if (currentDepth == 1) xml += createNode("root");
-
- try
- {
- // Add data description if needed
- if (currentDepth == 1) {
- var ojectName:String = DisplayObject(object).name;
- if (ojectName == null || ojectName == "null") {
- ojectName = "DisplayObject";
- }
- xml += createNode("node", {icon:ICON_ROOT, label:"(" + ojectName + ")", target:target});
- }
-
- // Get the childs
- childs = new Array();
- for (i = 0; i < DisplayObjectContainer(object).numChildren; i++) {
- childs.push(DisplayObjectContainer(object).getChildAt(i));
- }
-
- // Loop through the array
- for (i = 0; i < childs.length; i++)
- {
- // Save the child properties
- child = childs[i];
- childName = describeType(child).@name;
- childType = parseType(childName);
- childTarget = target + "." + "getChildAt(" + i + ")";
- childIcon = child is DisplayObjectContainer ? ICON_ROOT : ICON_VARIABLE;
- childChildren = child is DisplayObjectContainer ? String(DisplayObjectContainer(child).numChildren) : "";
-
- // Create the node
- xml += createNode("node", {
- icon: childIcon,
- label: child.name + " (" + childType + ") " + childChildren,
- name: child.name,
- type: childType,
- value: printObject(child, childType),
- target: childTarget,
- access: ACCESS_VARIABLE,
- permission: PERMISSION_READWRITE
- });
-
- try
- {
- // Try to parse the object
- xml += parseDisplayObject(child, childTarget, functions, currentDepth + 1, maxDepth);
- }
- catch(error:Error)
- {
- // If this fails add a warning message for the user
- xml += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Unreadable", name:"Unreadable"}, true);
- }
-
- xml += createNode("/node");
- }
-
- // Create a closing node if needed
- if (currentDepth == 1) xml += createNode("/node");
- }
- catch (error:Error)
- {
- // The object is not found
- var msg:String = "";
- msg += createNode("root");
- msg += createNode("node", {icon:ICON_WARNING, type:TYPE_WARNING, label:"Not found", name:"Not found"}, true);
- msg += createNode("/root");
- var obj:Object = {text:COMMAND_NOTFOUND, target:target, xml:XML(msg)};
- if (isConnected) {
- send(obj);
- } else {
- sendToBuffer(obj);
- }
- }
-
- // Create a closing node if needed
- if (currentDepth == 1) xml += createNode("/root");
- }
-
- //Return the xml
- return xml;
-
- }
-
-
- /**
- * Parse a XML node
- * @param node: The xml to parse
- * @param target: A point seperated path to the object
- * @param currentDepth: The current trace depth
- * @param maxDepth:: The maximum trace depth
- */
- protected function parseXML(node:*, target:String = "", currentDep…
Large files files are truncated, but you can click here to view the full file