Пример #1
0
        public void Constructor(string className, ASClassLayout classLayout, string[] memberNames)
        {
            ASClass @class = new ASClass(className, classLayout, memberNames);

            Assert.AreSame(className, @class.ClassAlias);
            Assert.AreEqual(classLayout, @class.Layout);
            Assert.AreSame(memberNames, @class.MemberNames);
        }
Пример #2
0
        public void Constructor(string className, ASClassLayout classLayout, string[] memberNames)
        {
            ASClass @class = new ASClass(className, classLayout, memberNames);

            Assert.AreSame(className, @class.ClassAlias);
            Assert.AreEqual(classLayout, @class.Layout);
            Assert.AreSame(memberNames, @class.MemberNames);
        }
Пример #3
0
        private static void AddPropertyMappingIfNeeded(MemberInfo propertyOrField,
                                                       IList <ActionScriptPropertyMapping> propertyMappings,
                                                       IList <string> memberNames,
                                                       ref ASClassLayout classLayout)
        {
            // Handle ignored properties and fields.
            if (HasActionScriptIgnoreAttribute(propertyOrField))
            {
                return;
            }

            ActionScriptPropertyAttribute propertyAttribute = GetActionScriptPropertyAttribute(propertyOrField);

            // Sanity check for externalizable classes.  They shouldn't have decorated properties or fields.
            if (classLayout == ASClassLayout.Externalizable)
            {
                if (propertyAttribute != null)
                {
                    throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                                                                  "Type '{0}' implements IExternalizable but property or field '{1}' has been decorated with ActionScriptPropertyAttribute which is not supported by the externalizable serialization protocol.",
                                                                  propertyOrField.DeclaringType.FullName,
                                                                  propertyOrField.Name));
                }

                return;
            }

            // Generate the property mapping.
            string propertyName;
            bool   isDynamic;

            if (propertyAttribute != null)
            {
                propertyName = propertyAttribute.PropertyName;
                if (propertyName == null)
                {
                    propertyName = propertyOrField.Name;
                }

                isDynamic = propertyAttribute.IsDynamic;
            }
            else
            {
                propertyName = propertyOrField.Name;
                isDynamic    = false;
            }

            if (!isDynamic)
            {
                memberNames.Add(propertyName);
            }

            propertyMappings.Add(new ActionScriptPropertyMapping(propertyOrField, propertyName, isDynamic));
        }
Пример #4
0
        public void ConstructorWithClassAndMemberValues(ASClassLayout classLayout, string[] memberNames, int[] memberValues)
        {
            IASValue[] asMemberValues = WrapInts(memberValues);

            ASClass  @class = new ASClass("class", classLayout, memberNames);
            ASObject obj    = new ASObject(@class, asMemberValues);

            Assert.AreSame(@class, obj.Class);
            Assert.AreSame(asMemberValues, obj.MemberValues);
            Assert.AreEqual(0, obj.DynamicProperties.Count);

            Assert.AreEqual(classLayout == ASClassLayout.Normal, obj.DynamicProperties.IsReadOnly);
        }
Пример #5
0
        public void ConstructorWithClassAndMemberValuesAndDynamicValues(ASClassLayout classLayout,
                                                                        string[] memberNames, int[] memberValues)
        {
            IASValue[] asMemberValues = WrapInts(memberValues);

            IDictionary <string, IASValue> dynamicProperties = new Dictionary <string, IASValue>();
            ASClass  @class = new ASClass("class", classLayout, memberNames);
            ASObject obj    = new ASObject(@class, asMemberValues, dynamicProperties);

            Assert.AreSame(@class, obj.Class);
            Assert.AreSame(asMemberValues, obj.MemberValues);
            Assert.AreSame(dynamicProperties, obj.DynamicProperties);
        }
