private void PrepSourceStream()
{
if (_sourceStream == null)
throw new ZipException(String.Format("The input stream is null for entry '{0}'.", FileName));
if (this._sourceStreamOriginalPosition != null)
{
// this will happen the 2nd cycle through, if the stream is seekable
this._sourceStream.Position = this._sourceStreamOriginalPosition.Value;
}
else if (this._sourceStream.CanSeek)
{
// this will happen the first cycle through, if seekable
this._sourceStreamOriginalPosition = new Nullable<Int64>(this._sourceStream.Position);
}
else if (this.Encryption == EncryptionAlgorithm.PkzipWeak)
{
// In general, using PKZIP encryption on a a zip entry whose input
// comes from a non-seekable stream, is tricky. Here's why:
//
// Byte 11 of the PKZIP encryption header is used for password
// validation and consistency checknig.
//
// Normally, the highest byte of the CRC is used as the 11th (last) byte
// in the PKZIP encryption header. This means the CRC must be known
// before encryption is performed. Normally that means we read the full
// data stream, compute the CRC, then seek back and read it again for
// the compression+encryption phase. Obviously this is bad for
// performance with a large input file.
//
// There's a twist in the ZIP spec (actually documented only in infozip
// code, not in the spec itself) that allows the high-order byte of the
// last modified time for the entry, when the lastmod time is in packed
// (DOS) format, to be used for Byte 11 in the encryption header. In
// this case, the bit 3 "data descriptor" must be used.
//
// An intelligent implementation would therefore force the use of the
// bit 3 data descriptor when PKZIP encryption is in use, regardless.
// This avoids the double-read of the stream to be encrypted. So far,
// DotNetZip doesn't do that; it just punts when the input stream is
// non-seekable, and the output does not use Bit 3.
//
// The other option is to use the CRC when it is already available, eg,
// when the source for the data is a ZipEntry (when the zip file is
// being updated). In this case we already know the CRC and can just use
// what we know.
if (this._Source != ZipEntrySource.ZipFile && ((this._BitField & 0x0008) != 0x0008))
throw new ZipException("It is not possible to use PKZIP encryption on a non-seekable input stream");
}
}