AMF stream reader.
Inheritance: System.IO.BinaryReader
Example #1
0
        /// <summary>
        /// Decode an AMF packet into an AMFX format.
        /// </summary>
        /// <exception cref="FormatException">Error during decoding.</exception>
        public void Decode(Stream stream, XmlWriter output)
        {
            if (stream == null) throw new ArgumentNullException("stream");
            if (!stream.CanRead) throw new ArgumentException(Errors.AmfPacketReader_Read_StreamClosed, "stream");
            if (output == null) throw new ArgumentNullException("output");

            try
            {
                var amfStreamReader = new AmfStreamReader(stream);

                var version = ReadPacketVersion(amfStreamReader);
                var decoder = CreateDecoder(version, _options);

                output.WriteStartDocument();
                output.WriteStartElement(AmfxContent.AmfxDocument, AmfxContent.Namespace);
                output.WriteAttributeString(AmfxContent.VersionAttribute, version.ToAmfxName());
                output.Flush();

                //Read headers
                var headerCount = ReadDataCount(amfStreamReader);

                for (var i = 0; i < headerCount; i++)
                {
                    var header = decoder.ReadPacketHeader(stream);

                    output.WriteStartElement(AmfxContent.PacketHeader);
                    output.WriteAttributeString(AmfxContent.PacketHeaderName, header.Name);
                    output.WriteAttributeString(AmfxContent.PacketHeaderMustUnderstand, header.MustUnderstand.ToString());
                    decoder.Decode(stream, output);
                    output.WriteEndElement();
                    output.Flush();
                }

                //Read messages
                var messageCount = ReadDataCount(amfStreamReader);

                for (var i = 0; i < messageCount; i++)
                {
                    var body = decoder.ReadPacketBody(stream);

                    output.WriteStartElement(AmfxContent.PacketBody);
                    output.WriteAttributeString(AmfxContent.PacketBodyTarget, body.Target);
                    output.WriteAttributeString(AmfxContent.PacketBodyResponse, body.Response);
                    decoder.Decode(stream, output);
                    output.WriteEndElement();
                    output.Flush();
                }

                output.WriteEndElement();
                output.WriteEndDocument();
                output.Flush();
            }
            catch (Exception e)
            {
                output.Flush();
                throw new FormatException(Errors.AmfPacketReader_DecodingError, e);
            }
        }
Example #2
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;
        }
Example #3
0
        public override sealed AmfHeaderDescriptor ReadPacketHeader(Stream stream)
        {
            var reader = new AmfStreamReader(stream);
            var context = CreateDefaultContext();

            try
            {
                var descriptor = new AmfHeaderDescriptor
                                     {
                                         Name = ReadString(reader),
                                         MustUnderstand = reader.ReadBoolean()
                                     };

                reader.ReadInt32(); //Header length

                context.ResetReferences();
                return descriptor;
            }
            catch (Exception e)
            {
                throw new FormatException(Errors.Amf0Deserializer_ReadPacketHeaders_InvalidFormat, e);
            }
        }
Example #4
0
        public override sealed AmfMessageDescriptor ReadPacketBody(Stream stream)
        {
            var reader = new AmfStreamReader(stream);
            var context = CreateDefaultContext();

            try
            {
                var descriptor = new AmfMessageDescriptor
                                     {
                                         Target = ReadString(reader),
                                         Response = ReadString(reader)
                                     };

                reader.ReadInt32(); //Message length

                context.ResetReferences();
                return descriptor;
            }
            catch (Exception e)
            {
                throw new FormatException(Errors.Amf0Deserializer_ReadPacketMessages_InvalidFormat, e);
            }
        }
Example #5
0
        /// <summary>
        /// Read an XML document.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>xml-document-type = xml-document-marker UTF-8-long</c>
        /// </remarks>
        private static void ReadXml(AmfStreamReader reader, XmlWriter output = null)
        {
            var data = ReadLongString(reader); //XML is stored as a long string

            if (output != null)
            {
                var rawData = Encoding.UTF8.GetBytes(data);
                var value = Convert.ToBase64String(rawData);
                output.WriteStartElement(AmfxContent.Xml);
                output.WriteValue(value);
                output.WriteEndElement();
            }
        }
Example #6
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();
        }
Example #7
0
 override public void Decode(Stream stream, XmlWriter output)
 {
     var reader = new AmfStreamReader(stream);
     var context = CreateDefaultContext();
     ReadAmfValue(context, reader, output);
 }
Example #8
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();
            }
        }
Example #9
0
        /// <summary>
        /// Read a double.
        /// </summary>
        private static void ReadDouble(AmfStreamReader reader, XmlWriter output = null)
        {
            var value = reader.ReadDouble();

            if (output != null)
            {
                if (value <= MinInt29Value || value >= MaxInt29Value && Math.Abs(value - Math.Round(value)) < MinDoublePrecision)
                {
                    var integer = Convert.ToInt32(value);
                    output.WriteStartElement(AmfxContent.Integer);
                    output.WriteValue(integer);
                }
                else
                {
                    output.WriteStartElement(AmfxContent.Double);
                    output.WriteValue(value);
                }

                output.WriteEndElement();
            }
        }
Example #10
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();
        }
Example #11
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();
        }
Example #12
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();
        }
Example #13
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);
            }
        }