Пример #6
0
        public void ConstructorWithClassAndMemberValues(ASClassLayout classLayout, string[] memberNames, int[] memberValues)
        {
            IASValue[] asMemberValues = WrapInts(memberValues);

            ASClass @class = new ASClass("class", classLayout, memberNames);
            ASObject obj = new ASObject(@class, asMemberValues);

            Assert.AreSame(@class, obj.Class);
            Assert.AreSame(asMemberValues, obj.MemberValues);
            Assert.AreEqual(0, obj.DynamicProperties.Count);

            Assert.AreEqual(classLayout == ASClassLayout.Normal, obj.DynamicProperties.IsReadOnly);
        }
Пример #7
0
        public void ConstructorWithClass(ASClassLayout classLayout, string[] memberNames)
        {
            ASClass @class = new ASClass("class", classLayout, memberNames);
            ASObject obj = new ASObject(@class);

            Assert.AreSame(@class, obj.Class);
            Assert.AreEqual(memberNames.Length, obj.MemberValues.Count);
            Assert.AreEqual(0, obj.DynamicProperties.Count);

            Assert.AreEqual(classLayout == ASClassLayout.Normal, obj.DynamicProperties.IsReadOnly);
            if (memberNames.Length == 0)
                Assert.IsTrue(obj.MemberValues.IsReadOnly);
        }
Пример #8
0
        public void ConstructorWithClass(ASClassLayout classLayout, string[] memberNames)
        {
            ASClass  @class = new ASClass("class", classLayout, memberNames);
            ASObject obj    = new ASObject(@class);

            Assert.AreSame(@class, obj.Class);
            Assert.AreEqual(memberNames.Length, obj.MemberValues.Count);
            Assert.AreEqual(0, obj.DynamicProperties.Count);

            Assert.AreEqual(classLayout == ASClassLayout.Normal, obj.DynamicProperties.IsReadOnly);
            if (memberNames.Length == 0)
            {
                Assert.IsTrue(obj.MemberValues.IsReadOnly);
            }
        }
Пример #9
0
        /// <summary>
        /// Creates a class with the specified alias name, layout and members.
        /// </summary>
        /// <param name="classAlias">The class alias, or an empty string if none</param>
        /// <param name="layout">The class layout</param>
        /// <param name="memberNames">The member names</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="classAlias"/>
        /// or <paramref name="memberNames"/> is null</exception>
        /// <exception cref="ArgumentException">Thrown if <paramref name="memberNames"/> is
        /// non-empty and <paramref name="layout"/> is <see cref="ASClassLayout.Externalizable" /></exception>
        /// <exception cref="ArgumentException">Thrown if <paramref name="classAlias"/>
        /// is empty but <paramref name="layout"/> is <see cref="ASClassLayout.Externalizable" /></exception>
        public ASClass(string classAlias, ASClassLayout layout, IList<string> memberNames)
        {
            if (classAlias == null)
                throw new ArgumentNullException("classAlias");
            if (memberNames == null)
                throw new ArgumentNullException("memberNames");
            if (layout == ASClassLayout.Externalizable && memberNames.Count != 0)
                throw new ArgumentException("An externalizable class cannot have any members.", "memberNames");
            if (layout == ASClassLayout.Externalizable && classAlias.Length == 0)
                throw new ArgumentException("An externalizable class must have a non-empty class name.", "className");

            this.classAlias = classAlias;
            this.layout = layout;
            this.memberNames = memberNames;
        }
Пример #10
0
        /// <summary>
        /// Gets a shared and read-only class definition with the specified properties.
        /// The class is cached for reuse in subsequent requests.
        /// </summary>
        /// <remarks>
        /// This method is safe for concurrent access.
        /// </remarks>
        /// <param name="classAlias">The class alias</param>
        /// <param name="classLayout">The class layout</param>
        /// <param name="memberNames">The class members</param>
        /// <returns>The shared class definition</returns>
        public static ASClass GetClass(string classAlias, ASClassLayout classLayout, IList<string> memberNames)
        {
            lock (cache)
            {
                // Yes we create a new class instance in order to search the cache.
                // However, if we do find a match we will not return it to the caller so it
                // will get promptly garbage collected.
                ASClass key = new ASClass(classAlias, classLayout, memberNames);
                ASClass @class;
                if (cache.TryGetValue(key, out @class))
                    return @class;

                cache.Add(key, key);
                return key;
            }
        }
