VersionedStreamOwner.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 / Base / MS / Internal / IO / Packaging / CompoundFile / VersionedStreamOwner.cs / 1 / VersionedStreamOwner.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//   This class provides file versioning support for streams provided by 
//   IDataTransform implementations and any client code that needs
//   to store a FormatVersion at the beginning of a stream. 
//
// History:
//  02/21/2006: BruceMac: Initial implementation.
// 
//-----------------------------------------------------------------------------
 
using System; 
using System.IO;                                // for Stream
using System.Windows;                           // ExceptionStringTable 
using System.Globalization;                     // for CultureInfo
using System.Diagnostics;                       // for Debug.Assert

namespace MS.Internal.IO.Packaging.CompoundFile 
{
    ///  
    /// Specialized stream that owns the FormatVersion 
    /// 
    /// Dispose() functionality is handled by our subclass VersionedStream 
    internal class VersionedStreamOwner : VersionedStream
    {
        #region Stream Methods
        ///  
        /// Return the bytes requested from the container
        ///  
        public override int Read(byte[] buffer, int offset, int count) 
        {
            // throw if version missing 
            ReadAttempt(true);
            return BaseStream.Read(buffer, offset, count);
        }
 
        /// 
        /// Write 
        ///  
        public override void Write(byte[] buffer, int offset, int count)
        { 
            WriteAttempt();
            BaseStream.Write(buffer, offset, count);
        }
 
        /// 
        /// ReadByte 
        ///  
        public override int ReadByte()
        { 
            ReadAttempt(true);
            return BaseStream.ReadByte();
        }
 
        /// 
        /// WriteByte 
        ///  
        public override void WriteByte(byte b)
        { 
            WriteAttempt();
            BaseStream.WriteByte(b);
        }
 
        /// 
        /// Seek 
        ///  
        /// offset
        /// origin 
        /// zero
        public override long Seek(long offset, SeekOrigin origin)
        {
            ReadAttempt(); 

            long temp = -1; 
            switch (origin) 
            {
                // seek beyond the FormatVersion 
                case SeekOrigin.Begin:
                    temp = offset;
                    break;
 
                case SeekOrigin.Current:
                    checked { temp = Position + offset; } 
                    break; 

                case SeekOrigin.End: 
                    checked { temp = Length + offset; }
                    break;
            }
 
            if (temp < 0)
                throw new ArgumentException(SR.Get(SRID.SeekNegative)); 
 
            checked { BaseStream.Position = temp + _dataOffset; }
            return temp; 
        }

        /// 
        /// SetLength 
        /// 
        public override void SetLength(long newLength) 
        { 
            if (newLength < 0)
                throw new ArgumentOutOfRangeException("newLength"); 

            WriteAttempt();
            checked { BaseStream.SetLength(newLength + _dataOffset); }
        } 

        ///  
        /// Flush 
        /// 
        public override void Flush() 
        {
            CheckDisposed();
            BaseStream.Flush();
        } 
        #endregion Stream Methods
 
        //----------------------------------------------------- 
        //
        //  Public Properties 
        //
        //-----------------------------------------------------
        #region Stream Properties
        ///  
        /// Current logical position within the stream
        ///  
        public override long Position 
        {
            get 
            {
                ReadAttempt();  // ensure _dataOffset is valid
                return checked(BaseStream.Position - _dataOffset);
            } 
            set
            { 
                // share Seek logic and validation 
                Seek(value, SeekOrigin.Begin);
            } 
        }

        /// 
        /// Length 
        /// 
        public override long Length 
        { 
            get
            { 
                ReadAttempt();  // ensure _dataOffset is valid

                long temp = checked(BaseStream.Length - _dataOffset);
                Invariant.Assert(temp >= 0);                    // catch any math errors 
                return temp;
            } 
        } 

        ///  
        /// Is stream readable?
        /// 
        /// returns false when called on disposed stream
        public override bool CanRead 
        {
            get 
            { 
                return (BaseStream != null) && BaseStream.CanRead && IsReadable;
            } 
        }

