diff --git a/NDecrypt/Enumerations.cs b/NDecrypt/Enumerations.cs
index 0470118..6cde69d 100644
--- a/NDecrypt/Enumerations.cs
+++ b/NDecrypt/Enumerations.cs
@@ -1,16 +1,5 @@
namespace NDecrypt
{
- ///
- /// Functionality to use from the program
- ///
- internal enum FeatureFlag
- {
- NULL,
- Decrypt,
- Encrypt,
- Info,
- }
-
///
/// Type of the detected file
///
diff --git a/NDecrypt/BaseFeature.cs b/NDecrypt/Features/BaseFeature.cs
similarity index 99%
rename from NDecrypt/BaseFeature.cs
rename to NDecrypt/Features/BaseFeature.cs
index 04beff5..49c313d 100644
--- a/NDecrypt/BaseFeature.cs
+++ b/NDecrypt/Features/BaseFeature.cs
@@ -5,7 +5,7 @@ using NDecrypt.Core;
using SabreTools.CommandLine;
using SabreTools.CommandLine.Inputs;
-namespace NDecrypt
+namespace NDecrypt.Features
{
internal abstract class BaseFeature : Feature
{
diff --git a/NDecrypt/DecryptFeature.cs b/NDecrypt/Features/DecryptFeature.cs
similarity index 98%
rename from NDecrypt/DecryptFeature.cs
rename to NDecrypt/Features/DecryptFeature.cs
index 1f944c3..2cff730 100644
--- a/NDecrypt/DecryptFeature.cs
+++ b/NDecrypt/Features/DecryptFeature.cs
@@ -1,6 +1,6 @@
using System;
-namespace NDecrypt
+namespace NDecrypt.Features
{
internal sealed class DecryptFeature : BaseFeature
{
diff --git a/NDecrypt/EncryptFeature.cs b/NDecrypt/Features/EncryptFeature.cs
similarity index 98%
rename from NDecrypt/EncryptFeature.cs
rename to NDecrypt/Features/EncryptFeature.cs
index e7878f3..4d93563 100644
--- a/NDecrypt/EncryptFeature.cs
+++ b/NDecrypt/Features/EncryptFeature.cs
@@ -1,6 +1,6 @@
using System;
-namespace NDecrypt
+namespace NDecrypt.Features
{
internal sealed class EncryptFeature : BaseFeature
{
diff --git a/NDecrypt/InfoFeature.cs b/NDecrypt/Features/InfoFeature.cs
similarity index 97%
rename from NDecrypt/InfoFeature.cs
rename to NDecrypt/Features/InfoFeature.cs
index d76da38..5eef9e3 100644
--- a/NDecrypt/InfoFeature.cs
+++ b/NDecrypt/Features/InfoFeature.cs
@@ -1,6 +1,6 @@
using System;
-namespace NDecrypt
+namespace NDecrypt.Features
{
internal sealed class InfoFeature : BaseFeature
{
diff --git a/NDecrypt/Options.cs b/NDecrypt/Options.cs
deleted file mode 100644
index aa0890c..0000000
--- a/NDecrypt/Options.cs
+++ /dev/null
@@ -1,263 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-#if NET20 || NET35 || NET40 || NET452
-using System.Reflection;
-#endif
-
-namespace NDecrypt
-{
- ///
- /// Set of options for the test executable
- ///
- internal sealed class Options
- {
- #region Properties
-
- ///
- /// Feature to process input files with
- ///
- public FeatureFlag Feature { get; private set; }
-
- ///
- /// Path to config.json
- ///
- public string? ConfigPath { get; private set; }
-
- ///
- /// Enable using development keys, if available
- ///
- public bool Development { get; private set; } = false;
-
- ///
- /// Force operation by avoiding sanity checks
- ///
- public bool Force { get; private set; } = false;
-
- ///
- /// Set of input paths to use for operations
- ///
- public List InputPaths { get; private set; } = [];
-
- ///
- /// Output size and hashes to a companion file
- ///
- public bool OutputHashes { get; private set; } = false;
-
- ///
- /// Enable overwriting of the original file
- ///
- /// TODO: Change this to default false when hooked up
- public bool Overwrite { get; private set; } = true;
-
- #endregion
-
- ///
- /// Parse commandline arguments into an Options object
- ///
- public static Options? ParseOptions(string[] args)
- {
- // If we have invalid arguments
- if (args == null || args.Length < 2)
- {
- Console.WriteLine("Not enough arguments");
- return null;
- }
-
- // Create an Options object
- var options = new Options();
-
- // Derive the feature
- switch (args[0])
- {
- case "-?":
- case "-h":
- case "--help":
- return null;
-
- case "d":
- case "decrypt":
- options.Feature = FeatureFlag.Decrypt;
- break;
-
- case "e":
- case "encrypt":
- options.Feature = FeatureFlag.Encrypt;
- break;
-
- case "i":
- case "info":
- options.Feature = FeatureFlag.Info;
- break;
-
- default:
- Console.WriteLine($"Invalid operation: {args[0]}");
- return null;
- }
-
- // Parse the options and paths
- for (int index = 1; index < args.Length; index++)
- {
- string arg = args[index];
- switch (arg)
- {
- case "-?":
- case "-h":
- case "--help":
- return null;
-
- case "-c":
- case "--config":
- if (index == args.Length - 1)
- {
- Console.WriteLine("Invalid config path: no additional arguments found!");
- continue;
- }
-
- index++;
- options.ConfigPath = args[index];
- if (string.IsNullOrEmpty(options.ConfigPath))
- Console.WriteLine($"Invalid config path: null or empty path found!");
-
- options.ConfigPath = Path.GetFullPath(options.ConfigPath);
- if (!File.Exists(options.ConfigPath))
- {
- Console.WriteLine($"Invalid config path: file {options.ConfigPath} not found!");
- options.ConfigPath = null;
- }
-
- break;
-
- case "-d":
- case "--development":
- options.Development = true;
- break;
-
- case "-f":
- case "--force":
- options.Force = true;
- break;
-
- case "--hash":
- options.OutputHashes = true;
- break;
-
- case "-o":
- case "--overwrite":
- options.Overwrite = true;
- 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;
- }
-
- // Derive the config path based on the runtime folder if not already set
- options.ConfigPath = DeriveConfigFile(options.ConfigPath);
-
- return options;
- }
-
- ///
- /// Display help text
- ///
- /// Additional error text to display, can be null to ignore
- public static void DisplayHelp(string? err = null)
- {
- if (!string.IsNullOrEmpty(err))
- Console.WriteLine($"Error: {err}");
-
- Console.WriteLine("Cart Image Encrypt/Decrypt Tool");
- Console.WriteLine();
- Console.WriteLine("NDecrypt [options] ...");
- Console.WriteLine();
- Console.WriteLine("Operations:");
- Console.WriteLine("e, encrypt Encrypt the input files");
- Console.WriteLine("d, decrypt Decrypt the input files");
- Console.WriteLine("i, info Output file information");
- Console.WriteLine();
- Console.WriteLine("Options:");
- Console.WriteLine("-?, -h, --help Display this help text and quit");
- Console.WriteLine("-c, --config Path to config.json");
- Console.WriteLine("-d, --development Enable using development keys, if available");
- Console.WriteLine("-f, --force Force operation by avoiding sanity checks");
- Console.WriteLine("--hash Output size and hashes to a companion file");
- // Console.WriteLine("-o, --overwrite Overwrite input files instead of creating new ones");
- Console.WriteLine();
- Console.WriteLine(" can be any file or folder that contains uncompressed items.");
- Console.WriteLine("More than one path can be specified at a time.");
- }
-
- #region Helpers
-
- ///
- /// Derive the full path to the config file, if possible
- ///
- private static string? DeriveConfigFile(string? config)
- {
- // If a path is passed in
- if (!string.IsNullOrEmpty(config))
- {
- config = Path.GetFullPath(config);
- if (File.Exists(config))
- return config;
- }
-
- // Derive the keyfile path, if possible
- return GetFileLocation("config.json");
- }
-
- ///
- /// Search for a file in local and config directories
- ///
- /// Filename to check in local and config directories
- /// The full path to the file if found, null otherwise
- ///
- /// This method looks in the following locations:
- /// - %HOME%/.config/ndecrypt
- /// - Assembly location directory
- /// - Process runtime directory
- ///
- private static string? GetFileLocation(string filename)
- {
- // User home directory
-#if NET20 || NET35
- string homeDir = Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
- homeDir = Path.Combine(Path.Combine(homeDir, ".config"), "ndecrypt");
-#else
- string homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
- homeDir = Path.Combine(homeDir, ".config", "ndecrypt");
-#endif
- if (File.Exists(Path.Combine(homeDir, filename)))
- return Path.Combine(homeDir, filename);
-
- // Local directory
-#if NET20 || NET35 || NET40 || NET452
- string runtimeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
-#else
- string runtimeDir = AppContext.BaseDirectory;
-#endif
- if (File.Exists(Path.Combine(runtimeDir, filename)))
- return Path.Combine(runtimeDir, filename);
-
- // Process directory
- using var processModule = System.Diagnostics.Process.GetCurrentProcess().MainModule;
- string applicationDirectory = Path.GetDirectoryName(processModule?.FileName) ?? string.Empty;
- if (File.Exists(Path.Combine(applicationDirectory, filename)))
- return Path.Combine(applicationDirectory, filename);
-
- // No file was found
- return null;
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/NDecrypt/Program.cs b/NDecrypt/Program.cs
index 725a88d..6589259 100644
--- a/NDecrypt/Program.cs
+++ b/NDecrypt/Program.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using NDecrypt.Features;
using SabreTools.CommandLine;
using SabreTools.CommandLine.Features;