ProgressiveCrcCalculatingStream.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 / Zip / ProgressiveCrcCalculatingStream.cs / 1 / ProgressiveCrcCalculatingStream.cs

                            //------------------------------------------------------------------------------ 
//-------------   *** WARNING ***
//-------------    This file is part of a legally monitored development project.
//-------------    Do not check in changes to this project.  Do not raid bugs on this
//-------------    code in the main PS database.  Do not contact the owner of this 
//-------------    code directly.  Contact the legal team at ‘ZSLegal’ for assistance.
//-------------   *** WARNING *** 
//----------------------------------------------------------------------------- 

//----------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  This is an internal stream class that calcuates CRC values progressively 
//      if possible
// 
// History:
//  06/03/2005: YoungGK: Initial creation.
//
//----------------------------------------------------------------------------- 

using System; 
using System.Diagnostics; 
using System.IO;
using System.Windows;               // For Exception strings - SRID 

using MS.Internal.IO.Zip;

namespace MS.Internal.IO.Zip 
{
    internal class ProgressiveCrcCalculatingStream:  Stream 
    { 
        ////////////////////////////////////
        // Stream section 
        /////////////////////////////////
        override public bool CanRead
        {
            get 
            {
                return (_underlyingStream != null && _underlyingStream.CanRead); 
            } 
        }
 
        override public bool CanSeek
        {
            get
            { 
                return (_underlyingStream != null && _underlyingStream.CanSeek);
            } 
        } 

        override public bool CanWrite 
        {
            get
            {
                return (_underlyingStream != null && _underlyingStream.CanWrite); 
            }
        } 
 
        override public long Length
        { 
            get
            {
                CheckDisposed();
 
                return  _underlyingStream.Length;
            } 
        } 

        override public long Position 
        {
            get
            {
                CheckDisposed(); 

                return _underlyingStream.Position; 
            } 

            set 
            {
                CheckDisposed();

                _underlyingStream.Position = value; 
            }
        } 
 
        public override void SetLength(long newLength)
        { 
            CheckDisposed();

            if (newLength < 0)
            { 
                throw new ArgumentOutOfRangeException("newLength");
            } 
 
            if (newLength < _highWaterMark)
            { 
                _highWaterMark = -1;
            }

            // We don't do any check if newLength == current length here 
            //  this normally should result in no-op, but this will complicate
            //  the logic due to the need of caching the underlying stream length 
            // Not doing this check here might result in CRC check being skipped 

            _underlyingStream.SetLength(newLength); 
            // Setting a new length is the same as write operation
            // CRC cannot be checked against the to-be-validated CRC anymore
            _validateCrcWithExpectedCrc = false;
 
            // mark the global dirty flag
            _blockManager.DirtyFlag = true; 
        } 

        override public long Seek(long offset, SeekOrigin origin) 
        {
            CheckDisposed();

            return _underlyingStream.Seek(offset, origin); 
        }
 
        override public int Read(byte[] buffer, int offset, int count) 
        {
            CheckDisposed(); 

            int readCount = 0;

            // We should calculate CRC accumulatively for the following conditions 
            // 1. Seek is not supported by the underlying stream: this will be the case for
            //      writing stream in streaming mode 
            // 2. This write request is consequtive to the highwater mark of the CRC calculation 
            // 3. This write request is at 0 offset and the CRC hasn't been calculated yet
            if (!_underlyingStream.CanSeek)                   // Case #1 
            {
                readCount = _underlyingStream.Read(buffer, offset, count);
                CrcCalculator.Accumulate(buffer, offset, readCount);
            } 
            else
            { 
                long originalPosition = _underlyingStream.Position; 

                readCount = _underlyingStream.Read(buffer, offset, count); 

                // This operation needs to be done after Read since read can throw an exception; in that case
                //  we want to preserve the original CRC
                if (originalPosition == 0 && _highWaterMark == -1) 
                {
                    _highWaterMark = 0; 
                    CrcCalculator.ClearCrc(); 
                }
 
                if (originalPosition == _highWaterMark)
                {
                    CrcCalculator.Accumulate(buffer, offset, readCount);
                    _highWaterMark = _underlyingStream.Position; 
                }
 
                if (_validateCrcWithExpectedCrc && CanValidateCrcWithoutRead()) 
                {
                    if (CrcCalculator.Crc != _expectedCrc) 
                    {
                        throw new FileFormatException(SR.Get(SRID.CorruptedData));
                    }
                } 
            }
 
            return readCount; 
        }
 
