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