context: // ***************************************************************
  // <copyright file="ConverterStream.cs" company="Microsoft">
  //      Copyright (C) Microsoft Corporation.  All rights reserved.
  // </copyright>
  // <summary>
  //      ...
  // </summary>
  // ***************************************************************
  
  namespace Microsoft.Exchange.Data.TextConverters
  {
      using System;
      using System.IO;
      using Data.Internal;
      using Strings = CtsResources.TextConvertersStrings;
  
      
  
      
      
      
      internal enum ConverterStreamAccess
      {
          
          Read,
          
          Write,
      }
  
      
      
      
      
      internal class ConverterStream : Stream, IProgressMonitor
      {
          
  
          private IProducerConsumer consumer;
  
          private int maxLoopsWithoutProgress;
          private bool madeProgress;
  
          private byte[] chunkToReadBuffer;
          private int chunkToReadOffset;
          private int chunkToReadCount;
  
          
  
          private IByteSource byteSource;
          private IProducerConsumer producer;
  
          private byte[] writeBuffer;
          private int writeOffset;
          private int writeCount;
  
          
  
          private object sourceOrDestination;
  
          private bool endOfFile;
          private bool inconsistentState;
  
          
          
          
          
          
          
          
          
          
          
          
          
          public ConverterStream(
              Stream stream,
              TextConverter converter,
              ConverterStreamAccess access)
          {
              if (stream == null)
              {
                  throw new ArgumentNullException("stream");
              }
  
              if (converter == null)
              {
                  throw new ArgumentNullException("converter");
              }
  
              if (access < ConverterStreamAccess.Read || ConverterStreamAccess.Write < access)
              {
                  throw new ArgumentException(Strings.AccessShouldBeReadOrWrite, "access");
              }
  
              if (access == ConverterStreamAccess.Read)
              {
                  if (!stream.CanRead)
                  {
                      throw new ArgumentException(Strings.CannotReadFromSource, "stream");
                  }
  
                  producer = converter.CreatePullChain(stream, this);
              }
              else
              {
                  if (!stream.CanWrite)
                  {
                      throw new ArgumentException(Strings.CannotWriteToDestination, "stream");
                  }
  
                  consumer = converter.CreatePushChain(this, stream);
              }
  
              sourceOrDestination = stream;
  
              maxLoopsWithoutProgress = 100000 + converter.InputStreamBufferSize + converter.OutputStreamBufferSize;
          }
  
          
          
          
          
          
          
          
          public ConverterStream(
              TextReader sourceReader,
              TextConverter converter)
          {
              if (sourceReader == null)
              {
                  throw new ArgumentNullException("sourceReader");
              }
  
              if (converter == null)
              {
                  throw new ArgumentNullException("converter");
              }
  
              producer = converter.CreatePullChain(sourceReader, this);
              sourceOrDestination = sourceReader;
  
              maxLoopsWithoutProgress = 100000 + converter.InputStreamBufferSize + converter.OutputStreamBufferSize;
          }
  
          
          
          
          
          
          
          public ConverterStream(
              TextWriter destinationWriter,
              TextConverter converter)
          {
              if (destinationWriter == null)
              {
                  throw new ArgumentNullException("destinationWriter");
              }
  
              if (converter == null)
              {
                  throw new ArgumentNullException("converter");
              }
  
              consumer = converter.CreatePushChain(this, destinationWriter);
              sourceOrDestination = destinationWriter;
  
              maxLoopsWithoutProgress = 100000 + converter.InputStreamBufferSize + converter.OutputStreamBufferSize;
          }
  
          
          
  
          
          
          
          
          public override bool CanRead => producer != null ? true : false;
  
  
          public override bool CanWrite => consumer != null ? true : false;
  
  
          public override bool CanSeek => false;
  
  
          public override long Length
          {
              get
              {
                  throw new NotSupportedException(Strings.SeekUnsupported);
              }
          }
  
          
          
          
          
          public override long Position
          {
              get
              {
                  throw new NotSupportedException(Strings.SeekUnsupported);
              }
  
              set
              {
                  throw new NotSupportedException(Strings.SeekUnsupported);
              }
          }
  
          
          
          
          
          
          
          public override long Seek(long offset, SeekOrigin origin)
          {
              throw new NotSupportedException(Strings.SeekUnsupported);
          }
  
          
          
          
          
          public override void SetLength(long value)
          {
              throw new NotSupportedException(Strings.SeekUnsupported);
          }
  
          
          
          
          
          
          
          
          public override void Write(byte[] buffer, int offset, int count)
          {
              if (sourceOrDestination == null)
              {
                  throw new ObjectDisposedException("ConverterStream");
              }
  
              if (consumer == null)
              {
                  throw new InvalidOperationException(Strings.WriteUnsupported);
              }
  
              if (null == buffer)
              {
                  throw new ArgumentNullException("buffer");
              }
  
              if (offset > buffer.Length || offset < 0)
              {
                  throw new ArgumentOutOfRangeException("offset", Strings.OffsetOutOfRange);
              }
  
              if (count > buffer.Length || count < 0)
              {
                  throw new ArgumentOutOfRangeException("count", Strings.CountOutOfRange);
              }
  
              if (count + offset > buffer.Length)
              {
                  throw new ArgumentOutOfRangeException("count", Strings.CountTooLarge);
              }
  
              if (endOfFile)
              {
                  throw new InvalidOperationException(Strings.WriteAfterFlush);
              }
  
              if (inconsistentState)
              {
                  throw new InvalidOperationException(Strings.ConverterStreamInInconsistentStare);
              }
  
              InternalDebug.Assert(consumer != null);
  
              chunkToReadBuffer = buffer;
              chunkToReadOffset = offset;
              chunkToReadCount = count;
  
              
              
              
  
              long loopsWithoutProgress = 0;
  
              
              
              inconsistentState = true;
  
              while (0 != chunkToReadCount)
              {
                  
                  consumer.Run();
  
                  if (madeProgress)
                  {
                      
                      loopsWithoutProgress = 0;
                      madeProgress = false;
                  }
                  else if (maxLoopsWithoutProgress == loopsWithoutProgress++)
                  {
                      InternalDebug.Assert(false);
                      throw new TextConvertersException(Strings.TooManyIterationsToProcessInput);
                  }
              }
  
              
              inconsistentState = false;
  
              chunkToReadBuffer = null;       
          }
  
          
          
          
          
          
          
          public override void Flush()
          {
              if (sourceOrDestination == null)
              {
                  throw new ObjectDisposedException("ConverterStream");
              }
  
              if (consumer == null)
              {
                  throw new InvalidOperationException(Strings.WriteUnsupported);
              }
  
              InternalDebug.Assert(consumer != null);
  
              endOfFile = true;
  
              if (!inconsistentState)
              {
                  long loopsWithoutProgress = 0;
  
                  
                  
                  inconsistentState = true;
  
                  while (!consumer.Flush())
                  {
                      if (madeProgress)
                      {
                          
                          loopsWithoutProgress = 0;
                          madeProgress = false;
                      }
  
gt:                     else if (maxLoopsWithoutProgress == loopsWithoutProgress++)