private void Save(object sender, RoutedEventArgs e) { if (!File.Exists(currentSPCFilename)) { SaveAs(sender, e); } else { currentSPC.Save(currentSPCFilename); statusText.Text = $"{currentSPCFilename} saved."; } }
/// <summary> /// Processes a previously-extracted subfile that's open in an editor. This process runs its translation steps backwards, /// before finally re-packing the final product into the original SPC file it came from. /// </summary> /// <param name="tempDir">The temporary directory where the extracted subfile data is located.</param> /// <param name="info">The <see cref="EditorTrackingInfo"/> associated with the editor and subfile.</param> private void RepackArchiveSubfile(string tempDir, EditorTrackingInfo info) { // First, run all translation steps in reverse var translationSteps = info.SelectedAssociation.TranslationSteps; var translatedFilenames = info.SubfileNameHistory; for (int step = (translationSteps.Count - 1); step >= 0; --step) { // Resolve internal/external translator object resolvedTranslator = Config.FileAssociationConfig.ResolveInternalExternal(translationSteps[step]) as Process; // Run the translation step if (resolvedTranslator is Window) { Window translatorWindow = resolvedTranslator as Window; // Finally, open the target editor window as blocking translatorWindow.ShowDialog(); } else if (resolvedTranslator is Process) { Process translatorProcess = resolvedTranslator as Process; // Setup the target process' launch args translatorProcess.StartInfo.Arguments = Path.Combine(tempDir, translatedFilenames[step + 1]); translatorProcess.Start(); translatorProcess.WaitForExit(); } else { // If we get here, there's been an error and we should abort return; } } // The final translated filename is the original file & format, repack it SpcFile spc = new SpcFile(); spc.Load(info.OriginArchivePath); string fullSubfilePath = Path.Combine(tempDir, translatedFilenames[0]); spc.InsertSubfile(fullSubfilePath); spc.Save(info.OriginArchivePath); }
static void Main(string[] args) { Console.WriteLine("SPC Tool by CaptainSwag101\n" + "Version 0.0.2, built on 2019-09-25\n"); // Parse input argument if (args.Length == 0) { return; } FileInfo info = new FileInfo(args[0]); if (!info.Exists) { Console.WriteLine($"ERROR: \"{args[0]}\" does not exist."); return; } if (info.Extension.ToLowerInvariant() != ".spc") { Console.WriteLine("ERROR: Input file does not have the \".spc\" extension."); return; } // If the first argument is a valid SPC file (and if we reach this point it probably is), it is the input. input = args[0]; // Parse operation argument // If command starts with "--", it is our operation to perform if (args.Length > 1 && args[1].StartsWith("--")) { string op = args[1].TrimStart('-').ToLowerInvariant(); if (validOperations.Keys.Any(op.Contains)) { operation = op; } else { Console.WriteLine("ERROR: Invalid operation specified."); return; } } // Parse target arguments for (int i = 2; i < args.Length; ++i) { targets.Add(args[i]); } // Load the input file SpcFile spc = new SpcFile(); spc.Load(input); // Execute operation if (operation == null) { Console.WriteLine("ERROR: No operation specified."); } else if (validOperations[operation] != -1 && targets.Count != validOperations[operation]) { Console.WriteLine($"ERROR: Invalid number of target(s) specified, expected {validOperations[operation]}."); } else { switch (operation) { case "list": case "bench": Console.WriteLine($"\"{info.Name}\" contains the following subfiles:\n"); foreach (SpcSubfile subfile in spc.Subfiles) { Console.WriteLine($"Subfile name: \"{subfile.Name}\""); Console.WriteLine($"\tCompression flag: {subfile.CompressionFlag}"); Console.WriteLine($"\tUnknown flag: {subfile.UnknownFlag}"); Console.WriteLine($"\tCurrent size: {subfile.CurrentSize.ToString("n0")} bytes"); Console.WriteLine($"\tOriginal size: {subfile.OriginalSize.ToString("n0")} bytes"); // Benchmark decompression and compression if (operation == "bench") { Stopwatch stopwatch = new Stopwatch(); Console.Write("Decompressing..."); stopwatch.Start(); subfile.Decompress(); stopwatch.Stop(); Console.WriteLine($" Done! Took {stopwatch.Elapsed.ToString()}"); Console.Write("Compressing..."); stopwatch.Restart(); subfile.Compress(); stopwatch.Stop(); Console.WriteLine($" Done! Took {stopwatch.Elapsed.ToString()}"); } Console.WriteLine(); } break; case "extract": // Setup an output directory for extracted files output ??= info.DirectoryName + Path.DirectorySeparatorChar + info.Name.Substring(0, info.Name.Length - info.Extension.Length); Directory.CreateDirectory(output); // Generate list of subfiles to be extracted that match the target regex List <string> subfilesToExtract = new List <string>(); foreach (string target in targets) { string regexTarget = "^" + Regex.Escape(target).Replace("\\?", ".").Replace("\\*", ".*") + "$"; foreach (SpcSubfile subfile in spc.Subfiles) { if (Regex.IsMatch(subfile.Name, regexTarget)) { subfilesToExtract.Add(subfile.Name); } } } // Extract the subfiles using Tasks Task[] extractTasks = new Task[subfilesToExtract.Count]; // IMPORTANT: If we ever switch to a for loop instead of foreach, // make sure to make a local scoped copy of the subfile name in order to prevent // threading weirdness from passing the wrong string value and causing random issues. foreach (string subfileName in subfilesToExtract) { Console.WriteLine($"Extracting \"{subfileName}\"..."); extractTasks[subfilesToExtract.IndexOf(subfileName)] = Task.Factory.StartNew(() => spc.ExtractSubfile(subfileName, output)); } // Wait until all target subfiles have been extracted Task.WaitAll(extractTasks); break; case "insert": // Insert the subfiles using Tasks Task[] insertTasks = new Task[targets.Count]; // IMPORTANT: If we ever switch to a for loop instead of foreach, // make sure to make a local scoped copy of the subfile name in order to prevent // threading weirdness from passing the wrong string value and causing random issues. foreach (string subfileName in targets) { Console.WriteLine($"Inserting \"{subfileName}\"..."); insertTasks[targets.IndexOf(subfileName)] = spc.InsertSubfileAsync(subfileName, confirmation: ConfirmOverwrite); } // Wait until all target subfiles have been inserted foreach (Task task in insertTasks) { task.Start(); task.Wait(); } // Save the spc file spc.Save(input); break; } } if (pauseAfterComplete) { Console.WriteLine("Press Enter to close..."); Console.Read(); } }