        /// 
        /// Is stream seekable - should be handled by our owner 
        /// 
        /// returns false when called on disposed stream 
        public override bool CanSeek 
        {
            get 
            {
                return (BaseStream != null) && BaseStream.CanSeek && IsReadable;
            }
        } 

        ///  
        /// Is stream writeable? 
        /// 
        /// returns false when called on disposed stream 
        public override bool CanWrite
        {
            get
            { 
                return (BaseStream != null) && BaseStream.CanWrite && IsUpdatable;
            } 
        } 
        #endregion
 

        /// 
        /// Constructor to use for the "versioned stream" - the one that actually houses the
        /// persisted FormatVersion. 
        /// 
        ///  
        ///  
        internal VersionedStreamOwner(Stream baseStream, FormatVersion codeVersion)
            : base(baseStream) 
        {
            _codeVersion = codeVersion;
        }
 
        internal bool IsUpdatable
        { 
            get 
            {
                CheckDisposed(); 

                // first try to read the format version
                EnsureParsed();
 
                // We can write if either:
                // 1. FileVersion doesn't exist - this is normal for a new, empty stream 
                // 2. It does exist and the FormatVersion indicates that we can update it 
                return (_fileVersion == null) ||
                    _fileVersion.IsUpdatableBy(_codeVersion.UpdaterVersion); 
            }
        }

        internal bool IsReadable 
        {
            get 
            { 
                CheckDisposed();
 
                // first try to read the format version
                EnsureParsed();

                // We can read if either: 
                // 1. FileVersion doesn't exist - normal for a new, empty stream
                // 1. FileVersion exists and indicates that we can read it 
                return (_fileVersion == null) || 
                    _fileVersion.IsReadableBy(_codeVersion.ReaderVersion);
            } 
        }

        /// 
        /// Callback for when a stream is written to 
        /// 
        /// Can modify the FormatVersion stream pointer. 
        internal void WriteAttempt() 
        {
            CheckDisposed();    // central location 

            if (!_writeOccurred)
            {
                // first try to read the format version 
                EnsureParsed();
 
                if (_fileVersion == null) 
                {
                    // stream is empty so write our version 
                    PersistVersion(_codeVersion);
                }
                else
                { 
                    // file version found - ensure we are able to update it
                    if (!_fileVersion.IsUpdatableBy(_codeVersion.UpdaterVersion)) 
                    { 
                        throw new FileFormatException(
                                        SR.Get( 
                                            SRID.UpdaterVersionError,
                                            _fileVersion.UpdaterVersion,
                                            _codeVersion
                                            ) 
                                        );
                    } 
 
                    // if our version is different than previous
                    // updater then "update" the updater 
                    if (_codeVersion.UpdaterVersion != _fileVersion.UpdaterVersion)
                    {
                        _fileVersion.UpdaterVersion = _codeVersion.UpdaterVersion;
                        PersistVersion(_fileVersion); 
                    }
                } 
 
                _writeOccurred = true;
            } 
        }

        internal void ReadAttempt()
        { 
            ReadAttempt(false);
        } 
 
        /// 
        /// Callback for when a Stream is read from 
        /// 
        /// Can modify the FormatVersion stream pointer.
        /// caller requires an existing FormatVersion
        internal void ReadAttempt(bool throwIfEmpty) 
        {
            CheckDisposed();    // central location 
 
            // only do this once
            if (!_readOccurred) 
            {
                // read
                EnsureParsed();
 
                // first usage?
                if (throwIfEmpty || BaseStream.Length > 0) 
                { 
                    if (_fileVersion == null)
                        throw new FileFormatException(SR.Get(SRID.VersionStreamMissing)); 

                    // compare versions
                    // verify we can read this version
                    if (!_fileVersion.IsReadableBy(_codeVersion.ReaderVersion)) 
                    {
                        throw new FileFormatException( 
                                        SR.Get( 
                                            SRID.ReaderVersionError,
                                            _fileVersion.ReaderVersion, 
                                            _codeVersion
                                            )
                                        );
                    } 
                }
                _readOccurred = true; 
            } 
        }
 
