// ZipForm.cs // ------------------------------------------------------------------ // // Copyright (c) 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 // // ------------------------------------------------------------------ // using System; using System.Collections.Generic; using System.Threading; using System.Windows.Forms; using Ionic.Zip; namespace Ionic.Zip.Forms { public partial class ZipForm : Form { delegate void ZipProgress(ZipProgressEventArgs e); delegate void ButtonClick(object sender, EventArgs e); HiResTimer _hrt; public ZipForm() { InitializeComponent(); InitializeListboxes(); FixTitle(); FillFormFromRegistry(); AdoptProgressBars(); SetListView2(); SetTextBoxes(); // first run only if (numRuns == 0) this.tabControl1.SelectedIndex = 2; // help/about tab } // This constructor works to load zips from the command line. // It also works to allow "open With..." from Windows Explorer. public ZipForm(string[] args) : this() { if (args != null && args.Length >= 1 && args[0] != null) _initialFileToLoad = args[0]; } // in ZipForm.DragDrop.cs partial void SetDragDrop(); private void SetTextBoxes() { this.tbComment.Text= TB_COMMENT_NOTE; this.tbDefaultExtractDirectory.Text= TB_EXTRACT_DIR_NOTE; this.tbExeOnUnpack.Text= TB_EXE_ON_UNPACK_NOTE; // set autocomplete on a few textboxes this.tbDirectoryToZip.AutoCompleteMode = AutoCompleteMode.Suggest; this.tbDirectoryToZip.AutoCompleteSource = AutoCompleteSource.FileSystemDirectories; this.tbExtractDir.AutoCompleteMode = AutoCompleteMode.Suggest; this.tbExtractDir.AutoCompleteSource = AutoCompleteSource.FileSystemDirectories; this.tbZipToOpen.AutoCompleteMode = AutoCompleteMode.Suggest; this.tbZipToOpen.AutoCompleteSource = AutoCompleteSource.FileSystem; this.tbZipToCreate.AutoCompleteMode = AutoCompleteMode.Suggest; this.tbZipToCreate.AutoCompleteSource = AutoCompleteSource.FileSystem; this.tbSelectionToExtract.AutoCompleteMode = AutoCompleteMode.Suggest; this.tbSelectionToExtract.AutoCompleteSource = AutoCompleteSource.CustomSource; this.tbSelectionToExtract.AutoCompleteCustomSource = _selectionCompletions; this.tbSelectionToZip.AutoCompleteMode = AutoCompleteMode.Suggest; this.tbSelectionToZip.AutoCompleteSource = AutoCompleteSource.CustomSource; this.tbSelectionToZip.AutoCompleteCustomSource = _selectionCompletions; tbExeOnUnpack_TextChanged(null, null); } private void SetListView2() { // The listview2 is a ListViewEx control, an extension of // System.Windows.Forms.ListView that allows editing of subitems using arbitrary // controls. You can have a textbox, a datepicker, or other controls. // I want the user to be able to modify the directory-in-archive value in the // list, which is why ListViewEx is interesting. // I also want a checkbox associated to each list item, but I don't want the // checkbox attached to the first subitem, as it normally is in a ListView. So I // put an empty string as the main ListView item (subitem #0), and then the // filename and directory-in-archive value in the 2nd and 3rd columns (subitems 1 // and 2). This way, the checkbox gets its own column. // Next twist is I want the checkbox label to be uneditable, which is easy // by just installing a listView2_BeforeLabelEdit method and always cancelling // it. (e.CancelEdit = true). // And then there is a "master checkbox" at the column header that indicates // whether the state of all checkboxes in the list is the same. With the "check // change" of any item in the list I want to see if the master should be checked // or unchecked. // The final thing is I want the checkbox for each item to change state only if I // click on the checkbox itself, rather than "anywhere in the item row". this.listView2.SubItemClicked += new ListViewEx.SubItemEventHandler(listView2_SubItemClicked); this.listView2.SubItemEndEditing += new ListViewEx.SubItemEndEditingEventHandler(listView2_SubItemEndEditing); this.listView2.DoubleClickActivation = true; SetDragDrop(); } private void AdoptProgressBars() { tabControl1_SelectedIndexChanged(null, null); } private void FixTitle() { this.Text = String.Format("DotNetZip Tool v{0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()); } private void InitializeListboxes() { InitEncodingsList(); InitFlavorList(); InitZip64List(); InitCompMethodList(); InitCompressionLevelList(); InitEncryptionList(); InitSplitBox(); InitExtractExistingFileList(); } private void InitSplitBox() { string[] values = { "-none-", "64kb", "128kb", "256kb", "512kb", "1mb", "2mb", "4mb", "8mb", "16mb", "32mb", "64mb", "128mb", "256mb", "512mb", "1gb" }; foreach (var value in values) this.comboSplit.Items.Add(value); this.comboSplit.SelectedIndex = 0; this.comboSplit.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; //this.comboSplit.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; } private void InitEncryptionList() { List _EncryptionNames = new List(Enum.GetNames(typeof(Ionic.Zip.EncryptionAlgorithm))); foreach (var name in _EncryptionNames) { if (name != "Unsupported") comboEncryption.Items.Add(name); } // select the first item: comboEncryption.SelectedIndex = 0; this.tbPassword.Text = ""; } private void InitExtractExistingFileList() { List _ExtractActionNames = new List(Enum.GetNames(typeof(Ionic.Zip.ExtractExistingFileAction))); foreach (var name in _ExtractActionNames) { if (!name.StartsWith("Invoke")) { if (name.StartsWith("Throw")) comboExistingFileAction.Items.Add("Stop"); else comboExistingFileAction.Items.Add(name); } } // select the first item: comboExistingFileAction.SelectedIndex = 0; } private void InitEncodingsList() { List _EncodingNames = new List(); var e = System.Text.Encoding.GetEncodings(); foreach (var e1 in e) { if (!_EncodingNames.Contains(e1.Name)) if (!_EncodingNames.Contains(e1.Name.ToUpper())) if (!_EncodingNames.Contains(e1.Name.ToLower())) if (e1.Name != "IBM437" && e1.Name != "utf-8") _EncodingNames.Add(e1.Name); } _EncodingNames.Sort(); comboEncoding.Items.Add("zip default (IBM437)"); comboEncoding.Items.Add("utf-8"); foreach (var name in _EncodingNames) { comboEncoding.Items.Add(name); } // select the first item: comboEncoding.SelectedIndex = 0; // also set the encoding usage List _UsageNames = new List(Enum.GetNames(typeof(Ionic.Zip.ZipOption))); _UsageNames.Sort(); foreach (var name in _UsageNames) { if (!name.StartsWith("Default")) comboEncodingUsage.Items.Add(name); } // select the first item: comboEncodingUsage.SelectedIndex = 0; } private void InitCompressionLevelList() { List _CompressionLevelNames = new List(Enum.GetNames(typeof(Ionic.Zlib.CompressionLevel))); _CompressionLevelNames.Sort(); foreach (var name in _CompressionLevelNames) { if (!name.StartsWith("Level")) { comboCompLevel.Items.Add(name); } } // select the 2nd item, "Default": comboCompLevel.SelectedIndex = 2; } private void InitFlavorList() { this.comboFlavor.Items.Add("traditional Zip"); this.comboFlavor.Items.Add("Self-extractor (GUI)"); this.comboFlavor.Items.Add("Self-extractor (CMD)"); // select the first item: comboFlavor.SelectedIndex = 0; } private void InitZip64List() { var _Names = new List(Enum.GetNames(typeof(Ionic.Zip.Zip64Option))); _Names.Sort(); foreach (var name in _Names) { if (!name.StartsWith("Default")) comboZip64.Items.Add(name); } // select the first item: comboZip64.SelectedIndex = 0; } private void InitCompMethodList() { var _Names = new List(Enum.GetNames(typeof(Ionic.Zip.CompressionMethod))); _Names.Sort(); foreach (var name in _Names) { if (!name.StartsWith("Default")) comboCompMethod.Items.Add(name); } // select DEFLATE: comboCompMethod.SelectedIndex = 1; } private void KickoffZipup() { if (String.IsNullOrEmpty(this.tbDirectoryToZip.Text)) return; if (!System.IO.Directory.Exists(this.tbDirectoryToZip.Text)) { var dlgResult = MessageBox.Show(String.Format("The directory you have specified ({0}) does not exist.", this.tbZipToCreate.Text), "Not gonna happen", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } if (this.tbZipToCreate.Text == null || this.tbZipToCreate.Text == "") return; // check for existence of the zip file: if (System.IO.File.Exists(this.tbZipToCreate.Text)) { var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) already exists. Do you want to overwrite this file?", this.tbZipToCreate.Text), "Confirmation is Required", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (dlgResult != DialogResult.Yes) return; System.IO.File.Delete(this.tbZipToCreate.Text); } // check for a valid zip file name: string extension = System.IO.Path.GetExtension(this.tbZipToCreate.Text); if ((extension != ".exe" && (this.comboFlavor.SelectedIndex == 1 || this.comboFlavor.SelectedIndex == 2)) || (extension != ".zip" && this.comboFlavor.SelectedIndex == 0)) { var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) has a non-standard extension ({1}) for this zip flavor. Do you want to continue anyway?", this.tbZipToCreate.Text, extension), "Hold on there, pardner!", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (dlgResult != DialogResult.Yes) return; System.IO.File.Delete(this.tbZipToCreate.Text); } _hrt = new HiResTimer(); _hrt.Start(); _working = true; _operationCanceled = false; _nFilesCompleted = 0; _totalBytesAfterCompress = 0; _totalBytesBeforeCompress = 0; PauseUI("Zipping..."); lblStatus.Text = "Zipping..."; var options = new SaveWorkerOptions { ZipName = this.tbZipToCreate.Text, Selection = this.tbSelectionToZip.Text, TraverseJunctions = this.chkTraverseJunctions.Checked, Encoding = "ibm437", //EncodingUsage = ZipOption.Always, ZipFlavor = this.comboFlavor.SelectedIndex, Password = this.tbPassword.Text, WindowsTimes = this.chkWindowsTime.Checked, UnixTimes = this.chkUnixTime.Checked, RemoveFilesAfterExe = this.chkRemoveFiles.Checked, ExtractExistingFile = this.comboExistingFileAction.SelectedIndex, }; if (this.comboEncoding.SelectedIndex != 0) options.Encoding = this.comboEncoding.SelectedItem.ToString(); options.Encryption = (EncryptionAlgorithm) Enum.Parse(typeof(EncryptionAlgorithm), this.comboEncryption.SelectedItem.ToString()); options.CompressionLevel = (Ionic.Zlib.CompressionLevel) Enum.Parse(typeof(Ionic.Zlib.CompressionLevel), this.comboCompLevel.SelectedItem.ToString()); options.CompressionMethod = (Ionic.Zip.CompressionMethod) Enum.Parse(typeof(Ionic.Zip.CompressionMethod), this.comboCompMethod.SelectedItem.ToString()); options.EncodingUsage = (Ionic.Zip.ZipOption) Enum.Parse(typeof(Ionic.Zip.ZipOption), this.comboEncodingUsage.SelectedItem.ToString()); string arg = this.comboSplit.SelectedItem.ToString().ToUpper(); try { int multiplier = 1; int suffixLength = 0; if (arg.EndsWith("KB")) { multiplier = 1024; suffixLength = 2; } else if (arg.EndsWith("K")) { multiplier = 1024; suffixLength = 1; } else if (arg.EndsWith("MB")) { multiplier = 1024*1024; suffixLength = 2; } else if (arg.EndsWith("M")) { multiplier = 1024*1024; suffixLength = 1; } else if (arg.EndsWith("GB")) { multiplier = 1024*1024*1024; suffixLength = 2; } else if (arg.EndsWith("G")) { multiplier = 1024*1024*1024; suffixLength = 1; } if (suffixLength > 0) { options.MaxSegmentSize = Int32.Parse(arg.Substring(0,arg.Length-suffixLength)) * multiplier; } else options.MaxSegmentSize = Int32.Parse(arg); } catch { // just reset to "none" this.comboSplit.SelectedIndex = 0; options.MaxSegmentSize = 0; } options.Zip64 = (Zip64Option)Enum.Parse(typeof(Zip64Option), this.comboZip64.SelectedItem.ToString()); //this.listView2.Items.ToList(); var entriesList = new System.Collections.ArrayList(this.listView2.Items); options.Entries = System.Array.ConvertAll((ListViewItem[])entriesList.ToArray(typeof(ListViewItem)), (item) => { return new ItemToAdd { LocalFileName = item.SubItems[1].Text, DirectoryInArchive = item.SubItems[2].Text, FileNameInArchive = item.SubItems[3].Text, }; } ); string compress = (options.CompressionMethod == Ionic.Zip.CompressionMethod.Deflate) ? "Deflate level" + options.CompressionLevel.ToString() : options.CompressionMethod.ToString(); options.Comment = String.Format("Encoding:{0} || Compression:{1} || Encrypt:{2} || ZIP64:{3}\r\nCreated at {4} || {5}\r\n", options.Encoding, compress, (this.tbPassword.Text == "") ? "None" : options.Encryption.ToString(), 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; if (this.tbExeOnUnpack.Text != TB_EXE_ON_UNPACK_NOTE) options.ExeOnUnpack = this.tbExeOnUnpack.Text; if (this.tbDefaultExtractDirectory.Text != TB_EXTRACT_DIR_NOTE) options.ExtractDirectory = this.tbDefaultExtractDirectory.Text; _workerThread = new Thread(this.DoSave); _workerThread.Name = "Zip Saver thread"; _workerThread.Start(options); this.Cursor = Cursors.WaitCursor; } private string FlavorToString(int p) { if (p == 2) return "SFX-CMD"; if (p == 1) return "SFX-GUI"; return "ZIP"; } private bool _firstFocusInCommentTextBox = true; private void tbComment_Enter(object sender, EventArgs e) { if (_firstFocusInCommentTextBox) { tbComment.Text = ""; tbComment.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); tbComment.ForeColor = System.Drawing.SystemColors.WindowText; _firstFocusInCommentTextBox = false; } } private void tbComment_Leave(object sender, EventArgs e) { string TextInTheBox = tbComment.Text; if ((TextInTheBox == null) || (TextInTheBox == "")) { this.tbComment.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.tbComment.ForeColor = System.Drawing.SystemColors.InactiveCaption; _firstFocusInCommentTextBox = true; this.tbComment.Text = TB_COMMENT_NOTE; } } private bool _firstFocusInExtractDirTextBox = true; private void tbDefaultExtractDirectory_Enter(object sender, EventArgs e) { if (_firstFocusInExtractDirTextBox) { tbDefaultExtractDirectory.Text = ""; tbDefaultExtractDirectory.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); tbDefaultExtractDirectory.ForeColor = System.Drawing.SystemColors.WindowText; _firstFocusInExtractDirTextBox = false; } } private void tbDefaultExtractDirectory_Leave(object sender, EventArgs e) { string TextInTheBox = tbDefaultExtractDirectory.Text; if ((TextInTheBox == null) || (TextInTheBox == "")) { this.tbDefaultExtractDirectory.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.tbDefaultExtractDirectory.ForeColor = System.Drawing.SystemColors.InactiveCaption; _firstFocusInExtractDirTextBox = true; this.tbDefaultExtractDirectory.Text = TB_EXTRACT_DIR_NOTE; } } // I want the values in the combobox to be right-aligned. private int delta = 0; private void comboBox1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e) { var rc = new System.Drawing.Rectangle(e.Bounds.X + delta, e.Bounds.Y + delta, e.Bounds.Width - delta, e.Bounds.Height - delta); var sf = new System.Drawing.StringFormat { Alignment = System.Drawing.StringAlignment.Far }; string str = (string)comboSplit.Items[e.Index]; if (e.State == (DrawItemState.Selected | DrawItemState.NoAccelerator | DrawItemState.NoFocusRect) || e.State == DrawItemState.Selected) { e.Graphics.FillRectangle(new System.Drawing.SolidBrush(System.Drawing.Color.CornflowerBlue), rc); e.Graphics.DrawString(str, this.comboSplit.Font, new System.Drawing.SolidBrush(System.Drawing.Color.Cyan), rc, sf); } else { e.Graphics.FillRectangle(new System.Drawing.SolidBrush(System.Drawing.Color.White), rc); e.Graphics.DrawString(str, this.comboSplit.Font, new System.Drawing.SolidBrush(System.Drawing.Color.Black), rc, sf); } } private bool _firstFocusInExeTextBox = true; private void tbExeOnUnpack_Enter(object sender, EventArgs e) { if (_firstFocusInExeTextBox) { tbExeOnUnpack.Text = ""; tbExeOnUnpack.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); tbExeOnUnpack.ForeColor = System.Drawing.SystemColors.WindowText; _firstFocusInExeTextBox = false; } } private void tbExeOnUnpack_Leave(object sender, EventArgs e) { string TextInTheBox = tbExeOnUnpack.Text; if ((TextInTheBox == null) || (TextInTheBox == "")) { this.tbExeOnUnpack.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.tbExeOnUnpack.ForeColor = System.Drawing.SystemColors.InactiveCaption; _firstFocusInExeTextBox = true; this.tbExeOnUnpack.Text = TB_EXE_ON_UNPACK_NOTE; this.label18.Enabled = false; this.chkRemoveFiles.Enabled = false; } else { this.label18.Enabled = true; this.chkRemoveFiles.Enabled = true; } } private void tbExeOnUnpack_TextChanged(object sender, EventArgs e) { if (this.tbExeOnUnpack.Text != TB_EXE_ON_UNPACK_NOTE && this.tbExeOnUnpack.Text != "") { this.label18.Enabled = true; this.chkRemoveFiles.Enabled = true; } else { this.label18.Enabled = false; this.chkRemoveFiles.Enabled = false; } } private void SetProgressBars() { if (this.progressBar1.InvokeRequired) { this.progressBar1.Invoke(new MethodInvoker(this.SetProgressBars)); //this.progressBar1.Invoke(new ProgressBarSetup(this.SetProgressBars), new object[] { count }); } else { this.progressBar1.Value = 0; this.progressBar1.Maximum = _totalEntriesToProcess; this.progressBar1.Minimum = 0; this.progressBar1.Step = 1; this.progressBar2.Value = 0; this.progressBar2.Minimum = 0; this.progressBar2.Maximum = 1; // will be set later, for each entry. this.progressBar2.Step = 1; } } private void DoSave(Object p) { SaveWorkerOptions options = p as SaveWorkerOptions; try { using (var zip1 = new ZipFile()) { zip1.CompressionMethod = options.CompressionMethod; zip1.CompressionLevel = options.CompressionLevel; zip1.AlternateEncoding = System.Text.Encoding.GetEncoding(options.Encoding); zip1.AlternateEncodingUsage = options.EncodingUsage; zip1.Comment = options.Comment; zip1.MaxOutputSegmentSize = options.MaxSegmentSize; zip1.Password = (options.Password != "") ? options.Password : null; zip1.Encryption = options.Encryption; zip1.EmitTimesInWindowsFormatWhenSaving = options.WindowsTimes; zip1.EmitTimesInUnixFormatWhenSaving = options.UnixTimes; zip1.AddDirectoryWillTraverseReparsePoints = options.TraverseJunctions; foreach (ItemToAdd item in options.Entries) { var e = zip1.AddItem(item.LocalFileName, item.DirectoryInArchive); // use a different name in the archive if appropriate if (!String.IsNullOrEmpty(item.FileNameInArchive) && item.FileNameInArchive != System.IO.Path.GetFileName(item.LocalFileName)) e.FileName = item.FileNameInArchive; } _totalEntriesToProcess = zip1.EntryFileNames.Count; SetProgressBars(); zip1.TempFileFolder = System.IO.Path.GetDirectoryName(options.ZipName); zip1.SaveProgress += this.zip1_SaveProgress; zip1.UseZip64WhenSaving = options.Zip64; if (options.ZipFlavor == 2 || options.ZipFlavor == 1) { SelfExtractorSaveOptions sfxOptions = new SelfExtractorSaveOptions() { Flavor = (options.ZipFlavor == 1)?SelfExtractorFlavor.WinFormsApplication: SelfExtractorFlavor.ConsoleApplication, DefaultExtractDirectory = options.ExtractDirectory, PostExtractCommandLine = options.ExeOnUnpack, RemoveUnpackedFilesAfterExecute = options.RemoveFilesAfterExe, ExtractExistingFile = (ExtractExistingFileAction) options.ExtractExistingFile, }; zip1.SaveSelfExtractor(options.ZipName, sfxOptions); } else zip1.Save(options.ZipName); } } catch (System.Exception exc1) { MessageBox.Show(String.Format("Exception while zipping:\n{0}\n\n{1}", exc1.Message, exc1.StackTrace.ToString())); 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: TempArchiveSaved(); break; } if (_operationCanceled) e.Cancel = true; } private void TempArchiveSaved() { if (this.lblStatus.InvokeRequired) { this.lblStatus.Invoke(new MethodInvoker(this.TempArchiveSaved)); } else { System.TimeSpan ts = new System.TimeSpan(0, 0, (int)_hrt.Seconds); lblStatus.Text = String.Format("Temp archive saved ({0})...{1}...", ts.ToString(), (this.comboFlavor.SelectedIndex == 0) ? "finishing" : "compiling SFX"); } } private void SaveCompleted() { if (this.lblStatus.InvokeRequired) { this.lblStatus.Invoke(new MethodInvoker(this.SaveCompleted)); } else { _hrt.Stop(); System.TimeSpan ts = new System.TimeSpan(0, 0, (int)_hrt.Seconds); lblStatus.Text = String.Format("Done, Compressed {0} files, {1:N0}% of original, time: {2}", _nFilesCompleted, (100.00 * _totalBytesAfterCompress) / _totalBytesBeforeCompress, ts.ToString()); ResetUiState(); } } private void StepArchiveProgress(ZipProgressEventArgs e) { if (this.progressBar1.InvokeRequired) { this.progressBar1.Invoke(new ZipProgress(this.StepArchiveProgress), new object[] { e }); } else { if (!_operationCanceled) { _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(); #if NOT_SPEEDY // Sleep here just to show the progress bar, when the number of files is small, // or when all done. // You may not want this for actual use! if (this.progressBar2.Value == this.progressBar2.Maximum) Thread.Sleep(350); else if (_entriesToZip < 10) Thread.Sleep(350); else if (_entriesToZip < 20) Thread.Sleep(200); else if (_entriesToZip < 30) Thread.Sleep(100); else if (_entriesToZip < 45) Thread.Sleep(80); else if (_entriesToZip < 75) Thread.Sleep(40); // more than 75 entries, don't sleep at all. #endif } } } private void StepEntryProgress(ZipProgressEventArgs e) { if (this.progressBar2.InvokeRequired) { this.progressBar2.Invoke(new ZipProgress(this.StepEntryProgress), new object[] { e }); } else { if (!_operationCanceled) { if (this.progressBar2.Maximum == 1) { // reset Int64 entryMax = e.TotalBytesToTransfer; Int64 absoluteMax = System.Int32.MaxValue; _progress2MaxFactor = 0; while (entryMax > absoluteMax) { entryMax /= 2; _progress2MaxFactor++; } if ((int)entryMax < 0) entryMax *= -1; this.progressBar2.Maximum = (int)entryMax; lblStatus.Text = String.Format("{0} of {1} files...({2})", _nFilesCompleted + 1, _totalEntriesToProcess, e.CurrentEntry.FileName); } // downcast is safe here because we have shifted e.BytesTransferred int xferred = (int)(e.BytesTransferred >> _progress2MaxFactor); this.progressBar2.Value = (xferred >= this.progressBar2.Maximum) ? this.progressBar2.Maximum : xferred; this.Update(); } } } private void btnDirBrowse_Click(object sender, EventArgs e) { var dlg1 = new Ionic.Utils.FolderBrowserDialogEx { Description = "Select a folder to zip up:", ShowNewFolderButton = false, ShowEditBox = true, //NewStyle = false, SelectedPath = this.tbDirectoryToZip.Text, ShowFullPathInEditBox = true, }; dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer; var result = dlg1.ShowDialog(); if (result == DialogResult.OK) { this.tbDirectoryToZip.Text = dlg1.SelectedPath; this.tbDirectoryInArchive.Text = System.IO.Path.GetFileName(this.tbDirectoryToZip.Text); } } private void btnCreateZipBrowse_Click(object sender, EventArgs e) { var dlg1 = new SaveFileDialog { OverwritePrompt = false, Title = "Where would you like to save the generated Zip file?", Filter = "ZIP files|*.zip", }; try { dlg1.FileName = System.IO.Path.GetFileName(this.tbZipToCreate.Text); } catch { dlg1.FileName = ""; } try { dlg1.InitialDirectory = System.IO.Path.GetDirectoryName(this.tbZipToCreate.Text); } catch { dlg1.InitialDirectory = ""; } var result = dlg1.ShowDialog(); if (result == DialogResult.OK) { this.tbZipToCreate.Text = dlg1.FileName; } } private void btnZipup_Click(object sender, EventArgs e) { // Do not start zipping while editing a textbox // in listView2. if (!textBox1.Visible) 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 { _operationCanceled = true; lblStatus.Text = "Canceled..."; ResetUiState(); } } private void comboFlavor_SelectedIndexChanged(object sender, EventArgs e) { if (this.comboFlavor.SelectedIndex == 1 || this.comboFlavor.SelectedIndex == 2) { // intelligently change the name of the thing to create // It's an SFX, swap out ZIP and insert EXE if (this.tbZipToCreate.Text.ToUpper().EndsWith(".ZIP")) { tbZipToCreate.Text = System.Text.RegularExpressions.Regex.Replace(tbZipToCreate.Text, "(?i:)\\.zip$", ".exe"); } // enable/disable other dependent UI elements this.label17.Enabled = false; this.comboSplit.Enabled = false; this.label15.Enabled = true; this.tbDefaultExtractDirectory.Enabled = true; this.label16.Enabled = true; this.tbExeOnUnpack.Enabled = true; this.label18.Enabled = true; this.chkRemoveFiles.Enabled = true; } else if (this.comboFlavor.SelectedIndex == 0) { // intelligently change the name of the thing to create // It's a regular ZIP, so swap out EXE and insert ZIP if (this.tbZipToCreate.Text.ToUpper().EndsWith(".EXE")) { tbZipToCreate.Text = System.Text.RegularExpressions.Regex.Replace(tbZipToCreate.Text, "(?i:)\\.exe$", ".zip"); } // enable/disable other dependent UI elements this.label17.Enabled = true; this.comboSplit.Enabled = true; this.label15.Enabled = false; this.tbDefaultExtractDirectory.Enabled = false; this.label16.Enabled = false; this.tbExeOnUnpack.Enabled = false; this.label18.Enabled = false; this.chkRemoveFiles.Enabled = false; } } private void comboEncryption_SelectedIndexChanged(object sender, EventArgs e) { //this.tbPassword.Enabled = (this.comboBox3.SelectedItem.ToString() != "None"); if (this.comboEncryption.SelectedIndex == 0) { this.label9.Enabled = false; this.tbPassword.Enabled = false; this.chkHidePassword.Enabled = false; } else { this.label9.Enabled = true; this.tbPassword.Enabled = true; this.chkHidePassword.Enabled = true; } } private void comboCompMethod_SelectedIndexChanged(object sender, EventArgs e) { if (this.comboCompMethod.SelectedIndex == 1) // DEFLATE { this.label4.Enabled = true; this.comboCompLevel.Enabled = true; } else { this.label4.Enabled = false; this.comboCompLevel.Enabled = false; } } private void comboEncoding_SelectedIndexChanged(object sender, EventArgs e) { this.comboEncodingUsage.Enabled = (this.comboEncoding.SelectedIndex != 0); } private void checkBox1_CheckedChanged(object sender, EventArgs e) { this.tbPassword.PasswordChar = (this.chkHidePassword.Checked) ? '*' : '\0'; } private void ResetUiState() { this.btnZipUp.Text = "Zip it!"; this.btnZipUp.Enabled = true; this.btnCancel.Text = "Cancel"; this.btnCancel.Enabled = false; this.btnExtract.Text = "Extract"; this.btnExtractDirBrowse.Enabled = true; this.btnZipupDirBrowse.Enabled = true; this.btnReadZipBrowse.Enabled = true; this.btnClearItemsToZip.Enabled = true; this.btnCreateZipBrowse.Enabled = true; this.progressBar1.Value = 0; this.progressBar2.Value = 0; this.Cursor = Cursors.Default; if (_workerThread != null) if (!_workerThread.IsAlive) _workerThread.Join(); _working = false; } private void SelectNamedEncoding(string s) { _SelectComboBoxItem(this.comboEncoding, s); } private void SelectNamedEncodingUsage(string s) { _SelectComboBoxItem(this.comboEncodingUsage, s); } private void SelectNamedCompressionLevel(string s) { _SelectComboBoxItem(this.comboCompLevel, s); } private void SelectNamedCompressionMethod(string s) { _SelectComboBoxItem(this.comboCompMethod, s); } private void SelectNamedEncryption(string s) { _SelectComboBoxItem(this.comboEncryption, s); //tbPassword.Text = ""; comboEncryption_SelectedIndexChanged(null, null); } private void _SelectComboBoxItem(ComboBox c, string s) { for (int i = 0; i < c.Items.Count; i++) { if (c.Items[i].ToString() == s) { c.SelectedIndex = i; break; } } } private void ZipForm_FormClosing(object sender, FormClosingEventArgs e) { SaveFormToRegistry(); } private void btnZipBrowse_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.InitialDirectory = (System.IO.File.Exists(this.tbZipToOpen.Text) ? System.IO.Path.GetDirectoryName(this.tbZipToOpen.Text) : this.tbZipToOpen.Text); openFileDialog1.Filter = "zip files|*.zip|EXE files|*.exe|All Files|*.*"; openFileDialog1.FilterIndex = 1; openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { this.tbZipToOpen.Text = openFileDialog1.FileName; if (System.IO.File.Exists(this.tbZipToOpen.Text)) btnOpen_Click(sender, e); } } string _DisplayedZip = null; private void btnOpen_Click(object sender, EventArgs e) { if (!System.IO.File.Exists(this.tbZipToOpen.Text)) return; DisplayZipFile(this.tbZipToOpen.Text); } private void DisplayZipFile(string zipFile) { try { listView1.Clear(); listView1.BeginUpdate(); string[] columnHeaders = new string[] { "n", "name", "lastmod", "original", "ratio", "compressed", "enc?", "CRC" }; foreach (string label in columnHeaders) { SortableColumnHeader ch = new SortableColumnHeader(label); if (label != "name" && label != "lastmod") ch.TextAlign = HorizontalAlignment.Right; listView1.Columns.Add(ch); } int n = 1; var readOptions = new ReadOptions { Encoding = (comboEncoding.SelectedIndex > 0) ? System.Text.Encoding.GetEncoding(comboEncoding.SelectedItem.ToString()) : System.Text.Encoding.GetEncoding("IBM437") }; using (ZipFile zip = ZipFile.Read(zipFile, readOptions)) { foreach (ZipEntry entry in zip.EntriesSorted) { ListViewItem item = new ListViewItem(n.ToString()); n++; string[] subitems = new string[] { entry.FileName.Replace("/","\\"), entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), entry.UncompressedSize.ToString(), String.Format("{0,5:F0}%", entry.CompressionRatio), entry.CompressedSize.ToString(), (entry.UsesEncryption) ? "Y" : "N", String.Format("{0:X8}", entry.Crc)}; foreach (String s in subitems) { ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem(); subitem.Text = s; item.SubItems.Add(subitem); } this.listView1.Items.Add(item); } } this.btnExtract.Enabled = true; _DisplayedZip = zipFile; this.listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); this.listView1.EndUpdate(); } catch (Exception exc1) { this.listView1.Clear(); this.listView1.EndUpdate(); MessageBox.Show(String.Format("There was a problem opening that file! [file={0}, problem={1}]", zipFile, exc1.Message), "Whoops!", MessageBoxButtons.OK); } } private void btnExtractDirBrowse_Click(object sender, EventArgs e) { // pop a dialog to ask where to extract // Configure the "select folder" dialog box //_folderName = tbDirName.Text; //_folderName = (System.IO.Directory.Exists(_folderName)) ? _folderName : ""; var dlg1 = new Ionic.Utils.FolderBrowserDialogEx { Description = "Select a folder to extract to:", ShowNewFolderButton = true, ShowEditBox = true, //NewStyle = false, SelectedPath = tbExtractDir.Text, ShowFullPathInEditBox = true, }; dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer; var result = dlg1.ShowDialog(); if (result == DialogResult.OK) { this.tbExtractDir.Text = dlg1.SelectedPath; // actually extract the files } } private void btnExtract_Click(object sender, EventArgs e) { if (!System.IO.File.Exists(_DisplayedZip)) return; KickoffExtract(); } private void KickoffExtract() { if (String.IsNullOrEmpty(this.tbExtractDir.Text)) return; _hrt = new HiResTimer(); _hrt.Start(); _working = true; _operationCanceled = false; _nFilesCompleted = 0; _totalBytesAfterCompress = 0; _totalBytesBeforeCompress = 0; PauseUI(null); lblStatus.Text = "Extracting..."; var options = new ExtractWorkerOptions { ExtractLocation = this.tbExtractDir.Text, Selection = this.tbSelectionToExtract.Text, OpenExplorer = this.chkOpenExplorer.Checked, ExtractExisting = (ExtractExistingFileAction) comboExistingFileAction.SelectedIndex, }; _workerThread = new Thread(this.DoExtract); _workerThread.Name = "Zip Extractor thread"; _workerThread.Start(options); this.Cursor = Cursors.WaitCursor; } private void PauseUI(string msg) { // this set for Zipping if (msg != null) this.btnZipUp.Text = msg; this.btnZipUp.Enabled = false; this.btnZipupDirBrowse.Enabled = false; this.btnCreateZipBrowse.Enabled = false; this.btnClearItemsToZip.Enabled = false; this.btnCancel.Enabled = true; // this for Extract this.btnExtract.Enabled = false; this.btnExtract.Text = "working..."; this.btnExtractDirBrowse.Enabled = false; this.btnCancel.Enabled = true; this.btnReadZipBrowse.Enabled = false; } private void zip_ExtractProgress(object sender, ExtractProgressEventArgs e) { if (e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten) { StepEntryProgress(e); } else if (e.EventType == ZipProgressEventType.Extracting_AfterExtractEntry) { StepArchiveProgress(e); } if (_setCancel) e.Cancel = true; } private void OnExtractDone() { if (this.lblStatus.InvokeRequired) { this.lblStatus.Invoke(new MethodInvoker(this.OnExtractDone)); } else { _hrt.Stop(); System.TimeSpan ts = new System.TimeSpan(0, 0, (int)_hrt.Seconds); lblStatus.Text = String.Format("Done, Extracted {0} files, time: {1}", _nFilesCompleted, ts.ToString()); ResetUiState(); // remember the successful selection strings if (!_selectionCompletions.Contains(this.tbSelectionToZip.Text)) { if (_selectionCompletions.Count >= _MaxMruListSize) _selectionCompletions.RemoveAt(0); _selectionCompletions.Add(this.tbSelectionToZip.Text); } } } bool _setCancel = false; private void DoExtract(object p) { ExtractWorkerOptions options = p as ExtractWorkerOptions; bool extractCancelled = false; _setCancel = false; string currentPassword = ""; try { using (var zip = ZipFile.Read(_DisplayedZip)) { System.Collections.Generic.ICollection collection = null; if (String.IsNullOrEmpty(options.Selection)) collection = zip.Entries; else collection = zip.SelectEntries(options.Selection); _totalEntriesToProcess = collection.Count; zip.ExtractProgress += zip_ExtractProgress; SetProgressBars(); foreach (global::Ionic.Zip.ZipEntry entry in collection) { if (_setCancel) { extractCancelled = true; break; } if (entry.Encryption == global::Ionic.Zip.EncryptionAlgorithm.None) { try { entry.Extract(options.ExtractLocation, options.ExtractExisting); } catch (Exception ex1) { string msg = String.Format("Faisled to extract entry {0} -- {1}", entry.FileName, ex1.Message.ToString()); DialogResult result = MessageBox.Show(msg, String.Format("Error Extracting {0}", entry.FileName), MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); if (result == DialogResult.Cancel) { _setCancel = true; extractCancelled = true; break; } } } else { bool done = false; while (!done) { if (currentPassword == "") { string t = PromptForPassword(entry.FileName); if (t == "") { done = true; // escape ExtractWithPassword loop continue; } currentPassword = t; } if (currentPassword == null) // cancel all { _setCancel = true; currentPassword = ""; break; } try { entry.ExtractWithPassword(options.ExtractLocation, options.ExtractExisting, currentPassword); done = true; } catch (Exception ex2) { // Retry here in the case of bad password. if (ex2 as Ionic.Zip.BadPasswordException != null) { currentPassword = ""; continue; // loop around, ask for password again } else { string msg = String.Format("Failed to extract the password-encrypted entry {0} -- {1}", entry.FileName, ex2.Message.ToString()); DialogResult result = MessageBox.Show(msg, String.Format("Error Extracting {0}", entry.FileName), MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); done = true; // done with this entry if (result == DialogResult.Cancel) { _setCancel = true; extractCancelled = true; break; } } } } // while } // else (encryption) } // foreach } // using } catch (Exception ex1) { MessageBox.Show(String.Format("There's been a problem extracting that zip file. {0}", ex1.Message), "Error Extracting", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); Application.Exit(); } OnExtractDone(); if (extractCancelled) return; if (options.OpenExplorer) { string w = System.IO.Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.System)); if (w == null) w = "c:\\windows"; try { System.Diagnostics.Process.Start(System.IO.Path.Combine(w, "explorer.exe"), options.ExtractLocation); } catch { } } } private string PromptForPassword(string entryName) { PasswordDialog dlg1 = new PasswordDialog(); dlg1.EntryName = entryName; // ask for password in a loop until user enters a proper one, // or clicks skip or cancel. bool done = false; do { dlg1.ShowDialog(); done = (dlg1.Result != PasswordDialog.PasswordDialogResult.OK || dlg1.Password != ""); } while (!done); if (dlg1.Result == PasswordDialog.PasswordDialogResult.OK) return dlg1.Password; else if (dlg1.Result == PasswordDialog.PasswordDialogResult.Skip) return ""; // cancel return null; } private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) { // Recycle the progress bars the cancel button, and the status textbox. // An alternative way to accomplish a similar thing is to visually place // the progress bars OFF the tabs. if (this.tabControl1.SelectedIndex == 0) { if (this.tabPage2.Controls.Contains(this.progressBar1)) this.tabPage2.Controls.Remove(this.progressBar1); if (this.tabPage2.Controls.Contains(this.progressBar2)) this.tabPage2.Controls.Remove(this.progressBar2); if (this.tabPage2.Controls.Contains(this.btnCancel)) this.tabPage2.Controls.Remove(this.btnCancel); if (this.tabPage2.Controls.Contains(this.lblStatus)) this.tabPage2.Controls.Remove(this.lblStatus); if (!this.tabPage1.Controls.Contains(this.lblStatus)) this.tabPage1.Controls.Add(this.lblStatus); if (!this.tabPage1.Controls.Contains(this.progressBar1)) this.tabPage1.Controls.Add(this.progressBar1); if (!this.tabPage1.Controls.Contains(this.progressBar2)) this.tabPage1.Controls.Add(this.progressBar2); if (!this.tabPage1.Controls.Contains(this.btnCancel)) this.tabPage1.Controls.Add(this.btnCancel); // swap the comboBox for Encoding to the selected panel if (groupBox2.Controls.Contains(comboEncoding)) { groupBox2.Controls.Remove(comboEncoding); tabPage1.Controls.Add(comboEncoding); int xpos = this.tbZipToOpen.Location.X ; this.comboEncoding.Location = new System.Drawing.Point(xpos, this.tbZipToOpen.Location.Y + this.comboEncoding.Height + 4); } this.toolTip1.SetToolTip(this.comboEncoding, "use this encoding to read the file"); } else if (this.tabControl1.SelectedIndex == 1) { if (this.tabPage1.Controls.Contains(this.progressBar1)) this.tabPage1.Controls.Remove(this.progressBar1); if (this.tabPage1.Controls.Contains(this.progressBar2)) this.tabPage1.Controls.Remove(this.progressBar2); if (this.tabPage1.Controls.Contains(this.btnCancel)) this.tabPage1.Controls.Remove(this.btnCancel); if (this.tabPage1.Controls.Contains(this.lblStatus)) this.tabPage1.Controls.Remove(this.lblStatus); if (!this.tabPage2.Controls.Contains(this.lblStatus)) this.tabPage2.Controls.Add(this.lblStatus); if (!this.tabPage2.Controls.Contains(this.progressBar1)) this.tabPage2.Controls.Add(this.progressBar1); if (!this.tabPage2.Controls.Contains(this.progressBar2)) this.tabPage2.Controls.Add(this.progressBar2); if (!this.tabPage2.Controls.Contains(this.btnCancel)) this.tabPage2.Controls.Add(this.btnCancel); // swap the comboBox for Encoding to the selected panel if (tabPage1.Controls.Contains(comboEncoding)) { tabPage1.Controls.Remove(comboEncoding); groupBox2.Controls.Add(comboEncoding); this.comboEncoding.Location = new System.Drawing.Point(104, 85); this.comboEncoding.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left))); } this.toolTip1.SetToolTip(this.comboEncoding, "use this encoding when saving the file"); } } private void tabControl1_Selecting(object sender, TabControlCancelEventArgs e) { // prevent switching TABs if working if (_working) e.Cancel = true; } private void listView1_ColumnClick(object sender, ColumnClickEventArgs e) { // Create an instance of the ColHeader class. SortableColumnHeader clickedCol = (SortableColumnHeader)this.listView1.Columns[e.Column]; // Set the ascending property to sort in the opposite order. clickedCol.SortAscending = !clickedCol.SortAscending; // Get the number of items in the list. int numItems = this.listView1.Items.Count; // Turn off display while data is repoplulated. this.listView1.BeginUpdate(); // Populate an ArrayList with a SortWrapper of each list item. List list = new List(); for (int i = 0; i < numItems; i++) { list.Add(new ItemWrapper(this.listView1.Items[i], e.Column)); } if (e.Column == 0 || e.Column == 3 || e.Column == 5) list.Sort(new ItemWrapper.NumericComparer(clickedCol.SortAscending)); else list.Sort(new ItemWrapper.StringComparer(clickedCol.SortAscending)); // Clear the list, and repopulate with the sorted items. this.listView1.Items.Clear(); for (int i = 0; i < numItems; i++) this.listView1.Items.Add(list[i].Item); // Turn display back on. this.listView1.EndUpdate(); } private void tbPassword_TextChanged(object sender, EventArgs e) { if (this.tbPassword.Text == "") { if (_mostRecentEncryption == null && this.comboEncryption.SelectedItem.ToString() != "None") { _mostRecentEncryption = this.comboEncryption.SelectedItem.ToString(); SelectNamedEncryption("None"); } } else { if (_mostRecentEncryption != null && this.comboEncryption.SelectedItem.ToString() == "None") { SelectNamedEncryption(_mostRecentEncryption); } _mostRecentEncryption = null; } } private void LoadAboutInfo() { var a = System.Reflection.Assembly.GetEntryAssembly(); string[] resourceNames = a.GetManifestResourceNames(); if (resourceNames != null && resourceNames.Length > 0) { String name = "Ionic.Zip.Forms.About.rtf"; var s = a.GetManifestResourceStream(name); var bytes = ReadAllBytes(s); this.richTextBox1.Rtf = System.Text.Encoding.ASCII.GetString(bytes); s.Close(); } } /// /// Reads the contents of the stream into a byte array. /// /// /// /// Like File.ReadAllBytes(), but for a stream. /// /// /// The stream to read. /// A byte array containing the contents of the stream. /// The stream does not support reading. /// Methods were called after the stream was closed. /// An I/O error occurs. private byte[] ReadAllBytes(System.IO.Stream source) { long originalPosition = source.Position; source.Position = 0; try { byte[] readBuffer = new byte[4096]; int totalBytesRead = 0; int bytesRead; while ((bytesRead = source.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0) { totalBytesRead += bytesRead; if (totalBytesRead == readBuffer.Length) { int nextByte = source.ReadByte(); if (nextByte != -1) { byte[] temp = new byte[readBuffer.Length * 2]; Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length); Buffer.SetByte(temp, totalBytesRead, (byte)nextByte); readBuffer = temp; totalBytesRead++; } } } byte[] buffer = readBuffer; if (readBuffer.Length != totalBytesRead) { buffer = new byte[totalBytesRead]; Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead); } return buffer; } finally { source.Position = originalPosition; } } private void ZipForm_Load(object sender, EventArgs e) { if (_initialFileToLoad != null) { // select the page that opens zip files. this.tabControl1.SelectedIndex = 0; //this.tabPage1.Select(); this.tbZipToOpen.Text = _initialFileToLoad; btnOpen_Click(null, null); } LoadAboutInfo(); } private void tbDirectoryToZip_Leave(object sender, EventArgs e) { this.tbDirectoryInArchive.Text = System.IO.Path.GetFileName(this.tbDirectoryToZip.Text); } private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e) { System.Diagnostics.Process.Start(e.LinkText); } private void listView_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent("FileDrop") && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) { // Get the data. var filePaths = (String[])e.Data.GetData("FileDrop"); // allow drop of one file on listView1, drop multiple files on listView2. if (filePaths.Length == 1 || sender == this.listView2) //A file is being dragged and it can be copied so provide feedback to the user. e.Effect = DragDropEffects.Copy; } } private void listView1_DragDrop(object sender, DragEventArgs e) { // The data can only be dropped if it is a file list and it can be copied. if (e.Data.GetDataPresent("FileDrop") && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) { // Get the data. var filePaths = (String[])e.Data.GetData("FileDrop"); // The data is an array of file paths. // If it is a single file and ends in .zip, then we know how to open it // and display the contents. // If it is more than one file, then we don't know what to do with it. if (filePaths.Length == 1) { DisplayZipFile(filePaths[0]); this.tbZipToOpen.Text = filePaths[0]; this.tbExtractDir.Text = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(filePaths[0]), System.IO.Path.GetFileNameWithoutExtension(filePaths[0]) + "_files"); } } } private void listView2_DragDrop(object sender, DragEventArgs e) { // The data can only be dropped if it is a file list and it can be copied. if (e.Data.GetDataPresent("FileDrop") && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) { // Get the data. var filePaths = (String[])e.Data.GetData("FileDrop"); this.listView2.BeginUpdate(); foreach (var f in filePaths) { var item = new ListViewItem(); // first subitem is the local filename on disk var subitem = new ListViewItem.ListViewSubItem(); subitem.Text = f; item.SubItems.Add(subitem); // next subitem is the directory name to use in the archive subitem = new ListViewItem.ListViewSubItem(); //subitem.Text = String.IsNullOrEmpty(_lastDirectory) ? this.tbDirectoryInArchive.Text : _lastDirectory; subitem.Text = String.IsNullOrEmpty(_lastDirectory) ? System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(f)) : _lastDirectory; item.SubItems.Add(subitem); // additional subitem (to be added): new filename in archive, if any subitem = new ListViewItem.ListViewSubItem(); item.SubItems.Add(subitem); this.listView2.Items.Add(item); } this.listView2.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); this.listView2.EndUpdate(); } } private void listView2_SubItemClicked(object sender, ListViewEx.SubItemEventArgs e) { //this.AcceptButton = null; // Prevent editing the 0th column - it's the checkbox. We want the checkbox // label to remain "". if (e.SubItem == 0) return; this.listView2.StartEditing(this.textBox1, e.Item, e.SubItem); //this.textBox1.Focus(); // to get the RETURN key? no. this did not work. } private void listView2_SubItemEndEditing(object sender, ListViewEx.SubItemEndEditingEventArgs e) { if (!e.Cancel) { e.DisplayText = textBox1.Text; //this.AcceptButton = this.btnZipUp; //this.listView2.Select(); // this.listView2.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); } //this.listView2.EndEditing(true); } private void textBox1_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == 13) { this.listView2.EndEditing(true); e.Handled = true; _lastDirectory = this.textBox1.Text; } } private void button1_Click(object sender, EventArgs e) { int nAdded = 0; PauseUI(null); try { // do file selection, add each item into the list box var fs = new global::Ionic.FileSelector(this.tbSelectionToZip.Text,this.chkTraverseJunctions.Checked); var files = fs.SelectFiles(this.tbDirectoryToZip.Text, this.chkRecurse.Checked); this.listView2.BeginUpdate(); foreach (String f in files) { var item = new ListViewItem(); // first subitem is the filename var subitem = new ListViewItem.ListViewSubItem(); subitem.Text = f; item.SubItems.Add(subitem); // second subitem is the directory name in the archive. subitem = new ListViewItem.ListViewSubItem(); var dirInArchive = this.tbDirectoryInArchive.Text; var subDir = System.IO.Path.GetDirectoryName(f.Replace(this.tbDirectoryToZip.Text, "")); subDir = subDir.Substring(1); subitem.Text = System.IO.Path.Combine(dirInArchive, subDir); item.SubItems.Add(subitem); // third subitem is the filename in the archive, if ay subitem = new ListViewItem.ListViewSubItem(); item.SubItems.Add(subitem); this.listView2.Items.Add(item); nAdded++; } this.listView2.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); this.listView2.EndUpdate(); this.lblStatus.Text = String.Format("Added {0} entries; {1} total entries to save.", nAdded, this.listView2.Items.Count); // remember the successful selection strings if (!_selectionCompletions.Contains(this.tbSelectionToZip.Text)) { if (_selectionCompletions.Count >= _MaxMruListSize) _selectionCompletions.RemoveAt(0); _selectionCompletions.Add(this.tbSelectionToZip.Text); } } catch { } ResetUiState(); //_disableMasterChecking = false; } private void btnClearItemsToZip_Click(object sender, EventArgs e) { int rCount=0; foreach (ListViewItem item in this.listView2.Items) { if (item.Checked) { this.listView2.Items.Remove(item); rCount++; } } // After removing all the checked items, all items are now unchecked. // We can set the mast checkbox to unchecked. But, we have to protect // against infinite recursion. _disableMasterChecking = true; this.checkBox1.Checked = false; _disableMasterChecking = false; this.lblStatus.Text = (rCount == 1) ? String.Format("Cleared 1 entry. {1} remaining entries to save.", rCount, this.listView2.Items.Count) : String.Format("Cleared {0} entries. {1} remaining entries to save.", rCount, this.listView2.Items.Count); } bool _disableMasterChecking = false; private void checkBox1_CheckedChanged_1(object sender, EventArgs e) { // prevent infinite recursion. if (_disableMasterChecking) return; // if we have a mixed state, then it happened programmatically if (this.checkBox1.CheckState == CheckState.Indeterminate) return; _disableListViewCheckedEvent = true; _disableMasterChecking = true; // change state of ALL items foreach (ListViewItem item in this.listView2.Items) { item.Checked = this.checkBox1.Checked; } _disableMasterChecking = false; _disableListViewCheckedEvent = false; } private bool _disableListViewCheckedEvent; private void listView2_ItemChecked(object sender, ItemCheckedEventArgs e) { // prevent infinite recursion if (_disableListViewCheckedEvent) return; System.Drawing.Point p = this.listView2.PointToClient(new System.Drawing.Point(Cursor.Position.X, Cursor.Position.Y)); ListViewItem lvi; int ix = this.listView2.GetSubItemAt(p.X, p.Y, out lvi); // lvi is null when the checkchange comes from a non-mouse event, like when // a new item is being added to the list. if (lvi == null) return; // ix is 0 when the checkbox is the thing that was tickled with the mouse. if (ix == 0) MaybeSetMasterCheckbox(); else { // Revert the checkChange if it was due to a mouse click on a subitem other than the 0th one. // The Checked property has already been changed (in ListView.WndProc?); we need to undo it. // In order to avoid an endless recursion, set the disable flag, first. _disableListViewCheckedEvent = true; lvi.Checked = !lvi.Checked; _disableListViewCheckedEvent = false; } } private void MaybeSetMasterCheckbox() { if (_disableMasterChecking) return; bool uniform = true; // check the state of all the items for (int i = 1; i < this.listView2.Items.Count; i++) { if (this.listView2.Items[i].Checked != this.listView2.Items[i - 1].Checked) { uniform = false; break; } } _disableMasterChecking = true; if (uniform) this.checkBox1.CheckState = (this.listView2.Items[0].Checked) ? CheckState.Checked : CheckState.Unchecked; else this.checkBox1.CheckState = CheckState.Indeterminate; _disableMasterChecking = false; } private void listView2_BeforeLabelEdit(object sender, LabelEditEventArgs e) { // never let the use edit the label associated to the main listview item, // the label on the item checkbox. e.CancelEdit = true; } private int _progress2MaxFactor; private int _totalEntriesToProcess; private bool _working; private bool _operationCanceled; private int _nFilesCompleted; private long _totalBytesBeforeCompress; private long _totalBytesAfterCompress; private Thread _workerThread; private static string TB_COMMENT_NOTE = "-zip file comment here-"; private static string TB_EXTRACT_DIR_NOTE = "-default extract directory-"; private static string TB_EXE_ON_UNPACK_NOTE = "-command line to execute here-"; private String _mostRecentEncryption; private string _initialFileToLoad; private string _lastDirectory; } // The ColHeader class is a ColumnHeader object with an // added property for determining an ascending or descending sort. // True specifies an ascending order, false specifies a descending order. public class SortableColumnHeader : ColumnHeader { public bool SortAscending; public SortableColumnHeader(string text) { this.Text = text; this.SortAscending = true; } } // An instance of the SortWrapper class is created for // each item and added to the ArrayList for sorting. public class ItemWrapper { internal ListViewItem Item; internal int Column; // A SortWrapper requires the item and the index of the clicked column. public ItemWrapper(ListViewItem item, int column) { Item = item; Column = column; } // Text property for getting the text of an item. public string Text { get { return Item.SubItems[Column].Text; } } // Implementation of the IComparer public class StringComparer : IComparer { bool ascending; // Constructor requires the sort order; // true if ascending, otherwise descending. public StringComparer(bool asc) { this.ascending = asc; } // Implemnentation of the IComparer:Compare // method for comparing two objects. public int Compare(ItemWrapper xItem, ItemWrapper yItem) { string xText = xItem.Item.SubItems[xItem.Column].Text; string yText = yItem.Item.SubItems[yItem.Column].Text; return xText.CompareTo(yText) * (this.ascending ? 1 : -1); } } public class NumericComparer : IComparer { bool ascending; // Constructor requires the sort order; // true if ascending, otherwise descending. public NumericComparer(bool asc) { this.ascending = asc; } // Implementation of the IComparer:Compare // method for comparing two objects. public int Compare(ItemWrapper xItem, ItemWrapper yItem) { int x = 0, y = 0; try { x = Int32.Parse(xItem.Item.SubItems[xItem.Column].Text); y = Int32.Parse(yItem.Item.SubItems[yItem.Column].Text); } catch { try { // lop off one char for % String trimmed = null; trimmed = xItem.Item.SubItems[xItem.Column].Text; trimmed = trimmed.Substring(0, trimmed.Length - 1); x = Int32.Parse(trimmed); trimmed = xItem.Item.SubItems[yItem.Column].Text; trimmed = trimmed.Substring(0, trimmed.Length - 1); y = Int32.Parse(trimmed); } catch { } } return (x - y) * (this.ascending ? 1 : -1); } } } public class ExtractWorkerOptions { public string ExtractLocation; public Ionic.Zip.ExtractExistingFileAction ExtractExisting; public bool OpenExplorer; public String Selection; } public class SaveWorkerOptions { public string ZipName; public string Selection; public bool TraverseJunctions; public bool RemoveFilesAfterExe; public string Encoding; public Ionic.Zip.ZipOption EncodingUsage; public string Comment; public string Password; public string ExeOnUnpack; public string ExtractDirectory; public int ExtractExistingFile; public int ZipFlavor; public int MaxSegmentSize; public Ionic.Zlib.CompressionLevel CompressionLevel; public Ionic.Zip.CompressionMethod CompressionMethod; public Ionic.Zip.EncryptionAlgorithm Encryption; public Zip64Option Zip64; public bool WindowsTimes; public bool UnixTimes; public ItemToAdd[] Entries; } public class ItemToAdd { public string LocalFileName; public string DirectoryInArchive; public string FileNameInArchive; } internal class HiResTimer { // usage: // // hrt= new HiResTimer(); // hrt.Start(); // ... do work ... // hrt.Stop(); // System.Console.WriteLine("elapsed time: {0:N4}", hrt.Seconds); // [System.Runtime.InteropServices.DllImport("KERNEL32")] private static extern bool QueryPerformanceCounter(ref long lpPerformanceCount); [System.Runtime.InteropServices.DllImport("KERNEL32")] private static extern bool QueryPerformanceFrequency(ref long lpFrequency); private long m_TickCountAtStart = 0; private long m_TickCountAtStop = 0; private long m_ElapsedTicks = 0; public HiResTimer() { m_Frequency = 0; QueryPerformanceFrequency(ref m_Frequency); } public void Start() { m_TickCountAtStart = 0; QueryPerformanceCounter(ref m_TickCountAtStart); } public void Stop() { m_TickCountAtStop = 0; QueryPerformanceCounter(ref m_TickCountAtStop); m_ElapsedTicks = m_TickCountAtStop - m_TickCountAtStart; } public void Reset() { m_TickCountAtStart = 0; m_TickCountAtStop = 0; m_ElapsedTicks = 0; } public long Elapsed { get { return m_ElapsedTicks; } } public float Seconds { get { return ((float)m_ElapsedTicks / (float)m_Frequency); } } private long m_Frequency = 0; public long Frequency { get { return m_Frequency; } } } }