示例#1
0
        /// <summary>
        /// Read an object reference.
        /// </summary>
        /// <param name="context">AMF decoding context.</param>
        /// <param name="reader">AMF reader.</param>
        /// <param name="index">Reference index.</param>
        /// <param name="reference">Reference value.</param>
        /// <returns>Referenced object or <c>null</c> if value does not contain a reference.</returns>
        /// <exception cref="SerializationException">Invalid reference.</exception>
        private static bool ReadReference(AmfContext context, AmfStreamReader reader, out int index, out int reference)
        {
            reference = ReadUint29(reader);

            //The first bit is a flag with value 0 to imply that this is not an instance but a reference
            if ((reference & 0x1) == 0)
            {
                //The remaining 1 to 28 significant bits are used to encode an object reference index
                index = reference >> 1;

                if (context.References.Count <= index)
                    throw new SerializationException("Invalid reference index: " + index);

                return true;
            }

            index = -1;
            return false;
        }
示例#2
0
        /// <summary>
        /// Read a strict array.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>array-count = U32
        /// strict-array-type = array-count *(value-type)</c>
        /// </remarks>
        private void ReadStrictArray(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            context.References.Track();

            var length = reader.ReadUInt32();

            if (output != null)
            {
                output.WriteStartElement(AmfxContent.Array);
                output.WriteAttributeString(AmfxContent.ArrayLength, length.ToString());
            }

            for (var i = 0; i < length; i++)
                ReadAmfValue(context, reader, output);

            if (output != null) output.WriteEndElement();
        }
示例#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, 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
        }
示例#4
0
        /// <summary>
        /// Write an XML.
        /// </summary>
        private static void WriteXml(AmfContext context, AmfStreamWriter writer, XmlReader input)
        {
            context.References.Add(new AmfReference {AmfxType = AmfxContent.Xml});
            WriteTypeMarker(writer, Amf3TypeMarker.Xml);

            input.Read();
            var encoded = input.Value;
            input.Read();

            var decoded = Encoding.UTF8.GetBytes(encoded);

            WriteUtf8(writer, decoded);
        }
示例#5
0
        /// <summary>
        /// Write a string.
        /// </summary>
        private static void WriteString(AmfContext context, AmfStreamWriter writer, XmlReader input)
        {
            WriteTypeMarker(writer, Amf3TypeMarker.String);

            string value;

            if (input.IsEmptyElement)
            {
                if (input.AttributeCount > 0)
                {
                    var index = Convert.ToInt32(input.GetAttribute(AmfxContent.StringId), CultureInfo.InvariantCulture);
                    WriteReference(writer, index);
                    return;
                }

                value = string.Empty;
            }
            else
            {
                input.Read();
                value = input.Value;
                input.Read();
            }

            WriteUtf8(context, writer, value);
        }
示例#6
0
        /// <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);
        }
示例#7
0
        /// <summary>
        /// Read a string reference.
        /// </summary>
        /// <param name="context">AMF decoding context.</param>
        /// <param name="reader">AMF reader.</param>
        /// <param name="index">Reference index.</param>
        /// <param name="reference">Reference value.</param>
        /// <returns>Referenced string or <c>null</c> if value does not contain a reference.</returns>
        /// <exception cref="SerializationException">Invalid reference.</exception>
        private static string ReadStringReference(AmfContext context, AmfStreamReader reader, out int index, out int reference)
        {
            reference = ReadUint29(reader);

            //The first bit is a flag with value 0
            if ((reference & 0x1) == 0)
            {
                //The remaining 1 to 28 significant bits are used to encode a string reference table index
                index = reference >> 1;

                if (context.StringReferences.Count <= index)
                    throw new SerializationException("Invalid reference index: " + index);

                return context.StringReferences[index];
            }

            index = -1;
            return null;
        }
示例#8
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
            }
        }
