You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2014/03/12 05:36:36 UTC
[2/7] more legacy classes need to make mustella happy. Some are
stripped down to eliminate undesirable dependencies
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/dec3558f/frameworks/as/projects/MXMLCClasses/src/mx/utils/ObjectUtil.as
----------------------------------------------------------------------
diff --git a/frameworks/as/projects/MXMLCClasses/src/mx/utils/ObjectUtil.as b/frameworks/as/projects/MXMLCClasses/src/mx/utils/ObjectUtil.as
new file mode 100644
index 0000000..bdf69ab
--- /dev/null
+++ b/frameworks/as/projects/MXMLCClasses/src/mx/utils/ObjectUtil.as
@@ -0,0 +1,1424 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+import flash.utils.ByteArray;
+import flash.utils.Dictionary;
+import flash.utils.getQualifiedClassName;
+import flash.xml.XMLNode;
+
+/**
+ * The ObjectUtil class is an all-static class with methods for
+ * working with Objects within Flex.
+ * You do not create instances of ObjectUtil;
+ * instead you simply call static methods such as the
+ * <code>ObjectUtil.isSimple()</code> method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class ObjectUtil
+{
+
+ /**
+ * Array of properties to exclude from debugging output.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private static var defaultToStringExcludes:Array = ["password", "credentials"];
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Compares the Objects and returns an integer value
+ * indicating if the first item is less than greater than or equal to
+ * the second item.
+ * This method will recursively compare properties on nested objects and
+ * will return as soon as a non-zero result is found.
+ * By default this method will recurse to the deepest level of any property.
+ * To change the depth for comparison specify a non-negative value for
+ * the <code>depth</code> parameter.
+ *
+ * @param a Object.
+ *
+ * @param b Object.
+ *
+ * @param depth Indicates how many levels should be
+ * recursed when performing the comparison.
+ * Set this value to 0 for a shallow comparison of only the primitive
+ * representation of each property.
+ * For example:<pre>
+ * var a:Object = {name:"Bob", info:[1,2,3]};
+ * var b:Object = {name:"Alice", info:[5,6,7]};
+ * var c:int = ObjectUtil.compare(a, b, 0);</pre>
+ *
+ * <p>In the above example the complex properties of <code>a</code> and
+ * <code>b</code> will be flattened by a call to <code>toString()</code>
+ * when doing the comparison.
+ * In this case the <code>info</code> property will be turned into a string
+ * when performing the comparison.</p>
+ *
+ * @return Return 0 if a and b are null, NaN, or equal.
+ * Return 1 if a is null or greater than b.
+ * Return -1 if b is null or greater than a.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function compare(a:Object, b:Object, depth:int = -1):int
+ {
+ return internalCompare(a, b, 0, depth, new Dictionary(true));
+ }
+
+ /**
+ * Copies the specified Object and returns a reference to the copy.
+ * The copy is made using a native serialization technique.
+ * This means that custom serialization will be respected during the copy.
+ *
+ * <p>This method is designed for copying data objects,
+ * such as elements of a collection. It is not intended for copying
+ * a UIComponent object, such as a TextInput control. If you want to create copies
+ * of specific UIComponent objects, you can create a subclass of the component and implement
+ * a <code>clone()</code> method, or other method to perform the copy.</p>
+ *
+ * @param value Object that should be copied.
+ *
+ * @return Copy of the specified Object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function copy(value:Object):Object
+ {
+ var buffer:ByteArray = new ByteArray();
+ buffer.writeObject(value);
+ buffer.position = 0;
+ var result:Object = buffer.readObject();
+ return result;
+ }
+
+ /**
+ * Clones the specified Object and returns a reference to the clone.
+ * The clone is made using a native serialization technique.
+ * This means that custom serialization will be respected during the
+ * cloning. clone() differs from copy() in that the uid property of
+ * each object instance is retained.
+ *
+ * <p>This method is designed for cloning data objects,
+ * such as elements of a collection. It is not intended for cloning
+ * a UIComponent object, such as a TextInput control. If you want to clone
+ * specific UIComponent objects, you can create a subclass of the component
+ * and implement a <code>clone()</code> method.</p>
+ *
+ * @param value Object that should be cloned.
+ *
+ * @return Clone of the specified Object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4
+ */
+ public static function clone(value:Object):Object
+ {
+ var result:Object = copy(value);
+ cloneInternal(result, value);
+ return result;
+ }
+
+ /**
+ * Recursive helper used by the public clone method.
+ * @private
+ */
+ private static function cloneInternal(result:Object, value:Object):void
+ {
+ if (value && value.hasOwnProperty("uid"))
+ result.uid = value.uid;
+
+ var classInfo:Object = getClassInfo(value);
+ var v:Object;
+ for each (var p:* in classInfo.properties)
+ {
+ v = value[p];
+ if (v && v.hasOwnProperty("uid"))
+ cloneInternal(result[p], v);
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if the object reference specified
+ * is a simple data type. The simple data types include the following:
+ * <ul>
+ * <li><code>String</code></li>
+ * <li><code>Number</code></li>
+ * <li><code>uint</code></li>
+ * <li><code>int</code></li>
+ * <li><code>Boolean</code></li>
+ * <li><code>Date</code></li>
+ * <li><code>Array</code></li>
+ * </ul>
+ *
+ * @param value Object inspected.
+ *
+ * @return <code>true</code> if the object specified
+ * is one of the types above; <code>false</code> otherwise.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isSimple(value:Object):Boolean
+ {
+ var type:String = typeof(value);
+ switch (type)
+ {
+ case "number":
+ case "string":
+ case "boolean":
+ {
+ return true;
+ }
+
+ case "object":
+ {
+ return (value is Date) || (value is Array);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Compares two numeric values.
+ *
+ * @param a First number.
+ *
+ * @param b Second number.
+ *
+ * @return 0 is both numbers are NaN.
+ * 1 if only <code>a</code> is a NaN.
+ * -1 if only <code>b</code> is a NaN.
+ * -1 if <code>a</code> is less than <code>b</code>.
+ * 1 if <code>a</code> is greater than <code>b</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function numericCompare(a:Number, b:Number):int
+ {
+ if (isNaN(a) && isNaN(b))
+ return 0;
+
+ if (isNaN(a))
+ return 1;
+
+ if (isNaN(b))
+ return -1;
+
+ if (a < b)
+ return -1;
+
+ if (a > b)
+ return 1;
+
+ return 0;
+ }
+
+ /**
+ * Compares two String values.
+ *
+ * @param a First String value.
+ *
+ * @param b Second String value.
+ *
+ * @param caseInsensitive Specifies to perform a case insensitive compare,
+ * <code>true</code>, or not, <code>false</code>.
+ *
+ * @return 0 is both Strings are null.
+ * 1 if only <code>a</code> is null.
+ * -1 if only <code>b</code> is null.
+ * -1 if <code>a</code> precedes <code>b</code>.
+ * 1 if <code>b</code> precedes <code>a</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function stringCompare(a:String, b:String,
+ caseInsensitive:Boolean = false):int
+ {
+ if (a == null && b == null)
+ return 0;
+
+ if (a == null)
+ return 1;
+
+ if (b == null)
+ return -1;
+
+ // Convert to lowercase if we are case insensitive.
+ if (caseInsensitive)
+ {
+ a = a.toLocaleLowerCase();
+ b = b.toLocaleLowerCase();
+ }
+
+ var result:int = a.localeCompare(b);
+
+ if (result < -1)
+ result = -1;
+ else if (result > 1)
+ result = 1;
+
+ return result;
+ }
+
+ /**
+ * Compares the two Date objects and returns an integer value
+ * indicating if the first Date object is before, equal to,
+ * or after the second item.
+ *
+ * @param a Date object.
+ *
+ * @param b Date object.
+ *
+ * @return 0 if <code>a</code> and <code>b</code> are equal
+ * (or both are <code>null</code>);
+ * -1 if <code>a</code> is before <code>b</code>
+ * (or <code>b</code> is <code>null</code>);
+ * 1 if <code>a</code> is after <code>b</code>
+ * (or <code>a</code> is <code>null</code>);
+ * 0 is both dates getTime's are NaN;
+ * 1 if only <code>a</code> getTime is a NaN;
+ * -1 if only <code>b</code> getTime is a NaN.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function dateCompare(a:Date, b:Date):int
+ {
+ if (a == null && b == null)
+ return 0;
+
+ if (a == null)
+ return 1;
+
+ if (b == null)
+ return -1;
+
+ var na:Number = a.getTime();
+ var nb:Number = b.getTime();
+
+ if (na < nb)
+ return -1;
+
+ if (na > nb)
+ return 1;
+
+ if (isNaN(na) && isNaN(nb))
+ return 0;
+
+ if (isNaN(na))
+ return 1;
+
+ if (isNaN(nb))
+ return -1;
+
+ return 0;
+ }
+
+ /**
+ * Pretty-prints the specified Object into a String.
+ * All properties will be in alpha ordering.
+ * Each object will be assigned an id during printing;
+ * this value will be displayed next to the object type token
+ * preceded by a '#', for example:
+ *
+ * <pre>
+ * (mx.messaging.messages::AsyncMessage)#2.</pre>
+ *
+ * <p>This id is used to indicate when a circular reference occurs.
+ * Properties of an object that are of the <code>Class</code> type will
+ * appear only as the assigned type.
+ * For example a custom definition like the following:</p>
+ *
+ * <pre>
+ * public class MyCustomClass {
+ * public var clazz:Class;
+ * }</pre>
+ *
+ * <p>With the <code>clazz</code> property assigned to <code>Date</code>
+ * will display as shown below:</p>
+ *
+ * <pre>
+ * (somepackage::MyCustomClass)#0
+ * clazz = (Date)</pre>
+ *
+ * @param obj Object to be pretty printed.
+ *
+ * @param namespaceURIs Array of namespace URIs for properties
+ * that should be included in the output.
+ * By default only properties in the public namespace will be included in
+ * the output.
+ * To get all properties regardless of namespace pass an array with a
+ * single element of "*".
+ *
+ * @param exclude Array of the property names that should be
+ * excluded from the output.
+ * Use this to remove data from the formatted string.
+ *
+ * @return String containing the formatted version
+ * of the specified object.
+ *
+ * @example
+ * <pre>
+ * // example 1
+ * var obj:AsyncMessage = new AsyncMessage();
+ * obj.body = [];
+ * obj.body.push(new AsyncMessage());
+ * obj.headers["1"] = { name: "myName", num: 15.3};
+ * obj.headers["2"] = { name: "myName", num: 15.3};
+ * obj.headers["10"] = { name: "myName", num: 15.3};
+ * obj.headers["11"] = { name: "myName", num: 15.3};
+ * trace(ObjectUtil.toString(obj));
+ *
+ * // will output to flashlog.txt
+ * (mx.messaging.messages::AsyncMessage)#0
+ * body = (Array)#1
+ * [0] (mx.messaging.messages::AsyncMessage)#2
+ * body = (Object)#3
+ * clientId = (Null)
+ * correlationId = ""
+ * destination = ""
+ * headers = (Object)#4
+ * messageId = "378CE96A-68DB-BC1B-BCF7FFFFFFFFB525"
+ * sequenceId = (Null)
+ * sequencePosition = 0
+ * sequenceSize = 0
+ * timeToLive = 0
+ * timestamp = 0
+ * clientId = (Null)
+ * correlationId = ""
+ * destination = ""
+ * headers = (Object)#5
+ * 1 = (Object)#6
+ * name = "myName"
+ * num = 15.3
+ * 10 = (Object)#7
+ * name = "myName"
+ * num = 15.3
+ * 11 = (Object)#8
+ * name = "myName"
+ * num = 15.3
+ * 2 = (Object)#9
+ * name = "myName"
+ * num = 15.3
+ * messageId = "1D3E6E96-AC2D-BD11-6A39FFFFFFFF517E"
+ * sequenceId = (Null)
+ * sequencePosition = 0
+ * sequenceSize = 0
+ * timeToLive = 0
+ * timestamp = 0
+ *
+ * // example 2 with circular references
+ * obj = {};
+ * obj.prop1 = new Date();
+ * obj.prop2 = [];
+ * obj.prop2.push(15.2);
+ * obj.prop2.push("testing");
+ * obj.prop2.push(true);
+ * obj.prop3 = {};
+ * obj.prop3.circular = obj;
+ * obj.prop3.deeper = new ErrorMessage();
+ * obj.prop3.deeper.rootCause = obj.prop3.deeper;
+ * obj.prop3.deeper2 = {};
+ * obj.prop3.deeper2.deeperStill = {};
+ * obj.prop3.deeper2.deeperStill.yetDeeper = obj;
+ * trace(ObjectUtil.toString(obj));
+ *
+ * // will output to flashlog.txt
+ * (Object)#0
+ * prop1 = Tue Apr 26 13:59:17 GMT-0700 2005
+ * prop2 = (Array)#1
+ * [0] 15.2
+ * [1] "testing"
+ * [2] true
+ * prop3 = (Object)#2
+ * circular = (Object)#0
+ * deeper = (mx.messaging.messages::ErrorMessage)#3
+ * body = (Object)#4
+ * clientId = (Null)
+ * code = (Null)
+ * correlationId = ""
+ * destination = ""
+ * details = (Null)
+ * headers = (Object)#5
+ * level = (Null)
+ * message = (Null)
+ * messageId = "14039376-2BBA-0D0E-22A3FFFFFFFF140A"
+ * rootCause = (mx.messaging.messages::ErrorMessage)#3
+ * sequenceId = (Null)
+ * sequencePosition = 0
+ * sequenceSize = 0
+ * timeToLive = 0
+ * timestamp = 0
+ * deeper2 = (Object)#6
+ * deeperStill = (Object)#7
+ * yetDeeper = (Object)#0
+ *
+ * // example 3 with Dictionary
+ * var point:Point = new Point(100, 100);
+ * var point2:Point = new Point(100, 100);
+ * var obj:Dictionary = new Dictionary();
+ * obj[point] = "point";
+ * obj[point2] = "point2";
+ * obj["1"] = { name: "one", num: 1};
+ * obj["two"] = { name: "2", num: 2};
+ * obj[3] = 3;
+ * trace(ObjectUtil.toString(obj));
+ *
+ * // will output to flashlog.txt
+ * (flash.utils::Dictionary)#0
+ * {(flash.geom::Point)#1
+ * length = 141.4213562373095
+ * x = 100
+ * y = 100} = "point2"
+ * {(flash.geom::Point)#2
+ * length = 141.4213562373095
+ * x = 100
+ * y = 100} = "point"
+ * {1} = (Object)#3
+ * name = "one"
+ * num = 1
+ * {3} = 3
+ * {"two"} = (Object)#4
+ * name = "2"
+ * num = 2
+ *
+ * </pre>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function toString(value:Object,
+ namespaceURIs:Array = null,
+ exclude:Array = null):String
+ {
+ if (exclude == null)
+ {
+ exclude = defaultToStringExcludes;
+ }
+
+ refCount = 0;
+ return internalToString(value, 0, null, namespaceURIs, exclude);
+ }
+
+ /**
+ * This method cleans up all of the additional parameters that show up in AsDoc
+ * code hinting tools that developers shouldn't ever see.
+ * @private
+ */
+ private static function internalToString(value:Object,
+ indent:int = 0,
+ refs:Dictionary= null,
+ namespaceURIs:Array = null,
+ exclude:Array = null):String
+ {
+ var str:String;
+ var type:String = value == null ? "null" : typeof(value);
+ switch (type)
+ {
+ case "boolean":
+ case "number":
+ {
+ return value.toString();
+ }
+
+ case "string":
+ {
+ return "\"" + value.toString() + "\"";
+ }
+
+ case "object":
+ {
+ if (value is Date)
+ {
+ return value.toString();
+ }
+ else if (value is XMLNode)
+ {
+ return value.toString();
+ }
+ else if (value is Class)
+ {
+ return "(" + getQualifiedClassName(value) + ")";
+ }
+ else
+ {
+ var classInfo:Object = getClassInfo(value, exclude,
+ { includeReadOnly: true, uris: namespaceURIs });
+
+ var properties:Array = classInfo.properties;
+
+ str = "(" + classInfo.name + ")";
+
+ // refs help us avoid circular reference infinite recursion.
+ // Each time an object is encoumtered it is pushed onto the
+ // refs stack so that we can determine if we have visited
+ // this object already.
+ if (refs == null)
+ refs = new Dictionary(true);
+
+ // Check to be sure we haven't processed this object before
+ // Dictionary has some bugs, so we want to work around them as best we can
+ try
+ {
+ var id:Object = refs[value];
+ if (id != null)
+ {
+ str += "#" + int(id);
+ return str;
+ }
+ }
+ catch (e:Error)
+ {
+ //Since we can't test for infinite loop, we simply return toString.
+ return String(value);
+ }
+
+ if (value != null)
+ {
+ str += "#" + refCount.toString();
+ refs[value] = refCount;
+ refCount++;
+ }
+
+ var isArray:Boolean = value is Array;
+ var isDict:Boolean = value is Dictionary;
+ var prop:*;
+ indent += 2;
+
+ // Print all of the variable values.
+ for (var j:int = 0; j < properties.length; j++)
+ {
+ str = newline(str, indent);
+ prop = properties[j];
+
+ if (isArray)
+ str += "[";
+ else if (isDict)
+ str += "{";
+
+
+ if (isDict)
+ {
+ // in dictionaries, recurse on the key, because it can be a complex object
+ str += internalToString(prop, indent, refs,
+ namespaceURIs, exclude);
+ }
+ else
+ {
+ str += prop.toString();
+ }
+
+ if (isArray)
+ str += "] ";
+ else if (isDict)
+ str += "} = ";
+ else
+ str += " = ";
+
+ try
+ {
+ // print the value
+ str += internalToString(value[prop], indent, refs,
+ namespaceURIs, exclude);
+ }
+ catch(e:Error)
+ {
+ // value[prop] can cause an RTE
+ // for certain properties of certain objects.
+ // For example, accessing the properties
+ // actionScriptVersion
+ // childAllowsParent
+ // frameRate
+ // height
+ // loader
+ // parentAllowsChild
+ // sameDomain
+ // swfVersion
+ // width
+ // of a Stage's loaderInfo causes
+ // Error #2099: The loading object is not
+ // sufficiently loaded to provide this information
+ // In this case, we simply output ? for the value.
+ str += "?";
+ }
+ }
+ indent -= 2;
+ return str;
+ }
+ break;
+ }
+
+ case "xml":
+ {
+ return value.toXMLString();
+ }
+
+ default:
+ {
+ return "(" + type + ")";
+ }
+ }
+
+ return "(unknown)";
+ }
+
+ /**
+ * @private
+ * This method will append a newline and the specified number of spaces
+ * to the given string.
+ */
+ private static function newline(str:String, n:int = 0):String
+ {
+ var result:String = str;
+ result += "\n";
+
+ for (var i:int = 0; i < n; i++)
+ {
+ result += " ";
+ }
+ return result;
+ }
+
+ private static function internalCompare(a:Object, b:Object,
+ currentDepth:int, desiredDepth:int,
+ refs:Dictionary):int
+ {
+ if (a == null && b == null)
+ return 0;
+
+ if (a == null)
+ return 1;
+
+ if (b == null)
+ return -1;
+
+ if (a is ObjectProxy)
+ a = ObjectProxy(a).object_proxy::object;
+
+ if (b is ObjectProxy)
+ b = ObjectProxy(b).object_proxy::object;
+
+ var typeOfA:String = typeof(a);
+ var typeOfB:String = typeof(b);
+
+ var result:int = 0;
+
+ if (typeOfA == typeOfB)
+ {
+ switch(typeOfA)
+ {
+ case "boolean":
+ {
+ result = numericCompare(Number(a), Number(b));
+ break;
+ }
+
+ case "number":
+ {
+ result = numericCompare(a as Number, b as Number);
+ break;
+ }
+
+ case "string":
+ {
+ result = stringCompare(a as String, b as String);
+ break;
+ }
+
+ case "object":
+ {
+ var newDepth:int = desiredDepth > 0 ? desiredDepth -1 : desiredDepth;
+
+ // refs help us avoid circular reference infinite recursion.
+ var aRef:Object = getRef(a,refs);
+ var bRef:Object = getRef(b,refs);
+
+ if (aRef == bRef)
+ return 0;
+ // the cool thing about our dictionary is that if
+ // we've seen objects and determined that they are inequal, then
+ // we would've already exited out of this compare() call. So the
+ // only info in the dictionary are sets of equal items
+
+ // let's first define them as equal
+ // this stops an "infinite loop" problem where A.i = B and B.i = A
+ // if we later find that an object (one of the subobjects) is in fact unequal,
+ // then we will return false and quit out of everything. These refs are thrown away
+ // so it doesn't matter if it's correct.
+ refs[bRef] = aRef;
+
+ if (desiredDepth != -1 && (currentDepth > desiredDepth))
+ {
+ // once we try to go beyond the desired depth we should
+ // toString() our way out
+ result = stringCompare(a.toString(), b.toString());
+ }
+ else if ((a is Array) && (b is Array))
+ {
+ result = arrayCompare(a as Array, b as Array, currentDepth, desiredDepth, refs);
+ }
+ else if ((a is Date) && (b is Date))
+ {
+ result = dateCompare(a as Date, b as Date);
+ }
+ else if ((a is ByteArray) && (b is ByteArray))
+ {
+ result = byteArrayCompare(a as ByteArray, b as ByteArray);
+ }
+ else if (getQualifiedClassName(a) == getQualifiedClassName(b))
+ {
+ var aProps:Array = getClassInfo(a).properties;
+ var bProps:Array;
+
+ // if the objects are dynamic they could have different
+ // # of properties and should be treated on that basis first
+ var isDynamicObject:Boolean = isDynamicObject(a);
+
+ // if it's dynamic, check to see that they have all the same properties
+ if (isDynamicObject)
+ {
+ bProps = getClassInfo(b).properties;
+ result = arrayCompare(aProps, bProps, currentDepth, newDepth, refs);
+ if (result != 0)
+ return result;
+ }
+
+ // now that we know we have the same properties, let's compare the values
+ var propName:QName;
+ var aProp:Object;
+ var bProp:Object;
+ for (var i:int = 0; i < aProps.length; i++)
+ {
+ propName = aProps[i];
+ aProp = a[propName];
+ bProp = b[propName];
+ result = internalCompare(aProp, bProp, currentDepth+1, newDepth, refs);
+ if (result != 0)
+ {
+ return result;
+ }
+ }
+ }
+ else
+ {
+ // We must be inequal, so return 1
+ return 1;
+ }
+ break;
+ }
+ }
+ }
+ else // be consistent with the order we return here
+ {
+ return stringCompare(typeOfA, typeOfB);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns information about the class, and properties of the class, for
+ * the specified Object.
+ *
+ * @param obj The Object to inspect.
+ *
+ * @param exclude Array of Strings specifying the property names that should be
+ * excluded from the returned result. For example, you could specify
+ * <code>["currentTarget", "target"]</code> for an Event object since these properties
+ * can cause the returned result to become large.
+ *
+ * @param options An Object containing one or more properties
+ * that control the information returned by this method.
+ * The properties include the following:
+ *
+ * <ul>
+ * <li><code>includeReadOnly</code>: If <code>false</code>,
+ * exclude Object properties that are read-only.
+ * The default value is <code>true</code>.</li>
+ * <li><code>includeTransient</code>: If <code>false</code>,
+ * exclude Object properties and variables that have <code>[Transient]</code> metadata.
+ * The default value is <code>true</code>.</li>
+ * <li><code>uris</code>: Array of Strings of all namespaces that should be included in the output.
+ * It does allow for a wildcard of "~~".
+ * By default, it is null, meaning no namespaces should be included.
+ * For example, you could specify <code>["mx_internal", "mx_object"]</code>
+ * or <code>["~~"]</code>.</li>
+ * </ul>
+ *
+ * @return An Object containing the following properties:
+ * <ul>
+ * <li><code>name</code>: String containing the name of the class.</li>
+ * <li><code>properties</code>: Sorted list of the property names of the specified object,
+ * or references to the original key if the specified object is a Dictionary. The individual
+ * array elements are QName instances, which contain both the local name of the property as well as the URI.</li>
+ * </ul>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function getClassInfo(obj:Object,
+ excludes:Array = null,
+ options:Object = null):Object
+ {
+ var n:int;
+ var i:int;
+
+ if (obj is ObjectProxy)
+ obj = ObjectProxy(obj).object_proxy::object;
+
+ if (options == null)
+ options = { includeReadOnly: true, uris: null, includeTransient: true };
+
+ var result:Object;
+ var propertyNames:Array = [];
+ var cacheKey:String;
+
+ var className:String;
+ var classAlias:String;
+ var properties:XMLList;
+ var prop:XML;
+ var dynamic:Boolean = false;
+ var metadataInfo:Object;
+
+ if (typeof(obj) == "xml")
+ {
+ className = "XML";
+ properties = obj.text();
+ if (properties.length())
+ propertyNames.push("*");
+ properties = obj.attributes();
+ }
+ else
+ {
+ var classInfo:XML = DescribeTypeCache.describeType(obj).typeDescription;
+ className = classInfo.@name.toString();
+ classAlias = classInfo.@alias.toString();
+ dynamic = (classInfo.@isDynamic.toString() == "true");
+
+ if (options.includeReadOnly)
+ properties = classInfo..accessor.(@access != "writeonly") + classInfo..variable;
+ else
+ properties = classInfo..accessor.(@access == "readwrite") + classInfo..variable;
+
+ var numericIndex:Boolean = false;
+ }
+
+ // If type is not dynamic, check our cache for class info...
+ if (!dynamic)
+ {
+ cacheKey = getCacheKey(obj, excludes, options);
+ result = CLASS_INFO_CACHE[cacheKey];
+ if (result != null)
+ return result;
+ }
+
+ result = {};
+ result["name"] = className;
+ result["alias"] = classAlias;
+ result["properties"] = propertyNames;
+ result["dynamic"] = dynamic;
+ result["metadata"] = metadataInfo = recordMetadata(properties);
+
+ var excludeObject:Object = {};
+ if (excludes)
+ {
+ n = excludes.length;
+ for (i = 0; i < n; i++)
+ {
+ excludeObject[excludes[i]] = 1;
+ }
+ }
+
+ var isArray:Boolean = (obj is Array);
+ var isDict:Boolean = (obj is Dictionary);
+
+ if (isDict)
+ {
+ // dictionaries can have multiple keys of the same type,
+ // (they can index by reference rather than QName, String, or number),
+ // which cannot be looked up by QName, so use references to the actual key
+ for (var key:* in obj)
+ {
+ propertyNames.push(key);
+ }
+ }
+ else if (dynamic)
+ {
+ for (var p:String in obj)
+ {
+ if (excludeObject[p] != 1)
+ {
+ if (isArray)
+ {
+ var pi:Number = parseInt(p);
+ if (isNaN(pi))
+ propertyNames.push(new QName("", p));
+ else
+ propertyNames.push(pi);
+ }
+ else
+ {
+ propertyNames.push(new QName("", p));
+ }
+ }
+ }
+ numericIndex = isArray && !isNaN(Number(p));
+ }
+
+ if (isArray || isDict || className == "Object")
+ {
+ // Do nothing since we've already got the dynamic members
+ }
+ else if (className == "XML")
+ {
+ n = properties.length();
+ for (i = 0; i < n; i++)
+ {
+ p = properties[i].name();
+ if (excludeObject[p] != 1)
+ propertyNames.push(new QName("", "@" + p));
+ }
+ }
+ else
+ {
+ n = properties.length();
+ var uris:Array = options.uris;
+ var uri:String;
+ var qName:QName;
+ for (i = 0; i < n; i++)
+ {
+ prop = properties[i];
+ p = prop.@name.toString();
+ uri = prop.@uri.toString();
+
+ if (excludeObject[p] == 1)
+ continue;
+
+ if (!options.includeTransient && internalHasMetadata(metadataInfo, p, "Transient"))
+ continue;
+
+ if (uris != null)
+ {
+ if (uris.length == 1 && uris[0] == "*")
+ {
+ qName = new QName(uri, p);
+ try
+ {
+ obj[qName]; // access the property to ensure it is supported
+ propertyNames.push();
+ }
+ catch(e:Error)
+ {
+ // don't keep property name
+ }
+ }
+ else
+ {
+ for (var j:int = 0; j < uris.length; j++)
+ {
+ uri = uris[j];
+ if (prop.@uri.toString() == uri)
+ {
+ qName = new QName(uri, p);
+ try
+ {
+ obj[qName];
+ propertyNames.push(qName);
+ }
+ catch(e:Error)
+ {
+ // don't keep property name
+ }
+ }
+ }
+ }
+ }
+ else if (uri.length == 0)
+ {
+ qName = new QName(uri, p);
+ try
+ {
+ obj[qName];
+ propertyNames.push(qName);
+ }
+ catch(e:Error)
+ {
+ // don't keep property name
+ }
+ }
+ }
+ }
+
+ propertyNames.sort(Array.CASEINSENSITIVE |
+ (numericIndex ? Array.NUMERIC : 0));
+
+ // dictionary keys can be indexed by an object reference
+ // there's a possibility that two keys will have the same toString()
+ // so we don't want to remove dupes
+ if (!isDict)
+ {
+ // for Arrays, etc., on the other hand...
+ // remove any duplicates, i.e. any items that can't be distingushed by toString()
+ for (i = 0; i < propertyNames.length - 1; i++)
+ {
+ // the list is sorted so any duplicates should be adjacent
+ // two properties are only equal if both the uri and local name are identical
+ if (propertyNames[i].toString() == propertyNames[i + 1].toString())
+ {
+ propertyNames.splice(i, 1);
+ i--; // back up
+ }
+ }
+ }
+
+ // For normal, non-dynamic classes we cache the class info
+ // Don't cache XML as it can be dynamic
+ if (!dynamic && className != "XML")
+ {
+ cacheKey = getCacheKey(obj, excludes, options);
+ CLASS_INFO_CACHE[cacheKey] = result;
+ }
+
+ return result;
+ }
+
+ /**
+ * Uses <code>getClassInfo</code> and examines the metadata information to
+ * determine whether a property on a given object has the specified
+ * metadata.
+ *
+ * @param obj The object holding the property.
+ * @param propName The property to check for metadata.
+ * @param metadataName The name of the metadata to check on the property.
+ * @param excludes If any properties need to be excluded when generating class info. (Optional)
+ * @param options If any options flags need to changed when generating class info. (Optional)
+ * @return true if the property has the specified metadata.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function hasMetadata(obj:Object,
+ propName:String,
+ metadataName:String,
+ excludes:Array = null,
+ options:Object = null):Boolean
+ {
+ var classInfo:Object = getClassInfo(obj, excludes, options);
+ var metadataInfo:Object = classInfo["metadata"];
+ return internalHasMetadata(metadataInfo, propName, metadataName);
+ }
+
+ /**
+ * Returns <code>true</code> if the object is an instance of a dynamic class.
+ *
+ * @param obj The object.
+ *
+ * @return <code>true</code> if the object is an instance of a dynamic class.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isDynamicObject(obj:Object):Boolean
+ {
+ try
+ {
+ // this test for checking whether an object is dynamic or not is
+ // pretty hacky, but it assumes that no-one actually has a
+ // property defined called "wootHackwoot"
+ obj["wootHackwoot"];
+ }
+ catch (e:Error)
+ {
+ // our object isn't from a dynamic class
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @private
+ */
+ private static function internalHasMetadata(metadataInfo:Object, propName:String, metadataName:String):Boolean
+ {
+ if (metadataInfo != null)
+ {
+ var metadata:Object = metadataInfo[propName];
+ if (metadata != null)
+ {
+ if (metadata[metadataName] != null)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @private
+ */
+ private static function recordMetadata(properties:XMLList):Object
+ {
+ var result:Object = null;
+
+ try
+ {
+ for each (var prop:XML in properties)
+ {
+ var propName:String = prop.attribute("name").toString();
+ var metadataList:XMLList = prop.metadata;
+
+ if (metadataList.length() > 0)
+ {
+ if (result == null)
+ result = {};
+
+ var metadata:Object = {};
+ result[propName] = metadata;
+
+ for each (var md:XML in metadataList)
+ {
+ var mdName:String = md.attribute("name").toString();
+
+ var argsList:XMLList = md.arg;
+ var value:Object = {};
+
+ for each (var arg:XML in argsList)
+ {
+ var argKey:String = arg.attribute("key").toString();
+ if (argKey != null)
+ {
+ var argValue:String = arg.attribute("value").toString();
+ value[argKey] = argValue;
+ }
+ }
+
+ var existing:Object = metadata[mdName];
+ if (existing != null)
+ {
+ var existingArray:Array;
+ if (existing is Array)
+ existingArray = existing as Array;
+ else
+ {
+ existingArray = [existing];
+ delete metadata[mdName];
+ }
+ existingArray.push(value);
+ existing = existingArray;
+ }
+ else
+ {
+ existing = value;
+ }
+ metadata[mdName] = existing;
+ }
+ }
+ }
+ }
+ catch(e:Error)
+ {
+ }
+
+ return result;
+ }
+
+
+ /**
+ * @private
+ */
+ private static function getCacheKey(o:Object, excludes:Array = null, options:Object = null):String
+ {
+ var key:String = getQualifiedClassName(o);
+
+ if (excludes != null)
+ {
+ var length:int = excludes.length;
+ for (var i:uint = 0; i < length; i++)
+ {
+ var excl:String = excludes[i] as String;
+ if (excl != null)
+ key += excl;
+ }
+ }
+
+ if (options != null)
+ {
+ for (var flag:String in options)
+ {
+ key += flag;
+ var value:String = options[flag];
+ if (value != null)
+ key += value.toString();
+ }
+ }
+ return key;
+ }
+
+ /**
+ * @private
+ */
+ private static function arrayCompare(a:Array, b:Array,
+ currentDepth:int, desiredDepth:int,
+ refs:Dictionary):int
+ {
+ var result:int = 0;
+
+ if (a.length != b.length)
+ {
+ if (a.length < b.length)
+ result = -1;
+ else
+ result = 1;
+ }
+ else
+ {
+ var key:Object;
+ for (key in a)
+ {
+ if (b.hasOwnProperty(key))
+ {
+ result = internalCompare(a[key], b[key], currentDepth,
+ desiredDepth, refs);
+
+ if (result != 0)
+ return result;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ for (key in b)
+ {
+ if (!a.hasOwnProperty(key))
+ {
+ return 1;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @private
+ */
+ private static function byteArrayCompare(a:ByteArray, b:ByteArray):int
+ {
+ var result:int = 0;
+
+ if (a == b)
+ return result;
+
+ if (a.length != b.length)
+ {
+ if (a.length < b.length)
+ result = -1;
+ else
+ result = 1;
+ }
+ else
+ {
+ for (var i:int = 0; i < a.length; i++)
+ {
+ result = numericCompare(a[i], b[i]);
+ if (result != 0)
+ {
+ i = a.length;
+ }
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * @private
+ * This is the "find" for our union-find algorithm when doing object searches.
+ * The dictionary keeps track of sets of equal objects
+ */
+ private static function getRef(o:Object, refs:Dictionary):Object
+ {
+ var oRef:Object = refs[o];
+ while (oRef && oRef != refs[oRef])
+ {
+ oRef = refs[oRef];
+ }
+ if (!oRef)
+ oRef = o;
+ if (oRef != refs[o])
+ refs[o] = oRef;
+
+ return oRef
+ }
+
+ /**
+ * @private
+ */
+ private static var refCount:int = 0;
+
+ /**
+ * @private
+ */
+ private static var CLASS_INFO_CACHE:Object = {};
+}
+
+}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/dec3558f/frameworks/as/projects/MXMLCClasses/src/mx/utils/StringUtil.as
----------------------------------------------------------------------
diff --git a/frameworks/as/projects/MXMLCClasses/src/mx/utils/StringUtil.as b/frameworks/as/projects/MXMLCClasses/src/mx/utils/StringUtil.as
new file mode 100644
index 0000000..ee6a6d0
--- /dev/null
+++ b/frameworks/as/projects/MXMLCClasses/src/mx/utils/StringUtil.as
@@ -0,0 +1,364 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+/**
+ * The StringUtil utility class is an all-static class with methods for
+ * working with String objects within Flex.
+ * You do not create instances of StringUtil;
+ * instead you call methods such as
+ * the <code>StringUtil.substitute()</code> method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class StringUtil
+{
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Removes all whitespace characters from the beginning and end
+ * of the specified string.
+ *
+ * @param str The String whose whitespace should be trimmed.
+ *
+ * @return Updated String where whitespace was removed from the
+ * beginning and end.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function trim(str:String):String
+ {
+ if (str == null) return '';
+
+ var startIndex:int = 0;
+ while (isWhitespace(str.charAt(startIndex)))
+ ++startIndex;
+
+ var endIndex:int = str.length - 1;
+ while (isWhitespace(str.charAt(endIndex)))
+ --endIndex;
+
+ if (endIndex >= startIndex)
+ return str.slice(startIndex, endIndex + 1);
+ else
+ return "";
+ }
+
+ /**
+ * Removes all whitespace characters from the beginning and end
+ * of each element in an Array, where the Array is stored as a String.
+ *
+ * @param value The String whose whitespace should be trimmed.
+ *
+ * @param separator The String that delimits each Array element in the string.
+ *
+ * @return Updated String where whitespace was removed from the
+ * beginning and end of each element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function trimArrayElements(value:String, delimiter:String):String
+ {
+ if (value != "" && value != null)
+ {
+ var items:Array = value.split(delimiter);
+
+ var len:int = items.length;
+ for (var i:int = 0; i < len; i++)
+ {
+ items[i] = StringUtil.trim(items[i]);
+ }
+
+ if (len > 0)
+ {
+ value = items.join(delimiter);
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Returns <code>true</code> if the specified string is
+ * a single space, tab, carriage return, newline, or formfeed character.
+ *
+ * @param str The String that is is being queried.
+ *
+ * @return <code>true</code> if the specified string is
+ * a single space, tab, carriage return, newline, or formfeed character.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isWhitespace(character:String):Boolean
+ {
+ switch (character)
+ {
+ case " ":
+ case "\t":
+ case "\r":
+ case "\n":
+ case "\f":
+ // non breaking space
+ case "\u00A0":
+ // line seperator
+ case "\u2028":
+ // paragraph seperator
+ case "\u2029":
+ // ideographic space
+ case "\u3000":
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Substitutes "{n}" tokens within the specified string
+ * with the respective arguments passed in.
+ *
+ * Note that this uses String.replace and "$" can have special
+ * meaning in the argument strings escape by using "$$".
+ *
+ * @param str The string to make substitutions in.
+ * This string can contain special tokens of the form
+ * <code>{n}</code>, where <code>n</code> is a zero based index,
+ * that will be replaced with the additional parameters
+ * found at that index if specified.
+ *
+ * @param rest Additional parameters that can be substituted
+ * in the <code>str</code> parameter at each <code>{n}</code>
+ * location, where <code>n</code> is an integer (zero based)
+ * index value into the array of values specified.
+ * If the first parameter is an array this array will be used as
+ * a parameter list.
+ * This allows reuse of this routine in other methods that want to
+ * use the ... rest signature.
+ * For example <pre>
+ * public function myTracer(str:String, ... rest):void
+ * {
+ * label.text += StringUtil.substitute(str, rest) + "\n";
+ * } </pre>
+ *
+ * @return New string with all of the <code>{n}</code> tokens
+ * replaced with the respective arguments specified.
+ *
+ * @example
+ *
+ * var str:String = "here is some info '{0}' and {1}";
+ * trace(StringUtil.substitute(str, 15.4, true));
+ *
+ * // this will output the following string:
+ * // "here is some info '15.4' and true"
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function substitute(str:String, ... rest):String
+ {
+ if (str == null) return '';
+
+ // Replace all of the parameters in the msg string.
+ var len:uint = rest.length;
+ var args:Array;
+ if (len == 1 && rest[0] is Array)
+ {
+ args = rest[0] as Array;
+ len = args.length;
+ }
+ else
+ {
+ args = rest;
+ }
+
+ for (var i:int = 0; i < len; i++)
+ {
+ str = str.replace(new RegExp("\\{"+i+"\\}", "g"), args[i]);
+ }
+
+ return str;
+ }
+
+ /**
+ * Returns a string consisting of a specified string
+ * concatenated with itself a specified number of times.
+ *
+ * @param str The string to be repeated.
+ *
+ * @param n The repeat count.
+ *
+ * @return The repeated string.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public static function repeat(str:String, n:int):String
+ {
+ if (n == 0)
+ return "";
+
+ var s:String = str;
+ for (var i:int = 1; i < n; i++)
+ {
+ s += str;
+ }
+ return s;
+ }
+
+ /**
+ * Removes "unallowed" characters from a string.
+ * A "restriction string" such as <code>"A-Z0-9"</code>
+ * is used to specify which characters are allowed.
+ * This method uses the same logic as the <code>restrict</code>
+ * property of TextField.
+ *
+ * @param str The input string.
+ *
+ * @param restrict The restriction string.
+ *
+ * @return The input string, minus any characters
+ * that are not allowed by the restriction string.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public static function restrict(str:String, restrict:String):String
+ {
+ // A null 'restrict' string means all characters are allowed.
+ if (restrict == null)
+ return str;
+
+ // An empty 'restrict' string means no characters are allowed.
+ if (restrict == "")
+ return "";
+
+ // Otherwise, we need to test each character in 'str'
+ // to determine whether the 'restrict' string allows it.
+ var charCodes:Array = [];
+
+ var n:int = str.length;
+ for (var i:int = 0; i < n; i++)
+ {
+ var charCode:uint = str.charCodeAt(i);
+ if (testCharacter(charCode, restrict))
+ charCodes.push(charCode);
+ }
+
+ return String.fromCharCode.apply(null, charCodes);
+ }
+
+ /**
+ * @private
+ * Helper method used by restrict() to test each character
+ * in the input string against the restriction string.
+ * The logic in this method implements the same algorithm
+ * as in TextField's 'restrict' property (which is quirky,
+ * such as how it handles a '-' at the beginning of the
+ * restriction string).
+ */
+ private static function testCharacter(charCode:uint,
+ restrict:String):Boolean
+ {
+ var allowIt:Boolean = false;
+
+ var inBackSlash:Boolean = false;
+ var inRange:Boolean = false;
+ var setFlag:Boolean = true;
+ var lastCode:uint = 0;
+
+ var n:int = restrict.length;
+ var code:uint;
+
+ if (n > 0)
+ {
+ code = restrict.charCodeAt(0);
+ if (code == 94) // caret
+ allowIt = true;
+ }
+
+ for (var i:int = 0; i < n; i++)
+ {
+ code = restrict.charCodeAt(i)
+
+ var acceptCode:Boolean = false;
+ if (!inBackSlash)
+ {
+ if (code == 45) // hyphen
+ inRange = true;
+ else if (code == 94) // caret
+ setFlag = !setFlag;
+ else if (code == 92) // backslash
+ inBackSlash = true;
+ else
+ acceptCode = true;
+ }
+ else
+ {
+ acceptCode = true;
+ inBackSlash = false;
+ }
+
+ if (acceptCode)
+ {
+ if (inRange)
+ {
+ if (lastCode <= charCode && charCode <= code)
+ allowIt = setFlag;
+ inRange = false;
+ lastCode = 0;
+ }
+ else
+ {
+ if (charCode == code)
+ allowIt = setFlag;
+ lastCode = code;
+ }
+ }
+ }
+
+ return allowIt;
+ }
+}
+
+}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/dec3558f/frameworks/as/projects/MXMLCClasses/src/mx/utils/UIDUtil.as
----------------------------------------------------------------------
diff --git a/frameworks/as/projects/MXMLCClasses/src/mx/utils/UIDUtil.as b/frameworks/as/projects/MXMLCClasses/src/mx/utils/UIDUtil.as
new file mode 100644
index 0000000..f6cf737
--- /dev/null
+++ b/frameworks/as/projects/MXMLCClasses/src/mx/utils/UIDUtil.as
@@ -0,0 +1,296 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+import flash.utils.ByteArray;
+import flash.utils.Dictionary;
+
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+/**
+ * The UIDUtil class is an all-static class
+ * with methods for working with UIDs (unique identifiers) within Flex.
+ * You do not create instances of UIDUtil;
+ * instead you simply call static methods such as the
+ * <code>UIDUtil.createUID()</code> method.
+ *
+ * <p><b>Note</b>: If you have a dynamic object that has no [Bindable] properties
+ * (which force the object to implement the IUID interface), Flex adds an
+ * <code>mx_internal_uid</code> property that contains a UID to the object.
+ * To avoid having this field
+ * in your dynamic object, make it [Bindable], implement the IUID interface
+ * in the object class, or set a <coded>uid</coded> property with a value.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class UIDUtil
+{
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Char codes for 0123456789ABCDEF
+ */
+ private static const ALPHA_CHAR_CODES:Array = [48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 65, 66, 67, 68, 69, 70];
+
+ private static const DASH:int = 45; // dash ascii
+ private static const UIDBuffer:ByteArray = new ByteArray(); // static ByteArray used for UID generation to save memory allocation cost
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * This Dictionary records all generated uids for all existing items.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private static var uidDictionary:Dictionary = new Dictionary(true);
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Generates a UID (unique identifier) based on ActionScript's
+ * pseudo-random number generator and the current time.
+ *
+ * <p>The UID has the form
+ * <code>"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"</code>
+ * where X is a hexadecimal digit (0-9, A-F).</p>
+ *
+ * <p>This UID will not be truly globally unique; but it is the best
+ * we can do without player support for UID generation.</p>
+ *
+ * @return The newly-generated UID.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function createUID():String
+ {
+ UIDBuffer.position = 0;
+
+ var i:int;
+ var j:int;
+
+ for (i = 0; i < 8; i++)
+ {
+ UIDBuffer.writeByte(ALPHA_CHAR_CODES[int(Math.random() * 16)]);
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ UIDBuffer.writeByte(DASH);
+ for (j = 0; j < 4; j++)
+ {
+ UIDBuffer.writeByte(ALPHA_CHAR_CODES[int(Math.random() * 16)]);
+ }
+ }
+
+ UIDBuffer.writeByte(DASH);
+
+ var time:uint = new Date().getTime(); // extract last 8 digits
+ var timeString:String = time.toString(16).toUpperCase();
+ // 0xFFFFFFFF milliseconds ~= 3 days, so timeString may have between 1 and 8 digits, hence we need to pad with 0s to 8 digits
+ for (i = 8; i > timeString.length; i--)
+ UIDBuffer.writeByte(48);
+ UIDBuffer.writeUTFBytes(timeString);
+
+ for (i = 0; i < 4; i++)
+ {
+ UIDBuffer.writeByte(ALPHA_CHAR_CODES[int(Math.random() * 16)]);
+ }
+
+ return UIDBuffer.toString();
+ }
+
+ /**
+ * Converts a 128-bit UID encoded as a ByteArray to a String representation.
+ * The format matches that generated by createUID. If a suitable ByteArray
+ * is not provided, null is returned.
+ *
+ * @param ba ByteArray 16 bytes in length representing a 128-bit UID.
+ *
+ * @return String representation of the UID, or null if an invalid
+ * ByteArray is provided.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function fromByteArray(ba:ByteArray):String
+ {
+ if (ba != null && ba.length >= 16 && ba.bytesAvailable >= 16)
+ {
+ UIDBuffer.position = 0;
+ var index:uint = 0;
+ for (var i:uint = 0; i < 16; i++)
+ {
+ if (i == 4 || i == 6 || i == 8 || i == 10)
+ UIDBuffer.writeByte(DASH); // Hyphen char code
+
+ var b:int = ba.readByte();
+ UIDBuffer.writeByte(ALPHA_CHAR_CODES[(b & 0xF0) >>> 4]);
+ UIDBuffer.writeByte(ALPHA_CHAR_CODES[(b & 0x0F)]);
+ }
+ return UIDBuffer.toString();
+ }
+
+ return null;
+ }
+
+ /**
+ * A utility method to check whether a String value represents a
+ * correctly formatted UID value. UID values are expected to be
+ * in the format generated by createUID(), implying that only
+ * capitalized A-F characters in addition to 0-9 digits are
+ * supported.
+ *
+ * @param uid The value to test whether it is formatted as a UID.
+ *
+ * @return Returns true if the value is formatted as a UID.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isUID(uid:String):Boolean
+ {
+ if (uid != null && uid.length == 36)
+ {
+ for (var i:uint = 0; i < 36; i++)
+ {
+ var c:Number = uid.charCodeAt(i);
+
+ // Check for correctly placed hyphens
+ if (i == 8 || i == 13 || i == 18 || i == 23)
+ {
+ if (c != DASH)
+ {
+ return false;
+ }
+ }
+ // We allow capital alpha-numeric hex digits only
+ else if (c < 48 || c > 70 || (c > 57 && c < 65))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Converts a UID formatted String to a ByteArray. The UID must be in the
+ * format generated by createUID, otherwise null is returned.
+ *
+ * @param String representing a 128-bit UID
+ *
+ * @return ByteArray 16 bytes in length representing the 128-bits of the
+ * UID or null if the uid could not be converted.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function toByteArray(uid:String):ByteArray
+ {
+ if (isUID(uid))
+ {
+ var result:ByteArray = new ByteArray();
+
+ for (var i:uint = 0; i < uid.length; i++)
+ {
+ var c:String = uid.charAt(i);
+ if (c == "-")
+ continue;
+ var h1:uint = getDigit(c);
+ i++;
+ var h2:uint = getDigit(uid.charAt(i));
+ result.writeByte(((h1 << 4) | h2) & 0xFF);
+ }
+ result.position = 0;
+ return result;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the decimal representation of a hex digit.
+ * @private
+ */
+ private static function getDigit(hex:String):uint
+ {
+ switch (hex)
+ {
+ case "A":
+ case "a":
+ return 10;
+ case "B":
+ case "b":
+ return 11;
+ case "C":
+ case "c":
+ return 12;
+ case "D":
+ case "d":
+ return 13;
+ case "E":
+ case "e":
+ return 14;
+ case "F":
+ case "f":
+ return 15;
+ default:
+ return new uint(hex);
+ }
+ }
+}
+
+}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/dec3558f/frameworks/as/projects/MXMLCClasses/src/mx/utils/object_proxy.as
----------------------------------------------------------------------
diff --git a/frameworks/as/projects/MXMLCClasses/src/mx/utils/object_proxy.as b/frameworks/as/projects/MXMLCClasses/src/mx/utils/object_proxy.as
new file mode 100644
index 0000000..5aea911
--- /dev/null
+++ b/frameworks/as/projects/MXMLCClasses/src/mx/utils/object_proxy.as
@@ -0,0 +1,34 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+/**
+ * Documentation is not currently available.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public namespace object_proxy =
+ "http://www.adobe.com/2006/actionscript/flash/objectproxy";
+
+}