        override public void Write(byte[] buffer, int offset, int count)
        {
            CheckDisposed();
 
            // We should calculate CRC accumulatively for the following conditions
            // 1. Seek is not supported by the underlying stream: this will be the case for 
            //      writing stream in streaming mode 
            // 2. This write request is consequtive to the highwater mark of the CRC calculation
            // 3. This write request is at 0 offset and the CRC hasn't been calculated yet 
            if (!_underlyingStream.CanSeek)                   // Case #1
            {
                _underlyingStream.Write(buffer, offset, count);
                CrcCalculator.Accumulate(buffer, offset, count); 
            }
            else 
            { 
                long originalPosition = _underlyingStream.Position;
 
                // If we ever fail to Write below _highWaterMark, we want CRC to be recalculated in case
                //  if a caller decides to recover from the error
                if (originalPosition < _highWaterMark)
                { 
                    _highWaterMark = -1;
                } 
 
                _underlyingStream.Write(buffer, offset, count);
 
                if (originalPosition == 0)
                {
                    _highWaterMark = 0;
                    CrcCalculator.ClearCrc(); 

                } 
 
                if (originalPosition == _highWaterMark)
                { 
                    CrcCalculator.Accumulate(buffer, offset, count);
                    _highWaterMark = _underlyingStream.Position;
                }
            } 

            // CRC cannot be checked against the to-be-validated CRC anymore 
            _validateCrcWithExpectedCrc = false; 

            // mark the global dirty flag 
            _blockManager.DirtyFlag = true;
        }

        override public void Flush() 
        {
            CheckDisposed(); 
 
            _underlyingStream.Flush();
        } 

        /////////////////////////////
        // Internal Constructor
        ///////////////////////////// 
        internal  ProgressiveCrcCalculatingStream(ZipIOBlockManager blockManager, Stream underlyingStream) :
            this(blockManager, underlyingStream, 0) 
        { 
            _validateCrcWithExpectedCrc = false;
        } 

        internal  ProgressiveCrcCalculatingStream(ZipIOBlockManager blockManager, Stream underlyingStream, UInt32 expectedCrc)
        {
            Debug.Assert(underlyingStream != null); 
            Debug.Assert(blockManager != null);
 
            _blockManager = blockManager; 
            _underlyingStream = underlyingStream;
            _validateCrcWithExpectedCrc = true; 
            _expectedCrc = expectedCrc;
            _highWaterMark = -1;
        }
 
        //------------------------------------------------------
        // 
        //  Protected Methods 
        //
        //----------------------------------------------------- 
        /// 
        /// Dispose(bool)
        /// 
        ///  
        /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to
        /// call Dispose() instead of Close(). 
        protected override void Dispose(bool disposing) 
        {
            try 
            {
                if (disposing)
                {
                    //streams wrapping this stream shouldn't pass Dipose calls through 
                    // it is responsibility of the BlockManager or LocalFileBlock (in case of Remove) to call
                    // this dispose as appropriate (that is the reason why Flush isn't called here) 
 
                    // multiple calls are fine - just ignore them
                    // and we shouldn't be closing a stream which we do not own 
                    _underlyingStream = null;
                }
            }
            finally 
            {
                base.Dispose(disposing); 
            } 
        }
 
        /////////////////////////////
        // Internal Methods
        /////////////////////////////
 

