Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / MS / Internal / IO / Packaging / InterleavedZipPartStream.cs / 1305600 / 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 using MS.Internal.WindowsBase; 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 using MS.Internal.WindowsBase; 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
- BaseCodePageEncoding.cs
- UnsafeCollabNativeMethods.cs
- EntityDataSource.cs
- DataColumnChangeEvent.cs
- ConnectionString.cs
- ExchangeUtilities.cs
- XsdBuildProvider.cs
- VisualTarget.cs
- ElementNotEnabledException.cs
- ResXResourceWriter.cs
- SqlGatherConsumedAliases.cs
- Enum.cs
- CodeDefaultValueExpression.cs
- Descriptor.cs
- GetCryptoTransformRequest.cs
- DeflateEmulationStream.cs
- XmlNamespaceManager.cs
- ModulesEntry.cs
- UrlAuthorizationModule.cs
- ArraySubsetEnumerator.cs
- ClonableStack.cs
- Triplet.cs
- BindingCollectionElement.cs
- HwndHost.cs
- UnsupportedPolicyOptionsException.cs
- ZipIOFileItemStream.cs
- Pens.cs
- InputScopeNameConverter.cs
- ToolStripItemTextRenderEventArgs.cs
- TransactionManager.cs
- PathFigure.cs
- PingReply.cs
- COAUTHINFO.cs
- COM2PictureConverter.cs
- FlowDocument.cs
- webclient.cs
- ButtonColumn.cs
- Converter.cs
- TypeSemantics.cs
- DataControlPagerLinkButton.cs
- UnknownWrapper.cs
- ConnectionsZone.cs
- EntityCollection.cs
- InfoCardRSAPKCS1KeyExchangeDeformatter.cs
- WinCategoryAttribute.cs
- MetadataImporter.cs
- Stylesheet.cs
- CharEntityEncoderFallback.cs
- Queue.cs
- OutOfProcStateClientManager.cs
- RegexRunnerFactory.cs
- ApplicationSettingsBase.cs
- SqlError.cs
- FixedPage.cs
- DBAsyncResult.cs
- StdValidatorsAndConverters.cs
- EntityDataSourceChangedEventArgs.cs
- CancellationScope.cs
- JsonFormatWriterGenerator.cs
- XmlDocument.cs
- DecoratedNameAttribute.cs
- FixedSOMTable.cs
- SqlFunctionAttribute.cs
- Aggregates.cs
- ListViewItem.cs
- WsdlHelpGeneratorElement.cs
- ICspAsymmetricAlgorithm.cs
- ForceCopyBuildProvider.cs
- TransformationRules.cs
- InfoCardCryptoHelper.cs
- CompilerInfo.cs
- WebServicesDescriptionAttribute.cs
- SqlDataSourceStatusEventArgs.cs
- ChannelPoolSettings.cs
- SafeSystemMetrics.cs
- PropertyGridEditorPart.cs
- CodePageEncoding.cs
- ErrorEventArgs.cs
- InfiniteIntConverter.cs
- WSFederationHttpSecurityElement.cs
- QilBinary.cs
- XslTransform.cs
- SortedSet.cs
- SHA384Cng.cs
- CalendarSelectionChangedEventArgs.cs
- TextRunProperties.cs
- IfJoinedCondition.cs
- DataKeyArray.cs
- LineSegment.cs
- Marshal.cs
- HttpCapabilitiesSectionHandler.cs
- TemplateControlCodeDomTreeGenerator.cs
- OpCopier.cs
- EditorZoneBase.cs
- WindowsFormsSectionHandler.cs
- Condition.cs
- SiteMapNodeItemEventArgs.cs
- CodeGeneratorOptions.cs
- ClipboardData.cs
- COM2TypeInfoProcessor.cs