示例#9
0
        protected override void WriteAmfValue(AmfContext context, XmlReader input, AmfStreamWriter writer)
        {
            if (context.AmfVersion != AmfVersion.Amf0)
                throw new InvalidOperationException(string.Format(Errors.Amf0Decoder_ReadAmfValue_AmfVersionNotSupported, context.AmfVersion));

            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));

            #region Primitive values
            switch (input.Name)
            {
                case AmfxContent.Null:
                    WriteNull(writer);
                    return;

                case AmfxContent.True:
                    WriteBoolean(writer, true);
                    return;

                case AmfxContent.False:
                    WriteBoolean(writer, false);
                    return;
            }
            #endregion

            #region Complex values
            var reader = input.ReadSubtree();
            reader.MoveToContent();

            switch (reader.Name)
            {
                case AmfxContent.Integer:
                case AmfxContent.Double:
                    WriteNumber(writer, reader);
                    break;

                case AmfxContent.String:
                    WriteString(writer, reader);
                    break;

                case AmfxContent.Date:
                    WriteDate(writer, reader);
                    break;

                case AmfxContent.Xml:
                    WriteXml(writer, reader);
                    break;

                case AmfxContent.Reference:
                    WriteReference(context, writer, reader);
                    break;

                case AmfxContent.Array:
                    WriteArray(context, writer, reader);
                    break;

                case AmfxContent.Object:
                    WriteObject(context, writer, reader);
                    break;

                default:
                    throw new NotSupportedException("Unexpected AMFX type: " + reader.Name);
            }
            #endregion
        }
示例#10
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);
        }
示例#11
0
        /// <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);
                }
            }
        }
示例#12
0
        /// <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));
            }
        }
示例#13
0
 /// <summary>
 /// Read AMF value from the current position.
 /// </summary>
 /// <param name="context">AMF context.</param>
 /// <param name="reader">AMF stream reader.</param>
 /// <param name="output">AMFX output writer.</param>
 /// <exception cref="NotSupportedException">AMF type is not supported.</exception>
 /// <exception cref="FormatException">Invalid data format.</exception>
 /// <exception cref="SerializationException">Error during deserialization.</exception>
 protected abstract void ReadAmfValue(AmfContext context, AmfStreamReader reader, XmlWriter output = null);
示例#14
0
        protected override void ReadAmfValue(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            if (context.AmfVersion != AmfVersion.Amf0)
                throw new InvalidOperationException(string.Format(Errors.Amf0Decoder_ReadAmfValue_AmfVersionNotSupported, context.AmfVersion));

            Amf0TypeMarker dataType;

            try
            {
                //Read a type marker byte
                dataType = (Amf0TypeMarker)reader.ReadByte();
            }
            catch (Exception e)
            {
                throw new FormatException(Errors.Amf0Decoder_ReadAmfValue_TypeMarkerMissing, e);
            }

            //Special case
            if(dataType == Amf0TypeMarker.AvmPlusObject)
            {
                var newContext = new AmfContext(AmfVersion.Amf3);
                ReadAmfValue(newContext, reader, output);
                return;
            }

            ReadValue(context, reader, dataType, output);
        }
示例#15
0
        /// <summary>
        /// Read a value of a given type from current reader's position.
        /// </summary>
        /// <remarks>
        /// Current reader position must be just after a value type marker of a type to read.
        /// </remarks>
        /// <param name="context">AMF decoding context.</param>
        /// <param name="reader">AMF stream reader.</param>
        /// <param name="type">Type of the value to read.</param>
        /// <param name="output">AMFX output.</param>
        /// <exception cref="NotSupportedException">AMF type is not supported.</exception>
        /// <exception cref="FormatException">Unknown data format.</exception>
        /// <exception cref="SerializationException">Error during deserialization.</exception>
        private void ReadValue(AmfContext context, AmfStreamReader reader, Amf0TypeMarker type, XmlWriter output = null)
        {
            switch (type)
            {
                case Amf0TypeMarker.Null:
                case Amf0TypeMarker.Undefined:
                    break;

                case Amf0TypeMarker.Boolean:
                    reader.ReadBoolean();
                    break;

                case Amf0TypeMarker.Number:
                    reader.ReadDouble();
                    break;

                case Amf0TypeMarker.String:
                    ReadString(reader, output);
                    break;

                case Amf0TypeMarker.LongString:
                    ReadLongString(reader, output);
                    break;

                case Amf0TypeMarker.Date:
                    ReadDate(reader, output);
                    break;

                case Amf0TypeMarker.XmlDocument:
                    ReadXml(reader, output);
                    break;

                case Amf0TypeMarker.Reference:
                    ReadReference(context, reader, output);
                    break;

                case Amf0TypeMarker.Object:
                    ReadObject(context, reader, output);
                    break;

                case Amf0TypeMarker.TypedObject:
                    ReadObject(context, reader, output, true);
                    break;

                case Amf0TypeMarker.EcmaArray:
                    ReadEcmaArray(context, reader, output);
                    break;

                case Amf0TypeMarker.StrictArray:
                    ReadStrictArray(context, reader, output);
                    break;

                case Amf0TypeMarker.MovieClip:
                case Amf0TypeMarker.RecordSet:
                case Amf0TypeMarker.Unsupported:
                    throw new NotSupportedException(string.Format(Errors.Amf0Deserializer_ReadValue_UnsupportedType, type));

                default:
                    throw new FormatException(string.Format(Errors.Amf0Decoder_ReadValue_UnknownType, (byte)type));
            }

            if (output != null) output.Flush();
        }
