unsafeIndexingFilterStream.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / MS / Internal / IO / Packaging / unsafeIndexingFilterStream.cs / 1 / unsafeIndexingFilterStream.cs

                            //------------------------------------------------------------------------------ 
//  Microsoft Avalon
//  Copyright (c) Microsoft Corporation, 2005
//
//  File:           UnsafeIndexingFilterStream.cs 
//
//  Description:    The class UnsafeIndexingFilterStream uses an OLE IStream component 
//                  passed on a indexing filter's IPersistStream interface to implement 
//                  the System.IO.Stream functions necessary for filtering a document.
//                  In other words, it basically implements a seekable read-only stream. 
//
//                  For a more complete example of an IStream adapter, see Listing 20.2
//                  in Adam Nathan's ".Net and COM".
// 
//  History:        02/15/05 - johnlarc - initial implementation
//----------------------------------------------------------------------------- 
 
using System;
using System.IO; 
using System.Runtime.InteropServices;           // For Marshal
using System.Windows;                           // for ExceptionStringTable
using MS.Win32;                                 // For NativeMethods
using MS.Internal.Interop;	                // for IStream 
using System.Security;                          // For SecurityCritical
 
 
namespace MS.Internal.IO.Packaging
{ 
    /// 
    /// The class UnsafeIndexingFilterStream uses an OLE IStream component
    /// passed on an indexing filter's IPersistStream interface to implement
    /// the System.IO.Stream functions necessary for filtering a document. 
    /// In other words, it basically implements a seekable read-only stream.
    ///  
    ///  
    ///
    /// This class is used only by the Container filter, since the Xaml filter is not accessible directly 
    /// from unmanaged code and so can use System.IO.Stream natively.
    ///
    /// This class does not own the process of closing the underlying stream. However,
    /// This class does own a reference to a COM object that should be released as a part of the Dispose pattern, 
    /// so that the underlying unmanaged code doesn't keep the stream open indefinitely  (or until GC gets to it)
    /// 
    /// The definition of IStream that is used is MS.Internal.Interop.IStream rather than the standard one 
    /// so as to allow efficient marshaling of arrays with specified offsets in Read.
    ///  
    /// 
    ///     Critical: Marking this as Security Critical as this stream serves a very specific functionality
    ///               required for indexing content using unmanaged Indexing Services. We do not want managed
    ///               code to start using this Stream implementation. 
    ///               This code is meant to be accessed only from unmanaged code. Currently there is one
    ///               unmanaged caller. 
    ///               This stream- 1. Calls into unmanaged code. 
    ///                            2. Implements a seekable read-only stream on an OLE IStream component.
    ///                            3. Behaves more like an unmanaged IStream as opposed to managed Stream. 
    ///                            4. This class does not do any elevation of privilege.
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)]
    internal class UnsafeIndexingFilterStream : Stream 
    {
        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------
        /// 
        /// Build a System.IO.Stream implementation around an IStream component.
        ///  
        /// 
        /// The client code is entirely responsible for the lifespan of the stream, 
        /// and there is no way it can tip us off for when to release it. Therefore, 
        /// its reference count is not incremented. The risk of the client
        /// releasing the IStream component before we're done with it is no worse than 
        /// that of the client passing a pointer to garbage in the first place, and we
        /// cannot protect against that either. After all, the client is unmanaged and
        /// has endless possibilities of trashing the machine if she wishes to.
        ///  
        internal UnsafeIndexingFilterStream(IStream oleStream)
        { 
            if (oleStream == null) 
                throw new ArgumentNullException("oleStream");
 
            _oleStream = oleStream;
            _disposed = false;
        }
 
        //------------------------------------------------------
        // 
        //  Public Methods 
        //
        //----------------------------------------------------- 

        /// 
        /// Return the bytes requested.
        ///  
        /// Destination buffer.
        /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. 
        /// How many bytes requested. 
        /// How many bytes were written into buffer.
        public unsafe override int Read(byte[] buffer, int offset, int count) 
        {
            ThrowIfStreamDisposed();

            // Check arguments. 
            PackagingUtilities.VerifyStreamReadArgs(this, buffer, offset, count);
 
            // Reading 0 bytes is a no-op. 
            if (count == 0)
                return 0; 

            // Prepare location of return value and call the COM object.
            int    bytesRead;
            IntPtr pBytesRead = new IntPtr(&bytesRead); 

            // Prepare to restore position in case the read fails. 
            long positionBeforeReadAttempt = this.Position; 

            try 
            {
                // Pin the array wrt GC while using an address in it.
                fixed (byte *bufferPointer = &buffer[offset])
                { 
                    _oleStream.Read(new IntPtr(bufferPointer), count, pBytesRead);
                } 
            } 
            catch (COMException comException)
            { 
                this.Position = positionBeforeReadAttempt;
                throw new IOException("Read", comException);
            }
            catch (IOException ioException) 
            {
                this.Position = positionBeforeReadAttempt; 
                throw new IOException("Read", ioException); 
            }
            return bytesRead; 
        }

        /// 
        /// Seek -unmanaged streams do not allow seeking beyond the end of the stream 
        /// and since we rely on the underlying stream to validate and return the seek
        /// results, unlike managed streams where seeking beyond the end of the stream 
        /// is allowed we will get an exception. 
        /// 
        /// Offset in byte. 
        /// Offset origin (start, current, or end).
        public unsafe override long Seek(long offset, SeekOrigin origin)
        {
            ThrowIfStreamDisposed(); 

            long position = 0; 
            // The address of 'position' can be used without pinning the object, because it 
            // is a value and is therefore allocated on the stack rather than the heap.
            IntPtr positionAddress = new IntPtr(&position); 

            // The enum values of SeekOrigin match the STREAM_SEEK_* values. This
            // convention is as good as carved in stone, so there's no need for a switch here.
            _oleStream.Seek(offset, (int)origin, positionAddress); 

            return position; 
        } 

        ///  
        /// SetLength
        /// 
        /// not supported
        ///  
        /// Not supported. No indexing filter should require it.
        ///  
        public override void SetLength(long newLength) 
        {
            ThrowIfStreamDisposed(); 
            throw new NotSupportedException(SR.Get(SRID.StreamDoesNotSupportWrite));
        }

        ///  
        /// Write
        ///  
        /// not supported 
        /// 
        /// Not supported. No indexing filter should require it. 
        /// 
        public override void Write(byte[] buf, int offset, int count)
        {
            ThrowIfStreamDisposed(); 
            throw new NotSupportedException(SR.Get(SRID.StreamDoesNotSupportWrite));
        } 
 
        /// 
        /// Flush 
        /// 
        public override void Flush()
        {
            ThrowIfStreamDisposed(); 
            //This stream is always readonly, and calling this method is a no-op
            //No IndexingFilter should require this method. 
        } 

        //------------------------------------------------------ 
        //
        //  Public Properties
        //
        //------------------------------------------------------ 

        ///  
        /// Is stream readable? 
        /// 
        ///  
        /// We always return true, because there's no way of checking whether the caller
        /// has closed the stream.
        /// 
        public override bool CanRead 
        {
            get 
            { 
                return !_disposed;
            } 
        }

        /// 
        /// Is stream seekable? 
        /// 
        public override bool CanSeek 
        { 
            get
            { 
                // This information is not available from the underlying stream.
                // So one assumption has to be made. True is the most common for indexable streams.
                return !_disposed;
            } 
        }
 
        ///  
        /// Is stream writable?
        ///  
        public override bool CanWrite
        {
            get
            { 
                return false;
            } 
        } 

        ///  
        /// Logical byte position in this stream
        /// 
        public override long Position
        { 
            get
            { 
                ThrowIfStreamDisposed(); 
                return Seek(0, SeekOrigin.Current);
            } 
            set
            {
                ThrowIfStreamDisposed();
 
                if (value < 0)
                    throw new ArgumentException(SR.Get(SRID.CannotSetNegativePosition)); 
 
                Seek(value, SeekOrigin.Begin);
            } 
        }

        /// 
        /// Length. 
        /// 
        public override long Length 
        { 
            get
            { 
                ThrowIfStreamDisposed();

                // Retrieve stream stats. STATFLAG_NONAME means don't return the stream name.
                System.Runtime.InteropServices.ComTypes.STATSTG statstg; 
                _oleStream.Stat(out statstg, NativeMethods.STATFLAG_NONAME);
                return statstg.cbSize; 
            } 
        }
 
        //-----------------------------------------------------
        //
        //   Protected methods.
        // 
        //------------------------------------------------------
 
        ///  
        /// 
        /// Although UnsafeIndexingFilterStream does not close the underlying stream, it is responsible for releasing 
        /// the ComObject it holds, so that unmanaged code can properly close the stream.
        ///  
        /// This method gets invoked as part of the base class's Dispose() or Close() implementation.
        ///  
        /// 
        protected override void Dispose(bool disposing) 
        { 
            try
            { 
                if (disposing)
                {
                    if (_oleStream != null)
                    { 
                        MS.Win32.UnsafeNativeMethods.SafeReleaseComObject(_oleStream);
                    } 
                } 
            }
            finally 
            {
                // Calls to Dispose(bool) are expected to bubble up through the class hierarchy.
                _oleStream = null;
                _disposed = true; 
                base.Dispose(disposing);
            } 
        } 

        //----------------------------------------------------- 
        //
        //   Private methods.
        //
        //----------------------------------------------------- 

        private void ThrowIfStreamDisposed() 
        { 
            if (_disposed)
                throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed)); 
        }

        //-----------------------------------------------------
        // 
        //  Private Fields
        // 
        //------------------------------------------------------ 
        private IStream          _oleStream;   // Underlying COM component.
        private bool             _disposed; 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
