Example #1
0
        /// <summary>
        /// Read an object.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="reader">
        /// The reader.
        /// </param>
        /// <param name="output">
        /// The output.
        /// </param>
        private void ReadObject(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            int reference = reader.PeekChar();
            int index;

            if ((reference & 0x1) == 0 && ReadReference(context, reader, out index, out reference))
            {
                if (output != null)
                {
                    WriteReference(index, output);
                }

                return;
            }

            context.References.Track();

            int           traitsindex, traitsreference;
            AmfTypeTraits traits;

            if ((traits = ReadTraitsReference(context, reader, out traitsindex, out traitsreference)) == null)
            {
                bool   isExternalizable = (traitsreference & 0x4) == 4;
                bool   isDynamic        = (traitsreference & 0x8) == 8;
                string typeName         = ReadString(context, reader);
                int    count            = traitsreference >> 4;
                var    classMembers     = new string[count];

                for (int i = 0; i < count; i++)
                {
                    classMembers[i] = ReadString(context, reader);
                }

                traits = new AmfTypeTraits
                {
                    IsDynamic        = isDynamic,
                    IsExternalizable = isExternalizable,
                    TypeName         = typeName,

                    // No property names are included for types
                    // that are externizable or dynamic
                    ClassMembers = isDynamic || isExternalizable ? new string[0] : classMembers
                };

                context.TraitsReferences.Add(traits);
            }

#if DEBUG
            Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadObject_Debug_Name, traits.TypeName));

            if (traits.IsDynamic)
            {
                Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_Dynamic);
            }
            else if (traits.IsExternalizable)
            {
                Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_Externizable);
            }
            else
            {
                Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_Members, traits.ClassMembers.Length);
            }
#endif

            using (var ms = new MemoryStream())
            {
                var members = new List <string>();

                var buffer = new XmlTextWriter(ms, Encoding.UTF8);
                buffer.WriteStartElement("buffer");
                buffer.WriteAttributeString("xmlns", AmfxContent.Namespace);

#if DEBUG
                int memberPosition = 0;
#endif

                // Read object's properties
                foreach (string classMember in traits.ClassMembers)
                {
#if DEBUG
                    Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_ReadingField, memberPosition, classMember);
                    memberPosition++;
#endif

                    this.ReadAmfValue(context, reader, buffer);
                    members.Add(classMember);
                }

                // Read dynamic properties too
                if (traits.IsDynamic)
                {
#if DEBUG
                    Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_ReadingDynamic);
#endif

                    string key = ReadString(context, reader);

                    while (key != string.Empty)
                    {
#if DEBUG
                        Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadObject_Debug_ReadingDynamicField, key));
#endif

                        this.ReadAmfValue(context, reader, buffer);
                        members.Add(key);

                        key = ReadString(context, reader);
                    }

#if DEBUG
                    Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_DynamicEnd);
#endif
                }

                buffer.WriteEndElement();
                buffer.Flush();



#if DEBUG
                Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_End);
#endif

                #region Writing member values

                if (output != null)
                {
                    output.WriteStartElement(AmfxContent.Object);

                    if (traits.TypeName != AmfTypeTraits.BaseTypeAlias)
                    {
                        output.WriteAttributeString(AmfxContent.ObjectType, traits.TypeName);
                    }

                    output.WriteStartElement(AmfxContent.Traits);

                    // Regular traits object
                    // Always write traits for dynamic objects
                    if (traitsindex == -1 || traits.IsDynamic)
                    {
                        if (traits.IsExternalizable)
                        {
                            output.WriteAttributeString(AmfxContent.TraitsExternizable, AmfxContent.True);
                        }
                        else
                        {
                            // Write object members
                            foreach (string classMember in members)
                            {
                                output.WriteStartElement(AmfxContent.String);
                                output.WriteValue(classMember);
                                output.WriteEndElement();
                            }
                        }
                    }

                    // Traits object reference
                    else
                    {
                        output.WriteAttributeString(AmfxContent.TraitsId, traitsindex.ToString());
                    }

                    output.WriteEndElement(); // End of traits

                    // Write object members
                    if (members.Count > 0)
                    {
                        ms.Position = 0;
                        var bufferreader = new XmlTextReader(ms);
                        bufferreader.Read();
                        bufferreader.ReadStartElement();

                        while (bufferreader.Depth >= 1)
                        {
                            output.WriteNode(bufferreader, false);
                        }
                    }

                    output.WriteEndElement(); // End of object
                }

                #endregion
            }
        }