示例#16
0
        /// <summary>
        /// Read an XML document.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>U29X-value = U29 (The first (low) bit is a flag with value 1.
        /// The remaining 1 to 28 significant bits are used to encode the byte-length
        /// of the UTF-8 encoded representation of the XML or XMLDocument). 
        /// xml-doc-type = xml-doc-marker (U29O-ref | (U29X-value *(UTF8-char)))</c>
        /// </remarks>
        private static void ReadXml(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            int index, reference;

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

            context.References.Track();

            //Get XML string length
            var length = (reference >> 1);
            var value = ReadUtf8(reader, length);

            if (output != null)
            {
                output.WriteStartElement(AmfxContent.Xml);
                output.WriteValue(value);
                output.WriteEndElement();
            }
        }
示例#17
0
        /// <summary>
        /// Read an array.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>U29A-value = U29 (The first (low) bit is a flag with value 1.
        /// The remaining 1 to 28 significant bits are used to encode 
        /// the count of the dense portion of the Array).
        /// assoc-value = UTF-8-vr value-type
        /// array-type = array-marker (U29O-ref | 
        /// (U29A-value (UTF-8-empty | *(assoc-value) UTF-8-empty) *(value-type)))</c>
        /// </remarks>
        private void ReadArray(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            int index, reference;

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

            context.References.Track();

            var length = reference >> 1;
            var key = ReadString(context, reader);

            if (output != null)
            {
                output.WriteStartElement(AmfxContent.Array);
                output.WriteAttributeString(AmfxContent.ArrayLength, length.ToString());
            }

            //ECMA array
            if (key != string.Empty)
            {
                if (output != null) output.WriteAttributeString(AmfxContent.ArrayEcma, AmfxContent.True);

                //Read associative values
                do
                {
                    if (output != null)
                    {
                        output.WriteStartElement(AmfxContent.ArrayItem);
                        output.WriteAttributeString(AmfxContent.ArrayKey, key);
                    }

                    ReadAmfValue(context, reader, output);
                    key = ReadString(context, reader);

                    if (output != null) output.WriteEndElement();
                }
                while (key != string.Empty);

                //Read array values
                for (var i = 0; i < length; i++)
                    ReadAmfValue(context, reader, output);
            }
            //Regular array
            else
            {
                //Read array values
                for (var i = 0; i < length; i++)
                    ReadAmfValue(context, reader, output);
            }

            if (output != null) output.WriteEndElement();
        }
示例#18
0
 /// <summary>
 /// Write AMF value from the current position.
 /// </summary>
 /// <param name="context">AMF decoding context.</param>
 /// <param name="input">AMFX input reader.</param>
 /// <param name="writer">AMF stream writer.</param>
 /// <exception cref="NotSupportedException">AMF type is not supported.</exception>
 /// <exception cref="FormatException">Invalid data format.</exception>
 /// <exception cref="SerializationException">Error during serialization.</exception>
 protected abstract void WriteAmfValue(AmfContext context, XmlReader input, AmfStreamWriter writer);
示例#19
0
        /// <summary>
        /// Read a traits reference.
        /// </summary>
        /// <param name="context">AMF decoding context.</param>
        /// <param name="reader">AMF reader.</param>
        /// <param name="index">Reference index.</param>
        /// <param name="reference">Reference value.</param>
        /// <returns>Referenced traits object or <c>null</c> if value does not contain a reference.</returns>
        /// <exception cref="SerializationException">Invalid reference.</exception>
        private static AmfTypeTraits ReadTraitsReference(AmfContext context, AmfStreamReader reader, out int index, out int reference)
        {
            reference = ReadUint29(reader);

            //The first bit is a flag with value 1. The second bit is a flag with value 0 to imply 
            //that this objects traits are being sent by reference
            if ((reference & 0x3) == 1) //x01 & x11 == x01
            {
                //The remaining 1 to 27 significant bits are used to encode a trait reference index
                index = reference >> 2;

                if (context.TraitsReferences.Count <= index)
                    throw new SerializationException("Invalid reference index: " + index);

                return context.TraitsReferences[index];
            }

            index = -1;
            return null;
        }