        //------------------------------------------------------
        //
        //  Private Methods
        // 
        //-----------------------------------------------------
        ///  
        /// Ensure that the version is persisted 
        /// 
        /// Leaves stream at position just after the FormatVersion. 
        /// Destructive.  This is called automatically from WriteAttempt but callers
        /// can call directly if they have changed the stream contents to a format
        /// that is no longer compatible with the persisted FormatVersion.  If
        /// this is not called directly, and a FormatVersion was found in the file 
        /// then only the Updater field is modified.
        ///  
        private void PersistVersion(FormatVersion version) 
        {
            if (!BaseStream.CanWrite) 
                throw new NotSupportedException(SR.Get(SRID.WriteNotSupported));

            // normalize and save
            long tempPos = checked(BaseStream.Position - _dataOffset); 
            BaseStream.Seek(0, SeekOrigin.Begin);
 
            // update _dataOffset 
            long offset = version.SaveToStream(BaseStream);
            _fileVersion = version;     // we know what it is - no need to deserialize 

            // existing value - ensure we didn't change sizes as this could lead to
            // data corruption
            if ((_dataOffset != 0) && (offset != _dataOffset)) 
                throw new FileFormatException(SR.Get(SRID.VersionUpdateFailure));
 
            // at this point we know the offset 
            _dataOffset = offset;
 
            // restore and shift
            checked { BaseStream.Position = tempPos + _dataOffset; }
        }
 
        /// 
        /// Load and compare feature identifier 
        ///  
        /// There is no need for this method to maintain any previous Seek pointer.
        /// This method only modifies the stream position when called for the first time with a non-empty 
        /// stream.  It is always called from Seek() and set_Position, which subsequently modify the stream
        /// pointer as appropriate after the call.
        private void EnsureParsed()
        { 
            // empty stream cannot have a version in it
            if ((_fileVersion == null) && (BaseStream.Length > 0)) 
            { 
                Debug.Assert(_dataOffset == 0);
 
                // if no version was found and we cannot read from it, then the format is invalid
                if (!BaseStream.CanRead)
                    throw new NotSupportedException(SR.Get(SRID.ReadNotSupported));
 
                //
                // The physical stream begins with a header that identifies the transform to 
                // which the stream belongs. The "logical" stream object handed to us by the 
                // compound file begins -after- this stream header, so when we seek to the
                // "beginning" of this stream, we are actually seeking to the location after 
                // the stream header, where the instance data starts.
                //
                BaseStream.Seek(0, SeekOrigin.Begin);
 
                //
                // The instance data starts with format version information for this transform. 
                // 
                _fileVersion = FormatVersion.LoadFromStream(BaseStream);
 
                //
                // Ensure that the feature name is as expected.
                //
                // NOTE: We preserve case, but do case-insensitive comparison. 
                if (String.CompareOrdinal(
                                _fileVersion.FeatureIdentifier.ToUpper(CultureInfo.InvariantCulture), 
                                _codeVersion.FeatureIdentifier.ToUpper(CultureInfo.InvariantCulture)) != 0) 
                {
                    throw new FileFormatException( 
                                    SR.Get(
                                        SRID.InvalidTransformFeatureName,
                                        _fileVersion.FeatureIdentifier,
                                        _codeVersion.FeatureIdentifier 
                                        )
                                    ); 
                } 

                _dataOffset = BaseStream.Position; 
            }
        }