Example #2
0
        /// <summary>
        /// Write an object.
        /// </summary>
        private void WriteObject(AmfContext context, AmfStreamWriter writer, XmlReader input)
        {
            context.References.Add(new AmfReference { AmfxType = AmfxContent.Object });
            WriteTypeMarker(writer, Amf3TypeMarker.Object);

            AmfTypeTraits traits;
            var typeName = string.Empty;

            if (input.HasAttributes)
                typeName = input.GetAttribute(AmfxContent.ObjectType);

            #region Write traits
            input.Read();

            //Send traits by value
            if (!input.IsEmptyElement)
            {
                traits = new AmfTypeTraits { TypeName = typeName };
                context.TraitsReferences.Add(traits);

                var traitsReader = input.ReadSubtree();
                traitsReader.MoveToContent();
                traitsReader.ReadStartElement();

                var members = new List<string>();

                while (input.NodeType != XmlNodeType.EndElement)
                    members.Add(traitsReader.ReadElementContentAsString());

                traits.ClassMembers = members.ToArray();

                //The first bit is a flag with value 1.
                //The second bit is a flag with value 1.
                //The third bit is a flag with value 0.
                var flag = 0x3; //00000011

                if (traits.IsExternalizable) flag |= 0x4; //00000111

                //The fourth bit is a flag specifying whether the type is dynamic.
                //A value of 0 implies not dynamic, a value of 1 implies dynamic.
                if (traits.IsDynamic) flag |= 0x8; //00001011

                //The remaining 1 to 25 significant bits are used to encode the number
                //of sealed traits member names that follow after the class name.
                var count = traits.ClassMembers.Count();
                flag |= count << 4;

                WriteUInt29(writer, flag);

                WriteUtf8(context, writer, traits.TypeName);

                //Write member names
                foreach (var member in traits.ClassMembers)
                    WriteUtf8(context, writer, member);
            }
            //Send traits by reference
            else
            {
                var index = Convert.ToInt32(input.GetAttribute(AmfxContent.TraitsId), CultureInfo.InvariantCulture);
                traits = context.TraitsReferences[index];

                var flag = index & UInt29Mask; //Truncate value to UInt29

                //The first bit is a flag with value 1.
                //The second bit is a flag (representing whether a trait
                //reference follows) with value 0 to imply that this objects
                //traits are being sent by reference. The remaining 1 to 27
                //significant bits are used to encode a trait reference index.
                flag = (flag << 2) | 0x1;
                WriteUInt29(writer, flag);
            }

            input.Read();
            #endregion

            #region Write members
            for (var i = 0; i < traits.ClassMembers.Length; i++)
            {
                WriteAmfValue(context, input, writer);
                input.Read();
            }
            #endregion
        }
