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