diff --git a/SabreTools.Helper/Data/Enums.cs b/SabreTools.Helper/Data/Enums.cs
index fcd1a5ca..411faf7b 100644
--- a/SabreTools.Helper/Data/Enums.cs
+++ b/SabreTools.Helper/Data/Enums.cs
@@ -285,6 +285,20 @@
#endregion
+ #region Help related
+
+ ///
+ /// Determines the feature type to check for
+ ///
+ public enum FeatureType
+ {
+ Flag = 0,
+ String,
+ List,
+ }
+
+ #endregion
+
#region Skippers and Mappers
///
diff --git a/SabreTools.Helper/Help/Feature.cs b/SabreTools.Helper/Help/Feature.cs
new file mode 100644
index 00000000..e6b9d90d
--- /dev/null
+++ b/SabreTools.Helper/Help/Feature.cs
@@ -0,0 +1,366 @@
+using System;
+using System.Collections.Generic;
+
+using SabreTools.Helper.Data;
+
+namespace SabreTools.Helper.Help
+{
+ public class Feature
+ {
+ #region Private variables
+
+ private List _flags;
+ private string _description;
+ private FeatureType _featureType;
+ private Dictionary _features;
+ private List _additionalNotes;
+ private bool _foundOnce = false;
+
+ #endregion
+
+ #region Constructors
+
+ public Feature()
+ {
+ _flags = new List();
+ _description = null;
+ _featureType = FeatureType.Flag;
+ _features = new Dictionary();
+ _additionalNotes = new List();
+ }
+
+ public Feature(string flag, string description, FeatureType featureType, List additionalNotes)
+ {
+ List flags = new List();
+ flags.Add(flag);
+ _flags = flags;
+ _description = description;
+ _featureType = featureType;
+ _features = new Dictionary();
+ _additionalNotes = additionalNotes;
+ }
+
+ public Feature(List flags, string description, FeatureType featureType, List additionalNotes)
+ {
+ _flags = flags;
+ _description = description;
+ _featureType = featureType;
+ _features = new Dictionary();
+ _additionalNotes = additionalNotes;
+ }
+
+ #endregion
+
+ #region Accessors
+
+ ///
+ /// Directly address a given subfeature
+ ///
+ public Feature this[string name]
+ {
+ get { return _features[name]; }
+ set { _features[name] = value; }
+ }
+
+ ///
+ /// Add a new feature for this feature
+ ///
+ /// Name of the feature to add
+ ///
+ public void AddFeature(string name, Feature feature)
+ {
+ if (_features == null)
+ {
+ _features = new Dictionary();
+ }
+
+ lock(_features)
+ {
+ if (!_features.ContainsKey(name))
+ {
+ _features.Add(name, feature);
+ }
+ else
+ {
+ _features[name] = feature;
+ }
+ }
+ }
+
+ ///
+ /// Add a new flag for this feature
+ ///
+ /// Flag to add for this feature
+ public void AddFlag(string flag)
+ {
+ if (_flags == null)
+ {
+ _flags = new List();
+ }
+
+ lock (_flags)
+ {
+ _flags.Add(flag);
+ }
+ }
+
+ ///
+ /// Add a set of new flags for this feature
+ ///
+ /// List of flags to add to this feature
+ public void AddFlags(List flags)
+ {
+ if (_flags == null)
+ {
+ _flags = new List();
+ }
+
+ lock (_flags)
+ {
+ _flags.AddRange(flags);
+ }
+ }
+
+ ///
+ /// Add a new additional note to this feature
+ ///
+ /// Note to add for this feature
+ public void AddNote(string note)
+ {
+ if (_additionalNotes == null)
+ {
+ _additionalNotes = new List();
+ }
+
+ lock (_additionalNotes)
+ {
+ _additionalNotes.Add(note);
+ }
+ }
+
+ ///
+ /// Add a set of new notes for this feature
+ ///
+ /// List of notes to add to this feature
+ public void AddNotes(List notes)
+ {
+ if (_additionalNotes == null)
+ {
+ _additionalNotes = new List();
+ }
+
+ lock (_additionalNotes)
+ {
+ _additionalNotes.AddRange(notes);
+ }
+ }
+
+ ///
+ /// Returns if a flag exists for the current feature
+ ///
+ /// Name of the flag to check
+ /// True if the flag was found, false otherwise
+ public bool ContainsFlag(string name)
+ {
+ bool success = false;
+
+ // Loop through the flags
+ foreach (string flag in _flags)
+ {
+ if (flag == name)
+ {
+ success = true;
+ break;
+ }
+ else if (flag.TrimStart('-') == name)
+ {
+ success = true;
+ break;
+ }
+ }
+
+ return success;
+ }
+
+ ///
+ /// Returns if the feature contains a flag that starts with the given character
+ ///
+ /// Character to check against
+ /// True if the flag was found, false otherwise
+ public bool StartsWith(char c)
+ {
+ bool success = false;
+
+ // Loop through the flags
+ foreach (string flag in _flags)
+ {
+ if (flag.TrimStart('-').ToLowerInvariant()[0] == c)
+ {
+ success = true;
+ break;
+ }
+ }
+
+ return success;
+ }
+
+ #endregion
+
+ #region Instance Methods
+
+ ///
+ /// Output this feature only
+ ///
+ /// Positive number representing number of spaces to put in front of the feature
+ /// Positive number representing the column where the description should start
+ public List Output(int pre = 0, int midpoint = 0)
+ {
+ // Create the output list
+ List outputList = new List();
+
+ // Build the output string first
+ string output = "";
+
+ // Add the pre-space first
+ for (int i = 0; i < pre; i++)
+ {
+ output += " ";
+ }
+
+ // Now add all flags
+ output += String.Join(", ", _flags);
+
+ // If we have a midpoint set, check to see if the string needs padding
+ if (midpoint > 0 && output.Length < midpoint)
+ {
+ while (output.Length < midpoint)
+ {
+ output += " ";
+ }
+ }
+ else
+ {
+ output += " ";
+ }
+
+ // Append the description
+ output += _description;
+
+ // Now append it to the list
+ outputList.Add(output);
+
+ return outputList;
+ }
+
+ ///
+ /// Output this feature and all subfeatures
+ ///
+ /// Level of indentation for this feature
+ /// Positive number representing number of spaces to put in front of the feature
+ /// Positive number representing the column where the description should start
+ public List OutputRecursive(int tabLevel, int pre = 0, int midpoint = 0)
+ {
+ // Create the output list
+ List outputList = new List();
+
+ // Build the output string first
+ string output = "";
+
+ // Normalize based on the tab level
+ int preAdjusted = pre;
+ int midpointAdjusted = midpoint;
+ if (tabLevel > 0)
+ {
+ preAdjusted += 4 * tabLevel;
+ midpointAdjusted += 4 * tabLevel;
+ }
+
+ // Add the pre-space first
+ for (int i = 0; i < preAdjusted; i++)
+ {
+ output += " ";
+ }
+
+ // Now add all flags
+ output += String.Join(", ", _flags);
+
+ // If we have a midpoint set, check to see if the string needs padding
+ if (midpoint > 0 && output.Length < midpointAdjusted)
+ {
+ while (output.Length < midpointAdjusted)
+ {
+ output += " ";
+ }
+ }
+ else
+ {
+ output += " ";
+ }
+
+ // Append the description
+ output += _description;
+
+ // Now append it to the list
+ outputList.Add(output);
+
+ // Now let's append all subfeatures
+ foreach (string feature in _features.Keys)
+ {
+ outputList.AddRange(_features[feature].OutputRecursive(tabLevel + 1, pre, midpoint));
+ }
+
+ return outputList;
+ }
+
+ ///
+ /// Validate whether a flag is valid for this feature or not
+ ///
+ /// Input to check against
+ /// True if just this feature should be checked, false if all subfeatures are checked as well
+ /// True if the flag was valid, false otherwise
+ public bool ValidateInput(string input, bool exact = false)
+ {
+ bool valid = false;
+
+ // Determine what we should be looking for
+ switch (_featureType)
+ {
+ // If we have a flag, make sure it doesn't have an equal sign in it
+ case FeatureType.Flag:
+ valid = !input.Contains("=") && _flags.Contains(input);
+ break;
+
+ // If we have an input, make sure it has an equals sign in it
+ case FeatureType.List:
+ case FeatureType.String:
+ valid = input.Contains("=") && _flags.Contains(input.Split('=')[0]);
+ break;
+ }
+
+ // If we haven't found a valid flag and we're not looking for just this feature, check to see if any of the subfeatures are valid
+ if (!valid && !exact)
+ {
+ foreach (string feature in _features.Keys)
+ {
+ valid = _features[feature].ValidateInput(input);
+
+ // If we've found a valid feature, we break out
+ if (valid)
+ {
+ break;
+ }
+ }
+ }
+
+ // If we've already found this flag before and we don't allow duplicates, set valid to false
+ if (valid && _foundOnce && _featureType != FeatureType.List)
+ {
+ valid = false;
+ }
+
+ return valid;
+ }
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Helper/Help/Help.cs b/SabreTools.Helper/Help/Help.cs
new file mode 100644
index 00000000..b7a9e01d
--- /dev/null
+++ b/SabreTools.Helper/Help/Help.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections.Generic;
+
+namespace SabreTools.Helper.Help
+{
+ public class Help
+ {
+ #region Private variables
+
+ private List _header;
+ private Dictionary _features;
+
+ #endregion
+
+ #region Constructors
+
+ public Help()
+ {
+ _header = new List();
+ _features = new Dictionary();
+ }
+
+ public Help(List header)
+ {
+ _header = header;
+ _features = new Dictionary();
+ }
+
+ #endregion
+
+ #region Accessors
+
+ ///
+ /// Add a new feature to the help
+ ///
+ /// Name of the feature to add
+ /// Feature object to map to
+ public void Add(string name, Feature feature)
+ {
+ if (_features == null)
+ {
+ _features = new Dictionary();
+ }
+
+ lock (_features)
+ {
+ _features.Add(name, feature);
+ }
+ }
+
+ #endregion
+
+ #region Instance Methods
+
+ ///
+ /// Output top-level features only
+ ///
+ public void OutputGenericHelp()
+ {
+ // Start building the output list
+ List output = new List();
+
+ // Append the header first
+ output.AddRange(_header);
+
+ // Now append all available top-level flags
+ output.Add("Available options:");
+ foreach (string feature in _features.Keys)
+ {
+ output.AddRange(_features[feature].Output(pre: 2, midpoint: 25));
+ }
+
+ // And append the generic ending
+ output.Add("");
+ output.Add("For information on available flags, put the option name after help");
+
+ // Now write out everything in a staged manner
+ WriteOutWithPauses(output);
+ }
+
+ ///
+ /// Output all features recursively
+ ///
+ public void OutputAllHelp()
+ {
+ // Start building the output list
+ List output = new List();
+
+ // Append the header first
+ output.AddRange(_header);
+
+ // Now append all available flags recursively
+ output.Add("Available options:");
+ foreach (string feature in _features.Keys)
+ {
+ output.AddRange(_features[feature].OutputRecursive(0, pre: 2, midpoint: 25));
+ }
+
+ // Now write out everything in a staged manner
+ WriteOutWithPauses(output);
+ }
+
+ ///
+ /// Output a single feature recursively
+ ///
+ public void OutputIndividualFeature(string featurename)
+ {
+ // Start building the output list
+ List output = new List();
+
+ // Append the header first
+ output.AddRange(_header);
+
+ // Now try to find the feature that has the name included
+ string realname = null;
+ List startsWith = new List();
+ foreach (string feature in _features.Keys)
+ {
+ // If we have a match to the feature name somehow
+ if (feature == featurename)
+ {
+ realname = feature;
+ break;
+ }
+
+ // If we have a match within the flags
+ else if (_features[feature].ContainsFlag(featurename))
+ {
+ realname = feature;
+ break;
+ }
+
+ // Otherwise, we want to get features with the same start
+ else if (_features[feature].StartsWith(featurename[0]))
+ {
+ startsWith.Add(feature);
+ }
+ }
+
+ // If we have a real name found, append all available subflags recursively
+ if (realname != null)
+ {
+ output.Add("Available options for " + realname + ":");
+ output.AddRange(_features[realname].OutputRecursive(0, pre: 2, midpoint: 25));
+ }
+
+ // If no name was found but we have possible matches, show them
+ else if (startsWith.Count > 0)
+ {
+ output.Add(featurename + " not found. Did you mean:");
+ foreach (string possible in startsWith)
+ {
+ output.AddRange(_features[possible].Output(pre: 2, midpoint: 25));
+ }
+ }
+
+ // Now write out everything in a staged manner
+ WriteOutWithPauses(output);
+ }
+
+ ///
+ /// Write out the help text with pauses, if needed
+ ///
+ ///
+ private void WriteOutWithPauses(List helptext)
+ {
+ // Now output based on the size of the screen
+ int i = 0;
+ foreach (string help in helptext)
+ {
+ Console.WriteLine(help);
+ i++;
+
+ // If we're not being redirected and we reached the size of the screen, pause
+ if (i == Console.WindowHeight - 3)
+ {
+ i = 0;
+ Pause();
+ }
+ }
+ Pause();
+ }
+
+ ///
+ /// Pause on console output
+ ///
+ private static void Pause()
+ {
+ if (!Console.IsOutputRedirected)
+ {
+ Console.WriteLine();
+ Console.WriteLine("Press enter to continue...");
+ Console.ReadLine();
+ }
+ }
+
+ /*
+ * Here is a non-comprehensive list of things we want a help method to do:
+ * - Parse and return flags from arguments
+ * - Perform partial matching to find potentially similar features
+ */
+
+ #endregion
+ }
+}
diff --git a/SabreTools.Helper/SabreTools.Helper.csproj b/SabreTools.Helper/SabreTools.Helper.csproj
index d62ad2ff..08236515 100644
--- a/SabreTools.Helper/SabreTools.Helper.csproj
+++ b/SabreTools.Helper/SabreTools.Helper.csproj
@@ -146,6 +146,8 @@
+
+
diff --git a/SabreTools/Partials/SabreTools.Help.cs b/SabreTools/Partials/SabreTools.Help.cs
new file mode 100644
index 00000000..7f882881
--- /dev/null
+++ b/SabreTools/Partials/SabreTools.Help.cs
@@ -0,0 +1,678 @@
+using System.Collections.Generic;
+
+using SabreTools.Helper.Data;
+using SabreTools.Helper.Help;
+using SabreTools.Helper.Resources;
+
+namespace SabreTools
+{
+ public partial class SabreTools
+ {
+ public static Help RetrieveHelp()
+ {
+ // Create and add the header to the Help object
+ string barrier = "-----------------------------------------";
+ List helpHeader = new List();
+ helpHeader.Add(Resources.SabreTools_Name + " - " + Resources.SabreTools_Desc);
+ helpHeader.Add(barrier);
+ helpHeader.Add(Resources.Usage + ": " + Resources.SabreTools_Name + " [option] [flags] [filename|dirname] ...");
+ helpHeader.Add("");
+ Help help = new Help(helpHeader);
+
+ // Create the Help feature
+ Feature helpFeature = new Feature(
+ new List() { "-?", "-h", "--help" },
+ "Show this help",
+ FeatureType.Flag,
+ null);
+
+ // Create the Script feature
+ Feature script = new Feature(
+ "--script",
+ "Enable script mode (no clear screen)",
+ FeatureType.Flag,
+ null);
+
+ // Create the DATFromDir feature
+ Feature datFromDir = new Feature(
+ new List() { "-d", "--d2d", "--dfd" },
+ "Create a DAT from an input directory",
+ FeatureType.Flag,
+ null);
+ datFromDir.AddFeature("noMD5", new Feature(
+ new List() { "-nm", "--noMD5" },
+ "Don't include MD5 in output",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("noSHA1", new Feature(
+ new List() { "-ns", "--noSHA1" },
+ "Don't include SHA1 in output",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("bare", new Feature(
+ new List() { "-b", "--bare" },
+ "Don't include date in file name",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("forcepack", new Feature(
+ new List() { "-fp", "--forcepack" },
+ "Set force packing",
+ FeatureType.String,
+ new List()
+ {
+ "Supported values are:",
+ " None, Zip, Unzip",
+ }));
+ datFromDir.AddFeature("files", new Feature(
+ new List() { "-f", "--files" },
+ "Treat archives as files",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-all", new Feature(
+ new List() { "-oa", "--output-all" },
+ "Output in all formats",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-am", new Feature(
+ new List() { "-oam", "--output-am" },
+ "Output in AttractMode format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-cmp", new Feature(
+ new List() { "-oc", "--output-cmp" },
+ "Output in CMP format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-csv", new Feature(
+ new List() { "-ocsv", "--output-csv" },
+ "Output in CSV format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-dc", new Feature(
+ new List() { "-od", "--output-dc" },
+ "Output in DOSCenter format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-miss", new Feature(
+ new List() { "-om", "--output-miss" },
+ "Output in Missfile format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-md5", new Feature(
+ new List() { "-oa", "--output-md5" },
+ "Output in MD5 format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-ol", new Feature(
+ new List() { "-ool", "--output-ol" },
+ "Output in OfflineList format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-rc", new Feature(
+ new List() { "-or", "--output-rc" },
+ "Output in RomCenter format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-sd", new Feature(
+ new List() { "-os", "--output-sd" },
+ "Output in SabreDat format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-sfv", new Feature(
+ new List() { "-osfv", "--output-sfv" },
+ "Output in SFV format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-sha1", new Feature(
+ new List() { "-osfv", "--output-sha1" },
+ "Output in SHA-1 format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-sl", new Feature(
+ new List() { "-osl", "--output-sl" },
+ "Output in Softwarelist format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-tsv", new Feature(
+ new List() { "-otsv", "--output-tsv" },
+ "Output in TSV format",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("output-xml", new Feature(
+ new List() { "-ox", "--output-xml" },
+ "Output in Logiqx XML format [default]",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("gz-files", new Feature(
+ new List() { "-gzf", "--gz-files" },
+ "Allow reading of GZIP files as archives",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("romba", new Feature(
+ new List() { "-ro", "--romba" },
+ "Read files from a Romba input",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("filename", new Feature(
+ new List() { "-f", "--filename" },
+ "Set the external name of the DAT",
+ FeatureType.String,
+ null));
+ datFromDir.AddFeature("name", new Feature(
+ new List() { "-n", "--name" },
+ "Set the internal name of the DAT",
+ FeatureType.String,
+ null));
+ datFromDir.AddFeature("desc", new Feature(
+ new List() { "-d", "--desc" },
+ "Set the description of the DAT",
+ FeatureType.String,
+ null));
+ datFromDir.AddFeature("cat", new Feature(
+ new List() { "-c", "--cat" },
+ "Set the category of the DAT",
+ FeatureType.String,
+ null));
+ datFromDir.AddFeature("version", new Feature(
+ new List() { "-v", "--version" },
+ "Set the version of the DAT",
+ FeatureType.String,
+ null));
+ datFromDir.AddFeature("author", new Feature(
+ new List() { "-au", "--author" },
+ "Set the author of the DAT",
+ FeatureType.String,
+ null));
+ datFromDir.AddFeature("superdat", new Feature(
+ new List() { "-sd", "--superdat" },
+ "Enable SuperDAT creation",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("exclude-of", new Feature(
+ new List() { "-xof", "--exclude-of" },
+ "Exclude romof, cloneof, sampleof tags",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("add-blank", new Feature(
+ new List() { "-ab", "--add-blank" },
+ "Output blank files for folders",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("add-date", new Feature(
+ new List() { "-ad", "--add-date" },
+ "Output dates for each file parsed",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("copy-files", new Feature(
+ new List() { "-cf", "--copy-files" },
+ "Copy files to the temp directory before parsing",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("header", new Feature(
+ new List() { "-h", "--header" },
+ "Set a header skipper to use, blank means all",
+ FeatureType.Flag,
+ null));
+ datFromDir.AddFeature("temp", new Feature(
+ new List() { "-t", "--temp" },
+ "Set the temporary directory to use",
+ FeatureType.String,
+ null));
+ datFromDir.AddFeature("mt", new Feature(
+ new List() { "-mt", "--mt" },
+ "Amount of threads to use (default 4, -1 unlimted)",
+ FeatureType.String,
+ null));
+
+ // Create the Extract feature
+ Feature extract = new Feature(
+ new List() { "-ex", "--extract" },
+ "Extract and remove copier headers",
+ FeatureType.Flag,
+ null);
+ extract.AddFeature("out", new Feature(
+ new List() { "-out", "--out" },
+ "Output directory",
+ FeatureType.String,
+ null));
+
+ // Create the Extension Split feature
+ Feature extSplit = new Feature(
+ new List() { "-es", "--ext-split" },
+ "Split a DAT by two file extensions",
+ FeatureType.Flag,
+ null);
+ extSplit.AddFeature("exta", new Feature(
+ new List() { "-exta", "--exta" },
+ "First extension (multiple allowed)",
+ FeatureType.List,
+ null));
+ extSplit.AddFeature("extb", new Feature(
+ new List() { "-extb", "--extb" },
+ "Second extension (multiple allowed)",
+ FeatureType.List,
+ null));
+ extSplit.AddFeature("out", new Feature(
+ new List() { "-out", "--out" },
+ "Output directory",
+ FeatureType.String,
+ null));
+
+ // Create the Hash Split feature
+ Feature hashSplit = new Feature(
+ new List() { "-hs", "--hash-split" },
+ "Split a DAT or folder by best-available hashes",
+ FeatureType.Flag,
+ null);
+ hashSplit.AddFeature("out", new Feature(
+ new List() { "-out", "--out" },
+ "Output directory",
+ FeatureType.String,
+ null));
+
+ // Create the Level Split feature
+ Feature levelSplit = new Feature(
+ new List() { "-ls", "--lvl-split" },
+ "Split a SuperDAT or folder by internal path",
+ FeatureType.Flag,
+ null);
+ levelSplit.AddFeature("out", new Feature(
+ new List() { "-out", "--out" },
+ "Output directory",
+ FeatureType.String,
+ null));
+ levelSplit.AddFeature("short", new Feature(
+ new List() { "-s", "--short" },
+ "Use short output names",
+ FeatureType.Flag,
+ null));
+ levelSplit.AddFeature("base", new Feature(
+ new List() { "-ba", "--base" },
+ "Use source DAT as base name for outputs",
+ FeatureType.Flag,
+ null));
+
+ // Create the Restore feature
+ Feature restore = new Feature(
+ new List() { "-re", "--restore" },
+ "Restore header to file based on SHA-1",
+ FeatureType.Flag,
+ null);
+ restore.AddFeature("out", new Feature(
+ new List() { "-out", "--out" },
+ "Output directory",
+ FeatureType.String,
+ null));
+
+ // Create the Sort feature
+ Feature sort = new Feature(
+ new List() { "-ss", "--sort" },
+ "Sort inputs by a set of DATs",
+ FeatureType.Flag,
+ new List()
+ {
+ "Archive scanning levels:",
+ " 0 Hash archive and contents",
+ " 1 Only hash contents",
+ " 2 Only hash archive",
+ });
+ sort.AddFeature("dat", new Feature(
+ new List() { "-dat", "--dat" },
+ "Input DAT to rebuild against",
+ FeatureType.List,
+ null));
+ sort.AddFeature("out", new Feature(
+ new List() { "-out", "--out" },
+ "Output directory",
+ FeatureType.String,
+ null));
+ sort.AddFeature("temp", new Feature(
+ new List() { "-temp", "--temp" },
+ "Set the temporary directory to use",
+ FeatureType.String,
+ null));
+ sort.AddFeature("delete", new Feature(
+ new List() { "-del", "--delete" },
+ "Delete fully rebuilt input files",
+ FeatureType.Flag,
+ null));
+ sort.AddFeature("inverse", new Feature(
+ new List() { "-in", "--inverse" },
+ "Rebuild only files not in DAT",
+ FeatureType.Flag,
+ null));
+ sort.AddFeature("quick", new Feature(
+ new List() { "-qs", "--quick" },
+ "Enable quick scanning of archives",
+ FeatureType.Flag,
+ null));
+ sort.AddFeature("add-date", new Feature(
+ new List() { "-ad", "--add-date" },
+ "Add original dates from DAT, if possible",
+ FeatureType.Flag,
+ null));
+ /*
+ sort.AddFeature("t7z", new Feature(
+ new List() { "-t7z", "--t7z" },
+ "Enable Torrent7z output",
+ FeatureType.Flag,
+ null));
+ */
+ sort.AddFeature("tar", new Feature(
+ new List() { "-tar", "--tar" },
+ "Enable TAR output",
+ FeatureType.Flag,
+ null));
+ sort.AddFeature("tgz", new Feature(
+ new List() { "-tgz", "--tgz" },
+ "Enable TorrentGZ output",
+ FeatureType.Flag,
+ null));
+ sort["tgz"].AddFeature("romba", new Feature(
+ new List() { "-r", "--romba" },
+ "Enable Romba depot dir output",
+ FeatureType.Flag,
+ null));
+ /*
+ sort.AddFeature("tlrz", new Feature(
+ new List() { "-tlrz", "--tlrz" },
+ "Enable TorrentLRZ output",
+ FeatureType.Flag,
+ null));
+ */
+ /*
+ sort.AddFeature("trar", new Feature(
+ new List() { "-trar", "--trar" },
+ "Enable TorrentRAR output",
+ FeatureType.Flag,
+ null));
+ */
+ /*
+ sort.AddFeature("txz", new Feature(
+ new List() { "-txz", "--txz" },
+ "Enable TorrentXZ output",
+ FeatureType.Flag,
+ null));
+ */
+ sort.AddFeature("tzip", new Feature(
+ new List() { "-tzip", "--tzip" },
+ "Enable TorrentZip output",
+ FeatureType.Flag,
+ null));
+ sort.AddFeature("header", new Feature(
+ new List() { "-h", "--header" },
+ "Set a header skipper to use, blank means all",
+ FeatureType.String,
+ null));
+ sort.AddFeature("7z", new Feature(
+ new List() { "-7z", "--7z" },
+ "Set scanning level for 7z archives (default 1)",
+ FeatureType.String,
+ null));
+ sort.AddFeature("gz", new Feature(
+ new List() { "-gz", "--gz" },
+ "Set scanning level for GZip archives (default 2)",
+ FeatureType.String,
+ null));
+ sort.AddFeature("rar", new Feature(
+ new List() { "-rar", "--rar" },
+ "Set scanning level for RAR archives (default 2)",
+ FeatureType.String,
+ null));
+ sort.AddFeature("zip", new Feature(
+ new List() { "-zip", "--zip" },
+ "Set scanning level for ZIP archives (default 1)",
+ FeatureType.String,
+ null));
+ sort.AddFeature("update-dat", new Feature(
+ new List() { "-ud", "--update-dat" },
+ "Output updated DAT to output directory",
+ FeatureType.Flag,
+ null));
+ sort.AddFeature("mt", new Feature(
+ new List() { "-mt", "--mt" },
+ "Amount of threads to use (default 4, -1 unlimted)",
+ FeatureType.String,
+ null));
+
+ /*
+
+ // Create the Sort Depot feature
+ Feature sortDepot = new Feature(
+ new List() { "-ssd", "--sort-depot" },
+ "Sort romba depots by a set of DATs",
+ FeatureType.Flag,
+ null);
+ helptext.Add(" -dat= Input DAT to rebuild against");
+ helptext.Add(" -out= Output directory");
+ helptext.Add(" -t=, --temp= Set the temporary directory to use");
+ helptext.Add(" -del, --delete Delete fully rebuilt input files");
+ helptext.Add(" -in, --inverse Rebuild only files not in DAT");
+ helptext.Add(" -ad, --add-date Add original dates from DAT, if possible");
+ //helptext.Add(" -t7z Enable Torrent7z output");
+ helptext.Add(" -tar Enable TAR output");
+ helptext.Add(" -tgz Enable TorrentGZ output");
+ helptext.Add(" -r, --romba Enable Romba depot dir output");
+ //helptext.Add(" -tlrz Enable TorrentLRZ output");
+ //helptext.Add(" -trar Enable TorrentRAR output");
+ //helptext.Add(" -txz Enable TorrentXZ output");
+ helptext.Add(" -tzip Enable TorrentZip output");
+ helptext.Add(" -h=, --header= Set a header skipper to use, blank means all");
+ helptext.Add(" -ud, --update-dat Output updated DAT to output directory");
+ helptext.Add(" -mt={4} Amount of threads to use (-1 unlimted)");
+
+ // Create the Stats feature
+ Feature stats = new Feature(
+ new List() { "-st", "--stats" },
+ "Get statistics on all input DATs",
+ FeatureType.Flag,
+ null);
+ helptext.Add(" -bc, --baddump-col Add baddump stats to output");
+ helptext.Add(" -csv, --csv Output in Comma-Separated Value format");
+ helptext.Add(" -f=, --filename= Set the filename for the output");
+ helptext.Add(" -out= Output directory");
+ helptext.Add(" -html, --html Output in HTML format");
+ helptext.Add(" -nc, --nodump-col Add nodump stats to output");
+ helptext.Add(" -si, --single Show individual statistics");
+ helptext.Add(" -tsv, --tsv Output in Tab-Separated Value format");
+
+ // Create the Type Split feature
+ Feature typeSplit = new Feature(
+ new List() { "-ts", "--type-split" },
+ "Split a DAT or folder by file types (rom/disk)",
+ FeatureType.Flag,
+ null);
+ elptext.Add(" -out= Output directory");
+
+ // Create the Update feature
+ Feature update = new Feature(
+ new List() { "-ud", "--update" },
+ "Update a DAT file",
+ FeatureType.Flag,
+ null);
+ helptext.Add(" -oa, --output-all Output in all formats");
+ helptext.Add(" -oam, --output-am Output in AttractMode format");
+ helptext.Add(" -oc, --output-cmp Output in CMP format");
+ helptext.Add(" -ocsv, --output-csv Output in CSV format");
+ helptext.Add(" -pre=, --prefix= Set prefix for all lines");
+ helptext.Add(" -post=, --postfix= Set postfix for all lines");
+ helptext.Add(" -q, --quotes Put double-quotes around each item");
+ helptext.Add(" -od, --output-dc Output in DOSCenter format");
+ helptext.Add(" -om, --output-miss Output in Missfile format");
+ helptext.Add(" -r, --roms Output roms to miss instead of sets");
+ helptext.Add(" -gp, --game-prefix Add game name as a prefix");
+ helptext.Add(" -pre=, --prefix= Set prefix for all lines");
+ helptext.Add(" -post=, --postfix= Set postfix for all lines");
+ helptext.Add(" -q, --quotes Put double-quotes around each item");
+ helptext.Add(" -ae=, --add-ext= Add an extension to each item");
+ helptext.Add(" -rep=, --rep-ext= Replace all extensions with specified");
+ helptext.Add(" -rme, --rem-ext Remove all extensions from each item");
+ helptext.Add(" -ro, --romba Output in Romba format (requires SHA-1)");
+ helptext.Add(" -tsv, --tsv Output in Tab-Separated Value format");
+ helptext.Add(" -csv, --csv Output in Comma-Separated Value format");
+ helptext.Add(" -omd5, --output-md5 Output in MD5 format");
+ helptext.Add(" -gp, --game-prefix Add game name as a prefix");
+ helptext.Add(" -ool, --output-ol Output in OfflineList format");
+ helptext.Add(" -or, --output-rc Output in RomCenter format");
+ helptext.Add(" -os, --output-sd Output in SabreDAT format");
+ helptext.Add(" -osfv, --ouput-sfv Output in SFV format");
+ helptext.Add(" -gp, --game-prefix Add game name as a prefix");
+ helptext.Add(" -osha1, --output-sha1 Output in SHA-1 format");
+ helptext.Add(" -gp, --game-prefix Add game name as a prefix");
+ helptext.Add(" -osl, --output-sl Output in Softwarelist format");
+ helptext.Add(" -otsv, --output-tsv Output in TSV format");
+ helptext.Add(" -pre=, --prefix= Set prefix for all lines");
+ helptext.Add(" -post=, --postfix= Set postfix for all lines");
+ helptext.Add(" -q, --quotes Put double-quotes around each item");
+ helptext.Add(" -ox, --output-xml Output in Logiqx XML format");
+ helptext.Add(" -f=, --filename= Set a new filename");
+ helptext.Add(" -n=, --name= Set a new internal name");
+ helptext.Add(" -de=, --desc= Set a new description");
+ helptext.Add(" -r=, --root= Set a new rootdir");
+ helptext.Add(" -ca=, --category= Set a new category");
+ helptext.Add(" -v=, --version= Set a new version");
+ helptext.Add(" -da=, --date= Set a new date");
+ helptext.Add(" -au=, --author= Set a new author");
+ helptext.Add(" -em=, --email= Set a new email");
+ helptext.Add(" -hp=, --homepage= Set a new homepage");
+ helptext.Add(" -u=, --url= Set a new URL");
+ helptext.Add(" -co=, --comment= Set a new comment");
+ helptext.Add(" -h=, --header= Set a new header skipper");
+ helptext.Add(" -sd=, --superdat Set SuperDAT type");
+ helptext.Add(" -fm=, --forcemerge= Set force merging");
+ helptext.Add(" Supported values are:");
+ helptext.Add(" None, Split, Full");
+ helptext.Add(" -fn=, --forcend= Set force nodump");
+ helptext.Add(" Supported values are:");
+ helptext.Add(" None, Obsolete, Required, Ignore");
+ helptext.Add(" -fp=, --forcepack= Set force packing");
+ helptext.Add(" Supported values are:");
+ helptext.Add(" None, Zip, Unzip");
+ helptext.Add(" -xof, --exclude-of Exclude romof, cloneof, sampleof tags");
+ helptext.Add(" -clean Clean game names according to WoD standards");
+ helptext.Add(" -sl, --softlist Use Software List name instead of description");
+ helptext.Add(" -dm, --dat-merged Create merged sets");
+ helptext.Add(" -ds, --dat-split Create split sets");
+ helptext.Add(" -dnm, --dat-nonmerged Create non-merged sets");
+ helptext.Add(" -df, --dat-fullnonmerged Create fully non-merged sets");
+ helptext.Add(" -trim Trim file names to fit NTFS length");
+ helptext.Add(" -rd=, --root-dir= Set the root directory for calc");
+ helptext.Add(" -si, --single All game names replaced by '!'");
+ helptext.Add(" -dd, --dedup Enable deduping in the created DAT");
+ helptext.Add(" -m, --merge Merge the input DATs");
+ helptext.Add(" -b, --bare Don't include date in automatic name");
+ helptext.Add(" -di, --diff Create diffdats from inputs (all outputs)");
+ helptext.Add(" -b, --bare Don't include date in automatic name");
+ helptext.Add(" -c, --cascade Enable cascaded diffing");
+ helptext.Add(" -ip, --inplace Enable inplace, cascaded diff");
+ helptext.Add(" -sf, --skip Skip output of first DAT");
+ helptext.Add(" -rc, --rev-cascade Enable reverse cascaded diffing");
+ helptext.Add(" -ip, --inplace Enable inplace, cascaded diff");
+ helptext.Add(" -sf, --skip Skip output of first DAT");
+ helptext.Add(" -did, --diff-du Create diffdat containing just duplicates");
+ helptext.Add(" -b, --bare Don't include date in automatic name");
+ helptext.Add(" -dii, --diff-in Create diffdats for individual DATs");
+ helptext.Add(" -b, --bare Don't include date in automatic name");
+ helptext.Add(" -din, --diff-nd Create diffdat containing no duplicates");
+ helptext.Add(" -b, --bare Don't include date in automatic name");
+ helptext.Add(" -gn=, --game-name= Filter by game name");
+ helptext.Add(" -ngn=, --not-game= Filter by not game name");
+ helptext.Add(" -rn=, --rom-name= Filter by rom name");
+ helptext.Add(" -nrn=, --not-rom= Filter by not rom name");
+ helptext.Add(" -rt=, --rom-type= Filter by rom type");
+ helptext.Add(" -nrt=, --not-type= Filter by not rom type");
+ helptext.Add(" -sgt=, --greater= Filter by size >=");
+ helptext.Add(" -slt=, --less= Filter by size <=");
+ helptext.Add(" -seq=, --equal= Filter by size ==");
+ helptext.Add(" -crc=, --crc= Filter by CRC hash");
+ helptext.Add(" -ncrc=, --not-crc= Filter by not CRC hash");
+ helptext.Add(" -md5=, --md5= Filter by MD5 hash");
+ helptext.Add(" -nmd5=, --not-md5= Filter by not MD5 hash");
+ helptext.Add(" -sha1=, --sha1= Filter by SHA-1 hash");
+ helptext.Add(" -nsha1=, --not-sha1= Filter by not SHA-1 hash");
+ helptext.Add(" -is=, --status= Include only items with a given status");
+ helptext.Add(" Supported values are:");
+ helptext.Add(" None, Good, BadDump, Nodump, Verified");
+ helptext.Add(" -nis=, --not-status= Exclude items with a given status");
+ helptext.Add(" Supported values are:");
+ helptext.Add(" None, Good, BadDump, Nodump, Verified");
+ helptext.Add(" -gt=, --game-type= Include only games with a given type");
+ helptext.Add(" Supported values are:");
+ helptext.Add(" None, Bios, Device, Mechanical");
+ helptext.Add(" -ngt=, --not-gtype= Exclude only games with a given type");
+ helptext.Add(" Supported values are:");
+ helptext.Add(" None, Bios, Device, Mechanical");
+ helptext.Add(" -run, --runnable Include only items that are marked runnable");
+ helptext.Add(" -nrun, --not-run Include only items that are marked unrunnable");
+ helptext.Add(" -out= Output directory (overridden by --inplace)");
+ helptext.Add(" -mt={4} Amount of threads to use (-1 unlimted)");
+
+
+ helptext.Add("");
+ helptext.Add(barrier);
+ helptext.Add("Additional Notes:");
+
+ helptext.Add("");
+ helptext.Add("All -diX, --diff-XX flags can be used with each other");
+
+ helptext.Add("");
+ helptext.Add("Filter parameters game name, rom name, CRC, MD5, SHA-1 can");
+ helptext.Add("do partial matches using asterisks as follows (case insensitive):");
+ helptext.Add(" *00 means ends with '00'");
+ helptext.Add(" 00* means starts with '00'");
+ helptext.Add(" *00* means contains '00'");
+ helptext.Add(" 00 means exactly equals '00'");
+
+ helptext.Add("");
+ helptext.Add("Filter parameters for size can use postfixes for inputs:");
+ helptext.Add(" e.g. 8kb => 8000 or 8kib => 8192");
+
+ helptext.Add("");
+ helptext.Add("Most of the filter parameters allow for multiple inputs:");
+ helptext.Add(" e.g. --game-name=foo --game-name=bar");
+
+ // Create the Verify feature
+ Feature verify = new Feature(
+ new List() { "-ve", "--verify" },
+ "Verify a folder against DATs",
+ FeatureType.Flag,
+ null);
+ helptext.Add(" -dat= Input DAT to verify against");
+ helptext.Add(" -t=, --temp= Set the temporary directory to use");
+ helptext.Add(" -ho, --hash-only Check files by hash only");
+ helptext.Add(" -qs, --quick Enable quick scanning of archives");
+ helptext.Add(" -h=, --header= Set a header skipper to use, blank means all");
+
+ // Create the Verify Depot feature
+ Feature verifyDepot = new Feature(
+ new List() { "-ved", "--verify-depot" },
+ "Verify a depot against DATs",
+ FeatureType.Flag,
+ null);
+ helptext.Add(" -dat= Input DAT to verify against");
+ helptext.Add(" -t=, --temp= Set the temporary directory to use");
+ helptext.Add(" -h=, --header= Set a header skipper to use, blank means all");
+
+ */
+
+ // Now, add all of the main features to the Help object
+ help.Add("Help", helpFeature);
+ help.Add("Script", script);
+ help.Add("DATFromDir", datFromDir);
+ help.Add("Extract", extract);
+ help.Add("Extension Split", extSplit);
+ help.Add("Hash Split", hashSplit);
+ help.Add("Level Split", levelSplit);
+ help.Add("Restore", restore);
+ help.Add("Sort", sort);
+ //help.Add("Sort Depot", sortDepot);
+ //help.Add("Stats", stats);
+ //help.Add("Type Split", typeSplit);
+ //help.Add("Update", update);
+ //help.Add("Verify", verify);
+ //help.Add("Verify Depot", verifyDepot);
+
+ return help;
+ }
+ }
+}
diff --git a/SabreTools/SabreTools.cs b/SabreTools/SabreTools.cs
index 39c3a236..74510a9d 100644
--- a/SabreTools/SabreTools.cs
+++ b/SabreTools/SabreTools.cs
@@ -4,6 +4,8 @@ using System.Linq;
using SabreTools.Helper;
using SabreTools.Helper.Data;
+using SabreTools.Helper.Help;
+using SabreTools.Helper.Resources;
#if MONO
using System.IO;
@@ -53,6 +55,9 @@ namespace SabreTools
return;
}
+ // Create a new Help object for this program
+ //Help help = RetrieveHelp();
+
// Feature flags
bool datFromDir = false,
extract = false,
diff --git a/SabreTools/SabreTools.csproj b/SabreTools/SabreTools.csproj
index 607b78d1..b5d891d6 100644
--- a/SabreTools/SabreTools.csproj
+++ b/SabreTools/SabreTools.csproj
@@ -122,6 +122,7 @@
+