Example #3
0
        /// <summary>
        /// Write an object.
        /// </summary>
        private void WriteObject(AmfContext context, AmfStreamWriter writer, XmlReader input)
        {
            context.References.Add(new AmfReference {
                AmfxType = AmfxContent.Object
            });

            WriteTypeMarker(writer, Amf0TypeMarker.Object);

            var typeName = string.Empty;

            if (input.HasAttributes)
            {
                typeName = input.GetAttribute(AmfxContent.ObjectType);
            }

            #region Read traits
            var traits = new AmfTypeTraits {
                TypeName = typeName
            };

            while (input.Read())
            {
                if (input.NodeType != XmlNodeType.Element && input.Name != AmfxContent.Traits)
                {
                    continue;
                }

                if (!input.IsEmptyElement)
                {
                    var traitsReader = input.ReadSubtree();
                    traitsReader.MoveToContent();
                    traitsReader.ReadStartElement();

                    var members = new List <string>();

                    while (input.NodeType != XmlNodeType.EndElement)
                    {
                        members.Add(traitsReader.ReadElementContentAsString());
                    }

                    traits.ClassMembers = members.ToArray();
                }

                break;
            }
            #endregion

            #region Type name
            //Untyped object
            if (string.IsNullOrEmpty(traits.TypeName))
            {
                WriteTypeMarker(writer, Amf0TypeMarker.Object);
            }
            //Strongly-typed object
            else
            {
                WriteTypeMarker(writer, Amf0TypeMarker.TypedObject);
                var typeNameData = Encoding.UTF8.GetBytes(traits.TypeName);
                writer.Write((ushort)typeNameData.Length);
                writer.Write(typeNameData);
            }
            #endregion

            #region Write members
            var i = 0;

            while (input.Read())
            {
                if (input.NodeType != XmlNodeType.Element)
                {
                    continue;
                }

                var memberName   = traits.ClassMembers[i];
                var memberReader = input.ReadSubtree();
                memberReader.MoveToContent();

                WriteUtf8(writer, memberName);
                WriteAmfValue(context, memberReader, writer);

                i++;
            }
            #endregion

            WriteUtf8(writer, string.Empty);
            WriteTypeMarker(writer, Amf0TypeMarker.ObjectEnd);
        }
Example #4
0
        /// <summary>
        /// Write an object.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="writer">
        /// The writer.
        /// </param>
        /// <param name="input">
        /// The input.
        /// </param>
        private void WriteObject(AmfContext context, AmfStreamWriter writer, XmlReader input)
        {
            context.References.Add(new AmfReference {
                AmfxType = AmfxContent.Object
            });
            WriteTypeMarker(writer, Amf3TypeMarker.Object);

            AmfTypeTraits traits;
            string        typeName = string.Empty;

            if (input.HasAttributes)
            {
                typeName = input.GetAttribute(AmfxContent.ObjectType);
            }

            input.Read();

            // Send traits by value
            if (!input.IsEmptyElement)
            {
                traits = new AmfTypeTraits {
                    TypeName = typeName
                };
                context.TraitsReferences.Add(traits);

                XmlReader traitsReader = input.ReadSubtree();
                traitsReader.MoveToContent();
                traitsReader.ReadStartElement();

                var members = new List <string>();

                while (input.NodeType != XmlNodeType.EndElement)
                {
                    members.Add(traitsReader.ReadElementContentAsString());
                }

                traits.ClassMembers = members.ToArray();
                traitsReader.Close();

                // The first bit is a flag with value 1.
                // The second bit is a flag with value 1.
                // The third bit is a flag with value 0.
                int flag = 0x3; // 00000011

                if (traits.IsExternalizable)
                {
                    flag |= 0x4; // 00000111
                }

                // The fourth bit is a flag specifying whether the type is dynamic.
                // A value of 0 implies not dynamic, a value of 1 implies dynamic.
                if (traits.IsDynamic)
                {
                    flag |= 0x8; // 00001011
                }

                // The remaining 1 to 25 significant bits are used to encode the number
                // of sealed traits member names that follow after the class name.
                int count = traits.ClassMembers.Count();
                flag |= count << 4;

                WriteUInt29(writer, flag);

                WriteUtf8(context, writer, traits.TypeName);

                // Write member names
                foreach (string member in traits.ClassMembers)
                {
                    WriteUtf8(context, writer, member);
                }
            }

            // Send traits by reference
            else
            {
                int index = Convert.ToInt32(input.GetAttribute(AmfxContent.TraitsId));
                traits = context.TraitsReferences[index];

                int flag = index & UInt29Mask; // Truncate value to UInt29

                // The first bit is a flag with value 1.
                // The second bit is a flag (representing whether a trait
                // reference follows) with value 0 to imply that this objects
                // traits are being sent by reference. The remaining 1 to 27
                // significant bits are used to encode a trait reference index.
                flag = (flag << 2) | 0x1;
                WriteUInt29(writer, flag);
            }

            input.Read();



            for (int i = 0; i < traits.ClassMembers.Length; i++)
            {
                this.WriteAmfValue(context, input, writer);
                input.Read();
            }
        }