        //------------------------------------------------------ 
        //
        //  Private Fields 
        // 
        //------------------------------------------------------
        private bool            _writeOccurred;     // did one of our streams get written to? 
        private bool            _readOccurred;      // did one of our streams get read from?
        private FormatVersion   _codeVersion;       // code version
        private FormatVersion   _fileVersion;       // current file version (null if not read or created yet)
        private long            _dataOffset = 0;    // where FormatVersion ends and data begins 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//   This class provides file versioning support for streams provided by 
//   IDataTransform implementations and any client code that needs
//   to store a FormatVersion at the beginning of a stream. 
//
// History:
//  02/21/2006: BruceMac: Initial implementation.
// 
//-----------------------------------------------------------------------------
 
using System; 
using System.IO;                                // for Stream
using System.Windows;                           // ExceptionStringTable 
using System.Globalization;                     // for CultureInfo
using System.Diagnostics;                       // for Debug.Assert

namespace MS.Internal.IO.Packaging.CompoundFile 
{
    ///  
    /// Specialized stream that owns the FormatVersion 
    /// 
    /// Dispose() functionality is handled by our subclass VersionedStream 
    internal class VersionedStreamOwner : VersionedStream
    {
        #region Stream Methods
        ///  
        /// Return the bytes requested from the container
        ///  
        public override int Read(byte[] buffer, int offset, int count) 
        {
            // throw if version missing 
            ReadAttempt(true);
            return BaseStream.Read(buffer, offset, count);
        }
 
        /// 
        /// Write 
        ///  
        public override void Write(byte[] buffer, int offset, int count)
        { 
            WriteAttempt();
            BaseStream.Write(buffer, offset, count);
        }
 
        /// 
        /// ReadByte 
        ///  
        public override int ReadByte()
        { 
            ReadAttempt(true);
            return BaseStream.ReadByte();
        }
 
        /// 
        /// WriteByte 
        ///  
        public override void WriteByte(byte b)
        { 
            WriteAttempt();
            BaseStream.WriteByte(b);
        }
 
        /// 
        /// Seek 
        ///  
        /// offset
        /// origin 
        /// zero
        public override long Seek(long offset, SeekOrigin origin)
        {
            ReadAttempt(); 

            long temp = -1; 
            switch (origin) 
            {
                // seek beyond the FormatVersion 
                case SeekOrigin.Begin:
                    temp = offset;
                    break;
 
                case SeekOrigin.Current:
                    checked { temp = Position + offset; } 
                    break; 

                case SeekOrigin.End: 
                    checked { temp = Length + offset; }
                    break;
            }
 
            if (temp < 0)
                throw new ArgumentException(SR.Get(SRID.SeekNegative)); 
 
            checked { BaseStream.Position = temp + _dataOffset; }
            return temp; 
        }

        /// 
        /// SetLength 
        /// 
        public override void SetLength(long newLength) 
        { 
            if (newLength < 0)
                throw new ArgumentOutOfRangeException("newLength"); 

            WriteAttempt();
            checked { BaseStream.SetLength(newLength + _dataOffset); }
        } 

        ///  
        /// Flush 
        /// 
        public override void Flush() 
        {
            CheckDisposed();
            BaseStream.Flush();
        } 
        #endregion Stream Methods
 
        //----------------------------------------------------- 
        //
        //  Public Properties 
        //
        //-----------------------------------------------------
        #region Stream Properties
        ///  
        /// Current logical position within the stream
        ///  
        public override long Position 
        {
            get 
            {
                ReadAttempt();  // ensure _dataOffset is valid
                return checked(BaseStream.Position - _dataOffset);
            } 
            set
            { 
                // share Seek logic and validation 
                Seek(value, SeekOrigin.Begin);
            } 
        }

        /// 
        /// Length 
        /// 
        public override long Length 
        { 
            get
            { 
                ReadAttempt();  // ensure _dataOffset is valid

                long temp = checked(BaseStream.Length - _dataOffset);
                Invariant.Assert(temp >= 0);                    // catch any math errors 
                return temp;
            } 
        } 

        ///  
        /// Is stream readable?
        /// 
        /// returns false when called on disposed stream
        public override bool CanRead 
        {
            get 
            { 
                return (BaseStream != null) && BaseStream.CanRead && IsReadable;
            } 
        }

