Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Base / MS / Internal / IO / Zip / ZipIOFileItemStream.cs / 1 / ZipIOFileItemStream.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 class that enables interactions with Zip archives // for OPC scenarios // // History: // 11/19/2004: IgorBel: Initial creation. // 06/21/2005: BruceMac: Add Write-time-streaming support //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Text; using System.Collections; using System.Runtime.Serialization; using System.Windows; using MS.Internal.IO.Packaging; // for PackagingUtilities namespace MS.Internal.IO.Zip { internal class ZipIOFileItemStream : Stream { //////////////////////////////////// // Stream section ///////////////////////////////// override public bool CanRead { get { return (!_disposedFlag) && (_blockManager.Stream.CanRead); } } override public bool CanSeek { get { return (!_disposedFlag) && (_blockManager.Stream.CanSeek); } } override public bool CanWrite { get { return (!_disposedFlag) && (_blockManager.Stream.CanWrite); } } override public long Length { get { CheckDisposed(); return _currentStreamLength; } } override public long Position { get { CheckDisposed(); return _currentStreamPosition; } set { CheckDisposed(); Seek(value, SeekOrigin.Begin); } } public override void SetLength(long newLength) { CheckDisposed(); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // that would between PreSaveNotofication call and Save SaveStreaming if (newLength < 0) { throw new ArgumentOutOfRangeException("newLength"); } if (_currentStreamLength != newLength) { _dirtyFlag = true; _dataChanged = true; if (newLength <= _persistedSize) { // the stream becomes smaller than our disk block, which means that // we can drop the in-memory-sparse-suffix if (_sparseMemoryStreamSuffix != null) { _sparseMemoryStreamSuffix.Close(); _sparseMemoryStreamSuffix = null; } } else { // we need to construct Sparse Memory stream if we do not have one yet if (_sparseMemoryStreamSuffix == null) { _sparseMemoryStreamSuffix = new SparseMemoryStream(_lowWaterMark, _highWaterMark); } // set size on the Sparse Memory Stream _sparseMemoryStreamSuffix.SetLength(newLength - _persistedSize); // no need for checked as it was verified above } _currentStreamLength = newLength; // if stream was truncated to the point that our current position is beyond the end of the stream, // we need to reset position so it is at the end of the stream if (_currentStreamLength < _currentStreamPosition) Seek(_currentStreamLength, SeekOrigin.Begin); } } override public long Seek(long offset, SeekOrigin origin) { CheckDisposed(); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // that would between PreSaveNotofication call and Save SaveStreaming long newStreamPosition = _currentStreamPosition; if (origin ==SeekOrigin.Begin) { newStreamPosition = offset; } else if (origin == SeekOrigin.Current) { checked{newStreamPosition += offset;} } else if (origin == SeekOrigin.End) { checked{newStreamPosition = _currentStreamLength + offset;} } else { throw new ArgumentOutOfRangeException("origin"); } if (newStreamPosition < 0) { throw new ArgumentException(SR.Get(SRID.SeekNegative)); } _currentStreamPosition = newStreamPosition; return _currentStreamPosition; } override public int Read(byte[] buffer, int offset, int count) { CheckDisposed(); PackagingUtilities.VerifyStreamReadArgs(this, buffer, offset, count); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // that would between PreSaveNotofication call and Save SaveStreaming Debug.Assert(_currentStreamPosition >= 0); if (count == 0) { return 0; } if (_currentStreamLength <= _currentStreamPosition) { // we are past the end of the stream so let's just return 0 return 0; } int totalBytesRead; int diskBytesRead = 0; int diskBytesToRead = 0; long persistedTailSize = 0; int memoryBytesRead = 0; long newStreamPosition = _currentStreamPosition; checked { // Try to satisfy request with the Read from the Disk if (newStreamPosition < _persistedSize) { // we have at least partial overlap between request and the data on disk //first let's get min between size of the stream's tail and the tail of the persisted chunk // in some cases stream might be smaller // e.g. _currentStreamLength < _persistedSize, if let's say stream was truncated persistedTailSize = Math.Min(_currentStreamLength, _persistedSize) - newStreamPosition; Debug.Assert(persistedTailSize > 0); // we also do not want to read more data than was requested by the user diskBytesToRead = (int)Math.Min((long)count, persistedTailSize); // this is a safe cast as count has int type Debug.Assert(diskBytesToRead > 0); // and now we can actually read it _blockManager.Stream.Seek(_persistedOffset + newStreamPosition, SeekOrigin.Begin); // we are ready for getting fewer bytes than reqested diskBytesRead = _blockManager.Stream.Read(buffer, offset, diskBytesToRead); newStreamPosition += diskBytesRead; count -= diskBytesRead; offset +=diskBytesRead; if (diskBytesRead < diskBytesToRead) { // we didn't everything that we hae asked for. In such case we shouldn't // try to get data from the _sparseMemoryStreamSuffix _currentStreamPosition = newStreamPosition; return diskBytesRead; } } // check whether we need to get data from the memory Stream; if ((_sparseMemoryStreamSuffix != null) && (newStreamPosition + count > _persistedSize)) { // we are either trying to finish the request partially satisfied by the // on disk data or the read is entirely within the suffix _sparseMemoryStreamSuffix.Seek(newStreamPosition - _persistedSize, SeekOrigin.Begin); memoryBytesRead = _sparseMemoryStreamSuffix.Read(buffer, offset, count); newStreamPosition += memoryBytesRead; } totalBytesRead = diskBytesRead + memoryBytesRead; } _currentStreamPosition = newStreamPosition; return totalBytesRead ; } ////// Write /// /// /// /// ///In streaming mode, write should accumulate data into the SparseMemoryStream. override public void Write(byte[] buffer, int offset, int count) { CheckDisposed(); PackagingUtilities.VerifyStreamWriteArgs(this, buffer, offset, count); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // that would between PreSaveNotofication call and Save SaveStreaming Debug.Assert(_currentStreamPosition >= 0); if (count == 0) { return; } int diskBytesToWrite = 0; _dirtyFlag = true; _dataChanged = true; long newStreamPosition = _currentStreamPosition; checked { // Try to satisfy request with the Write to the Disk if (newStreamPosition < _persistedSize) { Debug.Assert(!_blockManager.Streaming); // we have at least partial overlap between request and the data on disk _blockManager.Stream.Seek(_persistedOffset + newStreamPosition, SeekOrigin.Begin); // Note on casting: // It is safe to cast the result of Math.Min(count, _persistedSize - newStreamPosition)) // from long to int since it cannot be bigger than count and count is int type diskBytesToWrite = (int) (Math.Min(count, _persistedSize - newStreamPosition)); // this is a safe cast as count has int type _blockManager.Stream.Write(buffer, offset, diskBytesToWrite); newStreamPosition += diskBytesToWrite; count -= diskBytesToWrite; offset += diskBytesToWrite; } // check whether we need to save data to the memory Stream; if (newStreamPosition + count > _persistedSize) { if (_sparseMemoryStreamSuffix == null) { _sparseMemoryStreamSuffix = new SparseMemoryStream(_lowWaterMark, _highWaterMark); } _sparseMemoryStreamSuffix.Seek(newStreamPosition - _persistedSize, SeekOrigin.Begin); _sparseMemoryStreamSuffix.Write(buffer, offset, count); newStreamPosition += count; } _currentStreamPosition = newStreamPosition; _currentStreamLength = Math.Max(_currentStreamLength, _currentStreamPosition); } return; } override public void Flush() { CheckDisposed(); // tell the BlockManager that the caller called Flush on us. Block manager will process this // and possibly call us back on Save or SaveStreaming _blockManager.SaveStream(_block, false); // second parameter is a closing indicator } ///////////////////////////// // Internal Constructor ///////////////////////////// internal ZipIOFileItemStream(ZipIOBlockManager blockManager, // blockManager is only needed // to pass through to it Flush requests ZipIOLocalFileBlock block, // our owning block - needed for Streaming scenarios long persistedOffset, // to map to the stream long persistedSize) // to map to the stream ) { Debug.Assert(blockManager != null); Debug.Assert(persistedOffset >=0); Debug.Assert(persistedSize >= 0); Debug.Assert(block != null); _persistedOffset = persistedOffset; _offset = persistedOffset; _persistedSize = persistedSize; _blockManager = blockManager; _block = block; _currentStreamLength = persistedSize; } ///////////////////////////// // Internal Methods for the LocalFileBlock to call in order to know Dirty status and the new size ///////////////////////////// internal PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { return ZipIOBlockManager.CommonPreSaveNotificationHandler( _blockManager.Stream, offset, size, _persistedOffset, Math.Min(_persistedSize, _currentStreamLength), // in case the stream is smaller then our persisted block on // disk, there is no need to preserve the meaningless persisted suffix ref _cachePrefixStream); } internal bool DirtyFlag { get { return _dirtyFlag; } } internal bool DataChanged { get { return _dataChanged; } } internal long Offset { get { return _offset; } } internal void Move(long shiftSize) { CheckDisposed(); if (shiftSize != 0) { checked{_offset +=shiftSize;} _dirtyFlag = true; Debug.Assert(_offset >=0); } } ////// Streaming-specific variant of Save() /// ///Writes current data to the underlying stream. /// Assumes the stream is in the correct place. internal void SaveStreaming() { CheckDisposed(); Debug.Assert(_cachePrefixStream == null); // _cachePrefixStream must not be used in streaming cases at all Debug.Assert(_blockManager.Streaming); if (_dirtyFlag) { // in streaming cases all the data collected in the _sparseMemoryStreamSuffix // and now we can save the SparseMemoryStream if (_sparseMemoryStreamSuffix != null) { _sparseMemoryStreamSuffix.WriteToStream(_blockManager.Stream); // update so that subsequent MemoryStreams will know where they begin checked{_persistedSize += _sparseMemoryStreamSuffix.Length;} _sparseMemoryStreamSuffix.Close(); _sparseMemoryStreamSuffix = null; } _dirtyFlag = false; _dataChanged = false; } } ////// Save - called by the BlockManager to cause us to Flush to the underlying stream /// internal void Save() { CheckDisposed(); Debug.Assert(!_blockManager.Streaming); if(_dirtyFlag) { // we need to move the whole persisted block to the new position long moveBlockSourceOffset = _persistedOffset; // in case the stream is smaller then our persisted block on disk there is // no need to move meaningless persisted suffix long moveBlockSize = Math.Min(_persistedSize, _currentStreamLength); long moveBlockTargetOffset = _offset; long newPersistedSize = 0; if (_cachePrefixStream != null) { // if we have something in cache we only should move whatever isn't cached checked{moveBlockSourceOffset += _cachePrefixStream.Length;} checked{moveBlockTargetOffset += _cachePrefixStream.Length;} checked{moveBlockSize -= _cachePrefixStream.Length;} Debug.Assert(moveBlockSize >=0); } _blockManager.MoveData(moveBlockSourceOffset, moveBlockTargetOffset, moveBlockSize); checked{newPersistedSize += moveBlockSize;} // only after data on disk was moved it is safe to flush the cached prefix buffer if (_cachePrefixStream != null) { // we need to seek and it is safe to do as we are not in the streaming mode _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); Debug.Assert(_cachePrefixStream.Length > 0); // should be taken care of by the constructor // and PreSaveNotification _cachePrefixStream.WriteToStream(_blockManager.Stream); checked{newPersistedSize += _cachePrefixStream.Length;} // we can free the memory _cachePrefixStream.Close(); _cachePrefixStream = null; } // and now we can save the SparseMemoryStream if (_sparseMemoryStreamSuffix != null) { if (_blockManager.Stream.Position != checked (_offset + _persistedSize)) { // we need to seek _blockManager.Stream.Seek(_offset + _persistedSize, SeekOrigin.Begin); } _sparseMemoryStreamSuffix.WriteToStream(_blockManager.Stream); checked{newPersistedSize += _sparseMemoryStreamSuffix.Length;} _sparseMemoryStreamSuffix.Close(); _sparseMemoryStreamSuffix = null; } _blockManager.Stream.Flush(); // we are not shifted between on disk image and in memory image any more _persistedOffset = _offset; _persistedSize = newPersistedSize; Debug.Assert(newPersistedSize == _currentStreamLength); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // after we are saved this field must be clear _dirtyFlag = false; _dataChanged = false; } } //------------------------------------------------------ // // 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 Dispose 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 if (!_disposedFlag) { if (_sparseMemoryStreamSuffix != null) { _sparseMemoryStreamSuffix.Close(); } if (_cachePrefixStream != null) { _cachePrefixStream.Close(); } } } } finally { _sparseMemoryStreamSuffix = null; _cachePrefixStream = null; _disposedFlag = true; base.Dispose(disposing); } } ///////////////////////////// // Private Methods ///////////////////////////// private void CheckDisposed() { if (_disposedFlag) { throw new ObjectDisposedException(null, SR.Get(SRID.ZipFileItemDisposed)); } } private ZipIOBlockManager _blockManager; private ZipIOLocalFileBlock _block; // our owning block private long _offset; private long _persistedOffset; private long _persistedSize; private SparseMemoryStream _cachePrefixStream; private bool _dirtyFlag; private bool _dataChanged; //support for Stream methods private bool _disposedFlag; private long _currentStreamLength; private long _currentStreamPosition; private SparseMemoryStream _sparseMemoryStreamSuffix; private const long _lowWaterMark = 0x19000; // we definately would like to keep everythuing under 100 KB in memory private const long _highWaterMark = 0xA00000; // we would like to keep everything over 10 MB on disk } } // 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 class that enables interactions with Zip archives // for OPC scenarios // // History: // 11/19/2004: IgorBel: Initial creation. // 06/21/2005: BruceMac: Add Write-time-streaming support //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Text; using System.Collections; using System.Runtime.Serialization; using System.Windows; using MS.Internal.IO.Packaging; // for PackagingUtilities namespace MS.Internal.IO.Zip { internal class ZipIOFileItemStream : Stream { //////////////////////////////////// // Stream section ///////////////////////////////// override public bool CanRead { get { return (!_disposedFlag) && (_blockManager.Stream.CanRead); } } override public bool CanSeek { get { return (!_disposedFlag) && (_blockManager.Stream.CanSeek); } } override public bool CanWrite { get { return (!_disposedFlag) && (_blockManager.Stream.CanWrite); } } override public long Length { get { CheckDisposed(); return _currentStreamLength; } } override public long Position { get { CheckDisposed(); return _currentStreamPosition; } set { CheckDisposed(); Seek(value, SeekOrigin.Begin); } } public override void SetLength(long newLength) { CheckDisposed(); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // that would between PreSaveNotofication call and Save SaveStreaming if (newLength < 0) { throw new ArgumentOutOfRangeException("newLength"); } if (_currentStreamLength != newLength) { _dirtyFlag = true; _dataChanged = true; if (newLength <= _persistedSize) { // the stream becomes smaller than our disk block, which means that // we can drop the in-memory-sparse-suffix if (_sparseMemoryStreamSuffix != null) { _sparseMemoryStreamSuffix.Close(); _sparseMemoryStreamSuffix = null; } } else { // we need to construct Sparse Memory stream if we do not have one yet if (_sparseMemoryStreamSuffix == null) { _sparseMemoryStreamSuffix = new SparseMemoryStream(_lowWaterMark, _highWaterMark); } // set size on the Sparse Memory Stream _sparseMemoryStreamSuffix.SetLength(newLength - _persistedSize); // no need for checked as it was verified above } _currentStreamLength = newLength; // if stream was truncated to the point that our current position is beyond the end of the stream, // we need to reset position so it is at the end of the stream if (_currentStreamLength < _currentStreamPosition) Seek(_currentStreamLength, SeekOrigin.Begin); } } override public long Seek(long offset, SeekOrigin origin) { CheckDisposed(); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // that would between PreSaveNotofication call and Save SaveStreaming long newStreamPosition = _currentStreamPosition; if (origin ==SeekOrigin.Begin) { newStreamPosition = offset; } else if (origin == SeekOrigin.Current) { checked{newStreamPosition += offset;} } else if (origin == SeekOrigin.End) { checked{newStreamPosition = _currentStreamLength + offset;} } else { throw new ArgumentOutOfRangeException("origin"); } if (newStreamPosition < 0) { throw new ArgumentException(SR.Get(SRID.SeekNegative)); } _currentStreamPosition = newStreamPosition; return _currentStreamPosition; } override public int Read(byte[] buffer, int offset, int count) { CheckDisposed(); PackagingUtilities.VerifyStreamReadArgs(this, buffer, offset, count); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // that would between PreSaveNotofication call and Save SaveStreaming Debug.Assert(_currentStreamPosition >= 0); if (count == 0) { return 0; } if (_currentStreamLength <= _currentStreamPosition) { // we are past the end of the stream so let's just return 0 return 0; } int totalBytesRead; int diskBytesRead = 0; int diskBytesToRead = 0; long persistedTailSize = 0; int memoryBytesRead = 0; long newStreamPosition = _currentStreamPosition; checked { // Try to satisfy request with the Read from the Disk if (newStreamPosition < _persistedSize) { // we have at least partial overlap between request and the data on disk //first let's get min between size of the stream's tail and the tail of the persisted chunk // in some cases stream might be smaller // e.g. _currentStreamLength < _persistedSize, if let's say stream was truncated persistedTailSize = Math.Min(_currentStreamLength, _persistedSize) - newStreamPosition; Debug.Assert(persistedTailSize > 0); // we also do not want to read more data than was requested by the user diskBytesToRead = (int)Math.Min((long)count, persistedTailSize); // this is a safe cast as count has int type Debug.Assert(diskBytesToRead > 0); // and now we can actually read it _blockManager.Stream.Seek(_persistedOffset + newStreamPosition, SeekOrigin.Begin); // we are ready for getting fewer bytes than reqested diskBytesRead = _blockManager.Stream.Read(buffer, offset, diskBytesToRead); newStreamPosition += diskBytesRead; count -= diskBytesRead; offset +=diskBytesRead; if (diskBytesRead < diskBytesToRead) { // we didn't everything that we hae asked for. In such case we shouldn't // try to get data from the _sparseMemoryStreamSuffix _currentStreamPosition = newStreamPosition; return diskBytesRead; } } // check whether we need to get data from the memory Stream; if ((_sparseMemoryStreamSuffix != null) && (newStreamPosition + count > _persistedSize)) { // we are either trying to finish the request partially satisfied by the // on disk data or the read is entirely within the suffix _sparseMemoryStreamSuffix.Seek(newStreamPosition - _persistedSize, SeekOrigin.Begin); memoryBytesRead = _sparseMemoryStreamSuffix.Read(buffer, offset, count); newStreamPosition += memoryBytesRead; } totalBytesRead = diskBytesRead + memoryBytesRead; } _currentStreamPosition = newStreamPosition; return totalBytesRead ; } ////// Write /// /// /// /// ///In streaming mode, write should accumulate data into the SparseMemoryStream. override public void Write(byte[] buffer, int offset, int count) { CheckDisposed(); PackagingUtilities.VerifyStreamWriteArgs(this, buffer, offset, count); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // that would between PreSaveNotofication call and Save SaveStreaming Debug.Assert(_currentStreamPosition >= 0); if (count == 0) { return; } int diskBytesToWrite = 0; _dirtyFlag = true; _dataChanged = true; long newStreamPosition = _currentStreamPosition; checked { // Try to satisfy request with the Write to the Disk if (newStreamPosition < _persistedSize) { Debug.Assert(!_blockManager.Streaming); // we have at least partial overlap between request and the data on disk _blockManager.Stream.Seek(_persistedOffset + newStreamPosition, SeekOrigin.Begin); // Note on casting: // It is safe to cast the result of Math.Min(count, _persistedSize - newStreamPosition)) // from long to int since it cannot be bigger than count and count is int type diskBytesToWrite = (int) (Math.Min(count, _persistedSize - newStreamPosition)); // this is a safe cast as count has int type _blockManager.Stream.Write(buffer, offset, diskBytesToWrite); newStreamPosition += diskBytesToWrite; count -= diskBytesToWrite; offset += diskBytesToWrite; } // check whether we need to save data to the memory Stream; if (newStreamPosition + count > _persistedSize) { if (_sparseMemoryStreamSuffix == null) { _sparseMemoryStreamSuffix = new SparseMemoryStream(_lowWaterMark, _highWaterMark); } _sparseMemoryStreamSuffix.Seek(newStreamPosition - _persistedSize, SeekOrigin.Begin); _sparseMemoryStreamSuffix.Write(buffer, offset, count); newStreamPosition += count; } _currentStreamPosition = newStreamPosition; _currentStreamLength = Math.Max(_currentStreamLength, _currentStreamPosition); } return; } override public void Flush() { CheckDisposed(); // tell the BlockManager that the caller called Flush on us. Block manager will process this // and possibly call us back on Save or SaveStreaming _blockManager.SaveStream(_block, false); // second parameter is a closing indicator } ///////////////////////////// // Internal Constructor ///////////////////////////// internal ZipIOFileItemStream(ZipIOBlockManager blockManager, // blockManager is only needed // to pass through to it Flush requests ZipIOLocalFileBlock block, // our owning block - needed for Streaming scenarios long persistedOffset, // to map to the stream long persistedSize) // to map to the stream ) { Debug.Assert(blockManager != null); Debug.Assert(persistedOffset >=0); Debug.Assert(persistedSize >= 0); Debug.Assert(block != null); _persistedOffset = persistedOffset; _offset = persistedOffset; _persistedSize = persistedSize; _blockManager = blockManager; _block = block; _currentStreamLength = persistedSize; } ///////////////////////////// // Internal Methods for the LocalFileBlock to call in order to know Dirty status and the new size ///////////////////////////// internal PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { return ZipIOBlockManager.CommonPreSaveNotificationHandler( _blockManager.Stream, offset, size, _persistedOffset, Math.Min(_persistedSize, _currentStreamLength), // in case the stream is smaller then our persisted block on // disk, there is no need to preserve the meaningless persisted suffix ref _cachePrefixStream); } internal bool DirtyFlag { get { return _dirtyFlag; } } internal bool DataChanged { get { return _dataChanged; } } internal long Offset { get { return _offset; } } internal void Move(long shiftSize) { CheckDisposed(); if (shiftSize != 0) { checked{_offset +=shiftSize;} _dirtyFlag = true; Debug.Assert(_offset >=0); } } ////// Streaming-specific variant of Save() /// ///Writes current data to the underlying stream. /// Assumes the stream is in the correct place. internal void SaveStreaming() { CheckDisposed(); Debug.Assert(_cachePrefixStream == null); // _cachePrefixStream must not be used in streaming cases at all Debug.Assert(_blockManager.Streaming); if (_dirtyFlag) { // in streaming cases all the data collected in the _sparseMemoryStreamSuffix // and now we can save the SparseMemoryStream if (_sparseMemoryStreamSuffix != null) { _sparseMemoryStreamSuffix.WriteToStream(_blockManager.Stream); // update so that subsequent MemoryStreams will know where they begin checked{_persistedSize += _sparseMemoryStreamSuffix.Length;} _sparseMemoryStreamSuffix.Close(); _sparseMemoryStreamSuffix = null; } _dirtyFlag = false; _dataChanged = false; } } ////// Save - called by the BlockManager to cause us to Flush to the underlying stream /// internal void Save() { CheckDisposed(); Debug.Assert(!_blockManager.Streaming); if(_dirtyFlag) { // we need to move the whole persisted block to the new position long moveBlockSourceOffset = _persistedOffset; // in case the stream is smaller then our persisted block on disk there is // no need to move meaningless persisted suffix long moveBlockSize = Math.Min(_persistedSize, _currentStreamLength); long moveBlockTargetOffset = _offset; long newPersistedSize = 0; if (_cachePrefixStream != null) { // if we have something in cache we only should move whatever isn't cached checked{moveBlockSourceOffset += _cachePrefixStream.Length;} checked{moveBlockTargetOffset += _cachePrefixStream.Length;} checked{moveBlockSize -= _cachePrefixStream.Length;} Debug.Assert(moveBlockSize >=0); } _blockManager.MoveData(moveBlockSourceOffset, moveBlockTargetOffset, moveBlockSize); checked{newPersistedSize += moveBlockSize;} // only after data on disk was moved it is safe to flush the cached prefix buffer if (_cachePrefixStream != null) { // we need to seek and it is safe to do as we are not in the streaming mode _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); Debug.Assert(_cachePrefixStream.Length > 0); // should be taken care of by the constructor // and PreSaveNotification _cachePrefixStream.WriteToStream(_blockManager.Stream); checked{newPersistedSize += _cachePrefixStream.Length;} // we can free the memory _cachePrefixStream.Close(); _cachePrefixStream = null; } // and now we can save the SparseMemoryStream if (_sparseMemoryStreamSuffix != null) { if (_blockManager.Stream.Position != checked (_offset + _persistedSize)) { // we need to seek _blockManager.Stream.Seek(_offset + _persistedSize, SeekOrigin.Begin); } _sparseMemoryStreamSuffix.WriteToStream(_blockManager.Stream); checked{newPersistedSize += _sparseMemoryStreamSuffix.Length;} _sparseMemoryStreamSuffix.Close(); _sparseMemoryStreamSuffix = null; } _blockManager.Stream.Flush(); // we are not shifted between on disk image and in memory image any more _persistedOffset = _offset; _persistedSize = newPersistedSize; Debug.Assert(newPersistedSize == _currentStreamLength); Debug.Assert(_cachePrefixStream == null); // we only expect this thing to be not null during Archive Save execution // after we are saved this field must be clear _dirtyFlag = false; _dataChanged = false; } } //------------------------------------------------------ // // 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 Dispose 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 if (!_disposedFlag) { if (_sparseMemoryStreamSuffix != null) { _sparseMemoryStreamSuffix.Close(); } if (_cachePrefixStream != null) { _cachePrefixStream.Close(); } } } } finally { _sparseMemoryStreamSuffix = null; _cachePrefixStream = null; _disposedFlag = true; base.Dispose(disposing); } } ///////////////////////////// // Private Methods ///////////////////////////// private void CheckDisposed() { if (_disposedFlag) { throw new ObjectDisposedException(null, SR.Get(SRID.ZipFileItemDisposed)); } } private ZipIOBlockManager _blockManager; private ZipIOLocalFileBlock _block; // our owning block private long _offset; private long _persistedOffset; private long _persistedSize; private SparseMemoryStream _cachePrefixStream; private bool _dirtyFlag; private bool _dataChanged; //support for Stream methods private bool _disposedFlag; private long _currentStreamLength; private long _currentStreamPosition; private SparseMemoryStream _sparseMemoryStreamSuffix; private const long _lowWaterMark = 0x19000; // we definately would like to keep everythuing under 100 KB in memory private const long _highWaterMark = 0xA00000; // we would like to keep everything over 10 MB on disk } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Span.cs
- BmpBitmapDecoder.cs
- SecurityChannelListener.cs
- Int32RectConverter.cs
- KeyMatchBuilder.cs
- HttpRequestCacheValidator.cs
- BitmapData.cs
- GridView.cs
- OracleBoolean.cs
- FontSourceCollection.cs
- DefaultTypeArgumentAttribute.cs
- UnmanagedBitmapWrapper.cs
- VariantWrapper.cs
- ForEachAction.cs
- DnsPermission.cs
- Semaphore.cs
- ParseHttpDate.cs
- SQLConvert.cs
- InheritablePropertyChangeInfo.cs
- WindowsGraphicsWrapper.cs
- EdmFunction.cs
- WebPartDeleteVerb.cs
- Misc.cs
- InProcStateClientManager.cs
- VsPropertyGrid.cs
- RewritingPass.cs
- AmbiguousMatchException.cs
- BindingMemberInfo.cs
- ComponentDispatcherThread.cs
- CodeConstructor.cs
- GetRecipientRequest.cs
- DataBindingExpressionBuilder.cs
- InheritanceRules.cs
- EdmSchemaError.cs
- NamespaceList.cs
- ColorTransformHelper.cs
- OdbcParameter.cs
- DataGridViewAutoSizeModeEventArgs.cs
- TextAdaptor.cs
- ADMembershipProvider.cs
- KeyConverter.cs
- XmlSignificantWhitespace.cs
- HtmlValidatorAdapter.cs
- PassportAuthenticationEventArgs.cs
- WebPartConnectionsCancelEventArgs.cs
- XMLSyntaxException.cs
- DoubleStorage.cs
- ManualResetEvent.cs
- GetIndexBinder.cs
- ToolStripItemTextRenderEventArgs.cs
- DataRow.cs
- ProvidersHelper.cs
- XamlSerializerUtil.cs
- BasicViewGenerator.cs
- OleAutBinder.cs
- TabletCollection.cs
- NetworkInterface.cs
- EdgeProfileValidation.cs
- TextChange.cs
- HttpResponse.cs
- CacheDependency.cs
- StrokeCollectionConverter.cs
- MsmqBindingBase.cs
- MetadataSource.cs
- WindowsListView.cs
- OdbcEnvironmentHandle.cs
- Int32Rect.cs
- DataGridViewCellLinkedList.cs
- ButtonChrome.cs
- ElementNotEnabledException.cs
- HuffCodec.cs
- Baml2006SchemaContext.cs
- SafeRightsManagementQueryHandle.cs
- GridViewRowCollection.cs
- ViewValidator.cs
- DoubleKeyFrameCollection.cs
- LayoutTableCell.cs
- StrongNamePublicKeyBlob.cs
- Camera.cs
- ExternalException.cs
- SapiRecoInterop.cs
- XPathItem.cs
- ConfigurationSettings.cs
- WebBrowserDocumentCompletedEventHandler.cs
- ServiceNameElement.cs
- BaseCodeDomTreeGenerator.cs
- AttachmentCollection.cs
- Filter.cs
- PathData.cs
- TimeEnumHelper.cs
- _SslState.cs
- ReflectPropertyDescriptor.cs
- EventArgs.cs
- ExpressionBuilderCollection.cs
- UniqueIdentifierService.cs
- RankException.cs
- DesignUtil.cs
- Gdiplus.cs
- Imaging.cs
- ErrorTableItemStyle.cs