Example #5
0
        /// <summary>
        /// Read an object.
        /// </summary>
        private void ReadObject(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            var reference = reader.PeekChar();
            int index;

            if ((reference & 0x1) == 0 && ReadReference(context, reader, out index, out reference))
            {
                if (output != null) WriteReference(index, output);
                return;
            }

            context.References.Track();

            int traitsindex, traitsreference;
            AmfTypeTraits traits;

            #region Read object's traits
            if ((traits = ReadTraitsReference(context, reader, out traitsindex, out traitsreference)) == null)
            {
                var isExternalizable = ((traitsreference & 0x4) == 4);
                var isDynamic = ((traitsreference & 0x8) == 8);
                var typeName = ReadString(context, reader);
                var count = (traitsreference >> 4);
                var classMembers = new string[count];

                for (var i = 0; i < count; i++)
                    classMembers[i] = ReadString(context, reader);

                traits = new AmfTypeTraits
                             {
                                 IsDynamic = isDynamic,
                                 IsExternalizable = isExternalizable,
                                 TypeName = typeName,

                                 //No property names are included for types
                                 //that are externizable or dynamic
                                 ClassMembers = isDynamic || isExternalizable
                                    ? new string[0]
                                    : classMembers
                             };

                context.TraitsReferences.Add(traits);
            }
            #endregion

            #if DEBUG
            Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadObject_Debug_Name, traits.TypeName));

            if (traits.IsDynamic)
                Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_Dynamic);
            else if (traits.IsExternalizable)
                Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_Externizable);
            else
                Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadObject_Debug_Members, traits.ClassMembers.Length));
            #endif

            

            using (var ms = new MemoryStream())
            {
                #region Reading object members
                var members = new List<string>();

                var settings = new XmlWriterSettings
                {
                 
                };

                var buffer = XmlWriter.Create(ms, settings);
                buffer.WriteStartDocument();
                buffer.WriteStartElement("buffer", AmfxContent.Namespace);

                #if DEBUG
                var memberPosition = 0;
                #endif

                //Read object's properties
                foreach (var classMember in traits.ClassMembers)
                {
                    #if DEBUG
                    Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadObject_Debug_ReadingField, memberPosition,
                                                    classMember));
                    memberPosition++;
                    #endif

                    ReadAmfValue(context, reader, buffer);
                    members.Add(classMember);
                }

                //Read dynamic properties too
                if (traits.IsDynamic)
                {
                    #if DEBUG
                    Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_ReadingDynamic);
                    #endif

                    var key = ReadString(context, reader);

                    while (key != string.Empty)
                    {
                        #if DEBUG
                        Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadObject_Debug_ReadingDynamicField, key));
                        #endif

                        ReadAmfValue(context, reader, buffer);
                        members.Add(key);

                        key = ReadString(context, reader);
                    }

                    #if DEBUG
                    Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_DynamicEnd);
                    #endif
                }

                buffer.WriteEndElement();
                buffer.WriteEndDocument();
                buffer.Flush();
                #endregion

                #if DEBUG
                Debug.WriteLine(Errors.Amf3Decoder_ReadObject_Debug_End);
                #endif

                #region Writing member values
                if (output != null)
                {
                    output.WriteStartElement(AmfxContent.Object);

                    if (traits.TypeName != AmfTypeTraits.BaseTypeAlias)
                        output.WriteAttributeString(AmfxContent.ObjectType, traits.TypeName);

                    output.WriteStartElement(AmfxContent.Traits);

                    //Regular traits object
                    //Always write traits for dynamic objects
                    if (traitsindex == -1 || traits.IsDynamic)
                    {
                        if (traits.IsExternalizable)
                        {
                            output.WriteAttributeString(AmfxContent.TraitsExternizable, AmfxContent.True);
                        }
                        else
                        {
                            //Write object members
                            foreach (var classMember in members)
                            {
                                output.WriteStartElement(AmfxContent.String);
                                output.WriteValue(classMember);
                                output.WriteEndElement();
                            }
                        }
                    }
                    //Traits object reference
                    else
                    {
                        output.WriteAttributeString(AmfxContent.TraitsId, traitsindex.ToString());
                    }

                    output.WriteEndElement(); //End of traits

                    //Write object members
                    if (members.Count > 0)
                    {
                        ms.Position = 0;
                        var bufferreader = XmlReader.Create(ms);
                        bufferreader.Read();
                        bufferreader.ReadStartElement();

                        while (bufferreader.Depth >= 1)
                            output.WriteNode(bufferreader, false);
                    }

                    output.WriteEndElement(); //End of object
                }
                #endregion
            }
        }
        private static object ReadObject(XmlReader reader, SerializationContext context)
        {
            var properties = new Dictionary<string, object>();

            var proxy = new object();
            context.References.Add(new AmfReference { Reference = proxy, AmfxType = AmfxContent.Object });

            var referenceIndex = context.References.Count - 1;

            AmfTypeTraits traits;
            var typeName = string.Empty;

            if (reader.HasAttributes)
                typeName = reader.GetAttribute(AmfxContent.ObjectType);

            #region Read traits
            reader.Read();

            if (!reader.IsEmptyElement && reader.GetAttribute(AmfxContent.TraitsId) == null)
            {
                traits = new AmfTypeTraits { TypeName = typeName };
                context.TraitsReferences.Add(traits);

                var members = new List<string>();

                reader.Read();

                while (reader.NodeType != XmlNodeType.EndElement)
                    members.Add(reader.ReadElementContentAsString());

                traits.ClassMembers = members.ToArray();

                reader.Read();
            }
            else
            {
                var index = Convert.ToInt32(reader.GetAttribute(AmfxContent.TraitsId));
                traits = context.TraitsReferences[index];
                reader.Read();
                reader.Read();
            }

            if (traits == null) throw new SerializationException("Object traits not found.");
            #endregion

            #region Read members
            for (var i = 0; i < traits.ClassMembers.Length; i++)
            {
                var memberValue = Deserialize(reader, context);
                var memberName = traits.ClassMembers[i];

                properties[memberName] = memberValue;
                reader.Read();
            }
            #endregion

            #region Instantiate type
            object result;

            if (!string.IsNullOrEmpty(traits.TypeName))
            {
                if (!context.KnownTypes.ContainsKey(traits.TypeName))
                    throw new SerializationException(string.Format("Unable to find data contract for type alias '{0}'.", traits.TypeName));

                var typeDescriptor = context.KnownTypes[traits.TypeName];

                result = DataContractHelper.InstantiateContract(typeDescriptor.Type, properties, typeDescriptor.PropertyMap, typeDescriptor.FieldMap);
            }
            else
                result = properties;

            context.References[referenceIndex] = new AmfReference { Reference = result, AmfxType = AmfxContent.Object };

            return result;
            #endregion
        }
        /// <summary>
        /// Write an object.
        /// </summary>
        private static void WriteDataContract(XmlWriter writer, object graph, Type type, SerializationContext context, bool isDataContract)
        {
            var index = context.References.IndexOf(graph);

            //Write object reference
            if (index != -1)
            {
                var attributes = new Dictionary<string, string> { { AmfxContent.ReferenceId, index.ToString() } };
                WriteEmptyElement(writer, AmfxContent.Reference, attributes);
                return;
            }

            context.References.Add(new AmfReference { Reference = graph, AmfxType = AmfxContent.Object });

            Dictionary<string, object> properties;

            if (isDataContract)
            {
                var descriptor = context.GetDescriptor(type);

                if (descriptor == null)
                {
                    throw new SerializationException(
                        string.Format(
                            "Unable to resolve type '{0}'. Check if type was registered within the serializer.",
                            type.FullName));
                }

                var alias = descriptor.Alias;
                var traitsindex = context.TraitsIndex(alias);

                writer.WriteStartElement(AmfxContent.Object);

                if (!string.IsNullOrEmpty(alias))
                {
                    writer.WriteAttributeString(AmfxContent.ObjectType, alias);

                    if (traitsindex == -1)
                    {
                        var typeNameIndex = context.StringReferences.IndexOf(alias);
                        if (typeNameIndex == -1) context.StringReferences.Add(alias);
                    }
                }

                properties = DataContractHelper.GetContractProperties(graph, descriptor.PropertyMap, descriptor.FieldMap);

                //Write traits by reference
                if (context.AmfVersion == AmfVersion.Amf3 && traitsindex != -1)
                {
                    var attributes = new Dictionary<string, string> { { AmfxContent.TraitsId, traitsindex.ToString() } };
                    WriteEmptyElement(writer, AmfxContent.Traits, attributes);
                }
                //Write traits
                else
                {
                    var traits = new AmfTypeTraits { TypeName = alias, ClassMembers = properties.Keys.ToArray() };
                    context.TraitsReferences.Add(traits);

                    writer.WriteStartElement(AmfxContent.Traits);

                    foreach (var propertyName in properties.Keys)
                    {
                        WriteElement(writer, AmfxContent.String, propertyName);

                        var memberNameIndex = context.StringReferences.IndexOf(propertyName);
                        if (memberNameIndex == -1) context.StringReferences.Add(propertyName);
                    }

                    writer.WriteEndElement(); //End of traits
                }
            }
            else
            {
                var map = (IDictionary)graph;
                properties = new Dictionary<string, object>();

                foreach (var key in map.Keys)
                    properties[key.ToString()] = map[key];

                writer.WriteStartElement(AmfxContent.Object);

                writer.WriteStartElement(AmfxContent.Traits);

                foreach (var propertyName in properties.Keys)
                {
                    WriteElement(writer, AmfxContent.String, propertyName);
                    var memberNameIndex = context.StringReferences.IndexOf(propertyName);
                    if (memberNameIndex == -1) context.StringReferences.Add(propertyName);
                }

                writer.WriteEndElement(); //End of traits
            }

            foreach (var value in properties.Values)
                Serialize(writer, value, context);

            writer.WriteEndElement(); //End of object
        }
