private static void InitCompressionStreamCreators() { if (ZipEngine.compressionStreamCreators == null) { ZipEngine.compressionStreamCreators = new Dictionary <ZipCompressionMethod, Converter <Stream, Stream> >(); ZipEngine.decompressionStreamCreators = new Dictionary <ZipCompressionMethod, Converter <Stream, Stream> >(); ZipEngine.RegisterCompressionStreamCreator( ZipCompressionMethod.Store, CompressionMode.Compress, delegate(Stream stream) { return(stream); }); ZipEngine.RegisterCompressionStreamCreator( ZipCompressionMethod.Deflate, CompressionMode.Compress, delegate(Stream stream) { return(new DeflateStream(stream, CompressionMode.Compress, true)); }); ZipEngine.RegisterCompressionStreamCreator( ZipCompressionMethod.Store, CompressionMode.Decompress, delegate(Stream stream) { return(stream); }); ZipEngine.RegisterCompressionStreamCreator( ZipCompressionMethod.Deflate, CompressionMode.Decompress, delegate(Stream stream) { return(new DeflateStream(stream, CompressionMode.Decompress, true)); }); } }
/// <summary> /// Registers a delegate that can create a warpper stream for /// compressing or uncompressing the data of a source stream. /// </summary> /// <param name="compressionMethod">Compression method being registered.</param> /// <param name="compressionMode">Indicates registration for ether /// compress or decompress mode.</param> /// <param name="creator">Delegate being registered.</param> /// <remarks> /// For compression, the delegate accepts a stream that writes to the archive /// and returns a wrapper stream that compresses bytes as they are written. /// For decompression, the delegate accepts a stream that reads from the archive /// and returns a wrapper stream that decompresses bytes as they are read. /// This wrapper stream model follows the design used by /// System.IO.Compression.DeflateStream, and indeed that class is used /// to implement the Deflate compression method by default. /// <para>To unregister a delegate, call this method again and pass /// null for the delegate parameter.</para> /// </remarks> /// <example> /// When the ZipEngine class is initialized, the Deflate compression method /// is automatically registered like this: /// <code> /// ZipEngine.RegisterCompressionStreamCreator( /// ZipCompressionMethod.Deflate, /// CompressionMode.Compress, /// delegate(Stream stream) { /// return new DeflateStream(stream, CompressionMode.Compress, true); /// }); /// ZipEngine.RegisterCompressionStreamCreator( /// ZipCompressionMethod.Deflate, /// CompressionMode.Decompress, /// delegate(Stream stream) { /// return new DeflateStream(stream, CompressionMode.Decompress, true); /// }); /// </code></example> public static void RegisterCompressionStreamCreator( ZipCompressionMethod compressionMethod, CompressionMode compressionMode, Converter <Stream, Stream> creator) { ZipEngine.InitCompressionStreamCreators(); if (compressionMode == CompressionMode.Compress) { ZipEngine.compressionStreamCreators[compressionMethod] = creator; } else { ZipEngine.decompressionStreamCreators[compressionMethod] = creator; } }
/// <summary> /// Creates a new instance of the zip engine. /// </summary> public ZipEngine() : base() { ZipEngine.InitCompressionStreamCreators(); }
private IList<ArchiveFileInfo> RunZipPackUnpack(int fileCount, long fileSize, long maxArchiveSize, CompressionLevel compLevel) { Console.WriteLine("Creating zip archive with {0} files of size {1}", fileCount, fileSize); Console.WriteLine("MaxArchiveSize={0}, CompressionLevel={1}", maxArchiveSize, compLevel); string dirA = String.Format("{0}-{1}-A", fileCount, fileSize); if (Directory.Exists(dirA)) Directory.Delete(dirA, true); Directory.CreateDirectory(dirA); string dirB = String.Format("{0}-{1}-B", fileCount, fileSize); if (Directory.Exists(dirB)) Directory.Delete(dirB, true); Directory.CreateDirectory(dirB); string[] files = new string[fileCount]; for (int iFile = 0; iFile < fileCount; iFile++) { files[iFile] = TEST_FILENAME_PREFIX + iFile + ".txt"; CompressionTestUtil.GenerateRandomFile(Path.Combine(dirA, files[iFile]), iFile, fileSize); } string[] archiveNames = new string[1000]; for (int i = 0; i < archiveNames.Length; i++) { if (i < 100) { archiveNames[i] = String.Format( (i == 0 ? "{0}-{1}.zip" : "{0}-{1}.z{2:d02}"), fileCount, fileSize, i); } else { archiveNames[i] = String.Format( "{0}-{1}.{2:d03}", fileCount, fileSize, i); } } string progressTextFile = String.Format("progress_{0}-{1}.txt", fileCount, fileSize); CompressionTestUtil testUtil = new CompressionTestUtil(progressTextFile); IList<ArchiveFileInfo> fileInfo; using (ZipEngine zipEngine = new ZipEngine()) { zipEngine.CompressionLevel = compLevel; File.AppendAllText(progressTextFile, "\r\n\r\n====================================================\r\nCREATE\r\n\r\n"); zipEngine.Progress += testUtil.PrintArchiveProgress; OptionStreamContext streamContext = new OptionStreamContext(archiveNames, dirA, null); streamContext.OptionHandler = delegate(string optionName, object[] parameters) { // For testing purposes, force zip64 for only moderately large files. switch (optionName) { case "forceZip64": return fileSize > UInt16.MaxValue; default: return null; } }; zipEngine.Pack(streamContext, files, maxArchiveSize); string checkArchiveName = archiveNames[0]; if (File.Exists(archiveNames[1])) checkArchiveName = archiveNames[1]; using (Stream archiveStream = File.OpenRead(checkArchiveName)) { bool isArchive = zipEngine.IsArchive(archiveStream); Assert.IsTrue(isArchive, "Checking that created archive appears valid."); } IList<string> createdArchiveNames = new List<string>(archiveNames.Length); for (int i = 0; i < archiveNames.Length; i++) { if (File.Exists(archiveNames[i])) { createdArchiveNames.Add(archiveNames[i]); } else { break; } } Assert.AreNotEqual<int>(0, createdArchiveNames.Count); Console.WriteLine("Listing zip archive with {0} files of size {1}", fileCount, fileSize); File.AppendAllText(progressTextFile, "\r\n\r\nLIST\r\n\r\n"); fileInfo = zipEngine.GetFileInfo( new ArchiveFileStreamContext(createdArchiveNames, null, null), null); Assert.AreEqual<int>(fileCount, fileInfo.Count); Console.WriteLine("Extracting zip archive with {0} files of size {1}", fileCount, fileSize); File.AppendAllText(progressTextFile, "\r\n\r\nEXTRACT\r\n\r\n"); zipEngine.Unpack(new ArchiveFileStreamContext(createdArchiveNames, dirB, null), null); } bool directoryMatch = CompressionTestUtil.CompareDirectories(dirA, dirB); Assert.IsTrue(directoryMatch, "Testing whether zip output directory matches input directory."); return fileInfo; }
public void ZipBadUnpackStreamContexts() { int txtSize = 40960; ZipInfo zipInfo = new ZipInfo("test2.zip"); CompressionTestUtil.GenerateRandomFile("ziptest-0.txt", 0, txtSize); CompressionTestUtil.GenerateRandomFile("ziptest-1.txt", 1, txtSize); zipInfo.PackFiles(null, new string[] { "ziptest-0.txt", "ziptest-1.txt" }, null); using (ZipEngine zipEngine = new ZipEngine()) { CompressionTestUtil.TestBadUnpackStreamContexts(zipEngine, "test2.zip"); } }
public void ZipBadPackStreamContexts() { string[] testFiles = new string[] { "test.txt" }; CompressionTestUtil.GenerateRandomFile(testFiles[0], 0, 20000); using (ZipEngine zipEngine = new ZipEngine()) { zipEngine.CompressionLevel = CompressionLevel.None; CompressionTestUtil.TestBadPackStreamContexts(zipEngine, "test.zip", testFiles); } }
public void ZipEngineNullParams() { string[] testFiles = new string[] { "test.txt" }; ArchiveFileStreamContext streamContext = new ArchiveFileStreamContext("test.zip", null, null); using (ZipEngine zipEngine = new ZipEngine()) { zipEngine.CompressionLevel = CompressionLevel.None; CompressionTestUtil.TestCompressionEngineNullParams(zipEngine, streamContext, testFiles); } }
/// <summary> /// Unpacks a single file from an archive or archive chain. /// </summary> private void UnpackOneFile( IUnpackStreamContext streamContext, ZipFileHeader header, ref Stream archiveStream) { ZipFileInfo fileInfo = null; Stream fileStream = null; try { Converter <Stream, Stream> compressionStreamCreator; if (!ZipEngine.decompressionStreamCreators.TryGetValue( header.compressionMethod, out compressionStreamCreator)) { // Silently skip files of an unsupported compression method. return; } long compressedSize; long uncompressedSize; long localHeaderOffset; int archiveNumber; uint crc; header.GetZip64Fields( out compressedSize, out uncompressedSize, out localHeaderOffset, out archiveNumber, out crc); if (this.currentArchiveNumber != archiveNumber + 1) { if (archiveStream != null) { streamContext.CloseArchiveReadStream( this.currentArchiveNumber, String.Empty, archiveStream); archiveStream = null; this.OnProgress(ArchiveProgressType.FinishArchive); this.currentArchiveName = null; } this.currentArchiveNumber = (short)(archiveNumber + 1); this.currentArchiveBytesProcessed = 0; this.currentArchiveTotalBytes = 0; archiveStream = this.OpenArchive( streamContext, this.currentArchiveNumber); FileStream archiveFileStream = archiveStream as FileStream; this.currentArchiveName = (archiveFileStream != null ? Path.GetFileName(archiveFileStream.Name) : null); this.currentArchiveTotalBytes = archiveStream.Length; this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.StartArchive); this.currentArchiveNumber++; } archiveStream.Seek(localHeaderOffset, SeekOrigin.Begin); ZipFileHeader localHeader = new ZipFileHeader(); if (!localHeader.Read(archiveStream, false) || !ZipEngine.AreFilePathsEqual(localHeader.fileName, header.fileName)) { string msg = "Could not read file: " + header.fileName; throw new ZipException(msg); } fileInfo = header.ToZipFileInfo(); fileStream = streamContext.OpenFileWriteStream( fileInfo.FullName, fileInfo.Length, fileInfo.LastWriteTime); if (fileStream != null) { this.currentFileName = header.fileName; this.currentFileBytesProcessed = 0; this.currentFileTotalBytes = fileInfo.Length; this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.StartFile); this.currentArchiveNumber++; this.UnpackFileBytes( streamContext, fileInfo.FullName, fileInfo.CompressedLength, fileInfo.Length, header.crc32, fileStream, compressionStreamCreator, ref archiveStream); } } finally { if (fileStream != null) { streamContext.CloseFileWriteStream( fileInfo.FullName, fileStream, fileInfo.Attributes, fileInfo.LastWriteTime); this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.FinishFile); this.currentArchiveNumber++; } } }