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); }
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)); }
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); }
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); }
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); }
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); } }
/// <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; }
/// <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; } }
/// <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); } }
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()); }
/// <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; }
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)); }
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 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); }
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); }
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()); }
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); } }