Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Base / MS / Internal / IO / Packaging / InterleavedZipPartStream.cs / 1 / InterleavedZipPartStream.cs
//------------------------------------------------------------------------------ // Microsoft Avalon // Copyright (c) Microsoft Corporation, 2005 // // File: InterleavedZipPartStream.cs // // Description: The class InterleavedZipPartStream is used to wrap one or more Zip // part streams for an interleaved part. It hides the interleaving // from its callers by offering the abstraction of a continuous stream // across pieces. // // History: 05/15/05 - johnlarc - initial implementation //----------------------------------------------------------------------------- using System; using System.Diagnostics; using System.IO; using System.IO.Packaging; // For ZipPackagePart, etc. using MS.Internal.IO.Zip; // For ZipFileInfo. using System.Windows; // for ExceptionStringTable using System.Collections.Generic; // For List<> using MS.Internal; // for Invariant namespace MS.Internal.IO.Packaging { ////// The class InterleavedZipPartStream is used to wrap one or more Zip part streams /// for an interleaved part. It hides the interleaving from its callers by offering /// the abstraction of a continuous stream across pieces. /// ////// This class is defined for the benefit of ZipPackage, ZipPackagePart and /// InternalRelationshipCollection. /// Although it is quite specialized, it would hardly make sense to nest its definition in any /// of these clases. /// internal partial class InterleavedZipPartStream : Stream { #region Constructors //----------------------------------------------------- // // Constructors // //----------------------------------------------------- ////// Build a System.IO.Stream on a part that possibly consists of multiple files /// An InterleavedZipPartStream gets created by ZipPackagePart.GetStreamCore when the part /// is interleaved. It wraps one or more Zip streams (one per piece). /// (pieces). /// /// Mode (create, etc.) in which piece streams should be opened /// Access (read, write, etc.) with which piece streams should be opened /// /// The part to build a stream on. It contains all ZipFileInfo descriptors for the part's pieces /// (see ZipPackage.GetPartsCore). /// internal InterleavedZipPartStream(ZipPackagePart owningPart, FileMode mode, FileAccess access) : this(PackUriHelper.GetStringForPartUri(owningPart.Uri), owningPart.PieceDescriptors, mode, access) { } ////// This constructor is provided to be able to interleave other files than just parts, /// notably the contents type file. /// internal InterleavedZipPartStream(string partName, ListsortedPieceInfoList, FileMode mode, FileAccess access) { // The PieceDirectory mediates access to pieces. // It maps offsets to piece numbers and piece numbers to streams and start offsets. // Mode and access are entirely managed by the underlying streams, assumed to be seekable. _dir = new PieceDirectory(sortedPieceInfoList, mode, access); // GetCurrentPieceNumber is operational from the beginning. Invariant.Assert(_dir.GetStartOffset(GetCurrentPieceNumber()) == 0); } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- /// /// Return the bytes requested. /// /// Destination buffer. /// /// The zero-based byte offset in buffer at which to begin storing the data read /// from the current stream. /// /// How many bytes requested. ///How many bytes were written into buffer. public override int Read(byte[] buffer, int offset, int count) { CheckClosed(); // Check arguments. PackagingUtilities.VerifyStreamReadArgs(this, buffer, offset, count); // Leave capability and FileAccess checks up to the underlying stream(s). // Reading 0 bytes is a no-op. if (count == 0) return 0; int pieceNumber = GetCurrentPieceNumber(); int totalBytesRead = 0; Stream pieceStream = _dir.GetStream(pieceNumber); checked { //Seek to the correct location in the underlying stream for the current piece pieceStream.Seek(_currentOffset - _dir.GetStartOffset(pieceNumber), SeekOrigin.Begin); while (totalBytesRead < count) { int numBytesRead = pieceStream.Read( buffer, offset + totalBytesRead, count - totalBytesRead); // End of the current stream: try to move to the next stream. if (numBytesRead == 0) { if (_dir.IsLastPiece(pieceNumber)) break; ++pieceNumber; Invariant.Assert(_dir.GetStartOffset(pieceNumber) == _currentOffset + totalBytesRead); pieceStream = _dir.GetStream(pieceNumber); //Seek inorder to set the correct pointer for the next piece stream pieceStream.Seek(0, SeekOrigin.Begin); } totalBytesRead += numBytesRead; } // Advance current position now we know the operation completed successfully. _currentOffset += totalBytesRead; } return totalBytesRead; } ////// Seek /// /// Offset in byte. /// Offset origin (start, current, or end). public override long Seek(long offset, SeekOrigin origin) { CheckClosed(); // Check stream capabilities. (Normally, CanSeek will be false only // when the stream is closed.) if (!CanSeek) throw new NotSupportedException(SR.Get(SRID.SeekNotSupported)); // Convert offset to a start-based offset. switch (origin) { case SeekOrigin.Begin: break; case SeekOrigin.Current: checked { offset += _currentOffset; } break; case SeekOrigin.End: checked { offset += Length; } break; default: throw new ArgumentOutOfRangeException("origin"); } // Check offset validity. if (offset < 0) throw new ArgumentException(SR.Get(SRID.SeekNegative)); // OK if _currentOffset points beyond end of stream. // Update position field and return. _currentOffset = offset; return _currentOffset; } ////// SetLength /// public override void SetLength(long newLength) { CheckClosed(); // Check argument and stream capabilities. if (newLength < 0) throw new ArgumentOutOfRangeException("newLength"); if (!CanWrite) throw new NotSupportedException(SR.Get(SRID.StreamDoesNotSupportWrite)); if (!CanSeek) throw new NotSupportedException(SR.Get(SRID.SeekNotSupported)); // If some pieces are to be deleted, this is reflected only in memory at present. int lastPieceNumber; if (newLength == 0) { // This is special-cased because there is no last offset to speak of, and // so the piece directory cannot return any piece by offset. lastPieceNumber = 0; } else { lastPieceNumber = _dir.GetPieceNumberFromOffset(newLength - 1); // No need to use checked{] since newLength != 0 } _dir.SetLogicalLastPiece(lastPieceNumber); // Adjust last active stream to new size. Stream lastPieceStream = _dir.GetStream(lastPieceNumber); Debug.Assert(newLength - _dir.GetStartOffset(lastPieceNumber) >= 0); long lastPieceStreamSize = newLength - _dir.GetStartOffset(lastPieceNumber); lastPieceStream.SetLength(lastPieceStreamSize); if (_currentOffset > newLength) { _currentOffset = newLength; } } ////// Write. Distribute the bytes to write across several contiguous streams if needed. /// ////// Zip streams can be assumed seekable so the length will be available for chaining /// pieces. /// public override void Write(byte[] buffer, int offset, int count) { CheckClosed(); // Check arguments. PackagingUtilities.VerifyStreamWriteArgs(this, buffer, offset, count); // No check for FileAccess and stream capability (CanWrite). This is the responsibility // of the underlying stream(s). // A no-op if zero bytes to write. if (count == 0) return; // Write into piece streams, preserving all lengths in non-terminal pieces. int totalBytesWritten = 0; int pieceNumber = GetCurrentPieceNumber(); Stream pieceStream = _dir.GetStream(pieceNumber); checked { //Seek to the correct location in the underlying stream for the current piece pieceStream.Seek(_currentOffset - _dir.GetStartOffset(pieceNumber), SeekOrigin.Begin); while (totalBytesWritten < count) { // Compute the number of bytes to write into pieceStream. int numBytesToWriteInCurrentPiece = count - totalBytesWritten; if (!_dir.IsLastPiece(pieceNumber)) { // The write should not change the length of an intermediate piece. long currentPosition = _currentOffset + totalBytesWritten; long maxPosition = _dir.GetStartOffset(pieceNumber+1) - 1; if (numBytesToWriteInCurrentPiece > (maxPosition - currentPosition + 1)) { // Cast from long to cast is safe in so far as *count*, which is the // absolute max for all byte counts, is a positive int. numBytesToWriteInCurrentPiece = checked((int)(maxPosition - currentPosition + 1)); } } // Do the write. pieceStream.Write(buffer, offset + totalBytesWritten, numBytesToWriteInCurrentPiece); // Update the tally. totalBytesWritten += numBytesToWriteInCurrentPiece; // If there is more data to write, get the next piece stream if (!_dir.IsLastPiece(pieceNumber) && totalBytesWritten < count) { // The next write, should involve the next piece. ++pieceNumber; pieceStream = _dir.GetStream(pieceNumber); //Seek inorder to set the correct pointer for the next piece stream pieceStream.Seek(0, SeekOrigin.Begin); } } // Now we know the operation has completed, the current position can be updated. Invariant.Assert(totalBytesWritten == count); _currentOffset += totalBytesWritten; } } ////// Flush all dirty streams and commit pending piece deletions. /// ////// Flush gets called on all underlying streams ever accessed. If it turned out /// this is too inefficient, the PieceDirectory could be made to expose a SetDirty /// method that takes a piece number. /// public override void Flush() { CheckClosed(); // The underlying streams know whether they are dirty or not; // so _dir will indiscriminately flush all the streams that have been accessed. // It will also carry out necessary renamings and deletions to reflect calls to // SetLogicalLastPiece. _dir.Flush(); } //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ ////// Is stream readable? /// ////// public override bool CanRead { get { return _closed ? false : _dir.GetStream(0).CanRead; } } ////// Here, the assumption, as in all capability tests, is that the status of /// the first piece reflects the status of all pieces for the part. /// This is justified by the fact that (i) all piece streams are opened with the same /// parameters against the same archive and (ii) the current piece stream cannot get /// closed unless the whole part stream is closed. /// ////// A further assumption is that, as soon as interleaved zip part stream is initialized, there /// is a descriptor for the 1st piece. /// ////// Is stream seekable? /// ////// public override bool CanSeek { get { return _closed ? false : _dir.GetStream(0).CanSeek; } } ////// Here, the assumption, as in all capability tests, is that the status of /// the first piece reflects the status of all pieces for the part. /// This is justified by the fact that (i) all piece streams are opened with the same /// parameters against the same archive and (ii) the current piece stream cannot get /// closed unless the whole part stream is closed. /// ////// A further assumption is that, as soon as interleaved zip part stream is initialized, there /// is a descriptor for the 1st piece. /// ////// Is stream writable? /// ////// // public override bool CanWrite { get { return _closed ? false : _dir.GetStream(0).CanWrite; } } ////// Here, the assumption, as in all capability tests, is that the status of /// the first piece reflects the status of all pieces for the part. /// This is justified by the fact that (i) all piece streams are opened with the same /// parameters against the same archive and (ii) the current piece stream cannot get /// closed unless the whole part stream is closed. /// ////// A further assumption is that, as soon as interleaved zip part stream is initialized, there /// is a descriptor for the 1st piece. /// ////// Logical byte position in this stream. /// public override long Position { get { CheckClosed(); // Current offset is systematically updated to reflect the current position. return _currentOffset; } set { CheckClosed(); Seek(value, SeekOrigin.Begin); } } ////// Length. /// // public override long Length { get { CheckClosed(); Invariant.Assert(CanSeek); long length = 0; for (int pieceNumber = 0; pieceNumber < _dir.GetNumberOfPieces(); ++pieceNumber) { checked { length += _dir.GetStream(pieceNumber).Length; } } return length; } } //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Dispose(bool) /// /// ////// An instance of streams' peculiar dispose pattern, whereby /// the inherited abstract class implements Close by calling /// this virtual protected function. /// In turn, each implementation is responsible for calling back /// its base's implementation. /// protected override void Dispose(bool disposing) { try { if (disposing) { if (!_closed) { _dir.Close(); } } } finally { _closed = true; base.Dispose(disposing); } } #endregion Protected Methods //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- #region Private Methods private void CheckClosed() { if (_closed) throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed)); } ////// Infer the current piece number from _currentOffset. /// ////// Storing the current piece number in a field and computing the current offset from it /// would also have been possible, but less efficient. /// private int GetCurrentPieceNumber() { // Since this property is likely to be read more often than _currentOffset // gets updated, its value is cached in _currentPieceNumber. // The validity of the cached value is monitored using _offsetForCurrentPieceNumber. if (_offsetForCurrentPieceNumber != _currentOffset) { // Cached value is stale. Refresh. _currentPieceNumber = _dir.GetPieceNumberFromOffset(_currentOffset); _offsetForCurrentPieceNumber = _currentOffset; } return _currentPieceNumber; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // High-level object to access the collection of pieces by offset and pieceNumber. private PieceDirectory _dir; // Cached value for the current piece number. // (Lazily [....]'ed to _currentOffset when GetCurrentPieceNumber() is invoked.) private int _currentPieceNumber; // Control value to decide whether to use _currentPieceNumber without updating it. private Nullable_offsetForCurrentPieceNumber; // This variable continuously tracks the current stream position. private long _currentOffset = 0; // Closed status. private bool _closed = false; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // Microsoft Avalon // Copyright (c) Microsoft Corporation, 2005 // // File: InterleavedZipPartStream.cs // // Description: The class InterleavedZipPartStream is used to wrap one or more Zip // part streams for an interleaved part. It hides the interleaving // from its callers by offering the abstraction of a continuous stream // across pieces. // // History: 05/15/05 - johnlarc - initial implementation //----------------------------------------------------------------------------- using System; using System.Diagnostics; using System.IO; using System.IO.Packaging; // For ZipPackagePart, etc. using MS.Internal.IO.Zip; // For ZipFileInfo. using System.Windows; // for ExceptionStringTable using System.Collections.Generic; // For List<> using MS.Internal; // for Invariant namespace MS.Internal.IO.Packaging { /// /// The class InterleavedZipPartStream is used to wrap one or more Zip part streams /// for an interleaved part. It hides the interleaving from its callers by offering /// the abstraction of a continuous stream across pieces. /// ////// This class is defined for the benefit of ZipPackage, ZipPackagePart and /// InternalRelationshipCollection. /// Although it is quite specialized, it would hardly make sense to nest its definition in any /// of these clases. /// internal partial class InterleavedZipPartStream : Stream { #region Constructors //----------------------------------------------------- // // Constructors // //----------------------------------------------------- ////// Build a System.IO.Stream on a part that possibly consists of multiple files /// An InterleavedZipPartStream gets created by ZipPackagePart.GetStreamCore when the part /// is interleaved. It wraps one or more Zip streams (one per piece). /// (pieces). /// /// Mode (create, etc.) in which piece streams should be opened /// Access (read, write, etc.) with which piece streams should be opened /// /// The part to build a stream on. It contains all ZipFileInfo descriptors for the part's pieces /// (see ZipPackage.GetPartsCore). /// internal InterleavedZipPartStream(ZipPackagePart owningPart, FileMode mode, FileAccess access) : this(PackUriHelper.GetStringForPartUri(owningPart.Uri), owningPart.PieceDescriptors, mode, access) { } ////// This constructor is provided to be able to interleave other files than just parts, /// notably the contents type file. /// internal InterleavedZipPartStream(string partName, ListsortedPieceInfoList, FileMode mode, FileAccess access) { // The PieceDirectory mediates access to pieces. // It maps offsets to piece numbers and piece numbers to streams and start offsets. // Mode and access are entirely managed by the underlying streams, assumed to be seekable. _dir = new PieceDirectory(sortedPieceInfoList, mode, access); // GetCurrentPieceNumber is operational from the beginning. Invariant.Assert(_dir.GetStartOffset(GetCurrentPieceNumber()) == 0); } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- /// /// Return the bytes requested. /// /// Destination buffer. /// /// The zero-based byte offset in buffer at which to begin storing the data read /// from the current stream. /// /// How many bytes requested. ///How many bytes were written into buffer. public override int Read(byte[] buffer, int offset, int count) { CheckClosed(); // Check arguments. PackagingUtilities.VerifyStreamReadArgs(this, buffer, offset, count); // Leave capability and FileAccess checks up to the underlying stream(s). // Reading 0 bytes is a no-op. if (count == 0) return 0; int pieceNumber = GetCurrentPieceNumber(); int totalBytesRead = 0; Stream pieceStream = _dir.GetStream(pieceNumber); checked { //Seek to the correct location in the underlying stream for the current piece pieceStream.Seek(_currentOffset - _dir.GetStartOffset(pieceNumber), SeekOrigin.Begin); while (totalBytesRead < count) { int numBytesRead = pieceStream.Read( buffer, offset + totalBytesRead, count - totalBytesRead); // End of the current stream: try to move to the next stream. if (numBytesRead == 0) { if (_dir.IsLastPiece(pieceNumber)) break; ++pieceNumber; Invariant.Assert(_dir.GetStartOffset(pieceNumber) == _currentOffset + totalBytesRead); pieceStream = _dir.GetStream(pieceNumber); //Seek inorder to set the correct pointer for the next piece stream pieceStream.Seek(0, SeekOrigin.Begin); } totalBytesRead += numBytesRead; } // Advance current position now we know the operation completed successfully. _currentOffset += totalBytesRead; } return totalBytesRead; } ////// Seek /// /// Offset in byte. /// Offset origin (start, current, or end). public override long Seek(long offset, SeekOrigin origin) { CheckClosed(); // Check stream capabilities. (Normally, CanSeek will be false only // when the stream is closed.) if (!CanSeek) throw new NotSupportedException(SR.Get(SRID.SeekNotSupported)); // Convert offset to a start-based offset. switch (origin) { case SeekOrigin.Begin: break; case SeekOrigin.Current: checked { offset += _currentOffset; } break; case SeekOrigin.End: checked { offset += Length; } break; default: throw new ArgumentOutOfRangeException("origin"); } // Check offset validity. if (offset < 0) throw new ArgumentException(SR.Get(SRID.SeekNegative)); // OK if _currentOffset points beyond end of stream. // Update position field and return. _currentOffset = offset; return _currentOffset; } ////// SetLength /// public override void SetLength(long newLength) { CheckClosed(); // Check argument and stream capabilities. if (newLength < 0) throw new ArgumentOutOfRangeException("newLength"); if (!CanWrite) throw new NotSupportedException(SR.Get(SRID.StreamDoesNotSupportWrite)); if (!CanSeek) throw new NotSupportedException(SR.Get(SRID.SeekNotSupported)); // If some pieces are to be deleted, this is reflected only in memory at present. int lastPieceNumber; if (newLength == 0) { // This is special-cased because there is no last offset to speak of, and // so the piece directory cannot return any piece by offset. lastPieceNumber = 0; } else { lastPieceNumber = _dir.GetPieceNumberFromOffset(newLength - 1); // No need to use checked{] since newLength != 0 } _dir.SetLogicalLastPiece(lastPieceNumber); // Adjust last active stream to new size. Stream lastPieceStream = _dir.GetStream(lastPieceNumber); Debug.Assert(newLength - _dir.GetStartOffset(lastPieceNumber) >= 0); long lastPieceStreamSize = newLength - _dir.GetStartOffset(lastPieceNumber); lastPieceStream.SetLength(lastPieceStreamSize); if (_currentOffset > newLength) { _currentOffset = newLength; } } ////// Write. Distribute the bytes to write across several contiguous streams if needed. /// ////// Zip streams can be assumed seekable so the length will be available for chaining /// pieces. /// public override void Write(byte[] buffer, int offset, int count) { CheckClosed(); // Check arguments. PackagingUtilities.VerifyStreamWriteArgs(this, buffer, offset, count); // No check for FileAccess and stream capability (CanWrite). This is the responsibility // of the underlying stream(s). // A no-op if zero bytes to write. if (count == 0) return; // Write into piece streams, preserving all lengths in non-terminal pieces. int totalBytesWritten = 0; int pieceNumber = GetCurrentPieceNumber(); Stream pieceStream = _dir.GetStream(pieceNumber); checked { //Seek to the correct location in the underlying stream for the current piece pieceStream.Seek(_currentOffset - _dir.GetStartOffset(pieceNumber), SeekOrigin.Begin); while (totalBytesWritten < count) { // Compute the number of bytes to write into pieceStream. int numBytesToWriteInCurrentPiece = count - totalBytesWritten; if (!_dir.IsLastPiece(pieceNumber)) { // The write should not change the length of an intermediate piece. long currentPosition = _currentOffset + totalBytesWritten; long maxPosition = _dir.GetStartOffset(pieceNumber+1) - 1; if (numBytesToWriteInCurrentPiece > (maxPosition - currentPosition + 1)) { // Cast from long to cast is safe in so far as *count*, which is the // absolute max for all byte counts, is a positive int. numBytesToWriteInCurrentPiece = checked((int)(maxPosition - currentPosition + 1)); } } // Do the write. pieceStream.Write(buffer, offset + totalBytesWritten, numBytesToWriteInCurrentPiece); // Update the tally. totalBytesWritten += numBytesToWriteInCurrentPiece; // If there is more data to write, get the next piece stream if (!_dir.IsLastPiece(pieceNumber) && totalBytesWritten < count) { // The next write, should involve the next piece. ++pieceNumber; pieceStream = _dir.GetStream(pieceNumber); //Seek inorder to set the correct pointer for the next piece stream pieceStream.Seek(0, SeekOrigin.Begin); } } // Now we know the operation has completed, the current position can be updated. Invariant.Assert(totalBytesWritten == count); _currentOffset += totalBytesWritten; } } ////// Flush all dirty streams and commit pending piece deletions. /// ////// Flush gets called on all underlying streams ever accessed. If it turned out /// this is too inefficient, the PieceDirectory could be made to expose a SetDirty /// method that takes a piece number. /// public override void Flush() { CheckClosed(); // The underlying streams know whether they are dirty or not; // so _dir will indiscriminately flush all the streams that have been accessed. // It will also carry out necessary renamings and deletions to reflect calls to // SetLogicalLastPiece. _dir.Flush(); } //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ ////// Is stream readable? /// ////// public override bool CanRead { get { return _closed ? false : _dir.GetStream(0).CanRead; } } ////// Here, the assumption, as in all capability tests, is that the status of /// the first piece reflects the status of all pieces for the part. /// This is justified by the fact that (i) all piece streams are opened with the same /// parameters against the same archive and (ii) the current piece stream cannot get /// closed unless the whole part stream is closed. /// ////// A further assumption is that, as soon as interleaved zip part stream is initialized, there /// is a descriptor for the 1st piece. /// ////// Is stream seekable? /// ////// public override bool CanSeek { get { return _closed ? false : _dir.GetStream(0).CanSeek; } } ////// Here, the assumption, as in all capability tests, is that the status of /// the first piece reflects the status of all pieces for the part. /// This is justified by the fact that (i) all piece streams are opened with the same /// parameters against the same archive and (ii) the current piece stream cannot get /// closed unless the whole part stream is closed. /// ////// A further assumption is that, as soon as interleaved zip part stream is initialized, there /// is a descriptor for the 1st piece. /// ////// Is stream writable? /// ////// // public override bool CanWrite { get { return _closed ? false : _dir.GetStream(0).CanWrite; } } ////// Here, the assumption, as in all capability tests, is that the status of /// the first piece reflects the status of all pieces for the part. /// This is justified by the fact that (i) all piece streams are opened with the same /// parameters against the same archive and (ii) the current piece stream cannot get /// closed unless the whole part stream is closed. /// ////// A further assumption is that, as soon as interleaved zip part stream is initialized, there /// is a descriptor for the 1st piece. /// ////// Logical byte position in this stream. /// public override long Position { get { CheckClosed(); // Current offset is systematically updated to reflect the current position. return _currentOffset; } set { CheckClosed(); Seek(value, SeekOrigin.Begin); } } ////// Length. /// // public override long Length { get { CheckClosed(); Invariant.Assert(CanSeek); long length = 0; for (int pieceNumber = 0; pieceNumber < _dir.GetNumberOfPieces(); ++pieceNumber) { checked { length += _dir.GetStream(pieceNumber).Length; } } return length; } } //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Dispose(bool) /// /// ////// An instance of streams' peculiar dispose pattern, whereby /// the inherited abstract class implements Close by calling /// this virtual protected function. /// In turn, each implementation is responsible for calling back /// its base's implementation. /// protected override void Dispose(bool disposing) { try { if (disposing) { if (!_closed) { _dir.Close(); } } } finally { _closed = true; base.Dispose(disposing); } } #endregion Protected Methods //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- #region Private Methods private void CheckClosed() { if (_closed) throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed)); } ////// Infer the current piece number from _currentOffset. /// ////// Storing the current piece number in a field and computing the current offset from it /// would also have been possible, but less efficient. /// private int GetCurrentPieceNumber() { // Since this property is likely to be read more often than _currentOffset // gets updated, its value is cached in _currentPieceNumber. // The validity of the cached value is monitored using _offsetForCurrentPieceNumber. if (_offsetForCurrentPieceNumber != _currentOffset) { // Cached value is stale. Refresh. _currentPieceNumber = _dir.GetPieceNumberFromOffset(_currentOffset); _offsetForCurrentPieceNumber = _currentOffset; } return _currentPieceNumber; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // High-level object to access the collection of pieces by offset and pieceNumber. private PieceDirectory _dir; // Cached value for the current piece number. // (Lazily [....]'ed to _currentOffset when GetCurrentPieceNumber() is invoked.) private int _currentPieceNumber; // Control value to decide whether to use _currentPieceNumber without updating it. private Nullable_offsetForCurrentPieceNumber; // This variable continuously tracks the current stream position. private long _currentOffset = 0; // Closed status. private bool _closed = false; #endregion Private Fields } } // 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
- objectresult_tresulttype.cs
- SortFieldComparer.cs
- UntrustedRecipientException.cs
- WindowShowOrOpenTracker.cs
- DbBuffer.cs
- PopupRootAutomationPeer.cs
- InputReportEventArgs.cs
- Duration.cs
- RemoteWebConfigurationHost.cs
- AvTrace.cs
- Size3DConverter.cs
- RegisteredScript.cs
- BoundPropertyEntry.cs
- VirtualPathProvider.cs
- Message.cs
- RadialGradientBrush.cs
- HorizontalAlignConverter.cs
- XmlWrappingReader.cs
- StrongNamePublicKeyBlob.cs
- ErrorProvider.cs
- WebPermission.cs
- ManagementOperationWatcher.cs
- SynchronizationFilter.cs
- XmlSchemaRedefine.cs
- StoreItemCollection.cs
- NodeLabelEditEvent.cs
- SHA1Cng.cs
- Calendar.cs
- ServiceReference.cs
- AlignmentYValidation.cs
- Converter.cs
- XmlReflectionMember.cs
- ProfileProvider.cs
- ObjectDataSourceEventArgs.cs
- SiteMapNodeCollection.cs
- TriState.cs
- TdsParserHelperClasses.cs
- TreeNodeBinding.cs
- InstanceData.cs
- MemoryRecordBuffer.cs
- SharedUtils.cs
- RegexRunner.cs
- Size.cs
- DbInsertCommandTree.cs
- ClockGroup.cs
- WorkflowMarkupSerializer.cs
- ProcessHostFactoryHelper.cs
- Helpers.cs
- ClientOptions.cs
- TextDecorationCollectionConverter.cs
- AdapterDictionary.cs
- ItemContainerGenerator.cs
- pingexception.cs
- AutoResetEvent.cs
- FunctionCommandText.cs
- EdgeProfileValidation.cs
- SchemaElementDecl.cs
- UpdateTranslator.cs
- DbProviderFactory.cs
- ResetableIterator.cs
- CursorConverter.cs
- Image.cs
- PropertyChangingEventArgs.cs
- DependencyPropertyDescriptor.cs
- KeyedCollection.cs
- DispatcherExceptionEventArgs.cs
- Collection.cs
- GridViewDeletedEventArgs.cs
- Int64Storage.cs
- XmlReflectionMember.cs
- WorkItem.cs
- WmpBitmapDecoder.cs
- XmlSchemaCollection.cs
- SystemBrushes.cs
- ServiceNotStartedException.cs
- ImageSourceTypeConverter.cs
- CrossAppDomainChannel.cs
- SmtpSpecifiedPickupDirectoryElement.cs
- ResourceKey.cs
- Utility.cs
- QuaternionKeyFrameCollection.cs
- LiteralControl.cs
- CodeDomDecompiler.cs
- Point.cs
- HyperLink.cs
- CodeTypeDelegate.cs
- CachingParameterInspector.cs
- AsyncStreamReader.cs
- BaseComponentEditor.cs
- AnnotationResourceCollection.cs
- AssemblySettingAttributes.cs
- MenuEventArgs.cs
- LinkLabel.cs
- DockPanel.cs
- AxHost.cs
- CompilationLock.cs
- SecurityKeyIdentifierClause.cs
- RoleManagerEventArgs.cs
- HtmlLink.cs
- DataGridHeadersVisibilityToVisibilityConverter.cs