public override void WritePacketHeader(Stream stream, AmfHeaderDescriptor descriptor) { var writer = new AmfStreamWriter(stream); WriteUtf8(writer, descriptor.Name); writer.Write((byte)(descriptor.MustUnderstand ? 1 : 0)); writer.Write(-1); }
/// <summary> /// Write UTF8 data. /// </summary> private static void WriteUtf8(AmfStreamWriter writer, byte[] data) { if (data.Length < ShortStringLimit) { writer.Write((ushort)data.Length); } else { writer.Write((uint)data.Length); } writer.Write(data); }
/// <summary> /// Write a double. /// </summary> /// <param name="writer"> /// The writer. /// </param> /// <param name="input"> /// The input. /// </param> private static void WriteDouble(AmfStreamWriter writer, XmlReader input) { double value = Convert.ToDouble(input.ReadString()); WriteTypeMarker(writer, Amf3TypeMarker.Double); writer.Write(value); }
/// <summary> /// Write UTF-8 string. /// </summary> /// <param name="context"> /// The context. /// </param> /// <param name="writer"> /// The writer. /// </param> /// <param name="value"> /// The value. /// </param> private static void WriteUtf8(AmfContext context, AmfStreamWriter writer, string value) { if (value == null) { value = string.Empty; } // A special case if (value == string.Empty) { writer.Write((byte)0x01); return; } int index = context.StringReferences.IndexOf(value); if (index != -1) { WriteReference(writer, index); return; } context.StringReferences.Add(value); byte[] decoded = Encoding.UTF8.GetBytes(value); WriteUtf8(writer, decoded); }
/// <summary> /// Write an array. /// </summary> private void WriteArray(AmfContext context, AmfStreamWriter writer, XmlReader input) { context.References.Add(new AmfReference { AmfxType = AmfxContent.Array }); var length = Convert.ToUInt32(input.GetAttribute(AmfxContent.ArrayLength)); writer.Write(length); if (length == 0) { return; } input.MoveToContent(); while (input.Read()) { if (input.NodeType != XmlNodeType.Element) { continue; } for (var i = 0; i < length; i++) { var itemreader = input.ReadSubtree(); itemreader.MoveToContent(); WriteAmfValue(context, itemreader, writer); } } }
/// <summary> /// Write a number. /// </summary> private static void WriteNumber(AmfStreamWriter writer, XmlReader input) { WriteTypeMarker(writer, Amf0TypeMarker.Number); var value = Convert.ToDouble(input.ReadString()); writer.Write(value); }
public override void WritePacketBody(Stream stream, AmfMessageDescriptor descriptor) { var writer = new AmfStreamWriter(stream); WriteUtf8(writer, descriptor.Target); WriteUtf8(writer, descriptor.Response); writer.Write(-1); }
/// <summary> /// Write a number. /// </summary> private static void WriteNumber(AmfStreamWriter writer, XmlReader input) { WriteTypeMarker(writer, Amf0TypeMarker.Number); var value = input.ReadContentAsDouble(); writer.Write(value); }
/// <summary> /// Write UTF-8 data. /// </summary> /// <param name="writer"> /// The writer. /// </param> /// <param name="data"> /// The data. /// </param> private static void WriteUtf8(AmfStreamWriter writer, byte[] data) { // The first bit is a flag with value 1. // The remaining 1 to 28 significant bits are used // to encode the byte-length of the data int flag = (data.Length << 1) | 0x1; WriteUInt29(writer, flag); writer.Write(data); }
/// <summary> /// Write a double. /// </summary> private static void WriteDouble(AmfStreamWriter writer, XmlReader input) { input.Read(); var value = Convert.ToDouble(input.Value, CultureInfo.InvariantCulture); input.Read(); WriteTypeMarker(writer, Amf3TypeMarker.Double); writer.Write(value); }
/// <summary> /// Write an 29-bit unsigned integer. /// </summary> /// <param name="writer"> /// The writer. /// </param> /// <param name="value"> /// The value. /// </param> private static void WriteUInt29(AmfStreamWriter writer, int value) { // < 128: // 0x00000000 - 0x0000007F if (value < 0x80) { writer.Write((byte)value); // 0xxxxxxx } // < 16,384: // 0x00000080 - 0x00003FFF else if (value < 0x4000) { writer.Write((byte)(value >> 7 & 0x7F | 0x80)); // 1xxxxxxx writer.Write((byte)(value & 0x7F)); // xxxxxxxx } // < 2,097,152: // 0x00004000 - 0x001FFFFF else if (value < 0x200000) { writer.Write((byte)(value >> 14 & 0x7F | 0x80)); // 1xxxxxxx writer.Write((byte)(value >> 7 & 0x7F | 0x80)); // 1xxxxxxx writer.Write((byte)(value & 0x7F)); // xxxxxxxx } // 0x00200000 - 0x3FFFFFFF else if (value < 0x40000000) { writer.Write((byte)(value >> 22 & 0x7F | 0x80)); // 1xxxxxxx writer.Write((byte)(value >> 15 & 0x7F | 0x80)); // 1xxxxxxx writer.Write((byte)(value >> 8 & 0x7F | 0x80)); // 1xxxxxxx writer.Write((byte)(value & 0xFF)); // xxxxxxxx } // 0x40000000 - 0xFFFFFFFF, out of range else { throw new IndexOutOfRangeException("Integer is out of range: " + value); } }
/// <summary> /// Write a date. /// </summary> /// <param name="context"> /// The context. /// </param> /// <param name="writer"> /// The writer. /// </param> /// <param name="input"> /// The input. /// </param> private static void WriteDate(AmfContext context, AmfStreamWriter writer, XmlReader input) { context.References.Add(new AmfReference { AmfxType = AmfxContent.Date }); WriteTypeMarker(writer, Amf3TypeMarker.Date); double milliseconds = Convert.ToDouble(input.ReadString()); // The first bit is a flag with value 1. // The remaining bits are not used. WriteUInt29(writer, 0 | 0x1); writer.Write(milliseconds); }
/// <summary> /// Write a reference value. /// </summary> private static void WriteReference(AmfContext context, AmfStreamWriter writer, XmlReader input) { var index = Convert.ToInt32(input.GetAttribute(AmfxContent.ReferenceId)); var proxy = context.References[index]; switch (proxy.AmfxType) { case AmfxContent.Array: case AmfxContent.Object: WriteTypeMarker(writer, Amf0TypeMarker.Reference); writer.Write((ushort)index); break; default: throw new InvalidOperationException(string.Format("AMFX type '{0}' cannot be send by reference.", proxy.AmfxType)); } }
/// <summary> /// Write a byte array. /// </summary> private static void WriteByteArray(AmfContext context, AmfStreamWriter writer, XmlReader input) { context.References.Add(new AmfReference { AmfxType = AmfxContent.ByteArray }); WriteTypeMarker(writer, Amf3TypeMarker.ByteArray); var encoded = input.ReadString(); var bytes = Convert.FromBase64String(encoded); //The first bit is a flag with value 1. //The remaining 1 to 28 significant bits are used //to encode the byte-length of the data var flag = (bytes.Length << 1) | 0x1; WriteUInt29(writer, flag); writer.Write(bytes); }
/// <summary> /// Write an integer. /// </summary> private static void WriteInteger(AmfStreamWriter writer, XmlReader input) { var text = input.ReadString(); var value = Convert.ToInt64(text); //Check if the value fits the Int29 span if (value >= MinInt29Value && value <= MaxInt29Value) { //It should be safe to cast it there var integer = UInt29Mask & (int)value; //Truncate the value WriteTypeMarker(writer, Amf3TypeMarker.Integer); WriteUInt29(writer, integer); } //Promote the value to a double else { WriteTypeMarker(writer, Amf3TypeMarker.Double); writer.Write(Convert.ToDouble(value)); } }
/// <summary> /// Write AMF message headers count. /// </summary> private static void WriteHeaderCount(AmfStreamWriter writer, int count) { writer.Write((ushort)count); }
/// <summary> /// Write a reference value. /// </summary> private static void WriteReference(AmfContext context, AmfStreamWriter writer, XmlReader input) { var index = Convert.ToInt32(input.GetAttribute(AmfxContent.ReferenceId)); var proxy = context.References[index]; switch(proxy.AmfxType) { case AmfxContent.Array: case AmfxContent.Object: WriteTypeMarker(writer, Amf0TypeMarker.Reference); writer.Write((ushort)index); break; default: throw new InvalidOperationException(string.Format("AMFX type '{0}' cannot be send by reference.", proxy.AmfxType)); } }
/// <summary> /// Write a date. /// </summary> private static void WriteDate(AmfStreamWriter writer, double value) { WriteTypeMarker(writer, Amf0TypeMarker.Date); writer.Write(value); writer.Write((short)0); //Timezone (not used) }
/// <summary> /// Write UTF8 data. /// </summary> private static void WriteUtf8(AmfStreamWriter writer, byte[] data) { if (data.Length < ShortStringLimit) writer.Write((ushort)data.Length); else writer.Write((uint)data.Length); writer.Write(data); }
/// <summary> /// Write a boolean value. /// </summary> private static void WriteBoolean(AmfStreamWriter writer, bool value) { writer.Write(value); }
protected override void WriteAmfValue(AmfContext context, XmlReader input, AmfStreamWriter writer) { if (input == null) throw new ArgumentNullException("input"); if (context == null) throw new ArgumentNullException("context"); if (input.NodeType != XmlNodeType.Element) throw new XmlException(string.Format("Element node expected, {0} found.", input.NodeType)); if (context.AmfVersion != AmfVersion.Amf3) { context = new AmfContext(AmfVersion.Amf3); writer.Write((byte)Amf0TypeMarker.AvmPlusObject); } #region Primitive values switch (input.Name) { case AmfxContent.Null: WriteTypeMarker(writer, Amf3TypeMarker.Null); return; case AmfxContent.True: WriteTypeMarker(writer, Amf3TypeMarker.True); return; case AmfxContent.False: WriteTypeMarker(writer, Amf3TypeMarker.False); return; } #endregion #region Complex values switch (input.Name) { case AmfxContent.Integer: WriteInteger(writer, input); break; case AmfxContent.Double: WriteDouble(writer, input); break; case AmfxContent.String: WriteString(context, writer, input); break; case AmfxContent.Reference: WriteReference(context, writer, input); break; case AmfxContent.Date: WriteDate(context, writer, input); break; case AmfxContent.Xml: WriteXml(context, writer, input); break; case AmfxContent.Array: WriteArray(context, writer, input); break; case AmfxContent.ByteArray: WriteByteArray(context, writer, input); break; case AmfxContent.Object: WriteObject(context, writer, input); break; default: throw new NotSupportedException("Unexpected AMFX type: " + input.Name); } #endregion }
/// <summary> /// Write UTF-8 string. /// </summary> private static void WriteUtf8(AmfContext context, AmfStreamWriter writer, string value) { if (value == null) value = string.Empty; //A special case if (value == string.Empty) { writer.Write((byte)0x01); return; } var index = context.StringReferences.IndexOf(value); if(index != -1) { WriteReference(writer, index); return; } context.StringReferences.Add(value); var decoded = Encoding.UTF8.GetBytes(value); WriteUtf8(writer, decoded); }
/// <summary> /// Write an AMF0 type marker. /// </summary> private static void WriteTypeMarker(AmfStreamWriter writer, Amf3TypeMarker marker) { writer.Write((byte)marker); }
/// <summary> /// The write amf value. /// </summary> /// <param name="context"> /// The context. /// </param> /// <param name="input"> /// The input. /// </param> /// <param name="writer"> /// The writer. /// </param> /// <exception cref="ArgumentNullException"> /// </exception> /// <exception cref="XmlException"> /// </exception> /// <exception cref="NotSupportedException"> /// </exception> protected override void WriteAmfValue(AmfContext context, XmlReader input, AmfStreamWriter writer) { if (input == null) { throw new ArgumentNullException("input"); } if (context == null) { throw new ArgumentNullException("context"); } if (input.NodeType != XmlNodeType.Element) { throw new XmlException(string.Format("Element node expected, {0} found.", input.NodeType)); } if (context.AmfVersion != AmfVersion.Amf3) { context = new AmfContext(AmfVersion.Amf3); writer.Write((byte)Amf0TypeMarker.AvmPlusObject); } switch (input.Name) { case AmfxContent.Null: WriteTypeMarker(writer, Amf3TypeMarker.Null); return; case AmfxContent.True: WriteTypeMarker(writer, Amf3TypeMarker.True); return; case AmfxContent.False: WriteTypeMarker(writer, Amf3TypeMarker.False); return; } switch (input.Name) { case AmfxContent.Integer: WriteInteger(writer, input); break; case AmfxContent.Double: WriteDouble(writer, input); break; case AmfxContent.String: WriteString(context, writer, input); break; case AmfxContent.Reference: WriteReference(context, writer, input); break; case AmfxContent.Date: WriteDate(context, writer, input); break; case AmfxContent.Xml: WriteXml(context, writer, input); break; case AmfxContent.Array: this.WriteArray(context, writer, input); break; case AmfxContent.ByteArray: WriteByteArray(context, writer, input); break; case AmfxContent.Object: this.WriteObject(context, writer, input); break; default: throw new NotSupportedException("Unexpected AMFX type: " + input.Name); } }
/// <summary> /// Write AMF message bodies count. /// </summary> static private void WriteMessageCount(AmfStreamWriter writer, int count) { writer.Write((ushort)count); }
/// <summary> /// Write AMF message headers count. /// </summary> static private void WriteHeaderCount(AmfStreamWriter writer, int count) { writer.Write((ushort)count); }
/// <summary> /// Write AMF message version. /// </summary> static private void WriteAmfVersion(AmfStreamWriter writer, AmfVersion version) { writer.Write((ushort)version); }
/// <summary> /// Write an 29-bit unsigned integer. /// </summary> private static void WriteUInt29(AmfStreamWriter writer, int value) { //< 128: //0x00000000 - 0x0000007F if (value < 0x80) { writer.Write((byte)value); //0xxxxxxx } //< 16,384: //0x00000080 - 0x00003FFF else if (value < 0x4000) { writer.Write((byte)(value >> 7 & 0x7F | 0x80)); //1xxxxxxx writer.Write((byte)(value & 0x7F)); //xxxxxxxx } //< 2,097,152: //0x00004000 - 0x001FFFFF else if (value < 0x200000) { writer.Write((byte)(value >> 14 & 0x7F | 0x80)); //1xxxxxxx writer.Write((byte)(value >> 7 & 0x7F | 0x80)); //1xxxxxxx writer.Write((byte)(value & 0x7F)); //xxxxxxxx } //0x00200000 - 0x3FFFFFFF else if (value < 0x40000000) { writer.Write((byte)(value >> 22 & 0x7F | 0x80)); //1xxxxxxx writer.Write((byte)(value >> 15 & 0x7F | 0x80)); //1xxxxxxx writer.Write((byte)(value >> 8 & 0x7F | 0x80)); //1xxxxxxx writer.Write((byte)(value & 0xFF)); //xxxxxxxx } //0x40000000 - 0xFFFFFFFF, out of range else { throw new IndexOutOfRangeException("Integer is out of range: " + value); } }
/// <summary> /// Write AMF message version. /// </summary> private static void WriteAmfVersion(AmfStreamWriter writer, AmfVersion version) { writer.Write((ushort)version); }
/// <summary> /// Write UTF-8 data. /// </summary> private static void WriteUtf8(AmfStreamWriter writer, byte[] data) { //The first bit is a flag with value 1. //The remaining 1 to 28 significant bits are used //to encode the byte-length of the data var flag = (data.Length << 1) | 0x1; WriteUInt29(writer, flag); writer.Write(data); }
/// <summary> /// Write an AMF0 type marker. /// </summary> private static void WriteTypeMarker(AmfStreamWriter writer, Amf0TypeMarker marker) { writer.Write((byte)marker); }
/// <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 XML. /// </summary> private static void WriteXml(AmfStreamWriter writer, byte[] value) { WriteTypeMarker(writer, Amf0TypeMarker.XmlDocument); writer.Write((uint)value.Length); writer.Write(value); }
/// <summary> /// Write an array. /// </summary> private void WriteArray(AmfContext context, AmfStreamWriter writer, XmlReader input) { context.References.Add(new AmfReference {AmfxType = AmfxContent.Array}); var length = Convert.ToUInt32(input.GetAttribute(AmfxContent.ArrayLength)); writer.Write(length); if (length == 0) return; input.MoveToContent(); while (input.Read()) { if (input.NodeType != XmlNodeType.Element) continue; for (var i = 0; i < length; i++) { var itemreader = input.ReadSubtree(); itemreader.MoveToContent(); WriteAmfValue(context, itemreader, writer); } } }
/// <summary> /// Write a byte array. /// </summary> private static void WriteByteArray(AmfContext context, AmfStreamWriter writer, XmlReader input) { context.References.Add(new AmfReference { AmfxType = AmfxContent.ByteArray }); WriteTypeMarker(writer, Amf3TypeMarker.ByteArray); input.Read(); var encoded = input.Value; input.Read(); var bytes = Convert.FromBase64String(encoded); //The first bit is a flag with value 1. //The remaining 1 to 28 significant bits are used //to encode the byte-length of the data var flag = (bytes.Length << 1) | 0x1; WriteUInt29(writer, flag); writer.Write(bytes); }
/// <summary> /// Write a date. /// </summary> private static void WriteDate(AmfContext context, AmfStreamWriter writer, XmlReader input) { context.References.Add(new AmfReference { AmfxType = AmfxContent.Date }); WriteTypeMarker(writer, Amf3TypeMarker.Date); var milliseconds = input.ReadElementContentAsDouble(); //The first bit is a flag with value 1. //The remaining bits are not used. WriteUInt29(writer, 0 | 0x1); writer.Write(milliseconds); }
/// <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 integer. /// </summary> private static void WriteInteger(AmfStreamWriter writer, XmlReader input) { input.Read(); var value = Convert.ToInt32(input.Value, CultureInfo.InvariantCulture); input.Read(); //Check if the value fits the Int29 span if (value >= MinInt29Value && value <= MaxInt29Value) { //It should be safe to cast it there var integer = UInt29Mask & (int)value; //Truncate the value WriteTypeMarker(writer, Amf3TypeMarker.Integer); WriteUInt29(writer, integer); } //Promote the value to a double else { WriteTypeMarker(writer, Amf3TypeMarker.Double); writer.Write(Convert.ToDouble(value, CultureInfo.InvariantCulture)); } }
/// <summary> /// Write AMF message bodies count. /// </summary> private static void WriteMessageCount(AmfStreamWriter writer, int count) { writer.Write((ushort)count); }