示例#20
0
        protected override void ReadAmfValue(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            //Work in a legacy context
            if (context.AmfVersion == AmfVersion.Amf0)
            {
                base.ReadAmfValue(context, reader, output);
                return;
            }

            Amf3TypeMarker dataType;

            try
            {
                //Read a type marker byte
                dataType = (Amf3TypeMarker)reader.ReadByte();
            }
            catch (Exception e)
            {
                #if DEBUG
                Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadValue_InvalidMarker, reader.BaseStream.Position));
                #endif

                throw new FormatException(string.Format(Errors.Amf3Decoder_ReadValue_TypeMarkerNotFound, reader.BaseStream.Position), e);
            }

            ReadValue(context, reader, dataType, output);

            #if DEBUG
            Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadValue_End, dataType, reader.BaseStream.Position));
            #endif
        }
示例#21
0
        /// <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);
        }
示例#22
0
        /// <summary>
        /// Read a value of a given type from current reader's position.
        /// </summary>
        /// <remarks>
        /// Current reader position must be just after a value type marker of a type to read.
        /// </remarks>
        /// <param name="context">AMF decoding context.</param>
        /// <param name="reader">AMF reader.</param>
        /// <param name="type">Type of the value to read.</param>
        /// <param name="output">AMFX output.</param>
        /// <exception cref="NotSupportedException">AMF type is not supported.</exception>
        /// <exception cref="FormatException">Unknown data format.</exception>
        /// <exception cref="SerializationException">Error during deserialization.</exception>
        private void ReadValue(AmfContext context, AmfStreamReader reader, Amf3TypeMarker type, XmlWriter output = null)
        {
            #if DEBUG
            Debug.WriteLine(string.Format(Errors.Amf3Decoder_ReadValue_Debug, type, reader.BaseStream.Position));
            #endif

            switch (type)
            {
                case Amf3TypeMarker.Null:
                case Amf3TypeMarker.Undefined:
                    WriteEmptyElement(type.ToAmfxName(), output);
                    break;

                case Amf3TypeMarker.False:
                    WriteEmptyElement(type.ToAmfxName(), output);
                    break;

                case Amf3TypeMarker.True:
                    WriteEmptyElement(type.ToAmfxName(), output);
                    break;

                case Amf3TypeMarker.Integer:
                    ReadInteger(reader, output);
                    break;

                case Amf3TypeMarker.Double:
                    ReadDouble(reader, output);
                    break;

                case Amf3TypeMarker.String:
                    ReadString(context, reader, output);
                    break;

                case Amf3TypeMarker.Date:
                    ReadDate(context, reader, output);
                    break;

                case Amf3TypeMarker.ByteArray:
                    ReadByteArray(context, reader, output);
                    break;

                case Amf3TypeMarker.Xml:
                case Amf3TypeMarker.XmlDocument:
                    ReadXml(context, reader, output);
                    break;

                case Amf3TypeMarker.Array:
                    ReadArray(context, reader, output);
                    break;

                case Amf3TypeMarker.Object:
                    ReadObject(context, reader, output);
                    break;

                default:
                    throw new NotSupportedException("Type '" + type + "' is not supported.");
            }

            if (output != null) output.Flush();
        }
示例#23
0
        /// <summary>
        /// Write an integer.
        /// </summary>
        private static void WriteReference(AmfContext context, AmfStreamWriter writer, XmlReader input)
        {
            var index = Convert.ToInt32(input.GetAttribute(AmfxContent.ReferenceId), CultureInfo.InvariantCulture);
            var proxy = context.References[index];

            switch(proxy.AmfxType)
            {
                case AmfxContent.Date:
                    WriteTypeMarker(writer, Amf3TypeMarker.Date);
                    break;

                case AmfxContent.Xml:
                    WriteTypeMarker(writer, Amf3TypeMarker.Xml);
                    break;

                case AmfxContent.Array:
                    WriteTypeMarker(writer, Amf3TypeMarker.Array);
                    break;

                case AmfxContent.ByteArray:
                    WriteTypeMarker(writer, Amf3TypeMarker.ByteArray);
                    break;

                case AmfxContent.Object:
                    WriteTypeMarker(writer, Amf3TypeMarker.Object);
                    break;

                default:
                    throw new InvalidOperationException(string.Format("AMFX type '{0}' cannot be send by reference.", proxy.AmfxType));
            }

            WriteReference(writer, index);
        }