Пример #11
0
        /// <summary>
        /// Gets a shared and read-only class definition with the specified properties.
        /// The class is cached for reuse in subsequent requests.
        /// </summary>
        /// <remarks>
        /// This method is safe for concurrent access.
        /// </remarks>
        /// <param name="classAlias">The class alias</param>
        /// <param name="classLayout">The class layout</param>
        /// <param name="memberNames">The class members</param>
        /// <returns>The shared class definition</returns>
        public static ASClass GetClass(string classAlias, ASClassLayout classLayout, IList <string> memberNames)
        {
            lock (cache)
            {
                // Yes we create a new class instance in order to search the cache.
                // However, if we do find a match we will not return it to the caller so it
                // will get promptly garbage collected.
                ASClass key = new ASClass(classAlias, classLayout, memberNames);
                ASClass @class;
                if (cache.TryGetValue(key, out @class))
                {
                    return(@class);
                }

                cache.Add(key, key);
                return(key);
            }
        }
Пример #12
0
        public void WriteObject_Objects(AMFObjectEncoding objectEncoding, byte[] expected,
                                        string className, ASClassLayout classLayout,
                                        string[] memberNames, string[] memberValues, string[] dynamicKeysAndValues)
        {
            ASClass  @class = new ASClass(className, classLayout, memberNames);
            ASObject obj    = new ASObject(@class, WrapStrings(memberValues), new Dictionary <string, IASValue>());

            for (int i = 0; i < dynamicKeysAndValues.Length; i += 2)
            {
                obj.DynamicProperties[dynamicKeysAndValues[i]] = new ASString(dynamicKeysAndValues[i + 1]);
            }

            output.ObjectEncoding = objectEncoding;
            output.BeginObjectStream();
            output.WriteObject(obj);
            output.EndObjectStream();

            CollectionAssert.AreElementsEqual(expected, stream.ToArray());
        }
Пример #13
0
        /// <summary>
        /// Creates a class with the specified alias name, layout and members.
        /// </summary>
        /// <param name="classAlias">The class alias, or an empty string if none</param>
        /// <param name="layout">The class layout</param>
        /// <param name="memberNames">The member names</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="classAlias"/>
        /// or <paramref name="memberNames"/> is null</exception>
        /// <exception cref="ArgumentException">Thrown if <paramref name="memberNames"/> is
        /// non-empty and <paramref name="layout"/> is <see cref="ASClassLayout.Externalizable" /></exception>
        /// <exception cref="ArgumentException">Thrown if <paramref name="classAlias"/>
        /// is empty but <paramref name="layout"/> is <see cref="ASClassLayout.Externalizable" /></exception>
        public ASClass(string classAlias, ASClassLayout layout, IList <string> memberNames)
        {
            if (classAlias == null)
            {
                throw new ArgumentNullException("classAlias");
            }
            if (memberNames == null)
            {
                throw new ArgumentNullException("memberNames");
            }
            if (layout == ASClassLayout.Externalizable && memberNames.Count != 0)
            {
                throw new ArgumentException("An externalizable class cannot have any members.", "memberNames");
            }
            if (layout == ASClassLayout.Externalizable && classAlias.Length == 0)
            {
                throw new ArgumentException("An externalizable class must have a non-empty class name.", "className");
            }

            this.classAlias  = classAlias;
            this.layout      = layout;
            this.memberNames = memberNames;
        }