        /// 
        /// Is stream seekable - should be handled by our owner 
        /// 
        /// returns false when called on disposed stream 
        public override bool CanSeek 
        {
            get 
            {
                return (BaseStream != null) && BaseStream.CanSeek && IsReadable;
            }
        } 

        ///  
        /// Is stream writeable? 
        /// 
        /// returns false when called on disposed stream 
        public override bool CanWrite
        {
            get
            { 
                return (BaseStream != null) && BaseStream.CanWrite && IsUpdatable;
            } 
        } 
        #endregion
 

        /// 
        /// Constructor to use for the "versioned stream" - the one that actually houses the
        /// persisted FormatVersion. 
        /// 
        ///  
        ///  
        internal VersionedStreamOwner(Stream baseStream, FormatVersion codeVersion)
            : base(baseStream) 
        {
            _codeVersion = codeVersion;
        }
 
        internal bool IsUpdatable
        { 
            get 
            {
                CheckDisposed(); 

                // first try to read the format version
                EnsureParsed();
 
                // We can write if either:
                // 1. FileVersion doesn't exist - this is normal for a new, empty stream 
                // 2. It does exist and the FormatVersion indicates that we can update it 
                return (_fileVersion == null) ||
                    _fileVersion.IsUpdatableBy(_codeVersion.UpdaterVersion); 
            }
        }

        internal bool IsReadable 
        {
            get 
            { 
                CheckDisposed();
 
                // first try to read the format version
                EnsureParsed();

                // We can read if either: 
                // 1. FileVersion doesn't exist - normal for a new, empty stream
                // 1. FileVersion exists and indicates that we can read it 
                return (_fileVersion == null) || 
                    _fileVersion.IsReadableBy(_codeVersion.ReaderVersion);
            } 
        }

        /// 
        /// Callback for when a stream is written to 
        /// 
        /// Can modify the FormatVersion stream pointer. 
        internal void WriteAttempt() 
        {
            CheckDisposed();    // central location 

            if (!_writeOccurred)
            {
                // first try to read the format version 
                EnsureParsed();
 
                if (_fileVersion == null) 
                {
                    // stream is empty so write our version 
                    PersistVersion(_codeVersion);
                }
                else
                { 
                    // file version found - ensure we are able to update it
                    if (!_fileVersion.IsUpdatableBy(_codeVersion.UpdaterVersion)) 
                    { 
                        throw new FileFormatException(
                                        SR.Get( 
                                            SRID.UpdaterVersionError,
                                            _fileVersion.UpdaterVersion,
                                            _codeVersion
                                            ) 
                                        );
                    } 
 
                    // if our version is different than previous
                    // updater then "update" the updater 
                    if (_codeVersion.UpdaterVersion != _fileVersion.UpdaterVersion)
                    {
                        _fileVersion.UpdaterVersion = _codeVersion.UpdaterVersion;
                        PersistVersion(_fileVersion); 
                    }
                } 
 
                _writeOccurred = true;
            } 
        }

        internal void ReadAttempt()
        { 
            ReadAttempt(false);
        } 
 
        /// 
        /// Callback for when a Stream is read from 
        /// 
        /// Can modify the FormatVersion stream pointer.
        /// caller requires an existing FormatVersion
        internal void ReadAttempt(bool throwIfEmpty) 
        {
            CheckDisposed();    // central location 
 
            // only do this once
            if (!_readOccurred) 
            {
                // read
                EnsureParsed();
 
                // first usage?
                if (throwIfEmpty || BaseStream.Length > 0) 
                { 
                    if (_fileVersion == null)
                        throw new FileFormatException(SR.Get(SRID.VersionStreamMissing)); 

                    // compare versions
                    // verify we can read this version
                    if (!_fileVersion.IsReadableBy(_codeVersion.ReaderVersion)) 
                    {
                        throw new FileFormatException( 
                                        SR.Get( 
                                            SRID.ReaderVersionError,
                                            _fileVersion.ReaderVersion, 
                                            _codeVersion
                                            )
                                        );
                    } 
                }
                _readOccurred = true; 
            } 
        }
 
