public void Progress_ReadFile()
        {
            Directory.SetCurrentDirectory(TopLevelDir);
            string  zipFileToCreate = Path.Combine(TopLevelDir, "Progress_ReadFile.zip");
            string dirToZip = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());

            var files = TestUtilities.GenerateFilesFlat(dirToZip);

            using (ZipFile zip = new ZipFile())
            {
                zip.AddFiles(files);
                zip.Save(zipFileToCreate);
            }

            int count = TestUtilities.CountEntries(zipFileToCreate);
            Assert.IsTrue(count>0);

            var options = new ReadOptions {
                    StatusMessageWriter = new StringWriter(),
                    ReadProgress = ReadProgress1
            };
            using (ZipFile zip = ZipFile.Read(zipFileToCreate, options))
            {
                // this should be fine
                zip.RemoveEntry(zip[1]);
                zip.Save();
            }
            TestContext.WriteLine(options.StatusMessageWriter.ToString());
            Assert.AreEqual<Int32>(count, TestUtilities.CountEntries(zipFileToCreate)+1);
        }
 /// <summary>
 ///   Reads a zip file archive from the named filesystem file using the
 ///   specified options.
 /// </summary>
 ///
 /// <remarks>
 /// <para>
 ///   This version of the <c>Read()</c> method allows the caller to pass
 ///   in a <c>TextWriter</c> an <c>Encoding</c>, via an instance of the
 ///   <c>ReadOptions</c> class.  The <c>ZipFile</c> is read in using the
 ///   specified encoding for entries where UTF-8 encoding is not
 ///   explicitly specified.
 /// </para>
 /// </remarks>
 ///
 /// <example>
 ///
 /// <para>
 ///   This example shows how to read a zip file using the Big-5 Chinese
 ///   code page (950), and extract each entry in the zip file, while
 ///   sending status messages out to the Console.
 /// </para>
 ///
 /// <para>
 ///   For this code to work as intended, the zipfile must have been
 ///   created using the big5 code page (CP950). This is typical, for
 ///   example, when using WinRar on a machine with CP950 set as the
 ///   default code page.  In that case, the names of entries within the
 ///   Zip archive will be stored in that code page, and reading the zip
 ///   archive must be done using that code page.  If the application did
 ///   not use the correct code page in ZipFile.Read(), then names of
 ///   entries within the zip archive would not be correctly retrieved.
 /// </para>
 ///
 /// <code lang="C#">
 /// string zipToExtract = "MyArchive.zip";
 /// string extractDirectory = "extract";
 /// var options = new ReadOptions
 /// {
 ///   StatusMessageWriter = System.Console.Out,
 ///   Encoding = System.Text.Encoding.GetEncoding(950)
 /// };
 /// using (ZipFile zip = ZipFile.Read(zipToExtract, options))
 /// {
 ///   foreach (ZipEntry e in zip)
 ///   {
 ///      e.Extract(extractDirectory);
 ///   }
 /// }
 /// </code>
 ///
 ///
 /// <code lang="VB">
 /// Dim zipToExtract as String = "MyArchive.zip"
 /// Dim extractDirectory as String = "extract"
 /// Dim options as New ReadOptions
 /// options.Encoding = System.Text.Encoding.GetEncoding(950)
 /// options.StatusMessageWriter = System.Console.Out
 /// Using zip As ZipFile = ZipFile.Read(zipToExtract, options)
 ///     Dim e As ZipEntry
 ///     For Each e In zip
 ///      e.Extract(extractDirectory)
 ///     Next
 /// End Using
 /// </code>
 /// </example>
 ///
 ///
 /// <example>
 ///
 /// <para>
 ///   This example shows how to read a zip file using the default
 ///   code page, to remove entries that have a modified date before a given threshold,
 ///   sending status messages out to a <c>StringWriter</c>.
 /// </para>
 ///
 /// <code lang="C#">
 /// var options = new ReadOptions
 /// {
 ///   StatusMessageWriter = new System.IO.StringWriter()
 /// };
 /// using (ZipFile zip =  ZipFile.Read("PackedDocuments.zip", options))
 /// {
 ///   var Threshold = new DateTime(2007,7,4);
 ///   // We cannot remove the entry from the list, within the context of
 ///   // an enumeration of said list.
 ///   // So we add the doomed entry to a list to be removed later.
 ///   // pass 1: mark the entries for removal
 ///   var MarkedEntries = new System.Collections.Generic.List&lt;ZipEntry&gt;();
 ///   foreach (ZipEntry e in zip)
 ///   {
 ///     if (e.LastModified &lt; Threshold)
 ///       MarkedEntries.Add(e);
 ///   }
 ///   // pass 2: actually remove the entry.
 ///   foreach (ZipEntry zombie in MarkedEntries)
 ///      zip.RemoveEntry(zombie);
 ///   zip.Comment = "This archive has been updated.";
 ///   zip.Save();
 /// }
 /// // can now use contents of sw, eg store in an audit log
 /// </code>
 ///
 /// <code lang="VB">
 /// Dim options as New ReadOptions
 /// options.StatusMessageWriter = New System.IO.StringWriter
 /// Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip", options)
 ///     Dim Threshold As New DateTime(2007, 7, 4)
 ///     ' We cannot remove the entry from the list, within the context of
 ///     ' an enumeration of said list.
 ///     ' So we add the doomed entry to a list to be removed later.
 ///     ' pass 1: mark the entries for removal
 ///     Dim MarkedEntries As New System.Collections.Generic.List(Of ZipEntry)
 ///     Dim e As ZipEntry
 ///     For Each e In zip
 ///         If (e.LastModified &lt; Threshold) Then
 ///             MarkedEntries.Add(e)
 ///         End If
 ///     Next
 ///     ' pass 2: actually remove the entry.
 ///     Dim zombie As ZipEntry
 ///     For Each zombie In MarkedEntries
 ///         zip.RemoveEntry(zombie)
 ///     Next
 ///     zip.Comment = "This archive has been updated."
 ///     zip.Save
 /// End Using
 /// ' can now use contents of sw, eg store in an audit log
 /// </code>
 /// </example>
 ///
 /// <exception cref="System.Exception">
 ///   Thrown if the zipfile cannot be read. The implementation of
 ///   this method relies on <c>System.IO.File.OpenRead</c>, which
 ///   can throw a variety of exceptions, including specific
 ///   exceptions if a file is not found, an unauthorized access
 ///   exception, exceptions for poorly formatted filenames, and so
 ///   on.
 /// </exception>
 ///
 /// <param name="fileName">
 /// The name of the zip archive to open.
 /// This can be a fully-qualified or relative pathname.
 /// </param>
 ///
 /// <param name="options">
 /// The set of options to use when reading the zip file.
 /// </param>
 ///
 /// <returns>The ZipFile instance read from the zip archive.</returns>
 ///
 /// <seealso cref="ZipFile.Read(Stream, ReadOptions)"/>
 ///
 public static ZipFile Read(string fileName,
                            ReadOptions options)
 {
     if (options == null)
         throw new ArgumentNullException("options");
     return Read(fileName,
                 options.StatusMessageWriter,
                 options.Encoding,
                 options.ReadProgress);
 }
        /// <summary>
        ///   Reads a zip file archive from the given stream using the
        ///   specified options.
        /// </summary>
        ///
        /// <remarks>
        ///
        /// <para>
        ///   When reading from a file, it's probably easier to just use
        ///   <see cref="ZipFile.Read(String,
        ///   ReadOptions)">ZipFile.Read(String, ReadOptions)</see>.  This
        ///   overload is useful when when the zip archive content is
        ///   available from an already-open stream. The stream must be
        ///   open and readable and seekable when calling this method.  The
        ///   stream is left open when the reading is completed.
        /// </para>
        ///
        /// <para>
        ///   Reading of zip content begins at the current position in the
        ///   stream.  This means if you have a stream that concatenates
        ///   regular data and zip data, if you position the open, readable
        ///   stream at the start of the zip data, you will be able to read
        ///   the zip archive using this constructor, or any of the ZipFile
        ///   constructors that accept a <see cref="System.IO.Stream" /> as
        ///   input. Some examples of where this might be useful: the zip
        ///   content is concatenated at the end of a regular EXE file, as
        ///   some self-extracting archives do.  (Note: SFX files produced
        ///   by DotNetZip do not work this way; they can be read as normal
        ///   ZIP files). Another example might be a stream being read from
        ///   a database, where the zip content is embedded within an
        ///   aggregate stream of data.
        /// </para>
        /// </remarks>
        ///
        /// <param name="zipStream">the stream containing the zip data.</param>
        ///
        /// <param name="options">
        ///   The set of options to use when reading the zip file.
        /// </param>
        ///
        /// <exception cref="System.Exception">
        ///   Thrown if the zip archive cannot be read.
        /// </exception>
        ///
        /// <returns>The ZipFile instance read from the stream.</returns>
        ///
        /// <seealso cref="ZipFile.Read(String, ReadOptions)"/>
        ///
        public static ZipFile Read(Stream zipStream, ReadOptions options)
        {
            if (options == null)
                throw new ArgumentNullException("options");

            return Read(zipStream,
                        options.StatusMessageWriter,
                        options.Encoding,
                        options.ReadProgress);
        }
        public void Extract_ExistingFile()
        {
            string zipFileToCreate = Path.Combine(TopLevelDir, "Extract_ExistingFile.zip");
            string sourceDir = CurrentDir;
            for (int i = 0; i < 3; i++)
                sourceDir = Path.GetDirectoryName(sourceDir);

            Directory.SetCurrentDirectory(TopLevelDir);

            string[] filenames =
                {
                    Path.Combine(sourceDir, "Tools\\Zipit\\bin\\Debug\\Zipit.exe"),
                    Path.Combine(sourceDir, "Zip\\bin\\Debug\\Ionic.Zip.dll"),
                    Path.Combine(sourceDir, "Zip\\bin\\Debug\\Ionic.Zip.pdb"),
                    Path.Combine(sourceDir, "Zip\\bin\\Debug\\Ionic.Zip.xml"),
                    //Path.Combine(SourceDir, "AppNote.txt")
                };

            int j = 0;
            using (ZipFile zip = new ZipFile())
            {
                for (j = 0; j < filenames.Length; j++)
                    zip.AddFile(filenames[j], "");
                zip.Comment = "This is a Comment On the Archive";
                zip.Save(zipFileToCreate);
            }


            BasicVerifyZip(zipFileToCreate);

            Assert.AreEqual<int>(TestUtilities.CountEntries(zipFileToCreate), filenames.Length,
                                 "The zip file created has the wrong number of entries.");

            TestContext.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - - - - -");
            TestContext.WriteLine("1. first extract - this should succeed");
            var options = new ReadOptions { StatusMessageWriter = new StringWriter() };
            using (ZipFile zip = ZipFile.Read(zipFileToCreate, options))
            {
                for (j = 0; j < filenames.Length; j++)
                {
                    var f = Path.GetFileName(filenames[j]);
                    zip[f].Extract("unpack", ExtractExistingFileAction.Throw);
                }
            }
            TestContext.WriteLine(options.StatusMessageWriter.ToString());

            TestContext.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - - - - -");
            TestContext.WriteLine("2. extract again - DoNotOverwrite");
            options.StatusMessageWriter = new StringWriter();
            using (ZipFile zip = ZipFile.Read(zipFileToCreate, options))
            {
                for (j = 0; j < filenames.Length; j++)
                {
                    var f = Path.GetFileName(filenames[j]);
                    zip[f].Extract("unpack", ExtractExistingFileAction.DoNotOverwrite);
                }
            }
            TestContext.WriteLine(options.StatusMessageWriter.ToString());

            TestContext.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - - - - -");
            TestContext.WriteLine("3. extract again - OverwriteSilently");
            options.StatusMessageWriter = new StringWriter();
            using (ZipFile zip = ZipFile.Read(zipFileToCreate, options))
            {
                for (j = 0; j < filenames.Length; j++)
                {
                    var f = Path.GetFileName(filenames[j]);
                    zip[f].Extract("unpack", ExtractExistingFileAction.OverwriteSilently);
                }
            }
            TestContext.WriteLine(options.StatusMessageWriter.ToString());

            TestContext.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - - - - -");
            TestContext.WriteLine("4. extract again - InvokeExtractProgressEvent");
            options.StatusMessageWriter = new StringWriter();
            using (ZipFile zip = ZipFile.Read(zipFileToCreate, options))
            {
                zip.ExtractProgress += OverwriteDecider;
                for (j = 0; j < filenames.Length; j++)
                {
                    var f = Path.GetFileName(filenames[j]);
                    zip[f].Extract("unpack", ExtractExistingFileAction.InvokeExtractProgressEvent);
                }
            }
            TestContext.WriteLine(options.StatusMessageWriter.ToString());
        }
        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<System.Text.Encoding>
                            (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<string>(f, zip0[f].FileName,
                                                "The FileName was not expected, (cycle {0}) ", j);
                    }
                }
            }
        }
        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<int>(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<String>(fname, Path.GetFileName(e.FileName));
                            }
                            else
                            {
                                Assert.AreNotEqual<String>(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<String>(origComment, zip2.Comment);

                    }
                }
            }
        }
        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.");
        }
        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<String>(cyrillicComment, comment2,
                                    "The comments are not equal.");
        }