        // !!!!!!!!!!!!!!!!IMPORTANT !!!!!!!!!!!!!!!! 
        // This method doesn't preserve the seek position of the underlying stream. 
        // It (non-preservation of the seek pointer) is mostly done for compression
        // scenarios in which seeking back in the compressed streams will result in 
        // switching to the expensive simulation stream. This method is only called
        // from scenarios during Flush Close of the package where position of the
        // Compressed stream is insignificant
        internal UInt32 CalculateCrc() 
        {
            CheckDisposed(); 
 
            if (_underlyingStream.CanSeek)
            { 
                long originalPosition = _underlyingStream.Position;

                if (_highWaterMark == -1)
                { 
                    CrcCalculator.ClearCrc();
                    _highWaterMark = 0; 
                } 

                if (_highWaterMark < _underlyingStream.Length) 
                {
                    _underlyingStream.Position = _highWaterMark;
                    CrcCalculator.CalculateStreamCrc(_underlyingStream);
                    _highWaterMark = _underlyingStream.Length; 
                }
            } 
 
            return CrcCalculator.Crc;
        } 

        /////////////////////////////
        // Private Methods
        ///////////////////////////// 

        private void CheckDisposed() 
        { 
            if (_underlyingStream == null)
            { 
                throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed));
            }
        }
 
        private Crc32Calculator CrcCalculator
        { 
            get 
            {
                if (_crcCalculator == null) 
                {
                    _crcCalculator = new Crc32Calculator();
                }
                return _crcCalculator; 
            }
        } 
 
        private bool CanValidateCrcWithoutRead()
        { 
            if (_underlyingStream.CanSeek && _highWaterMark == _underlyingStream.Length)
            {
                return true;
            } 

            return false; 
        } 

        // this is only used to switch the dirty flag in case of Write or SetLength 
        // no other communication is done with the BlockManager from this class
        private ZipIOBlockManager _blockManager;

        private long _highWaterMark; 
        private Crc32Calculator _crcCalculator;
        private bool _validateCrcWithExpectedCrc; 
        private UInt32 _expectedCrc; 

        private Stream _underlyingStream; 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
//-------------   *** WARNING ***
//-------------    This file is part of a legally monitored development project.
//-------------    Do not check in changes to this project.  Do not raid bugs on this
//-------------    code in the main PS database.  Do not contact the owner of this 
//-------------    code directly.  Contact the legal team at ‘ZSLegal’ for assistance.
//-------------   *** WARNING *** 
//----------------------------------------------------------------------------- 

//----------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  This is an internal stream class that calcuates CRC values progressively 
//      if possible
// 
// History:
//  06/03/2005: YoungGK: Initial creation.
//
//----------------------------------------------------------------------------- 

using System; 
using System.Diagnostics; 
using System.IO;
using System.Windows;               // For Exception strings - SRID 

using MS.Internal.IO.Zip;

namespace MS.Internal.IO.Zip 
{
    internal class ProgressiveCrcCalculatingStream:  Stream 
    { 
        ////////////////////////////////////
        // Stream section 
        /////////////////////////////////
        override public bool CanRead
        {
            get 
            {
                return (_underlyingStream != null && _underlyingStream.CanRead); 
            } 
        }
 
        override public bool CanSeek
        {
            get
            { 
                return (_underlyingStream != null && _underlyingStream.CanSeek);
            } 
        } 

        override public bool CanWrite 
        {
            get
            {
                return (_underlyingStream != null && _underlyingStream.CanWrite); 
            }
        } 
 
        override public long Length
        { 
            get
            {
                CheckDisposed();
 
                return  _underlyingStream.Length;
            } 
        } 

        override public long Position 
        {
            get
            {
                CheckDisposed(); 

                return _underlyingStream.Position; 
            } 

            set 
            {
                CheckDisposed();

                _underlyingStream.Position = value; 
            }
        } 
 
