ProgressiveCrcCalculatingStream.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / MS / Internal / IO / Zip / ProgressiveCrcCalculatingStream.cs / 1305600 / 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: [....]: Initial creation.
//
//----------------------------------------------------------------------------- 

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

using MS.Internal.IO.Zip;
using MS.Internal.WindowsBase;
 
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: [....]: Initial creation.
//
//----------------------------------------------------------------------------- 

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

using MS.Internal.IO.Zip;
using MS.Internal.WindowsBase;
 
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