示例#24
0
        /// <summary>
        /// Read a string.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>U29S-ref = U29 (The first (low) bit is a flag with value 0. The remaining 1 to 28
        /// significant bits are used to encode a string reference table index (an integer)).
        /// U29S-value = U29 (The first (low) bit is a flag with value 1. The remaining 1 to 28 significant 
        /// bits are used to encode the byte-length of the UTF-8 encoded representation of the string).
        /// UTF-8-empty = 0x01 (The UTF-8-vr empty string which is never sent by reference).
        /// UTF-8-vr = U29S-ref | (U29S-value *(UTF8-char))
        /// string-type = string-marker UTF-8-vr</c>
        /// </remarks>
        private static string ReadString(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            int index, reference;
            string cache;

            if ((cache = ReadStringReference(context, reader, out index, out reference)) != null)
            {
                if (output != null)
                {
                    output.WriteStartElement(AmfxContent.String);
                    output.WriteAttributeString(AmfxContent.StringId, index.ToString());
                    output.WriteEndElement();
                }

                return cache;
            }

            //Get string length
            var length = (reference >> 1);
            var value = ReadUtf8(reader, length);

            if (value != string.Empty)
                context.StringReferences.Add(value);

            if (output != null)
            {
                output.WriteStartElement(AmfxContent.String);
                output.WriteValue(value);
                output.WriteEndElement();
            }

            return value;
        }
示例#25
0
        /// <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);
        }
示例#26
0
        /// <summary>
        /// Read a date.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>U29D-value = U29 (The first (low) bit is a flag with value 1.
        /// The remaining bits are not used).
        /// date-time = DOUBLE (A 64-bit integer value transported as a double).
        /// date-type = date-marker (U29O-ref | (U29D-value date-time))</c>
        /// </remarks>
        private static void ReadDate(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            int index, reference;

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

            context.References.Track();

            //Dates are represented as an Unix time stamp, but in milliseconds
            var milliseconds = reader.ReadDouble();
            var value = milliseconds.ToString();

            if (output != null)
            {
                output.WriteStartElement(AmfxContent.Date);
                output.WriteValue(value);
                output.WriteEndElement();
            }
        }
示例#27
0
        /// <summary>
        /// Write an array.
        /// </summary>
        private void WriteArray(AmfContext context, AmfStreamWriter writer, XmlReader input)
        {
            context.References.Add(new AmfReference { AmfxType = AmfxContent.Array });
            WriteTypeMarker(writer, Amf3TypeMarker.Array);

            var length = Convert.ToInt32(input.GetAttribute(AmfxContent.ArrayLength), CultureInfo.InvariantCulture);

            //The first bit is a flag with value 1.
            //The remaining 1 to 28 significant bits
            //are used to encode the count of the dense
            //portion of the Array.
            var size = (length << 1) | 0x1;
            WriteUInt29(writer, size);

            WriteUtf8(context, writer, string.Empty); //No associative values

            if (length == 0) return;

            input.Read();

            for (var i = 0; i < length; i++)
            {
                WriteAmfValue(context, input, writer);
                input.Read();
            }
        }
示例#28
0
        /// <summary>
        /// Read a byte array.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>U29B-value = U29 (The first (low) bit is a flag with value 1.
        /// The remaining 1 to 28 significant bits are used to encode the
        /// byte-length of the ByteArray).
        /// bytearray-type = bytearray-marker (U29O-ref | U29B-value *(U8))</c>
        /// </remarks>
        private static void ReadByteArray(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            int index, reference;

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

            context.References.Track();

            //Get array length
            var length = (reference >> 1);
            var data = length == 0 ? new byte[] { } : reader.ReadBytes(length);
            var value = Convert.ToBase64String(data);

            if (output != null)
            {
                output.WriteStartElement(AmfxContent.ByteArray);
                output.WriteValue(value);
                output.WriteEndElement();
            }
        }
示例#29
0
        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
        }
示例#30
0
        /// <summary>
        /// Read object properties map.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker)</c>
        /// </remarks>
        /// <exception cref="SerializationException"></exception>
        private IList<string> ReadPropertiesMap(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            try
            {
                var result = new List<string>();
                var property = ReadString(reader); //Read first property's name

                //An empty property name indicates that object's declaration ends here
                while (property != string.Empty)
                {
                    result.Add(property);

                    ReadAmfValue(context, reader, output);
                    property = ReadString(reader);
                }

                //Last byte is always an "ObjectEnd" marker
                var marker = (Amf0TypeMarker)reader.ReadByte();

                //Something goes wrong
                if (marker != Amf0TypeMarker.ObjectEnd)
                    throw new FormatException(Errors.Amf0Decoder_ReadPropertiesMap_UnexpectedObjectEnd);

                return result;
            }
            catch (Exception e)
            {
                throw new SerializationException(Errors.Amf0Decoder_ReadPropertiesMap_UnableToDeserialize, e);
            }
        }