/// <summary> /// Prepare the given stream for output - wrap it in a CountingStream, and /// then in a CRC stream, and an encryptor and deflator as appropriate. /// </summary> /// <remarks> /// <para> /// Previously this was used in ZipEntry.Write(), but in an effort to /// introduce some efficiencies in that method I've refactored to put the /// code inline. This method still gets called by ZipOutputStream. /// </para> /// </remarks> internal void PrepOutputStream(Stream s, long streamLength, out CountingStream outputCounter, out Stream encryptor, out Stream compressor, out Crisis.Ionic.Crc.CrcCalculatorStream output) { TraceWriteLine("PrepOutputStream: e({0}) comp({1}) crypto({2}) zf({3})", FileName, CompressionLevel, Encryption, _container.Name); // Wrap a counting stream around the raw output stream: // This is the last thing that happens before the bits go to the // application-provided stream. outputCounter = new CountingStream(s); // Sometimes the incoming "raw" output stream is already a CountingStream. // Doesn't matter. Wrap it with a counter anyway. We need to count at both // levels. if (streamLength != 0L) { // Maybe wrap an encrypting stream around that: // This will happen BEFORE output counting, and AFTER deflation, if encryption // is used. encryptor = MaybeApplyEncryption(outputCounter); // Maybe wrap a compressing Stream around that. // This will happen BEFORE encryption (if any) as we write data out. compressor = MaybeApplyCompression(encryptor, streamLength); } else { encryptor = compressor = outputCounter; } // Wrap a CrcCalculatorStream around that. // This will happen BEFORE compression (if any) as we write data out. output = new Crisis.Ionic.Crc.CrcCalculatorStream(compressor, true); }
private Int32 FigureCrc32() { if (_crcCalculated == false) { Stream input = null; // get the original stream: if (this._Source == ZipEntrySource.WriteDelegate) { var output = new Crisis.Ionic.Crc.CrcCalculatorStream(Stream.Null); // allow the application to write the data this._WriteDelegate(this.FileName, output); _Crc32 = output.Crc; } else if (this._Source == ZipEntrySource.ZipFile) { // nothing to do - the CRC is already set } else { if (this._Source == ZipEntrySource.Stream) { PrepSourceStream(); input = this._sourceStream; } else if (this._Source == ZipEntrySource.JitStream) { // allow the application to open the stream if (this._sourceStream == null) _sourceStream = this._OpenDelegate(this.FileName); PrepSourceStream(); input = this._sourceStream; } else if (this._Source == ZipEntrySource.ZipOutputStream) { } else { //input = File.OpenRead(LocalFileName); input = File.Open(LocalFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); } var crc32 = new Crisis.Ionic.Crc.CRC32(); _Crc32 = crc32.GetCrc32(input); if (_sourceStream == null) { #if NETCF input.Close(); #else input.Dispose(); #endif } } _crcCalculated = true; } return _Crc32; }
private void _WriteEntryData(Stream s) { // Read in the data from the input stream (often a file in the filesystem), // and write it to the output stream, calculating a CRC on it as we go. // We will also compress and encrypt as necessary. Stream input = null; long fdp = -1L; try { // Want to record the position in the zip file of the zip entry // data (as opposed to the metadata). s.Position may fail on some // write-only streams, eg stdout or System.Web.HttpResponseStream. // We swallow that exception, because we don't care, in that case. // But, don't set __FileDataPosition directly. It may be needed // to READ the zip entry from the zip file, if this is a // "re-stream" situation. In other words if the zip entry has // changed compression level, or compression method, or (maybe?) // encryption algorithm. In that case if the original entry is // encrypted, we need __FileDataPosition to be the value for the // input zip file. This s.Position is for the output zipfile. So // we copy fdp to __FileDataPosition after this entry has been // (maybe) restreamed. fdp = s.Position; } catch (Exception) { } try { // Use fileLength for progress updates, and to decide whether we can // skip encryption and compression altogether (in case of length==zero) long fileLength = SetInputAndFigureFileLength(ref input); // Wrap a counting stream around the raw output stream: // This is the last thing that happens before the bits go to the // application-provided stream. // // Sometimes s is a CountingStream. Doesn't matter. Wrap it with a // counter anyway. We need to count at both levels. CountingStream entryCounter = new CountingStream(s); Stream encryptor; Stream compressor; if (fileLength != 0L) { // Maybe wrap an encrypting stream around the counter: This will // happen BEFORE output counting, and AFTER compression, if encryption // is used. encryptor = MaybeApplyEncryption(entryCounter); // Maybe wrap a compressing Stream around that. // This will happen BEFORE encryption (if any) as we write data out. compressor = MaybeApplyCompression(encryptor, fileLength); } else { encryptor = compressor = entryCounter; } // Wrap a CrcCalculatorStream around that. // This will happen BEFORE compression (if any) as we write data out. var output = new Crisis.Ionic.Crc.CrcCalculatorStream(compressor, true); // output.Write() causes this flow: // calc-crc -> compress -> encrypt -> count -> actually write if (this._Source == ZipEntrySource.WriteDelegate) { // allow the application to write the data this._WriteDelegate(this.FileName, output); } else { // synchronously copy the input stream to the output stream-chain byte[] buffer = new byte[BufferSize]; int n; while ((n = SharedUtilities.ReadWithRetry(input, buffer, 0, buffer.Length, FileName)) != 0) { output.Write(buffer, 0, n); OnWriteBlock(output.TotalBytesSlurped, fileLength); if (_ioOperationCanceled) break; } } FinishOutputStream(s, entryCounter, encryptor, compressor, output); } finally { if (this._Source == ZipEntrySource.JitStream) { // allow the application to close the stream if (this._CloseDelegate != null) this._CloseDelegate(this.FileName, input); } else if ((input as FileStream) != null) { #if NETCF input.Close(); #else input.Dispose(); #endif } } if (_ioOperationCanceled) return; // set FDP now, to allow for re-streaming this.__FileDataPosition = fdp; PostProcessOutput(s); }
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; }