|  | // ZipFile.Events.cs | 
|  | // ------------------------------------------------------------------ | 
|  | // | 
|  | // Copyright (c) 2008, 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 (in emacs): | 
|  | // Time-stamp: <2011-July-09 08:42:35> | 
|  | // | 
|  | // ------------------------------------------------------------------ | 
|  | // | 
|  | // This module defines the methods for issuing events from the ZipFile class. | 
|  | // | 
|  | // ------------------------------------------------------------------ | 
|  | // | 
|  |  | 
|  | using System; | 
|  | using System.IO; | 
|  |  | 
|  | namespace OfficeOpenXml.Packaging.Ionic.Zip | 
|  | { | 
|  | internal partial class ZipFile | 
|  | { | 
|  | private string ArchiveNameForEvent | 
|  | { | 
|  | get | 
|  | { | 
|  | return (_name != null) ? _name : "(stream)"; | 
|  | } | 
|  | } | 
|  |  | 
|  | #region Save | 
|  |  | 
|  | /// <summary> | 
|  | ///   An event handler invoked when a Save() starts, before and after each | 
|  | ///   entry has been written to the archive, when a Save() completes, and | 
|  | ///   during other Save events. | 
|  | /// </summary> | 
|  | /// | 
|  | /// <remarks> | 
|  | /// <para> | 
|  | ///   Depending on the particular event, different properties on the <see | 
|  | ///   cref="SaveProgressEventArgs"/> parameter are set.  The following | 
|  | ///   table summarizes the available EventTypes and the conditions under | 
|  | ///   which this event handler is invoked with a | 
|  | ///   <c>SaveProgressEventArgs</c> with the given EventType. | 
|  | /// </para> | 
|  | /// | 
|  | /// <list type="table"> | 
|  | /// <listheader> | 
|  | /// <term>value of EntryType</term> | 
|  | /// <description>Meaning and conditions</description> | 
|  | /// </listheader> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_Started</term> | 
|  | /// <description>Fired when ZipFile.Save() begins. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_BeforeSaveEntry</term> | 
|  | /// <description> | 
|  | ///   Fired within ZipFile.Save(), just before writing data for each | 
|  | ///   particular entry. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_AfterSaveEntry</term> | 
|  | /// <description> | 
|  | ///   Fired within ZipFile.Save(), just after having finished writing data | 
|  | ///   for each particular entry. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_Completed</term> | 
|  | /// <description>Fired when ZipFile.Save() has completed. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_AfterSaveTempArchive</term> | 
|  | /// <description> | 
|  | ///   Fired after the temporary file has been created.  This happens only | 
|  | ///   when saving to a disk file.  This event will not be invoked when | 
|  | ///   saving to a stream. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_BeforeRenameTempArchive</term> | 
|  | /// <description> | 
|  | ///   Fired just before renaming the temporary file to the permanent | 
|  | ///   location.  This happens only when saving to a disk file.  This event | 
|  | ///   will not be invoked when saving to a stream. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_AfterRenameTempArchive</term> | 
|  | /// <description> | 
|  | ///   Fired just after renaming the temporary file to the permanent | 
|  | ///   location.  This happens only when saving to a disk file.  This event | 
|  | ///   will not be invoked when saving to a stream. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_AfterCompileSelfExtractor</term> | 
|  | /// <description> | 
|  | ///   Fired after a self-extracting archive has finished compiling.  This | 
|  | ///   EventType is used only within SaveSelfExtractor(). | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Saving_BytesRead</term> | 
|  | /// <description> | 
|  | ///   Set during the save of a particular entry, to update progress of the | 
|  | ///   Save().  When this EventType is set, the BytesTransferred is the | 
|  | ///   number of bytes that have been read from the source stream.  The | 
|  | ///   TotalBytesToTransfer is the number of bytes in the uncompressed | 
|  | ///   file. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// </list> | 
|  | /// </remarks> | 
|  | /// | 
|  | /// <example> | 
|  | /// | 
|  | ///    This example uses an anonymous method to handle the | 
|  | ///    SaveProgress event, by updating a progress bar. | 
|  | /// | 
|  | /// <code lang="C#"> | 
|  | /// progressBar1.Value = 0; | 
|  | /// progressBar1.Max = listbox1.Items.Count; | 
|  | /// using (ZipFile zip = new ZipFile()) | 
|  | /// { | 
|  | ///    // listbox1 contains a list of filenames | 
|  | ///    zip.AddFiles(listbox1.Items); | 
|  | /// | 
|  | ///    // do the progress bar: | 
|  | ///    zip.SaveProgress += (sender, e) => { | 
|  | ///       if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) { | 
|  | ///          progressBar1.PerformStep(); | 
|  | ///       } | 
|  | ///    }; | 
|  | /// | 
|  | ///    zip.Save(fs); | 
|  | /// } | 
|  | /// </code> | 
|  | /// </example> | 
|  | /// | 
|  | /// <example> | 
|  | ///   This example uses a named method as the | 
|  | ///   <c>SaveProgress</c> event handler, to update the user, in a | 
|  | ///   console-based application. | 
|  | /// | 
|  | /// <code lang="C#"> | 
|  | /// static bool justHadByteUpdate= false; | 
|  | /// public static void SaveProgress(object sender, SaveProgressEventArgs e) | 
|  | /// { | 
|  | ///     if (e.EventType == ZipProgressEventType.Saving_Started) | 
|  | ///         Console.WriteLine("Saving: {0}", e.ArchiveName); | 
|  | /// | 
|  | ///     else if (e.EventType == ZipProgressEventType.Saving_Completed) | 
|  | ///     { | 
|  | ///         justHadByteUpdate= false; | 
|  | ///         Console.WriteLine(); | 
|  | ///         Console.WriteLine("Done: {0}", e.ArchiveName); | 
|  | ///     } | 
|  | /// | 
|  | ///     else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) | 
|  | ///     { | 
|  | ///         if (justHadByteUpdate) | 
|  | ///             Console.WriteLine(); | 
|  | ///         Console.WriteLine("  Writing: {0} ({1}/{2})", | 
|  | ///                           e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal); | 
|  | ///         justHadByteUpdate= false; | 
|  | ///     } | 
|  | /// | 
|  | ///     else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead) | 
|  | ///     { | 
|  | ///         if (justHadByteUpdate) | 
|  | ///             Console.SetCursorPosition(0, Console.CursorTop); | 
|  | ///          Console.Write("     {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, | 
|  | ///                       e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); | 
|  | ///         justHadByteUpdate= true; | 
|  | ///     } | 
|  | /// } | 
|  | /// | 
|  | /// public static ZipUp(string targetZip, string directory) | 
|  | /// { | 
|  | ///   using (var zip = new ZipFile()) { | 
|  | ///     zip.SaveProgress += SaveProgress; | 
|  | ///     zip.AddDirectory(directory); | 
|  | ///     zip.Save(targetZip); | 
|  | ///   } | 
|  | /// } | 
|  | /// | 
|  | /// </code> | 
|  | /// | 
|  | /// <code lang="VB"> | 
|  | /// Public Sub ZipUp(ByVal targetZip As String, ByVal directory As String) | 
|  | ///     Using zip As ZipFile = New ZipFile | 
|  | ///         AddHandler zip.SaveProgress, AddressOf MySaveProgress | 
|  | ///         zip.AddDirectory(directory) | 
|  | ///         zip.Save(targetZip) | 
|  | ///     End Using | 
|  | /// End Sub | 
|  | /// | 
|  | /// Private Shared justHadByteUpdate As Boolean = False | 
|  | /// | 
|  | /// Public Shared Sub MySaveProgress(ByVal sender As Object, ByVal e As SaveProgressEventArgs) | 
|  | ///     If (e.EventType Is ZipProgressEventType.Saving_Started) Then | 
|  | ///         Console.WriteLine("Saving: {0}", e.ArchiveName) | 
|  | /// | 
|  | ///     ElseIf (e.EventType Is ZipProgressEventType.Saving_Completed) Then | 
|  | ///         justHadByteUpdate = False | 
|  | ///         Console.WriteLine | 
|  | ///         Console.WriteLine("Done: {0}", e.ArchiveName) | 
|  | /// | 
|  | ///     ElseIf (e.EventType Is ZipProgressEventType.Saving_BeforeWriteEntry) Then | 
|  | ///         If justHadByteUpdate Then | 
|  | ///             Console.WriteLine | 
|  | ///         End If | 
|  | ///         Console.WriteLine("  Writing: {0} ({1}/{2})", e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal) | 
|  | ///         justHadByteUpdate = False | 
|  | /// | 
|  | ///     ElseIf (e.EventType Is ZipProgressEventType.Saving_EntryBytesRead) Then | 
|  | ///         If justHadByteUpdate Then | 
|  | ///             Console.SetCursorPosition(0, Console.CursorTop) | 
|  | ///         End If | 
|  | ///         Console.Write("     {0}/{1} ({2:N0}%)", e.BytesTransferred, _ | 
|  | ///                       e.TotalBytesToTransfer, _ | 
|  | ///                       (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) | 
|  | ///         justHadByteUpdate = True | 
|  | ///     End If | 
|  | /// End Sub | 
|  | /// </code> | 
|  | /// </example> | 
|  | /// | 
|  | /// <example> | 
|  | /// | 
|  | /// This is a more complete example of using the SaveProgress | 
|  | /// events in a Windows Forms application, with a | 
|  | /// Thread object. | 
|  | /// | 
|  | /// <code lang="C#"> | 
|  | /// delegate void SaveEntryProgress(SaveProgressEventArgs e); | 
|  | /// delegate void ButtonClick(object sender, EventArgs e); | 
|  | /// | 
|  | /// internal class WorkerOptions | 
|  | /// { | 
|  | ///     public string ZipName; | 
|  | ///     public string Folder; | 
|  | ///     public string Encoding; | 
|  | ///     public string Comment; | 
|  | ///     public int ZipFlavor; | 
|  | ///     public Zip64Option Zip64; | 
|  | /// } | 
|  | /// | 
|  | /// private int _progress2MaxFactor; | 
|  | /// private bool _saveCanceled; | 
|  | /// private long _totalBytesBeforeCompress; | 
|  | /// private long _totalBytesAfterCompress; | 
|  | /// private Thread _workerThread; | 
|  | /// | 
|  | /// | 
|  | /// private void btnZipup_Click(object sender, EventArgs e) | 
|  | /// { | 
|  | ///     KickoffZipup(); | 
|  | /// } | 
|  | /// | 
|  | /// private void btnCancel_Click(object sender, EventArgs e) | 
|  | /// { | 
|  | ///     if (this.lblStatus.InvokeRequired) | 
|  | ///     { | 
|  | ///         this.lblStatus.Invoke(new ButtonClick(this.btnCancel_Click), new object[] { sender, e }); | 
|  | ///     } | 
|  | ///     else | 
|  | ///     { | 
|  | ///         _saveCanceled = true; | 
|  | ///         lblStatus.Text = "Canceled..."; | 
|  | ///         ResetState(); | 
|  | ///     } | 
|  | /// } | 
|  | /// | 
|  | /// private void KickoffZipup() | 
|  | /// { | 
|  | ///     _folderName = tbDirName.Text; | 
|  | /// | 
|  | ///     if (_folderName == null || _folderName == "") return; | 
|  | ///     if (this.tbZipName.Text == null || this.tbZipName.Text == "") return; | 
|  | /// | 
|  | ///     // check for existence of the zip file: | 
|  | ///     if (System.IO.File.Exists(this.tbZipName.Text)) | 
|  | ///     { | 
|  | ///         var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) already exists." + | 
|  | ///                                                       "  Do you want to overwrite this file?", this.tbZipName.Text), | 
|  | ///                                         "Confirmation is Required", MessageBoxButtons.YesNo, MessageBoxIcon.Question); | 
|  | ///         if (dlgResult != DialogResult.Yes) return; | 
|  | ///         System.IO.File.Delete(this.tbZipName.Text); | 
|  | ///     } | 
|  | /// | 
|  | ///      _saveCanceled = false; | 
|  | ///     _nFilesCompleted = 0; | 
|  | ///     _totalBytesAfterCompress = 0; | 
|  | ///     _totalBytesBeforeCompress = 0; | 
|  | ///     this.btnOk.Enabled = false; | 
|  | ///     this.btnOk.Text = "Zipping..."; | 
|  | ///     this.btnCancel.Enabled = true; | 
|  | ///     lblStatus.Text = "Zipping..."; | 
|  | /// | 
|  | ///     var options = new WorkerOptions | 
|  | ///     { | 
|  | ///         ZipName = this.tbZipName.Text, | 
|  | ///         Folder = _folderName, | 
|  | ///         Encoding = "ibm437" | 
|  | ///     }; | 
|  | /// | 
|  | ///     if (this.comboBox1.SelectedIndex != 0) | 
|  | ///     { | 
|  | ///         options.Encoding = this.comboBox1.SelectedItem.ToString(); | 
|  | ///     } | 
|  | /// | 
|  | ///     if (this.radioFlavorSfxCmd.Checked) | 
|  | ///         options.ZipFlavor = 2; | 
|  | ///     else if (this.radioFlavorSfxGui.Checked) | 
|  | ///         options.ZipFlavor = 1; | 
|  | ///     else options.ZipFlavor = 0; | 
|  | /// | 
|  | ///     if (this.radioZip64AsNecessary.Checked) | 
|  | ///         options.Zip64 = Zip64Option.AsNecessary; | 
|  | ///     else if (this.radioZip64Always.Checked) | 
|  | ///         options.Zip64 = Zip64Option.Always; | 
|  | ///     else options.Zip64 = Zip64Option.Never; | 
|  | /// | 
|  | ///     options.Comment = String.Format("Encoding:{0} || Flavor:{1} || ZIP64:{2}\r\nCreated at {3} || {4}\r\n", | 
|  | ///                 options.Encoding, | 
|  | ///                 FlavorToString(options.ZipFlavor), | 
|  | ///                 options.Zip64.ToString(), | 
|  | ///                 System.DateTime.Now.ToString("yyyy-MMM-dd HH:mm:ss"), | 
|  | ///                 this.Text); | 
|  | /// | 
|  | ///     if (this.tbComment.Text != TB_COMMENT_NOTE) | 
|  | ///         options.Comment += this.tbComment.Text; | 
|  | /// | 
|  | ///     _workerThread = new Thread(this.DoSave); | 
|  | ///     _workerThread.Name = "Zip Saver thread"; | 
|  | ///     _workerThread.Start(options); | 
|  | ///     this.Cursor = Cursors.WaitCursor; | 
|  | ///  } | 
|  | /// | 
|  | /// | 
|  | /// private void DoSave(Object p) | 
|  | /// { | 
|  | ///     WorkerOptions options = p as WorkerOptions; | 
|  | ///     try | 
|  | ///     { | 
|  | ///         using (var zip1 = new ZipFile()) | 
|  | ///         { | 
|  | ///             zip1.ProvisionalAlternateEncoding = System.Text.Encoding.GetEncoding(options.Encoding); | 
|  | ///             zip1.Comment = options.Comment; | 
|  | ///             zip1.AddDirectory(options.Folder); | 
|  | ///             _entriesToZip = zip1.EntryFileNames.Count; | 
|  | ///             SetProgressBars(); | 
|  | ///             zip1.SaveProgress += this.zip1_SaveProgress; | 
|  | /// | 
|  | ///             zip1.UseZip64WhenSaving = options.Zip64; | 
|  | /// | 
|  | ///             if (options.ZipFlavor == 1) | 
|  | ///                 zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.WinFormsApplication); | 
|  | ///             else if (options.ZipFlavor == 2) | 
|  | ///                 zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.ConsoleApplication); | 
|  | ///             else | 
|  | ///                 zip1.Save(options.ZipName); | 
|  | ///         } | 
|  | ///     } | 
|  | ///     catch (System.Exception exc1) | 
|  | ///     { | 
|  | ///         MessageBox.Show(String.Format("Exception while zipping: {0}", exc1.Message)); | 
|  | ///         btnCancel_Click(null, null); | 
|  | ///     } | 
|  | /// } | 
|  | /// | 
|  | /// | 
|  | /// | 
|  | /// void zip1_SaveProgress(object sender, SaveProgressEventArgs e) | 
|  | /// { | 
|  | ///     switch (e.EventType) | 
|  | ///     { | 
|  | ///         case ZipProgressEventType.Saving_AfterWriteEntry: | 
|  | ///             StepArchiveProgress(e); | 
|  | ///             break; | 
|  | ///         case ZipProgressEventType.Saving_EntryBytesRead: | 
|  | ///             StepEntryProgress(e); | 
|  | ///             break; | 
|  | ///         case ZipProgressEventType.Saving_Completed: | 
|  | ///             SaveCompleted(); | 
|  | ///             break; | 
|  | ///         case ZipProgressEventType.Saving_AfterSaveTempArchive: | 
|  | ///             // this event only occurs when saving an SFX file | 
|  | ///             TempArchiveSaved(); | 
|  | ///             break; | 
|  | ///     } | 
|  | ///     if (_saveCanceled) | 
|  | ///         e.Cancel = true; | 
|  | /// } | 
|  | /// | 
|  | /// | 
|  | /// | 
|  | /// private void StepArchiveProgress(SaveProgressEventArgs e) | 
|  | /// { | 
|  | ///     if (this.progressBar1.InvokeRequired) | 
|  | ///     { | 
|  | ///         this.progressBar1.Invoke(new SaveEntryProgress(this.StepArchiveProgress), new object[] { e }); | 
|  | ///     } | 
|  | ///     else | 
|  | ///     { | 
|  | ///         if (!_saveCanceled) | 
|  | ///         { | 
|  | ///             _nFilesCompleted++; | 
|  | ///             this.progressBar1.PerformStep(); | 
|  | ///             _totalBytesAfterCompress += e.CurrentEntry.CompressedSize; | 
|  | ///             _totalBytesBeforeCompress += e.CurrentEntry.UncompressedSize; | 
|  | /// | 
|  | ///             // reset the progress bar for the entry: | 
|  | ///             this.progressBar2.Value = this.progressBar2.Maximum = 1; | 
|  | /// | 
|  | ///             this.Update(); | 
|  | ///         } | 
|  | ///     } | 
|  | /// } | 
|  | /// | 
|  | /// | 
|  | /// private void StepEntryProgress(SaveProgressEventArgs e) | 
|  | /// { | 
|  | ///     if (this.progressBar2.InvokeRequired) | 
|  | ///     { | 
|  | ///         this.progressBar2.Invoke(new SaveEntryProgress(this.StepEntryProgress), new object[] { e }); | 
|  | ///     } | 
|  | ///     else | 
|  | ///     { | 
|  | ///         if (!_saveCanceled) | 
|  | ///         { | 
|  | ///             if (this.progressBar2.Maximum == 1) | 
|  | ///             { | 
|  | ///                 // reset | 
|  | ///                 Int64 max = e.TotalBytesToTransfer; | 
|  | ///                 _progress2MaxFactor = 0; | 
|  | ///                 while (max > System.Int32.MaxValue) | 
|  | ///                 { | 
|  | ///                     max /= 2; | 
|  | ///                     _progress2MaxFactor++; | 
|  | ///                 } | 
|  | ///                 this.progressBar2.Maximum = (int)max; | 
|  | ///                 lblStatus.Text = String.Format("{0} of {1} files...({2})", | 
|  | ///                     _nFilesCompleted + 1, _entriesToZip, e.CurrentEntry.FileName); | 
|  | ///             } | 
|  | /// | 
|  | ///              int xferred = e.BytesTransferred >> _progress2MaxFactor; | 
|  | /// | 
|  | ///              this.progressBar2.Value = (xferred >= this.progressBar2.Maximum) | 
|  | ///                 ? this.progressBar2.Maximum | 
|  | ///                 : xferred; | 
|  | /// | 
|  | ///              this.Update(); | 
|  | ///         } | 
|  | ///     } | 
|  | /// } | 
|  | /// | 
|  | /// private void SaveCompleted() | 
|  | /// { | 
|  | ///     if (this.lblStatus.InvokeRequired) | 
|  | ///     { | 
|  | ///         this.lblStatus.Invoke(new MethodInvoker(this.SaveCompleted)); | 
|  | ///     } | 
|  | ///     else | 
|  | ///     { | 
|  | ///         lblStatus.Text = String.Format("Done, Compressed {0} files, {1:N0}% of original.", | 
|  | ///             _nFilesCompleted, (100.00 * _totalBytesAfterCompress) / _totalBytesBeforeCompress); | 
|  | ///          ResetState(); | 
|  | ///     } | 
|  | /// } | 
|  | /// | 
|  | /// private void ResetState() | 
|  | /// { | 
|  | ///     this.btnCancel.Enabled = false; | 
|  | ///     this.btnOk.Enabled = true; | 
|  | ///     this.btnOk.Text = "Zip it!"; | 
|  | ///     this.progressBar1.Value = 0; | 
|  | ///     this.progressBar2.Value = 0; | 
|  | ///     this.Cursor = Cursors.Default; | 
|  | ///     if (!_workerThread.IsAlive) | 
|  | ///         _workerThread.Join(); | 
|  | /// } | 
|  | /// </code> | 
|  | /// | 
|  | /// </example> | 
|  | /// | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ReadProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.AddProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/> | 
|  | internal event EventHandler<SaveProgressEventArgs> SaveProgress; | 
|  |  | 
|  |  | 
|  | internal bool OnSaveBlock(ZipEntry entry, Int64 bytesXferred, Int64 totalBytesToXfer) | 
|  | { | 
|  | EventHandler<SaveProgressEventArgs> sp = SaveProgress; | 
|  | if (sp != null) | 
|  | { | 
|  | var e = SaveProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry, | 
|  | bytesXferred, totalBytesToXfer); | 
|  | sp(this, e); | 
|  | if (e.Cancel) | 
|  | _saveOperationCanceled = true; | 
|  | } | 
|  | return _saveOperationCanceled; | 
|  | } | 
|  |  | 
|  | private void OnSaveEntry(int current, ZipEntry entry, bool before) | 
|  | { | 
|  | EventHandler<SaveProgressEventArgs> sp = SaveProgress; | 
|  | if (sp != null) | 
|  | { | 
|  | var e = new SaveProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, entry); | 
|  | sp(this, e); | 
|  | if (e.Cancel) | 
|  | _saveOperationCanceled = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | private void OnSaveEvent(ZipProgressEventType eventFlavor) | 
|  | { | 
|  | EventHandler<SaveProgressEventArgs> sp = SaveProgress; | 
|  | if (sp != null) | 
|  | { | 
|  | var e = new SaveProgressEventArgs(ArchiveNameForEvent, eventFlavor); | 
|  | sp(this, e); | 
|  | if (e.Cancel) | 
|  | _saveOperationCanceled = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | private void OnSaveStarted() | 
|  | { | 
|  | EventHandler<SaveProgressEventArgs> sp = SaveProgress; | 
|  | if (sp != null) | 
|  | { | 
|  | var e = SaveProgressEventArgs.Started(ArchiveNameForEvent); | 
|  | sp(this, e); | 
|  | if (e.Cancel) | 
|  | _saveOperationCanceled = true; | 
|  | } | 
|  | } | 
|  | private void OnSaveCompleted() | 
|  | { | 
|  | EventHandler<SaveProgressEventArgs> sp = SaveProgress; | 
|  | if (sp != null) | 
|  | { | 
|  | var e = SaveProgressEventArgs.Completed(ArchiveNameForEvent); | 
|  | sp(this, e); | 
|  | } | 
|  | } | 
|  | #endregion | 
|  |  | 
|  |  | 
|  | #region Read | 
|  | /// <summary> | 
|  | /// An event handler invoked before, during, and after the reading of a zip archive. | 
|  | /// </summary> | 
|  | /// | 
|  | /// <remarks> | 
|  | /// <para> | 
|  | /// Depending on the particular event being signaled, different properties on the | 
|  | /// <see cref="ReadProgressEventArgs"/> parameter are set.  The following table | 
|  | /// summarizes the available EventTypes and the conditions under which this | 
|  | /// event handler is invoked with a <c>ReadProgressEventArgs</c> with the given EventType. | 
|  | /// </para> | 
|  | /// | 
|  | /// <list type="table"> | 
|  | /// <listheader> | 
|  | /// <term>value of EntryType</term> | 
|  | /// <description>Meaning and conditions</description> | 
|  | /// </listheader> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Reading_Started</term> | 
|  | /// <description>Fired just as ZipFile.Read() begins. Meaningful properties: ArchiveName. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Reading_Completed</term> | 
|  | /// <description>Fired when ZipFile.Read() has completed. Meaningful properties: ArchiveName. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Reading_ArchiveBytesRead</term> | 
|  | /// <description>Fired while reading, updates the number of bytes read for the entire archive. | 
|  | /// Meaningful properties: ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Reading_BeforeReadEntry</term> | 
|  | /// <description>Indicates an entry is about to be read from the archive. | 
|  | /// Meaningful properties: ArchiveName, EntriesTotal. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Reading_AfterReadEntry</term> | 
|  | /// <description>Indicates an entry has just been read from the archive. | 
|  | /// Meaningful properties: ArchiveName, EntriesTotal, CurrentEntry. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// </list> | 
|  | /// </remarks> | 
|  | /// | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.SaveProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.AddProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/> | 
|  | internal event EventHandler<ReadProgressEventArgs> ReadProgress; | 
|  |  | 
|  | private void OnReadStarted() | 
|  | { | 
|  | EventHandler<ReadProgressEventArgs> rp = ReadProgress; | 
|  | if (rp != null) | 
|  | { | 
|  | var e = ReadProgressEventArgs.Started(ArchiveNameForEvent); | 
|  | rp(this, e); | 
|  | } | 
|  | } | 
|  |  | 
|  | private void OnReadCompleted() | 
|  | { | 
|  | EventHandler<ReadProgressEventArgs> rp = ReadProgress; | 
|  | if (rp != null) | 
|  | { | 
|  | var e = ReadProgressEventArgs.Completed(ArchiveNameForEvent); | 
|  | rp(this, e); | 
|  | } | 
|  | } | 
|  |  | 
|  | internal void OnReadBytes(ZipEntry entry) | 
|  | { | 
|  | EventHandler<ReadProgressEventArgs> rp = ReadProgress; | 
|  | if (rp != null) | 
|  | { | 
|  | var e = ReadProgressEventArgs.ByteUpdate(ArchiveNameForEvent, | 
|  | entry, | 
|  | ReadStream.Position, | 
|  | LengthOfReadStream); | 
|  | rp(this, e); | 
|  | } | 
|  | } | 
|  |  | 
|  | internal void OnReadEntry(bool before, ZipEntry entry) | 
|  | { | 
|  | EventHandler<ReadProgressEventArgs> rp = ReadProgress; | 
|  | if (rp != null) | 
|  | { | 
|  | ReadProgressEventArgs e = (before) | 
|  | ? ReadProgressEventArgs.Before(ArchiveNameForEvent, _entries.Count) | 
|  | : ReadProgressEventArgs.After(ArchiveNameForEvent, entry, _entries.Count); | 
|  | rp(this, e); | 
|  | } | 
|  | } | 
|  |  | 
|  | private Int64 _lengthOfReadStream = -99; | 
|  | private Int64 LengthOfReadStream | 
|  | { | 
|  | get | 
|  | { | 
|  | if (_lengthOfReadStream == -99) | 
|  | { | 
|  | _lengthOfReadStream = (_ReadStreamIsOurs) | 
|  | ? SharedUtilities.GetFileLength(_name) | 
|  | : -1L; | 
|  | } | 
|  | return _lengthOfReadStream; | 
|  | } | 
|  | } | 
|  | #endregion | 
|  |  | 
|  |  | 
|  | #region Extract | 
|  | /// <summary> | 
|  | ///   An event handler invoked before, during, and after extraction of | 
|  | ///   entries in the zip archive. | 
|  | /// </summary> | 
|  | /// | 
|  | /// <remarks> | 
|  | /// <para> | 
|  | ///   Depending on the particular event, different properties on the <see | 
|  | ///   cref="ExtractProgressEventArgs"/> parameter are set.  The following | 
|  | ///   table summarizes the available EventTypes and the conditions under | 
|  | ///   which this event handler is invoked with a | 
|  | ///   <c>ExtractProgressEventArgs</c> with the given EventType. | 
|  | /// </para> | 
|  | /// | 
|  | /// <list type="table"> | 
|  | /// <listheader> | 
|  | /// <term>value of EntryType</term> | 
|  | /// <description>Meaning and conditions</description> | 
|  | /// </listheader> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Extracting_BeforeExtractAll</term> | 
|  | /// <description> | 
|  | ///   Set when ExtractAll() begins. The ArchiveName, Overwrite, and | 
|  | ///   ExtractLocation properties are meaningful.</description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Extracting_AfterExtractAll</term> | 
|  | /// <description> | 
|  | ///   Set when ExtractAll() has completed.  The ArchiveName, Overwrite, | 
|  | ///   and ExtractLocation properties are meaningful. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Extracting_BeforeExtractEntry</term> | 
|  | /// <description> | 
|  | ///   Set when an Extract() on an entry in the ZipFile has begun. | 
|  | ///   Properties that are meaningful: ArchiveName, EntriesTotal, | 
|  | ///   CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Extracting_AfterExtractEntry</term> | 
|  | /// <description> | 
|  | ///   Set when an Extract() on an entry in the ZipFile has completed. | 
|  | ///   Properties that are meaningful: ArchiveName, EntriesTotal, | 
|  | ///   CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Extracting_EntryBytesWritten</term> | 
|  | /// <description> | 
|  | ///   Set within a call to Extract() on an entry in the ZipFile, as data | 
|  | ///   is extracted for the entry.  Properties that are meaningful: | 
|  | ///   ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// <item> | 
|  | /// <term>ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite</term> | 
|  | /// <description> | 
|  | ///   Set within a call to Extract() on an entry in the ZipFile, when the | 
|  | ///   extraction would overwrite an existing file. This event type is used | 
|  | ///   only when <c>ExtractExistingFileAction</c> on the <c>ZipFile</c> or | 
|  | ///   <c>ZipEntry</c> is set to <c>InvokeExtractProgressEvent</c>. | 
|  | /// </description> | 
|  | /// </item> | 
|  | /// | 
|  | /// </list> | 
|  | /// | 
|  | /// </remarks> | 
|  | /// | 
|  | /// <example> | 
|  | /// <code> | 
|  | /// private static bool justHadByteUpdate = false; | 
|  | /// public static void ExtractProgress(object sender, ExtractProgressEventArgs e) | 
|  | /// { | 
|  | ///   if(e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten) | 
|  | ///   { | 
|  | ///     if (justHadByteUpdate) | 
|  | ///       Console.SetCursorPosition(0, Console.CursorTop); | 
|  | /// | 
|  | ///     Console.Write("   {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, | 
|  | ///                   e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); | 
|  | ///     justHadByteUpdate = true; | 
|  | ///   } | 
|  | ///   else if(e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) | 
|  | ///   { | 
|  | ///     if (justHadByteUpdate) | 
|  | ///       Console.WriteLine(); | 
|  | ///     Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName); | 
|  | ///     justHadByteUpdate= false; | 
|  | ///   } | 
|  | /// } | 
|  | /// | 
|  | /// public static ExtractZip(string zipToExtract, string directory) | 
|  | /// { | 
|  | ///   string TargetDirectory= "extract"; | 
|  | ///   using (var zip = ZipFile.Read(zipToExtract)) { | 
|  | ///     zip.ExtractProgress += ExtractProgress; | 
|  | ///     foreach (var e in zip1) | 
|  | ///     { | 
|  | ///       e.Extract(TargetDirectory, true); | 
|  | ///     } | 
|  | ///   } | 
|  | /// } | 
|  | /// | 
|  | /// </code> | 
|  | /// <code lang="VB"> | 
|  | /// Public Shared Sub Main(ByVal args As String()) | 
|  | ///     Dim ZipToUnpack As String = "C1P3SML.zip" | 
|  | ///     Dim TargetDir As String = "ExtractTest_Extract" | 
|  | ///     Console.WriteLine("Extracting file {0} to {1}", ZipToUnpack, TargetDir) | 
|  | ///     Using zip1 As ZipFile = ZipFile.Read(ZipToUnpack) | 
|  | ///         AddHandler zip1.ExtractProgress, AddressOf MyExtractProgress | 
|  | ///         Dim e As ZipEntry | 
|  | ///         For Each e In zip1 | 
|  | ///             e.Extract(TargetDir, True) | 
|  | ///         Next | 
|  | ///     End Using | 
|  | /// End Sub | 
|  | /// | 
|  | /// Private Shared justHadByteUpdate As Boolean = False | 
|  | /// | 
|  | /// Public Shared Sub MyExtractProgress(ByVal sender As Object, ByVal e As ExtractProgressEventArgs) | 
|  | ///     If (e.EventType = ZipProgressEventType.Extracting_EntryBytesWritten) Then | 
|  | ///         If ExtractTest.justHadByteUpdate Then | 
|  | ///             Console.SetCursorPosition(0, Console.CursorTop) | 
|  | ///         End If | 
|  | ///         Console.Write("   {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) | 
|  | ///         ExtractTest.justHadByteUpdate = True | 
|  | ///     ElseIf (e.EventType = ZipProgressEventType.Extracting_BeforeExtractEntry) Then | 
|  | ///         If ExtractTest.justHadByteUpdate Then | 
|  | ///             Console.WriteLine | 
|  | ///         End If | 
|  | ///         Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName) | 
|  | ///         ExtractTest.justHadByteUpdate = False | 
|  | ///     End If | 
|  | /// End Sub | 
|  | /// </code> | 
|  | /// </example> | 
|  | /// | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.SaveProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ReadProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.AddProgress"/> | 
|  | internal event EventHandler<ExtractProgressEventArgs> ExtractProgress; | 
|  |  | 
|  |  | 
|  |  | 
|  | private void OnExtractEntry(int current, bool before, ZipEntry currentEntry, string path) | 
|  | { | 
|  | EventHandler<ExtractProgressEventArgs> ep = ExtractProgress; | 
|  | if (ep != null) | 
|  | { | 
|  | var e = new ExtractProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, currentEntry, path); | 
|  | ep(this, e); | 
|  | if (e.Cancel) | 
|  | _extractOperationCanceled = true; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | // Can be called from within ZipEntry._ExtractOne. | 
|  | internal bool OnExtractBlock(ZipEntry entry, Int64 bytesWritten, Int64 totalBytesToWrite) | 
|  | { | 
|  | EventHandler<ExtractProgressEventArgs> ep = ExtractProgress; | 
|  | if (ep != null) | 
|  | { | 
|  | var e = ExtractProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry, | 
|  | bytesWritten, totalBytesToWrite); | 
|  | ep(this, e); | 
|  | if (e.Cancel) | 
|  | _extractOperationCanceled = true; | 
|  | } | 
|  | return _extractOperationCanceled; | 
|  | } | 
|  |  | 
|  |  | 
|  | // Can be called from within ZipEntry.InternalExtract. | 
|  | internal bool OnSingleEntryExtract(ZipEntry entry, string path, bool before) | 
|  | { | 
|  | EventHandler<ExtractProgressEventArgs> ep = ExtractProgress; | 
|  | if (ep != null) | 
|  | { | 
|  | var e = (before) | 
|  | ? ExtractProgressEventArgs.BeforeExtractEntry(ArchiveNameForEvent, entry, path) | 
|  | : ExtractProgressEventArgs.AfterExtractEntry(ArchiveNameForEvent, entry, path); | 
|  | ep(this, e); | 
|  | if (e.Cancel) | 
|  | _extractOperationCanceled = true; | 
|  | } | 
|  | return _extractOperationCanceled; | 
|  | } | 
|  |  | 
|  | internal bool OnExtractExisting(ZipEntry entry, string path) | 
|  | { | 
|  | EventHandler<ExtractProgressEventArgs> ep = ExtractProgress; | 
|  | if (ep != null) | 
|  | { | 
|  | var e = ExtractProgressEventArgs.ExtractExisting(ArchiveNameForEvent, entry, path); | 
|  | ep(this, e); | 
|  | if (e.Cancel) | 
|  | _extractOperationCanceled = true; | 
|  | } | 
|  | return _extractOperationCanceled; | 
|  | } | 
|  |  | 
|  |  | 
|  | private void OnExtractAllCompleted(string path) | 
|  | { | 
|  | EventHandler<ExtractProgressEventArgs> ep = ExtractProgress; | 
|  | if (ep != null) | 
|  | { | 
|  | var e = ExtractProgressEventArgs.ExtractAllCompleted(ArchiveNameForEvent, | 
|  | path ); | 
|  | ep(this, e); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | private void OnExtractAllStarted(string path) | 
|  | { | 
|  | EventHandler<ExtractProgressEventArgs> ep = ExtractProgress; | 
|  | if (ep != null) | 
|  | { | 
|  | var e = ExtractProgressEventArgs.ExtractAllStarted(ArchiveNameForEvent, | 
|  | path ); | 
|  | ep(this, e); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #endregion | 
|  |  | 
|  |  | 
|  |  | 
|  | #region Add | 
|  | /// <summary> | 
|  | /// An event handler invoked before, during, and after Adding entries to a zip archive. | 
|  | /// </summary> | 
|  | /// | 
|  | /// <remarks> | 
|  | ///     Adding a large number of entries to a zip file can take a long | 
|  | ///     time.  For example, when calling <see cref="AddDirectory(string)"/> on a | 
|  | ///     directory that contains 50,000 files, it could take 3 minutes or so. | 
|  | ///     This event handler allws an application to track the progress of the Add | 
|  | ///     operation, and to optionally cancel a lengthy Add operation. | 
|  | /// </remarks> | 
|  | /// | 
|  | /// <example> | 
|  | /// <code lang="C#"> | 
|  | /// | 
|  | /// int _numEntriesToAdd= 0; | 
|  | /// int _numEntriesAdded= 0; | 
|  | /// void AddProgressHandler(object sender, AddProgressEventArgs e) | 
|  | /// { | 
|  | ///     switch (e.EventType) | 
|  | ///     { | 
|  | ///         case ZipProgressEventType.Adding_Started: | 
|  | ///             Console.WriteLine("Adding files to the zip..."); | 
|  | ///             break; | 
|  | ///         case ZipProgressEventType.Adding_AfterAddEntry: | 
|  | ///             _numEntriesAdded++; | 
|  | ///             Console.WriteLine(String.Format("Adding file {0}/{1} :: {2}", | 
|  | ///                                      _numEntriesAdded, _numEntriesToAdd, e.CurrentEntry.FileName)); | 
|  | ///             break; | 
|  | ///         case ZipProgressEventType.Adding_Completed: | 
|  | ///             Console.WriteLine("Added all files"); | 
|  | ///             break; | 
|  | ///     } | 
|  | /// } | 
|  | /// | 
|  | /// void CreateTheZip() | 
|  | /// { | 
|  | ///     using (ZipFile zip = new ZipFile()) | 
|  | ///     { | 
|  | ///         zip.AddProgress += AddProgressHandler; | 
|  | ///         zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)); | 
|  | ///         zip.Save(ZipFileToCreate); | 
|  | ///     } | 
|  | /// } | 
|  | /// | 
|  | /// </code> | 
|  | /// | 
|  | /// <code lang="VB"> | 
|  | /// | 
|  | /// Private Sub AddProgressHandler(ByVal sender As Object, ByVal e As AddProgressEventArgs) | 
|  | ///     Select Case e.EventType | 
|  | ///         Case ZipProgressEventType.Adding_Started | 
|  | ///             Console.WriteLine("Adding files to the zip...") | 
|  | ///             Exit Select | 
|  | ///         Case ZipProgressEventType.Adding_AfterAddEntry | 
|  | ///             Console.WriteLine(String.Format("Adding file {0}", e.CurrentEntry.FileName)) | 
|  | ///             Exit Select | 
|  | ///         Case ZipProgressEventType.Adding_Completed | 
|  | ///             Console.WriteLine("Added all files") | 
|  | ///             Exit Select | 
|  | ///     End Select | 
|  | /// End Sub | 
|  | /// | 
|  | /// Sub CreateTheZip() | 
|  | ///     Using zip as ZipFile = New ZipFile | 
|  | ///         AddHandler zip.AddProgress, AddressOf AddProgressHandler | 
|  | ///         zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)) | 
|  | ///         zip.Save(ZipFileToCreate); | 
|  | ///     End Using | 
|  | /// End Sub | 
|  | /// | 
|  | /// </code> | 
|  | /// | 
|  | /// </example> | 
|  | /// | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.SaveProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ReadProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/> | 
|  | internal event EventHandler<AddProgressEventArgs> AddProgress; | 
|  |  | 
|  | private void OnAddStarted() | 
|  | { | 
|  | EventHandler<AddProgressEventArgs> ap = AddProgress; | 
|  | if (ap != null) | 
|  | { | 
|  | var e = AddProgressEventArgs.Started(ArchiveNameForEvent); | 
|  | ap(this, e); | 
|  | if (e.Cancel) // workitem 13371 | 
|  | _addOperationCanceled = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | private void OnAddCompleted() | 
|  | { | 
|  | EventHandler<AddProgressEventArgs> ap = AddProgress; | 
|  | if (ap != null) | 
|  | { | 
|  | var e = AddProgressEventArgs.Completed(ArchiveNameForEvent); | 
|  | ap(this, e); | 
|  | } | 
|  | } | 
|  |  | 
|  | internal void AfterAddEntry(ZipEntry entry) | 
|  | { | 
|  | EventHandler<AddProgressEventArgs> ap = AddProgress; | 
|  | if (ap != null) | 
|  | { | 
|  | var e = AddProgressEventArgs.AfterEntry(ArchiveNameForEvent, entry, _entries.Count); | 
|  | ap(this, e); | 
|  | if (e.Cancel) // workitem 13371 | 
|  | _addOperationCanceled = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | #endregion | 
|  |  | 
|  |  | 
|  |  | 
|  | #region Error | 
|  | /// <summary> | 
|  | /// An event that is raised when an error occurs during open or read of files | 
|  | /// while saving a zip archive. | 
|  | /// </summary> | 
|  | /// | 
|  | /// <remarks> | 
|  | ///  <para> | 
|  | ///     Errors can occur as a file is being saved to the zip archive.  For | 
|  | ///     example, the File.Open may fail, or a File.Read may fail, because of | 
|  | ///     lock conflicts or other reasons.  If you add a handler to this event, | 
|  | ///     you can handle such errors in your own code.  If you don't add a | 
|  | ///     handler, the library will throw an exception if it encounters an I/O | 
|  | ///     error during a call to <c>Save()</c>. | 
|  | ///  </para> | 
|  | /// | 
|  | ///  <para> | 
|  | ///    Setting a handler implicitly sets <see cref="ZipFile.ZipErrorAction"/> to | 
|  | ///    <c>ZipErrorAction.InvokeErrorEvent</c>. | 
|  | ///  </para> | 
|  | /// | 
|  | ///  <para> | 
|  | ///    The handler you add applies to all <see cref="ZipEntry"/> items that are | 
|  | ///    subsequently added to the <c>ZipFile</c> instance. If you set this | 
|  | ///    property after you have added items to the <c>ZipFile</c>, but before you | 
|  | ///    have called <c>Save()</c>, errors that occur while saving those items | 
|  | ///    will not cause the error handler to be invoked. | 
|  | ///  </para> | 
|  | /// | 
|  | ///  <para> | 
|  | ///    If you want to handle any errors that occur with any entry in the zip | 
|  | ///    file using the same error handler, then add your error handler once, | 
|  | ///    before adding any entries to the zip archive. | 
|  | ///  </para> | 
|  | /// | 
|  | ///  <para> | 
|  | ///    In the error handler method, you need to set the <see | 
|  | ///    cref="ZipEntry.ZipErrorAction"/> property on the | 
|  | ///    <c>ZipErrorEventArgs.CurrentEntry</c>.  This communicates back to | 
|  | ///    DotNetZip what you would like to do with this particular error.  Within | 
|  | ///    an error handler, if you set the <c>ZipEntry.ZipErrorAction</c> property | 
|  | ///    on the <c>ZipEntry</c> to <c>ZipErrorAction.InvokeErrorEvent</c> or if | 
|  | ///    you don't set it at all, the library will throw the exception. (It is the | 
|  | ///    same as if you had set the <c>ZipEntry.ZipErrorAction</c> property on the | 
|  | ///    <c>ZipEntry</c> to <c>ZipErrorAction.Throw</c>.) If you set the | 
|  | ///    <c>ZipErrorEventArgs.Cancel</c> to true, the entire <c>Save()</c> will be | 
|  | ///    canceled. | 
|  | ///  </para> | 
|  | /// | 
|  | ///  <para> | 
|  | ///    In the case that you use <c>ZipErrorAction.Skip</c>, implying that | 
|  | ///    you want to skip the entry for which there's been an error, DotNetZip | 
|  | ///    tries to seek backwards in the output stream, and truncate all bytes | 
|  | ///    written on behalf of that particular entry. This works only if the | 
|  | ///    output stream is seekable.  It will not work, for example, when using | 
|  | ///    ASPNET's Response.OutputStream. | 
|  | ///  </para> | 
|  | /// | 
|  | /// </remarks> | 
|  | /// | 
|  | /// <example> | 
|  | /// | 
|  | /// This example shows how to use an event handler to handle | 
|  | /// errors during save of the zip file. | 
|  | /// <code lang="C#"> | 
|  | /// | 
|  | /// public static void MyZipError(object sender, ZipErrorEventArgs e) | 
|  | /// { | 
|  | ///     Console.WriteLine("Error saving {0}...", e.FileName); | 
|  | ///     Console.WriteLine("   Exception: {0}", e.exception); | 
|  | ///     ZipEntry entry = e.CurrentEntry; | 
|  | ///     string response = null; | 
|  | ///     // Ask the user whether he wants to skip this error or not | 
|  | ///     do | 
|  | ///     { | 
|  | ///         Console.Write("Retry, Skip, Throw, or Cancel ? (R/S/T/C) "); | 
|  | ///         response = Console.ReadLine(); | 
|  | ///         Console.WriteLine(); | 
|  | /// | 
|  | ///     } while (response != null && | 
|  | ///              response[0]!='S' && response[0]!='s' && | 
|  | ///              response[0]!='R' && response[0]!='r' && | 
|  | ///              response[0]!='T' && response[0]!='t' && | 
|  | ///              response[0]!='C' && response[0]!='c'); | 
|  | /// | 
|  | ///     e.Cancel = (response[0]=='C' || response[0]=='c'); | 
|  | /// | 
|  | ///     if (response[0]=='S' || response[0]=='s') | 
|  | ///         entry.ZipErrorAction = ZipErrorAction.Skip; | 
|  | ///     else if (response[0]=='R' || response[0]=='r') | 
|  | ///         entry.ZipErrorAction = ZipErrorAction.Retry; | 
|  | ///     else if (response[0]=='T' || response[0]=='t') | 
|  | ///         entry.ZipErrorAction = ZipErrorAction.Throw; | 
|  | /// } | 
|  | /// | 
|  | /// public void SaveTheFile() | 
|  | /// { | 
|  | ///   string directoryToZip = "fodder"; | 
|  | ///   string directoryInArchive = "files"; | 
|  | ///   string zipFileToCreate = "Archive.zip"; | 
|  | ///   using (var zip = new ZipFile()) | 
|  | ///   { | 
|  | ///     // set the event handler before adding any entries | 
|  | ///     zip.ZipError += MyZipError; | 
|  | ///     zip.AddDirectory(directoryToZip, directoryInArchive); | 
|  | ///     zip.Save(zipFileToCreate); | 
|  | ///   } | 
|  | /// } | 
|  | /// </code> | 
|  | /// | 
|  | /// <code lang="VB"> | 
|  | /// Private Sub MyZipError(ByVal sender As Object, ByVal e As Ionic.Zip.ZipErrorEventArgs) | 
|  | ///     ' At this point, the application could prompt the user for an action to take. | 
|  | ///     ' But in this case, this application will simply automatically skip the file, in case of error. | 
|  | ///     Console.WriteLine("Zip Error,  entry {0}", e.CurrentEntry.FileName) | 
|  | ///     Console.WriteLine("   Exception: {0}", e.exception) | 
|  | ///     ' set the desired ZipErrorAction on the CurrentEntry to communicate that to DotNetZip | 
|  | ///     e.CurrentEntry.ZipErrorAction = Zip.ZipErrorAction.Skip | 
|  | /// End Sub | 
|  | /// | 
|  | /// Public Sub SaveTheFile() | 
|  | ///     Dim directoryToZip As String = "fodder" | 
|  | ///     Dim directoryInArchive As String = "files" | 
|  | ///     Dim zipFileToCreate as String = "Archive.zip" | 
|  | ///     Using zipArchive As ZipFile = New ZipFile | 
|  | ///         ' set the event handler before adding any entries | 
|  | ///         AddHandler zipArchive.ZipError, AddressOf MyZipError | 
|  | ///         zipArchive.AddDirectory(directoryToZip, directoryInArchive) | 
|  | ///         zipArchive.Save(zipFileToCreate) | 
|  | ///     End Using | 
|  | /// End Sub | 
|  | /// | 
|  | /// </code> | 
|  | /// </example> | 
|  | /// | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ZipErrorAction"/> | 
|  | internal event EventHandler<ZipErrorEventArgs> ZipError; | 
|  |  | 
|  | internal bool OnZipErrorSaving(ZipEntry entry, Exception exc) | 
|  | { | 
|  | if (ZipError != null) | 
|  | { | 
|  | lock (LOCK) | 
|  | { | 
|  | var e = ZipErrorEventArgs.Saving(this.Name, entry, exc); | 
|  | ZipError(this, e); | 
|  | if (e.Cancel) | 
|  | _saveOperationCanceled = true; | 
|  | } | 
|  | } | 
|  | return _saveOperationCanceled; | 
|  | } | 
|  | #endregion | 
|  |  | 
|  | } | 
|  | } |