Example #14
0
        /// <summary>
        /// Read an object.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker)
        /// anonymous-object-type = object-marker *(object-property)</c>
        /// </remarks>
        private void ReadObject(AmfContext context, AmfStreamReader reader, XmlWriter output = null, bool isTyped = false)
        {
            context.References.Track();

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

                //Read properties
                using (var ms = new MemoryStream())
                {
                    var buffer = XmlWriter.Create(ms);
                    buffer.WriteStartElement("buffer");
                    buffer.WriteAttributeString("xmlns", AmfxContent.Namespace);

                    var members = ReadPropertiesMap(context, reader);

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

                    if (isTyped)
                    {
                        var typeName = ReadString(reader);
                        output.WriteAttributeString(AmfxContent.ObjectType, typeName);
                    }

                    output.WriteStartElement(AmfxContent.Traits);

                    //Write traits
                    foreach (var classMember in members)
                    {
                        output.WriteStartElement(AmfxContent.String);
                        output.WriteValue(classMember);
                        output.WriteEndElement();
                    }

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

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

                output.WriteEndElement(); //End of object
            }
            else
            {
                //Just read the object's properties
                ReadPropertiesMap(context ,reader);
                if(isTyped) ReadString(reader);
            }
        }
Example #15
0
        /// <summary>
        /// Read an ECMA array.
        /// </summary>
        /// <remarks>
        /// Type declaration:
        /// <c>associative-count = U32
        /// ecma-array-type = associative-count *(object-property)</c>
        /// </remarks>
        private void ReadEcmaArray(AmfContext context, AmfStreamReader reader, XmlWriter output = null)
        {
            context.References.Track();

            reader.ReadUInt32(); //Read properties count
            ReadObject(context, reader, output);
        }
Example #16
0
        /// <summary>
        /// Read a specified number of bytes of a string.
        /// </summary>
        /// <param name="reader">AMF reader.</param>
        /// <param name="length">Number of bytes to read.</param>
        private static string ReadUtf8(AmfStreamReader reader, int length)
        {
            if (length < 0) throw new ArgumentException(Errors.Amf3Deserializer_ReadString_NegativeLength, "length");

            //Make sure that a null is never returned
            if (length == 0) return string.Empty;

            var data = reader.ReadBytes(length);

            //All strings are encoded in UTF-8
            return Encoding.UTF8.GetString(data, 0, data.Length);
        }
Example #17
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
        }
Example #18
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);
        }
Example #19
0
        /// <summary>
        /// Read an integer.
        /// </summary>
        private static void ReadInteger(AmfStreamReader reader, XmlWriter output = null)
        {
            var value = ReadUint29(reader);

            const int mask = 1 << 28; //Integer sign mask
            value = -(value & mask) | value;

            if (output != null)
            {
                output.WriteStartElement(AmfxContent.Integer);
                output.WriteValue(value);
                output.WriteEndElement();
            }
        }
Example #20
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);
Example #21
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;
        }
Example #22
0
 /// <summary>
 /// Read number of following headers/messages.
 /// </summary>
 private static uint ReadDataCount(AmfStreamReader reader)
 {
     return reader.ReadUInt16();
 }
Example #23
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();
            }
        }
Example #24
0
 /// <summary>
 /// Read AMF packet version.
 /// </summary>
 /// <exception cref="FormatException">Data has unknown format.</exception>
 private static AmfVersion ReadPacketVersion(AmfStreamReader reader)
 {
     try
     {
         //First two bytes contain message version number
         return (AmfVersion)reader.ReadUInt16();
     }
     catch (Exception e)
     {
         throw new FormatException(Errors.AmfPacketReader_ReadPacketVersion_VersionReadError, e);
     }
 }
Example #25
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();
            }
        }
Example #26
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;
        }
Example #27
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
            }
        }
Example #28
0
        /// <summary>
        /// Read a 29-bit unsigned integer.
        /// </summary>
        /// <remarks>
        /// Up to 4 bytes are required to hold the value however the high bit 
        /// of the first 3 bytes are used as flags to determine 
        /// whether the next byte is part of the integer.
        /// <c>
        /// 0x00000000 - 0x0000007F : 0xxxxxxx
        /// 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx
        /// 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx
        /// 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx
        /// 0x40000000 - 0xFFFFFFFF : throw range exception
        /// </c>
        /// </remarks>
        private static int ReadUint29(AmfStreamReader reader)
        {
            const byte mask = 0x7F; //0111 1111
            var octet = reader.ReadByte() & 0xFF;

            //0xxxxxxx
            if (octet < 128) return octet;

            var result = (octet & mask) << 7;
            octet = reader.ReadByte() & 0xFF;

            //1xxxxxxx 0xxxxxxx
            if (octet < 128) return (result | octet);

            result = (result | (octet & mask)) << 7;
            octet = reader.ReadByte() & 0xFF;

            //1xxxxxxx 1xxxxxxx 0xxxxxxx
            if (octet < 128) return (result | octet);

            result = (result | (octet & mask)) << 8;
            octet = reader.ReadByte() & 0xFF;

            //1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx
            return (result | octet);
        }
Example #29
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;
        }
Example #30
0
        /// <summary>
        /// Read a specified number of bytes of a string.
        /// </summary>
        /// <param name="reader">AMF reader.</param>
        /// <param name="length">Number of bytes to read.</param>
        private static string ReadUtf8(AmfStreamReader reader, uint length)
        {
            //Make sure that a null is never returned
            if (length == 0) return string.Empty;

            var data = reader.ReadBytes((int)length);

            //All strings are encoded in UTF-8)
            return Encoding.UTF8.GetString(data, 0, data.Length);
        }