        //------------------------------------------------------
        //
        //  Private Methods
        // 
        //-----------------------------------------------------
        ///  
        /// Ensure that the version is persisted 
        /// 
        /// Leaves stream at position just after the FormatVersion. 
        /// Destructive.  This is called automatically from WriteAttempt but callers
        /// can call directly if they have changed the stream contents to a format
        /// that is no longer compatible with the persisted FormatVersion.  If
        /// this is not called directly, and a FormatVersion was found in the file 
        /// then only the Updater field is modified.
        ///  
        private void PersistVersion(FormatVersion version) 
        {
            if (!BaseStream.CanWrite) 
                throw new NotSupportedException(SR.Get(SRID.WriteNotSupported));

            // normalize and save
            long tempPos = checked(BaseStream.Position - _dataOffset); 
            BaseStream.Seek(0, SeekOrigin.Begin);
 
            // update _dataOffset 
            long offset = version.SaveToStream(BaseStream);
            _fileVersion = version;     // we know what it is - no need to deserialize 

            // existing value - ensure we didn't change sizes as this could lead to
            // data corruption
            if ((_dataOffset != 0) && (offset != _dataOffset)) 
                throw new FileFormatException(SR.Get(SRID.VersionUpdateFailure));
 
            // at this point we know the offset 
            _dataOffset = offset;
 
            // restore and shift
            checked { BaseStream.Position = tempPos + _dataOffset; }
        }
 
        /// 
        /// Load and compare feature identifier 
        ///  
        /// There is no need for this method to maintain any previous Seek pointer.
        /// This method only modifies the stream position when called for the first time with a non-empty 
        /// stream.  It is always called from Seek() and set_Position, which subsequently modify the stream
        /// pointer as appropriate after the call.
        private void EnsureParsed()
        { 
            // empty stream cannot have a version in it
            if ((_fileVersion == null) && (BaseStream.Length > 0)) 
            { 
                Debug.Assert(_dataOffset == 0);
 
                // if no version was found and we cannot read from it, then the format is invalid
                if (!BaseStream.CanRead)
                    throw new NotSupportedException(SR.Get(SRID.ReadNotSupported));
 
                //
                // The physical stream begins with a header that identifies the transform to 
                // which the stream belongs. The "logical" stream object handed to us by the 
                // compound file begins -after- this stream header, so when we seek to the
                // "beginning" of this stream, we are actually seeking to the location after 
                // the stream header, where the instance data starts.
                //
                BaseStream.Seek(0, SeekOrigin.Begin);
 
                //
                // The instance data starts with format version information for this transform. 
                // 
                _fileVersion = FormatVersion.LoadFromStream(BaseStream);
 
                //
                // Ensure that the feature name is as expected.
                //
                // NOTE: We preserve case, but do case-insensitive comparison. 
                if (String.CompareOrdinal(
                                _fileVersion.FeatureIdentifier.ToUpper(CultureInfo.InvariantCulture), 
                                _codeVersion.FeatureIdentifier.ToUpper(CultureInfo.InvariantCulture)) != 0) 
                {
                    throw new FileFormatException( 
                                    SR.Get(
                                        SRID.InvalidTransformFeatureName,
                                        _fileVersion.FeatureIdentifier,
                                        _codeVersion.FeatureIdentifier 
                                        )
                                    ); 
                } 

                _dataOffset = BaseStream.Position; 
            }
        }

        //------------------------------------------------------ 
        //
        //  Private Fields 
        // 
        //------------------------------------------------------
        private bool            _writeOccurred;     // did one of our streams get written to? 
        private bool            _readOccurred;      // did one of our streams get read from?
        private FormatVersion   _codeVersion;       // code version
        private FormatVersion   _fileVersion;       // current file version (null if not read or created yet)
        private long            _dataOffset = 0;    // where FormatVersion ends and data begins 
    }
} 

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