File: System\ServiceModel\XmlBuffer.cs
Web Access
Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.Runtime;
using System.ServiceModel.Channels;
using System.Xml;
 
namespace System.ServiceModel
{
    internal class XmlBuffer
    {
        private List<Section> _sections;
        private byte[] _buffer;
        private int _offset;
        private BufferedOutputStream _stream;
        private BufferState _bufferState;
        private XmlDictionaryWriter _writer;
        private XmlDictionaryReaderQuotas _quotas;
 
        private enum BufferState
        {
            Created,
            Writing,
            Reading,
        }
 
        internal struct Section
        {
            private int _size;
 
            public Section(int offset, int size, XmlDictionaryReaderQuotas quotas)
            {
                Offset = offset;
                _size = size;
                Quotas = quotas;
            }
 
            public int Offset { get; }
 
            public int Size
            {
                get { return _size; }
            }
 
            public XmlDictionaryReaderQuotas Quotas { get; }
        }
 
        public XmlBuffer(int maxBufferSize)
        {
            if (maxBufferSize < 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(maxBufferSize), maxBufferSize,
                                                    SRP.ValueMustBeNonNegative));
            }
 
            int initialBufferSize = Math.Min(512, maxBufferSize);
            _stream = new BufferManagerOutputStream(SRP.XmlBufferQuotaExceeded, initialBufferSize, maxBufferSize,
                BufferManager.CreateBufferManager(0, int.MaxValue));
            _sections = new List<Section>(1);
        }
 
        public int BufferSize
        {
            get
            {
                Fx.Assert(_bufferState == BufferState.Reading, "Buffer size shuold only be retrieved during Reading state");
                return _buffer.Length;
            }
        }
 
        public int SectionCount
        {
            get { return _sections.Count; }
        }
 
        public XmlDictionaryWriter OpenSection(XmlDictionaryReaderQuotas quotas)
        {
            if (_bufferState != BufferState.Created)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidStateException());
            }
 
            _bufferState = BufferState.Writing;
            _quotas = new XmlDictionaryReaderQuotas();
            quotas.CopyTo(_quotas);
            if (_writer != null)
            {
                // We always want to Dispose of the writer now; previously, writers could be reassigned 
                // to a new stream, with a new dictionary and session. 
                var thisWriter = _writer;
                thisWriter.Dispose();
                _writer = null;
            }
            _writer = XmlDictionaryWriter.CreateBinaryWriter(_stream, XD.Dictionary, null, true);
            return _writer;
        }
 
        public void CloseSection()
        {
            if (_bufferState != BufferState.Writing)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidStateException());
            }
 
            _writer.Dispose();
            _writer = null;
            _bufferState = BufferState.Created;
            int size = (int)_stream.Length - _offset;
            _sections.Add(new Section(_offset, size, _quotas));
            _offset += size;
        }
 
        public void Close()
        {
            if (_bufferState != BufferState.Created)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidStateException());
            }
 
            _bufferState = BufferState.Reading;
            int bufferSize;
            _buffer = _stream.ToArray(out bufferSize);
            _writer = null;
            _stream = null;
        }
 
        private Exception CreateInvalidStateException()
        {
            return new InvalidOperationException(SRP.XmlBufferInInvalidState);
        }
 
        public XmlDictionaryReader GetReader(int sectionIndex)
        {
            if (_bufferState != BufferState.Reading)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidStateException());
            }
 
            Section section = _sections[sectionIndex];
            XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(_buffer, section.Offset, section.Size, XD.Dictionary, section.Quotas);
            reader.MoveToContent();
            return reader;
        }
 
        public void WriteTo(int sectionIndex, XmlWriter writer)
        {
            if (_bufferState != BufferState.Reading)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidStateException());
            }
 
            XmlDictionaryReader reader = GetReader(sectionIndex);
            try
            {
                writer.WriteNode(reader, false);
            }
            finally
            {
                reader.Dispose();
            }
        }
    }
}