| // 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 | |
| } | |
| } |