//  Microsoft Avalon
//  Copyright (c) Microsoft Corporation, 2005
//
//  File:           UnsafeIndexingFilterStream.cs 
//
//  Description:    The class UnsafeIndexingFilterStream uses an OLE IStream component 
//                  passed on a indexing filter's IPersistStream interface to implement 
//                  the System.IO.Stream functions necessary for filtering a document.
//                  In other words, it basically implements a seekable read-only stream. 
//
//                  For a more complete example of an IStream adapter, see Listing 20.2
//                  in Adam Nathan's ".Net and COM".
// 
//  History:        02/15/05 - johnlarc - initial implementation
//----------------------------------------------------------------------------- 
 
using System;
using System.IO; 
using System.Runtime.InteropServices;           // For Marshal
using System.Windows;                           // for ExceptionStringTable
using MS.Win32;                                 // For NativeMethods
using MS.Internal.Interop;	                // for IStream 
using System.Security;                          // For SecurityCritical
 
 
namespace MS.Internal.IO.Packaging
{ 
    /// 
    /// The class UnsafeIndexingFilterStream uses an OLE IStream component
    /// passed on an indexing filter's IPersistStream interface to implement
    /// the System.IO.Stream functions necessary for filtering a document. 
    /// In other words, it basically implements a seekable read-only stream.
    ///  
    ///  
    ///
    /// This class is used only by the Container filter, since the Xaml filter is not accessible directly 
    /// from unmanaged code and so can use System.IO.Stream natively.
    ///
    /// This class does not own the process of closing the underlying stream. However,
    /// This class does own a reference to a COM object that should be released as a part of the Dispose pattern, 
    /// so that the underlying unmanaged code doesn't keep the stream open indefinitely  (or until GC gets to it)
    /// 
    /// The definition of IStream that is used is MS.Internal.Interop.IStream rather than the standard one 
    /// so as to allow efficient marshaling of arrays with specified offsets in Read.
    ///  
    /// 
    ///     Critical: Marking this as Security Critical as this stream serves a very specific functionality
    ///               required for indexing content using unmanaged Indexing Services. We do not want managed
    ///               code to start using this Stream implementation. 
    ///               This code is meant to be accessed only from unmanaged code. Currently there is one
    ///               unmanaged caller. 
    ///               This stream- 1. Calls into unmanaged code. 
    ///                            2. Implements a seekable read-only stream on an OLE IStream component.
    ///                            3. Behaves more like an unmanaged IStream as opposed to managed Stream. 
    ///                            4. This class does not do any elevation of privilege.
    /// 
    [SecurityCritical(SecurityCriticalScope.Everything)]
    internal class UnsafeIndexingFilterStream : Stream 
    {
        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------
        /// 
        /// Build a System.IO.Stream implementation around an IStream component.
        ///  
        /// 
        /// The client code is entirely responsible for the lifespan of the stream, 
        /// and there is no way it can tip us off for when to release it. Therefore, 
        /// its reference count is not incremented. The risk of the client
        /// releasing the IStream component before we're done with it is no worse than 
        /// that of the client passing a pointer to garbage in the first place, and we
        /// cannot protect against that either. After all, the client is unmanaged and
        /// has endless possibilities of trashing the machine if she wishes to.
        ///  
        internal UnsafeIndexingFilterStream(IStream oleStream)
        { 
            if (oleStream == null) 
                throw new ArgumentNullException("oleStream");
 
            _oleStream = oleStream;
            _disposed = false;
        }
 
        //------------------------------------------------------
        // 
        //  Public Methods 
        //
        //----------------------------------------------------- 

        /// 
        /// Return the bytes requested.
        ///  
        /// Destination buffer.
        /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. 
        /// How many bytes requested. 
        /// How many bytes were written into buffer.
        public unsafe override int Read(byte[] buffer, int offset, int count) 
        {
            ThrowIfStreamDisposed();

            // Check arguments. 
            PackagingUtilities.VerifyStreamReadArgs(this, buffer, offset, count);
 
            // Reading 0 bytes is a no-op. 
            if (count == 0)
                return 0; 

            // Prepare location of return value and call the COM object.
            int    bytesRead;
            IntPtr pBytesRead = new IntPtr(&bytesRead); 

            // Prepare to restore position in case the read fails. 
            long positionBeforeReadAttempt = this.Position; 

            try 
            {
                // Pin the array wrt GC while using an address in it.
                fixed (byte *bufferPointer = &buffer[offset])
                { 
                    _oleStream.Read(new IntPtr(bufferPointer), count, pBytesRead);
                } 
            } 
            catch (COMException comException)
            { 
                this.Position = positionBeforeReadAttempt;
                throw new IOException("Read", comException);
            }
            catch (IOException ioException) 
            {
                this.Position = positionBeforeReadAttempt; 
                throw new IOException("Read", ioException); 
            }
            return bytesRead; 
        }

        /// 
        /// Seek -unmanaged streams do not allow seeking beyond the end of the stream 
        /// and since we rely on the underlying stream to validate and return the seek
        /// results, unlike managed streams where seeking beyond the end of the stream 
        /// is allowed we will get an exception. 
        /// 
        /// Offset in byte. 
        /// Offset origin (start, current, or end).
        public unsafe override long Seek(long offset, SeekOrigin origin)
        {
            ThrowIfStreamDisposed(); 

            long position = 0; 
            // The address of 'position' can be used without pinning the object, because it 
            // is a value and is therefore allocated on the stack rather than the heap.
            IntPtr positionAddress = new IntPtr(&position); 

            // The enum values of SeekOrigin match the STREAM_SEEK_* values. This
            // convention is as good as carved in stone, so there's no need for a switch here.
            _oleStream.Seek(offset, (int)origin, positionAddress); 

            return position; 
        } 

        ///  
        /// SetLength
        /// 
        /// not supported
        ///  
        /// Not supported. No indexing filter should require it.
        ///  
        public override void SetLength(long newLength) 
        {
            ThrowIfStreamDisposed(); 
            throw new NotSupportedException(SR.Get(SRID.StreamDoesNotSupportWrite));
        }

        ///  
        /// Write
        ///  
        /// not supported 
        /// 
        /// Not supported. No indexing filter should require it. 
        /// 
        public override void Write(byte[] buf, int offset, int count)
        {
            ThrowIfStreamDisposed(); 
            throw new NotSupportedException(SR.Get(SRID.StreamDoesNotSupportWrite));
        } 
 
        /// 
        /// Flush 
        /// 
        public override void Flush()
        {
            ThrowIfStreamDisposed(); 
            //This stream is always readonly, and calling this method is a no-op
            //No IndexingFilter should require this method. 
        } 

        //------------------------------------------------------ 
        //
        //  Public Properties
        //
        //------------------------------------------------------ 

        ///  
        /// Is stream readable? 
        /// 
        ///  
        /// We always return true, because there's no way of checking whether the caller
        /// has closed the stream.
        /// 
        public override bool CanRead 
        {
            get 
            { 
                return !_disposed;
            } 
        }

        /// 
        /// Is stream seekable? 
        /// 
        public override bool CanSeek 
        { 
            get
            { 
                // This information is not available from the underlying stream.
                // So one assumption has to be made. True is the most common for indexable streams.
                return !_disposed;
            } 
        }
 
        ///  
        /// Is stream writable?
        ///  
        public override bool CanWrite
        {
            get
            { 
                return false;
            } 
        } 

        ///  
        /// Logical byte position in this stream
        /// 
        public override long Position
        { 
            get
            { 
                ThrowIfStreamDisposed(); 
                return Seek(0, SeekOrigin.Current);
            } 
            set
            {
                ThrowIfStreamDisposed();
 
                if (value < 0)
                    throw new ArgumentException(SR.Get(SRID.CannotSetNegativePosition)); 
 
                Seek(value, SeekOrigin.Begin);
            } 
        }

        /// 
        /// Length. 
        /// 
        public override long Length 
        { 
            get
            { 
                ThrowIfStreamDisposed();

                // Retrieve stream stats. STATFLAG_NONAME means don't return the stream name.
                System.Runtime.InteropServices.ComTypes.STATSTG statstg; 
                _oleStream.Stat(out statstg, NativeMethods.STATFLAG_NONAME);
                return statstg.cbSize; 
            } 
        }
 
        //-----------------------------------------------------
        //
        //   Protected methods.
        // 
        //------------------------------------------------------
 
        ///  
        /// 
        /// Although UnsafeIndexingFilterStream does not close the underlying stream, it is responsible for releasing 
        /// the ComObject it holds, so that unmanaged code can properly close the stream.
        ///  
        /// This method gets invoked as part of the base class's Dispose() or Close() implementation.
        ///  
        /// 
        protected override void Dispose(bool disposing) 
        { 
            try
            { 
                if (disposing)
                {
                    if (_oleStream != null)
                    { 
                        MS.Win32.UnsafeNativeMethods.SafeReleaseComObject(_oleStream);
                    } 
                } 
            }
            finally 
            {
                // Calls to Dispose(bool) are expected to bubble up through the class hierarchy.
                _oleStream = null;
                _disposed = true; 
                base.Dispose(disposing);
            } 
        } 

        //----------------------------------------------------- 
        //
        //   Private methods.
        //
        //----------------------------------------------------- 

        private void ThrowIfStreamDisposed() 
        { 
            if (_disposed)
                throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed)); 
        }

        //-----------------------------------------------------
        // 
        //  Private Fields
        // 
        //------------------------------------------------------ 
        private IStream          _oleStream;   // Underlying COM component.
        private bool             _disposed; 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK