You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by gr...@apache.org on 2020/10/07 08:25:55 UTC

[royale-asjs] branch develop updated (73dd273 -> 151952c)

This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git.


    from 73dd273  Add some methods so override doesn't result in compiler error.
     new d610a9b  Added missing checks for ExtraData in reflection 'aliasing' support
     new 9ac12c6  Refactored AMFBinaryData use 'internal' namespace for Serialization context. -Added support for Vector in AMF3, (may need more work/testing for nested Vectors). -fixed undefined vs. null not correct in some cases in AMF3. Added Enhanced Serialization Context that supports AMF0 (legacy format) optional support Added a new bead which allows support for AMF0 to be opt-in at application level. Added new unit tests for amf3 cases described above, and a new suite of unit tests [...]
     new 151952c  Merge branch 'develop' of https://github.com/apache/royale-asjs into develop

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../Network/src/main/resources/basic-manifest.xml  |    1 +
 .../royale/net/remoting/amf/AMF0AMF3Context.as     |  508 ++++++++
 .../royale/net/remoting/amf/AMF0SupportBead.as}    |   52 +-
 .../royale/net/remoting/amf/AMFBinaryData.as       | 1320 +-------------------
 .../amf/{AMFBinaryData.as => AMFContext.as}        |  713 +++++------
 .../org/apache/royale/net/remoting/amf/Traits.as   |  136 ++
 .../src/test/royale/flexUnitTests/NetworkTester.as |    2 +-
 ...taTesterTest.as => AMF0BinaryDataTesterTest.as} |  338 +++--
 .../network/AMFBinaryDataTesterTest.as             |   82 +-
 .../org/apache/royale/reflection/TypeDefinition.as |    8 +-
 .../apache/royale/reflection/getAliasByClass.as    |    3 +
 .../apache/royale/reflection/getClassByAlias.as    |    2 +-
 .../apache/royale/reflection/registerClassAlias.as |    2 +-
 13 files changed, 1385 insertions(+), 1782 deletions(-)
 create mode 100644 frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMF0AMF3Context.as
 copy frameworks/projects/{Reflection/src/main/royale/org/apache/royale/reflection/beads/ExtraReflectionDataBead.as => Network/src/main/royale/org/apache/royale/net/remoting/amf/AMF0SupportBead.as} (61%)
 copy frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/{AMFBinaryData.as => AMFContext.as} (75%)
 create mode 100644 frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/Traits.as
 copy frameworks/projects/Network/src/test/royale/flexUnitTests/network/{AMFBinaryDataTesterTest.as => AMF0BinaryDataTesterTest.as} (64%)


[royale-asjs] 03/03: Merge branch 'develop' of https://github.com/apache/royale-asjs into develop

Posted by gr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit 151952c4f284a8bc70e3f329812c902461a32971
Merge: 9ac12c6 73dd273
Author: greg-dove <gr...@gmail.com>
AuthorDate: Wed Oct 7 21:25:35 2020 +1300

    Merge branch 'develop' of https://github.com/apache/royale-asjs into develop

 .../src/main/royale/mx/states/Transition.as        | 16 ++++++++--
 .../src/main/resources/spark-royale-manifest.xml   |  1 +
 .../royale/spark/components/SkinnableContainer.as  |  8 ++---
 .../components/supportClasses/DropDownListBase.as  | 36 +++++++++++-----------
 .../supportClasses/SkinnableComponent.as           |  2 ++
 .../src/main/royale/spark/skins/SparkSkin.as       |  4 +++
 6 files changed, 43 insertions(+), 24 deletions(-)


[royale-asjs] 02/03: Refactored AMFBinaryData use 'internal' namespace for Serialization context. -Added support for Vector in AMF3, (may need more work/testing for nested Vectors). -fixed undefined vs. null not correct in some cases in AMF3. Added Enhanced Serialization Context that supports AMF0 (legacy format) optional support Added a new bead which allows support for AMF0 to be opt-in at application level. Added new unit tests for amf3 cases described above, and a new suite of unit tests for AMF0

Posted by gr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit 9ac12c6872ce5c2bd7423f3916b01bcc4a0238ee
Author: greg-dove <gr...@gmail.com>
AuthorDate: Wed Oct 7 21:23:44 2020 +1300

    Refactored AMFBinaryData use 'internal' namespace for Serialization context.
    -Added support for Vector in AMF3, (may need more work/testing for nested Vectors).
    -fixed undefined vs. null not correct in some cases in AMF3.
    Added Enhanced Serialization Context that supports AMF0 (legacy format) optional support
    Added a new bead which allows support for AMF0 to be opt-in at application level.
    Added new unit tests for amf3 cases described above, and a new suite of unit tests for AMF0
---
 .../Network/src/main/resources/basic-manifest.xml  |    1 +
 .../royale/net/remoting/amf/AMF0AMF3Context.as     |  508 ++++++++
 .../royale/net/remoting/amf/AMF0SupportBead.as     |   88 ++
 .../royale/net/remoting/amf/AMFBinaryData.as       | 1320 +-------------------
 .../amf/{AMFBinaryData.as => AMFContext.as}        |  713 +++++------
 .../org/apache/royale/net/remoting/amf/Traits.as   |  136 ++
 .../src/test/royale/flexUnitTests/NetworkTester.as |    2 +-
 ...taTesterTest.as => AMF0BinaryDataTesterTest.as} |  338 +++--
 .../network/AMFBinaryDataTesterTest.as             |   82 +-
 9 files changed, 1428 insertions(+), 1760 deletions(-)

diff --git a/frameworks/projects/Network/src/main/resources/basic-manifest.xml b/frameworks/projects/Network/src/main/resources/basic-manifest.xml
index 3fb6d18..74197fd 100644
--- a/frameworks/projects/Network/src/main/resources/basic-manifest.xml
+++ b/frameworks/projects/Network/src/main/resources/basic-manifest.xml
@@ -19,6 +19,7 @@
 -->
 
 <componentPackage>
+    <component id="AMF0SupportBead" class="org.apache.royale.net.remoting.amf.AMF0SupportBead"/>
     <component id="SimpleRemoteObject" class="org.apache.royale.net.SimpleRemoteObject"/>
     <component id="RemoteObject" class="org.apache.royale.net.RemoteObject"/>
     <component id="CompressedRemoteObject" class="org.apache.royale.net.CompressedRemoteObject"/>
