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, List sortedPieceInfoList,
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?
///
///
///
/// 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.
///
///
public override bool CanRead
{
get
{
return _closed ? false : _dir.GetStream(0).CanRead;
}
}
///
/// Is stream seekable?
///
///
///
/// 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.
///
///
public override bool CanSeek
{
get
{
return _closed ? false : _dir.GetStream(0).CanSeek;
}
}
///
/// Is stream writable?
///
///
///
/// 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.
///
///
//
public override bool CanWrite
{
get
{
return _closed ? false : _dir.GetStream(0).CanWrite;
}
}
///
/// 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, List sortedPieceInfoList,
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?
///
///
///
/// 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.
///
///
public override bool CanRead
{
get
{
return _closed ? false : _dir.GetStream(0).CanRead;
}
}
///
/// Is stream seekable?
///
///
///
/// 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.
///
///
public override bool CanSeek
{
get
{
return _closed ? false : _dir.GetStream(0).CanSeek;
}
}
///
/// Is stream writable?
///
///
///
/// 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.
///
///
//
public override bool CanWrite
{
get
{
return _closed ? false : _dir.GetStream(0).CanWrite;
}
}
///
/// 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
- LinearKeyFrames.cs
- XmlArrayItemAttributes.cs
- LabelLiteral.cs
- UserControlBuildProvider.cs
- DoubleAnimationUsingPath.cs
- InfoCard.cs
- ListControlBoundActionList.cs
- ObjectSet.cs
- TreeViewImageGenerator.cs
- XmlSchemaSimpleType.cs
- MembershipValidatePasswordEventArgs.cs
- WebEventTraceProvider.cs
- PreviewPrintController.cs
- CheckBox.cs
- EditorZone.cs
- DropDownList.cs
- ProcessThreadCollection.cs
- AttributeSetAction.cs
- UpdatePanelTriggerCollection.cs
- VirtualPath.cs
- WebPartZone.cs
- ImplicitInputBrush.cs
- DataGridViewBand.cs
- HwndSubclass.cs
- DbInsertCommandTree.cs
- ServiceOperationParameter.cs
- SafeUserTokenHandle.cs
- SafeProcessHandle.cs
- ProgressPage.cs
- DocumentsTrace.cs
- PreviewPrintController.cs
- RawStylusInputCustomDataList.cs
- WebPartDescriptionCollection.cs
- SerializationObjectManager.cs
- HatchBrush.cs
- Timer.cs
- XhtmlConformanceSection.cs
- Tag.cs
- TextClipboardData.cs
- ApplicationFileParser.cs
- HtmlImage.cs
- Button.cs
- ALinqExpressionVisitor.cs
- SamlAdvice.cs
- _RequestLifetimeSetter.cs
- FixedSOMSemanticBox.cs
- SamlAction.cs
- SchemaNamespaceManager.cs
- MSHTMLHostUtil.cs
- XomlSerializationHelpers.cs
- ReferenceEqualityComparer.cs
- BoundField.cs
- GenericEnumerator.cs
- XmlSchemaAll.cs
- SimpleTypesSurrogate.cs
- ImageSource.cs
- ErrorInfoXmlDocument.cs
- CheckedPointers.cs
- Int16.cs
- TableItemStyle.cs
- SpeechSynthesizer.cs
- OracleRowUpdatingEventArgs.cs
- BinaryConverter.cs
- BindingNavigator.cs
- ClientTargetSection.cs
- CalendarDay.cs
- PolyLineSegment.cs
- InputLangChangeRequestEvent.cs
- RowToParametersTransformer.cs
- WebPartDescriptionCollection.cs
- ImmutableObjectAttribute.cs
- ClassValidator.cs
- SmiEventSink.cs
- RawStylusInputCustomDataList.cs
- ImageListStreamer.cs
- Pair.cs
- TraceEventCache.cs
- SrgsDocumentParser.cs
- CacheEntry.cs
- ElementInit.cs
- ColumnMapProcessor.cs
- HttpHandlerAction.cs
- AnimationClockResource.cs
- DataObjectFieldAttribute.cs
- ClientSideProviderDescription.cs
- SetIterators.cs
- RichTextBox.cs
- OutputScopeManager.cs
- COM2Enum.cs
- Profiler.cs
- NameNode.cs
- _BufferOffsetSize.cs
- HttpConfigurationContext.cs
- SplashScreen.cs
- ApplicationManager.cs
- AccessDataSourceDesigner.cs
- TextElementEnumerator.cs
- DefaultParameterValueAttribute.cs
- EditingCoordinator.cs
- XmlDataImplementation.cs