File: Shared\MS\Internal\IO\SynchronizingStream.cs
Project: wpf\src\PresentationCore.csproj (PresentationCore)
//------------------------------------------------------------------------------
//  Microsoft Avalon
//  Copyright (c) Microsoft Corporation, 2001
//
//  File:           SynchronizingStream.cs
//
//  Description:    Stream that locks on given syncRoot before entering any public API's.
//
//  History:        01/20/06 - brucemac - created
//------------------------------------------------------------------------------
 
using System;
using System.Diagnostics;
using System.IO;
using System.Windows;
 
namespace MS.Internal.IO.Packaging
{
    /// <summary>
    /// Wrap returned stream to protect non-thread-safe API's from race conditions
    /// </summary>
    internal class SynchronizingStream : Stream
    {
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
        /// <summary>
        /// Serializes access by locking on the given object
        /// </summary>
        /// <param name="stream">stream to read from (baseStream)</param>
        /// <param name="syncRoot">object to lock on</param>
        internal SynchronizingStream(Stream stream, Object syncRoot)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");
 
            if (syncRoot == null)
                throw new ArgumentNullException("syncRoot");
 
            _baseStream = stream;
            _syncRoot = syncRoot;
        }
 
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------
 
        /// <summary>
        /// Return the bytes requested
        /// </summary>
        /// <param name="buffer">destination buffer</param>
        /// <param name="offset">offset to write into that buffer</param>
        /// <param name="count">how many bytes requested</param>
        /// <returns>how many bytes were written into buffer</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            lock (_syncRoot)
            {
                CheckDisposed();
                return (_baseStream.Read(buffer, offset, count));
            }
        }
 
        /// <summary>
        /// Read a single byte
        /// </summary>
        /// <returns>The unsigned byte cast to an Int32, or -1 if at the end of the stream.</returns>
        public override int ReadByte()
        {
            lock (_syncRoot)
            {
                CheckDisposed();
                return (_baseStream.ReadByte());
            }
        }
 
        /// <summary>
        /// Write a single byte
        /// </summary>
        /// <param name="b">byte to write</param>
        public override void WriteByte(byte b)
        {
            lock (_syncRoot)
            {
                CheckDisposed();
                _baseStream.WriteByte(b);
            }
        }
 
        /// <summary>
        /// Seek
        /// </summary>
        /// <param name="offset">only zero is supported</param>
        /// <param name="origin">only SeekOrigin.Begin is supported</param>
        /// <returns>zero</returns>
        public override long Seek(long offset, SeekOrigin origin)
        {
            lock (_syncRoot)
            {
                CheckDisposed();
                return _baseStream.Seek(offset, origin);
            }
        }
        /// <summary>
        /// SetLength
        /// </summary>
        /// <exception cref="NotSupportedException">not supported</exception>
        public override void SetLength(long newLength)
        {
            lock (_syncRoot)
            {
                CheckDisposed();
                _baseStream.SetLength(newLength);
            }
        }
 
        /// <summary>
        /// Write
        /// </summary>
        /// <exception cref="NotSupportedException">not supported</exception>
        public override void Write(byte[] buf, int offset, int count)
        {
            lock (_syncRoot)
            {
                CheckDisposed();
                _baseStream.Write(buf, offset, count);
            }
        }
 
        /// <summary>
        /// Flush
        /// </summary>
        /// <exception cref="NotSupportedException">not supported</exception>
        public override void Flush()
        {
            lock (_syncRoot)
            {
                CheckDisposed();
                _baseStream.Flush();
            }
        }
 
        //------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------
 
        /// <summary>
        /// Is stream readable?
        /// </summary>
        public override bool CanRead
        {
            get
            {
                lock (_syncRoot)
                {
                    return ((_baseStream != null) && _baseStream.CanRead);
                }
            }
        }
        /// <summary>
        /// Is stream seekable?
        /// </summary>
        /// <remarks>We MUST support seek as this is used to implement ILockBytes.ReadAt()</remarks>
        public override bool CanSeek
        {
            get
            {
                lock (_syncRoot)
                {
                    return ((_baseStream != null) && _baseStream.CanSeek);
                }
            }
        }
        /// <summary>
        /// Is stream writeable?
        /// </summary>
        public override bool CanWrite
        {
            get
            {
                lock (_syncRoot)
                {
                    return ((_baseStream != null) && _baseStream.CanWrite);
                }
            }
        }
 
        /// <summary>
        /// Logical byte position in this stream
        /// </summary>
        public override long Position
        {
            get
            {
                lock (_syncRoot)
                {
                    CheckDisposed();
                    return _baseStream.Position;
                }
            }
            set
            {
                lock (_syncRoot)
                {
                    CheckDisposed();
                    _baseStream.Position = value;
                }
            }
        }
 
        /// <summary>
        /// Length
        /// </summary>
        public override long Length
        {
            get
            {
                lock (_syncRoot)
                {
                    CheckDisposed();
                    return _baseStream.Length;
                }
            }
        }
 
        //------------------------------------------------------
        //
        //  Protected Methods
        //
        //------------------------------------------------------
        protected override void Dispose(bool disposing)
        {
            lock (_syncRoot)
            {
                try
                {
                    if (disposing && (_baseStream != null))
                    {
                        // close the underlying Stream
                        _baseStream.Close();
 
                        // NOTE: We cannot set _syncRoot to null because it is used
                        // on entry to every public method and property.
                    }
                }
                finally
                {
                    base.Dispose(disposing);
                    _baseStream = null;
                }
            }
        }
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
        /// <summary>
        /// CheckDisposed
        /// </summary>
        /// <remarks>Pre-condition that lock has been acquired.</remarks>
        private void CheckDisposed()
        {
            if (_baseStream == null)
                throw new ObjectDisposedException("Stream");
        }
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
        private Stream      _baseStream;    // stream we are wrapping
        private Object      _syncRoot;      // object to lock on
    }
}