namespace WatsonTcp { using System; using System.IO; /// /// Stream containing message data. /// public class WatsonStream : Stream { #region Public-Members /// /// Indicates if the stream is readable. /// This value will always be true. /// public override bool CanRead => true; /// /// Indicates if seek operations are supported. /// This value will always be false. /// public override bool CanSeek => false; /// /// Indicates if the stream is writeable. /// This value will always be false. /// public override bool CanWrite => false; /// /// The number of bytes remaining in the stream. /// public override long Length { get { return _Length; } } /// /// The current position within the stream. /// public override long Position { get { return _Position; } set { throw new InvalidOperationException("Position may not be modified."); } } #endregion #region Private-Members private readonly object _Lock = new object(); private Stream _Stream = null; private long _Length = 0; private long _Position = 0; private long _BytesRemaining { get { return _Length - _Position; } } #endregion #region Constructors-and-Factories internal WatsonStream(long contentLength, Stream stream) { if (contentLength < 0) throw new ArgumentException("Content length must be zero or greater."); if (stream == null) throw new ArgumentNullException(nameof(stream)); if (!stream.CanRead) throw new ArgumentException("Cannot read from supplied stream."); _Length = contentLength; _Stream = stream; } #endregion #region Public-Methods /// /// Flushes data awaiting in the stream. /// public override void Flush() { } /// /// Read data from the stream. /// /// The buffer to which the data should be read. /// The offset within the buffer where data should begin. /// The number of bytes to read. /// Number of bytes read. public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); if (offset < 0) throw new ArgumentException("Offset must be zero or greater."); if (offset >= buffer.Length) throw new IndexOutOfRangeException("Offset must be less than the buffer length of " + buffer.Length + "."); if (count < 0) throw new ArgumentException("Count must be zero or greater."); if (count == 0) return 0; if (count + offset > buffer.Length) throw new ArgumentException("Offset and count must sum to a value less than the buffer length of " + buffer.Length + "."); lock (_Lock) { byte[] temp = null; if (_BytesRemaining == 0) return 0; if (count > _BytesRemaining) temp = new byte[_BytesRemaining]; else temp = new byte[count]; int bytesRead = _Stream.Read(temp, 0, temp.Length); Buffer.BlockCopy(temp, 0, buffer, offset, bytesRead); _Position += bytesRead; return bytesRead; } } /// /// Not supported. /// Seek to a specific position within a stream. /// /// /// /// public override long Seek(long offset, SeekOrigin origin) { throw new InvalidOperationException("Seek operations are not supported."); } /// /// Not supported. /// Set the length of the stream. /// /// Length. public override void SetLength(long value) { throw new InvalidOperationException("Length may not be modified."); } /// /// Not supported. /// Write to the stream. /// /// The buffer containing the data that should be written to the stream. /// The offset within the buffer from which data should be read. /// The number of bytes to read. public override void Write(byte[] buffer, int offset, int count) { throw new InvalidOperationException("Stream is not writeable."); } #endregion } }