Пример #14
0
        public void ReadObject_Objects(AMFObjectEncoding objectEncoding, byte[] bytes,
                                       string className, ASClassLayout classLayout,
                                       string[] memberNames, string[] memberValues, string[] dynamicKeysAndValues)
        {
            SetStreamContents(bytes);

            input.BeginObjectStream();
            ASObject result = (ASObject)input.ReadObject();

            Assert.AreEqual(objectEncoding, input.ObjectEncoding);
            input.EndObjectStream();

            Assert.AreEqual(classLayout, result.Class.Layout);
            Assert.AreEqual(className, result.Class.ClassAlias);
            CollectionAssert.AreElementsEqual(memberNames, result.Class.MemberNames);

            CollectionAssert.AreElementsEqual(WrapStrings(memberValues), result.MemberValues);

            Assert.AreEqual(dynamicKeysAndValues.Length / 2, result.DynamicProperties.Count);
            for (int i = 0; i < dynamicKeysAndValues.Length; i += 2)
            {
                Assert.AreEqual(new ASString(dynamicKeysAndValues[i + 1]), result.DynamicProperties[dynamicKeysAndValues[i]]);
            }
        }
        private static void AddPropertyMappingIfNeeded(MemberInfo propertyOrField,
            IList<ActionScriptPropertyMapping> propertyMappings,
            IList<string> memberNames,
            ref ASClassLayout classLayout)
        {
            // Handle ignored properties and fields.
            if (HasActionScriptIgnoreAttribute(propertyOrField))
                return;

            ActionScriptPropertyAttribute propertyAttribute = GetActionScriptPropertyAttribute(propertyOrField);

            // Sanity check for externalizable classes.  They shouldn't have decorated properties or fields.
            if (classLayout == ASClassLayout.Externalizable)
            {
                if (propertyAttribute != null)
                    throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                        "Type '{0}' implements IExternalizable but property or field '{1}' has been decorated with ActionScriptPropertyAttribute which is not supported by the externalizable serialization protocol.",
                        propertyOrField.DeclaringType.FullName,
                        propertyOrField.Name));

                return;
            }

            // Generate the property mapping.
            string propertyName;
            bool isDynamic;

            if (propertyAttribute != null)
            {
                propertyName = propertyAttribute.PropertyName;
                if (propertyName == null)
                    propertyName = propertyOrField.Name;

                isDynamic = propertyAttribute.IsDynamic;
            }
            else
            {
                propertyName = propertyOrField.Name;
                isDynamic = false;
            }

            if (!isDynamic)
                memberNames.Add(propertyName);

            propertyMappings.Add(new ActionScriptPropertyMapping(propertyOrField, propertyName, isDynamic));
        }
Пример #16
0
        public void ReadObject_Objects(AMFObjectEncoding objectEncoding, byte[] bytes,
            string className, ASClassLayout classLayout,
            string[] memberNames, string[] memberValues, string[] dynamicKeysAndValues)
        {
            SetStreamContents(bytes);

            input.BeginObjectStream();
            ASObject result = (ASObject)input.ReadObject();
            Assert.AreEqual(objectEncoding, input.ObjectEncoding);
            input.EndObjectStream();

            Assert.AreEqual(classLayout, result.Class.Layout);
            Assert.AreEqual(className, result.Class.ClassAlias);
            CollectionAssert.AreElementsEqual(memberNames, result.Class.MemberNames);

            CollectionAssert.AreElementsEqual(WrapStrings(memberValues), result.MemberValues);

            Assert.AreEqual(dynamicKeysAndValues.Length / 2, result.DynamicProperties.Count);
            for (int i = 0; i < dynamicKeysAndValues.Length; i += 2)
                Assert.AreEqual(new ASString(dynamicKeysAndValues[i + 1]), result.DynamicProperties[dynamicKeysAndValues[i]]);
        }