Example #8
0
        /// <summary>
        /// Write an object.
        /// </summary>
        private void WriteObject(AmfContext context, AmfStreamWriter writer, XmlReader input)
        {
            context.References.Add(new AmfReference { AmfxType = AmfxContent.Object });

            WriteTypeMarker(writer, Amf0TypeMarker.Object);

            var typeName = string.Empty;

            if (input.HasAttributes)
                typeName = input.GetAttribute(AmfxContent.ObjectType);

            #region Read traits
            var traits = new AmfTypeTraits { TypeName = typeName };

            while (input.Read())
            {
                if (input.NodeType != XmlNodeType.Element && input.Name != AmfxContent.Traits) continue;

                if (!input.IsEmptyElement)
                {
                    var traitsReader = input.ReadSubtree();
                    traitsReader.MoveToContent();
                    traitsReader.ReadStartElement();

                    var members = new List<string>();

                    while (input.NodeType != XmlNodeType.EndElement)
                        members.Add(traitsReader.ReadElementContentAsString());

                    traits.ClassMembers = members.ToArray();
                }

                break;
            }
            #endregion

            #region Type name
            //Untyped object
            if(string.IsNullOrEmpty(traits.TypeName))
            {
                WriteTypeMarker(writer, Amf0TypeMarker.Object);
            }
            //Strongly-typed object
            else
            {
                WriteTypeMarker(writer, Amf0TypeMarker.TypedObject);
                var typeNameData = Encoding.UTF8.GetBytes(traits.TypeName);
                writer.Write((ushort)typeNameData.Length);
                writer.Write(typeNameData);
            }
            #endregion

            #region Write members
            var i = 0;

            while (input.Read())
            {
                if (input.NodeType != XmlNodeType.Element) continue;

                var memberName = traits.ClassMembers[i];
                var memberReader = input.ReadSubtree();
                memberReader.MoveToContent();

                WriteUtf8(writer, memberName);
                WriteAmfValue(context, memberReader, writer);

                i++;
            }
            #endregion

            WriteUtf8(writer, string.Empty);
            WriteTypeMarker(writer, Amf0TypeMarker.ObjectEnd);
        }