diff --git a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMF0AMF3Context.as b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMF0AMF3Context.as
new file mode 100644
index 0000000..c670fd5
--- /dev/null
+++ b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMF0AMF3Context.as
@@ -0,0 +1,508 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed 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.
+//
+////////////////////////////////////////////////////////////////////////////////
+/***
+ * Based on the
+ * AMF JavaScript library by Emil Malinov https://github.com/emilkm/amfjs
+ */
+package org.apache.royale.net.remoting.amf {
+
+
+import org.apache.royale.net.remoting.amf.AMFBinaryData;
+import org.apache.royale.net.remoting.amf.AMFContext;
+import org.apache.royale.utils.net.IDynamicPropertyOutput;
+import org.apache.royale.utils.net.IDynamicPropertyWriter;
+import org.apache.royale.reflection.getAliasByClass;
+import org.apache.royale.reflection.getClassByAlias;
+import org.apache.royale.reflection.getDynamicFields;
+import org.apache.royale.reflection.getDefinitionByName;
+import org.apache.royale.reflection.getQualifiedClassName;
+import org.apache.royale.reflection.isDynamicObject;
+import org.apache.royale.utils.net.IDataInput;
+import org.apache.royale.utils.net.IDataOutput;
+import org.apache.royale.utils.BinaryData;
+import org.apache.royale.utils.net.IExternalizable;
+import org.apache.royale.utils.net.IDataInput;
+import org.apache.royale.utils.net.IDataOutput;
+
+
+	COMPILE::JS
+	/**
+	 * @royalesuppressexport
+	 */
+	internal class AMF0AMF3Context extends AMFContext {
+		import goog.DEBUG;
+
+		import org.apache.royale.utils.Language;
+
+
+		internal static function install():void{
+			AMFBinaryData.installAlternateContext(AMF0AMF3Context);
+		}
+
+		//@todo :
+		private static const AMF0_AMF3:int = 0x11;
+
+		private static const AMF0_NUMBER:uint = 0x0;
+		private static const AMF0_BOOLEAN:uint =0x1;
+		private static const AMF0_STRING:uint = 0x2;
+		private static const AMF0_OBJECT:uint = 0x3;
+		/*private static const AMF0_MOVIECLIP:uint =  0x4; NOT USED */
+		private static const AMF0_NULL:uint = 0x05;
+		private static const AMF0_UNDEFINED:uint = 0x06;
+		private static const AMF0_REFERENCE:uint = 0x07;
+		private static const AMF0_ECMA_ARRAY:uint = 0x08; //includes non-numeric keys
+		private static const AMF0_OBJECT_END:uint = 0x09;
+		private static const AMF0_STRICT_ARRAY:uint = 0x0A; //only numeric keys (this does not seem to be used for client-side serialization)
+		private static const AMF0_DATE:uint = 0x0B;
+		private static const AMF0_LONG_STRING:uint = 0x0C;
+		private static const AMF0_UNSUPPORTED:uint = 0x0D;
+		/*private static const AMF0_RECORDSET:uint = 0x0E; NOT USED */
+		private static const AMF0_XMLDOCUMENT:int = 0x0F; //
+		private static const AMF0_TYPED_OBJECT:int = 0x10;
+
+
+
+		public function AMF0AMF3Context(ownerReference:AMFBinaryData) {
+			super(ownerReference);
+		}
+
+		override public function supportsAMFEncoding(type:uint):Boolean{
+			return type == 3 || type == 0;
+		}
+
+		override public function writeObject(v:*):void {
+			trace('to check here')
+			super.writeObject(v)
+		}
+
+		/**
+		 * @royaleignorecoercion Class
+		 * @royaleignorecoercion String
+		 * @royaleignorecoercion Number
+		 * @royaleignorecoercion Array
+		 */
+		override public function writeAmf0Object(v:*):void{
+			if (v == null) {
+				if (v === undefined) {
+					writeByte(AMF0_UNDEFINED);
+				} else {
+					writeByte(AMF0_NULL);
+				}
+				return;
+			}
+			if (isFunctionValue(v)) {
+				//output function value as undefined
+				writeByte(AMF0_UNDEFINED);
+				return;
+			}
+			if (v is String) {
+				var str:String = v as String;
+				if (str == '') {
+					writeByte(AMF0_STRING);
+					writeByte(0);
+					writeByte(0);
+				} else {
+					var bytes:Uint8Array = getUTFBytes(str, false);
+					if (bytes.length < 65536) {
+						writeByte(AMF0_STRING);
+						writeShort(bytes.length );
+					} else {
+						writeByte(AMF0_LONG_STRING);
+						writeUnsignedInt(bytes.length);
+					}
+					var srcArray:Array = [].slice.call(bytes);
+					addByteSequence(srcArray);
+				}
+			} else if (v is Number) {
+				var n:Number = v as Number;
+				writeByte(AMF0_NUMBER);
+				writeDouble(n);
+			} else if (v is Boolean) {
+				writeByte(AMF0_BOOLEAN);
+				writeByte( v ? 1 : 0);
+			}
+			else if (v is Date) {
+				writeAMF0Date(v as Date);
+			}
+			else if (AMFContext._xmlClass && v is AMFContext._xmlClass) {
+				writeAMF0XML(v);
+			}
+			else {
+				if (v is Array) {
+					if (v[Language.SYNTH_TAG_FIELD] != undefined) {
+						writeAMF0Vector(v); //writes as Object with fields 'fixed' and 'length', similar to ecma array
+					} else {
+						writeAMF0Array(v as Array);
+					}
+				} else writeAMF0ObjectVariant(v);
+			}
+		}
+
+		private function writeAMF0Date(v:Date):void {
+			//writeByte(AMF3_DATE);
+			if (!amf0ObjectByReference(v)) {
+				writeByte(AMF0_DATE);
+				writeDouble(v.getTime());
+				//timezone offset is mandatory but never used
+				//it is a S16 in spec, but because it is always zero, cheat:
+				writeByte(0);
+				writeByte(0);
+			}
+		}
+
+		private function writeAMF0Vector(v:Object):void {
+			throw new Error('@todo');
+		}
+
+		private function writeAMF0Array(v:Array):void {
+			//is it strict or associative
+			var key:String;
+			var val:*;
+			if (!this.amf0ObjectByReference(v)) {
+				var len:uint = v.length;
+				var i:uint = 0;
+				var akl:uint = 0; //associative keys length
+				var denseLength:uint = len;
+				var keys:Array = Object.keys(v);
+				//profile the array
+				//es6 specifies a generalized traversal order we can rely upon going forward
+				//testing in IE11 shows the same order applies in that es5 Array implementation, so we assume it here:
+				/*
+				Property keys are traversed in the following order:
+
+				First, the keys that are integer indices, in ascending numeric order.
+				note non-integers: '02' round-tripping results in the different string '2'.
+					'3.141' is not an integer index, because 3.141 is not an integer.
+				Then, all other string keys, in the order in which they were added to the object.
+				Lastly, all symbol keys, in the order in which they were added to the object.
+				We don't need to worry about Symbols here
+				 */
+				var kl:uint = keys.length;
+				//Assumption - based on the above,
+				//if the last key in the keys is an integer index, and length matches the array.length then it is a pure strict array
+				//if not, it is non-strict
+				//	var isFunctionValue:Function = this.isFunctionValue;
+				//discriminate between strict and ecma by any inclusion or not of non-ordinal keys only. dense vs. non-dense is not a factor
+				if ((((keys[kl-1])>>0).toString() !== keys[kl-1])) {
+					//ecma
+					//var firstAssociative:int = keys.length ? keys.lastIndexOf(''+ (keys.length)): 0;
+					//var count:uint = len + keys.length - firstAssociative;
+					writeByte(AMF0_ECMA_ARRAY);
+					writeUnsignedInt(len);
+					len = keys.length;
+					if (len) {
+						for (i = 0;i<len; i++) {
+							key = keys[i]
+							val = v[key];
+							if (!isFunctionValue(val)) {
+								writeUTF(key)
+								writeAmf0Object(val);
+							}
+						}
+					}
+					//end of object
+					writeByte(0);
+					writeByte(0);
+					writeByte(AMF0_OBJECT_END);
+
+				} else {
+					//strict
+					//encode as ecma anyway... because player seems to do that
+					writeByte(AMF0_ECMA_ARRAY);
+					writeUnsignedInt(len); //array length
+					len = keys.length; //now keys length
+					for (i = 0; i < len; i++) {
+						key = keys[i]
+						val = v[key];
+						if (!isFunctionValue(val)) {
+							writeUTF(key)
+							writeAmf0Object(val);
+						}
+					}
+					writeByte(0);
+					writeByte(0);
+					writeByte(AMF0_OBJECT_END);
+
+					//in theory this should be it, but it looks like player always encodes as ecma (above)
+					/*writeByte(AMF0_STRICT_ARRAY);
+					writeUnsignedInt(len);
+					if (len) {
+						for (i = 0; i < len; i++) {
+							writeObject(v[i]);
+						}
+					}*/
+				}
+			}
+		}
+
+		public function amf0ObjectByReference(v:Object):Boolean {
+			const ref:int = objects.indexOf(v);
+			const found:Boolean = ref !== -1;
+			if (found) {
+				writeByte(AMF0_REFERENCE);
+				writeShort(ref);
+			} else {
+				objects.push(v);
+				objectCount++;
+			}
+			return found;
+		}
+
+		private function writeAMF0ObjectVariant(v:Object):void {
+			if (!this.amf0ObjectByReference(v)) {
+				const localTraits:Traits = getLocalTraitsInfo(v);
+				/*if (localTraits.externalizable && !localTraits.alias) {
+					//in flash player if you try to write an object with no alias that is externalizable it does this:
+					throw new Error("ArgumentError: Error #2004: One of the parameters is invalid.");
+				}*/
+				writeAMF0TypedObject(v, localTraits);
+			}
+		}
+
+		private function writeAMF0TypedObject(v:Object, localTraits:Traits):void {
+
+			if (!localTraits.alias) {
+				writeByte(AMF0_OBJECT);
+			} else {
+				writeByte(AMF0_TYPED_OBJECT);
+				writeUTF(localTraits.alias);
+			}
+			var l:uint;
+			var i:uint;
+			l = localTraits.count;
+			for (i = 0; i < l; i++) {
+				//sealed props
+				var val:* = localTraits.getterSetters[localTraits.props[i]].getValue(v);
+				if (val === null || val === undefined) {
+					//coerce null values to the 'correct' types
+					val = localTraits.nullValues[localTraits.props[i]];
+
+					//handle '*' type which can be undefined or explicitly null
+					if (val === undefined && localTraits.getterSetters[localTraits.props[i]].getValue(v) === null) {
+						val = null;
+					}
+				}
+				this.writeUTF(localTraits.props[i]);
+				this.writeAmf0Object(val);
+			}
+
+			if (localTraits.isDynamic) {
+				/*if (dynamicPropertyWriter != null) {
+					dynamicPropertyWriter.writeDynamicProperties(v, this);
+				} else {*/
+				//default implementation
+				var dynFields:Array = getDynamicFields(v);
+				i = 0;
+				l = dynFields.length;
+				for (; i < l; i++) {
+					val = v[dynFields[i]];
+					if (isFunctionValue(val)) {
+						//skip this name-value pair, don't even write it out as undefined (match flash)
+						continue;
+					}
+					this.writeUTF(dynFields[i]);
+					this.writeAmf0Object(val);
+				}
+			}
+
+			writeByte(0);
+			writeByte(0);
+			writeByte(AMF0_OBJECT_END);
+
+		}
+
+
+		private function writeAMF0XML(v:Object):void{
+			//e4x XML does not exist in AMF0.
+			//so send to 'Object'
+			writeAMF0ObjectVariant(v)
+		}
+
+
+
+		/**
+		 * This serialization context is passed as the 2nd parameter to an IDynamicPropertyWriter
+		 * implementation's writeDynamicProperties method call. The resolved properties are written here
+		 * @param name property name
+		 * @param value property value
+		 */
+		override public function writeDynamicProperty(name:String, value:*):void {
+			trace('to check writeDynamicProperty');
+			super.writeDynamicProperty(name, value);
+		}
+
+
+
+		override public function readObject():* {
+			trace('@todo')
+			return super.readObject();
+		}
+
+		override public function readAmf0Object():* {
+			var amfType:uint = readUnsignedByte();
+			return readAmf0ObjectValue(amfType);
+		}
+
+		private function readAmf0ObjectValue(amfType:uint):Object {
+			var value:Object = null;
+			var u:uint;
+
+			switch (amfType) {
+				case AMF0_NUMBER:
+					value = readDouble();
+					break;
+				case AMF0_BOOLEAN:
+					value = readUnsignedByte() ? true : false;
+					break;
+				case AMF0_STRING:
+					//readUTF reads the unsigned short (U16) length as well
+					value = readUTF();
+					break;
+				case AMF0_OBJECT:
+					value = readAMF0ScriptObject(null);
+					break;
+				case AMF0_NULL:
+					value = null;
+					break;
+				case AMF0_UNDEFINED:
+					value = undefined;
+					break;
+				case AMF0_REFERENCE:
+					value = getObject(readUnsignedShort());
+
+					break;
+				case AMF0_ECMA_ARRAY:
+					value = readAMF0Array(true);
+					break;
+				case AMF0_OBJECT_END:
+					throw 'unexpected'; //this should already be encountered during Object deserialization
+					break;
+				case AMF0_STRICT_ARRAY:
+					value = readAMF0Array(false);
+					break;
+				case AMF0_DATE:
+					value = readAMF0Date();
+					break;
+				case AMF0_LONG_STRING:
+					var len:uint = readUnsignedInt();
+					value = readUTFBytes(len);
+					break;
+				case AMF0_XMLDOCUMENT:
+					throw 'unimplemented' ; //should we provide an option to deserialize as as3 XML ?
+					break;
+
+
+				case AMF0_TYPED_OBJECT:
+					var className:String = readUTF();
+					value= readAMF0ScriptObject(className);
+					break;
+
+				default:
+					throw new Error("Unsupported AMF type: " + amfType);
+			}
+			return value;
+		}
+
+
+
+		private function readAMF0ScriptObject(alias:String):Object {
+			var obj:Object;
+			var localTraits:Traits;
+			var hasProp:Boolean;
+			if (alias) {
+				var c:Class = getClassByAlias(alias);
+				if (c) {
+					obj = new c();
+					localTraits = getLocalTraitsInfo(obj);
+				}
+			}
+			if (!obj) {
+				obj = {};
+				localTraits = Traits.getBaseObjectTraits();
+			}
+
+			rememberObject(obj);
+			var more:Boolean = true;
+			while(more) {
+				var key:String = readUTF();
+				if (key == '') {
+					more = false;
+
+				} else {
+					var fieldValue:* = readAmf0Object();
+					hasProp = localTraits &&  (localTraits.hasProp(key) || localTraits.isTransient(key)) ;
+					if (hasProp) {
+						localTraits.getterSetters[key].setValue(obj, fieldValue);
+					} else if (localTraits.isDynamic) {
+						obj[key] = fieldValue;
+					} else {
+						//@todo
+						trace('unknown field ', key)
+						if (goog.DEBUG) {
+							trace('ReferenceError: Error #1056: Cannot create property ' + key + ' on ' + localTraits.qName);
+						}
+					}
+				}
+			}
+
+			var check:uint = readUnsignedByte();
+			if (check != AMF0_OBJECT_END) {
+				throw 'unexpected. should be AMF0_OBJECT_END';
+			}
+			return obj;
+		}
+
+		private function readAMF0Array(ecma:Boolean):Array {
+			var array:Array = [];
+			rememberObject(array);
+			var len:uint = readUnsignedInt();
+			var i:uint = 0;
+			if (ecma) {
+				array.length = len;
+				var more:Boolean=true;
+				while(more) {
+					var key:String = readUTF();
+					if (key == '') {
+						more = false;
+					} else {
+						array[key] = readAmf0Object();
+					}
+				}
+				var byte:uint = readUnsignedByte();
+				if (byte != AMF0_OBJECT_END)  throw 'unexpected. should be AMF0_OBJECT_END';
+			} else {
+				while(i < len) {
+					array[i] = readAmf0Object();
+					i++;
+				}
+			}
+			return array;
+		}
+
+		private function readAMF0Date():Date{
+			var time:Number = readDouble();
+			var date:Date = new Date(time);
+			rememberObject(date);
+			//skip the S16 timezone data (not used)
+			_position += 2;
+			return date;
+		}
+
+
+	}
+}
+
+
diff --git a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMF0SupportBead.as b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMF0SupportBead.as
new file mode 100644
index 0000000..edf4a75
--- /dev/null
+++ b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMF0SupportBead.as
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.royale.net.remoting.amf
+{
+    import org.apache.royale.core.IBead;
+    import org.apache.royale.core.IStrand;
+    import org.apache.royale.core.IDocument;
+
+    
+    /**
+     *  The AMF0SupportBead adds support for legacy AMF0
+     *  serialization/deserialization into AMFBinaryData
+     *  It should be used once at the Application level
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Royale 0.0
+     */
+	public class AMF0SupportBead implements IBead, IDocument
+	{
+        /**
+         *  Constructor.
+         *  
+         *  @langversion 3.0
+         *  @playerversion Flash 10.2
+         *  @playerversion AIR 2.6
+         *  @productversion Royale 0.0
+         */
+		public function AMF0SupportBead()
+		{
+		}
+		
+        private static var _strandSet:Boolean;
+
+
+        public static function installAMF0Support():void{
+            COMPILE::JS{
+                AMF0AMF3Context.install();
+            }
+        }
+        
+        /**
+         *  @copy org.apache.royale.core.IBead#strand
+         *
+         *  @langversion 3.0
+         *  @playerversion Flash 10.2
+         *  @playerversion AIR 2.6
+         *  @productversion Royale 0.0
+         */
+        public function set strand(value:IStrand):void
+        {
+            if (!value || _strandSet) return;
+            _strandSet = true;
+            installAMF0Support();
+        }
+
+        /**
+         *  the following ensures that this bead will be processed in mxml bead declaration order
+         *  @private
+         *  @royaleignorecoercion org.apache.royale.core.IStrand
+         */
+        public function setDocument(document:Object, id:String = null):void
+        {
+            if (document is IStrand) {
+                strand = IStrand(document);
+            }
+        }
+            
+
+    }
+}
diff --git a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as
index 89350f4..0d86cbb 100644
--- a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as
+++ b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as
@@ -30,6 +30,7 @@ package org.apache.royale.net.remoting.amf {
 	
 	COMPILE::SWF{
 		import flash.net.ObjectEncoding;
+		import flash.utils.ByteArray;
 	}
 	
 	/**
@@ -47,6 +48,43 @@ package org.apache.royale.net.remoting.amf {
 
 		COMPILE::JS
 		private static var _propertyWriter:IDynamicPropertyWriter;
+		COMPILE::JS
+		private static var _amfContextClass:Class;
+
+		COMPILE::JS
+		internal static function installAlternateContext(clazz:Class):void{
+			//this should always be a valid subclass of AMFContext (only AMF0 support)
+			_amfContextClass = clazz;
+		}
+		COMPILE::JS
+		private static var _defaultEncoding:uint = 3;
+		public static function get defaultObjectEncoding() : uint{
+			COMPILE::JS{
+				return _defaultEncoding;
+			}
+			COMPILE::SWF{
+				return ByteArray.defaultObjectEncoding;
+			}
+		}
+		public static function set defaultObjectEncoding(value:uint) : void{
+			COMPILE::JS{
+				_defaultEncoding = value;
+			}
+			COMPILE::SWF{
+				ByteArray.defaultObjectEncoding = value;
+			}
+		}
+
+		/**
+		 *
+		 * @royaleignorecoercion org.apache.royale.net.remoting.amf.AMFContext
+		 */
+		COMPILE::JS
+		private static function createSerializationContext(forInstance:AMFBinaryData):AMFContext{
+			var clazz:Class = _amfContextClass;
+			if (!clazz) clazz = _amfContextClass = AMFContext;
+			return new clazz(forInstance) as AMFContext;
+		}
 		
 		/**
 		 * Allows greater control over the serialization of dynamic properties of dynamic objects.
@@ -86,25 +124,45 @@ package org.apache.royale.net.remoting.amf {
 		
 		public function AMFBinaryData(bytes:Object = null) {
 			super(bytes);
+			COMPILE::JS{
+				if (_objectEncoding != _defaultEncoding) _objectEncoding = _defaultEncoding;
+			}
 		}
-		
-		COMPILE::SWF
+
+		COMPILE::JS
+		private var _objectEncoding:int=3;
+
+
 		public function get objectEncoding():uint{
-			return 3;
+			COMPILE::SWF{
+				return ba.objectEncoding;
+			}
+			COMPILE::JS{
+				return _objectEncoding;
+			}
 		}
-		COMPILE::SWF
+
 		public function set objectEncoding(value:uint):void{
-			trace('objectEncoding is always AMF3, setter is ignored');
+			COMPILE::SWF{
+				ba.objectEncoding = value;
+			}
+			COMPILE::JS{
+				if (([0,3]).indexOf(value) == -1) {
+					throw new Error('ArgumentError: Error #2008: Parameter objectEncoding must be one of the accepted values.')
+				} else {
+					_objectEncoding = value;
+				}
+			}
 		}
 		
 		
 		
 		COMPILE::JS
-		private var _serializationContext:SerializationContext;
+		private var _serializationContext:AMFContext;
 		
 		COMPILE::JS
 		public function writeObject(v:*):void {
-			if (!_serializationContext) _serializationContext = new SerializationContext(this);
+			if (!_serializationContext) _serializationContext = createSerializationContext(this);
 			_serializationContext.dynamicPropertyWriter = _propertyWriter;
 			_position = _serializationContext.writeObjectExternal(v, _position, mergeInToArrayBuffer);
 			var err:Error = _serializationContext.getError();
@@ -115,7 +173,7 @@ package org.apache.royale.net.remoting.amf {
 		
 		COMPILE::JS
 		public function readObject():* {
-			if (!_serializationContext) _serializationContext = new SerializationContext(this);
+			if (!_serializationContext) _serializationContext = createSerializationContext(this);
 			var value:* = _serializationContext.readObjectExternal();
 			var err:Error = _serializationContext.getError();
 			if (err) {
@@ -139,7 +197,7 @@ package org.apache.royale.net.remoting.amf {
 	}
 }
 
-
+import org.apache.royale.utils.net.IDynamicPropertyWriter;
 COMPILE::SWF
 class ExternallySetDynamicPropertyWriter implements IDynamicPropertyWriter{
 	
@@ -154,1246 +212,4 @@ class ExternallySetDynamicPropertyWriter implements IDynamicPropertyWriter{
 	public function writeDynamicProperties(obj:Object, output:flash.net.IDynamicPropertyOutput):void {
 		_externalImplementation.writeDynamicProperties(obj, output);
 	}
-	
-}
-
-import org.apache.royale.net.remoting.amf.AMFBinaryData;
-import org.apache.royale.utils.net.IDynamicPropertyOutput;
-import org.apache.royale.utils.net.IDynamicPropertyWriter;
-import org.apache.royale.reflection.getAliasByClass;
-import org.apache.royale.reflection.getClassByAlias;
-import org.apache.royale.reflection.getDynamicFields;
-import org.apache.royale.reflection.getDefinitionByName;
-import org.apache.royale.reflection.isDynamicObject;
-import org.apache.royale.utils.net.IDataInput;
-import org.apache.royale.utils.net.IDataOutput;
-import org.apache.royale.utils.BinaryData;
-import org.apache.royale.utils.net.IExternalizable;
-import org.apache.royale.utils.net.IDataInput;
-import org.apache.royale.utils.net.IDataOutput;
-
-
-COMPILE::JS
-/**
- * @royalesuppressexport
- */
-class SerializationContext extends BinaryData  implements IDataInput, IDataOutput, IDynamicPropertyOutput {
-	import goog.DEBUG;
-	
-	
-	private static const AMF0_AMF3:int = 0x11;
-	private static const AMF3_OBJECT_ENCODING:int = 0x03;
-	
-	private static const AMF3_UNDEFINED:int = 0x00;
-	private static const AMF3_NULL:int = 0x01;
-	private static const AMF3_BOOLEAN_FALSE:int = 0x02;
-	private static const AMF3_BOOLEAN_TRUE:int = 0x03;
-	private static const AMF3_INTEGER:int = 0x04;
-	private static const AMF3_DOUBLE:int = 0x05;
-	private static const AMF3_STRING:int = 0x06;
-	private static const AMF3_XMLDOCUMENT:int = 0x07;
-	private static const AMF3_DATE:int = 0x08;
-	private static const AMF3_ARRAY:int = 0x09;
-	private static const AMF3_OBJECT:int = 0x0A;
-	private static const AMF3_XML:int = 0x0B;
-	private static const AMF3_BYTEARRAY:int = 0x0C;
-	private static const AMF3_VECTOR_INT:int = 0x0D;
-	private static const AMF3_VECTOR_UINT:int = 0x0E;
-	private static const AMF3_VECTOR_DOUBLE:int = 0x0F;
-	private static const AMF3_VECTOR_OBJECT:int = 0x10;
-	private static const AMF3_DICTIONARY:int = 0x11;
-	
-	
-	private static const UINT29_MASK:int = 0x1FFFFFFF;
-	private static const INT28_MAX_VALUE:int = 268435455;
-	private static const INT28_MIN_VALUE:int = -268435456;
-	
-	private static const EMPTY_STRING:String = "";
-	
-	private var owner:AMFBinaryData;
-	public var dynamicPropertyWriter:IDynamicPropertyWriter;
-	private var writeBuffer:Array;
-	
-	private var objects:Array ;
-	
-	private var traits:Object;
-	
-	private var strings:Object;
-	
-	private var stringCount:uint;
-	private var traitCount:uint;
-	private var objectCount:uint;
-	
-	
-	private var writeMode:Boolean = false;
-	
-	
-
-	private var _numbers:ArrayBuffer;
-
-	private var _numberView:DataView;
-
-	private var _numberBytes:Uint8Array;
-	
-	private static var _xmlClass:Class;
-	private static var _xmlChecked:Boolean;
-	
-	private var _error:Error;
-	public function getError():Error{
-		var _err:Error = _error;
-		_error = null;
-		return _err;
-	}
-	
-	/**
-	 * @royaleignorecoercion Class
-	 */
-	public function SerializationContext(ownerReference:AMFBinaryData){
-		owner = ownerReference;
-		reset();
-		if (!_xmlChecked) {
-			_xmlChecked = true;
-			try{
-				_xmlClass = getDefinitionByName('XML') as Class;
-			} catch(e:Error){}
-		}
-		super();
-	}
-	
-	public function reset():void{
-		writeBuffer = [];
-		objects = [];
-		traits = {};
-		strings = {};
-		stringCount = 0;
-		traitCount = 0;
-		objectCount = 0;
-	}
-	
-
-	/**
-	 * used internally as an override to return the writeBuffer Array for use to mimic Uint8Array during writing.
-	 * Array is used because it is not usually known what the byte allocation should be in advance,
-	 * and length is not mutable with javascript typed arrays, so 'growing' the buffer with each write is not
-	 * a good strategy for performance.
-	 * The assumption is that, while write access is slower for individual elements, increasing the length of
-	 * the 'buffer' is not, and that using Array will be more performant.
-	 * @royaleignorecoercion Uint8Array
-	 */
-	override protected function getTypedArray():Uint8Array{
-		return writeMode ? writeBuffer as Uint8Array : super.getTypedArray();
-	}
-	
-
-	override protected function getDataView():DataView
-	{
-		if(!writeMode) return super.getDataView();
-		//in write mode, return a utility version
-		if (!_numberView) {
-			_numbers = new ArrayBuffer(8);
-			_numberView = new DataView(_numbers);
-			_numberBytes = new Uint8Array(_numbers);
-		}
-		return _numberView;
-	}
-	
-	
-
-	override protected function setBufferSize(newSize:uint):void
-	{
-		//writing variation: in this subclass, writing  is always using 'Array' so length is not fixed
-		_len = newSize;
-	}
-	
-
-	override public function writeByte(byte:int):void
-	{
-		writeBuffer[_position++] = byte & 255;
-	}
-	
-	override public function writeByteAt(idx:uint, byte:int):void
-	{
-		while (idx > _len) {
-			writeBuffer[_len++] = 0;
-		}
-		writeBuffer[idx] = byte & 255;
-	}
-	
-	public function writeUInt29(v:uint):void {
-		const write:Function = writeByte;
-		if (v < 128) {
-			write(v);
-		} else if (v < 16384) {
-			write(((v >> 7) & 127) | 128);
-			write(v & 127);
-		} else if (v < 2097152) {
-			write(((v >> 14) & 127) | 128);
-			write(((v >> 7) & 127) | 128);
-			write(v & 127);
-		} else if (v < 0x40000000) {
-			write(((v >> 22) & 127) | 128);
-			write(((v >> 15) & 127) | 128);
-			write(((v >> 8) & 127) | 128);
-			write(v & 255);
-		} else {
-			throw "Integer out of range: " + v;
-		}
-	}
-	
-	protected function addByteSequence(array:Array):void{
-		var length:uint = array.length;
-		if (_position == _len) {
-			writeBuffer = writeBuffer.concat(array);
-			_len = _len + length;
-			/*if (_len != writeBuffer.length) {
-				throw new Error('code review')
-			}*/
-		} else {
-			if (_position + length > _len) {
-				//overwrite beyond
-				//first truncate to _position
-				writeBuffer.length = _position;
-				//then append the new content
-				writeBuffer = writeBuffer.concat(array);
-				_len = _position + length;
-				if (_len != writeBuffer.length) {
-					throw new Error('code review')
-				}
-				
-			} else {
-				//overwrite within - concatenate left and right slices with the new content between
-				writeBuffer = writeBuffer.slice(0, _position).concat(array, writeBuffer.slice(_position + length));
-				
-				if (_len != writeBuffer.length) {
-					throw new Error('code review')
-				}
-			}
-		}
-		_position += length;
-	}
-	
-	
-	override public function writeBytes(bytes:ArrayBuffer, offset:uint = 0, length:uint = 0):void
-	{
-		if (length == 0) length = bytes.byteLength - offset ;
-		if (!length) return;
-		var src:Uint8Array = new Uint8Array(bytes, offset, offset + length);
-		var srcArray:Array = [].slice.call(src);
-		addByteSequence(srcArray);
-	}
-	
-	override public function writeUTF(str:String):void
-	{
-		var utcBytes:Uint8Array = getUTFBytes(str , true);
-		var srcArray:Array = [].slice.call(utcBytes);
-		addByteSequence(srcArray);
-	}
-	
-	override public function writeUTFBytes(str:String):void
-	{
-		var utcBytes:Uint8Array = getUTFBytes(str, false);
-		var srcArray:Array = [].slice.call(utcBytes);
-		addByteSequence(srcArray);
-	}
-	
-	protected function copyNumericBytes(byteCount:uint):void{
-		//arr here is actually an Array, not Uint8Array
-		var arr:Uint8Array = getTypedArray();
-		var numbers:Uint8Array = _numberBytes;
-		var idx:uint = 0;
-		while(byteCount--) {
-			arr[_position++] = numbers[idx++];
-		}
-	}
-	
-	override public function writeFloat(val:Number):void
-	{
-		//always big endian
-		getDataView().setFloat32(0,val,false);
-		copyNumericBytes(4);
-	}
-	
-	override public function writeDouble(val:Number):void
-	{
-		//always big endian
-		getDataView().setFloat64(0,val,false);
-		copyNumericBytes(8);
-	}
-	
-	private function writeAMF_UTF(string:String):void{
-		var utcBytes:Uint8Array = getUTFBytes(string , false);
-		var srcArray:Array = [].slice.call(utcBytes);
-		writeUInt29((srcArray.length << 1) | 1);
-		addByteSequence(srcArray);
-	}
-	
-	private function writeStringWithoutType(v:String):void {
-		if (v.length == 0) {
-			writeUInt29(1);
-		} else {
-			if (!this.stringByReference(v)) {
-				writeAMF_UTF(v);
-			}
-		}
-	}
-	
-	private function stringByReference(v:String):Boolean {
-		const strIndex:* = strings[v];
-		const found:Boolean = strIndex !== undefined;
-		if (found) {
-			const ref:uint = strIndex;
-			writeUInt29(ref << 1);
-		} else {
-			strings[v] = stringCount++;
-		}
-		return found;
-	}
-	
-	public function objectByReference(v:Object):Boolean {
-		const ref:int = objects.indexOf(v);
-		const found:Boolean = ref !== -1;
-		if (found) {
-			writeUInt29(ref << 1);
-		} else {
-			objects.push(v);
-			objectCount++;
-		}
-		return found;
-	}
-	
-	private function traitsByReference(props:Array, alias:String):Boolean {
-		//@todo review this. Don't think it is necessary to do the long joins with the props
-		//maybe alias alone is enough...?
-		const s:String = alias + "|" + props.join("|");
-		const traitsIndex:* = traits[s];
-		const found:Boolean = traitsIndex !== undefined;
-		if (found) {
-			const ref:uint = traitsIndex;
-			writeUInt29((ref << 2) | 1);
-		} else {
-			traits[s] = traitCount++;
-		}
-		return found;
-	}
-	
-	private function writeAmfInt(v:int):void {
-		if (v >= INT28_MIN_VALUE && v <= INT28_MAX_VALUE) {
-			v = v & UINT29_MASK;
-			writeByte(AMF3_INTEGER);
-			writeUInt29(v);
-		} else {
-			writeByte(AMF3_DOUBLE);
-			writeDouble(v);
-		}
-	}
-	
-	private function writeDate(v:Date):void {
-		writeByte(AMF3_DATE);
-		if (!objectByReference(v)) {
-			writeUInt29(1);
-			writeDouble(v.getTime());
-		}
-	}
-	
-	private function filterSerializableMembers(fieldSet:Object, accessChecks:Object, localTraits:Traits, asAccessors:Boolean = false, excludeTransient:Boolean = true):Array {
-		var l:uint;
-		var metas:Array;
-		var exclude:Boolean;
-		var transient:Boolean;
-		var fieldName:String;
-		const into:Array = localTraits.props;
-		
-		for (fieldName in fieldSet) {
-			//exclude all static props
-			if (fieldName.charAt(0) == '|') continue;
-			//exclude all non-public namespaces (identified by '::' between uri and name)
-			if (fieldName.indexOf('::') != -1) continue;
-			var field:Object = fieldSet[fieldName];
-			exclude = false;
-			transient = false;
-			var alreadyPresent:Boolean = into.indexOf(fieldName) != -1 ;
-			if (asAccessors) {
-				exclude = field.access != 'readwrite';
-				if (exclude && !alreadyPresent) { //<-- if at some level we already have read-write access, then that wins
-					//check: does it combine to provide 'readwrite' permissions via accessChecks through inheritance chain
-					if (accessChecks[fieldName] && accessChecks[fieldName] != field.access) {
-						//readonly or writeonly overridde at one level and different at another == readwrite
-						exclude = false;
-					} else {
-						if (!accessChecks[fieldName]) {
-							//cache for subsequent cross-checks as above
-							accessChecks[fieldName] = field.access;
-						}
-					}
-				}
-			}
-			//if a subclass override does not redeclare the field as transient, then it is already considered explicitly 'non-transient'
-			if (!exclude && !alreadyPresent && excludeTransient && field.metadata != null) {
-				//we need to mark Transient fields as special case
-				metas = field.metadata();
-				l = metas.length;
-				while (l--) {
-					if (metas[l].name == 'Transient') {
-						transient = true;
-						Traits.markTransient(fieldName, localTraits);
-						break;
-					}
-				}
-			}
-			if (!exclude) {
-				//set up null/undefined value lookups for undefined field values (when encoding)
-				var nullValues:Object = localTraits.nullValues;
-				if (field.type == 'Number') {
-					nullValues[fieldName] = Number.NaN;
-				} else if (field.type == 'Boolean') {
-					nullValues[fieldName] = false;
-				} else if (field.type == 'int' || field.type == 'uint') {
-					nullValues[fieldName] = 0;
-				} else if (field.type == '*') {
-					nullValues[fieldName] = undefined;
-				} else {
-					nullValues[fieldName] = null;
-				}
-				if (alreadyPresent) {
-					into.splice(into.indexOf(fieldName), 1);
-				}
-				if (!transient) into.push(fieldName);
-				if (asAccessors) {
-					localTraits.getterSetters[fieldName] = Traits.createInstanceAccessorGetterSetter(fieldName);
-				} else {
-					//variable
-					localTraits.getterSetters[fieldName] = Traits.createInstanceVariableGetterSetter(field.get_set, field.type);
-				}
-			}
-		}
-		return into;
-	}
-	
-	private const nothing:Object = {};
-	private function populateSerializableMembers(reflectionInfo:Object, accessChecks:Object, localTraits:Traits):Array {
-		if (!reflectionInfo) return localTraits.props;
-		var fields:Object = reflectionInfo.variables ? reflectionInfo.variables() : nothing;
-		filterSerializableMembers(fields, accessChecks, localTraits, false, true);
-		fields = reflectionInfo.accessors ? reflectionInfo.accessors() : nothing;
-		filterSerializableMembers(fields, accessChecks, localTraits, true, true);
-		return localTraits.props;
-	}
-	
-	private function getLocalTraitsInfo(instance:Object):Traits {
-		var classInfo:Object = instance.ROYALE_CLASS_INFO;
-		var originalClassInfo:Object;
-		var localTraits:Traits;
-		if (classInfo) {
-			localTraits = classInfo.localTraits;
-			if (localTraits) {
-				//implementation note: @todo a class may have more than one alias point to it
-				//update alias, in case of registration of alias changed since traits was last cached.
-				localTraits.alias = classInfo.alias || '';
-				return classInfo.localTraits;
-			}
-			originalClassInfo = classInfo;
-			localTraits = new Traits();
-			var alias:String = classInfo.alias;// getAliasByClass(instance.constructor as Class); //<- @todo possible optimization: registerClassAlias implementation stores in the classInfo Object, access directly
-			if (alias) localTraits.alias = alias;
-			else localTraits.alias = '';
-			localTraits.qName = classInfo.names[0].qName;
-			localTraits.isDynamic = Boolean(classInfo.names[0].isDynamic);
-			localTraits.externalizable = instance is IExternalizable;
-			
-			if (localTraits.externalizable) {
-				localTraits.count = 0;
-			} else {
-				var accessChecks:Object = {};
-				var c:Object = instance;
-				while (classInfo) {
-					var reflectionInfo:Object = c.ROYALE_REFLECTION_INFO();
-					populateSerializableMembers(reflectionInfo, accessChecks, localTraits);
-					if (!c.constructor.superClass_ || !c.constructor.superClass_.ROYALE_CLASS_INFO)
-						break;
-					classInfo = c.constructor.superClass_.ROYALE_CLASS_INFO;
-					c = c.constructor.superClass_;
-				}
-				//sometimes flash native seriazliation double-counts props and outputs some props data twice.
-				//this can happen with overrides (it was noticed with Transient overrides)
-				//it may mean that js amf output can sometimes be more compact, but should always deserialize to the same result.
-				localTraits.count = localTraits.props.length;
-				//not required, but useful when testing:
-				localTraits.props.sort();
-			}
-			//cache in the classInfo for faster lookups next time
-			originalClassInfo.localTraits = localTraits;
-		} else {
-			//assume dynamic, anon object
-			if (Object == instance.constructor) {
-				localTraits = Traits.getBaseObjectTraits();
-			} else {
-				//could be a class object
-				var anonFields:Array = [];
-				for (var key:String in instance) {
-					if (key !== "") {
-						anonFields.push(key);
-					}
-				}
-				localTraits = Traits.getDynObjectTraits(anonFields);
-			}
-			//not required, but useful when testing:
-			localTraits.props.sort();
-		}
-		return localTraits;
-	}
-	
-	public function writeObjectExternal(v:*, position:uint, mergeIntoOwner:Function):uint {
-		writeMode = true;
-		_position = 0;
-		_len = 0;
-		try{
-			writeObject(v);
-		} catch (e:Error) {
-			_error = e;
-		}
-		var output:Uint8Array = new Uint8Array(writeBuffer);
-		reset();
-		writeMode = false;
-		return mergeIntoOwner(position, output);
-	}
-	
-	/**
-	 * @royaleignorecoercion Class
-	 * @royaleignorecoercion String
-	 * @royaleignorecoercion Number
-	 * @royaleignorecoercion Array
-	 */
-	public function writeObject(v:*):void {
-		if (v == null) {
-			writeByte(AMF3_NULL);
-			return;
-		}
-		if (isFunctionValue(v)) {
-			//output function value as undefined
-			writeByte(AMF3_UNDEFINED);
-			return;
-		}
-		if (v is String) {
-			writeByte(AMF3_STRING);
-			writeStringWithoutType(v as String);
-		} else if (v is Number) {
-			var n:Number = v as Number;
-			if (n === +n && n === (n | 0)) {
-				writeAmfInt(n);
-			} else {
-				writeByte(AMF3_DOUBLE);
-				writeDouble(n);
-			}
-		} else if (v is Boolean) {
-			writeByte((v
-					? AMF3_BOOLEAN_TRUE
-					: AMF3_BOOLEAN_FALSE));
-		}
-		else if (v is Date) {
-			writeDate(v as Date);
-		}
-		else if (_xmlClass && v is _xmlClass) {
-			writeXML(v);
-		}
-		else {
-			if (v is Array) {
-				if (v.toString().indexOf("[Vector") == 0)
-					writeVector(v);
-				else
-					writeArray(v as Array);
-			} else writeObjectVariant(v);
-		}
-	}
-	
-	
-	private function writeXML(v:Object):void{
-		writeByte(AMF3_XML);
-		if (!this.objectByReference(v)) {
-			var source:String = v.toXMLString();
-			//don't use the regular string writing... it is not added to the String reference table (it seems)
-			//this.writeStringWithoutType(source);
-			writeAMF_UTF(source);
-		}
-	}
-	
-	
-	/**
-	 *
-	 * @royaleignorecoercion BinaryData
-	 * @royaleignorecoercion ArrayBuffer
-	 */
-	private function writeObjectVariant(v:Object):void {
-		if (v is AMFBinaryData || v is BinaryData) {
-			writeByte(AMF3_BYTEARRAY);
-			if (!this.objectByReference(v)) {
-				var binaryData:BinaryData = v as BinaryData;
-				var len:uint = binaryData.length;
-				this.writeUInt29((len << 1) | 1);
-				writeBytes(binaryData.data as ArrayBuffer);
-			}
-			return;
-		}
-		
-		writeByte(AMF3_OBJECT);
-		if (!this.objectByReference(v)) {
-			const localTraits:Traits = getLocalTraitsInfo(v);
-			if (localTraits.externalizable && !localTraits.alias) {
-				//in flash player if you try to write an object with no alias that is externalizable it does this:
-				throw new Error("ArgumentError: Error #2004: One of the parameters is invalid.");
-			}
-			writeTypedObject(v, localTraits);
-		}
-	}
-	
-	/**
-	 * This serialization context is passed as the 2nd parameter to an IDynamicPropertyWriter
-	 * implementation's writeDynamicProperties method call. The resolved properties are written here
-	 * @param name property name
-	 * @param value property value
-	 */
-	public function writeDynamicProperty(name:String, value:*):void {
-		this.writeStringWithoutType(name);
-		this.writeObject(value);
-	}
-	
-	
-	private function writeTypedObject(v:Object, localTraits:Traits):void {
-		var encodedName:String = localTraits.alias && localTraits.alias.length ? localTraits.alias : ']:' + localTraits.qName + ":[";
-		
-		if (!traitsByReference(localTraits.props, encodedName)) {
-			this.writeUInt29(3 | (localTraits.externalizable ? 4 : 0) | (localTraits.isDynamic ? 8 : 0) | (localTraits.count << 4));
-			this.writeStringWithoutType(localTraits.alias);
-			
-			if (!localTraits.externalizable) {
-				var l:uint = localTraits.count;
-				for (var i:uint = 0; i < l; i++) {
-					this.writeStringWithoutType(localTraits.props[i]);
-				}
-			}
-		}
-		
-		if (localTraits.externalizable) {
-			v.writeExternal(this);
-		} else {
-			l = localTraits.count;
-			for (i = 0; i < l; i++) {
-				//sealed props
-				var val:* = localTraits.getterSetters[localTraits.props[i]].getValue(v);
-				if (val === null || val === undefined) {
-					//coerce null values to the 'correct' types
-					val = localTraits.nullValues[localTraits.props[i]];
-					
-					//handle '*' type which can be undefined or explicitly null
-					if (val === undefined && localTraits.getterSetters[localTraits.props[i]].getValue(v) === null) {
-						val = null;
-					}
-				}
-				this.writeObject(val);
-			}
-			
-			if (localTraits.isDynamic) {
-				if (dynamicPropertyWriter != null) {
-					dynamicPropertyWriter.writeDynamicProperties(v, this);
-				} else {
-					//default implementation
-					var dynFields:Array = getDynamicFields(v);
-					i = 0;
-					l = dynFields.length;
-					for (; i < l; i++) {
-						val = v[dynFields[i]];
-						if (isFunctionValue(val)) {
-							//skip this name-value pair, don't even write it out as undefined (match flash)
-							continue;
-						}
-						this.writeStringWithoutType(dynFields[i]);
-						this.writeObject(val);
-					}
-				}
-				//end of dynamic properties marker
-				this.writeStringWithoutType(EMPTY_STRING);
-			}
-		}
-	}
-	
-	private var _comparator:String;
-	
-	/**
-	 * javascript does not differentiate between 'Class' and 'Function'
-	 * So in javascript : Object instanceof Function is true, in flash it is not (Object instanceof Class *is* true).
-	 * The function below is an attempt to discriminate between a pure function and a 'constructor' function
-	 * @param value the value to inspect
-	 * @return true if considered to be a 'pure' function value (not a constructor)
-	 */
-	private function isFunctionValue(value:*):Boolean {
-		if (value instanceof Function) {
-			var comparator:String = _comparator;
-			var checkBase:Array;
-			if (!comparator) {
-				//var ff:Function = function f():void {};
-				checkBase = Object.getOwnPropertyNames(function():void {});
-				if (checkBase.indexOf('name') != -1) {
-					checkBase.splice(checkBase.indexOf('name'), 1);
-				}
-				_comparator = comparator = checkBase.join(",");
-			}
-			checkBase = Object.getOwnPropertyNames(value);
-			if (checkBase.indexOf('name') != -1) {
-				checkBase.splice(checkBase.indexOf('name'), 1);
-			}
-			var check:String = checkBase.join(",");
-			return check == comparator ;
-		}
-		return false;
-	}
-
-	/**
-	 *
-	 * @royaleignorecoercion String
-	 */
-	private function writeArray(v:Array):void {
-		writeByte(AMF3_ARRAY);
-		var len:uint = v.length;
-		var i:uint = 0;
-		var akl:uint = 0; //associative keys length
-		if (!this.objectByReference(v)) {
-			var denseLength:uint = len;
-			var keys:Array = Object.keys(v);
-			//profile the array
-			//es6 specifies a generalized traversal order we can rely upon going forward
-			//testing in IE11 shows the same order applies in that es5 Array implementation, so we assume it here:
-			/*
-			Property keys are traversed in the following order:
-
-			First, the keys that are integer indices, in ascending numeric order.
-			note non-integers: '02' round-tripping results in the different string '2'.
-				'3.141' is not an integer index, because 3.141 is not an integer.
-			Then, all other string keys, in the order in which they were added to the object.
-			Lastly, all symbol keys, in the order in which they were added to the object.
-			We don't need to worry about Symbols here
-			 */
-			var kl:uint = keys.length;
-			//Assumption - based on the above,
-			//if the last key in the keys is an integer index, and length matches the array.length then it is a pure strict array
-			//if not, it is non-strict
-			var isFunctionValue:Function = this.isFunctionValue;
-			if (kl != len || (((keys[kl-1])>>0).toString() !== keys[kl-1]) || v.some(isFunctionValue)) {
-				//Array is not strict
-				if (len) {
-					//the array has at least some integer keys
-					
-					//find denseLength
-					for (i=0;i<len;i++) {
-						if (keys[i] != ""+i ) break;
-						//also seems to be true in avm:
-						if (isFunctionValue(v[i])) break;
-						
-					}
-					denseLength = i;
-					//remove dense keys,
-					//leaving only associative keys (which may include valid integer keys outside the dense part)
-					keys.splice(0, denseLength);
-				}// else all keys are associative keys, and denseLength is zero
-				akl = keys.length;
-			}
-			this.writeUInt29((denseLength << 1) | 1);
-			
-			if (akl) {
-				//name-value pairs of associative keys
-				for (i = 0; i < akl; i++) {
-					var val:* = v[keys[i]];
-					if (isFunctionValue(val)) {
-						continue;
-					}
-					this.writeStringWithoutType(keys[i] as String);
-					this.writeObject(val);
-				}
-			}
-			//empty string 'terminates' associative keys block - no more associative keys (if there were any)
-			writeStringWithoutType(EMPTY_STRING);
-			if (denseLength) {
-				for (i = 0; i < denseLength; i++) {
-					writeObject(v[i]);
-				}
-			}
-		}
-	}
-	
-	private function writeVector(v:Object):void {
-		writeByte(v.type);
-		var i:uint;
-		var len:uint = v.length;
-		if (!this.objectByReference(v)) {
-			this.writeUInt29((len << 1) | 1);
-			this.writeBoolean(v.fixed);
-		}
-		if (v.type == AMF3_VECTOR_OBJECT) {
-			var className:String = "";
-			if (len > 0) {
-				// TODO: how much of the PHP logic can we do here
-				className = v[0].constructor.name;
-			}
-			this.writeStringWithoutType(className);
-			for (i = 0; i < len; i++) {
-				writeObject(v[i]);
-			}
-		} else if (v.type == AMF3_VECTOR_INT) {
-			for (i = 0; i < len; i++) {
-				writeInt(v[i]);
-			}
-		} else if (v.type == AMF3_VECTOR_UINT) {
-			for (i = 0; i < len; i++) {
-				writeUnsignedInt(v[i]);
-			}
-		} else if (v.type == AMF3_VECTOR_DOUBLE) {
-			for (i = 0; i < len; i++) {
-				writeDouble(v[i]);
-			}
-		}
-	}
-	
-	public function readUInt29():int {
-		const read:Function = readUnsignedByte;
-		var b:uint = read() & 255;
-		if (b < 128) {
-			return b;
-		}
-		var value:uint = (b & 127) << 7;
-		b = read() & 255;
-		if (b < 128)
-			return (value | b);
-		value = (value | (b & 127)) << 7;
-		b = read() & 255;
-		if (b < 128)
-			return (value | b);
-		value = (value | (b & 127)) << 8;
-		b = read() & 255;
-		return (value | b);
-	}
-	
-	/**
-	 *
-	 * @royaleignorecoercion ArrayBuffer
-	 */
-	public function readObjectExternal():* {
-		if (ba != owner.data) {
-			ba = owner.data as ArrayBuffer;
-			_typedArray = new Uint8Array(ba);
-		}
-		_position = owner.position;
-		_len = owner.length;
-		try{
-			var result:* = readObject();
-		} catch (e:Error) {
-			_error = e;
-		}
-		reset();
-		owner.position = _position;
-		return result;
-	}
-	
-	public function readObject():* {
-		var amfType:uint = readUnsignedByte();
-		return readObjectValue(amfType);
-	}
-	
-	public function readXML():Object{
-		var ref:uint = readUInt29();
-		if ((ref & 1) == 0)
-			return getObject(ref >> 1);
-		else {
-			var len:uint = (ref >> 1);
-			var stringSource:String = readUTFBytes(len);
-			if (!_xmlClass) {
-				throw new Error("XML class is not linked in, as required for deserialization");
-			}
-			var xml:Object = new _xmlClass(stringSource);
-			rememberObject(xml);
-			return xml;
-		}
-	}
-	
-	public function readString():String {
-		var ref:uint = readUInt29();
-		if ((ref & 1) == 0) {
-			return getString(ref >> 1);
-		} else {
-			var len:uint = (ref >> 1);
-			if (len == 0) {
-				return EMPTY_STRING;
-			}
-			var str:String = readUTFBytes(len);
-			rememberString(str);
-			return str;
-		}
-	}
-	
-	private function rememberString(v:String):void {
-		strings[stringCount++] = v;
-	}
-	
-	private function getString(v:uint):String {
-		return strings[v];
-	}
-	
-	private function getObject(v:uint):Object {
-		
-		return objects[v];
-	}
-	
-	
-	private function getTraits(v:uint):Traits {
-		return traits[v] as Traits;
-	}
-	
-	private function rememberTraits(v:Traits):void {
-		traits[traitCount++] = v;
-	}
-	
-	
-	private function rememberObject(v:Object):void {
-		objects.push(v);
-	}
-	
-	private function readTraits(ref:uint):Traits {
-		var ti:Traits;
-		if ((ref & 3) == 1) {
-			ti = getTraits(ref >> 2);
-			return ti;
-		} else {
-			ti = new Traits();
-			ti.externalizable = ((ref & 4) == 4);
-			ti.isDynamic = ((ref & 8) == 8);
-			ti.count = (ref >> 4);
-			var className:String = readString();
-			if (className != null && className != "") {
-				ti.alias = className;
-			}
-			
-			for (var i:int = 0; i < ti.count; i++) {
-				ti.props.push(readString());
-			}
-			
-			rememberTraits(ti);
-			return ti;
-		}
-	}
-	
-	private function readScriptObject():Object {
-		var ref:uint = readUInt29();
-		if ((ref & 1) == 0) {
-			//retrieve object from object reference table
-			return getObject(ref >> 1);
-		} else {
-			var decodedTraits:Traits = readTraits(ref);
-			var obj:Object;
-			var localTraits:Traits;
-			if (decodedTraits.alias) {
-				var c:Class = getClassByAlias(decodedTraits.alias);
-				if (c) {
-					obj = new c();
-					localTraits = getLocalTraitsInfo(obj);
-				} else {
-					obj = {};
-				}
-			} else {
-				obj = {};
-			}
-			rememberObject(obj);
-			if (decodedTraits.externalizable) {
-				obj.readExternal(this);
-			} else {
-				const l:uint = decodedTraits.props.length;
-				var hasProp:Boolean;
-				for (var i:uint = 0; i < l; i++) {
-					var fieldValue:* = readObject();
-					var prop:String = decodedTraits.props[i];
-					hasProp = localTraits &&  (localTraits.hasProp(prop) || localTraits.isDynamic || localTraits.isTransient(prop));
-					if (hasProp) {
-						localTraits.getterSetters[prop].setValue(obj, fieldValue);
-					} else {
-						if (!localTraits) {
-							obj[prop] = fieldValue;
-						} else {
-							//@todo add debug-only logging for error checks (e.g. ReferenceError: Error #1074: Illegal write to read-only property)
-							if (goog.DEBUG) {
-								trace('ReferenceError: Error #1056: Cannot create property ' + prop + ' on ' + localTraits.qName);
-							}
-						}
-					}
-				}
-				if (decodedTraits.isDynamic) {
-					for (; ;) {
-						var name:String = readString();
-						if (name == null || name.length == 0) {
-							break;
-						}
-						obj[name] = readObject();
-					}
-				}
-			}
-			return obj;
-		}
-	}
-	
-	/**
-	 * @royaleignorecoercion Array
-	 */
-	public function readArray():Array {
-		var ref:uint = readUInt29();
-		if ((ref & 1) == 0)
-			return getObject(ref >> 1) as Array;
-		var denseLength:uint = (ref >> 1);
-		var array:Array = [];
-		rememberObject(array);
-		while (true) {
-			var name:String = readString();
-			if (!name)
-				break;
-			//associative keys first
-			array[name] = readObject();
-		}
-		//then dense array keys
-		for (var i:uint = 0; i < denseLength; i++) {
-			array[i] = readObject();
-		}
-		return array;
-	}
-	
-	/**
-	 * @royaleignorecoercion Array
-	 */
-	public function readDate():Date {
-		var ref:uint = readUInt29();
-		if ((ref & 1) == 0)
-			return getObject(ref >> 1) as Date;
-		var time:Number = readDouble();
-		var date:Date = new Date(time);
-		rememberObject(date);
-		return date;
-	}
-	
-	public function readByteArray():AMFBinaryData {
-		var ref:uint = readUInt29();
-		if ((ref & 1) == 0)
-			return getObject(ref >> 1) as AMFBinaryData;
-		else {
-			var len:uint = (ref >> 1);
-			var bytes:Uint8Array = new Uint8Array(len);
-			bytes.set(new Uint8Array(this.ba, _position, len));
-			_position += len;
-			var ba:AMFBinaryData = new AMFBinaryData(bytes.buffer);
-			rememberObject(ba);
-			return ba;
-		}
-	}
-	
-	private function toVector(type:uint, array:Array, fixed:Boolean):Array {
-		// TODO (aharui) handle vectors
-		return array;
-	}
-	
-	private function readAmf3Vector(amfType:uint):Object {
-		var ref:uint = readUInt29();
-		if ((ref & 1) == 0)
-			return getObject(ref >> 1);
-		var len:uint = (ref >> 1);
-		var vector:Array = toVector(amfType, [], readBoolean());
-		var i:uint;
-		if (amfType === AMF3_VECTOR_OBJECT) {
-			readString(); //className
-			for (i = 0; i < len; i++)
-				vector.push(readObject());
-		} else if (amfType === AMF3_VECTOR_INT) {
-			for (i = 0; i < len; i++)
-				vector.push(readInt());
-		} else if (amfType === AMF3_VECTOR_UINT) {
-			for (i = 0; i < len; i++)
-				vector.push(readUnsignedInt());
-		} else if (amfType === AMF3_VECTOR_DOUBLE) {
-			for (i = 0; i < len; i++)
-				vector.push(readDouble());
-		}
-		rememberObject(vector);
-		return vector;
-	}
-	
-	private function readObjectValue(amfType:uint):Object {
-		var value:Object = null;
-		var u:uint;
-		
-		switch (amfType) {
-			case AMF3_STRING:
-				value = readString();
-				break;
-			case AMF3_OBJECT:
-				try {
-					value = readScriptObject();
-				} catch (e:Error) {
-					if (goog.DEBUG){
-						var err:Error = (e.message.indexOf("Failed to deserialize") == -1)
-								? new Error("Failed to deserialize: " + e.message +' '+e.stack.split('\n')[1])
-								: e;
-						throw err;
-					}
-					else throw new Error("Failed to deserialize: " + e.message);
-				}
-				break;
-			case AMF3_ARRAY:
-				value = readArray();
-				break;
-			case AMF3_BOOLEAN_FALSE:
-				value = false;
-				break;
-			case AMF3_BOOLEAN_TRUE:
-				value = true;
-				break;
-			case AMF3_INTEGER:
-				u = readUInt29();
-				// Symmetric with writing an integer to fix sign bits for
-				// negative values...
-				value = (u << 3) >> 3;
-				break;
-			case AMF3_DOUBLE:
-				value = readDouble();
-				break;
-			case AMF3_UNDEFINED:
-			case AMF3_NULL:
-				break;
-			case AMF3_DATE:
-				value = readDate();
-				break;
-			case AMF3_BYTEARRAY:
-				value = readByteArray();
-				break;
-			case AMF3_XML:
-				value = readXML();
-				break;
-			case AMF3_VECTOR_INT:
-			case AMF3_VECTOR_UINT:
-			case AMF3_VECTOR_DOUBLE:
-			case AMF3_VECTOR_OBJECT:
-				value = readAmf3Vector(amfType);
-				break;
-			case AMF0_AMF3:
-				value = readObject();
-				break;
-			default:
-				throw new Error("Unsupported AMF type: " + amfType);
-		}
-		return value;
-	}
-}
-
-COMPILE::JS
-/**
- *  @royalesuppresspublicvarwarning
- *  @royalesuppressexport
- */
-class Traits {
-	import goog.DEBUG;
-	
-	
-	public static function createInstanceVariableGetterSetter(reflectionFunction:Function, type:String):Object{
-		var ret:Object = {
-			setValue: function(inst:Object, value:*):void {
-				reflectionFunction(inst, value);
-			}
-		};
-		
-		if (type == "*") {
-			ret.getValue =
-			 	function(inst:Object):* {
-					return reflectionFunction(inst, reflectionFunction);
-				}
-		} else {
-			ret.getValue =
-				function(inst:Object):* {
-					return reflectionFunction(inst);
-				}
-		}
-		return ret;
-	}
-	
-	public static function createInstanceAccessorGetterSetter(fieldName:String):Object{
-		return {
-			getValue: function(inst:Object):* {
-				return inst[fieldName];
-			},
-			setValue: function(inst:Object, value:*):void {
-				inst[fieldName] = value;
-			}
-		};
-	}
-
-	public static function markTransient(fieldName:String, traits:Traits):void{
-		if (!traits.transients) traits.transients={};
-		traits.transients[fieldName] = true;
-	}
-	
-	private static var _emtpy_object:Traits;
-	
-	
-	
-	public static function getClassTraits(fields:Array, qName:String):Traits{
-		var traits:Traits = new Traits();
-		traits.qName = '[Class] '+ qName;
-		traits.isDynamic = true;
-		traits.externalizable = false;
-		traits.props = fields;
-		
-		return traits;
-	}
-	
-	public static function getBaseObjectTraits():Traits {
-		if (_emtpy_object) return _emtpy_object;
-		var traits:Traits = _emtpy_object = new Traits();
-		traits.qName = 'Object';
-		traits.externalizable = false;
-		traits.isDynamic = true;
-		return traits;
-	}
-	
-	public static function getDynObjectTraits(fields:Array):Traits {
-		var traits:Traits;
-		traits = new Traits();
-		traits.qName = 'Object';
-		traits.externalizable = false;
-		traits.isDynamic = true;
-		traits.props = fields;
-		return traits;
-	}
-	
-	public var alias:String = '';
-	public var qName:String;
-	public var externalizable:Boolean;
-	public var isDynamic:Boolean;
-	public var count:uint = 0;
-	public var props:Array = [];
-	public var nullValues:Object = {};
-	
-	public var getterSetters:Object = {};
-	public var transients:Object ;
-	
-	public function hasProp(prop:String):Boolean {
-		return props.indexOf(prop) != -1;
-	}
-
-	public function isTransient(prop:String):Boolean {
-		return transients && prop in transients;
-	}
-	
-	public function toString():String {
-		if (goog.DEBUG) {
-			return 'Traits for \'' + qName + '\'\n'
-					+ 'alias: \'' + alias + '\'\n'
-					+ 'externalizable:' + Boolean(externalizable) + '\n'
-					+ 'isDynamic:' + Boolean(isDynamic) + '\n'
-					+ 'count:' + count + '\n'
-					+ 'props:\n\t' + props.join('\n\t');
-		} else {
-			return 'Traits';
-		}
-	}
-}
-
-
+}
\ No newline at end of file
diff --git a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFContext.as
similarity index 75%
copy from frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as
copy to frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFContext.as
index 89350f4..f383a42 100644
--- a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFBinaryData.as
+++ b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/AMFContext.as
@@ -18,144 +18,7 @@
  * AMF JavaScript library by Emil Malinov https://github.com/emilkm/amfjs
  */
 package org.apache.royale.net.remoting.amf {
-	import org.apache.royale.utils.net.IDataInput;
-	import org.apache.royale.utils.net.IDataOutput;
-	import org.apache.royale.utils.net.IDynamicPropertyWriter;
-	import org.apache.royale.utils.net.IExternalizable;
-	import org.apache.royale.utils.BinaryData;
 
-	COMPILE::JS{
-		import goog.DEBUG;
-	}
-	
-	COMPILE::SWF{
-		import flash.net.ObjectEncoding;
-	}
-	
-	/**
-	 *  A version of BinaryData specific to AMF.
-	 *
-	 *  @langversion 3.0
-	 *  @playerversion Flash 9
-	 *  @playerversion AIR 1.1
-	 *  @productversion BlazeDS 4
-	 *  @productversion LCDS 3
-	 *
-	 *  @royalesuppresspublicvarwarning
-	 */
-	public class AMFBinaryData extends BinaryData implements IDataInput, IDataOutput {
-
-		COMPILE::JS
-		private static var _propertyWriter:IDynamicPropertyWriter;
-		
-		/**
-		 * Allows greater control over the serialization of dynamic properties of dynamic objects.
-		 * When this property is set to null, the default value, dynamic properties are serialized using native code,
-		 * which writes all dynamic properties excluding those whose value is a function.
-		 * This value is called only for properties of a dynamic object (objects declared within a dynamic class) or
-		 * for objects declared using the new operator.
-		 * You can use this property to exclude properties of dynamic objects from serialization; to write values
-		 * to properties of dynamic objects; or to create new properties for dynamic objects. To do so,
-		 * set this property to an object that implements the IDynamicPropertyWriter interface. For more information,
-		 * see the IDynamicPropertyWriter interface.
-		 */
-		public static function get dynamicPropertyWriter():IDynamicPropertyWriter {
-			COMPILE::JS{
-				return _propertyWriter;
-			}
-			COMPILE::SWF{
-				var value:flash.net.IDynamicPropertyWriter =  ObjectEncoding.dynamicPropertyWriter;
-				var outValue:org.apache.royale.utils.net.IDynamicPropertyWriter = value as org.apache.royale.utils.net.IDynamicPropertyWriter;
-				if (value && !outValue) {
-					outValue = new ExternallySetDynamicPropertyWriter(value);
-				}
-				return outValue;
-			}
-		}
-		
-		public static function set dynamicPropertyWriter(value:IDynamicPropertyWriter):void {
-			COMPILE::JS{
-				_propertyWriter = value;
-			}
-			COMPILE::SWF{
-				ObjectEncoding.dynamicPropertyWriter = value;
-			}
-		}
-		
-		
-		
-		public function AMFBinaryData(bytes:Object = null) {
-			super(bytes);
-		}
-		
-		COMPILE::SWF
-		public function get objectEncoding():uint{
-			return 3;
-		}
-		COMPILE::SWF
-		public function set objectEncoding(value:uint):void{
-			trace('objectEncoding is always AMF3, setter is ignored');
-		}
-		
-		
-		
-		COMPILE::JS
-		private var _serializationContext:SerializationContext;
-		
-		COMPILE::JS
-		public function writeObject(v:*):void {
-			if (!_serializationContext) _serializationContext = new SerializationContext(this);
-			_serializationContext.dynamicPropertyWriter = _propertyWriter;
-			_position = _serializationContext.writeObjectExternal(v, _position, mergeInToArrayBuffer);
-			var err:Error = _serializationContext.getError();
-			if (err) {
-				throw new Error(err.message);
-			}
-		}
-		
-		COMPILE::JS
-		public function readObject():* {
-			if (!_serializationContext) _serializationContext = new SerializationContext(this);
-			var value:* = _serializationContext.readObjectExternal();
-			var err:Error = _serializationContext.getError();
-			if (err) {
-				if (goog.DEBUG){
-					console.log('%c[AMFBinaryData.readObject] - Deserialization Error :'+ err.message,'color:red');
-				}
-				throw new Error(err.message);
-			}
-			return value;
-		}
-		
-		COMPILE::SWF
-		public function writeObject(v:*):void {
-			ba.writeObject(v);
-		}
-		
-		COMPILE::SWF
-		public function readObject():* {
-			return ba.readObject();
-		}
-	}
-}
-
-
-COMPILE::SWF
-class ExternallySetDynamicPropertyWriter implements IDynamicPropertyWriter{
-	
-	import flash.net.IDynamicPropertyOutput;
-	
-	private var _externalImplementation:flash.net.IDynamicPropertyWriter;
-	
-	public function ExternallySetDynamicPropertyWriter(original:flash.net.IDynamicPropertyWriter) {
-		_externalImplementation = original;
-	}
-	
-	public function writeDynamicProperties(obj:Object, output:flash.net.IDynamicPropertyOutput):void {
-		_externalImplementation.writeDynamicProperties(obj, output);
-	}
-	
-}
 
 import org.apache.royale.net.remoting.amf.AMFBinaryData;
 import org.apache.royale.utils.net.IDynamicPropertyOutput;