Пример #17
0
        private static ActionScriptClassMapping InternalCreateDefaultClassMapping(Type nativeType, string classAliasOverride,
                                                                                  ActionScriptClassAttribute classAttribute)
        {
            // Determine the class alias.
            string classAlias;

            if (classAliasOverride != null)
            {
                classAlias = classAliasOverride;
            }
            else if (classAttribute != null)
            {
                classAlias = classAttribute.ClassAlias;
            }
            else
            {
                classAlias = "";
            }

            // Determine the class layout.
            ASClassLayout classLayout = ASClassLayout.Normal;

            if (typeof(IDynamic).IsAssignableFrom(nativeType))
            {
                classLayout = ASClassLayout.Dynamic;
            }

            if (typeof(IExternalizable).IsAssignableFrom(nativeType))
            {
                if (classAlias.Length == 0)
                {
                    throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                                                                  "Type '{0}' implements IExternalizable but does not have a non-empty class alias name which is required by the externalizable serialization protocol.",
                                                                  nativeType.FullName));
                }

                if (classLayout == ASClassLayout.Dynamic)
                {
                    throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture,
                                                                  "Type '{0}' implements IExternalizable as well as IDynamic which is not supported by the externalizable serialization protocol.",
                                                                  nativeType.FullName));
                }

                classLayout = ASClassLayout.Externalizable;
            }

            // Populate the list of property mappings.
            List <ActionScriptPropertyMapping> propertyMappings = new List <ActionScriptPropertyMapping>();
            List <string> memberNames = new List <string>();

            foreach (PropertyInfo property in nativeType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                AddPropertyMappingIfNeeded(property, propertyMappings, memberNames, ref classLayout);
            }

            foreach (FieldInfo field in nativeType.GetFields(BindingFlags.Instance | BindingFlags.Public))
            {
                AddPropertyMappingIfNeeded(field, propertyMappings, memberNames, ref classLayout);
            }

            // Finish up.
            // Convert the lists to arrays to reduce the memory footprint.
            string[] memberNamesArray = memberNames.Count == 0 ? EmptyArray <string> .Instance : memberNames.ToArray();
            ActionScriptPropertyMapping[] propertyMappingsArray = propertyMappings.Count == 0 ?
                                                                  EmptyArray <ActionScriptPropertyMapping> .Instance : propertyMappings.ToArray();

            ASClass classDefinition = ASClassCache.GetClass(classAlias, classLayout, memberNamesArray);
            ActionScriptClassMapping classMapping = new ActionScriptClassMapping(nativeType, classDefinition, propertyMappingsArray);

            return(classMapping);
        }
Пример #18
0
        public void ConstructorWithClassAndMemberValuesAndDynamicValues(ASClassLayout classLayout,
            string[] memberNames, int[] memberValues)
        {
            IASValue[] asMemberValues = WrapInts(memberValues);

            IDictionary<string, IASValue> dynamicProperties = new Dictionary<string, IASValue>();
            ASClass @class = new ASClass("class", classLayout, memberNames);
            ASObject obj = new ASObject(@class, asMemberValues, dynamicProperties);

            Assert.AreSame(@class, obj.Class);
            Assert.AreSame(asMemberValues, obj.MemberValues);
            Assert.AreSame(dynamicProperties, obj.DynamicProperties);
        }
Пример #19
0
        public void WriteObject_Objects(AMFObjectEncoding objectEncoding, byte[] expected,
            string className, ASClassLayout classLayout,
            string[] memberNames, string[] memberValues, string[] dynamicKeysAndValues)
        {
            ASClass @class = new ASClass(className, classLayout, memberNames);
            ASObject obj = new ASObject(@class, WrapStrings(memberValues), new Dictionary<string, IASValue>());

            for (int i = 0; i < dynamicKeysAndValues.Length; i += 2)
                obj.DynamicProperties[dynamicKeysAndValues[i]] = new ASString(dynamicKeysAndValues[i + 1]);

            output.ObjectEncoding = objectEncoding;
            output.BeginObjectStream();
            output.WriteObject(obj);
            output.EndObjectStream();

            CollectionAssert.AreElementsEqual(expected, stream.ToArray());
        }