        public override void SetLength(long newLength)
        { 
            CheckDisposed();

            if (newLength < 0)
            { 
                throw new ArgumentOutOfRangeException("newLength");
            } 
 
            if (newLength < _highWaterMark)
            { 
                _highWaterMark = -1;
            }

            // We don't do any check if newLength == current length here 
            //  this normally should result in no-op, but this will complicate
            //  the logic due to the need of caching the underlying stream length 
            // Not doing this check here might result in CRC check being skipped 

            _underlyingStream.SetLength(newLength); 
            // Setting a new length is the same as write operation
            // CRC cannot be checked against the to-be-validated CRC anymore
            _validateCrcWithExpectedCrc = false;
 
            // mark the global dirty flag
            _blockManager.DirtyFlag = true; 
        } 

        override public long Seek(long offset, SeekOrigin origin) 
        {
            CheckDisposed();

            return _underlyingStream.Seek(offset, origin); 
        }
 
        override public int Read(byte[] buffer, int offset, int count) 
        {
            CheckDisposed(); 

            int readCount = 0;

            // We should calculate CRC accumulatively for the following conditions 
            // 1. Seek is not supported by the underlying stream: this will be the case for
            //      writing stream in streaming mode 
            // 2. This write request is consequtive to the highwater mark of the CRC calculation 
            // 3. This write request is at 0 offset and the CRC hasn't been calculated yet
            if (!_underlyingStream.CanSeek)                   // Case #1 
            {
                readCount = _underlyingStream.Read(buffer, offset, count);
                CrcCalculator.Accumulate(buffer, offset, readCount);
            } 
            else
            { 
                long originalPosition = _underlyingStream.Position; 

                readCount = _underlyingStream.Read(buffer, offset, count); 

                // This operation needs to be done after Read since read can throw an exception; in that case
                //  we want to preserve the original CRC
                if (originalPosition == 0 && _highWaterMark == -1) 
                {
                    _highWaterMark = 0; 
                    CrcCalculator.ClearCrc(); 
                }
 
                if (originalPosition == _highWaterMark)
                {
                    CrcCalculator.Accumulate(buffer, offset, readCount);
                    _highWaterMark = _underlyingStream.Position; 
                }
 
                if (_validateCrcWithExpectedCrc && CanValidateCrcWithoutRead()) 
                {
                    if (CrcCalculator.Crc != _expectedCrc) 
                    {
                        throw new FileFormatException(SR.Get(SRID.CorruptedData));
                    }
                } 
            }
 
            return readCount; 
        }
 
        override public void Write(byte[] buffer, int offset, int count)
        {
            CheckDisposed();
 
            // We should calculate CRC accumulatively for the following conditions
            // 1. Seek is not supported by the underlying stream: this will be the case for 
            //      writing stream in streaming mode 
            // 2. This write request is consequtive to the highwater mark of the CRC calculation
            // 3. This write request is at 0 offset and the CRC hasn't been calculated yet 
            if (!_underlyingStream.CanSeek)                   // Case #1
            {
                _underlyingStream.Write(buffer, offset, count);
                CrcCalculator.Accumulate(buffer, offset, count); 
            }
            else 
            { 
                long originalPosition = _underlyingStream.Position;
 
                // If we ever fail to Write below _highWaterMark, we want CRC to be recalculated in case
                //  if a caller decides to recover from the error
                if (originalPosition < _highWaterMark)
                { 
                    _highWaterMark = -1;
                } 
 
                _underlyingStream.Write(buffer, offset, count);
 
                if (originalPosition == 0)
                {
                    _highWaterMark = 0;
                    CrcCalculator.ClearCrc(); 

                } 
 
                if (originalPosition == _highWaterMark)
                { 
                    CrcCalculator.Accumulate(buffer, offset, count);
                    _highWaterMark = _underlyingStream.Position;
                }
            } 

            // CRC cannot be checked against the to-be-validated CRC anymore 
            _validateCrcWithExpectedCrc = false; 

            // mark the global dirty flag 
            _blockManager.DirtyFlag = true;
        }

        override public void Flush() 
        {
            CheckDisposed(); 
 
            _underlyingStream.Flush();
        } 

