/// <summary> /// Writes compressed bytes of one file to the archive, /// keeping track of the CRC and number of bytes written. /// </summary> private long PackFileBytes( IPackStreamContext streamContext, Stream fileStream, long maxArchiveSize, Func <Stream, Stream> compressionStreamCreator, ref Stream archiveStream, out uint crc) { long writeStartPosition = archiveStream.Position; long bytesWritten = 0; CrcStream fileCrcStream = new CrcStream(fileStream); ConcatStream concatStream = new ConcatStream( delegate(ConcatStream s) { Stream sourceStream = s.Source; bytesWritten += sourceStream.Position - writeStartPosition; this.CheckArchiveWriteStream( streamContext, maxArchiveSize, 1, ref sourceStream); writeStartPosition = sourceStream.Position; s.Source = sourceStream; }); concatStream.Source = archiveStream; if (maxArchiveSize > 0) { concatStream.SetLength(maxArchiveSize); } Stream compressionStream = compressionStreamCreator(concatStream); try { byte[] buf = new byte[4096]; long bytesRemaining = fileStream.Length; int counter = 0; while (bytesRemaining > 0) { int count = (int)Math.Min( bytesRemaining, (long)buf.Length); count = fileCrcStream.Read(buf, 0, count); if (count <= 0) { throw new ZipException( "Failed to read file: " + this.currentFileName); } compressionStream.Write(buf, 0, count); bytesRemaining -= count; this.fileBytesProcessed += count; this.currentFileBytesProcessed += count; this.currentArchiveTotalBytes = concatStream.Source.Position; this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes; if (++counter % 16 == 0) // Report every 64K { this.OnProgress(ArchiveProgressType.PartialFile); } } if (compressionStream is DeflateStream) { #if CORECLR compressionStream.Dispose(); #else compressionStream.Close(); #endif } else { compressionStream.Flush(); } } finally { archiveStream = concatStream.Source; } bytesWritten += archiveStream.Position - writeStartPosition; crc = fileCrcStream.Crc; return(bytesWritten); }
/// <summary> /// Decompresses bytes for one file from an archive or archive chain, /// checking the crc at the end. /// </summary> private void UnpackFileBytes( IUnpackStreamContext streamContext, string fileName, long compressedSize, long uncompressedSize, uint crc, Stream fileStream, Func <Stream, Stream> compressionStreamCreator, ref Stream archiveStream) { CrcStream crcStream = new CrcStream(fileStream); ConcatStream concatStream = new ConcatStream( delegate(ConcatStream s) { this.currentArchiveBytesProcessed = s.Source.Position; streamContext.CloseArchiveReadStream( this.currentArchiveNumber, String.Empty, s.Source); this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.FinishArchive); this.currentArchiveNumber += 2; this.currentArchiveName = null; this.currentArchiveBytesProcessed = 0; this.currentArchiveTotalBytes = 0; s.Source = this.OpenArchive(streamContext, this.currentArchiveNumber); FileStream archiveFileStream = s.Source as FileStream; this.currentArchiveName = (archiveFileStream != null ? Path.GetFileName(archiveFileStream.Name) : null); this.currentArchiveTotalBytes = s.Source.Length; this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.StartArchive); this.currentArchiveNumber++; }); concatStream.Source = archiveStream; concatStream.SetLength(compressedSize); Stream decompressionStream = compressionStreamCreator(concatStream); try { byte[] buf = new byte[4096]; long bytesRemaining = uncompressedSize; int counter = 0; while (bytesRemaining > 0) { int count = (int)Math.Min(buf.Length, bytesRemaining); count = decompressionStream.Read(buf, 0, count); crcStream.Write(buf, 0, count); bytesRemaining -= count; this.fileBytesProcessed += count; this.currentFileBytesProcessed += count; this.currentArchiveBytesProcessed = concatStream.Source.Position; if (++counter % 16 == 0) // Report every 64K { this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.PartialFile); this.currentArchiveNumber++; } } } finally { archiveStream = concatStream.Source; } crcStream.Flush(); if (crcStream.Crc != crc) { throw new ZipException("CRC check failed for file: " + fileName); } }