using System; using System.IO; namespace CGS { /// /// Wraps another stream and provides reporting for when bytes are read or written to the stream. /// public class ProgressStream : Stream { #region Private Data Members private Stream innerStream; #endregion #region Constructor /// /// Creates a new ProgressStream supplying the stream for it to report on. /// /// The underlying stream that will be reported on when bytes are read or written. public ProgressStream(Stream streamToReportOn) { if (streamToReportOn != null) { this.innerStream = streamToReportOn; } else { throw new ArgumentNullException("streamToReportOn"); } } #endregion #region Events /// /// Raised when bytes are read from the stream. /// public event ProgressStreamReportDelegate BytesRead; /// /// Raised when bytes are written to the stream. /// public event ProgressStreamReportDelegate BytesWritten; /// /// Raised when bytes are either read or written to the stream. /// public event ProgressStreamReportDelegate BytesMoved; protected virtual void OnBytesRead(int bytesMoved) { if (BytesRead != null) { var args = new ProgressStreamReportEventArgs(bytesMoved, innerStream.Length, innerStream.Position, true); BytesRead(this, args); } } protected virtual void OnBytesWritten(int bytesMoved) { if (BytesWritten != null) { var args = new ProgressStreamReportEventArgs(bytesMoved, innerStream.Length, innerStream.Position, false); BytesWritten(this, args); } } protected virtual void OnBytesMoved(int bytesMoved, bool isRead) { if (BytesMoved != null) { var args = new ProgressStreamReportEventArgs(bytesMoved, innerStream.Length, innerStream.Position, isRead); BytesMoved(this, args); } } #endregion #region Stream Members public override bool CanRead { get { return innerStream.CanRead; } } public override bool CanSeek { get { return innerStream.CanSeek; } } public override bool CanWrite { get { return innerStream.CanWrite; } } public override void Flush() { innerStream.Flush(); } public override long Length { get { return innerStream.Length; } } public override long Position { get { return innerStream.Position; } set { innerStream.Position = value; } } public override int Read(byte[] buffer, int offset, int count) { var bytesRead = innerStream.Read(buffer, offset, count); OnBytesRead(bytesRead); OnBytesMoved(bytesRead, true); return bytesRead; } public override long Seek(long offset, SeekOrigin origin) { return innerStream.Seek(offset, origin); } public override void SetLength(long value) { innerStream.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { innerStream.Write(buffer, offset, count); OnBytesWritten(count); OnBytesMoved(count, false); } public override void Close() { innerStream.Close(); base.Close(); } #endregion } /// /// Contains the pertinent data for a ProgressStream Report event. /// public class ProgressStreamReportEventArgs : EventArgs { /// /// The number of bytes that were read/written to/from the stream. /// public int BytesMoved { get; private set; } /// /// The total length of the stream in bytes. /// public long StreamLength { get; private set; } /// /// The current position in the stream. /// public long StreamPosition { get; private set; } /// /// True if the bytes were read from the stream, false if they were written. /// public bool WasRead { get; private set; } /// /// Default constructor for ProgressStreamReportEventArgs. /// public ProgressStreamReportEventArgs() : base() { } /// /// Creates a new ProgressStreamReportEventArgs initializing its members. /// /// The number of bytes that were read/written to/from the stream. /// The total length of the stream in bytes. /// The current position in the stream. /// True if the bytes were read from the stream, false if they were written. public ProgressStreamReportEventArgs(int bytesMoved, long streamLength, long streamPosition, bool wasRead) :this() { this.BytesMoved = bytesMoved; this.StreamLength = streamLength; this.StreamPosition = streamPosition; this.WasRead = WasRead; } } /// /// The delegate for handling a ProgressStream Report event. /// /// The object that raised the event, should be a ProgressStream. /// The arguments raised with the event. public delegate void ProgressStreamReportDelegate(object sender, ProgressStreamReportEventArgs args); }