@@ -164,6 +27,7 @@ import org.apache.royale.reflection.getAliasByClass;
 import org.apache.royale.reflection.getClassByAlias;
 import org.apache.royale.reflection.getDynamicFields;
 import org.apache.royale.reflection.getDefinitionByName;
+import org.apache.royale.reflection.getQualifiedClassName;
 import org.apache.royale.reflection.isDynamicObject;
 import org.apache.royale.utils.net.IDataInput;
 import org.apache.royale.utils.net.IDataOutput;
@@ -177,13 +41,14 @@ COMPILE::JS
 /**
  * @royalesuppressexport
  */
-class SerializationContext extends BinaryData  implements IDataInput, IDataOutput, IDynamicPropertyOutput {
+internal class AMFContext extends BinaryData implements IDataInput, IDataOutput, IDynamicPropertyOutput {
 	import goog.DEBUG;
-	
-	
+
+	import org.apache.royale.utils.Language;
+
 	private static const AMF0_AMF3:int = 0x11;
 	private static const AMF3_OBJECT_ENCODING:int = 0x03;
-	
+
 	private static const AMF3_UNDEFINED:int = 0x00;
 	private static const AMF3_NULL:int = 0x01;
 	private static const AMF3_BOOLEAN_FALSE:int = 0x02;
@@ -202,65 +67,66 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 	private static const AMF3_VECTOR_DOUBLE:int = 0x0F;
 	private static const AMF3_VECTOR_OBJECT:int = 0x10;
 	private static const AMF3_DICTIONARY:int = 0x11;
-	
-	
+
+
 	private static const UINT29_MASK:int = 0x1FFFFFFF;
 	private static const INT28_MAX_VALUE:int = 268435455;
 	private static const INT28_MIN_VALUE:int = -268435456;
-	
+
 	private static const EMPTY_STRING:String = "";
-	
-	private var owner:AMFBinaryData;
+
+	protected var owner:AMFBinaryData;
 	public var dynamicPropertyWriter:IDynamicPropertyWriter;
 	private var writeBuffer:Array;
-	
-	private var objects:Array ;
-	
+
+	protected var objects:Array;
+
 	private var traits:Object;
-	
+
 	private var strings:Object;
-	
+
 	private var stringCount:uint;
 	private var traitCount:uint;
-	private var objectCount:uint;
-	
-	
+	protected var objectCount:uint;
+
+
 	private var writeMode:Boolean = false;
-	
-	
+
 
 	private var _numbers:ArrayBuffer;
 
 	private var _numberView:DataView;
 
 	private var _numberBytes:Uint8Array;
-	
-	private static var _xmlClass:Class;
+
+	protected static var _xmlClass:Class;
 	private static var _xmlChecked:Boolean;
-	
+
 	private var _error:Error;
-	public function getError():Error{
+
+	public function getError():Error {
 		var _err:Error = _error;
 		_error = null;
 		return _err;
 	}
-	
+
 	/**
 	 * @royaleignorecoercion Class
 	 */
-	public function SerializationContext(ownerReference:AMFBinaryData){
+	public function AMFContext(ownerReference:AMFBinaryData) {
 		owner = ownerReference;
 		reset();
 		if (!_xmlChecked) {
 			_xmlChecked = true;
-			try{
+			try {
 				_xmlClass = getDefinitionByName('XML') as Class;
-			} catch(e:Error){}
+			} catch (e:Error) {
+			}
 		}
 		super();
 	}
-	
-	public function reset():void{
+
+	public function reset():void {
 		writeBuffer = [];
 		objects = [];
 		traits = {};
@@ -269,7 +135,10 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		traitCount = 0;
 		objectCount = 0;
 	}
-	
+
+	public function supportsAMFEncoding(type:uint):Boolean{
+		return type == 3;
+	}
 
 	/**
 	 * used internally as an override to return the writeBuffer Array for use to mimic Uint8Array during writing.
@@ -280,14 +149,13 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 	 * the 'buffer' is not, and that using Array will be more performant.
 	 * @royaleignorecoercion Uint8Array
 	 */
-	override protected function getTypedArray():Uint8Array{
+	override protected function getTypedArray():Uint8Array {
 		return writeMode ? writeBuffer as Uint8Array : super.getTypedArray();
 	}
-	
 
-	override protected function getDataView():DataView
-	{
-		if(!writeMode) return super.getDataView();
+
+	override protected function getDataView():DataView {
+		if (!writeMode) return super.getDataView();
 		//in write mode, return a utility version
 		if (!_numberView) {
 			_numbers = new ArrayBuffer(8);
@@ -296,29 +164,25 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		return _numberView;
 	}
-	
-	
 
-	override protected function setBufferSize(newSize:uint):void
-	{
+
+	override protected function setBufferSize(newSize:uint):void {
 		//writing variation: in this subclass, writing  is always using 'Array' so length is not fixed
 		_len = newSize;
 	}
-	
 
-	override public function writeByte(byte:int):void
-	{
+
+	override public function writeByte(byte:int):void {
 		writeBuffer[_position++] = byte & 255;
 	}
-	
-	override public function writeByteAt(idx:uint, byte:int):void
-	{
+
+	override public function writeByteAt(idx:uint, byte:int):void {
 		while (idx > _len) {
 			writeBuffer[_len++] = 0;
 		}
 		writeBuffer[idx] = byte & 255;
 	}
-	
+
 	public function writeUInt29(v:uint):void {
 		const write:Function = writeByte;
 		if (v < 128) {
@@ -339,8 +203,8 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			throw "Integer out of range: " + v;
 		}
 	}
-	
-	protected function addByteSequence(array:Array):void{
+
+	protected function addByteSequence(array:Array):void {
 		var length:uint = array.length;
 		if (_position == _len) {
 			writeBuffer = writeBuffer.concat(array);
@@ -359,11 +223,11 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				if (_len != writeBuffer.length) {
 					throw new Error('code review')
 				}
-				
+
 			} else {
 				//overwrite within - concatenate left and right slices with the new content between
 				writeBuffer = writeBuffer.slice(0, _position).concat(array, writeBuffer.slice(_position + length));
-				
+
 				if (_len != writeBuffer.length) {
 					throw new Error('code review')
 				}
@@ -371,73 +235,68 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		_position += length;
 	}
-	
-	
-	override public function writeBytes(bytes:ArrayBuffer, offset:uint = 0, length:uint = 0):void
-	{
-		if (length == 0) length = bytes.byteLength - offset ;
+
+
+	override public function writeBytes(bytes:ArrayBuffer, offset:uint = 0, length:uint = 0):void {
+		if (length == 0) length = bytes.byteLength - offset;
 		if (!length) return;
 		var src:Uint8Array = new Uint8Array(bytes, offset, offset + length);
 		var srcArray:Array = [].slice.call(src);
 		addByteSequence(srcArray);
 	}
-	
-	override public function writeUTF(str:String):void
-	{
-		var utcBytes:Uint8Array = getUTFBytes(str , true);
+
+	override public function writeUTF(str:String):void {
+		var utcBytes:Uint8Array = getUTFBytes(str, true);
 		var srcArray:Array = [].slice.call(utcBytes);
 		addByteSequence(srcArray);
 	}
-	
-	override public function writeUTFBytes(str:String):void
-	{
+
+	override public function writeUTFBytes(str:String):void {
 		var utcBytes:Uint8Array = getUTFBytes(str, false);
 		var srcArray:Array = [].slice.call(utcBytes);
 		addByteSequence(srcArray);
 	}
-	
-	protected function copyNumericBytes(byteCount:uint):void{
+
+	protected function copyNumericBytes(byteCount:uint):void {
 		//arr here is actually an Array, not Uint8Array
 		var arr:Uint8Array = getTypedArray();
 		var numbers:Uint8Array = _numberBytes;
 		var idx:uint = 0;
-		while(byteCount--) {
+		while (byteCount--) {
 			arr[_position++] = numbers[idx++];
 		}
 	}
-	
-	override public function writeFloat(val:Number):void
-	{
+
+	override public function writeFloat(val:Number):void {
 		//always big endian
-		getDataView().setFloat32(0,val,false);
+		getDataView().setFloat32(0, val, false);
 		copyNumericBytes(4);
 	}
-	
-	override public function writeDouble(val:Number):void
-	{
+
+	override public function writeDouble(val:Number):void {
 		//always big endian
-		getDataView().setFloat64(0,val,false);
+		getDataView().setFloat64(0, val, false);
 		copyNumericBytes(8);
 	}
-	
-	private function writeAMF_UTF(string:String):void{
-		var utcBytes:Uint8Array = getUTFBytes(string , false);
+
+	private function writeAMF3_UTF(string:String):void {
+		var utcBytes:Uint8Array = getUTFBytes(string, false);
 		var srcArray:Array = [].slice.call(utcBytes);
 		writeUInt29((srcArray.length << 1) | 1);
 		addByteSequence(srcArray);
 	}
-	
-	private function writeStringWithoutType(v:String):void {
+
+	private function writeAMF3StringWithoutType(v:String):void {
 		if (v.length == 0) {
 			writeUInt29(1);
 		} else {
-			if (!this.stringByReference(v)) {
-				writeAMF_UTF(v);
+			if (!this.amf3StringByReference(v)) {
+				writeAMF3_UTF(v);
 			}
 		}
 	}
-	
-	private function stringByReference(v:String):Boolean {
+
+	private function amf3StringByReference(v:String):Boolean {
 		const strIndex:* = strings[v];
 		const found:Boolean = strIndex !== undefined;
 		if (found) {
@@ -448,8 +307,8 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		return found;
 	}
-	
-	public function objectByReference(v:Object):Boolean {
+
+	public function amf3ObjectByReference(v:Object):Boolean {
 		const ref:int = objects.indexOf(v);
 		const found:Boolean = ref !== -1;
 		if (found) {
@@ -460,7 +319,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		return found;
 	}
-	
+
 	private function traitsByReference(props:Array, alias:String):Boolean {
 		//@todo review this. Don't think it is necessary to do the long joins with the props
 		//maybe alias alone is enough...?
@@ -475,8 +334,8 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		return found;
 	}
-	
-	private function writeAmfInt(v:int):void {
+
+	private function writeAmf3Int(v:int):void {
 		if (v >= INT28_MIN_VALUE && v <= INT28_MAX_VALUE) {
 			v = v & UINT29_MASK;
 			writeByte(AMF3_INTEGER);
@@ -486,15 +345,15 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			writeDouble(v);
 		}
 	}
-	
-	private function writeDate(v:Date):void {
+
+	private function writeAmf3Date(v:Date):void {
 		writeByte(AMF3_DATE);
-		if (!objectByReference(v)) {
+		if (!amf3ObjectByReference(v)) {
 			writeUInt29(1);
 			writeDouble(v.getTime());
 		}
 	}
-	
+
 	private function filterSerializableMembers(fieldSet:Object, accessChecks:Object, localTraits:Traits, asAccessors:Boolean = false, excludeTransient:Boolean = true):Array {
 		var l:uint;
 		var metas:Array;
@@ -502,7 +361,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		var transient:Boolean;
 		var fieldName:String;
 		const into:Array = localTraits.props;
-		
+
 		for (fieldName in fieldSet) {
 			//exclude all static props
 			if (fieldName.charAt(0) == '|') continue;
@@ -511,7 +370,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			var field:Object = fieldSet[fieldName];
 			exclude = false;
 			transient = false;
-			var alreadyPresent:Boolean = into.indexOf(fieldName) != -1 ;
+			var alreadyPresent:Boolean = into.indexOf(fieldName) != -1;
 			if (asAccessors) {
 				exclude = field.access != 'readwrite';
 				if (exclude && !alreadyPresent) { //<-- if at some level we already have read-write access, then that wins
@@ -568,8 +427,9 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		return into;
 	}
-	
+
 	private const nothing:Object = {};
+
 	private function populateSerializableMembers(reflectionInfo:Object, accessChecks:Object, localTraits:Traits):Array {
 		if (!reflectionInfo) return localTraits.props;
 		var fields:Object = reflectionInfo.variables ? reflectionInfo.variables() : nothing;
@@ -578,8 +438,8 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		filterSerializableMembers(fields, accessChecks, localTraits, true, true);
 		return localTraits.props;
 	}
-	
-	private function getLocalTraitsInfo(instance:Object):Traits {
+
+	protected function getLocalTraitsInfo(instance:Object):Traits {
 		var classInfo:Object = instance.ROYALE_CLASS_INFO;
 		var originalClassInfo:Object;
 		var localTraits:Traits;
@@ -599,7 +459,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			localTraits.qName = classInfo.names[0].qName;
 			localTraits.isDynamic = Boolean(classInfo.names[0].isDynamic);
 			localTraits.externalizable = instance is IExternalizable;
-			
+
 			if (localTraits.externalizable) {
 				localTraits.count = 0;
 			} else {
@@ -641,13 +501,15 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		return localTraits;
 	}
-	
+
 	public function writeObjectExternal(v:*, position:uint, mergeIntoOwner:Function):uint {
 		writeMode = true;
 		_position = 0;
 		_len = 0;
-		try{
-			writeObject(v);
+		try {
+			if (owner.objectEncoding == 0)
+				writeAmf0Object(v);
+			else writeAmf3Object(v)
 		} catch (e:Error) {
 			_error = e;
 		}
@@ -656,16 +518,29 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		writeMode = false;
 		return mergeIntoOwner(position, output);
 	}
-	
+
+	public function writeObject(v:*):void {
+		writeAmf3Object(v);
+	}
+
+
+	public function writeAmf0Object(v:*):void {
+		throw new Error('AMF0 support is unimplemented by default, supported via bead');
+	}
+
 	/**
 	 * @royaleignorecoercion Class
 	 * @royaleignorecoercion String
 	 * @royaleignorecoercion Number
 	 * @royaleignorecoercion Array
 	 */
-	public function writeObject(v:*):void {
+	public function writeAmf3Object(v:*):void {
 		if (v == null) {
-			writeByte(AMF3_NULL);
+			if (v === undefined) {
+				writeByte(AMF3_UNDEFINED);
+			} else {
+				writeByte(AMF3_NULL);
+			}
 			return;
 		}
 		if (isFunctionValue(v)) {
@@ -675,11 +550,11 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		if (v is String) {
 			writeByte(AMF3_STRING);
-			writeStringWithoutType(v as String);
+			writeAMF3StringWithoutType(v as String);
 		} else if (v is Number) {
 			var n:Number = v as Number;
 			if (n === +n && n === (n | 0)) {
-				writeAmfInt(n);
+				writeAmf3Int(n);
 			} else {
 				writeByte(AMF3_DOUBLE);
 				writeDouble(n);
@@ -688,44 +563,43 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			writeByte((v
 					? AMF3_BOOLEAN_TRUE
 					: AMF3_BOOLEAN_FALSE));
-		}
-		else if (v is Date) {
-			writeDate(v as Date);
-		}
-		else if (_xmlClass && v is _xmlClass) {
+		} else if (v is Date) {
+			writeAmf3Date(v as Date);
+		} else if (_xmlClass && v is _xmlClass) {
 			writeXML(v);
-		}
-		else {
-			if (v is Array) {
-				if (v.toString().indexOf("[Vector") == 0)
-					writeVector(v);
-				else
-					writeArray(v as Array);
-			} else writeObjectVariant(v);
+		} else {
+			if (Array.isArray(v)) {
+				if (v[Language.SYNTH_TAG_FIELD] != undefined) {
+					writeAmf3Vector(v[Language.SYNTH_TAG_FIELD]);
+				} else {
+					writeAmf3Array(v as Array);
+				}
+			} else {
+				writeAmf3ObjectVariant(v);
+			}
 		}
 	}
-	
-	
-	private function writeXML(v:Object):void{
+
+	private function writeXML(v:Object):void {
 		writeByte(AMF3_XML);
-		if (!this.objectByReference(v)) {
+		if (!this.amf3ObjectByReference(v)) {
 			var source:String = v.toXMLString();
 			//don't use the regular string writing... it is not added to the String reference table (it seems)
-			//this.writeStringWithoutType(source);
-			writeAMF_UTF(source);
+			//this.writeAMF3StringWithoutType(source);
+			writeAMF3_UTF(source);
 		}
 	}
-	
-	
+
+
 	/**
 	 *
 	 * @royaleignorecoercion BinaryData
 	 * @royaleignorecoercion ArrayBuffer
 	 */
-	private function writeObjectVariant(v:Object):void {
+	private function writeAmf3ObjectVariant(v:Object):void {
 		if (v is AMFBinaryData || v is BinaryData) {
 			writeByte(AMF3_BYTEARRAY);
-			if (!this.objectByReference(v)) {
+			if (!this.amf3ObjectByReference(v)) {
 				var binaryData:BinaryData = v as BinaryData;
 				var len:uint = binaryData.length;
 				this.writeUInt29((len << 1) | 1);
@@ -733,9 +607,9 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			}
 			return;
 		}
-		
+
 		writeByte(AMF3_OBJECT);
-		if (!this.objectByReference(v)) {
+		if (!this.amf3ObjectByReference(v)) {
 			const localTraits:Traits = getLocalTraitsInfo(v);
 			if (localTraits.externalizable && !localTraits.alias) {
 				//in flash player if you try to write an object with no alias that is externalizable it does this:
@@ -744,7 +618,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			writeTypedObject(v, localTraits);
 		}
 	}
-	
+
 	/**
 	 * This serialization context is passed as the 2nd parameter to an IDynamicPropertyWriter
 	 * implementation's writeDynamicProperties method call. The resolved properties are written here
@@ -752,26 +626,26 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 	 * @param value property value
 	 */
 	public function writeDynamicProperty(name:String, value:*):void {
-		this.writeStringWithoutType(name);
-		this.writeObject(value);
+		this.writeAMF3StringWithoutType(name);
+		this.writeAmf3Object(value);
 	}
-	
-	
+
+
 	private function writeTypedObject(v:Object, localTraits:Traits):void {
 		var encodedName:String = localTraits.alias && localTraits.alias.length ? localTraits.alias : ']:' + localTraits.qName + ":[";
-		
+
 		if (!traitsByReference(localTraits.props, encodedName)) {
 			this.writeUInt29(3 | (localTraits.externalizable ? 4 : 0) | (localTraits.isDynamic ? 8 : 0) | (localTraits.count << 4));
-			this.writeStringWithoutType(localTraits.alias);
-			
+			this.writeAMF3StringWithoutType(localTraits.alias);
+
 			if (!localTraits.externalizable) {
 				var l:uint = localTraits.count;
 				for (var i:uint = 0; i < l; i++) {
-					this.writeStringWithoutType(localTraits.props[i]);
+					this.writeAMF3StringWithoutType(localTraits.props[i]);
 				}
 			}
 		}
-		
+
 		if (localTraits.externalizable) {
 			v.writeExternal(this);
 		} else {
@@ -782,15 +656,15 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				if (val === null || val === undefined) {
 					//coerce null values to the 'correct' types
 					val = localTraits.nullValues[localTraits.props[i]];
-					
+
 					//handle '*' type which can be undefined or explicitly null
 					if (val === undefined && localTraits.getterSetters[localTraits.props[i]].getValue(v) === null) {
 						val = null;
 					}
 				}
-				this.writeObject(val);
+				this.writeAmf3Object(val);
 			}
-			
+
 			if (localTraits.isDynamic) {
 				if (dynamicPropertyWriter != null) {
 					dynamicPropertyWriter.writeDynamicProperties(v, this);
@@ -805,18 +679,18 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 							//skip this name-value pair, don't even write it out as undefined (match flash)
 							continue;
 						}
-						this.writeStringWithoutType(dynFields[i]);
-						this.writeObject(val);
+						this.writeAMF3StringWithoutType(dynFields[i]);
+						this.writeAmf3Object(val);
 					}
 				}
 				//end of dynamic properties marker
-				this.writeStringWithoutType(EMPTY_STRING);
+				this.writeAMF3StringWithoutType(EMPTY_STRING);
 			}
 		}
 	}
-	
+
 	private var _comparator:String;
-	
+
 	/**
 	 * javascript does not differentiate between 'Class' and 'Function'
 	 * So in javascript : Object instanceof Function is true, in flash it is not (Object instanceof Class *is* true).
@@ -824,13 +698,14 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 	 * @param value the value to inspect
 	 * @return true if considered to be a 'pure' function value (not a constructor)
 	 */
-	private function isFunctionValue(value:*):Boolean {
+	protected function isFunctionValue(value:*):Boolean {
 		if (value instanceof Function) {
 			var comparator:String = _comparator;
 			var checkBase:Array;
 			if (!comparator) {
 				//var ff:Function = function f():void {};
-				checkBase = Object.getOwnPropertyNames(function():void {});
+				checkBase = Object.getOwnPropertyNames(function ():void {
+				});
 				if (checkBase.indexOf('name') != -1) {
 					checkBase.splice(checkBase.indexOf('name'), 1);
 				}
@@ -841,7 +716,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				checkBase.splice(checkBase.indexOf('name'), 1);
 			}
 			var check:String = checkBase.join(",");
-			return check == comparator ;
+			return check == comparator;
 		}
 		return false;
 	}
@@ -850,12 +725,12 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 	 *
 	 * @royaleignorecoercion String
 	 */
-	private function writeArray(v:Array):void {
+	private function writeAmf3Array(v:Array):void {
 		writeByte(AMF3_ARRAY);
 		var len:uint = v.length;
 		var i:uint = 0;
 		var akl:uint = 0; //associative keys length
-		if (!this.objectByReference(v)) {
+		if (!this.amf3ObjectByReference(v)) {
 			var denseLength:uint = len;
 			var keys:Array = Object.keys(v);
 			//profile the array
@@ -876,17 +751,17 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			//if the last key in the keys is an integer index, and length matches the array.length then it is a pure strict array
 			//if not, it is non-strict
 			var isFunctionValue:Function = this.isFunctionValue;
-			if (kl != len || (((keys[kl-1])>>0).toString() !== keys[kl-1]) || v.some(isFunctionValue)) {
+			if (kl != len || (((keys[kl - 1]) >> 0).toString() !== keys[kl - 1]) || v.some(isFunctionValue)) {
 				//Array is not strict
 				if (len) {
 					//the array has at least some integer keys
-					
+
 					//find denseLength
-					for (i=0;i<len;i++) {
-						if (keys[i] != ""+i ) break;
+					for (i = 0; i < len; i++) {
+						if (keys[i] != "" + i) break;
 						//also seems to be true in avm:
 						if (isFunctionValue(v[i])) break;
-						
+
 					}
 					denseLength = i;
 					//remove dense keys,
@@ -896,7 +771,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				akl = keys.length;
 			}
 			this.writeUInt29((denseLength << 1) | 1);
-			
+
 			if (akl) {
 				//name-value pairs of associative keys
 				for (i = 0; i < akl; i++) {
@@ -904,53 +779,84 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 					if (isFunctionValue(val)) {
 						continue;
 					}
-					this.writeStringWithoutType(keys[i] as String);
-					this.writeObject(val);
+					this.writeAMF3StringWithoutType(keys[i] as String);
+					this.writeAmf3Object(val);
 				}
 			}
 			//empty string 'terminates' associative keys block - no more associative keys (if there were any)
-			writeStringWithoutType(EMPTY_STRING);
+			writeAMF3StringWithoutType(EMPTY_STRING);
 			if (denseLength) {
 				for (i = 0; i < denseLength; i++) {
-					writeObject(v[i]);
+					writeAmf3Object(v[i]);
 				}
 			}
 		}
 	}
-	
-	private function writeVector(v:Object):void {
-		writeByte(v.type);
+
+	/**
+	 *
+	 * @royaleignorecoercion Array
+	 * @royaleignorecoercion String
+	 * @royaleignorecoercion Boolean
+	 * @royaleignorecoercion Number
+	 * @royaleignorecoercion uint
+	 * @royaleignorecoercion int
+	 */
+	private function writeAmf3Vector(v:Object):void {
+		//v is a Vector synthType instance
+		var className:String = v['type'] as String;
+		var content:Array = v['value'] as Array;
+		var amfType:uint;
+		if (className == 'Vector.<int>') amfType = AMF3_VECTOR_INT
+		else if (className == 'Vector.<uint>') amfType = AMF3_VECTOR_UINT
+		else if (className == 'Vector.<Number>') amfType = AMF3_VECTOR_DOUBLE
+		else amfType = AMF3_VECTOR_OBJECT
+		writeByte(amfType);
+
 		var i:uint;
 		var len:uint = v.length;
-		if (!this.objectByReference(v)) {
+		if (!this.amf3ObjectByReference(v)) {
 			this.writeUInt29((len << 1) | 1);
-			this.writeBoolean(v.fixed);
-		}
-		if (v.type == AMF3_VECTOR_OBJECT) {
-			var className:String = "";
-			if (len > 0) {
-				// TODO: how much of the PHP logic can we do here
-				className = v[0].constructor.name;
-			}
-			this.writeStringWithoutType(className);
-			for (i = 0; i < len; i++) {
-				writeObject(v[i]);
-			}
-		} else if (v.type == AMF3_VECTOR_INT) {
-			for (i = 0; i < len; i++) {
-				writeInt(v[i]);
-			}
-		} else if (v.type == AMF3_VECTOR_UINT) {
-			for (i = 0; i < len; i++) {
-				writeUnsignedInt(v[i]);
-			}
-		} else if (v.type == AMF3_VECTOR_DOUBLE) {
-			for (i = 0; i < len; i++) {
-				writeDouble(v[i]);
+			this.writeBoolean(v['fixed'] as Boolean);
+			if (amfType == AMF3_VECTOR_OBJECT) {
+				//note this is available as a specific field, but not yet readily accessible in terms of field name
+				className = className.substring(8, className.length - 1); //strip leading 'Vector.<' and trailing '>'
+				if (className == '*') {
+					className = '';
+				} else {
+					try {
+						className = getAliasByClass(getDefinitionByName(className)) || '';
+					} catch (e:Error) {
+						className = '';
+					}
+				}
+
+				/*if (className == 'Boolean' || className == 'String' || className == 'Class' || className == 'Array' || className=='Object' || className=='*') {
+					className = ''; // this will be a Vector.<Object> on read (even for '*' it seems, contrary to spec)
+				} else {
+
+				}*/
+				this.writeAMF3StringWithoutType(className);
+				for (i = 0; i < len; i++) {
+
+					writeAmf3Object(content[i]);
+				}
+			} else if (amfType == AMF3_VECTOR_INT) {
+				for (i = 0; i < len; i++) {
+					writeInt(content[i] as int);
+				}
+			} else if (v.type == AMF3_VECTOR_UINT) {
+				for (i = 0; i < len; i++) {
+					writeUnsignedInt(content[i] as uint);
+				}
+			} else if (v.type == AMF3_VECTOR_DOUBLE) {
+				for (i = 0; i < len; i++) {
+					writeDouble(content[i] as Number);
+				}
 			}
 		}
 	}
-	
+
 	public function readUInt29():int {
 		const read:Function = readUnsignedByte;
 		var b:uint = read() & 255;
@@ -969,7 +875,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		b = read() & 255;
 		return (value | b);
 	}
-	
+
 	/**
 	 *
 	 * @royaleignorecoercion ArrayBuffer
@@ -978,11 +884,15 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		if (ba != owner.data) {
 			ba = owner.data as ArrayBuffer;
 			_typedArray = new Uint8Array(ba);
+			_dataView = null;
 		}
 		_position = owner.position;
 		_len = owner.length;
-		try{
-			var result:* = readObject();
+		try {
+			var result:*;
+			if (owner.objectEncoding == 0)
+					 result = readAmf0Object();
+			else result = readAmf3Object();
 		} catch (e:Error) {
 			_error = e;
 		}
@@ -990,13 +900,22 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		owner.position = _position;
 		return result;
 	}
-	
+
 	public function readObject():* {
+		return readAmf3Object();
+	}
+
+	public function readAmf0Object():* {
+		throw new Error('AMF0 support is unimplemented by default, supported via bead');
+	}
+
+	public function readAmf3Object():* {
 		var amfType:uint = readUnsignedByte();
-		return readObjectValue(amfType);
+		return readAmf3ObjectValue(amfType);
 	}
-	
-	public function readXML():Object{
+
+
+	public function readAmf3XML():Object {
 		var ref:uint = readUInt29();
 		if ((ref & 1) == 0)
 			return getObject(ref >> 1);
@@ -1011,8 +930,8 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			return xml;
 		}
 	}
-	
-	public function readString():String {
+
+	public function readAmf3String():String {
 		var ref:uint = readUInt29();
 		if ((ref & 1) == 0) {
 			return getString(ref >> 1);
@@ -1026,34 +945,34 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			return str;
 		}
 	}
-	
+
 	private function rememberString(v:String):void {
 		strings[stringCount++] = v;
 	}
-	
+
 	private function getString(v:uint):String {
 		return strings[v];
 	}
-	
-	private function getObject(v:uint):Object {
-		
+
+	protected function getObject(v:uint):Object {
+
 		return objects[v];
 	}
-	
-	
+
+
 	private function getTraits(v:uint):Traits {
 		return traits[v] as Traits;
 	}
-	
+
 	private function rememberTraits(v:Traits):void {
 		traits[traitCount++] = v;
 	}
-	
-	
-	private function rememberObject(v:Object):void {
+
+
+	protected function rememberObject(v:Object):void {
 		objects.push(v);
 	}
-	
+
 	private function readTraits(ref:uint):Traits {
 		var ti:Traits;
 		if ((ref & 3) == 1) {
@@ -1064,20 +983,20 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			ti.externalizable = ((ref & 4) == 4);
 			ti.isDynamic = ((ref & 8) == 8);
 			ti.count = (ref >> 4);
-			var className:String = readString();
+			var className:String = readAmf3String();
 			if (className != null && className != "") {
 				ti.alias = className;
 			}
-			
+
 			for (var i:int = 0; i < ti.count; i++) {
-				ti.props.push(readString());
+				ti.props.push(readAmf3String());
 			}
-			
+
 			rememberTraits(ti);
 			return ti;
 		}
 	}
-	
+
 	private function readScriptObject():Object {
 		var ref:uint = readUInt29();
 		if ((ref & 1) == 0) {
@@ -1107,7 +1026,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				for (var i:uint = 0; i < l; i++) {
 					var fieldValue:* = readObject();
 					var prop:String = decodedTraits.props[i];
-					hasProp = localTraits &&  (localTraits.hasProp(prop) || localTraits.isDynamic || localTraits.isTransient(prop));
+					hasProp = localTraits && (localTraits.hasProp(prop) || localTraits.isDynamic || localTraits.isTransient(prop));
 					if (hasProp) {
 						localTraits.getterSetters[prop].setValue(obj, fieldValue);
 					} else {
@@ -1123,7 +1042,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				}
 				if (decodedTraits.isDynamic) {
 					for (; ;) {
-						var name:String = readString();
+						var name:String = readAmf3String();
 						if (name == null || name.length == 0) {
 							break;
 						}
@@ -1134,11 +1053,11 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			return obj;
 		}
 	}
-	
+
 	/**
 	 * @royaleignorecoercion Array
 	 */
-	public function readArray():Array {
+	public function readAmf3Array():Array {
 		var ref:uint = readUInt29();
 		if ((ref & 1) == 0)
 			return getObject(ref >> 1) as Array;
@@ -1146,7 +1065,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		var array:Array = [];
 		rememberObject(array);
 		while (true) {
-			var name:String = readString();
+			var name:String = readAmf3String();
 			if (!name)
 				break;
 			//associative keys first
@@ -1158,11 +1077,11 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		}
 		return array;
 	}
-	
+
 	/**
 	 * @royaleignorecoercion Array
 	 */
-	public function readDate():Date {
+	public function readAmf3Date():Date {
 		var ref:uint = readUInt29();
 		if ((ref & 1) == 0)
 			return getObject(ref >> 1) as Date;
@@ -1171,7 +1090,7 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		rememberObject(date);
 		return date;
 	}
-	
+
 	public function readByteArray():AMFBinaryData {
 		var ref:uint = readUInt29();
 		if ((ref & 1) == 0)
@@ -1186,60 +1105,74 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 			return ba;
 		}
 	}
-	
-	private function toVector(type:uint, array:Array, fixed:Boolean):Array {
-		// TODO (aharui) handle vectors
-		return array;
-	}
-	
+
+
+	/**
+	 *
+	 * @royaleignorecoercion Array
+	 */
 	private function readAmf3Vector(amfType:uint):Object {
 		var ref:uint = readUInt29();
 		if ((ref & 1) == 0)
 			return getObject(ref >> 1);
 		var len:uint = (ref >> 1);
-		var vector:Array = toVector(amfType, [], readBoolean());
+		var fixed:Boolean = readBoolean();
+		/*var vector:Array = toVector(amfType, [], readBoolean());*/
+		var vector:Array;
 		var i:uint;
 		if (amfType === AMF3_VECTOR_OBJECT) {
-			readString(); //className
+			var className:String = readAmf3String(); //className
+			if (className == '') {
+				className = 'Object'
+			} else {
+				try {
+					className = getQualifiedClassName(getClassByAlias(className));
+				} catch (e:Error) {
+					className = 'Object'
+				}
+			}
+			vector = Language.Vector(len, className, fixed) as Array;
 			for (i = 0; i < len; i++)
-				vector.push(readObject());
+				vector[i] = readObject();
 		} else if (amfType === AMF3_VECTOR_INT) {
+			vector = Language.Vector(len, 'int', fixed) as Array;
 			for (i = 0; i < len; i++)
-				vector.push(readInt());
+				vector[i] = readInt();
 		} else if (amfType === AMF3_VECTOR_UINT) {
+			vector = Language.Vector(len, 'uint', fixed) as Array;
 			for (i = 0; i < len; i++)
-				vector.push(readUnsignedInt());
+				vector[i] = readUnsignedInt();
 		} else if (amfType === AMF3_VECTOR_DOUBLE) {
+			vector = Language.Vector(len, 'Number', fixed) as Array;
 			for (i = 0; i < len; i++)
-				vector.push(readDouble());
+				vector[i] = readDouble();
 		}
 		rememberObject(vector);
 		return vector;
 	}
-	
-	private function readObjectValue(amfType:uint):Object {
+
+	private function readAmf3ObjectValue(amfType:uint):Object {
 		var value:Object = null;
 		var u:uint;
-		
+
 		switch (amfType) {
 			case AMF3_STRING:
-				value = readString();
+				value = readAmf3String();
 				break;
 			case AMF3_OBJECT:
 				try {
 					value = readScriptObject();
 				} catch (e:Error) {
-					if (goog.DEBUG){
+					if (goog.DEBUG) {
 						var err:Error = (e.message.indexOf("Failed to deserialize") == -1)
-								? new Error("Failed to deserialize: " + e.message +' '+e.stack.split('\n')[1])
+								? new Error("Failed to deserialize: " + e.message + ' ' + e.stack.split('\n')[1])
 								: e;
 						throw err;
-					}
-					else throw new Error("Failed to deserialize: " + e.message);
+					} else throw new Error("Failed to deserialize: " + e.message);
 				}
 				break;
 			case AMF3_ARRAY:
-				value = readArray();
+				value = readAmf3Array();
 				break;
 			case AMF3_BOOLEAN_FALSE:
 				value = false;
@@ -1257,16 +1190,19 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 				value = readDouble();
 				break;
 			case AMF3_UNDEFINED:
+				value = undefined;
+				break;
 			case AMF3_NULL:
+				//null is already assigned by default
 				break;
 			case AMF3_DATE:
-				value = readDate();
+				value = readAmf3Date();
 				break;
 			case AMF3_BYTEARRAY:
 				value = readByteArray();
 				break;
 			case AMF3_XML:
-				value = readXML();
+				value = readAmf3XML();
 				break;
 			case AMF3_VECTOR_INT:
 			case AMF3_VECTOR_UINT:
@@ -1283,12 +1219,14 @@ class SerializationContext extends BinaryData  implements IDataInput, IDataOutpu
 		return value;
 	}
 }
+}
 
+/*
 COMPILE::JS
-/**
+/!**
  *  @royalesuppresspublicvarwarning
  *  @royalesuppressexport
- */
+ *!/
 class Traits {
 	import goog.DEBUG;
 	
@@ -1395,5 +1333,6 @@ class Traits {
 		}
 	}
 }
+*/
 
 
diff --git a/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/Traits.as b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/Traits.as
new file mode 100644
index 0000000..a5c7cf8
--- /dev/null
+++ b/frameworks/projects/Network/src/main/royale/org/apache/royale/net/remoting/amf/Traits.as
@@ -0,0 +1,136 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed 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.
+//
+////////////////////////////////////////////////////////////////////////////////
+/***
+ * Based on the
+ * AMF JavaScript library by Emil Malinov https://github.com/emilkm/amfjs
+ */
+package org.apache.royale.net.remoting.amf {
+
+
+
+COMPILE::JS
+/**
+ * @royalesuppressexport
+ */
+internal class Traits  {
+	import goog.DEBUG;
+
+
+	public static function createInstanceVariableGetterSetter(reflectionFunction:Function, type:String):Object{
+		var ret:Object = {
+			setValue: function(inst:Object, value:*):void {
+				reflectionFunction(inst, value);
+			}
+		};
+
+		if (type == "*") {
+			ret.getValue =
+					function(inst:Object):* {
+						return reflectionFunction(inst, reflectionFunction);
+					}
+		} else {
+			ret.getValue =
+					function(inst:Object):* {
+						return reflectionFunction(inst);
+					}
+		}
+		return ret;
+	}
+
+	public static function createInstanceAccessorGetterSetter(fieldName:String):Object{
+		return {
+			getValue: function(inst:Object):* {
+				return inst[fieldName];
+			},
+			setValue: function(inst:Object, value:*):void {
+				inst[fieldName] = value;
+			}
+		};
+	}
+
+	public static function markTransient(fieldName:String, traits:Traits):void{
+		if (!traits.transients) traits.transients={};
+		traits.transients[fieldName] = true;
+	}
+
+	private static var _emtpy_object:Traits;
+
+
+
+	public static function getClassTraits(fields:Array, qName:String):Traits{
+		var traits:Traits = new Traits();
+		traits.qName = '[Class] '+ qName;
+		traits.isDynamic = true;
+		traits.externalizable = false;
+		traits.props = fields;
+
+		return traits;
+	}
+
+	public static function getBaseObjectTraits():Traits {
+		if (_emtpy_object) return _emtpy_object;
+		var traits:Traits = _emtpy_object = new Traits();
+		traits.qName = 'Object';
+		traits.externalizable = false;
+		traits.isDynamic = true;
+		return traits;
+	}
+
+	public static function getDynObjectTraits(fields:Array):Traits {
+		var traits:Traits;
+		traits = new Traits();
+		traits.qName = 'Object';
+		traits.externalizable = false;
+		traits.isDynamic = true;
+		traits.props = fields;
+		return traits;
+	}
+
+	public var alias:String = '';
+	public var qName:String;
+	public var externalizable:Boolean;
+	public var isDynamic:Boolean;
+	public var count:uint = 0;
+	public var props:Array = [];
+	public var nullValues:Object = {};
+
+	public var getterSetters:Object = {};
+	public var transients:Object ;
+
+	public function hasProp(prop:String):Boolean {
+		return props.indexOf(prop) != -1;
+	}
+
+	public function isTransient(prop:String):Boolean {
+		return transients && prop in transients;
+	}
+
+	public function toString():String {
+		if (goog.DEBUG) {
+			return 'Traits for \'' + qName + '\'\n'
+					+ 'alias: \'' + alias + '\'\n'
+					+ 'externalizable:' + Boolean(externalizable) + '\n'
+					+ 'isDynamic:' + Boolean(isDynamic) + '\n'
+					+ 'count:' + count + '\n'
+					+ 'props:\n\t' + props.join('\n\t');
+		} else {
+			return 'Traits';
+		}
+	}
+	}
+}
+
+
diff --git a/frameworks/projects/Network/src/test/royale/flexUnitTests/NetworkTester.as b/frameworks/projects/Network/src/test/royale/flexUnitTests/NetworkTester.as
index 317c6c8..183e762 100644
--- a/frameworks/projects/Network/src/test/royale/flexUnitTests/NetworkTester.as
+++ b/frameworks/projects/Network/src/test/royale/flexUnitTests/NetworkTester.as
@@ -34,7 +34,7 @@ package flexUnitTests
         }
         
         public var amfBinaryDataTesterTest:AMFBinaryDataTesterTest;
-        
+        public var amf0BinaryDataTesterTest:AMF0BinaryDataTesterTest;
         public var urlVariablesTesterTest:URLVariablesTesterTest;
         
     }
diff --git a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMF0BinaryDataTesterTest.as
similarity index 64%
copy from frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as
copy to frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMF0BinaryDataTesterTest.as
index 1cca14c..c5850fb 100644
--- a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as
+++ b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMF0BinaryDataTesterTest.as
@@ -30,15 +30,17 @@ package flexUnitTests.network
     import flexUnitTests.network.support.TestClass6;
     import flexUnitTests.network.support.TestClass7a;
     import flexUnitTests.network.support.TestClass7b;
-    import org.apache.royale.test.asserts.*;
-    
+
     import org.apache.royale.net.remoting.amf.AMFBinaryData;
+    import org.apache.royale.net.remoting.amf.AMF0SupportBead;
+
+    import org.apache.royale.test.asserts.*;
     import org.apache.royale.reflection.*;
     
-    
-    public class AMFBinaryDataTesterTest
+
+    public class AMF0BinaryDataTesterTest
     {
-        
+
         [Before]
         public function setUp():void
         {
@@ -52,6 +54,9 @@ package flexUnitTests.network
         [BeforeClass]
         public static function setUpBeforeClass():void
         {
+            ExtraData.addAll();
+            //this is simply to avoid adding the bead in the RoyaleUnit Application:
+            AMF0SupportBead.installAMF0Support();
         }
         
         [AfterClass]
@@ -59,6 +64,12 @@ package flexUnitTests.network
         {
         }
         
+        private function createAMFOBinaryData():AMFBinaryData{
+            var amf:AMFBinaryData = new AMFBinaryData();
+            amf.objectEncoding = 0;
+            return amf;
+        }
+        
         
         //util check functions
         private static function bytesMatchExpectedData(bd:AMFBinaryData, expected:Array, offset:int = 0):Boolean
@@ -91,28 +102,59 @@ package flexUnitTests.network
         [Test]
         public function testStringObjectEncoding():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             var testString:String = 'testString';
             
             ba.writeObject(testString);
-            
-            assertEquals( ba.length, 12, "post-write length was not correct");
-            assertEquals( ba.position, 12, "post-write position was not correct");
+
+            assertEquals( ba.length, 13, "post-write length was not correct");
+            assertEquals( ba.position, 13, "post-write position was not correct");
             ba.position = 0;
             var readString:String = ba.readObject() as String;
             assertEquals( readString, testString, "post-write read of written string was not correct");
+
+            //test long string
+            var baseString:String = '';
+            var l:uint = 100;
+            while (l) {
+                baseString += String.fromCharCode(32+100-l);
+                l--;
+            }
+            var buffer:Array = [];
+            while (l<65536) {
+                buffer.push(baseString);
+                l += 100;
+            }
+            baseString = buffer.join('');
+
+            ba.length = 0;
+            ba.writeObject(baseString);
+
+            assertEquals( ba.length, 68229, "post-write length was not correct");
+            assertEquals( ba.position, 68229, "post-write position was not correct");
+            ba.position = 0;
+            readString = ba.readObject() as String;
+            assertEquals( readString, baseString, "post-write read of written string was not correct");
+
+            ba.length=0;
+            ba.writeObject('');
+            assertEquals( ba.length, 3, "post-write length was not correct");
+            assertEquals( ba.position, 3, "post-write position was not correct");
+            ba.position = 0;
+            readString = ba.readObject() as String;
+            assertEquals( readString, '', "post-write read of written string was not correct");
         }
         
         [Test]
         public function testBooleanObjectEncoding():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             
             ba.writeObject(false);
             ba.writeObject(true);
             
-            assertEquals( ba.length, 2, "post-write length was not correct");
-            assertEquals( ba.position, 2, "post-write position was not correct");
+            assertEquals( ba.length, 4, "post-write length was not correct");
+            assertEquals( ba.position, 4, "post-write position was not correct");
             ba.position = 0;
             
             assertTrue( ba.readObject() === false, "post-write read of written boolean was not correct");
@@ -122,7 +164,7 @@ package flexUnitTests.network
         [Test]
         public function testNumberEncoding():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             
             
             ba.writeObject(NaN);
@@ -133,8 +175,8 @@ package flexUnitTests.network
             ba.writeObject(Infinity);
             ba.writeObject(-Infinity);
             
-            assertEquals( ba.length, 52, "post-write length was not correct");
-            assertEquals( ba.position, 52, "post-write position was not correct");
+            assertEquals( ba.length, 63, "post-write length was not correct");
+            assertEquals( ba.position, 63, "post-write position was not correct");
             ba.position = 0;
             
             var num:Number = ba.readObject();
@@ -161,23 +203,39 @@ package flexUnitTests.network
             assertTrue( !isFinite(num), "post-write read of written Number was not correct");
             assertTrue( (num < 0), "post-write read of written Number was not correct");
         }
+
+        [Test]
+        public function testNullAndUndefinedEncoding():void
+        {
+            var ba:AMFBinaryData = createAMFOBinaryData();
+            ba.writeObject(null);
+            ba.writeObject(undefined);
+
+            ba.position = 0;
+            var val:* = ba.readObject();
+            assertStrictlyEquals(val, null, 'Should be null');
+            val = ba.readObject();
+            assertStrictlyEquals(val, undefined, 'Should be undefined');
+        }
         
         
         [Test]
         public function testArrayInstance():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             var instance:Array = [];
             ba.writeObject(instance);
-            
-            assertEquals( ba.length, 3, "post-write length was not correct");
-            assertEquals( ba.position, 3, "post-write position was not correct");
-            
+
+            assertEquals( ba.length, 8, "post-write length was not correct");
+            assertEquals( ba.position, 8, "post-write position was not correct");
+
+
             instance = [99];
             ba.length = 0;
             ba.writeObject(instance);
             ba.position = 0;
-            assertTrue( bytesMatchExpectedData(ba, [9, 3, 1, 4, 99]), "post-write bytes did not match expected data");
+
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x30, 0x00, 0x40, 0x58, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             instance = ba.readObject() as Array;
             assertTrue( instance.length == 1 && instance[0] == 99, "post-write read did not match expected result");
             //sparse array
@@ -185,9 +243,11 @@ package flexUnitTests.network
             instance[100] = '100';
             ba.length = 0;
             ba.writeObject(instance);
-            assertEquals( ba.length, 9, "post-write length was not correct");
-            assertEquals( ba.position, 9, "post-write position was not correct");
-            assertTrue( bytesMatchExpectedData(ba, [9, 1, 7, 49, 48, 48, 6, 0, 1]), "post-write bytes did not match expected data");
+
+
+            assertEquals( ba.length, 19, "post-write length was not correct");
+            assertEquals( ba.position, 19, "post-write position was not correct");
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x65, 0x00, 0x03, 0x31, 0x30, 0x30, 0x02, 0x00, 0x03, 0x31, 0x30, 0x30, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             //check that read matches
             ba.position = 0;
             instance = ba.readObject();
@@ -201,9 +261,10 @@ package flexUnitTests.network
             instance[10] = 'I am number 10';
             ba.length = 0;
             ba.writeObject(instance);
-            assertEquals( ba.length, 28, "post-write length was not correct");
-            assertEquals( ba.position, 28, "post-write position was not correct");
-            assertTrue( bytesMatchExpectedData(ba, [9, 1, 5, 49, 48, 6, 29, 73, 32, 97, 109, 32, 110, 117, 109, 98, 101, 114, 32, 49, 48, 9, 116, 101, 115, 116, 3, 1]), "post-write bytes did not match expected data");
+
+            assertEquals( ba.length, 37, "post-write length was not correct");
+            assertEquals( ba.position, 37, "post-write position was not correct");
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x31, 0x30, 0x02, 0x00, 0x0e, 0x49, 0x20, 0x61, 0x6d, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x31, 0x30, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x01, 0x01, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             
             //check that read matches
             ba.position = 0;
@@ -221,24 +282,27 @@ package flexUnitTests.network
             instance['test'] = true;
             ba.length = 0;
             ba.writeObject(instance);
-            assertEquals( ba.length, 12, "post-write length was not correct");
-            assertEquals( ba.position, 12, "post-write position was not correct");
-            
-            assertTrue( bytesMatchExpectedData(ba, [9, 1, 3, 49, 3, 9, 116, 101, 115, 116, 3, 1]), "post-write bytes did not match expected data");
+
+            assertEquals( ba.length, 21, "post-write length was not correct");
+            assertEquals( ba.position, 21, "post-write position was not correct");
+
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x31, 0x01, 0x01, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x01, 0x01, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             
             //empty array with length
             instance = new Array(100);
             assertEquals( instance.length, 100, "pre-write array length was not correct");
             ba.length = 0;
             ba.writeObject(instance);
-            assertEquals( ba.length, 3, "post-write length was not correct");
-            assertEquals( ba.position, 3, "post-write position was not correct");
-            assertTrue( bytesMatchExpectedData(ba, [9, 1, 1]), "post-write bytes did not match expected data");
+
+            assertEquals( ba.length, 8, "post-write length was not correct");
+            assertEquals( ba.position, 8, "post-write position was not correct");
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             
             ba.position = 0;
             instance = ba.readObject() as Array;
-            //although the Array had a length of 100 on write, it has length zero on read:
-            assertTrue( instance.length == 0, "post-write read did not match expected value");
+
+            //AMF0 keeps original array length here, AMF3 does not :
+            assertTrue( instance.length == 100, "post-write read did not match expected value");
             
             var ar:Array = [1, 2, 3];
             var f:Function = function ():void
@@ -248,45 +312,67 @@ package flexUnitTests.network
             ar['__AS3__.vec'] = f;
             ba.length = 0;
             ba.writeObject(ar);
-            assertEquals( ba.length, 9, "post-write length was not correct");
-            assertEquals( ba.position, 9, "post-write position was not correct");
-            assertTrue( bytesMatchExpectedData(ba, [9, 7, 1, 4, 1, 4, 2, 4, 3]), "post-write bytes did not match expected data");
+
+            assertEquals( ba.length, 44, "post-write length was not correct");
+            assertEquals( ba.position, 44, "post-write position was not correct");
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x30, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x31, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             ar = [f, 1, 2, 3, f];
             ba.length = 0;
             ba.writeObject(ar);
-            assertEquals( ba.length, 15, "post-write length was not correct");
-            assertEquals( ba.position, 15, "post-write position was not correct");
-            assertTrue( bytesMatchExpectedData(ba, [9, 1, 3, 49, 4, 1, 3, 50, 4, 2, 3, 51, 4, 3, 1]), "post-write bytes did not match expected data");
-            //post write read is an array with length of 4 instead of 5.
+
+            assertEquals( ba.length, 44, "post-write length was not correct");
+            assertEquals( ba.position, 44, "post-write position was not correct");
+
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x31, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
+
             ba.position = 0;
             ar = ba.readObject();
-            assertEquals( ar.length, 4, "post-write read length was not correct");
-            
+            //post write read is an array with length of 4 instead of 5 in amf3, but is 5 in amf0.
+            assertEquals( ar.length, 5, "post-write read length was not correct");
+
             
             ar = [Object, 1, 2, 3, Object];
             ba.length = 0;
             ba.writeObject(ar);
-            assertEquals( ba.length, 15, "post-write length was not correct");
-            assertEquals( ba.position, 15, "post-write position was not correct");
-            assertTrue( bytesMatchExpectedData(ba, [9, 11, 1, 10, 11, 1, 1, 4, 1, 4, 2, 4, 3, 10, 2]), "post-write bytes did not match expected data");
-            
-            
+
+            assertEquals( ba.length, 57, "post-write length was not correct");
+            assertEquals( ba.position, 57, "post-write position was not correct");
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x30, 0x03, 0x00, 0x00, 0x09, 0x00, 0x01, 0x31, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x34, 0x07, 0x00, 0x01, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
+
+            //it seems that the flash player always encodes as ecma array, but we should also test reading of an externally encoded 'strict' array (as per spec)
+            //strict array = AMF_STRICT_ARRAY 0x0a, count U32, count * (value-type)
+            //manual recreation of  array: [99, 'hello', false, null]
+            ba.length=0;
+            ba.writeByte(0x0a);
+            ba.writeUnsignedInt(4);
+            ba.writeObject(99);
+            ba.writeObject('hello');
+            ba.writeObject(false);
+            ba.writeObject(null);
+            ba.position = 0;
+
+            assertTrue( bytesMatchExpectedData(ba, [0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x40, 0x58, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x01, 0x00, 0x05]), "post-write bytes did not match expected data");
+            //now to read the 'strict' definition
+            ar = ba.readObject();
+            //check whether it matches the expected result
+            assertEquals( JSON.stringify(ar), '[99,"hello",false,null]', "post-write read was not correct");
+
         }
         
         
         [Test]
         public function testAnonObject():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             
             var instance:Object = {};
             ba.writeObject(instance);
-            
+
             assertEquals( ba.length, 4, "post-write length was not correct");
             assertEquals( ba.position, 4, "post-write position was not correct");
             ba.position = 0;
             
-            assertTrue( bytesMatchExpectedData(ba, [10, 11, 1, 1]), "post-write bytes did not match expected data");
+            assertTrue( bytesMatchExpectedData(ba, [0x03, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             instance = ba.readObject();
             assertTrue( dynamicKeyCountMatches(instance, 0), "post-write read did not match expected result");
             
@@ -296,15 +382,19 @@ package flexUnitTests.network
             ba.length = 0;
             ba.writeObject([obj1, obj2, obj3]);
             ba.position = 0;
-            assertTrue( bytesMatchExpectedData(ba, [9, 7, 1, 10, 11, 1, 9, 116, 101, 115, 116, 3, 1, 10, 1, 0, 6, 11, 109, 97, 121, 98, 101, 1, 10, 1, 0, 3, 1]), "post-write bytes did not match expected data");
-            
+
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x30, 0x03, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x01, 0x01, 0x00, 0x00, 0x09, 0x00, 0x01, 0x31, 0x03, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x02, 0x00, 0x05, 0x6d, 0x61, 0x79, 0x62, 0x65, 0x00, 0x00, 0x09, 0x00, 0x01, 0x32, 0x03, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x01, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
+
+            ba.writeObject([obj1, obj3, obj1]);
+            ba.position = 0;
+
         }
         
         
         [Test]
         public function testFunction():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             //functions are always encoded as undefined
             var instance:Function = function ():void
             {
@@ -315,11 +405,12 @@ package flexUnitTests.network
             assertEquals( ba.position, 1, "post-write position was not correct");
             ba.position = 0;
             
-            assertTrue( bytesMatchExpectedData(ba, [0]), "post-write bytes did not match expected data");
+            assertTrue( bytesMatchExpectedData(ba, [0x06]), "post-write bytes did not match expected data");
             instance = ba.readObject();
             
             assertTrue( instance === null, "post-write read did not match expected result");
-            
+
+
             //for a property that has a function value, the property is also undefined
             var objectWithFunction:Object = {
                 'function': function ():void
@@ -328,11 +419,11 @@ package flexUnitTests.network
             };
             ba.length = 0;
             ba.writeObject(objectWithFunction);
-            
+
             assertEquals( ba.length, 4, "post-write length was not correct");
             assertEquals( ba.position, 4, "post-write position was not correct");
             ba.position = 0;
-            assertTrue( bytesMatchExpectedData(ba, [10, 11, 1, 1]), "post-write bytes did not match expected data");
+            assertTrue( bytesMatchExpectedData(ba, [0x03, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             
             //the dynamic deserialized object has no key for the function value
             var obj:Object = ba.readObject();
@@ -345,10 +436,11 @@ package flexUnitTests.network
             };
             
             ba.writeObject(tc4);
-            assertEquals( ba.length, 15, "post-write length was not correct");
-            assertEquals( ba.position, 15, "post-write position was not correct");
+
+            assertEquals( ba.length, 17, "post-write length was not correct");
+            assertEquals( ba.position, 17, "post-write position was not correct");
             
-            assertTrue( bytesMatchExpectedData(ba, [10, 19, 1, 21, 116, 101, 115, 116, 70, 105, 101, 108, 100, 49, 0]), "post-write bytes did not match expected data");
+            assertTrue( bytesMatchExpectedData(ba, [0x03, 0x00, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x06, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             
         }
         
@@ -359,16 +451,16 @@ package flexUnitTests.network
          */
         public function testBasicClassInstance():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             
             var instance:TestClass1 = new TestClass1();
             ba.writeObject(instance);
-            
-            assertEquals( ba.length, 16, "post-write length was not correct");
-            assertEquals( ba.position, 16, "post-write position was not correct");
+
+            assertEquals( ba.length, 19, "post-write length was not correct");
+            assertEquals( ba.position, 19, "post-write position was not correct");
             
             ba.position = 0;
-            assertTrue( bytesMatchExpectedData(ba, [10, 19, 1, 21, 116, 101, 115, 116, 70, 105, 101, 108, 100, 49, 6, 1]), "post-write bytes did not match expected data");
+            assertTrue( bytesMatchExpectedData(ba, [0x03, 0x00, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x02, 0x00, 0x00, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             ba.position = 0;
             
             var anonObject:Object = ba.readObject();
@@ -378,34 +470,35 @@ package flexUnitTests.network
             var multipleDifferentInstances:Array = [new TestClass1(), new TestClass2()];
             ba.length = 0;
             ba.writeObject(multipleDifferentInstances);
-            
-            assertEquals( ba.length, 24, "post-write length was not correct");
-            assertEquals( ba.position, 24, "post-write position was not correct");
+
+            assertEquals( ba.length, 51, "post-write length was not correct");
+            assertEquals( ba.position, 51, "post-write position was not correct");
             ba.position = 0;
             
-            assertTrue( bytesMatchExpectedData(ba, [9, 5, 1, 10, 19, 1, 21, 116, 101, 115, 116, 70, 105, 101, 108, 100, 49, 6, 1, 10, 19, 1, 0, 3]), "post-write bytes did not match expected data");
+            assertTrue( bytesMatchExpectedData(ba, [0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x30, 0x03, 0x00, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x02, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x31, 0x03, 0x00, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x01, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             
         }
         
         [Test]
         public function testDynamicClassInstance():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             var instance:DynamicTestClass = new DynamicTestClass();
             ba.writeObject(instance);
-            
-            assertEquals( ba.length, 25, "post-write length was not correct");
-            assertEquals( ba.position, 25, "post-write position was not correct");
+
+            assertEquals( ba.length, 27, "post-write length was not correct");
+            assertEquals( ba.position, 27, "post-write position was not correct");
             ba.position = 0;
-            assertTrue( bytesMatchExpectedData(ba, [10, 27, 1, 39, 115, 101, 97, 108, 101, 100, 73, 110, 115, 116, 97, 110, 99, 101, 80, 114, 111, 112, 49, 2, 1]), "post-write bytes did not match expected data");
+            assertTrue( bytesMatchExpectedData(ba, [0x03, 0x00, 0x13, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x31, 0x01, 0x00, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             
             instance['someDynamicField'] = 'nonSealedPropValue';
             
             ba.writeObject(instance);
-            assertEquals( ba.length, 62, "post-write length was not correct");
-            assertEquals( ba.position, 62, "post-write position was not correct");
+
+            assertEquals( ba.length, 66, "post-write length was not correct");
+            assertEquals( ba.position, 66, "post-write position was not correct");
             ba.position = 0;
-            assertTrue( bytesMatchExpectedData(ba, [10, 27, 1, 39, 115, 101, 97, 108, 101, 100, 73, 110, 115, 116, 97, 110, 99, 101, 80, 114, 111, 112, 49, 2, 33, 115, 111, 109, 101, 68, 121, 110, 97, 109, 105, 99, 70, 105, 101, 108, 100, 6, 37, 110, 111, 110, 83, 101, 97, 108, 101, 100, 80, 114, 111, 112, 86, 97, 108, 117, 101, 1]), "post-write bytes did not match expected data");
+            assertTrue( bytesMatchExpectedData(ba, [0x03, 0x00, 0x13, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x31, 0x01, 0x00, 0x00, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x02, 0x00, 0x12, 0x6e, 0x6f, 0x6e, 0x53, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
             
             var instanceAnon:Object = ba.readObject();
             assertTrue(instanceAnon['someDynamicField'] === 'nonSealedPropValue', "post-write read did not match expected value");
@@ -413,7 +506,7 @@ package flexUnitTests.network
             
         }
         
-        [Test]
+    //    [Test]
         public function testByteArray():void
         {
             //on swf it is native ByteArray that encodes to 'ByteArray', in js it is AMFBinaryData
@@ -424,11 +517,11 @@ package flexUnitTests.network
             }
             
             COMPILE::JS{
-                var source:AMFBinaryData = new AMFBinaryData();
+                var source:AMFBinaryData = createAMFOBinaryData();
             }
             
             for (var i:uint = 0; i < 26; i++) source.writeByte(i);
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             var holder:Array = [source, source];
             
             ba.writeObject(holder);
@@ -439,10 +532,10 @@ package flexUnitTests.network
         }
         
         
-        [Test]
+    //    [Test]
         public function testExternalizable():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             var test3:TestClass3 = new TestClass3();
             //TestClass3 is externalizable and does not have an alias, this is an error in flash
             
@@ -486,16 +579,16 @@ package flexUnitTests.network
         }
         
         
-        [Test]
+    //    [Test]
         public function testDynamicPropertyWriter():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             var instance:DynamicTestClass2 = new DynamicTestClass2();
             instance['_underscore'] = 'pseudo - private value';
             instance['raining'] = 'cats and dogs';
             
             ba.writeObject(instance);
-            
+
             assertEquals( ba.length, 84, "post-write length was not correct");
             assertEquals( ba.position, 84, "post-write position was not correct");
             
@@ -523,44 +616,59 @@ package flexUnitTests.network
         [Test]
         public function testXML():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             var xml:XML =   <xml><item/></xml>;
             
             ba.writeObject(xml);
+
+            assertEquals( ba.length, 4, "post-write length was not correct");
+            assertEquals( ba.position, 4, "post-write position was not correct");
             ba.position = 0;
-            
+            assertTrue( bytesMatchExpectedData(ba, [0x03, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
+
+
             var xml2:XML = ba.readObject() as XML;
-            
-            //javascript toXMLString pretty printing does not match exactly flash...
-            assertTrue( xml.toXMLString() === xml2.toXMLString(), "XML round-tripping failed");
-        }
+
+            assertNull(xml2, 'e4X XML does not survive round-tripping via amf0');
+            //even attributes are not encoded:
+            xml = <xml test="testatt"/>;
+            ba.position = 0;
+            ba.length=0;
+            ba.writeObject(xml);
+            assertTrue( bytesMatchExpectedData(ba, [0x03, 0x00, 0x00, 0x09]), "post-write bytes did not match expected data");
 
 
-        [Test]
+            //javascript toXMLString pretty printing may not match exactly flash...
+            //assertTrue( xml.toXMLString() === xml2.toXMLString(), "XML round-tripping failed");
+
+        }
+    
+    
+    //    [Test]
         public function testWithCustomNS():void
         {
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             var test:TestClass6 = new TestClass6();
             ba.writeObject(test);
             ba.position = 0;
             assertEquals(ba.length, 50, 'unexpected serialized content with custom namespaces');
             //cover variation in order
             const validOptions:Array = [
-                '0a23010b6d79566172156d794163636573736f7206177075626c69634d79566172061f7075626c6963206163636573736f72',
-                '0a2301156d794163636573736f720b6d79566172061f7075626c6963206163636573736f7206177075626c69634d79566172'
+                    '0a23010b6d79566172156d794163636573736f7206177075626c69634d79566172061f7075626c6963206163636573736f72',
+                    '0a2301156d794163636573736f720b6d79566172061f7075626c6963206163636573736f7206177075626c69634d79566172'
             ];
-
+            
             assertTrue(validOptions.indexOf(getBytesOut(ba)) != -1, 'unexpected byte content with custom namespace content');
-
-           /* var restored:Object = ba.readObject();
-
-            var json:String = JSON.stringify(restored)*/
+            
+            var restored:Object = ba.readObject();
+            
+            var json:String = JSON.stringify(restored)
             //order may be different... need json object check here for: {"myAccessor":"public accessor","myVar":"publicMyVar"}
         }
 
-        [Test]
+   //     [Test]
         public function testTransientAndBindable():void{
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             registerClassAlias('TestClass7a', TestClass7a);
             registerClassAlias('TestClass7b', TestClass7b);
             var test1:TestClass7a = new TestClass7a();
@@ -571,6 +679,7 @@ package flexUnitTests.network
 
             var retrieved:Object = ba.readObject();
 
+
             assertTrue(retrieved is TestClass7a, 'unexpected deserialization');
 
             var test2:TestClass7b = new TestClass7b();
@@ -579,6 +688,7 @@ package flexUnitTests.network
             ba.writeObject(test2);
 
             ba.position = 0;
+
             retrieved = ba.readObject();
 
             assertTrue(retrieved is TestClass7b, 'unexpected deserialization');
@@ -586,7 +696,7 @@ package flexUnitTests.network
         }
 
 
-        [Test]
+   //     [Test]
         public function testTransientDeserialized():void{
             //if a transient field is already serialized, then we do deserialize it
             //this means it can be sent from the server (for example) but is not sent to the server
@@ -595,7 +705,7 @@ package flexUnitTests.network
             //a subsequent deserialization to a TestClass7a instance (where 'something' is Transient);
             //the expected result will be that the Transient field is still deserialized
 
-            var ba:AMFBinaryData = new AMFBinaryData();
+            var ba:AMFBinaryData = createAMFOBinaryData();
             registerClassAlias('TestClass7a', TestClass7b);
             var test1:TestClass7b = new TestClass7b();
             test1.something = 'something interesting';
@@ -620,7 +730,7 @@ package flexUnitTests.network
             assertEquals(retrieved.something , 'something interesting', 'unexpected deserialization');
             assertEquals(retrieved.test , 'test', 'unexpected deserialization');
 
-            //this time round it won't be read out because it is Transient for serialization/inbound:
+            //this time round it won't be read out because it is Transient inbound:
             ba.position = 0;
             ba.length=0;
             ba.writeObject(retrieved);
@@ -630,15 +740,15 @@ package flexUnitTests.network
             assertEquals(retrieved.something , null, 'unexpected deserialization');
             assertEquals(retrieved.test , 'test', 'unexpected deserialization');
         }
-
-
-        private function getBytesOut(bytes:AMFBinaryData):String{
+        
+        
+        private function getBytesOut(bytes:AMFBinaryData, asTestData:Boolean=false):String{
             var out:Array = [];
             for each(var byte:uint in bytes) {
-                out.push(('0'+byte.toString(16)).substr(-2));
+                if (asTestData)  out.push('0x'+('0'+byte.toString(16)).substr(-2));
+                else out.push(('0'+byte.toString(16)).substr(-2));
             }
-            return out.join('');
+            return asTestData? '['+out.join(', ') +']':out.join('');
         }
-        
     }
 }
diff --git a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as
index 1cca14c..e6e667e 100644
--- a/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as
+++ b/frameworks/projects/Network/src/test/royale/flexUnitTests/network/AMFBinaryDataTesterTest.as
@@ -34,7 +34,8 @@ package flexUnitTests.network
     
     import org.apache.royale.net.remoting.amf.AMFBinaryData;
     import org.apache.royale.reflection.*;
-    
+    import org.apache.royale.reflection.utils.*;
+
     
     public class AMFBinaryDataTesterTest
     {
@@ -52,6 +53,7 @@ package flexUnitTests.network
         [BeforeClass]
         public static function setUpBeforeClass():void
         {
+            ExtraData.addAll();
         }
         
         [AfterClass]
@@ -161,7 +163,21 @@ package flexUnitTests.network
             assertTrue( !isFinite(num), "post-write read of written Number was not correct");
             assertTrue( (num < 0), "post-write read of written Number was not correct");
         }
-        
+
+        [Test]
+        public function testNullAndUndefinedEncoding():void
+        {
+            var ba:AMFBinaryData = new AMFBinaryData();
+            ba.writeObject(null);
+            ba.writeObject(undefined);
+
+            ba.position = 0;
+            var val:* = ba.readObject();
+            assertStrictlyEquals(val, null, 'Should be null');
+            val = ba.readObject();
+            assertStrictlyEquals(val, undefined, 'Should be undefined');
+        }
+
         
         [Test]
         public function testArrayInstance():void
@@ -272,7 +288,60 @@ package flexUnitTests.network
             
             
         }
-        
+
+        [Test]
+        public function testVector():void{
+            var ba:AMFBinaryData = new AMFBinaryData();
+            var instance:Vector.<int> = new <int>[1,-1,0];
+            ba.writeObject(instance);
+
+
+            //RoyaleUnitTestRunner.consoleOut(getBytesOut(ba, true));
+
+            assertEquals( ba.length, 15, "post-write length was not correct");
+            assertEquals( ba.position, 15, "post-write position was not correct");
+            assertTrue( bytesMatchExpectedData(ba, [0x0d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00]), "post-write bytes did not match expected data");
+            ba.position = 0;
+            var obj:Object = ba.readObject();
+
+            assertTrue( obj is Vector.<int>, "post-write read did not match expected result");
+            assertTrue( obj.toString() == instance.toString(), "post-write read did not match expected result");
+
+            ba.length = 0;
+            var instBool:Vector.<Boolean> = new <Boolean>[true, false, true, false];
+            ba.writeObject(instBool);
+
+
+            assertTrue( bytesMatchExpectedData(ba, [0x10, 0x09, 0x00, 0x01, 0x03, 0x02, 0x03, 0x02]), "post-write bytes did not match expected data");
+            ba.position = 0;
+            obj = ba.readObject();
+            assertTrue( obj.toString() == instBool.toString(), "post-write read did not match expected result");
+
+
+            ba.length = 0;
+            registerClassAlias('Bool', Boolean);
+            ba.writeObject(instBool);
+           // RoyaleUnitTestRunner.consoleOut(getBytesOut(ba, true));
+
+            assertTrue( bytesMatchExpectedData(ba, [0x10, 0x09, 0x00, 0x09, 0x42, 0x6f, 0x6f, 0x6c, 0x03, 0x02, 0x03, 0x02]), "post-write bytes did not match expected data");
+
+            ba.position = 0;
+            obj = ba.readObject();
+            assertTrue( obj.toString() == instBool.toString(), "post-write read did not match expected result");
+
+
+
+            ba.length = 0;
+
+            var tc1:TestClass1 = new TestClass1();
+            var instObject:Vector.<TestClass1> = new <TestClass1>[new TestClass1(), new TestClass1(), tc1, tc1, null, tc1];
+
+            ba.writeObject(instObject);
+
+            assertTrue( bytesMatchExpectedData(ba, [0x10, 0x0d, 0x00, 0x01, 0x0a, 0x13, 0x01, 0x15, 0x74, 0x65, 0x73, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x06, 0x01, 0x0a, 0x01, 0x06, 0x01, 0x0a, 0x01, 0x06, 0x01, 0x0a, 0x06, 0x01, 0x0a, 0x06]), "post-write bytes did not match expected data");
+
+        }
+
         
         [Test]
         public function testAnonObject():void
@@ -632,12 +701,13 @@ package flexUnitTests.network
         }
 
 
-        private function getBytesOut(bytes:AMFBinaryData):String{
+        private function getBytesOut(bytes:AMFBinaryData, asTestData:Boolean=false):String{
             var out:Array = [];
             for each(var byte:uint in bytes) {
-                out.push(('0'+byte.toString(16)).substr(-2));
+                if (asTestData)  out.push('0x'+('0'+byte.toString(16)).substr(-2));
+                else out.push(('0'+byte.toString(16)).substr(-2));
             }
-            return out.join('');
+            return asTestData? '['+out.join(', ') +']':out.join('');
         }
         
     }


[royale-asjs] 01/03: Added missing checks for ExtraData in reflection 'aliasing' support

Posted by gr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit d610a9b8625c21ffd681055308b59bdc73053418
Author: greg-dove <gr...@gmail.com>
AuthorDate: Wed Oct 7 21:17:01 2020 +1300

    Added missing checks for ExtraData in reflection 'aliasing' support
---
 .../main/royale/org/apache/royale/reflection/TypeDefinition.as    | 8 +++++++-
 .../main/royale/org/apache/royale/reflection/getAliasByClass.as   | 3 +++
 .../main/royale/org/apache/royale/reflection/getClassByAlias.as   | 2 +-
 .../royale/org/apache/royale/reflection/registerClassAlias.as     | 2 +-
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/TypeDefinition.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/TypeDefinition.as
index e124e1a..7ed7890 100755
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/TypeDefinition.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/TypeDefinition.as
@@ -47,6 +47,9 @@ COMPILE::SWF {
             COMPILE::JS
             internal static function registerClassAlias(aliasName:String, classObject:Class ) :void{
                 var info:* = classObject.prototype.ROYALE_CLASS_INFO;
+                if (!info && ExtraData.hasData(classObject)) {
+                    info = ExtraData.getData(classObject)['ROYALE_CLASS_INFO'];
+                }
                 if (info) {
                     //a class may have more than one alias point to it, but only the most recently registered
                     //alias is retained for reflection (applying same approach as swf)
@@ -61,7 +64,10 @@ COMPILE::SWF {
                     var altClass:Class = _aliasMappings[aliasName];
                     if (altClass) {
                         var altInfo:* = altClass.prototype.ROYALE_CLASS_INFO;
-                        delete altInfo.alias;
+                        if (!altInfo) altInfo = ExtraData.getData(altClass)['ROYALE_CLASS_INFO'];
+                        if (altInfo){
+                            delete altInfo.alias;
+                        }
                     }
                     _aliasMappings[aliasName] = classObject;
                     info.alias = aliasName;
diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getAliasByClass.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getAliasByClass.as
index 79091d6..edb9883 100644
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getAliasByClass.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getAliasByClass.as
@@ -39,6 +39,9 @@ COMPILE::SWF {
 
         COMPILE::JS {
             var info:* = classObject.prototype.ROYALE_CLASS_INFO;
+            if (!info && ExtraData.hasData(classObject)) {
+                info = ExtraData.getData(classObject)['ROYALE_CLASS_INFO'];
+            }
             if (info) {
                 ret = info.alias;
                 if (ret == '') ret = null;
diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getClassByAlias.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getClassByAlias.as
index c430afd..5e0734c 100644
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getClassByAlias.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getClassByAlias.as
@@ -40,7 +40,7 @@ COMPILE::SWF {
             {
                 var klazz:Class = TypeDefinition.getClassByAlias(aliasName);
             }
-            catch (e)
+            catch (e:Error)
             {
                 throw new ReferenceError("Class "+aliasName+" could not be found.");
             }
diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/registerClassAlias.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/registerClassAlias.as
index 0bc565d..c8a0823 100644
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/registerClassAlias.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/registerClassAlias.as
@@ -37,7 +37,7 @@ COMPILE::SWF {
         COMPILE::JS {
             if (classObject == null) throw new TypeError("Parameter classObject must be non-null.");
             if (aliasName == null) throw new TypeError("Parameter aliasName must be non-null.");
-            if (aliasName.length==0) throw new TypeError("Parameter aliasName must be non-empty string.");
+            if (aliasName.length == 0) throw new TypeError("Parameter aliasName must be non-empty string.");
             TypeDefinition.registerClassAlias(aliasName , classObject);
         }
     }