// UnicodeTests.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2008-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-06 19:29:37>
//
// ------------------------------------------------------------------
//
// This module defines the tests for the Unicode features in DotNetZip.
//
// ------------------------------------------------------------------
using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ionic.Zip;
using Ionic.Zip.Tests.Utilities;
using System.IO;
namespace Ionic.Zip.Tests.Unicode
{
///
/// Summary description for UnicodeTests
///
[TestClass]
public class UnicodeTests : IonicTestClass
{
public UnicodeTests() : base() { }
[TestMethod]
public void Create_UnicodeEntries()
{
int i;
string origComment = "This is a Unicode comment. "+
"Chinese: 弹 出 应 用 程 序 "+
"Norwegian/Danish: æøåÆØÅ. "+
"Portugese: Configurações.";
string[] formats = {
"弹出应用程序{0:D3}.bin",
"n.æøåÆØÅ{0:D3}.bin",
"Configurações-弹出-ÆØÅ-xx{0:D3}.bin"
};
for (int k = 0; k < formats.Length; k++)
{
// create the subdirectory
string subdir = Path.Combine(TopLevelDir, "files" + k);
Directory.CreateDirectory(subdir);
// create a bunch of files
int numFilesToCreate = _rnd.Next(18) + 14;
string[] filesToZip = new string[numFilesToCreate];
for (i = 0; i < numFilesToCreate; i++)
{
filesToZip[i] = Path.Combine(subdir, String.Format(formats[k], i));
TestUtilities.CreateAndFillFileBinary(filesToZip[i], _rnd.Next(5000) + 2000);
}
// create a zipfile twice, once using Unicode, once without
for (int j = 0; j < 2; j++)
{
// select the name of the zip file
string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Create_UnicodeEntries_{0}_{1}.zip", k, j));
Assert.IsFalse(File.Exists(zipFileToCreate), "The zip file '{0}' already exists.", zipFileToCreate);
TestContext.WriteLine("\n\nFormat {0}, trial {1}. filename: {2}...", k, j, zipFileToCreate);
string dirInArchive = String.Format("{0}-{1}", Path.GetFileName(subdir), j);
using (ZipFile zip1 = new ZipFile())
{
#pragma warning disable 618
zip1.UseUnicodeAsNecessary = (j == 0);
#pragma warning restore 618
for (i = 0; i < filesToZip.Length; i++)
{
// use the local filename (not fully qualified)
ZipEntry e = zip1.AddFile(filesToZip[i], dirInArchive);
e.Comment = String.Format("This entry encoded with {0}", (j == 0) ? "unicode" : "the default code page.");
}
zip1.Comment = origComment;
zip1.Save(zipFileToCreate);
}
// Verify the number of files in the zip
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), filesToZip.Length,
"Incorrect number of entries in the zip file.");
i = 0;
// verify the filenames are (or are not) unicode
var options = new ReadOptions {
Encoding = (j == 0) ? System.Text.Encoding.UTF8 : ZipFile.DefaultEncoding
};
using (ZipFile zip2 = ZipFile.Read(zipFileToCreate, options))
{
foreach (ZipEntry e in zip2)
{
string fname = String.Format(formats[k], i);
if (j == 0)
{
Assert.AreEqual(fname, Path.GetFileName(e.FileName));
}
else
{
Assert.AreNotEqual(fname, Path.GetFileName(e.FileName));
}
i++;
}
// according to the spec,
// unicode is not supported on the zip archive comment!
// But this library won't enforce that.
// We will leave it up to the application.
// Assert.AreNotEqual(origComment, zip2.Comment);
}
}
}
}
string[] miscNameFormats = {
"file{0:D3}.bin", // keep this at index==0
"弹出应用程序{0:D3}.bin", // Chinese
"codeplexの更新RSSを見てふと書いた投稿だったけど日本語情報がないかは調{0:D3}.bin", // Japanese
"n.æøåÆØÅ{0:D3}.bin", // greek
"Configurações-弹出-ÆØÅ-xx{0:D3}.bin", // portugese + Chinese
"¡¢£ ¥â° €Ãƒ †œ Ñ añoAbba{0:D3.bin}", //??
"А Б В Г Д Є Ж Ѕ З И І К Л М Н О П Р С Т Ф Х Ц Ч Ш Щ Ъ ЪІ Ь Ю ІА {0:D3}.b", // Russian
"Ελληνικό αλφάβητο {0:D3}.b",
"א ב ג ד ה ו ז ח ט י " + "{0:D3}", // I don't know what language this is
};
private List _CreateUnicodeFiles()
{
// create the subdirectory
string subdir = Path.Combine(TopLevelDir, "files");
Directory.CreateDirectory(subdir);
var filesToZip = new List();
// create a bunch of files in that subdir
int numFilesToCreate = _rnd.Next(18) + 14;
for (int i = 0; i < numFilesToCreate; i++)
{
int k = i % miscNameFormats.Length;
var f = Path.Combine(subdir, String.Format(miscNameFormats[k], i));
filesToZip.Add(f);
TestUtilities.CreateAndFillFileBinary(f, _rnd.Next(5000) + 2000);
}
return filesToZip;
}
[TestMethod]
public void Create_UnicodeEntries_Mixed()
{
var filesToZip = _CreateUnicodeFiles();
// Using those files create a zipfile 4 times:
// cycle 0 - UseUnicodeAsNecessary
// cycle 1 - Nothing
// cycle 2 - AlternateEncoding = UTF8, AlternateEncodingUsage = Always
// cycle 3 - AlternateEncoding = UTF8, AlternateEncodingUsage = AsNecessary
for (int j = 0; j < 4; j++)
{
string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("Archive-{0}.zip", j));
Assert.IsFalse(File.Exists(zipFileToCreate), "The file already exists ({0}).", zipFileToCreate);
using (ZipFile zip1 = new ZipFile(zipFileToCreate))
{
switch (j)
{
#pragma warning disable 618
case 0:
zip1.UseUnicodeAsNecessary = (j == 0);
break;
#pragma warning restore 618
case 1:
// do nothing
break;
case 2:
zip1.AlternateEncoding = System.Text.Encoding.UTF8;
zip1.AlternateEncodingUsage = ZipOption.Always;
break;
case 3:
zip1.AlternateEncoding = System.Text.Encoding.UTF8;
zip1.AlternateEncodingUsage = ZipOption.AsNecessary;
break;
}
foreach (var fileToZip in filesToZip)
{
zip1.AddFile(fileToZip, "");
}
zip1.Save();
}
// Verify the number of files in the zip
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), filesToZip.Count,
"Incorrect number of entries in the zip file.");
_CheckUnicodeZip(zipFileToCreate, j);
}
}
[TestMethod]
public void Unicode_Create_ZOS_wi12634()
{
TestContext.WriteLine("==Unicode_Create_ZOS_wi12634()=");
var filesToZip = _CreateUnicodeFiles();
byte[] buffer = new byte[2048];
int n;
// using those files create a zipfile twice. First cycle uses Unicode,
// 2nd cycle does not.
for (int j = 0; j < 2; j++)
{
// select the name of the zip file
var bpath = String.Format("wi12634-{0}.zip", j);
string zipFileToCreate = Path.Combine(TopLevelDir, bpath);
TestContext.WriteLine("========");
TestContext.WriteLine("Trial {0}", j);
Assert.IsFalse(File.Exists(zipFileToCreate),
"The zip file '{0}' already exists.",
zipFileToCreate);
TestContext.WriteLine("file {0}", zipFileToCreate);
int excCount = 0;
// create using ZOS
using (var ofs = File.Open(zipFileToCreate, FileMode.Create, FileAccess.ReadWrite))
{
using (var zos = new ZipOutputStream(ofs))
{
#pragma warning disable 618
if (j == 0)
zos.ProvisionalAlternateEncoding = System.Text.Encoding.UTF8;
#pragma warning restore 618
try
{
foreach (var fileToZip in filesToZip)
{
var ename = Path.GetFileName(fileToZip);
TestContext.WriteLine("adding entry '{0}'", ename);
zos.PutNextEntry(ename); // with no path
using (var ifs = File.OpenRead(fileToZip))
{
while ((n = ifs.Read(buffer, 0, buffer.Length)) > 0)
{
zos.Write(buffer, 0, n);
}
}
}
}
catch (System.Exception exc1)
{
TestContext.WriteLine("Exception #{0}", excCount);
TestContext.WriteLine("{0}", exc1.ToString());
excCount++;
}
}
}
Assert.IsTrue(excCount==0,
"Exceptions occurred during zip creation.");
// Verify the number of files in the zip
Assert.AreEqual(TestUtilities.CountEntries(zipFileToCreate), filesToZip.Count,
"Incorrect number of entries in the zip file.");
_CheckUnicodeZip(zipFileToCreate, j);
TestContext.WriteLine("Trial {0} file checks ok", j);
}
}
[TestMethod]
public void UnicodeComment_wi10392()
{
const string zipFileToCreate = "UnicodeComment_wi10392.zip";
const string cyrillicComment = "Hello, Привет";
TestContext.WriteLine("{0}", zipFileToCreate);
TestContext.WriteLine("==== creating zip");
using (ZipFile zip1 = new ZipFile(zipFileToCreate, Encoding.UTF8))
{
zip1.Comment = cyrillicComment;
zip1.AddEntry("entry", "this is the content of the added entry");
zip1.Save();
}
string comment2 = null;
TestContext.WriteLine("==== checking zip");
var options = new ReadOptions {
Encoding = Encoding.UTF8
};
using (ZipFile zip2 = ZipFile.Read(zipFileToCreate, options))
{
comment2 = zip2.Comment;
}
Assert.AreEqual(cyrillicComment, comment2,
"The comments are not equal.");
}
[TestMethod]
public void UnicodeUpdate_wi12744()
{
const string specialEntryName = "Привет.txt";
// two passes: one that uses the old "useUnicodeAsNecessary" property,
// and the second that uses the newer property.
for (int k=0; k < 2; k++)
{
string zipFileToCreate = String.Format("UnicodeUpdate_wi12744-{0}.zip", k);
TestContext.WriteLine("{0}", zipFileToCreate);
TestContext.WriteLine("==== creating zip, trial {0}", k);
using (ZipFile zip1 = new ZipFile())
{
if (k==0)
{
#pragma warning disable 618
zip1.UseUnicodeAsNecessary = true;
#pragma warning restore 618
}
else
{
zip1.AlternateEncoding = System.Text.Encoding.UTF8;
zip1.AlternateEncodingUsage = ZipOption.AsNecessary;
}
zip1.AddEntry(specialEntryName, "this is the content of the added entry");
zip1.Save(zipFileToCreate);
}
TestContext.WriteLine("==== create a directory with 2 addl files in it");
string subdir = Path.Combine(TopLevelDir, "files"+k);
Directory.CreateDirectory(subdir);
for (int i=0; i < 2; i++)
{
var filename = Path.Combine(subdir, "file" + i + ".txt");
TestUtilities.CreateAndFillFileText(filename, _rnd.Next(5000) + 2000);
}
TestContext.WriteLine("==== update the zip");
using (ZipFile zip2 = ZipFile.Read(zipFileToCreate))
{
zip2.AddDirectory(subdir);
zip2.Save();
}
TestContext.WriteLine("==== check the original file in the zip");
using (ZipFile zip3 = ZipFile.Read(zipFileToCreate))
{
var e = zip3[specialEntryName];
Assert.IsTrue(e!=null, "Entry not found");
Assert.IsTrue(e.FileName == specialEntryName, "name mismatch");
}
}
}
private void _CheckUnicodeZip(string filename, int j)
{
int i = 0;
// Verify that the filenames do, or do not, match the
// names that were added. They will match if unicode
// was used (j!=1) or if the filename used was the first
// in the formats list (k==0).
using (ZipFile zip2 = ZipFile.Read(filename))
{
foreach (ZipEntry e in zip2)
{
int k = i % miscNameFormats.Length;
string fname = String.Format(miscNameFormats[k], i);
if (j != 1 || k == 0)
{
Assert.AreEqual(fname, e.FileName, "cycle ({0},{1},{2})", i, j, k);
}
else
{
Assert.AreNotEqual(fname, e.FileName, "cycle ({0},{1},{2})", i, j, k);
}
i++;
}
}
}
struct CodepageTrial
{
public string codepage;
public string filenameFormat;
public bool exceptionExpected; // not all codepages will yield legal filenames for a given filenameFormat
public CodepageTrial(string cp, string format, bool except)
{
codepage = cp;
filenameFormat = format;
exceptionExpected = except;
}
}
[TestMethod]
public void Create_WithSpecifiedCodepage()
{
int i;
CodepageTrial[] trials = {
new CodepageTrial( "big5", "弹出应用程序{0:D3}.bin", true),
new CodepageTrial ("big5", "您好{0:D3}.bin", false),
new CodepageTrial ("gb2312", "弹出应用程序{0:D3}.bin", false),
new CodepageTrial ("gb2312", "您好{0:D3}.bin", false),
// insert other trials here.??
};
for (int k = 0; k < trials.Length; k++)
{
TestContext.WriteLine("");
TestContext.WriteLine("---------------------Trial {0}....", k);
TestContext.WriteLine("---------------------codepage: {0}....", trials[k].codepage);
// create the subdirectory
string subdir = Path.Combine(TopLevelDir, String.Format("trial{0}-files", k));
Directory.CreateDirectory(subdir);
// create a bunch of files
int numFiles = _rnd.Next(3) + 3;
string[] filesToZip = new string[numFiles];
for (i = 0; i < numFiles; i++)
{
filesToZip[i] = Path.Combine(subdir, String.Format(trials[k].filenameFormat, i));
TestUtilities.CreateAndFillFileBinary(filesToZip[i], _rnd.Next(5000) + 2000);
}
Directory.SetCurrentDirectory(subdir);
// three cases: one for old-style
// ProvisionalAlternateEncoding, one for "AsNecessary"
// and one for "Always"
for (int j=0; j < 3; j++)
{
// select the name of the zip file
string zipFileToCreate = Path.Combine(TopLevelDir, String.Format("WithSpecifiedCodepage_{0}_{1}_{2}.zip",
k, j, trials[k].codepage));
TestContext.WriteLine("");
TestContext.WriteLine("---------------Creating zip, trial ({0},{1})....", k, j);
using (ZipFile zip1 = new ZipFile(zipFileToCreate))
{
switch (j)
{
case 0:
#pragma warning disable 618
zip1.ProvisionalAlternateEncoding = System.Text.Encoding.GetEncoding(trials[k].codepage);
#pragma warning restore 618
break;
case 1:
zip1.AlternateEncoding = System.Text.Encoding.GetEncoding(trials[k].codepage);
zip1.AlternateEncodingUsage = ZipOption.AsNecessary;
break;
case 2:
zip1.AlternateEncoding = System.Text.Encoding.GetEncoding(trials[k].codepage);
zip1.AlternateEncodingUsage = ZipOption.Always;
break;
}
for (i = 0; i < filesToZip.Length; i++)
{
TestContext.WriteLine("adding entry {0}", filesToZip[i]);
// use the local filename (not fully qualified)
ZipEntry e = zip1.AddFile(filesToZip[i], "");
e.Comment = String.Format("This entry was encoded in the {0} codepage", trials[k].codepage);
}
zip1.Save();
}
TestContext.WriteLine("\n---------------------Extracting....");
Directory.SetCurrentDirectory(TopLevelDir);
try
{
// verify the filenames are (or are not) unicode
var options = new ReadOptions {
Encoding = System.Text.Encoding.GetEncoding(trials[k].codepage)
};
using (ZipFile zip2 = ZipFile.Read(zipFileToCreate, options))
{
foreach (ZipEntry e in zip2)
{
TestContext.WriteLine("found entry {0}", e.FileName);
e.Extract(String.Format("trial{0}-{1}-{2}-extract", k, j, trials[k].codepage));
}
}
}
catch (Exception e1)
{
if (trials[k].exceptionExpected)
TestContext.WriteLine("caught expected exception");
else
throw new System.Exception("while extracting", e1);
}
}
}
TestContext.WriteLine("\n---------------------Done.");
}
[TestMethod]
public void CodePage_UpdateZip_AlternateEncoding_wi10180()
{
System.Text.Encoding JIS = System.Text.Encoding.GetEncoding("shift_jis");
TestContext.WriteLine("The CP for JIS is: {0}", JIS.CodePage);
ReadOptions options = new ReadOptions { Encoding = JIS };
string[] filenames = {
"日本語.txt",
"日本語テスト.txt"
};
// three trials: one for old-style
// ProvisionalAlternateEncoding, one for "AsNecessary"
// and one for "Always"
for (int j=0; j < 3; j++)
{
string zipFileToCreate = String.Format("wi10180-{0}.zip", j);
// pass 1 - create it
TestContext.WriteLine("Create zip, cycle {0}...", j);
using (var zip = new ZipFile())
{
switch (j)
{
case 0:
#pragma warning disable 618
zip.ProvisionalAlternateEncoding = JIS;
#pragma warning restore 618
break;
case 1:
zip.AlternateEncoding = JIS;
zip.AlternateEncodingUsage = ZipOption.AsNecessary;
break;
case 2:
zip.AlternateEncoding = JIS;
zip.AlternateEncodingUsage = ZipOption.Always;
break;
}
zip.AddEntry(filenames[0], "This is the content for entry (" + filenames[0] + ")");
TestContext.WriteLine("adding file: {0}", filenames[0]);
zip.Save(zipFileToCreate);
}
// pass 2 - read and update it
TestContext.WriteLine("Update zip...");
using (var zip0 = ZipFile.Read(zipFileToCreate, options))
{
foreach (var e in zip0)
{
TestContext.WriteLine("existing entry name: {0} encoding: {1}",
e.FileName, e.AlternateEncoding.EncodingName );
Assert.AreEqual
(options.Encoding, e.AlternateEncoding);
}
zip0.AddEntry(filenames[1], "This is more content..." + System.DateTime.UtcNow.ToString("G"));
TestContext.WriteLine("adding file: {0}", filenames[1]);
zip0.Save();
}
// pass 3 - verify the filenames, again
TestContext.WriteLine("Verify zip...");
using (var zip0 = ZipFile.Read(zipFileToCreate, options))
{
foreach (string f in filenames)
{
Assert.AreEqual(f, zip0[f].FileName,
"The FileName was not expected, (cycle {0}) ", j);
}
}
}
}
[TestMethod]
public void Unicode_AddDirectoryByName_wi8984()
{
string format = "弹出应用程序{0:D3}.dir"; // Chinese characters
System.Text.Encoding UTF8 = System.Text.Encoding.GetEncoding("UTF-8");
TestContext.WriteLine("== WorkItem 8984");
// three trials: one for old-style
// ProvisionalAlternateEncoding, one for "AsNecessary"
// and one for "Always"
for (int j=0; j < 3; j++)
{
TestContext.WriteLine("Trial {0}", j);
for (int n = 1; n <= 10; n++)
{
TestContext.WriteLine("nEntries {0}", n);
var dirsAdded = new System.Collections.Generic.List();
var zipFileToCreate = String.Format("wi8984-{0}-{1:N2}.zip", j, n);
using (ZipFile zip1 = new ZipFile(zipFileToCreate))
{
switch (j)
{
case 0:
#pragma warning disable 618
zip1.UseUnicodeAsNecessary = true;
#pragma warning restore 618
break;
case 1:
zip1.AlternateEncoding = UTF8;
zip1.AlternateEncodingUsage = ZipOption.AsNecessary;
break;
case 2:
zip1.AlternateEncoding = UTF8;
zip1.AlternateEncodingUsage = ZipOption.Always;
break;
}
for (int i = 0; i < n; i++)
{
// create an arbitrary directory name, add it to the zip archive
string dirName = String.Format(format, i);
zip1.AddDirectoryByName(dirName);
dirsAdded.Add(dirName + "/");
}
zip1.Save();
}
string extractDir = String.Format("extract-{0}-{1:D3}", j, n);
int dirCount = 0;
using (ZipFile zip2 = ZipFile.Read(zipFileToCreate))
{
foreach (var e in zip2)
{
TestContext.WriteLine("dir: {0}", e.FileName);
Assert.IsTrue(dirsAdded.Contains(e.FileName), "Cannot find the expected entry ({0})", e.FileName);
Assert.IsTrue(e.IsDirectory);
e.Extract(extractDir);
dirCount++;
}
}
Assert.AreEqual(n, dirCount);
TestContext.WriteLine("");
}
TestContext.WriteLine("");
}
}
}
}