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
}
}