BinaryMessageEncoder.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / BinaryMessageEncoder.cs / 1 / BinaryMessageEncoder.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Channels
{ 
    using System.Collections.Generic;
    using System.ServiceModel; 
    using System.IO; 
    using System.Runtime.Serialization;
    using System.ServiceModel.Diagnostics; 
    using System.Text;
    using System.Xml;
    using System.Collections.ObjectModel;
 
    class BinaryMessageEncoderFactory : MessageEncoderFactory
    { 
        BinaryMessageEncoder messageEncoder; 
        MessageVersion messageVersion;
        int maxReadPoolSize; 
        int maxWritePoolSize;
        SynchronizedPool streamedWriterPool;
        SynchronizedPool streamedReaderPool;
        SynchronizedPool bufferedDataPool; 
        SynchronizedPool bufferedWriterPool;
        SynchronizedPool recycledStatePool; 
        object thisLock; 
        //bool running;
        const int maxPooledXmlReaderPerMessage = 2; 
        int maxSessionSize;
        OnXmlDictionaryReaderClose onStreamedReaderClose;
        XmlDictionaryReaderQuotas readerQuotas;
        BinaryVersion binaryVersion; 

        public BinaryMessageEncoderFactory(MessageVersion messageVersion, int maxReadPoolSize, int maxWritePoolSize, int maxSessionSize, 
            XmlDictionaryReaderQuotas readerQuotas, BinaryVersion version) 
        {
            this.messageVersion = messageVersion; 
            this.messageEncoder = new BinaryMessageEncoder(this, false, 0);
            this.maxReadPoolSize = maxReadPoolSize;
            this.maxWritePoolSize = maxWritePoolSize;
            this.maxSessionSize = maxSessionSize; 
            this.thisLock = new object();
            this.onStreamedReaderClose = new OnXmlDictionaryReaderClose(ReturnStreamedReader); 
            this.readerQuotas = new XmlDictionaryReaderQuotas(); 
            if (readerQuotas != null)
                readerQuotas.CopyTo(this.readerQuotas); 
            this.binaryVersion = version;
        }

        public override MessageEncoder Encoder 
        {
            get 
            { 
                return messageEncoder;
            } 
        }

        public override MessageVersion MessageVersion
        { 
            get { return messageVersion; }
        } 
 
        object ThisLock
        { 
            get { return thisLock; }
        }

        public static IXmlDictionary XmlDictionary 
        {
            get { return XD.Dictionary; } 
        } 

        public int MaxWritePoolSize 
        {
            get { return maxWritePoolSize; }
        }
 
        public XmlDictionaryReaderQuotas ReaderQuotas
        { 
            get 
            {
                return readerQuotas; 
            }
        }

        public int MaxReadPoolSize 
        {
            get { return maxReadPoolSize; } 
        } 

        public int MaxSessionSize 
        {
            get { return maxSessionSize; }
        }
 
        public override MessageEncoder CreateSessionEncoder()
        { 
            return new BinaryMessageEncoder(this, true, maxSessionSize); 
        }
 
        XmlDictionaryWriter TakeStreamedWriter(Stream stream)
        {
            if (streamedWriterPool == null)
            { 
                lock (ThisLock)
                { 
                    if (streamedWriterPool == null) 
                    {
                        //running = true; 
                        streamedWriterPool = new SynchronizedPool(maxWritePoolSize);
                    }
                }
            } 
            XmlDictionaryWriter xmlWriter = streamedWriterPool.Take();
            if (xmlWriter == null) 
                xmlWriter = XmlDictionaryWriter.CreateBinaryWriter(stream, binaryVersion.Dictionary, null, false); 
            else
                ((IXmlBinaryWriterInitializer)xmlWriter).SetOutput(stream, binaryVersion.Dictionary, null, false); 
            return xmlWriter;
        }

        void ReturnStreamedWriter(XmlDictionaryWriter xmlWriter) 
        {
            xmlWriter.Close(); 
            streamedWriterPool.Return(xmlWriter); 
        }
 
        BinaryBufferedMessageWriter TakeBufferedWriter()
        {
            if (bufferedWriterPool == null)
            { 
                lock (ThisLock)
                { 
                    if (bufferedWriterPool == null) 
                    {
                        //running = true; 
                        bufferedWriterPool = new SynchronizedPool(maxWritePoolSize);
                    }
                }
            } 

            BinaryBufferedMessageWriter messageWriter = bufferedWriterPool.Take(); 
            if (messageWriter == null) 
                messageWriter = new BinaryBufferedMessageWriter(binaryVersion.Dictionary);
            return messageWriter; 
        }

        void ReturnMessageWriter(BinaryBufferedMessageWriter messageWriter)
        { 
            bufferedWriterPool.Return(messageWriter);
        } 
 
        XmlDictionaryReader TakeStreamedReader(Stream stream)
        { 
            if (streamedReaderPool == null)
            {
                lock (ThisLock)
                { 
                    if (streamedReaderPool == null)
                    { 
                        //running = true; 
                        streamedReaderPool = new SynchronizedPool(maxReadPoolSize);
                    } 
                }
            }

            XmlDictionaryReader xmlReader = streamedReaderPool.Take(); 
            if (xmlReader == null)
            { 
                xmlReader = XmlDictionaryReader.CreateBinaryReader(stream, 
                                                                   binaryVersion.Dictionary,
                                                                   readerQuotas, 
                                                                   null,
                                                                   onStreamedReaderClose);
            }
            else 
            {
                ((IXmlBinaryReaderInitializer)xmlReader).SetInput(stream, 
                                                                  binaryVersion.Dictionary, 
                                                                  readerQuotas,
                                                                  null, 
                                                                  onStreamedReaderClose);
            }

            return xmlReader; 
        }
 
        void ReturnStreamedReader(XmlDictionaryReader xmlReader) 
        {
            streamedReaderPool.Return(xmlReader); 
        }

        BinaryBufferedMessageData TakeBufferedData(BinaryMessageEncoder messageEncoder)
        { 
            if (bufferedDataPool == null)
            { 
                lock (ThisLock) 
                {
                    if (bufferedDataPool == null) 
                    {
                        //running = true;
                        bufferedDataPool = new SynchronizedPool(maxReadPoolSize);
                    } 
                }
            } 
            BinaryBufferedMessageData messageData = bufferedDataPool.Take(); 
            if (messageData == null)
                messageData = new BinaryBufferedMessageData(this, maxPooledXmlReaderPerMessage); 
            messageData.SetMessageEncoder(messageEncoder);
            return messageData;
        }
 
        void ReturnBufferedData(BinaryBufferedMessageData messageData)
        { 
            messageData.SetMessageEncoder(null); 
            bufferedDataPool.Return(messageData);
        } 

        SynchronizedPool RecycledStatePool
        {
            get 
            {
                if (recycledStatePool == null) 
                { 
                    lock (ThisLock)
                    { 
                        if (recycledStatePool == null)
                        {
                            //running = true;
                            recycledStatePool = new SynchronizedPool(maxReadPoolSize); 
                        }
                    } 
                } 
                return recycledStatePool;
            } 
        }

        class BinaryBufferedMessageData : BufferedMessageData
        { 
            BinaryMessageEncoderFactory factory;
            BinaryMessageEncoder messageEncoder; 
            Pool readerPool; 
            OnXmlDictionaryReaderClose onClose;
 
            public BinaryBufferedMessageData(BinaryMessageEncoderFactory factory, int maxPoolSize)
                : base(factory.RecycledStatePool)
            {
                this.factory = factory; 
                readerPool = new Pool(maxPoolSize);
                onClose = new OnXmlDictionaryReaderClose(OnXmlReaderClosed); 
            } 

            public override MessageEncoder MessageEncoder 
            {
                get { return messageEncoder; }
            }
 
            public override XmlDictionaryReaderQuotas Quotas
            { 
                get { return factory.readerQuotas; } 
            }
 
            public void SetMessageEncoder(BinaryMessageEncoder messageEncoder)
            {
                this.messageEncoder = messageEncoder;
            } 

            protected override XmlDictionaryReader TakeXmlReader() 
            { 
                ArraySegment buffer = this.Buffer;
                XmlDictionaryReader xmlReader = readerPool.Take(); 

                if (xmlReader != null)
                {
                    ((IXmlBinaryReaderInitializer)xmlReader).SetInput(buffer.Array, buffer.Offset, buffer.Count, 
                                                                      factory.binaryVersion.Dictionary,
                                                                      factory.readerQuotas, 
                                                                      messageEncoder.ReaderSession, 
                                                                      onClose);
                } 
                else
                {
                    xmlReader = XmlDictionaryReader.CreateBinaryReader(buffer.Array, buffer.Offset, buffer.Count,
                                                                       factory.binaryVersion.Dictionary, 
                                                                       factory.readerQuotas,
                                                                       messageEncoder.ReaderSession, 
                                                                       onClose); 
                }
 
                return xmlReader;
            }

            protected override void ReturnXmlReader(XmlDictionaryReader reader) 
            {
                readerPool.Return(reader); 
            } 

            protected override void OnClosed() 
            {
                factory.ReturnBufferedData(this);
            }
        } 

        class BinaryBufferedMessageWriter : BufferedMessageWriter 
        { 
            XmlDictionaryWriter writer;
            IXmlDictionary dictionary; 
            XmlBinaryWriterSession session;

            public BinaryBufferedMessageWriter(IXmlDictionary dictionary)
            { 
                this.dictionary = dictionary;
            } 
 
            public BinaryBufferedMessageWriter(IXmlDictionary dictionary, XmlBinaryWriterSession session)
            { 
                this.dictionary = dictionary;
                this.session = session;
            }
 
            protected override XmlDictionaryWriter TakeXmlWriter(Stream stream)
            { 
                XmlDictionaryWriter returnedWriter = writer; 
                if (returnedWriter == null)
                { 
                    returnedWriter = XmlDictionaryWriter.CreateBinaryWriter(stream, dictionary, session, false);
                }
                else
                { 
                    writer = null;
                    ((IXmlBinaryWriterInitializer)returnedWriter).SetOutput(stream, dictionary, session, false); 
                } 
                return returnedWriter;
            } 

            protected override void ReturnXmlWriter(XmlDictionaryWriter writer)
            {
                writer.Close(); 

                if (this.writer == null) 
                    this.writer = writer; 
            }
        } 

        class BinaryMessageEncoder : MessageEncoder
        {
            BinaryMessageEncoderFactory factory; 
            bool isSession;
            XmlBinaryWriterSessionWithQuota writerSession; 
            BinaryBufferedMessageWriter sessionMessageWriter; 
            XmlBinaryReaderSession readerSession;
            XmlBinaryReaderSession readerSessionForLogging; 
            bool readerSessionForLoggingIsInvalid = false;
            int writeIdCounter;
            int idCounter;
            int maxSessionSize; 
            int remainingReaderSessionSize;
            bool isReaderSessionInvalid; 
            MessagePatterns messagePatterns; 

            public BinaryMessageEncoder(BinaryMessageEncoderFactory factory, bool isSession, int maxSessionSize) 
            {
                this.factory = factory;
                this.isSession = isSession;
                this.maxSessionSize = maxSessionSize; 
                this.remainingReaderSessionSize = maxSessionSize;
            } 
 
            public override string ContentType
            { 
                get { return isSession ? factory.binaryVersion.SessionContentType : factory.binaryVersion.ContentType; }
            }

            public override MessageVersion MessageVersion 
            {
                get { return factory.messageVersion; } 
            } 

            public override string MediaType 
            {
                get { return isSession ? factory.binaryVersion.SessionContentType : factory.binaryVersion.ContentType; }
            }
 
            public XmlBinaryReaderSession ReaderSession
            { 
                get { return readerSession; } 
            }
 
            ArraySegment AddSessionInformationToMessage(ArraySegment messageData, BufferManager bufferManager, int maxMessageSize)
            {
                int dictionarySize = 0;
                byte[] buffer = messageData.Array; 

                if (writerSession.HasNewStrings) 
                { 
                    IList newStrings = writerSession.GetNewStrings();
                    for (int i = 0; i < newStrings.Count; i++) 
                    {
                        int utf8ValueSize = Encoding.UTF8.GetByteCount(newStrings[i].Value);
                        dictionarySize += IntEncoder.GetEncodedSize(utf8ValueSize) + utf8ValueSize;
                    } 

                    int messageSize = messageData.Offset + messageData.Count; 
                    int remainingMessageSize = maxMessageSize - messageSize; 
                    if (remainingMessageSize - dictionarySize < 0)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QuotaExceededException(SR.GetString(SR.MaxSentMessageSizeExceeded, maxMessageSize)));
                    }

                    int requiredBufferSize = messageData.Offset + messageData.Count + dictionarySize; 
                    if (buffer.Length < requiredBufferSize)
                    { 
                        byte[] newBuffer = bufferManager.TakeBuffer(requiredBufferSize); 
                        Buffer.BlockCopy(buffer, messageData.Offset, newBuffer, messageData.Offset, messageData.Count);
                        bufferManager.ReturnBuffer(buffer); 
                        buffer = newBuffer;
                    }

                    Buffer.BlockCopy(buffer, messageData.Offset, buffer, messageData.Offset + dictionarySize, messageData.Count); 

                    int offset = messageData.Offset; 
                    for (int i = 0; i < newStrings.Count; i++) 
                    {
                        string newString = newStrings[i].Value; 
                        int utf8ValueSize = Encoding.UTF8.GetByteCount(newString);
                        offset += IntEncoder.Encode(utf8ValueSize, buffer, offset);
                        offset += Encoding.UTF8.GetBytes(newString, 0, newString.Length, buffer, offset);
                    } 

                    writerSession.ClearNewStrings(); 
                } 

                int headerSize = IntEncoder.GetEncodedSize(dictionarySize); 
                int newOffset = messageData.Offset - headerSize;
                int newSize = headerSize + messageData.Count + dictionarySize;
                IntEncoder.Encode(dictionarySize, buffer, newOffset);
                return new ArraySegment(buffer, newOffset, newSize); 
            }
 
            ArraySegment ExtractSessionInformationFromMessage(ArraySegment messageData) 
            {
                if (isReaderSessionInvalid) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.GetString(SR.BinaryEncoderSessionInvalid)));
                }
 
                byte[] buffer = messageData.Array;
                int dictionarySize; 
                int headerSize; 
                int newOffset;
                int newSize; 
                bool throwing = true;
                try
                {
                    IntDecoder decoder = new IntDecoder(); 
                    headerSize = decoder.Decode(buffer, messageData.Offset, messageData.Count);
                    dictionarySize = decoder.Value; 
                    if (dictionarySize > messageData.Count) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.GetString(SR.BinaryEncoderSessionMalformed))); 
                    }
                    newOffset = messageData.Offset + headerSize + dictionarySize;
                    newSize = messageData.Count - headerSize - dictionarySize;
                    if (newSize < 0) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.GetString(SR.BinaryEncoderSessionMalformed))); 
                    } 
                    if (dictionarySize > 0)
                    { 
                        if (dictionarySize > remainingReaderSessionSize)
                        {
                            string message = SR.GetString(SR.BinaryEncoderSessionTooLarge, this.maxSessionSize);
                            Exception inner = new QuotaExceededException(message); 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(message, inner));
                        } 
                        else 
                        {
                            remainingReaderSessionSize -= dictionarySize; 
                        }

                        int size = dictionarySize;
                        int offset = messageData.Offset + headerSize; 

                        while (size > 0) 
                        { 
                            decoder.Reset();
                            int bytesDecoded = decoder.Decode(buffer, offset, size); 
                            int utf8ValueSize = decoder.Value;
                            offset += bytesDecoded;
                            size -= bytesDecoded;
                            if (utf8ValueSize > size) 
                            {
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.GetString(SR.BinaryEncoderSessionMalformed))); 
                            } 
                            string value = Encoding.UTF8.GetString(buffer, offset, utf8ValueSize);
                            offset += utf8ValueSize; 
                            size -= utf8ValueSize;
                            readerSession.Add(idCounter, value);
                            idCounter++;
                        } 
                    }
                    throwing = false; 
                } 
                finally
                { 
                    if (throwing)
                    {
                        isReaderSessionInvalid = true;
                    } 
                }
 
                return new ArraySegment(buffer, newOffset, newSize); 
            }
 
            public override Message ReadMessage(ArraySegment buffer, BufferManager bufferManager, string contentType)
            {
                if (bufferManager == null)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("bufferManager");
                } 
 
                if (contentType != null && contentType != this.ContentType && string.Compare(contentType, this.ContentType, StringComparison.OrdinalIgnoreCase) != 0)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.EncoderUnrecognizedContentType, contentType, this.ContentType)));
                }

                if (isSession) 
                {
                    if (readerSession == null) 
                    { 
                        readerSession = new XmlBinaryReaderSession();
                        messagePatterns = new MessagePatterns(factory.binaryVersion.Dictionary, readerSession, this.MessageVersion); 
                    }
                    try
                    {
                        buffer = ExtractSessionInformationFromMessage(buffer); 
                    }
                    catch (InvalidDataException) 
                    { 
                        MessageLogger.LogMessage(buffer, MessageLoggingSource.Malformed);
                        throw; 
                    }
                }
                BinaryBufferedMessageData messageData = factory.TakeBufferedData(this);
                Message message; 
                if (messagePatterns != null)
                { 
                    message = messagePatterns.TryCreateMessage(buffer.Array, buffer.Offset, buffer.Count, bufferManager, messageData); 
                }
                else 
                {
                    message = null;
                }
                if (message == null) 
                {
                    messageData.Open(buffer, bufferManager); 
                    RecycledMessageState messageState = messageData.TakeMessageState(); 
                    if (messageState == null)
                        messageState = new RecycledMessageState(); 
                    message = new BufferedMessage(messageData, messageState);
                }
                message.Properties.Encoder = this;
                if (MessageLogger.LogMessagesAtTransportLevel) 
                {
                    MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive); 
                } 
                return message;
            } 

            public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
            {
                if (stream == null) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream"); 
                } 

                if (contentType != null && contentType != this.ContentType && string.Compare(contentType, this.ContentType, StringComparison.OrdinalIgnoreCase) != 0) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.EncoderUnrecognizedContentType, contentType, this.ContentType)));
                }
 
                XmlDictionaryReader reader = factory.TakeStreamedReader(stream);
                Message message = Message.CreateMessage(reader, maxSizeOfHeaders, factory.messageVersion); 
                message.Properties.Encoder = this; 
                if (MessageLogger.LogMessagesAtTransportLevel)
                { 
                    MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
                }
                return message;
            } 

            public override ArraySegment WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset) 
            { 
                if (message == null)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
                }

                if (bufferManager == null) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("bufferManager"); 
                } 

                if (maxMessageSize < 0) 
                {

                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxMessageSize", maxMessageSize,
                                                                        SR.GetString(SR.ValueMustBeNonNegative))); 
                }
 
                message.Properties.Encoder = this; 

                if (isSession) 
                {
                    if (writerSession == null)
                    {
                        writerSession = new XmlBinaryWriterSessionWithQuota(maxSessionSize); 
                        sessionMessageWriter = new BinaryBufferedMessageWriter(factory.binaryVersion.Dictionary, writerSession);
                    } 
                    messageOffset += IntEncoder.MaxEncodedSize; 
                }
 
                if (messageOffset < 0)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("messageOffset", messageOffset,
                                                                        SR.GetString(SR.ValueMustBeNonNegative))); 
                }
 
                if (messageOffset > maxMessageSize) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QuotaExceededException(SR.GetString(SR.MaxSentMessageSizeExceeded, maxMessageSize))); 
                }

                ThrowIfMismatchedMessageVersion(message);
                BinaryBufferedMessageWriter messageWriter; 
                if (isSession)
                { 
                    messageWriter = sessionMessageWriter; 
                }
                else 
                {
                    messageWriter = factory.TakeBufferedWriter();
                }
                ArraySegment messageData = messageWriter.WriteMessage(message, bufferManager, messageOffset, maxMessageSize); 

                if (MessageLogger.LogMessagesAtTransportLevel && !this.readerSessionForLoggingIsInvalid) 
                { 
                    if (isSession)
                    { 
                        if (this.readerSessionForLogging == null)
                        {
                            this.readerSessionForLogging = new XmlBinaryReaderSession();
                        } 
                        if (this.writerSession.HasNewStrings)
                        { 
                            foreach (XmlDictionaryString xmlDictionaryString in this.writerSession.GetNewStrings()) 
                            {
                                this.readerSessionForLogging.Add(this.writeIdCounter++, xmlDictionaryString.Value); 
                            }
                        }
                    }
                XmlDictionaryReader xmlDictionaryReader = XmlDictionaryReader.CreateBinaryReader(messageData.Array, messageData.Offset, messageData.Count, XD.Dictionary, XmlDictionaryReaderQuotas.Max, this.readerSessionForLogging, null); 
                MessageLogger.LogMessage(ref message, xmlDictionaryReader, MessageLoggingSource.TransportSend);
            } 
            else 
            {
                this.readerSessionForLoggingIsInvalid = true; 
            }
            if (isSession)
                {
                    messageData = AddSessionInformationToMessage(messageData, bufferManager, maxMessageSize); 
                }
                else 
                { 
                    factory.ReturnMessageWriter(messageWriter);
                } 
                return messageData;
            }

            public override void WriteMessage(Message message, Stream stream) 
            {
                if (message == null) 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message")); 
                if (stream == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream")); 
                ThrowIfMismatchedMessageVersion(message);
                message.Properties.Encoder = this;
                XmlDictionaryWriter xmlWriter = factory.TakeStreamedWriter(stream);
                message.WriteMessage(xmlWriter); 
                xmlWriter.Flush();
                factory.ReturnStreamedWriter(xmlWriter); 
                if (MessageLogger.LogMessagesAtTransportLevel) 
                {
                    MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend); 
                }
            }
        }
 
        class XmlBinaryWriterSessionWithQuota : XmlBinaryWriterSession
        { 
            int bytesRemaining; 
            List newStrings;
 
            public XmlBinaryWriterSessionWithQuota(int maxSessionSize)
            {
                bytesRemaining = maxSessionSize;
            } 

            public override bool TryAdd(XmlDictionaryString s, out int key) 
            { 
                if (bytesRemaining == 0)
                { 
                    key = -1;
                    return false;
                }
 
                int bytesRequired = Encoding.UTF8.GetByteCount(s.Value);
                bytesRequired += IntEncoder.GetEncodedSize(bytesRequired); 
 
                if (bytesRequired > bytesRemaining)
                { 
                    key = -1;
                    bytesRemaining = 0;
                    return false;
                } 

                if (base.TryAdd(s, out key)) 
                { 
                    if (newStrings == null)
                    { 
                        newStrings = new List();
                    }
                    newStrings.Add(s);
                    bytesRemaining -= bytesRequired; 
                    return true;
                } 
                else 
                {
                    return false; 
                }
            }

            public bool HasNewStrings 
            {
                get { return newStrings != null; } 
            } 

            public IList GetNewStrings() 
            {
                return newStrings;
            }
 
            public void ClearNewStrings()
            { 
                newStrings = null; 
            }
        } 
    }

    class BinaryFormatBuilder
    { 
        List bytes;
 
        public BinaryFormatBuilder() 
        {
            this.bytes = new List(); 
        }

        public int Count
        { 
            get { return bytes.Count; }
        } 
 
        public void AppendPrefixDictionaryElement(char prefix, int key)
        { 
            this.AppendNode(XmlBinaryNodeType.PrefixDictionaryElementA + GetPrefixOffset(prefix));
            this.AppendKey(key);
        }
 
        public void AppendDictionaryXmlnsAttribute(char prefix, int key)
        { 
            this.AppendNode(XmlBinaryNodeType.DictionaryXmlnsAttribute); 
            this.AppendUtf8(prefix);
            this.AppendKey(key); 
        }

        public void AppendPrefixDictionaryAttribute(char prefix, int key, char value)
        { 
            this.AppendNode(XmlBinaryNodeType.PrefixDictionaryAttributeA + GetPrefixOffset(prefix));
            this.AppendKey(key); 
            if (value == '1') 
            {
                this.AppendNode(XmlBinaryNodeType.OneText); 
            }
            else
            {
                this.AppendNode(XmlBinaryNodeType.Chars8Text); 
                this.AppendUtf8(value);
            } 
        } 

        public void AppendDictionaryAttribute(char prefix, int key, char value) 
        {
            this.AppendNode(XmlBinaryNodeType.DictionaryAttribute);
            this.AppendUtf8(prefix);
            this.AppendKey(key); 
            this.AppendNode(XmlBinaryNodeType.Chars8Text);
            this.AppendUtf8(value); 
        } 

        public void AppendDictionaryTextWithEndElement(int key) 
        {
            this.AppendNode(XmlBinaryNodeType.DictionaryTextWithEndElement);
            this.AppendKey(key);
        } 

        public void AppendDictionaryTextWithEndElement() 
        { 
            this.AppendNode(XmlBinaryNodeType.DictionaryTextWithEndElement);
        } 

        public void AppendUniqueIDWithEndElement()
        {
            this.AppendNode(XmlBinaryNodeType.UniqueIdTextWithEndElement); 
        }
 
        public void AppendEndElement() 
        {
            this.AppendNode(XmlBinaryNodeType.EndElement); 
        }

        void AppendKey(int key)
        { 
            if (key < 0 || key >= 0x4000)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("key", key, 
                                                    SR.GetString(SR.ValueMustBeInRange, 0, 0x4000))); 
            if (key >= 0x80)
            { 
                this.AppendByte((key & 0x7f) | 0x80);
                this.AppendByte(key >> 7);
            }
            else 
            {
                this.AppendByte(key); 
            } 
        }
 
        void AppendNode(XmlBinaryNodeType value)
        {
            this.AppendByte((int)value);
        } 

        void AppendByte(int value) 
        { 
            if (value < 0 || value > 0xFF)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, 
                                                    SR.GetString(SR.ValueMustBeInRange, 0, 0xFF)));
            this.bytes.Add((byte)value);
        }
 
        void AppendUtf8(char value)
        { 
            AppendByte(1); 
            AppendByte((int)value);
        } 

        public int GetStaticKey(int value)
        {
            return value * 2; 
        }
 
        public int GetSessionKey(int value) 
        {
            return value * 2 + 1; 
        }

        int GetPrefixOffset(char prefix)
        { 
            if (prefix < 'a' && prefix > 'z')
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("prefix", prefix, 
                                                    SR.GetString(SR.ValueMustBeInRange, 'a', 'z'))); 
            return prefix - 'a';
        } 

        public byte[] ToByteArray()
        {
            byte[] array = this.bytes.ToArray(); 
            this.bytes.Clear();
            return array; 
        } 
    }
 
    static class BinaryFormatParser
    {
        public static bool IsSessionKey(int value)
        { 
            return (value & 1) != 0;
        } 
 
        public static int GetSessionKey(int value)
        { 
            return value / 2;
        }

        public static int GetStaticKey(int value) 
        {
            return value / 2; 
        } 

        public static int ParseInt32(byte[] buffer, int offset, int size) 
        {
            switch (size)
            {
                case 1: 
                    return buffer[offset];
                case 2: 
                    return (buffer[offset] & 0x7f) + (buffer[offset + 1] << 7); 
                case 3:
                    return (buffer[offset] & 0x7f) + ((buffer[offset + 1] & 0x7f) << 7) + (buffer[offset + 2] << 14); 
                case 4:
                    return (buffer[offset] & 0x7f) + ((buffer[offset + 1] & 0x7f) << 7) + ((buffer[offset + 2] & 0x7f) << 14) + (buffer[offset + 3] << 21);
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("size", size, 
                                                                            SR.GetString(SR.ValueMustBeInRange, 1, 4)));
            } 
        } 

        public static int ParseKey(byte[] buffer, int offset, int size) 
        {
            return ParseInt32(buffer, offset, size);
        }
 
        public unsafe static UniqueId ParseUniqueID(byte[] buffer, int offset, int size)
        { 
            return new UniqueId(buffer, offset); 
        }
 
        public static int MatchBytes(byte[] buffer, int offset, int size, byte[] buffer2)
        {
            if (size < buffer2.Length)
            { 
                return 0;
            } 
            int j = offset; 
            for (int i = 0; i < buffer2.Length; i++, j++)
            { 
                if (buffer2[i] != buffer[j])
                {
                    return 0;
                } 
            }
            return buffer2.Length; 
        } 

 
        public static bool MatchAttributeNode(byte[] buffer, int offset, int size)
        {
            const XmlBinaryNodeType minAttribute = XmlBinaryNodeType.ShortAttribute;
            const XmlBinaryNodeType maxAttribute = XmlBinaryNodeType.DictionaryAttribute; 
            if (size < 1)
                return false; 
            XmlBinaryNodeType nodeType = (XmlBinaryNodeType)buffer[offset]; 
            return nodeType >= minAttribute && nodeType <= maxAttribute;
        } 

        public static int MatchKey(byte[] buffer, int offset, int size)
        {
            return MatchInt32(buffer, offset, size); 
        }
 
        public static int MatchInt32(byte[] buffer, int offset, int size) 
        {
            if (size > 0) 
            {
                if ((buffer[offset] & 0x80) == 0)
                {
                    return 1; 
                }
            } 
            if (size > 1) 
            {
                if ((buffer[offset + 1] & 0x80) == 0) 
                {
                    return 2;
                }
            } 
            if (size > 2)
            { 
                if ((buffer[offset + 2] & 0x80) == 0) 
                {
                    return 3; 
                }
            }
            if (size > 3)
            { 
                if ((buffer[offset + 3] & 0x80) == 0)
                { 
                    return 4; 
                }
            } 

            return 0;
        }
 
        public static int MatchUniqueID(byte[] buffer, int offset, int size)
        { 
            if (size < 16) 
                return 0;
            return 16; 
        }
    }

    class MessagePatterns 
    {
        IXmlDictionary dictionary; 
        XmlBinaryReaderSession readerSession; 
        ToHeader toHeader;
        static readonly byte[] commonFragment;    //  
        static readonly byte[] requestFragment1;  // 
        static readonly byte[] requestFragment2;  // ...session-to-key
        static readonly byte[] responseFragment1; // 
        static readonly byte[] responseFragment2; // static-anonymous-key 
        static readonly byte[] bodyFragment;      // 
        const int ToValueSessionKey = 1; 
        MessageVersion messageVersion; 

        public MessagePatterns(IXmlDictionary dictionary, XmlBinaryReaderSession readerSession, MessageVersion messageVersion) 
        {
            this.dictionary = dictionary;
            this.readerSession = readerSession;
            this.messageVersion = messageVersion; 
        }
 
        static MessagePatterns() 
        {
            BinaryFormatBuilder builder = new BinaryFormatBuilder(); 

            MessageDictionary messageDictionary = XD.MessageDictionary;
            Message12Dictionary message12Dictionary = XD.Message12Dictionary;
            AddressingDictionary addressingDictionary = XD.AddressingDictionary; 
            Addressing10Dictionary addressing10Dictionary = XD.Addressing10Dictionary;
 
            char messagePrefix = MessageStrings.Prefix[0]; 
            char addressingPrefix = AddressingStrings.Prefix[0];
 
            // 
            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Envelope.Key));
            builder.AppendDictionaryXmlnsAttribute(messagePrefix, builder.GetStaticKey(message12Dictionary.Namespace.Key));
            builder.AppendDictionaryXmlnsAttribute(addressingPrefix, builder.GetStaticKey(addressing10Dictionary.Namespace.Key)); 

            //  
            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Header.Key)); 

            // ... 
            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.Action.Key));
            builder.AppendPrefixDictionaryAttribute(messagePrefix, builder.GetStaticKey(messageDictionary.MustUnderstand.Key), '1');
            builder.AppendDictionaryTextWithEndElement();
            commonFragment = builder.ToByteArray(); 

            // ... 
            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.MessageId.Key)); 
            builder.AppendUniqueIDWithEndElement();
            requestFragment1 = builder.ToByteArray(); 

            // static-anonymous-key
            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.ReplyTo.Key));
            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.Address.Key)); 
            builder.AppendDictionaryTextWithEndElement(builder.GetStaticKey(addressing10Dictionary.Anonymous.Key));
            builder.AppendEndElement(); 
 
            // session-to-key
            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.To.Key)); 
            builder.AppendPrefixDictionaryAttribute(messagePrefix, builder.GetStaticKey(messageDictionary.MustUnderstand.Key), '1');
            builder.AppendDictionaryTextWithEndElement(builder.GetSessionKey(ToValueSessionKey));

            //  
            builder.AppendEndElement();
 
            //  
            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Body.Key));
            requestFragment2 = builder.ToByteArray(); 

            // ...
            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.RelatesTo.Key));
            builder.AppendUniqueIDWithEndElement(); 
            responseFragment1 = builder.ToByteArray();
 
            // static-anonymous-key 
            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.To.Key));
            builder.AppendPrefixDictionaryAttribute(messagePrefix, builder.GetStaticKey(messageDictionary.MustUnderstand.Key), '1'); 
            builder.AppendDictionaryTextWithEndElement(builder.GetStaticKey(addressing10Dictionary.Anonymous.Key));

            // 
            builder.AppendEndElement(); 

            //  
            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Body.Key)); 
            responseFragment2 = builder.ToByteArray();
 
            // 
            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Envelope.Key));
            builder.AppendDictionaryXmlnsAttribute(messagePrefix, builder.GetStaticKey(message12Dictionary.Namespace.Key));
            builder.AppendDictionaryXmlnsAttribute(addressingPrefix, builder.GetStaticKey(addressing10Dictionary.Namespace.Key)); 

            //  
            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Body.Key)); 
            bodyFragment = builder.ToByteArray();
        } 

        public Message TryCreateMessage(byte[] buffer, int offset, int size, BufferManager bufferManager, BufferedMessageData messageData)
        {
            RelatesToHeader relatesToHeader; 
            MessageIDHeader messageIDHeader;
            XmlDictionaryString toString; 
 
            int currentOffset = offset;
            int remainingSize = size; 

            int bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, commonFragment);
            if (bytesMatched == 0)
                return null; 
            currentOffset += bytesMatched;
            remainingSize -= bytesMatched; 
 
            bytesMatched = BinaryFormatParser.MatchKey(buffer, currentOffset, remainingSize);
            if (bytesMatched == 0) 
                return null;
            int actionOffset = currentOffset;
            int actionSize = bytesMatched;
            currentOffset += bytesMatched; 
            remainingSize -= bytesMatched;
 
            int totalBytesMatched; 

            bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, requestFragment1); 
            if (bytesMatched != 0)
            {
                currentOffset += bytesMatched;
                remainingSize -= bytesMatched; 

                bytesMatched = BinaryFormatParser.MatchUniqueID(buffer, currentOffset, remainingSize); 
                if (bytesMatched == 0) 
                    return null;
                int messageIDOffset = currentOffset; 
                int messageIDSize = bytesMatched;
                currentOffset += bytesMatched;
                remainingSize -= bytesMatched;
 
                bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, requestFragment2);
                if (bytesMatched == 0) 
                    return null; 
                currentOffset += bytesMatched;
                remainingSize -= bytesMatched; 

                if (BinaryFormatParser.MatchAttributeNode(buffer, currentOffset, remainingSize))
                    return null;
 
                UniqueId messageId = BinaryFormatParser.ParseUniqueID(buffer, messageIDOffset, messageIDSize);
                messageIDHeader = MessageIDHeader.Create(messageId, messageVersion.Addressing); 
                relatesToHeader = null; 

                if (!readerSession.TryLookup(ToValueSessionKey, out toString)) 
                    return null;

                totalBytesMatched = requestFragment1.Length + messageIDSize + requestFragment2.Length;
            } 
            else
            { 
                bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, responseFragment1); 

                if (bytesMatched == 0) 
                    return null;

                currentOffset += bytesMatched;
                remainingSize -= bytesMatched; 

                bytesMatched = BinaryFormatParser.MatchUniqueID(buffer, currentOffset, remainingSize); 
                if (bytesMatched == 0) 
                    return null;
                int messageIDOffset = currentOffset; 
                int messageIDSize = bytesMatched;
                currentOffset += bytesMatched;
                remainingSize -= bytesMatched;
 
                bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, responseFragment2);
                if (bytesMatched == 0) 
                    return null; 
                currentOffset += bytesMatched;
                remainingSize -= bytesMatched; 

                if (BinaryFormatParser.MatchAttributeNode(buffer, currentOffset, remainingSize))
                    return null;
 
                UniqueId messageId = BinaryFormatParser.ParseUniqueID(buffer, messageIDOffset, messageIDSize);
                relatesToHeader = RelatesToHeader.Create(messageId, messageVersion.Addressing); 
                messageIDHeader = null; 
                toString = XD.Addressing10Dictionary.Anonymous;
 
                totalBytesMatched = responseFragment1.Length + messageIDSize + responseFragment2.Length;
            }

            totalBytesMatched += commonFragment.Length + actionSize; 

            int actionKey = BinaryFormatParser.ParseKey(buffer, actionOffset, actionSize); 
 
            XmlDictionaryString actionString;
            if (!TryLookupKey(actionKey, out actionString)) 
                return null;

            ActionHeader actionHeader = ActionHeader.Create(actionString, messageVersion.Addressing);
 
            if (toHeader == null)
            { 
                toHeader = ToHeader.Create(new Uri(toString.Value), messageVersion.Addressing); 
            }
 
            int abandonedSize = totalBytesMatched - bodyFragment.Length;

            offset += abandonedSize;
            size -= abandonedSize; 

            Buffer.BlockCopy(bodyFragment, 0, buffer, offset, bodyFragment.Length); 
 
            messageData.Open(new ArraySegment(buffer, offset, size), bufferManager);
 
            PatternMessage patternMessage = new PatternMessage(messageData, this.messageVersion);

            MessageHeaders headers = patternMessage.Headers;
            headers.AddActionHeader(actionHeader); 
            if (messageIDHeader != null)
            { 
                headers.AddMessageIDHeader(messageIDHeader); 
                headers.AddReplyToHeader(ReplyToHeader.AnonymousReplyTo10);
            } 
            else
            {
                headers.AddRelatesToHeader(relatesToHeader);
            } 
            headers.AddToHeader(toHeader);
 
            return patternMessage; 
        }
 
        bool TryLookupKey(int key, out XmlDictionaryString result)
        {
            if (BinaryFormatParser.IsSessionKey(key))
            { 
                return readerSession.TryLookup(BinaryFormatParser.GetSessionKey(key), out result);
            } 
            else 
            {
                return dictionary.TryLookup(BinaryFormatParser.GetStaticKey(key), out result); 
            }
        }

        sealed class PatternMessage : ReceivedMessage 
        {
            IBufferedMessageData messageData; 
            MessageHeaders headers; 
            RecycledMessageState recycledMessageState;
            MessageProperties properties; 
            XmlDictionaryReader reader;

            public PatternMessage(IBufferedMessageData messageData, MessageVersion messageVersion)
            { 
                this.messageData = messageData;
                recycledMessageState = messageData.TakeMessageState(); 
                if (recycledMessageState == null) 
                    recycledMessageState = new RecycledMessageState();
                properties = recycledMessageState.TakeProperties(); 
                if (properties == null)
                    this.properties = new MessageProperties();
                headers = recycledMessageState.TakeHeaders();
                if (headers == null) 
                {
                    headers = new MessageHeaders(messageVersion); 
                } 
                else
                { 
                    headers.Init(messageVersion);
                }
                XmlDictionaryReader reader = messageData.GetMessageReader();
                reader.ReadStartElement(); 
                VerifyStartBody(reader, messageVersion.Envelope);
                ReadStartBody(reader); 
                this.reader = reader; 
            }
 
            public override MessageHeaders Headers
            {
                get
                { 
                    if (IsDisposed)
#pragma warning suppress 56503 // [....], Invalid State after dispose 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateMessageDisposedException()); 
                    return headers;
                } 
            }

            public override MessageProperties Properties
            { 
                get
                { 
                    if (IsDisposed) 
#pragma warning suppress 56503 // [....], Invalid State after dispose
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateMessageDisposedException()); 
                    return properties;
                }
            }
 
            internal override RecycledMessageState RecycledMessageState
            { 
                get { return recycledMessageState; } 
            }
 
            public override MessageVersion Version
            {
                get
                { 
                    if (IsDisposed)
#pragma warning suppress 56503 // [....], Invalid State after dispose 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateMessageDisposedException()); 
                    return headers.MessageVersion;
                } 
            }

            XmlDictionaryReader GetBufferedReaderAtBody()
            { 
                XmlDictionaryReader reader = messageData.GetMessageReader();
                reader.ReadStartElement(); 
                reader.ReadStartElement(); 
                return reader;
            } 

            protected override void OnBodyToString(XmlDictionaryWriter writer)
            {
                using (XmlDictionaryReader reader = GetBufferedReaderAtBody()) 
                {
                    while (reader.NodeType != XmlNodeType.EndElement) 
                        writer.WriteNode(reader, false); 
                }
            } 

            protected override void OnClose()
            {
                Exception ex = null; 
                try
                { 
                    base.OnClose(); 
                }
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e))
                        throw;
                    ex = e; 
                }
 
                try 
                {
                    properties.Dispose(); 
                }
                catch (Exception e)
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                        throw;
                    if (ex == null) 
                        ex = e; 
                }
 
                try
                {
                    if (reader != null)
                    { 
                        reader.Close();
                    } 
                } 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                        throw;
                    if (ex == null)
                        ex = e; 
                }
 
                try 
                {
                    recycledMessageState.ReturnHeaders(headers); 
                    recycledMessageState.ReturnProperties(properties);
                    messageData.ReturnMessageState(recycledMessageState);
                    recycledMessageState = null;
                    messageData.Close(); 
                    messageData = null;
                } 
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                        throw;
                    if (ex == null)
                        ex = e;
                } 

                if (ex != null) 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex); 
            }
 
            protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
            {
                return base.OnCreateBufferedCopy(maxBufferSize);
            } 

            protected override XmlDictionaryReader OnGetReaderAtBodyContents() 
            { 
                XmlDictionaryReader reader = this.reader;
                this.reader = null; 
                return reader;
            }

            protected override string OnGetBodyAttribute(string localName, string ns) 
            {
                return null; 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK