private Int32 ExtractOne(Stream output)
{
Int32 CrcResult = 0;
Stream input = this.ArchiveStream;
try
{
// change for workitem 8098
input.Seek(this.FileDataPosition, SeekOrigin.Begin);
// workitem 10178
Crisis.Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(input);
byte[] bytes = new byte[BufferSize];
// The extraction process varies depending on how the entry was
// stored. It could have been encrypted, and it coould have
// been compressed, or both, or neither. So we need to check
// both the encryption flag and the compression flag, and take
// the proper action in all cases.
Int64 LeftToRead = (_CompressionMethod_FromZipFile != (short)CompressionMethod.None)
? this.UncompressedSize
: this._CompressedFileDataSize;
// Get a stream that either decrypts or not.
_inputDecryptorStream = GetExtractDecryptor(input);
Stream input3 = GetExtractDecompressor( _inputDecryptorStream );
Int64 bytesWritten = 0;
// As we read, we maybe decrypt, and then we maybe decompress. Then we write.
using (var s1 = new Crisis.Ionic.Crc.CrcCalculatorStream(input3))
{
while (LeftToRead > 0)
{
//Console.WriteLine("ExtractOne: LeftToRead {0}", LeftToRead);
// Casting LeftToRead down to an int is ok here in the else clause,
// because that only happens when it is less than bytes.Length,
// which is much less than MAX_INT.
int len = (LeftToRead > bytes.Length) ? bytes.Length : (int)LeftToRead;
int n = s1.Read(bytes, 0, len);
// must check data read - essential for detecting corrupt zip files
_CheckRead(n);
output.Write(bytes, 0, n);
LeftToRead -= n;
bytesWritten += n;
// fire the progress event, check for cancels
OnExtractProgress(bytesWritten, UncompressedSize);
if (_ioOperationCanceled)
{
break;
}
}
CrcResult = s1.Crc;
}
}
finally
{
var zss = input as ZipSegmentedStream;
if (zss != null)
{
#if NETCF
zss.Close();
#else
// need to dispose it
zss.Dispose();
#endif
_archiveStream = null;
}
}
return CrcResult;
}