//! \file GarExtract.cs //! \date Fri Jul 25 05:52:27 2014 //! \brief Extract archive frontend. // // Copyright (C) 2014 by morkt // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Diagnostics; using System.Windows; using System.Windows.Input; using Ookii.Dialogs.Wpf; using GameRes; using GARbro.GUI.Strings; namespace GARbro.GUI { public partial class MainWindow : Window { /// /// Handle "Extract item" command. /// private void ExtractItemExec (object sender, ExecutedRoutedEventArgs e) { var entry = CurrentDirectory.SelectedItem as EntryViewModel; if (null == entry) return; try { if (!ViewModel.IsArchive) { if (!entry.IsDirectory) { var arc_dir = CurrentPath; var source = Path.Combine (arc_dir, entry.Name); string destination = arc_dir; // extract into directory named after archive if (!string.IsNullOrEmpty (Path.GetExtension (entry.Name))) destination = Path.GetFileNameWithoutExtension (source); ExtractArchive (source, destination); } } else if (null != m_app.CurrentArchive) { var vm = ViewModel as ArchiveViewModel; string destination = Path.GetDirectoryName (vm.Path); string arc_name = Path.GetFileName (vm.Path); if (entry.Name == ".." && vm.SubDir == "") // root entry { ExtractArchive (m_app.CurrentArchive, arc_name, destination); } else { ExtractFileFromArchive (entry, destination); } } } catch (Exception X) { PopupError (X.Message, guiStrings.MsgErrorExtracting); } } private void ExtractArchive (string path, string destination) { string arc_name = Path.GetFileName (path); FormatCatalog.Instance.LastError = null; var arc = ArcFile.TryOpen (path); if (null != arc) { ExtractArchive (arc, arc_name, destination); } else { string error_message; if (FormatCatalog.Instance.LastError != null) error_message = FormatCatalog.Instance.LastError.Message; else error_message = guiStrings.MsgUnknownFormat; SetStatusText (string.Format ("{1}: {0}", error_message, arc_name)); } } private void ExtractArchive (ArcFile arc, string arc_name, string destination) { if (0 == arc.Dir.Count) { SetStatusText (string.Format ("{1}: {0}", guiStrings.MsgEmptyArchive, arc_name)); return; } var extractDialog = new ExtractArchiveDialog (arc_name, destination); extractDialog.Owner = this; var result = extractDialog.ShowDialog(); if (!result.Value) return; destination = extractDialog.DestinationDir.Text; if (!string.IsNullOrEmpty (destination)) { destination = Path.GetFullPath (destination); Trace.WriteLine (destination, "Extract destination"); StopWatchDirectoryChanges(); try { Directory.CreateDirectory (destination); Directory.SetCurrentDirectory (destination); } finally { m_watcher.EnableRaisingEvents = true; } } IEnumerable file_list = arc.Dir; bool skip_images = !extractDialog.ExtractImages.IsChecked.Value; bool skip_script = !extractDialog.ExtractText.IsChecked.Value; if (skip_images || skip_script) file_list = file_list.Where (f => !(skip_images && f.Type == "image") && !(skip_script && f.Type == "script")); if (!file_list.Any()) { SetStatusText (string.Format ("{1}: {0}", guiStrings.MsgNoFiles, arc_name)); return; } ImageFormat image_format = null; if (!skip_images) image_format = extractDialog.GetImageFormat (extractDialog.ImageConversionFormat); SetStatusText (string.Format(guiStrings.MsgExtractingTo, arc_name, destination)); ExtractFilesFromArchive (string.Format (guiStrings.MsgExtractingArchive, arc_name), arc, file_list, image_format); } private void ExtractFileFromArchive (EntryViewModel entry, string destination) { var extractDialog = new ExtractFile (entry, destination); extractDialog.Owner = this; var result = extractDialog.ShowDialog(); if (!result.Value) return; var file_list = (ViewModel as ArchiveViewModel).GetFiles (entry); destination = extractDialog.DestinationDir.Text; if (!string.IsNullOrEmpty (destination)) { destination = Path.GetFullPath (destination); Directory.CreateDirectory (destination); Directory.SetCurrentDirectory (destination); } ImageFormat format = null; if (entry.Type == "image") format = extractDialog.GetImageFormat (extractDialog.ImageConversionFormat); string arc_name = Path.GetFileName (CurrentPath); ExtractFilesFromArchive (string.Format (guiStrings.MsgExtractingFile, arc_name), m_app.CurrentArchive, file_list, format); } private void ExtractFilesFromArchive (string text, ArcFile arc, IEnumerable file_list, ImageFormat image_format = null) { file_list = file_list.OrderBy (e => e.Offset); var extractProgressDialog = new ProgressDialog () { WindowTitle = guiStrings.TextTitle, Text = text, Description = "", MinimizeBox = true, }; if (!file_list.Skip (1).Any()) // 1 == file_list.Count() { extractProgressDialog.Description = file_list.First().Name; extractProgressDialog.ProgressBarStyle = ProgressBarStyle.MarqueeProgressBar; } extractProgressDialog.DoWork += (s, e) => { try { int total = file_list.Count(); int i = 0; foreach (var entry in file_list) { if (extractProgressDialog.CancellationPending) break; if (total > 1) extractProgressDialog.ReportProgress (i*100/total, null, entry.Name); if (null != image_format && entry.Type == "image") ExtractImage (arc, entry, image_format); else arc.Extract (entry); ++i; } SetStatusText (string.Format (guiStrings.MsgExtractCompletePlural, i, Localization.Plural (i, "file"))); } catch (Exception X) { SetStatusText (X.Message); } }; extractProgressDialog.RunWorkerCompleted += (s, e) => { extractProgressDialog.Dispose(); if (!ViewModel.IsArchive) { arc.Dispose(); Dispatcher.Invoke (RefreshView); } }; extractProgressDialog.ShowDialog (this); } } }