diff --git a/ExtractionTool/ExtractionTool.csproj b/ExtractionTool/ExtractionTool.csproj
index 893fff93..ee21a5e6 100644
--- a/ExtractionTool/ExtractionTool.csproj
+++ b/ExtractionTool/ExtractionTool.csproj
@@ -58,6 +58,7 @@
+
diff --git a/ExtractionTool/Options.cs b/ExtractionTool/Options.cs
index 18956c25..e3df600a 100644
--- a/ExtractionTool/Options.cs
+++ b/ExtractionTool/Options.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.IO;
namespace ExtractionTool
@@ -14,96 +13,22 @@ namespace ExtractionTool
///
/// Enable debug output for relevant operations
///
- public bool Debug { get; private set; } = false;
-
- ///
- /// Set of input paths to use for operations
- ///
- public List InputPaths { get; private set; } = [];
+ public bool Debug { get; set; }
///
/// Output path for archive extraction
///
- public string OutputPath { get; private set; } = string.Empty;
+ public string OutputPath { get; set; } = string.Empty;
#endregion
- ///
- /// Parse commandline arguments into an Options object
- ///
- public static Options? ParseOptions(string[] args)
- {
- // If we have invalid arguments
- if (args == null || args.Length == 0)
- return null;
-
- // Create an Options object
- var options = new Options();
-
- // Parse the options and paths
- for (int index = 0; index < args.Length; index++)
- {
- string arg = args[index];
- switch (arg)
- {
- case "-?":
- case "-h":
- case "--help":
- return null;
-
- case "-d":
- case "--debug":
- options.Debug = true;
- break;
-
- case "-o":
- case "--outdir":
- options.OutputPath = index + 1 < args.Length ? args[++index] : string.Empty;
- break;
-
- default:
- options.InputPaths.Add(arg);
- break;
- }
- }
-
- // Validate we have any input paths to work on
- if (options.InputPaths.Count == 0)
- {
- Console.WriteLine("At least one path is required!");
- return null;
- }
-
- // Validate the output path
- bool validPath = ValidateExtractionPath(options);
- if (!validPath)
- return null;
-
- return options;
- }
-
- ///
- /// Display help text
- ///
- public static void DisplayHelp()
- {
- Console.WriteLine("Extraction Tool");
- Console.WriteLine();
- Console.WriteLine("ExtractionTool.exe file|directory ...");
- Console.WriteLine();
- Console.WriteLine("Options:");
- Console.WriteLine("-?, -h, --help Display this help text and quit");
- Console.WriteLine("-d, --debug Enable debug mode");
- Console.WriteLine("-o, --outdir [PATH] Set output path for extraction (required)");
- }
-
///
/// Validate the extraction path
///
- private static bool ValidateExtractionPath(Options options)
+ public bool ValidateExtractionPath()
{
// Null or empty output path
- if (string.IsNullOrEmpty(options.OutputPath))
+ if (string.IsNullOrEmpty(OutputPath))
{
Console.WriteLine("Output directory required for extraction!");
Console.WriteLine();
@@ -113,8 +38,8 @@ namespace ExtractionTool
// Malformed output path or invalid location
try
{
- options.OutputPath = Path.GetFullPath(options.OutputPath);
- Directory.CreateDirectory(options.OutputPath);
+ OutputPath = Path.GetFullPath(OutputPath);
+ Directory.CreateDirectory(OutputPath);
}
catch
{
diff --git a/ExtractionTool/Program.cs b/ExtractionTool/Program.cs
index 8f202f8f..d9186297 100644
--- a/ExtractionTool/Program.cs
+++ b/ExtractionTool/Program.cs
@@ -1,5 +1,8 @@
using System;
+using System.Collections.Generic;
using System.IO;
+using SabreTools.CommandLine;
+using SabreTools.CommandLine.Inputs;
using SabreTools.IO.Extensions;
using SabreTools.Serialization;
using SabreTools.Serialization.Wrappers;
@@ -8,6 +11,14 @@ namespace ExtractionTool
{
class Program
{
+ #region Constants
+
+ private const string _debugName = "debug";
+ private const string _helpName = "help";
+ private const string _outputPathName = "output-path";
+
+ #endregion
+
static void Main(string[] args)
{
#if NET462_OR_GREATER || NETCOREAPP
@@ -15,30 +26,85 @@ namespace ExtractionTool
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
- // Get the options from the arguments
- var options = Options.ParseOptions(args);
+ // Create the command set
+ var commandSet = CreateCommands();
- // If we have an invalid state
- if (options == null)
+ // If we have no args, show the help and quit
+ if (args == null || args.Length == 0)
{
- Options.DisplayHelp();
+ commandSet.OutputAllHelp();
+ return;
+ }
+
+ // Loop through and process the options
+ int firstFileIndex = 0;
+ for (; firstFileIndex < args.Length; firstFileIndex++)
+ {
+ string arg = args[firstFileIndex];
+
+ var input = commandSet.GetTopLevel(arg);
+ if (input == null)
+ break;
+
+ input.ProcessInput(args, ref firstFileIndex);
+ }
+
+ // If help was specified
+ if (commandSet.GetBoolean(_helpName))
+ {
+ commandSet.OutputAllHelp();
+ return;
+ }
+
+ // Get the options from the arguments
+ var options = new Options
+ {
+ Debug = commandSet.GetBoolean(_debugName),
+ OutputPath = commandSet.GetString(_outputPathName) ?? string.Empty,
+ };
+
+ // Validate the output path
+ if (!options.ValidateExtractionPath())
+ {
+ commandSet.OutputAllHelp();
return;
}
// Loop through the input paths
- foreach (string inputPath in options.InputPaths)
+ for (int i = firstFileIndex; i < args.Length; i++)
{
- ExtractPath(inputPath, options.OutputPath, options.Debug);
+ string arg = args[i];
+ ExtractPath(arg, options);
}
}
+ ///
+ /// Create the command set for the program
+ ///
+ private static CommandSet CreateCommands()
+ {
+ List header = [
+ "Extraction Tool",
+ string.Empty,
+ "ExtractionTool file|directory ...",
+ string.Empty,
+ ];
+
+ var commandSet = new CommandSet(header);
+
+ commandSet.Add(new FlagInput(_helpName, ["-?", "-h", "--help"], "Display this help text"));
+ commandSet.Add(new FlagInput(_debugName, ["-d", "--debug"], "Enable debug mode"));
+ commandSet.Add(new StringInput(_outputPathName, ["-o", "--outdir"], "Set output path for extraction (required)"));
+
+ return commandSet;
+ }
+
///
/// Wrapper to extract data for a single path
///
/// File or directory path
- /// Output directory path
- /// Enable including debug information
- private static void ExtractPath(string path, string outputDirectory, bool includeDebug)
+ /// User-defined options
+ private static void ExtractPath(string path, Options options)
{
// Normalize by getting the full path
path = Path.GetFullPath(path);
@@ -47,13 +113,13 @@ namespace ExtractionTool
// Check if the file or directory exists
if (File.Exists(path))
{
- ExtractFile(path, outputDirectory, includeDebug);
+ ExtractFile(path, options);
}
else if (Directory.Exists(path))
{
foreach (string file in IOExtensions.SafeEnumerateFiles(path, "*", SearchOption.AllDirectories))
{
- ExtractFile(file, outputDirectory, includeDebug);
+ ExtractFile(file, options);
}
}
else
@@ -65,7 +131,9 @@ namespace ExtractionTool
///
/// Print information for a single file, if possible
///
- private static void ExtractFile(string file, string outputDirectory, bool includeDebug)
+ /// File path
+ /// User-defined options
+ private static void ExtractFile(string file, Options options)
{
Console.WriteLine($"Attempting to extract all files from {file}");
using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
@@ -82,7 +150,7 @@ namespace ExtractionTool
}
catch (Exception ex)
{
- if (includeDebug) Console.Error.WriteLine(ex);
+ if (options.Debug) Console.Error.WriteLine(ex);
return;
}
@@ -91,7 +159,7 @@ namespace ExtractionTool
var wrapper = WrapperFactory.CreateWrapper(ft, stream);
// Create the output directory
- Directory.CreateDirectory(outputDirectory);
+ Directory.CreateDirectory(options.OutputPath);
// Print the preamble
Console.WriteLine($"Attempting to extract from '{wrapper?.Description() ?? "UNKNOWN"}'");
@@ -101,142 +169,142 @@ namespace ExtractionTool
{
// 7-zip
case SevenZip sz:
- sz.Extract(outputDirectory, includeDebug);
+ sz.Extract(options.OutputPath, options.Debug);
break;
// BFPK archive
case BFPK bfpk:
- bfpk.Extract(outputDirectory, includeDebug);
+ bfpk.Extract(options.OutputPath, options.Debug);
break;
// BSP
case BSP bsp:
- bsp.Extract(outputDirectory, includeDebug);
+ bsp.Extract(options.OutputPath, options.Debug);
break;
// bzip2
case BZip2 bzip2:
- bzip2.Extract(outputDirectory, includeDebug);
+ bzip2.Extract(options.OutputPath, options.Debug);
break;
// CFB
case CFB cfb:
- cfb.Extract(outputDirectory, includeDebug);
+ cfb.Extract(options.OutputPath, options.Debug);
break;
// GCF
case GCF gcf:
- gcf.Extract(outputDirectory, includeDebug);
+ gcf.Extract(options.OutputPath, options.Debug);
break;
// gzip
case GZip gzip:
- gzip.Extract(outputDirectory, includeDebug);
+ gzip.Extract(options.OutputPath, options.Debug);
break;
// InstallShield Archive V3 (Z)
case InstallShieldArchiveV3 isv3:
- isv3.Extract(outputDirectory, includeDebug);
+ isv3.Extract(options.OutputPath, options.Debug);
break;
// IS-CAB archive
case InstallShieldCabinet iscab:
- iscab.Extract(outputDirectory, includeDebug);
+ iscab.Extract(options.OutputPath, options.Debug);
break;
// LZ-compressed file, KWAJ variant
case LZKWAJ kwaj:
- kwaj.Extract(outputDirectory, includeDebug);
+ kwaj.Extract(options.OutputPath, options.Debug);
break;
// LZ-compressed file, QBasic variant
case LZQBasic qbasic:
- qbasic.Extract(outputDirectory, includeDebug);
+ qbasic.Extract(options.OutputPath, options.Debug);
break;
// LZ-compressed file, SZDD variant
case LZSZDD szdd:
- szdd.Extract(outputDirectory, includeDebug);
+ szdd.Extract(options.OutputPath, options.Debug);
break;
// Microsoft Cabinet archive
case MicrosoftCabinet mscab:
- mscab.Extract(outputDirectory, includeDebug);
+ mscab.Extract(options.OutputPath, options.Debug);
break;
// MoPaQ (MPQ) archive
case MoPaQ mpq:
- mpq.Extract(outputDirectory, includeDebug);
+ mpq.Extract(options.OutputPath, options.Debug);
break;
// New Executable
case NewExecutable nex:
- nex.Extract(outputDirectory, includeDebug);
+ nex.Extract(options.OutputPath, options.Debug);
break;
// PAK
case PAK pak:
- pak.Extract(outputDirectory, includeDebug);
+ pak.Extract(options.OutputPath, options.Debug);
break;
// PFF
case PFF pff:
- pff.Extract(outputDirectory, includeDebug);
+ pff.Extract(options.OutputPath, options.Debug);
break;
// PKZIP
case PKZIP pkzip:
- pkzip.Extract(outputDirectory, includeDebug);
+ pkzip.Extract(options.OutputPath, options.Debug);
break;
// Portable Executable
case PortableExecutable pex:
- pex.Extract(outputDirectory, includeDebug);
+ pex.Extract(options.OutputPath, options.Debug);
break;
// Quantum
case Quantum quantum:
- quantum.Extract(outputDirectory, includeDebug);
+ quantum.Extract(options.OutputPath, options.Debug);
break;
// RAR
case RAR rar:
- rar.Extract(outputDirectory, includeDebug);
+ rar.Extract(options.OutputPath, options.Debug);
break;
// SGA
case SGA sga:
- sga.Extract(outputDirectory, includeDebug);
+ sga.Extract(options.OutputPath, options.Debug);
break;
// Tape Archive
case TapeArchive tar:
- tar.Extract(outputDirectory, includeDebug);
+ tar.Extract(options.OutputPath, options.Debug);
break;
// VBSP
case VBSP vbsp:
- vbsp.Extract(outputDirectory, includeDebug);
+ vbsp.Extract(options.OutputPath, options.Debug);
break;
// VPK
case VPK vpk:
- vpk.Extract(outputDirectory, includeDebug);
+ vpk.Extract(options.OutputPath, options.Debug);
break;
// WAD3
case WAD3 wad:
- wad.Extract(outputDirectory, includeDebug);
+ wad.Extract(options.OutputPath, options.Debug);
break;
// xz
case XZ xz:
- xz.Extract(outputDirectory, includeDebug);
+ xz.Extract(options.OutputPath, options.Debug);
break;
// XZP
case XZP xzp:
- xzp.Extract(outputDirectory, includeDebug);
+ xzp.Extract(options.OutputPath, options.Debug);
break;
// Everything else
diff --git a/InfoPrint/InfoPrint.csproj b/InfoPrint/InfoPrint.csproj
index 11cb82a5..bdcebf34 100644
--- a/InfoPrint/InfoPrint.csproj
+++ b/InfoPrint/InfoPrint.csproj
@@ -32,6 +32,7 @@
+
diff --git a/InfoPrint/Options.cs b/InfoPrint/Options.cs
index 6d80dec0..2689ffc8 100644
--- a/InfoPrint/Options.cs
+++ b/InfoPrint/Options.cs
@@ -1,6 +1,3 @@
-using System;
-using System.Collections.Generic;
-
namespace InfoPrint
{
///
@@ -8,134 +5,26 @@ namespace InfoPrint
///
internal sealed class Options
{
- #region Properties
-
///
/// Enable debug output for relevant operations
///
- public bool Debug { get; private set; } = false;
+ public bool Debug { get; set; }
///
/// Output information to file only, skip printing to console
///
- public bool FileOnly { get; private set; } = false;
+ public bool FileOnly { get; set; }
///
/// Print external file hashes
///
- public bool Hash { get; private set; } = false;
-
- ///
- /// Set of input paths to use for operations
- ///
- public List InputPaths { get; private set; } = [];
+ public bool Hash { get; set; }
#if NETCOREAPP
///
/// Enable JSON output
///
- public bool Json { get; private set; } = false;
+ public bool Json { get; set; }
#endif
-
- #endregion
-
- ///
- /// Parse commandline arguments into an Options object
- ///
- public static Options? ParseOptions(string[] args)
- {
- // If we have invalid arguments
- if (args == null || args.Length == 0)
- return null;
-
- // Create an Options object
- var options = new Options();
-
- // Parse the features
- int index = 0;
- for (; index < args.Length; index++)
- {
- string arg = args[index];
- bool featureFound = false;
- switch (arg)
- {
- case "-?":
- case "-h":
- case "--help":
- return null;
-
- default:
- break;
- }
-
- // If the flag wasn't a feature
- if (!featureFound)
- break;
- }
-
- // Parse the options and paths
- for (; index < args.Length; index++)
- {
- string arg = args[index];
- switch (arg)
- {
- case "-d":
- case "--debug":
- options.Debug = true;
- break;
-
- case "-c":
- case "--hash":
- options.Hash = true;
- break;
-
- case "-f":
- case "--file":
- options.FileOnly = true;
- break;
-
- case "-j":
- case "--json":
-#if NETCOREAPP
- options.Json = true;
-#else
- Console.WriteLine("JSON output not available in .NET Framework");
-#endif
- break;
-
- default:
- options.InputPaths.Add(arg);
- break;
- }
- }
-
- // Validate we have any input paths to work on
- if (options.InputPaths.Count == 0)
- {
- Console.WriteLine("At least one path is required!");
- return null;
- }
-
- return options;
- }
-
- ///
- /// Display help text
- ///
- public static void DisplayHelp()
- {
- Console.WriteLine("Information Printing Program");
- Console.WriteLine();
- Console.WriteLine("InfoPrint file|directory ...");
- Console.WriteLine();
- Console.WriteLine("Options:");
- Console.WriteLine("-?, -h, --help Display this help text and quit");
- Console.WriteLine("-d, --debug Enable debug mode");
- Console.WriteLine("-c, --hash Output file hashes");
- Console.WriteLine("-f, --file Print to file only");
-#if NETCOREAPP
- Console.WriteLine("-j, --json Print info as JSON");
-#endif
- }
}
}
diff --git a/InfoPrint/Program.cs b/InfoPrint/Program.cs
index 55a7d35f..83555e2a 100644
--- a/InfoPrint/Program.cs
+++ b/InfoPrint/Program.cs
@@ -1,6 +1,9 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Text;
+using SabreTools.CommandLine;
+using SabreTools.CommandLine.Inputs;
using SabreTools.Hashing;
using SabreTools.IO.Extensions;
using SabreTools.Serialization;
@@ -10,23 +13,92 @@ namespace InfoPrint
{
public static class Program
{
+ #region Constants
+
+ private const string _debugName = "debug";
+ private const string _fileOnlyName = "file-only";
+ private const string _hashName = "hash";
+ private const string _helpName = "help";
+#if NETCOREAPP
+ private const string _jsonName = "json";
+#endif
+
+ #endregion
+
public static void Main(string[] args)
{
- // Get the options from the arguments
- var options = Options.ParseOptions(args);
+ // Create the command set
+ var commandSet = CreateCommands();
- // If we have an invalid state
- if (options == null)
+ // If we have no args, show the help and quit
+ if (args == null || args.Length == 0)
{
- Options.DisplayHelp();
+ commandSet.OutputAllHelp();
return;
}
- // Loop through the input paths
- foreach (string inputPath in options.InputPaths)
+ // Loop through and process the options
+ int firstFileIndex = 0;
+ for (; firstFileIndex < args.Length; firstFileIndex++)
{
- PrintPathInfo(inputPath, options);
+ string arg = args[firstFileIndex];
+
+ var input = commandSet.GetTopLevel(arg);
+ if (input == null)
+ break;
+
+ input.ProcessInput(args, ref firstFileIndex);
}
+
+ // If help was specified
+ if (commandSet.GetBoolean(_helpName))
+ {
+ commandSet.OutputAllHelp();
+ return;
+ }
+
+ // Get the options from the arguments
+ var options = new Options
+ {
+ Debug = commandSet.GetBoolean(_debugName),
+ Hash = commandSet.GetBoolean(_hashName),
+ FileOnly = commandSet.GetBoolean(_fileOnlyName),
+#if NETCOREAPP
+ Json = commandSet.GetBoolean(_jsonName),
+#endif
+ };
+
+ // Loop through the input paths
+ for (int i = firstFileIndex; i < args.Length; i++)
+ {
+ string arg = args[i];
+ PrintPathInfo(arg, options);
+ }
+ }
+
+ ///
+ /// Create the command set for the program
+ ///
+ private static CommandSet CreateCommands()
+ {
+ List header = [
+ "Information Printing Program",
+ string.Empty,
+ "InfoPrint file|directory ...",
+ string.Empty,
+ ];
+
+ var commandSet = new CommandSet(header);
+
+ commandSet.Add(new FlagInput(_helpName, ["-?", "-h", "--help"], "Display this help text"));
+ commandSet.Add(new FlagInput(_debugName, ["-d", "--debug"], "Enable debug mode"));
+ commandSet.Add(new FlagInput(_hashName, ["-c", "--hash"], "Output file hashes"));
+ commandSet.Add(new FlagInput(_fileOnlyName, ["-f", "--file"], "Print to file only"));
+#if NETCOREAPP
+ commandSet.Add(new FlagInput(_jsonName, ["-j", "--json"], "Print info as JSON"));
+#endif
+
+ return commandSet;
}
///
diff --git a/README.MD b/README.MD
index c6bdfbd0..69b5e1b9 100644
--- a/README.MD
+++ b/README.MD
@@ -30,7 +30,7 @@ For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/S
InfoPrint file|directory ...
Options:
--?, -h, --help Display this help text and quit
+-?, -h, --help Display this help text
-d, --debug Enable debug mode
-c, --hash Output file hashes
-f, --file Print to file only
@@ -42,10 +42,10 @@ Options:
**ExtractionTool** is a reference implementation for the extraction features of the library, packaged as a standalone executable for all supported platforms. It will attempt to detect and extract many supported file types. See the table below for supported extraction functionality.
```text
-ExtractionTool.exe file|directory ...
+ExtractionTool file|directory ...
Options:
--?, -h, --help Display this help text and quit
+-?, -h, --help Display this help text
-d, --debug Enable debug mode
-o, --outdir [PATH] Set output path for extraction (required)
```