        /////////////////////////////
        // Internal Constructor
        ///////////////////////////// 
        internal  ProgressiveCrcCalculatingStream(ZipIOBlockManager blockManager, Stream underlyingStream) :
            this(blockManager, underlyingStream, 0) 
        { 
            _validateCrcWithExpectedCrc = false;
        } 

        internal  ProgressiveCrcCalculatingStream(ZipIOBlockManager blockManager, Stream underlyingStream, UInt32 expectedCrc)
        {
            Debug.Assert(underlyingStream != null); 
            Debug.Assert(blockManager != null);
 
            _blockManager = blockManager; 
            _underlyingStream = underlyingStream;
            _validateCrcWithExpectedCrc = true; 
            _expectedCrc = expectedCrc;
            _highWaterMark = -1;
        }
 
        //------------------------------------------------------
        // 
        //  Protected Methods 
        //
        //----------------------------------------------------- 
        /// 
        /// Dispose(bool)
        /// 
        ///  
        /// We implement this because we want a consistent experience (essentially Flush our data) if the user chooses to
        /// call Dispose() instead of Close(). 
        protected override void Dispose(bool disposing) 
        {
            try 
            {
                if (disposing)
                {
                    //streams wrapping this stream shouldn't pass Dipose calls through 
                    // it is responsibility of the BlockManager or LocalFileBlock (in case of Remove) to call
                    // this dispose as appropriate (that is the reason why Flush isn't called here) 
 
                    // multiple calls are fine - just ignore them
                    // and we shouldn't be closing a stream which we do not own 
                    _underlyingStream = null;
                }
            }
            finally 
            {
                base.Dispose(disposing); 
            } 
        }
 
        /////////////////////////////
        // Internal Methods
        /////////////////////////////
 

        // !!!!!!!!!!!!!!!!IMPORTANT !!!!!!!!!!!!!!!! 
        // This method doesn't preserve the seek position of the underlying stream. 
        // It (non-preservation of the seek pointer) is mostly done for compression
        // scenarios in which seeking back in the compressed streams will result in 
        // switching to the expensive simulation stream. This method is only called
        // from scenarios during Flush Close of the package where position of the
        // Compressed stream is insignificant
        internal UInt32 CalculateCrc() 
        {
            CheckDisposed(); 
 
            if (_underlyingStream.CanSeek)
            { 
                long originalPosition = _underlyingStream.Position;

                if (_highWaterMark == -1)
                { 
                    CrcCalculator.ClearCrc();
                    _highWaterMark = 0; 
                } 

                if (_highWaterMark < _underlyingStream.Length) 
                {
                    _underlyingStream.Position = _highWaterMark;
                    CrcCalculator.CalculateStreamCrc(_underlyingStream);
                    _highWaterMark = _underlyingStream.Length; 
                }
            } 
 
            return CrcCalculator.Crc;
        } 

        /////////////////////////////
        // Private Methods
        ///////////////////////////// 

        private void CheckDisposed() 
        { 
            if (_underlyingStream == null)
            { 
                throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed));
            }
        }
 
        private Crc32Calculator CrcCalculator
        { 
            get 
            {
                if (_crcCalculator == null) 
                {
                    _crcCalculator = new Crc32Calculator();
                }
                return _crcCalculator; 
            }
        } 
 
        private bool CanValidateCrcWithoutRead()
        { 
            if (_underlyingStream.CanSeek && _highWaterMark == _underlyingStream.Length)
            {
                return true;
            } 

            return false; 
        } 

        // this is only used to switch the dirty flag in case of Write or SetLength 
        // no other communication is done with the BlockManager from this class
        private ZipIOBlockManager _blockManager;

        private long _highWaterMark; 
        private Crc32Calculator _crcCalculator;
        private bool _validateCrcWithExpectedCrc; 
        private UInt32 _expectedCrc; 

        private Stream _underlyingStream; 
    }
}


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