// Streams.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2011 Dino Chiesa
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// Last Saved: <2011-July-28 07:33:02>
//
// ------------------------------------------------------------------
//
// This module defines tests for Streams interfaces into DotNetZip, that
// DotNetZip can write to streams, read from streams, ZipOutputStream,
// ZipInputStream, etc.
//
// ------------------------------------------------------------------
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ionic.Zip;
using Ionic.Zlib;
using Ionic.Zip.Tests.Utilities;
namespace Ionic.Zip.Tests.Streams
{
///
/// Summary description for StreamsTests
///
[TestClass]
public class StreamsTests : IonicTestClass
{
public StreamsTests() : base() { }
EncryptionAlgorithm[] crypto =
{
EncryptionAlgorithm.None,
EncryptionAlgorithm.PkzipWeak,
EncryptionAlgorithm.WinZipAes128,
EncryptionAlgorithm.WinZipAes256,
};
#if NOT
EncryptionAlgorithm[] cryptoNoPkzip =
{
EncryptionAlgorithm.None,
EncryptionAlgorithm.WinZipAes128,
EncryptionAlgorithm.WinZipAes256,
};
#endif
Ionic.Zlib.CompressionLevel[] compLevels =
{
Ionic.Zlib.CompressionLevel.None,
Ionic.Zlib.CompressionLevel.BestSpeed,
Ionic.Zlib.CompressionLevel.Default,
Ionic.Zlib.CompressionLevel.BestCompression,
};
Zip64Option[] z64 =
{
Zip64Option.Never,
Zip64Option.AsNecessary,
Zip64Option.Always,
};
[TestMethod]
public void ZOS_Create_Encrypt_wi12815()
{
string zipFileToCreate =
"ZOS_Create_Encrypt_wi12815.zip";
var content = new byte[1789];
unchecked
{
byte b = 0;
for (var i = 0; i < content.Length; i++, b++)
{
content[i] = b;
}
}
var checkBuffer = new Action(stage =>
{
byte b = 0;
TestContext.WriteLine("Checking buffer ({0})", stage);
for (var i = 0; i < content.Length; i++, b++)
{
Assert.IsTrue((content[i] == b),
"Buffer was modified.");
}
});
checkBuffer("before");
using (var fileStream = File.OpenWrite(zipFileToCreate))
{
using (var zipStream = new ZipOutputStream(fileStream, true))
{
zipStream.CompressionLevel = Ionic.Zlib.CompressionLevel.None;
zipStream.Password = "mydummypassword";
zipStream.Encryption = EncryptionAlgorithm.WinZipAes256;
zipStream.PutNextEntry("myentry.myext");
zipStream.Write(content, 0, content.Length);
}
}
checkBuffer("after");
}
[TestMethod]
public void ReadZip_OpenReader()
{
string[] passwords = { null, Path.GetRandomFileName(), "EE", "***()" };
for (int j = 0; j < compLevels.Length; j++)
{
for (int k = 0; k < passwords.Length; k++)
{
string zipFileToCreate = String.Format("ReadZip_OpenReader-{0}-{1}.zip", j, k);
//int entriesAdded = 0;
//String filename = null;
string dirToZip = String.Format("dirToZip.{0}.{1}", j, k);
var files = TestUtilities.GenerateFilesFlat(dirToZip);
using (ZipFile zip1 = new ZipFile())
{
zip1.CompressionLevel = compLevels[j];
zip1.Password = passwords[k];
zip1.AddDirectory(dirToZip,dirToZip);
zip1.Save(zipFileToCreate);
}
// Verify the files are in the zip
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate),
files.Length,
String.Format("Trial ({0},{1})", j, k));
int i = 0;
ZipEntry e1 = null;
Func opener = () => {
if (i == 0)
return e1.OpenReader();
if (i == 1)
return e1.OpenReader(passwords[k]);
e1.Password = passwords[k];
return e1.OpenReader();
};
// now extract the files and verify their contents
using (ZipFile zip2 = ZipFile.Read(zipFileToCreate))
{
for (i = 0; i < 3; i++)
{
// try once with Password set on ZipFile,
// another with password on the entry, and
// a third time with password passed into the OpenReader() method.
if (i == 0) zip2.Password = passwords[k];
foreach (string eName in zip2.EntryFileNames)
{
e1 = zip2[eName];
if (e1.IsDirectory) continue;
using (var s = opener())
{
string outFile = String.Format("{0}.{1}.out", eName, i);
int totalBytesRead = 0;
using (var output = File.Create(outFile))
{
byte[] buffer = new byte[4096];
int n;
while ((n = s.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytesRead += n;
output.Write(buffer, 0, n);
}
}
TestContext.WriteLine("CRC expected({0:X8}) actual({1:X8})",
e1.Crc, s.Crc);
Assert.AreEqual(s.Crc, e1.Crc,
string.Format("{0} :: CRC Mismatch", eName));
Assert.AreEqual(totalBytesRead, (int)e1.UncompressedSize,
string.Format("We read an unexpected number of bytes. ({0})", eName));
}
}
}
}
}
}
}
[TestMethod]
public void ZOS_Create_WithComment_wi10339()
{
string zipFileToCreate = "ZOS_Create_WithComment_wi10339.zip";
using (var fs = File.Create(zipFileToCreate))
{
using (var output = new ZipOutputStream(fs))
{
output.CompressionLevel = Ionic.Zlib.CompressionLevel.None;
output.Comment = "Cheeso is the man!";
string entryName = String.Format("entry{0:D4}.txt", _rnd.Next(10000));
output.PutNextEntry(entryName);
string content = "This is the content for the entry.";
byte[] buffer = Encoding.ASCII.GetBytes(content);
output.Write(buffer, 0, buffer.Length);
}
}
}
[TestMethod]
[ExpectedException(typeof(System.ArgumentNullException))]
public void ZOS_Create_NullBuffer_wi12964()
{
using (var zip = new Ionic.Zip.ZipOutputStream(new MemoryStream()))
{
zip.PutNextEntry("EmptyFile.txt");
zip.Write(null, 0, 0);
//zip.Write(new byte[1], 0, 0);
}
}
[TestMethod]
public void ZOS_Create_ZeroByteEntry_wi12964()
{
using (var zip = new Ionic.Zip.ZipOutputStream(new MemoryStream()))
{
zip.PutNextEntry("EmptyFile.txt");
zip.Write(new byte[1], 0, 0);
}
}
[TestMethod]
public void AddEntry_JitProvided()
{
for (int i = 0; i < crypto.Length; i++)
{
for (int k = 0; k < compLevels.Length; k++)
{
string zipFileToCreate = String.Format("AddEntry_JitProvided.{0}.{1}.zip", i, k);
string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
var files = TestUtilities.GenerateFilesFlat(dirToZip);
string password = Path.GetRandomFileName();
using (var zip = new ZipFile())
{
TestContext.WriteLine("=================================");
TestContext.WriteLine("Creating {0}...", Path.GetFileName(zipFileToCreate));
TestContext.WriteLine("Encryption({0}) Compression({1}) pw({2})",
crypto[i].ToString(), compLevels[k].ToString(), password);
zip.Password = password;
zip.Encryption = crypto[i];
zip.CompressionLevel = compLevels[k];
foreach (var file in files)
zip.AddEntry(file,
(name) => File.OpenRead(name),
(name, stream) => stream.Close()
);
zip.Save(zipFileToCreate);
}
if (crypto[i] == EncryptionAlgorithm.None)
BasicVerifyZip(zipFileToCreate);
else
BasicVerifyZip(zipFileToCreate, password);
Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate),
"Trial ({0},{1}): The zip file created has the wrong number of entries.", i, k);
}
}
}
private delegate void TestCompressionLevels(string[] files,
EncryptionAlgorithm crypto,
bool seekable,
int cycle,
string format,
int fileOutputOption);
private void _TestDriver(TestCompressionLevels test, string label, bool seekable, bool zero)
{
_TestDriver(test, label, seekable, zero, 0);
}
private void _TestDriver(TestCompressionLevels test, string label, bool seekable, bool zero, int fileOutputOption)
{
int[] fileCounts = new int[] { 1, 2, _rnd.Next(14) + 13 };
for (int j = 0; j < fileCounts.Length; j++)
{
string dirToZip = String.Format("subdir{0}", j);
string[] files = null;
if (zero)
{
// zero length files
Directory.CreateDirectory(dirToZip);
files = new string[fileCounts[j]];
for (int i = 0; i < fileCounts[j]; i++)
files[i] = TestUtilities.CreateUniqueFile("zerolength", dirToZip);
}
else
files = TestUtilities.GenerateFilesFlat(dirToZip, fileCounts[j], 40000, 72000);
for (int i = 0; i < crypto.Length; i++)
{
string format = String.Format("{0}.{1}.count.{2}.Encrypt.{3}.Seek.{4}.Compress.{5}.zip",
label,
(zero) ? "ZeroBytes" : "regular",
fileCounts[j],
crypto[i].ToString(),
seekable ? "Oui" : "Non",
"{0}");
test(files, crypto[i], seekable, i, format, fileOutputOption);
}
}
}
private void _Internal_AddEntry_WriteDelegate(string[] files,
EncryptionAlgorithm crypto,
bool seekable,
int cycle,
string format,
int ignored)
{
int bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
int n;
for (int k = 0; k < compLevels.Length; k++)
{
string zipFileToCreate = Path.Combine(TopLevelDir, String.Format(format, compLevels[k].ToString()));
string password = TestUtilities.GenerateRandomPassword();
using (var zip = new ZipFile())
{
TestContext.WriteLine("=================================");
TestContext.WriteLine("Creating {0}...", Path.GetFileName(zipFileToCreate));
TestContext.WriteLine("Encryption({0}) Compression({1}) pw({2})",
crypto.ToString(), compLevels[k].ToString(), password);
zip.Password = password;
zip.Encryption = crypto;
zip.CompressionLevel = compLevels[k];
foreach (var file in files)
{
zip.AddEntry(file, (name, output) =>
{
using (var input = File.OpenRead(name))
{
while ((n = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, n);
}
}
});
}
if (!seekable)
{
// conditionally use a non-seekable output stream
using (var raw = File.Create(zipFileToCreate))
{
using (var ns = new Ionic.Zip.Tests.NonSeekableOutputStream(raw))
{
zip.Save(ns);
}
}
}
else
zip.Save(zipFileToCreate);
}
BasicVerifyZip(Path.GetFileName(zipFileToCreate), password);
Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate),
"Trial ({0},{1}): The zip file created has the wrong number of entries.", cycle, k);
}
}
[TestMethod]
public void WriteDelegate()
{
_TestDriver(new TestCompressionLevels(_Internal_AddEntry_WriteDelegate), "WriteDelegate", true, false);
}
[TestMethod]
public void WriteDelegate_NonSeekable()
{
_TestDriver(new TestCompressionLevels(_Internal_AddEntry_WriteDelegate), "WriteDelegate", false, false);
}
[TestMethod]
public void WriteDelegate_ZeroBytes_wi8931()
{
_TestDriver(new TestCompressionLevels(_Internal_AddEntry_WriteDelegate), "WriteDelegate", true, true);
}
[TestMethod]
public void ZOS_Create_ZeroBytes_Encrypt_NonSeekable()
{
// At one stage, using ZipOutputStream with Encryption and a
// non-seekable output stream did not work. DotNetZip was changed to be
// smarter, so that works now. This test verifies that combination
// of stuff.
string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
Directory.CreateDirectory(dirToZip);
int fileCount = _rnd.Next(4) + 1;
string[] files = new string[fileCount];
for (int i = 0; i < fileCount; i++)
files[i] = TestUtilities.CreateUniqueFile("zerolength", dirToZip);
for (int i = 0; i < crypto.Length; i++)
{
string format = String.Format("ZipOutputStream.ZeroBytes.filecount{0}.Encryption.{1}.NonSeekable.{2}.zip",
fileCount,
crypto[i],
"{0}");
_Internal_ZOS_Create(files, EncryptionAlgorithm.PkzipWeak, false, 99, format);
}
}
[TestMethod, Timeout(45 * 60*1000)]
public void ZOS_over65534_EncryptPkZip_CompressDefault_Z64AsNecessary()
{
_ZOS_z64Over65534Entries(Zip64Option.AsNecessary,
EncryptionAlgorithm.PkzipWeak,
Ionic.Zlib.CompressionLevel.Default);
}
[TestMethod, Timeout(2 * 60*60*1000)]
public void ZOS_over65534_EncryptWinZip_CompressDefault_Z64AsNecessary()
{
_ZOS_z64Over65534Entries(Zip64Option.AsNecessary,
EncryptionAlgorithm.WinZipAes256,
Ionic.Zlib.CompressionLevel.Default);
}
[TestMethod, Timeout(45 * 60*1000)]
public void ZOS_over65534_EncryptNo_CompressDefault_Z64AsNecessary()
{
_ZOS_z64Over65534Entries(Zip64Option.AsNecessary,
EncryptionAlgorithm.None,
Ionic.Zlib.CompressionLevel.Default);
}
[TestMethod, Timeout(35 * 60 * 1000)]
[ExpectedException(typeof(System.InvalidOperationException))]
public void ZOS_over65534_FAIL()
{
_ZOS_z64Over65534Entries(Zip64Option.Never,
EncryptionAlgorithm.PkzipWeak,
Ionic.Zlib.CompressionLevel.Default);
}
private void _ZOS_z64Over65534Entries
(Zip64Option z64option,
EncryptionAlgorithm encryption,
Ionic.Zlib.CompressionLevel compression)
{
TestContext.WriteLine("_ZOS_z64Over65534Entries hello: {0}",
DateTime.Now.ToString("G"));
int fileCount = _rnd.Next(14616) + 65536;
//int fileCount = _rnd.Next(146) + 5536;
TestContext.WriteLine("entries: {0}", fileCount);
var txrxLabel =
String.Format("ZOS #{0} 64({3}) E({1}) C({2})",
fileCount,
encryption.ToString(),
compression.ToString(),
z64option.ToString());
TestContext.WriteLine("label: {0}", txrxLabel);
string zipFileToCreate =
String.Format("ZOS.Zip64.over65534.{0}.{1}.{2}.zip",
z64option.ToString(), encryption.ToString(),
compression.ToString());
TestContext.WriteLine("zipFileToCreate: {0}", zipFileToCreate);
_txrx = TestUtilities.StartProgressMonitor(zipFileToCreate,
txrxLabel, "starting up...");
TestContext.WriteLine("generating {0} entries ", fileCount);
_txrx.Send("pb 0 max 3"); // 2 stages: Write, Count, Verify
_txrx.Send("pb 0 value 0");
string password = Path.GetRandomFileName();
string statusString = String.Format("status Encryption:{0} Compression:{1}",
encryption.ToString(),
compression.ToString());
_txrx.Send(statusString);
int dirCount = 0;
using (FileStream fs = File.Create(zipFileToCreate))
{
using (var output = new ZipOutputStream(fs))
{
_txrx.Send("test " + txrxLabel);
System.Threading.Thread.Sleep(400);
_txrx.Send("pb 1 max " + fileCount);
_txrx.Send("pb 1 value 0");
output.Password = password;
output.Encryption = encryption;
output.CompressionLevel = compression;
output.EnableZip64 = z64option;
for (int k = 0; k < fileCount; k++)
{
if (_rnd.Next(7) == 0)
{
// make it a directory
string entryName = String.Format("{0:D4}/", k);
output.PutNextEntry(entryName);
dirCount++;
}
else
{
string entryName = String.Format("{0:D4}.txt", k);
output.PutNextEntry(entryName);
// only a few entries are non-empty
if (_rnd.Next(18) == 0)
{
var block = TestUtilities.GenerateRandomAsciiString();
string content = String.Format("This is the content for entry #{0}.\n", k);
int n = _rnd.Next(4) + 1;
for (int j=0; j < n; j++)
content+= block;
byte[] buffer = Encoding.ASCII.GetBytes(content);
output.Write(buffer, 0, buffer.Length);
}
}
if (k % 1024 == 0)
_txrx.Send(String.Format("status saving ({0}/{1}) {2:N0}%",
k, fileCount,
((double)k) / (0.01 * fileCount)));
else if (k % 256 == 0)
_txrx.Send("pb 1 value " + k);
}
}
}
_txrx.Send("pb 1 max 1");
_txrx.Send("pb 1 value 1");
_txrx.Send("pb 0 step");
System.Threading.Thread.Sleep(400);
TestContext.WriteLine("Counting entries ... " + DateTime.Now.ToString("G"));
_txrx.Send("status Counting entries...");
Assert.AreEqual
(fileCount - dirCount,
TestUtilities.CountEntries(zipFileToCreate),
"{0}: The zip file created has the wrong number of entries.",
zipFileToCreate);
_txrx.Send("pb 0 step");
System.Threading.Thread.Sleep(140);
// basic verify. The output is really large, so we pass emitOutput=false .
_txrx.Send("status Verifying...");
TestContext.WriteLine("Verifying ... " + DateTime.Now.ToString("G"));
_numExtracted = 0;
_numFilesToExtract = fileCount;
_txrx.Send("pb 1 max " + fileCount);
System.Threading.Thread.Sleep(200);
_txrx.Send("pb 1 value 0");
BasicVerifyZip(zipFileToCreate, password, false, Streams_ExtractProgress);
_txrx.Send("pb 0 step");
System.Threading.Thread.Sleep(800);
TestContext.WriteLine("Done ... " + DateTime.Now.ToString("G"));
}
private int _numExtracted;
private int _numFilesToExtract;
void Streams_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
switch (e.EventType)
{
case ZipProgressEventType.Extracting_AfterExtractEntry:
_numExtracted++;
if ((_numExtracted % 512) == 0)
_txrx.Send("pb 1 value " + _numExtracted);
else if ((_numExtracted % 256) == 0)
_txrx.Send(String.Format("status extract {0}/{1} {2:N0}%",
_numExtracted, _numFilesToExtract,
_numExtracted / (0.01 *_numFilesToExtract)));
break;
}
}
[TestMethod]
[ExpectedException(typeof(System.InvalidOperationException))]
public void ZOS_Create_WriteBeforePutNextEntry()
{
string zipFileToCreate = "ZOS_Create_WriteBeforePutNextEntry.zip";
using (var fs = File.Create(zipFileToCreate))
{
using (var output = new ZipOutputStream(fs))
{
//output.PutNextEntry("entry1.txt");
byte[] buffer = Encoding.ASCII.GetBytes("This is the content for entry #1.");
output.Write(buffer, 0, buffer.Length);
}
}
}
[TestMethod]
public void ZOS_Create_Directories()
{
for (int i = 0; i < crypto.Length; i++)
{
for (int j = 0; j < compLevels.Length; j++)
{
string password = Path.GetRandomFileName();
for (int k = 0; k < 2; k++)
{
string zipFileToCreate =
String.Format("ZOS_Create_Directories.Encryption.{0}.{1}.{2}.zip",
crypto[i].ToString(), compLevels[j].ToString(), k);
using (var fs = File.Create(zipFileToCreate))
{
using (var output = new ZipOutputStream(fs))
{
byte[] buffer;
output.Password = password;
output.Encryption = crypto[i];
output.CompressionLevel = compLevels[j];
output.PutNextEntry("entry1.txt");
if (k == 0)
{
buffer = Encoding.ASCII.GetBytes("This is the content for entry #1.");
output.Write(buffer, 0, buffer.Length);
}
output.PutNextEntry("entry2/"); // this will be a directory
output.PutNextEntry("entry3.txt");
if (k == 0)
{
buffer = Encoding.ASCII.GetBytes("This is the content for entry #3.");
output.Write(buffer, 0, buffer.Length);
}
output.PutNextEntry("entry4.txt"); // a zero length entry
output.PutNextEntry("entry5.txt"); // zero length
}
}
BasicVerifyZip(zipFileToCreate, password);
Assert.AreEqual(4, TestUtilities.CountEntries(zipFileToCreate),
"Trial ({0},{1})", i, j);
}
}
}
}
[TestMethod]
[ExpectedException(typeof(System.InvalidOperationException))]
public void ZOS_Create_Directories_Write()
{
for (int k = 0; k < 2; k++)
{
string zipFileToCreate = String.Format("ZOS_Create_Directories.{0}.zip", k);
using (var fs = File.Create(zipFileToCreate))
{
using (var output = new ZipOutputStream(fs))
{
byte[] buffer;
output.Encryption = EncryptionAlgorithm.None;
output.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
output.PutNextEntry("entry1/");
if (k == 0)
{
buffer = Encoding.ASCII.GetBytes("This is the content for entry #1.");
// this should fail
output.Write(buffer, 0, buffer.Length);
}
output.PutNextEntry("entry2/"); // this will be a directory
output.PutNextEntry("entry3.txt");
if (k == 0)
{
buffer = Encoding.ASCII.GetBytes("This is the content for entry #3.");
output.Write(buffer, 0, buffer.Length);
}
output.PutNextEntry("entry4.txt"); // this will be zero length
output.PutNextEntry("entry5.txt"); // this will be zero length
}
}
}
}
[TestMethod]
public void ZOS_Create_EmptyEntries()
{
for (int i = 0; i < crypto.Length; i++)
{
for (int j = 0; j < compLevels.Length; j++)
{
string password = Path.GetRandomFileName();
for (int k = 0; k < 2; k++)
{
string zipFileToCreate = String.Format("ZOS_Create_EmptyEntries.Encryption.{0}.{1}.{2}.zip",
crypto[i].ToString(), compLevels[j].ToString(), k);
using (var fs = File.Create(zipFileToCreate))
{
using (var output = new ZipOutputStream(fs))
{
byte[] buffer;
output.Password = password;
output.Encryption = crypto[i];
output.CompressionLevel = compLevels[j];
output.PutNextEntry("entry1.txt");
if (k == 0)
{
buffer = Encoding.ASCII.GetBytes("This is the content for entry #1.");
output.Write(buffer, 0, buffer.Length);
}
output.PutNextEntry("entry2.txt"); // this will be zero length
output.PutNextEntry("entry3.txt");
if (k == 0)
{
buffer = Encoding.ASCII.GetBytes("This is the content for entry #3.");
output.Write(buffer, 0, buffer.Length);
}
output.PutNextEntry("entry4.txt"); // this will be zero length
output.PutNextEntry("entry5.txt"); // this will be zero length
}
}
BasicVerifyZip(zipFileToCreate, password);
Assert.AreEqual(5, TestUtilities.CountEntries(zipFileToCreate),
"Trial ({0},{1}): The zip file created has the wrong number of entries.", i, j);
}
}
}
}
[TestMethod]
[ExpectedException(typeof(System.ArgumentException))]
public void ZOS_Create_DuplicateEntry()
{
string zipFileToCreate = "ZOS_Create_DuplicateEntry.zip";
string entryName = Path.GetRandomFileName();
using (var fs = File.Create(zipFileToCreate))
{
using (var output = new ZipOutputStream(fs))
{
output.PutNextEntry(entryName);
output.PutNextEntry(entryName);
}
}
}
[TestMethod]
public void ZOS_Create()
{
bool seekable = true;
bool zero = false;
_TestDriver(new TestCompressionLevels(_Internal_ZOS_Create), "ZipOutputStream", seekable, zero);
}
[TestMethod]
public void ZOS_Create_file()
{
bool seekable = true;
bool zero = false;
int fileOutputOption = 1;
_TestDriver(new TestCompressionLevels(_Internal_ZOS_Create), "ZipOutputStream", seekable, zero, fileOutputOption);
}
[TestMethod]
public void ZOS_Create_NonSeekable()
{
bool seekable = false;
bool zero = false;
_TestDriver(new TestCompressionLevels(_Internal_ZOS_Create), "ZipOutputStream", seekable, zero);
}
[TestMethod]
public void ZOS_Create_ZeroLength_wi8933()
{
bool seekable = true;
bool zero = true;
_TestDriver(new TestCompressionLevels(_Internal_ZOS_Create), "ZipOutputStream", seekable, zero);
}
[TestMethod]
public void ZOS_Create_ZeroLength_wi8933_file()
{
bool seekable = true;
bool zero = true;
int fileOutputOption = 1;
_TestDriver(new TestCompressionLevels(_Internal_ZOS_Create), "ZipOutputStream", seekable, zero, fileOutputOption);
}
private void _Internal_ZOS_Create(string[] files,
EncryptionAlgorithm crypto,
bool seekable,
int cycle,
string format)
{
_Internal_ZOS_Create(files, crypto, seekable, cycle, format, 0);
}
private void _Internal_ZOS_Create(string[] files,
EncryptionAlgorithm crypto,
bool seekable,
int cycle,
string format,
int fileOutputOption)
{
int BufferSize = 2048;
for (int k = 0; k < compLevels.Length; k++)
{
string zipFileToCreate = Path.Combine(TopLevelDir, String.Format(format, compLevels[k].ToString()));
string password = Path.GetRandomFileName();
TestContext.WriteLine("=================================");
TestContext.WriteLine("Creating {0}...", Path.GetFileName(zipFileToCreate));
TestContext.WriteLine("Encryption({0}) Compression({1}) pw({2})",
crypto.ToString(), compLevels[k].ToString(), password);
using (ZipOutputStream output = GetZipOutputStream(seekable, fileOutputOption, zipFileToCreate))
{
if (crypto != EncryptionAlgorithm.None)
{
output.Password = password;
output.Encryption = crypto;
}
output.CompressionLevel = compLevels[k];
byte[] buffer = new byte[BufferSize];
int n;
foreach (var file in files)
{
TestContext.WriteLine("file: {0}", file);
output.PutNextEntry(file);
using (var input = File.OpenRead(file))
{
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, n);
}
}
}
}
BasicVerifyZip(zipFileToCreate, password);
Assert.AreEqual(files.Length, TestUtilities.CountEntries(zipFileToCreate),
"Trial ({0},{1}): The zip file created has the wrong number of entries.", cycle, k);
}
}
private static ZipOutputStream GetZipOutputStream(bool seekable, int fileOutputOption, string zipFileToCreate)
{
if (fileOutputOption == 0)
{
Stream raw = File.Create(zipFileToCreate);
// conditionally use a non-seekable output stream
if (!seekable)
raw = new Ionic.Zip.Tests.NonSeekableOutputStream(raw);
return new ZipOutputStream(raw);
}
return new ZipOutputStream(zipFileToCreate);
}
bool _pb2Set;
bool _pb1Set;
int _numSaving;
int _totalToSave;
private void streams_SaveProgress(object sender, SaveProgressEventArgs e)
{
string msg;
switch (e.EventType)
{
case ZipProgressEventType.Saving_Started:
//_txrx.Send("status saving started...");
_pb1Set = false;
_numSaving = 1;
break;
case ZipProgressEventType.Saving_BeforeWriteEntry:
//_txrx.Send(String.Format("status Compressing {0}", e.CurrentEntry.FileName));
if (!_pb1Set)
{
_txrx.Send(String.Format("pb 1 max {0}", e.EntriesTotal));
_pb1Set = true;
}
_totalToSave = e.EntriesTotal;
_pb2Set = false;
break;
case ZipProgressEventType.Saving_EntryBytesRead:
if (!_pb2Set)
{
_txrx.Send(String.Format("pb 2 max {0}", e.TotalBytesToTransfer));
_pb2Set = true;
}
// _txrx.Send(String.Format("status Saving entry {0}/{1} :: {2} :: {3}/{4}mb {5:N0}%",
// _numSaving, _totalToSave,
// e.CurrentEntry.FileName,
// e.BytesTransferred/(1024*1024), e.TotalBytesToTransfer/(1024*1024),
// ((double)e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer)));
msg = String.Format("pb 2 value {0}", e.BytesTransferred);
_txrx.Send(msg);
//System.Threading.Thread.Sleep(40);
break;
case ZipProgressEventType.Saving_AfterWriteEntry:
_txrx.Send("pb 1 step");
_numSaving++;
break;
case ZipProgressEventType.Saving_Completed:
//_txrx.Send("status Save completed");
_pb1Set = false;
_pb2Set = false;
_txrx.Send("pb 1 max 1");
_txrx.Send("pb 1 value 1");
break;
}
}
[TestMethod]
public void ZipFile_JitStream_CloserTwice_wi10489()
{
int fileCount = 20 + _rnd.Next(20);
string zipFileToCreate = "CloserTwice.zip";
string dirToZip = "fodder";
var files = TestUtilities.GenerateFilesFlat(dirToZip, fileCount, 100, 72000);
OpenDelegate opener = (name) =>
{
TestContext.WriteLine("Opening {0}", name);
Stream s = File.OpenRead(Path.Combine(dirToZip,name));
return s;
};
CloseDelegate closer = (e, s) =>
{
TestContext.WriteLine("Closing {0}", e);
s.Dispose();
};
TestContext.WriteLine("Creating zipfile {0}", zipFileToCreate);
using (var zip = new ZipFile())
{
foreach (var file in files)
{
zip.AddEntry(Path.GetFileName(file),opener,closer);
}
zip.Save(zipFileToCreate);
}
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate),
files.Length);
BasicVerifyZip(zipFileToCreate);
}
[TestMethod]
public void JitStream_Update_wi13899()
{
int fileCount = 12 + _rnd.Next(16);
string dirToZip = "fodder";
var files = TestUtilities.GenerateFilesFlat(dirToZip, fileCount, 100, 72000);
OpenDelegate opener = (name) =>
{
TestContext.WriteLine("Opening {0}", name);
Stream s = File.OpenRead(Path.Combine(dirToZip,name));
return s;
};
CloseDelegate closer = (e, s) =>
{
TestContext.WriteLine("Closing {0}", e);
s.Dispose();
};
// Two passes: first to call UpdateEntry() when no prior entry exists.
// Second to call UpdateEntry when a prior entry exists.
for (int j=0; j < 2; j++)
{
string zipFileToCreate = String.Format("wi13899-{0}.zip", j);
TestContext.WriteLine("");
TestContext.WriteLine("Creating zipfile {0}", zipFileToCreate);
if (j!=0)
{
using (var zip = new ZipFile(zipFileToCreate))
{
foreach (var file in files)
{
zip.AddEntry(Path.GetFileName(file), "This is the content for file " + file);
}
zip.Save();
}
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate),
files.Length);
BasicVerifyZip(zipFileToCreate);
TestContext.WriteLine("Updating zipfile {0}", zipFileToCreate);
}
using (var zip = new ZipFile(zipFileToCreate))
{
foreach (var file in files)
{
zip.UpdateEntry(Path.GetFileName(file), opener, closer);
}
zip.Save();
}
BasicVerifyZip(zipFileToCreate);
// verify checksum here?
}
}
[TestMethod, Timeout(30 * 60 * 1000)] // in ms. 30*60*100 == 30min
public void ZipFile_PDOS_LeakTest_wi10030()
{
// Test memory growth over many many cycles.
// There was a leak in the ParallelDeflateOutputStream, where
// the PDOS was not being GC'd. This test checks for that.
//
// If the error is present, this test will either timeout or
// throw an InsufficientMemoryException (or whatever). The
// timeout occurs because GC begins to get verrrrry
// sloooooow. IF the error is not present, this test will
// complete successfully, in about 20 minutes.
//
string zipFileToCreate = "ZipFile_PDOS_LeakTest_wi10030.zip";
int nCycles = 4096;
int nFiles = 3;
int sizeBase = 384 * 1024;
int sizeRange = 32 * 1024;
int count = 0;
byte[] buffer = new byte[1024];
int n;
// fill a couple memory streams with random text
MemoryStream[] ms = new MemoryStream[nFiles];
for (int i = 0; i < ms.Length; i++)
{
ms[i] = new MemoryStream();
int sz = sizeBase + _rnd.Next(sizeRange);
using (Stream rtg = new Ionic.Zip.Tests.Utilities.RandomTextInputStream(sz))
{
while ((n = rtg.Read(buffer, 0, buffer.Length)) > 0)
{
ms[i].Write(buffer, 0, n);
}
}
}
buffer = null;
OpenDelegate opener = (x) =>
{
Stream s = ms[count % ms.Length];
s.Seek(0L, SeekOrigin.Begin);
count++;
return s;
};
CloseDelegate closer = (e, s) =>
{
//s.Close();
};
string txrxLabel = "PDOS Leak Test";
_txrx = TestUtilities.StartProgressMonitor("ZipFile_PDOS_LeakTest_wi10030", txrxLabel, "starting up...");
TestContext.WriteLine("Testing for leaks....");
_txrx.Send(String.Format("pb 0 max {0}", nCycles));
_txrx.Send("pb 0 value 0");
for (int x = 0; x < nCycles; x++)
{
if (x != 0 && x % 16 == 0)
{
TestContext.WriteLine("Cycle {0}...", x);
string status = String.Format("status Cycle {0}/{1} {2:N0}%",
x + 1, nCycles,
((x+1)/(0.01 * nCycles)));
_txrx.Send(status);
}
using (ZipFile zip = new ZipFile())
{
zip.ParallelDeflateThreshold = 128 * 1024;
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
//zip.SaveProgress += streams_SaveProgress;
for (int y = 0; y < nFiles; y++)
{
zip.AddEntry("Entry" + y + ".txt", opener, closer);
}
zip.Comment = "Produced at " + System.DateTime.UtcNow.ToString("G");
zip.Save(zipFileToCreate);
}
_txrx.Send("pb 0 step");
}
for (int i = 0; i < ms.Length; i++)
{
ms[i].Dispose();
ms[i] = null;
}
ms = null;
}
[TestMethod]
public void ZipOutputStream_Parallel()
{
int _sizeBase = 1024 * 1024;
int _sizeRange = 256 * 1024;
//int _sizeBase = 1024 * 256;
//int _sizeRange = 256 * 12;
var sw = new System.Diagnostics.Stopwatch();
byte[] buffer = new byte[0x8000];
int n = 0;
TimeSpan[] ts = new TimeSpan[2];
int nFiles = _rnd.Next(8) + 8;
//int nFiles = 2;
string[] filenames = new string[nFiles];
string dirToZip = Path.Combine(TopLevelDir, "dirToZip");
string channel = String.Format("ZOS_Parallel{0:000}", _rnd.Next(1000));
string txrxLabel = "ZipOutputStream Parallel";
_txrx = TestUtilities.StartProgressMonitor(channel, txrxLabel, "starting up...");
TestContext.WriteLine("Creating {0} fodder files...", nFiles);
Directory.CreateDirectory(dirToZip);
_txrx.Send(String.Format("pb 0 max {0}", nFiles));
_txrx.Send("pb 0 value 0");
sw.Start();
for (int x = 0; x < nFiles; x++)
{
string status = String.Format("status Creating file {0}/{1}", x + 1, nFiles);
_txrx.Send(status);
filenames[x] = Path.Combine(dirToZip, String.Format("file{0:000}.txt", x));
using (var output = File.Create(filenames[x]))
{
using (Stream input = new Ionic.Zip.Tests.Utilities.RandomTextInputStream(_sizeBase + _rnd.Next(_sizeRange)))
{
while ((n = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, n);
}
}
}
_txrx.Send("pb 0 step");
}
sw.Stop();
TestContext.WriteLine("file generation took {0}", sw.Elapsed);
_txrx.Send(String.Format("pb 0 max {0}", crypto.Length));
_txrx.Send("pb 0 value 0");
for (int i = 0; i < crypto.Length; i++)
{
//int c = i;
int c = (i + 2) % crypto.Length;
_txrx.Send(String.Format("pb 1 max {0}", compLevels.Length));
_txrx.Send("pb 1 value 0");
for (int j = 0; j < compLevels.Length; j++)
{
string password = Path.GetRandomFileName();
// I wanna do 2 cycles if there is compression, so I can compare MT
// vs 1T compression. The first cycle will ALWAYS use the threaded
// compression, the 2nd will NEVER use it. If
// CompressionLevel==None, then just do one cycle.
//
int kCycles = (compLevels[j] == Ionic.Zlib.CompressionLevel.None)
? 1
: 2;
for (int k = 0; k < kCycles; k++)
{
// Also, I use Stopwatch to time the compression, and compare.
// In light of that, I wanna do one warmup, and then one timed
// trial (for t==0..2). But here again, if CompressionLevel==None, then I
// don't want to do a timing comparison, so I don't need 2 trials.
// Therefore, in that case, the "warmup" is the only trial I want to do.
// So when k==1 and Compression==None, do no cycles at all.
//
int tCycles = (compLevels[j] == Ionic.Zlib.CompressionLevel.None)
? ((k == 0) ? 1 : 0)
: 2;
if (k == 0)
{
_txrx.Send(String.Format("pb 2 max {0}", kCycles * tCycles));
_txrx.Send("pb 2 value 0");
}
for (int t = 0; t < tCycles; t++)
{
TestContext.WriteLine(new String('-', 72));
string zipFileToCreate = String.Format("ZipOutputStream_Parallel.E-{0}.C-{1}.{2}.{3}timed.zip",
crypto[c].ToString(), compLevels[j].ToString(),
(compLevels[j] == Ionic.Zlib.CompressionLevel.None)
? "NA"
: (k == 0) ? "1T" : "MT",
(t == 0) ? "not-" : "");
TestContext.WriteLine("Trial {0}.{1}.{2}.{3}", i, j, k, t);
TestContext.WriteLine("Create zip file {0}", zipFileToCreate);
_txrx.Send("status " + zipFileToCreate);
sw.Reset();
sw.Start();
using (var output = new ZipOutputStream(zipFileToCreate))
{
if (k == 0)
output.ParallelDeflateThreshold = -1L; // never
else
output.ParallelDeflateThreshold = 0L; // always
output.Password = password;
output.Encryption = crypto[c]; // maybe "None"
output.CompressionLevel = compLevels[j];
_txrx.Send(String.Format("pb 3 max {0}", nFiles));
_txrx.Send("pb 3 value 0");
for (int x = 0; x < nFiles; x++)
{
output.PutNextEntry(Path.GetFileName(filenames[x]));
using (var input = File.OpenRead(filenames[x]))
{
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, n);
}
}
_txrx.Send("pb 3 step");
}
}
sw.Stop();
ts[k] = sw.Elapsed;
TestContext.WriteLine("compression took {0}", ts[k]);
//if (t==0)
BasicVerifyZip(zipFileToCreate, password);
Assert.AreEqual(nFiles, TestUtilities.CountEntries(zipFileToCreate),
"Trial ({0}.{1}.{2}.{3}): The zip file created has the wrong number of entries.", i, j, k, t);
_txrx.Send("pb 2 step");
}
}
#if NOT_DEBUGGING
// parallel is not always faster!
if (_sizeBase > 256 * 1024 &&
compLevels[j] != Ionic.Zlib.CompressionLevel.None &&
compLevels[j] != Ionic.Zlib.CompressionLevel.BestSpeed &&
crypto[c] != EncryptionAlgorithm.WinZipAes256 &&
crypto[c] != EncryptionAlgorithm.WinZipAes128 )
Assert.IsTrue(ts[0]>ts[1], "Whoops! Cycle {0}.{1} (crypto({4}) Comp({5})): Parallel deflate is slower ({2}<{3})",
i, j, ts[0], ts[1],
crypto[c],
compLevels[j]);
#endif
_txrx.Send("pb 1 step");
}
_txrx.Send("pb 0 step");
}
_txrx.Send("stop");
}
[TestMethod]
public void Streams_7z_Zip_ZeroLength()
{
_Internal_Streams_7z_Zip(0, "zero");
}
[TestMethod]
public void Streams_7z_Zip()
{
_Internal_Streams_7z_Zip(1, "nonzero");
}
[TestMethod]
public void Streams_7z_Zip_Mixed()
{
_Internal_Streams_7z_Zip(2, "mixed");
}
[TestMethod]
public void Streams_Winzip_Zip_Mixed_Password()
{
string password = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
_Internal_Streams_WinZip_Zip(2, password, "mixed");
}
[TestMethod]
public void Streams_Winzip_Zip()
{
_Internal_Streams_WinZip_Zip(1, null, "nonzero");
}
private string CreateZeroLengthFile(int ix, string directory)
{
string nameOfFileToCreate = Path.Combine(directory, String.Format("ZeroLength{0:D4}.txt", ix));
using (var fs = File.Create(nameOfFileToCreate)) { }
return nameOfFileToCreate;
}
public void _Internal_Streams_7z_Zip(int flavor, string label)
{
if (!SevenZipIsPresent)
{
TestContext.WriteLine("skipping test [_Internal_Streams_7z_Zip] : SevenZip is not present");
return;
}
int[] fileCounts = { 1, 2, _rnd.Next(8) + 6, _rnd.Next(18) + 16, _rnd.Next(48) + 56 };
for (int m = 0; m < fileCounts.Length; m++)
{
string dirToZip = String.Format("trial{0:D2}", m);
if (!Directory.Exists(dirToZip)) Directory.CreateDirectory(dirToZip);
int fileCount = fileCounts[m];
string zipFileToCreate = Path.Combine(TopLevelDir,
String.Format("Streams_7z_Zip.{0}.{1}.{2}.zip", flavor, label, m));
string[] files = null;
if (flavor == 0)
{
// zero length files
files = new string[fileCount];
for (int i = 0; i < fileCount; i++)
files[i] = CreateZeroLengthFile(i, dirToZip);
}
else if (flavor == 1)
files = TestUtilities.GenerateFilesFlat(dirToZip, fileCount, 100, 72000);
else
{
// mixed
files = new string[fileCount];
for (int i = 0; i < fileCount; i++)
{
if (_rnd.Next(3) == 0)
files[i] = CreateZeroLengthFile(i, dirToZip);
else
{
files[i] = Path.Combine(dirToZip, String.Format("nonzero{0:D4}.txt", i));
TestUtilities.CreateAndFillFileText(files[i], _rnd.Next(60000) + 100);
}
}
}
// Create the zip archive via 7z.exe
this.Exec(sevenZip, String.Format("a {0} {1}", zipFileToCreate, dirToZip));
// Verify the number of files in the zip
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), files.Length,
"Incorrect number of entries in the zip file.");
// extract the files
string extractDir = String.Format("extract{0:D2}", m);
byte[] buffer = new byte[2048];
int n;
using (var raw = File.OpenRead(zipFileToCreate))
{
using (var input = new ZipInputStream(raw))
{
ZipEntry e;
while ((e = input.GetNextEntry()) != null)
{
TestContext.WriteLine("entry: {0}", e.FileName);
string outputPath = Path.Combine(extractDir, e.FileName);
if (e.IsDirectory)
{
// create the directory
Directory.CreateDirectory(outputPath);
}
else
{
// create the file
using (var output = File.Create(outputPath))
{
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, n);
}
}
}
// we don't set the timestamps or attributes
// on the file/directory.
}
}
}
// winzip does not include the base path in the filename;
// 7zip does.
string[] filesUnzipped = Directory.GetFiles(Path.Combine(extractDir, dirToZip));
// Verify the number of files extracted
Assert.AreEqual(files.Length, filesUnzipped.Length,
"Incorrect number of files extracted.");
}
}
public void _Internal_Streams_WinZip_Zip(int fodderOption, string password, string label)
{
if (!WinZipIsPresent)
throw new Exception("skipping test [_Internal_Streams_WinZip_Zip] : winzip is not present");
int[] fileCounts = { 1, 2, _rnd.Next(8) + 6, _rnd.Next(18) + 16, _rnd.Next(48) + 56 };
for (int m = 0; m < fileCounts.Length; m++)
{
string dirToZip = String.Format("trial{0:D2}", m);
if (!Directory.Exists(dirToZip)) Directory.CreateDirectory(dirToZip);
int fileCount = fileCounts[m];
string zipFileToCreate = Path.Combine(TopLevelDir,
String.Format("Streams_Winzip_Zip.{0}.{1}.{2}.zip", fodderOption, label, m));
string[] files = null;
if (fodderOption == 0)
{
// zero length files
files = new string[fileCount];
for (int i = 0; i < fileCount; i++)
files[i] = CreateZeroLengthFile(i, dirToZip);
}
else if (fodderOption == 1)
files = TestUtilities.GenerateFilesFlat(dirToZip, fileCount, 100, 72000);
else
{
// mixed
files = new string[fileCount];
for (int i = 0; i < fileCount; i++)
{
if (_rnd.Next(3) == 0)
files[i] = CreateZeroLengthFile(i, dirToZip);
else
{
files[i] = Path.Combine(dirToZip, String.Format("nonzero{0:D4}.txt", i));
TestUtilities.CreateAndFillFileText(files[i], _rnd.Next(60000) + 100);
}
}
}
// Create the zip archive via WinZip.exe
string pwdOption = String.IsNullOrEmpty(password) ? "" : "-s" + password;
string formatString = "-a -p {0} -yx {1} {2}\\*.*";
string wzzipOut = this.Exec(wzzip, String.Format(formatString, pwdOption, zipFileToCreate, dirToZip));
// Verify the number of files in the zip
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), files.Length,
"Incorrect number of entries in the zip file.");
// extract the files
string extractDir = String.Format("extract{0:D2}", m);
Directory.CreateDirectory(extractDir);
byte[] buffer = new byte[2048];
int n;
using (var raw = File.OpenRead(zipFileToCreate))
{
using (var input = new ZipInputStream(raw))
{
input.Password = password;
ZipEntry e;
while ((e = input.GetNextEntry()) != null)
{
TestContext.WriteLine("entry: {0}", e.FileName);
string outputPath = Path.Combine(extractDir, e.FileName);
if (e.IsDirectory)
{
// create the directory
Directory.CreateDirectory(outputPath);
continue;
}
// create the file
using (var output = File.Create(outputPath))
{
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, n);
}
}
// we don't set the timestamps or attributes
// on the file/directory.
}
}
}
string[] filesUnzipped = Directory.GetFiles(extractDir);
// Verify the number of files extracted
Assert.AreEqual(files.Length, filesUnzipped.Length,
"Incorrect number of files extracted.");
}
}
[TestMethod]
public void ZIS_Crypto_zero()
{
_Internal_Streams_ZipInput_Encryption(0);
}
[TestMethod]
public void ZIS_Crypto_zero_subdir()
{
_Internal_Streams_ZipInput_Encryption(3);
}
[TestMethod]
public void ZIS_Crypto_nonzero()
{
_Internal_Streams_ZipInput_Encryption(1);
}
[TestMethod]
public void ZIS_Crypto_nonzero_subdir()
{
_Internal_Streams_ZipInput_Encryption(4);
}
[TestMethod]
public void ZIS_Crypto_mixed()
{
_Internal_Streams_ZipInput_Encryption(2);
}
[TestMethod]
public void ZIS_Crypto_mixed_subdir()
{
_Internal_Streams_ZipInput_Encryption(5);
}
[TestMethod]
public void ZIS_Crypto_zero_file()
{
_Internal_Streams_ZipInput_Encryption(0, 1);
}
[TestMethod]
public void ZIS_Crypto_zero_subdir_file()
{
_Internal_Streams_ZipInput_Encryption(3, 1);
}
[TestMethod]
public void ZIS_Crypto_nonzero_file()
{
_Internal_Streams_ZipInput_Encryption(1, 1);
}
[TestMethod]
public void ZIS_Crypto_nonzero_subdir_file()
{
_Internal_Streams_ZipInput_Encryption(4, 1);
}
[TestMethod]
public void ZIS_Crypto_mixed_file()
{
_Internal_Streams_ZipInput_Encryption(2, 1);
}
[TestMethod]
public void ZIS_Crypto_mixed_subdir_file()
{
_Internal_Streams_ZipInput_Encryption(5, 1);
}
public void _Internal_Streams_ZipInput_Encryption(int fodderOption)
{
_Internal_Streams_ZipInput_Encryption(fodderOption, 0);
}
public void _Internal_Streams_ZipInput_Encryption(int fodderOption, int fileReadOption)
{
byte[] buffer = new byte[2048];
int n;
int[] fileCounts = { 1,
2,
_rnd.Next(8) + 6,
_rnd.Next(18) + 16,
_rnd.Next(48) + 56 };
for (int m = 0; m < fileCounts.Length; m++)
{
string password = TestUtilities.GenerateRandomPassword();
string dirToZip = String.Format("trial{0:D2}", m);
if (!Directory.Exists(dirToZip)) Directory.CreateDirectory(dirToZip);
int fileCount = fileCounts[m];
TestContext.WriteLine("=====");
TestContext.WriteLine("Trial {0} filecount={1}", m, fileCount);
var files = (new Func( () => {
if (fodderOption == 0)
{
// zero length files
var a = new string[fileCount];
for (int i = 0; i < fileCount; i++)
a[i] = CreateZeroLengthFile(i, dirToZip);
return a;
}
if (fodderOption == 1)
return TestUtilities.GenerateFilesFlat(dirToZip, fileCount, 100, 72000);
// mixed = some zero and some not
var b = new string[fileCount];
for (int i = 0; i < fileCount; i++)
{
if (_rnd.Next(3) == 0)
b[i] = CreateZeroLengthFile(i, dirToZip);
else
{
b[i] = Path.Combine(dirToZip, String.Format("nonzero{0:D4}.txt", i));
TestUtilities.CreateAndFillFileText(b[i], _rnd.Next(60000) + 100);
}
}
return b;
}))();
for (int i = 0; i < crypto.Length; i++)
{
EncryptionAlgorithm c = crypto[i];
string zipFileToCreate =
Path.Combine(TopLevelDir,
String.Format("ZIS_Crypto.{0}.count.{1:D2}.{2}.zip",
c.ToString(), fileCounts[m], fodderOption));
// Create the zip archive
using (var zip = new ZipFile())
{
zip.Password = password;
zip.Encryption = c;
if (fodderOption > 2)
{
zip.AddDirectoryByName("subdir");
zip.AddDirectory(dirToZip, "subdir");
}
else
zip.AddDirectory(dirToZip);
zip.Save(zipFileToCreate);
}
// Verify the number of files in the zip
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), files.Length,
"Incorrect number of entries in the zip file.");
// extract the files
string extractDir = String.Format("extract{0:D2}.{1:D2}", m, i);
TestContext.WriteLine("Extract to: {0}", extractDir);
Directory.CreateDirectory(extractDir);
var input = (new Func( () => {
if (fileReadOption == 0)
{
var raw = File.OpenRead(zipFileToCreate);
return new ZipInputStream(raw);
}
return new ZipInputStream(zipFileToCreate);
}))();
using (input)
{
// set password if necessary
if (crypto[i] != EncryptionAlgorithm.None)
input.Password = password;
ZipEntry e;
while ((e = input.GetNextEntry()) != null)
{
TestContext.WriteLine("entry: {0}", e.FileName);
string outputPath = Path.Combine(extractDir, e.FileName);
if (e.IsDirectory)
{
// create the directory
Directory.CreateDirectory(outputPath);
}
else
{
// emit the file
using (var output = File.Create(outputPath))
{
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, n);
}
}
}
}
}
string[] filesUnzipped = (fodderOption > 2)
? Directory.GetFiles(Path.Combine(extractDir, "subdir"))
: Directory.GetFiles(extractDir);
// Verify the number of files extracted
Assert.AreEqual(files.Length, filesUnzipped.Length,
"Incorrect number of files extracted. ({0}!={1})", files.Length, filesUnzipped.Length);
}
}
}
[TestMethod]
public void ASPNET_GenerateZip()
{
string testBin = TestUtilities.GetTestBinDir(CurrentDir);
string resourceDir = Path.Combine(testBin, "Resources");
string aspnetHost = Path.Combine(resourceDir, "AspNetHost.exe");
Assert.IsTrue(File.Exists(aspnetHost), "file {0} does not exit.", aspnetHost);
string aspnetHostPdb = Path.Combine(resourceDir, "AspNetHost.pdb");
// page that generates a zip file.
string aspxPage = Path.Combine(resourceDir, "GenerateZip-cs.aspx");
Assert.IsTrue(File.Exists(aspxPage));
string ionicZipDll = Path.Combine(testBin, "Ionic.Zip.dll");
string loremFile = "LoremIpsum.txt";
Action copyToBin = (x) =>
File.Copy(x, Path.Combine("bin",
Path.GetFileName(x)));
Directory.CreateDirectory("bin");
copyToBin(aspnetHost);
copyToBin(aspnetHostPdb);
copyToBin(ionicZipDll);
File.Copy(aspxPage, Path.GetFileName(aspxPage));
File.WriteAllText(loremFile, TestUtilities.LoremIpsum);
string zipFileToCreate = "ASPX-output.out";
string binAspNetHostExe = Path.Combine("bin",
Path.GetFileName(aspnetHost));
string urlRequest = Path.GetFileName(aspxPage) + "?file=LoremIpsum.txt";
int rc = this.ExecRedirectStdOut(binAspNetHostExe,
urlRequest,
zipFileToCreate);
Assert.AreEqual(rc, 0, "Non-zero RC: ({0})", rc);
int nEntries = TestUtilities.CountEntries(zipFileToCreate);
Assert.AreEqual(nEntries,
2, "wrong number of entries ({0})", nEntries);
string extractDir = "extract";
// read/extract the generated zip
using (var zip = ZipFile.Read(zipFileToCreate))
{
foreach (var e in zip)
{
e.Extract(extractDir);
}
}
// compare checksums
var chk1 = TestUtilities.ComputeChecksum(loremFile);
var chk2 = TestUtilities.ComputeChecksum(Path.Combine(extractDir,loremFile));
string s1 = TestUtilities.CheckSumToString(chk1);
string s2 = TestUtilities.CheckSumToString(chk2);
Assert.AreEqual(s1, s2, "Unexpected checksum on extracted file.");
}
void CopyStream(Stream source, Stream dest)
{
int n;
var buf = new byte[2048];
while ((n= source.Read(buf, 0, buf.Length)) > 0)
{
dest.Write(buf,0,n);
}
}
[TestMethod]
public void ZIS_ZOS_VaryCompression()
{
string testBin = TestUtilities.GetTestBinDir(CurrentDir);
string resourceDir = Path.Combine(testBin, "Resources");
var filesToAdd = Directory.GetFiles(resourceDir);
Func chooseCompression = (ix, cycle) => {
var name = Path.GetFileName(filesToAdd[ix]);
switch (cycle)
{
case 0:
return !(name.EndsWith(".zip") ||
name.EndsWith(".docx") ||
name.EndsWith(".xslx"));
case 1:
return ((ix%2)==0);
default:
return (ix == filesToAdd.Length - 1);
}
};
// Three cycles - three different ways to vary compression
for (int k=0; k < 3; k++)
{
string zipFileToCreate = String.Format("VaryCompression-{0}.zip", k);
TestContext.WriteLine("");
TestContext.WriteLine("Creating zip, cycle {0}", k);
using (var fileStream = File.OpenWrite(zipFileToCreate))
{
using (var zos = new ZipOutputStream(fileStream, true))
{
for (int i=0; i < filesToAdd.Length; i++)
{
var file = filesToAdd[i];
var shortName = Path.GetFileName(file);
bool compress = chooseCompression(i, k);
if (compress)
zos.CompressionLevel = Ionic.Zlib.CompressionLevel.Default;
else
zos.CompressionLevel = Ionic.Zlib.CompressionLevel.None;
zos.PutNextEntry(shortName);
using (var input = File.OpenRead(file))
{
CopyStream(input, zos);
}
}
}
}
TestContext.WriteLine("");
TestContext.WriteLine("Extracting cycle {0}", k);
string extractDir = "extract-" + k;
Directory.CreateDirectory(extractDir);
using (var raw = File.OpenRead(zipFileToCreate))
{
using (var input = new ZipInputStream(raw))
{
ZipEntry e;
while ((e = input.GetNextEntry()) != null)
{
TestContext.WriteLine("entry: {0}", e.FileName);
string outputPath = Path.Combine(extractDir, e.FileName);
if (e.IsDirectory)
{
// create the directory
Directory.CreateDirectory(outputPath);
}
else
{
// create the file
using (var output = File.Create(outputPath))
{
CopyStream(input,output);
}
}
}
}
}
string[] filesUnzipped = Directory.GetFiles(extractDir);
Assert.AreEqual(filesToAdd.Length, filesUnzipped.Length,
"Incorrect number of files extracted.");
}
}
}
}