// ZipFile.Events.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2008, 2009 Dino Chiesa and Microsoft Corporation.
// 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: <2010-January-11 18:14:17>
//
// ------------------------------------------------------------------
//
// This module defines the methods for issuing events from the ZipFile class.
//
// ------------------------------------------------------------------
//
using System;
using System.IO;
namespace Ionic.Zip{
public 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);
///
/// public 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"/>
public event EventHandler<SaveProgressEventArgs> SaveProgress;
internal bool OnSaveBlock(ZipEntry entry, Int64 bytesXferred, Int64 totalBytesToXfer)
{
if (SaveProgress != null)
{
lock (LOCK)
{
var e = SaveProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry,
bytesXferred, totalBytesToXfer);
SaveProgress(this, e);
if (e.Cancel)
_saveOperationCanceled = true;
}
}
return _saveOperationCanceled;
}
private void OnSaveEntry(int current, ZipEntry entry, bool before)
{
if (SaveProgress != null)
{
lock (LOCK)
{
var e = new SaveProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, entry);
SaveProgress(this, e);
if (e.Cancel)
_saveOperationCanceled = true;
}
}
}
private void OnSaveEvent(ZipProgressEventType eventFlavor)
{
if (SaveProgress != null)
{
lock (LOCK)
{
var e = new SaveProgressEventArgs(ArchiveNameForEvent, eventFlavor);
SaveProgress(this, e);
if (e.Cancel)
_saveOperationCanceled = true;
}
}
}
private void OnSaveStarted()
{
if (SaveProgress != null)
{
lock (LOCK)
{
var e = SaveProgressEventArgs.Started(ArchiveNameForEvent);
SaveProgress(this, e);
}
}
}
private void OnSaveCompleted()
{
if (SaveProgress != null)
{
lock (LOCK)
{
var e = SaveProgressEventArgs.Completed(ArchiveNameForEvent);
SaveProgress(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"/>
public event EventHandler<ReadProgressEventArgs> ReadProgress;
private void OnReadStarted()
{
if (ReadProgress != null)
{
lock (LOCK)
{
var e = ReadProgressEventArgs.Started(ArchiveNameForEvent);
ReadProgress(this, e);
}
}
}
private void OnReadCompleted()
{
if (ReadProgress != null)
{
lock (LOCK)
{
var e = ReadProgressEventArgs.Completed(ArchiveNameForEvent);
ReadProgress(this, e);
}
}
}
internal void OnReadBytes(ZipEntry entry)
{
if (ReadProgress != null)
{
lock (LOCK)
{
var e = ReadProgressEventArgs.ByteUpdate(ArchiveNameForEvent,
entry,
ReadStream.Position,
LengthOfReadStream);
ReadProgress(this, e);
}
}
}
internal void OnReadEntry(bool before, ZipEntry entry)
{
if (ReadProgress != null)
{
lock (LOCK)
{
ReadProgressEventArgs e = (before)
? ReadProgressEventArgs.Before(ArchiveNameForEvent, _entries.Count)
: ReadProgressEventArgs.After(ArchiveNameForEvent, entry, _entries.Count);
ReadProgress(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"/>
public event EventHandler<ExtractProgressEventArgs> ExtractProgress;
private void OnExtractEntry(int current, bool before, ZipEntry currentEntry, string path)
{
if (ExtractProgress != null)
{
lock (LOCK)
{
var e = new ExtractProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, currentEntry, path);
ExtractProgress(this, e);
if (e.Cancel)
_extractOperationCanceled = true;
}
}
}
// Can be called from within ZipEntry._ExtractOne.
internal bool OnExtractBlock(ZipEntry entry, Int64 bytesWritten, Int64 totalBytesToWrite)
{
if (ExtractProgress != null)
{
lock (LOCK)
{
var e = ExtractProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry,
bytesWritten, totalBytesToWrite);
ExtractProgress(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)
{
if (ExtractProgress != null)
{
lock (LOCK)
{
var e = (before)
? ExtractProgressEventArgs.BeforeExtractEntry(ArchiveNameForEvent, entry, path)
: ExtractProgressEventArgs.AfterExtractEntry(ArchiveNameForEvent, entry, path);
ExtractProgress(this, e);
if (e.Cancel)
_extractOperationCanceled = true;
}
}
return _extractOperationCanceled;
}
internal bool OnExtractExisting(ZipEntry entry, string path)
{
if (ExtractProgress != null)
{
lock (LOCK)
{
var e = ExtractProgressEventArgs.ExtractExisting(ArchiveNameForEvent, entry, path);
ExtractProgress(this, e);
if (e.Cancel)
_extractOperationCanceled = true;
}
}
return _extractOperationCanceled;
}
private void OnExtractAllCompleted(string path)
{
if (ExtractProgress != null)
{
lock (LOCK)
{
var e = ExtractProgressEventArgs.ExtractAllCompleted(ArchiveNameForEvent,
path );
ExtractProgress(this, e);
}
}
}
private void OnExtractAllStarted(string path)
{
if (ExtractProgress != null)
{
lock (LOCK)
{
var e = ExtractProgressEventArgs.ExtractAllStarted(ArchiveNameForEvent,
path );
ExtractProgress(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.
/// </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"/>
public event EventHandler<AddProgressEventArgs> AddProgress;
private void OnAddStarted()
{
if (AddProgress != null)
{
lock (LOCK)
{
var e = AddProgressEventArgs.Started(ArchiveNameForEvent);
AddProgress(this, e);
}
}
}
private void OnAddCompleted()
{
if (AddProgress != null)
{
lock (LOCK)
{
var e = AddProgressEventArgs.Completed(ArchiveNameForEvent);
AddProgress(this, e);
}
}
}
internal void AfterAddEntry(ZipEntry entry)
{
if (AddProgress != null)
{
lock (LOCK)
{
var e = AddProgressEventArgs.AfterEntry(ArchiveNameForEvent, entry, _entries.Count);
AddProgress(this, e);
}
}
}
#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>
///
/// </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"/>
public 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
}
}
|