Пример #20
0
        private IASValue ReadObjectValue()
        {
            int bits = input.ReadVWInt29();

            // Handle cached objects.
            if ((bits & 1) == 0)
            {
                int referenceId = bits >> 1;
                return(GetObjectFromCache(AMF3ObjectTypeCode.Object, referenceId));
            }

            // Handle cached class definitions.
            ASClass classDefinition;

            if ((bits & 2) == 0)
            {
                int referenceId = bits >> 2;

                // Note: Object might be an ASExternalizableObject.
                IASValue obj = GetObjectFromCache(AMF3ObjectTypeCode.Object, referenceId);
                classDefinition = obj.Class;
            }
            else
            {
                // Read the class definition.
                ASClassLayout classLayout = (ASClassLayout)((bits & 0x0c) >> 2);
                if (classLayout > ASClassLayout.Dynamic)
                {
                    throw new AMFException(String.Format(CultureInfo.CurrentCulture,
                                                         ExceptionPrefix + "Encountered Object token with invalid class layout '{0}'.", classLayout));
                }

                int memberCount = bits >> 4;
                if (memberCount < 0)
                {
                    throw new AMFException(String.Format(CultureInfo.CurrentCulture,
                                                         ExceptionPrefix + "Encountered Object token with invalid member count '{0}'.", memberCount));
                }

                if (classLayout == ASClassLayout.Externalizable && memberCount != 0)
                {
                    throw new AMFException(String.Format(CultureInfo.CurrentCulture,
                                                         ExceptionPrefix + "Encountered Object token with Externalizable class layout and non-zero member count '{0}'.", memberCount));
                }

                string classAlias = ReadStringData();

                string[] memberNames;
                if (memberCount != 0)
                {
                    memberNames = new string[memberCount];

                    for (int i = 0; i < memberCount; i++)
                    {
                        memberNames[i] = ReadStringData();
                    }
                }
                else
                {
                    memberNames = EmptyArray <string> .Instance;
                }

                // Look up the class in the cache.
                classDefinition = ASClassCache.GetClass(classAlias, classLayout, memberNames);
            }

            // Read the instance data.
            if (classDefinition.Layout == ASClassLayout.Externalizable)
            {
                // Important: Add the object to the cache before deserializing its properties!
                ASExternalizableObject result = ASExternalizableObject.CreateUninitializedInstance(classDefinition);
                AddObjectToCache(AMF3ObjectTypeCode.Object, result);

                // Use custom serialization for the externalizable object.
                IExternalizable externalizableValue = input.Serializer.CreateExternalizableInstance(classDefinition.ClassAlias);
                externalizableValue.ReadExternal(input);

                result.SetProperties(externalizableValue);
                return(result);
            }
            else
            {
                // Important: Add the object to the cache before deserializing its properties!
                ASObject result = ASObject.CreateUninitializedInstance(classDefinition);
                AddObjectToCache(AMF3ObjectTypeCode.Object, result);

                // Read the member values.
                int        memberCount = classDefinition.MemberNames.Count;
                IASValue[] memberValues;

                if (memberCount != 0)
                {
                    memberValues = new IASValue[memberCount];

                    for (int i = 0; i < memberCount; i++)
                    {
                        memberValues[i] = ReadObject();
                    }
                }
                else
                {
                    memberValues = EmptyArray <IASValue> .Instance;
                }

                // Read the dynamic property values.
                IDictionary <string, IASValue> dynamicProperties;

                if (classDefinition.Layout == ASClassLayout.Dynamic)
                {
                    string key = ReadStringData();
                    if (key.Length != 0)
                    {
                        dynamicProperties = new Dictionary <string, IASValue>();

                        for (; ;)
                        {
                            IASValue value = ReadObject();
                            dynamicProperties.Add(key, value);

                            key = ReadStringData();
                            if (key.Length == 0)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        dynamicProperties = EmptyDictionary <string, IASValue> .Instance;
                    }
                }
                else
                {
                    dynamicProperties = EmptyDictionary <string, IASValue> .Instance;
                }

                result.SetProperties(memberValues, dynamicProperties);
                return(result);
            }
        }