示例#1
0
        /// <summary>
        /// Create a new Dat from a directory
        /// </summary>
        /// <param name="datFile">Current DatFile object to add to</param>
        /// <param name="basePath">Base folder to be used in creating the DAT</param>
        /// <param name="asFiles">TreatAsFiles representing CHD and Archive scanning</param>
        /// <param name="skipFileType">Type of files that should be skipped</param>
        /// <param name="addBlanks">True if blank items should be created for empty folders, false otherwise</param>
        /// <param name="hashes">Hashes to include in the information</param>
        public static bool PopulateFromDir(
            DatFile datFile,
            string basePath,
            TreatAsFile asFiles       = 0x00,
            SkipFileType skipFileType = SkipFileType.None,
            bool addBlanks            = false,
            Hash hashes = Hash.Standard)
        {
            // Set the progress variables
            long totalSize   = 0;
            long currentSize = 0;

            InternalStopwatch watch = new InternalStopwatch($"Populating DAT from {basePath}");

            // Process the input
            if (Directory.Exists(basePath))
            {
                logger.Verbose($"Folder found: {basePath}");

                // Get a list of all files to process
                List <string> files = Directory.EnumerateFiles(basePath, "*", SearchOption.AllDirectories).ToList();

                // Loop through and add the file sizes
                Parallel.ForEach(files, Globals.ParallelOptions, item =>
                {
                    Interlocked.Add(ref totalSize, new FileInfo(item).Length);
                });

                // Process the files in the main folder or any subfolder
                logger.User(totalSize, currentSize);
                foreach (string item in files)
                {
                    CheckFileForHashes(datFile, item, basePath, asFiles, skipFileType, addBlanks, hashes);
                    currentSize += new FileInfo(item).Length;
                    logger.User(totalSize, currentSize, item);
                }

                // Now find all folders that are empty, if we are supposed to
                if (addBlanks)
                {
                    ProcessDirectoryBlanks(datFile, basePath);
                }
            }
            else if (File.Exists(basePath))
            {
                logger.Verbose($"File found: {basePath}");

                totalSize = new FileInfo(basePath).Length;
                logger.User(totalSize, currentSize);

                string parentPath = Path.GetDirectoryName(Path.GetDirectoryName(basePath));
                CheckFileForHashes(datFile, basePath, parentPath, asFiles, skipFileType, addBlanks, hashes);
                logger.User(totalSize, totalSize, basePath);
            }

            watch.Stop();
            return(true);
        }
        /// <summary>
        /// Wrap creating a DAT file from files or a directory in parallel
        /// </summary>
        /// <param name="inputs">List of input filenames</param>
        /// /* Normal DAT header info */
        /// <param name="datHeader">All DatHeader info to be used</param>
        /// /* Standard DFD info */
        /// <param name="omitFromScan">Hash flag saying what hashes should not be calculated</param>
        /// <param name="removeDateFromAutomaticName">True if the date should be omitted from the DAT, false otherwise</param>
        /// <param name="archivesAsFiles">True if archives should be treated as files, false otherwise</param>
        /// <param name="chdsAsFiles">True if CHDs should be treated like regular files, false otherwise</param>
        /// <param name="skipFileType">Type of files that should be skipped on scan</param>
        /// <param name="addBlankFilesForEmptyFolder">True if blank items should be created for empty folders, false otherwise</param>
        /// <param name="addFileDates">True if dates should be archived for all files, false otherwise</param>
        /// <param name="filter">Filter object to be passed to the DatItem level</param>
        /// /* Output DAT info */
        /// <param name="tempDir">Name of the directory to create a temp folder in (blank is default temp directory)</param>
        /// <param name="outDir">Name of the directory to output the DAT to (blank is the current directory)</param>
        /// <param name="copyFiles">True if files should be copied to the temp directory before hashing, false otherwise</param>
        /// /* Filtering info */
        /// <param name="filter">Filter object to be passed to the DatItem level</param>
        private static void InitDatFromDir(List <string> inputs,
                                           /* Normal DAT header info */
                                           DatHeader datHeader,

                                           /* Standard DFD info */
                                           Hash omitFromScan,
                                           bool removeDateFromAutomaticName,
                                           bool archivesAsFiles,
                                           bool chdsAsFiles,
                                           SkipFileType skipFileType,
                                           bool addBlankFilesForEmptyFolder,
                                           bool addFileDates,

                                           /* Output DAT info */
                                           string tempDir,
                                           string outDir,
                                           bool copyFiles,

                                           /* Filtering info */
                                           Filter filter)
        {
            // Create a new DATFromDir object and process the inputs
            DatFile basedat = new DatFile(datHeader)
            {
                Date = DateTime.Now.ToString("yyyy-MM-dd"),
            };

            // For each input directory, create a DAT
            foreach (string path in inputs)
            {
                if (Directory.Exists(path) || File.Exists(path))
                {
                    // Clone the base Dat for information
                    DatFile datdata = new DatFile(basedat);

                    string basePath = Path.GetFullPath(path);
                    bool   success  = datdata.PopulateFromDir(basePath, omitFromScan, removeDateFromAutomaticName, archivesAsFiles,
                                                              skipFileType, addBlankFilesForEmptyFolder, addFileDates, tempDir, copyFiles, datHeader.Header, chdsAsFiles, filter);

                    // If it was a success, write the DAT out
                    if (success)
                    {
                        datdata.Write(outDir);
                    }

                    // Otherwise, show the help
                    else
                    {
                        Console.WriteLine();
                        _help.OutputIndividualFeature("DATFromDir");
                    }
                }
            }
        }
示例#3
0
        /// <summary>
        /// Check a given file for hashes, based on current settings
        /// </summary>
        /// <param name="datFile">Current DatFile object to add to</param>
        /// <param name="item">Filename of the item to be checked</param>
        /// <param name="basePath">Base folder to be used in creating the DAT</param>
        /// <param name="asFiles">TreatAsFiles representing CHD and Archive scanning</param>
        /// <param name="skipFileType">Type of files that should be skipped</param>
        /// <param name="addBlanks">True if blank items should be created for empty folders, false otherwise</param>
        /// <param name="hashes">Hashes to include in the information</param>
        private static void CheckFileForHashes(
            DatFile datFile,
            string item,
            string basePath,
            TreatAsFile asFiles,
            SkipFileType skipFileType,
            bool addBlanks,
            Hash hashes)
        {
            // If we're in depot mode, process it separately
            if (CheckDepotFile(datFile, item))
            {
                return;
            }

            // Initialize possible archive variables
            BaseArchive archive = BaseArchive.Create(item);

            // Process archives according to flags
            if (archive != null)
            {
                // Set the archive flags
                archive.AvailableHashes = hashes;

                // Skip if we're treating archives as files and skipping files
                if (asFiles.HasFlag(TreatAsFile.Archive) && skipFileType == SkipFileType.File)
                {
                    return;
                }

                // Skip if we're skipping archives
                else if (skipFileType == SkipFileType.Archive)
                {
                    return;
                }

                // Process as archive if we're not treating archives as files
                else if (!asFiles.HasFlag(TreatAsFile.Archive))
                {
                    var extracted = archive.GetChildren();

                    // If we have internal items to process, do so
                    if (extracted != null)
                    {
                        ProcessArchive(datFile, item, basePath, extracted);
                    }

                    // Now find all folders that are empty, if we are supposed to
                    if (addBlanks)
                    {
                        ProcessArchiveBlanks(datFile, item, basePath, archive);
                    }
                }

                // Process as file if we're treating archives as files
                else
                {
                    ProcessFile(datFile, item, basePath, hashes, asFiles);
                }
            }

            // Process non-archives according to flags
            else
            {
                // Skip if we're skipping files
                if (skipFileType == SkipFileType.File)
                {
                    return;
                }

                // Process as file
                else
                {
                    ProcessFile(datFile, item, basePath, hashes, asFiles);
                }
            }
        }
        /// <summary>
        /// Entry class for the SabreTools application
        /// </summary>
        /// <param name="args">String array representing command line parameters</param>
        public static void Main(string[] args)
        {
            // Perform initial setup and verification
            Globals.Logger = new Logger(true, "sabretools.log");

            // Create a new Help object for this program
            _help = SabreTools.RetrieveHelp();

            // Get the location of the script tag, if it exists
            int scriptLocation = (new List <string>(args)).IndexOf("--script");

            // If output is being redirected or we are in script mode, don't allow clear screens
            if (!Console.IsOutputRedirected && scriptLocation == -1)
            {
                Console.Clear();
                Build.PrepareConsole("SabreTools");
            }

            // Now we remove the script tag because it messes things up
            if (scriptLocation > -1)
            {
                List <string> newargs = new List <string>(args);
                newargs.RemoveAt(scriptLocation);
                args = newargs.ToArray();
            }

            // Credits take precidence over all
            if ((new List <string>(args)).Contains("--credits"))
            {
                _help.OutputCredits();
                Globals.Logger.Close();
                return;
            }

            // If there's no arguments, show help
            if (args.Length == 0)
            {
                _help.OutputGenericHelp();
                Globals.Logger.Close();
                return;
            }

            // User flags
            bool addBlankFiles             = false,
                 addFileDates              = false,
                 archivesAsFiles           = false,
                 basedat                   = false,
                 chdsAsFiles               = false,
                 cleanGameNames            = false,
                 copyFiles                 = false,
                 delete                    = false,
                 depot                     = false,
                 descAsName                = false,
                 hashOnly                  = false,
                 individual                = false,
                 inplace                   = false,
                 inverse                   = false,
                 noAutomaticDate           = false,
                 nostore                   = false,
                 onlySame                  = false,
                 quickScan                 = false,
                 removeUnicode             = false,
                 showBaddumpColumn         = false,
                 showNodumpColumn          = false,
                 shortname                 = false,
                 skipFirstOutput           = false,
                 updateDat                 = false;
            Hash             omitFromScan  = Hash.DeepHashes;// TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually
            OutputFormat     outputFormat  = OutputFormat.Folder;
            ReplaceMode      replaceMode   = ReplaceMode.None;
            SkipFileType     skipFileType  = SkipFileType.None;
            SplittingMode    splittingMode = SplittingMode.None;
            SplitType        splitType     = SplitType.None;
            StatReportFormat statDatFormat = StatReportFormat.None;
            UpdateMode       updateMode    = UpdateMode.None;

            // User inputs
            int gz                     = 1,
                rar                    = 1,
                sevenzip               = 1,
                zip                    = 1;
            long   radix               = 0;
            string outDir              = null,
                   tempDir             = "";
            DatHeader     datHeader    = new DatHeader();
            Filter        filter       = new Filter();
            List <string> basePaths    = new List <string>();
            List <string> datfiles     = new List <string>();
            List <string> exta         = new List <string>();
            List <string> extb         = new List <string>();
            List <string> inputs       = new List <string>();
            List <Field>  updateFields = new List <Field>();

            // Get the first argument as a feature flag
            string feature = args[0];

            // Verify that the flag is valid
            if (!_help.TopLevelFlag(feature))
            {
                Globals.Logger.User("'{0}' is not valid feature flag", feature);
                _help.OutputIndividualFeature(feature);
                Globals.Logger.Close();
                return;
            }

            // Now get the proper name for the feature
            feature = _help.GetFeatureName(feature);

            // If we had the help feature first
            if (feature == "Help")
            {
                // If we had something else after help
                if (args.Length > 1)
                {
                    _help.OutputIndividualFeature(args[1]);
                    Globals.Logger.Close();
                    return;
                }
                // Otherwise, show generic help
                else
                {
                    _help.OutputGenericHelp();
                    Globals.Logger.Close();
                    return;
                }
            }
            else if (feature == "Help (Detailed)")
            {
                // If we had something else after help
                if (args.Length > 1)
                {
                    _help.OutputIndividualFeature(args[1], includeLongDescription: true);
                    Globals.Logger.Close();
                    return;
                }
                // Otherwise, show generic help
                else
                {
                    _help.OutputAllHelp();
                    Globals.Logger.Close();
                    return;
                }
            }

            // Now verify that all other flags are valid
            for (int i = 1; i < args.Length; i++)
            {
                // Verify that the current flag is proper for the feature
                if (!_help[feature].ValidateInput(args[i]))
                {
                    Globals.Logger.Error("Invalid input detected: {0}", args[i]);
                    _help.OutputIndividualFeature(feature);
                    Globals.Logger.Close();
                    return;
                }

                // Special precautions for files and directories
                if (File.Exists(args[i]) || Directory.Exists(args[i]))
                {
                    inputs.Add(args[i]);
                }
            }

            // Now loop through all inputs
            Dictionary <string, Feature> features = _help.GetEnabledFeatures();

            foreach (KeyValuePair <string, Feature> feat in features)
            {
                // Check all of the flag names and translate to arguments
                switch (feat.Key)
                {
                    #region User Flags

                case "add-blank-files":
                    addBlankFiles = true;
                    break;

                case "add-date":
                    addFileDates = true;
                    break;

                case "archives-as-files":
                    archivesAsFiles = true;
                    break;

                case "baddump-column":
                    showBaddumpColumn = true;
                    break;

                case "base":
                    basedat = true;
                    break;

                case "base-replace":
                    updateMode |= UpdateMode.BaseReplace;
                    break;

                case "chds-as-Files":
                    chdsAsFiles = true;
                    break;

                case "copy-files":
                    copyFiles = true;
                    break;

                case "clean":
                    cleanGameNames = true;
                    break;

                case "dat-device-non-merged":
                    splitType = SplitType.DeviceNonMerged;
                    break;

                case "dat-full-non-merged":
                    splitType = SplitType.FullNonMerged;
                    break;

                case "dat-merged":
                    splitType = SplitType.Merged;
                    break;

                case "dat-non-merged":
                    splitType = SplitType.NonMerged;
                    break;

                case "dat-split":
                    splitType = SplitType.Split;
                    break;

                case "dedup":
                    datHeader.DedupeRoms = DedupeType.Full;
                    break;

                case "delete":
                    delete = true;
                    break;

                case "depot":
                    depot = true;
                    break;

                case "depreciated":
                    // Remove the Logiqx standard output if this is included
                    if ((datHeader.DatFormat & DatFormat.Logiqx) != 0)
                    {
                        datHeader.DatFormat &= ~DatFormat.Logiqx;
                    }
                    datHeader.DatFormat |= DatFormat.LogiqxDepreciated;
                    break;

                case "description-as-name":
                    descAsName = true;
                    break;

                case "diff-against":
                    updateMode |= UpdateMode.DiffAgainst;
                    break;

                case "diff-all":
                    updateMode |= UpdateMode.AllDiffs;
                    break;

                case "diff-cascade":
                    updateMode |= UpdateMode.DiffCascade;
                    break;

                case "diff-duplicates":
                    updateMode |= UpdateMode.DiffDupesOnly;
                    break;

                case "diff-individuals":
                    updateMode |= UpdateMode.DiffIndividualsOnly;
                    break;

                case "diff-no-duplicates":
                    updateMode |= UpdateMode.DiffNoDupesOnly;
                    break;

                case "diff-reverse-cascade":
                    updateMode |= UpdateMode.DiffReverseCascade;
                    break;

                case "exclude-of":
                    Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _excludeFieldListInput.Flags));
                    datHeader.ExcludeFields[(int)Field.CloneOf]     = true;
                    datHeader.ExcludeFields[(int)Field.MachineType] = true;
                    datHeader.ExcludeFields[(int)Field.RomOf]       = true;
                    datHeader.ExcludeFields[(int)Field.Runnable]    = true;
                    datHeader.ExcludeFields[(int)Field.SampleOf]    = true;
                    break;

                case "extension":
                    splittingMode |= SplittingMode.Extension;
                    break;

                case "game-dedup":
                    datHeader.DedupeRoms = DedupeType.Game;
                    break;

                case "game-prefix":
                    datHeader.GameName = true;
                    break;

                case "hash":
                    splittingMode |= SplittingMode.Hash;
                    break;

                case "hash-only":
                    hashOnly = true;
                    break;

                case "individual":
                    individual = true;
                    break;

                case "inplace":
                    inplace = true;
                    break;

                case "inverse":
                    inverse = true;
                    break;

                case "keep-empty-games":
                    datHeader.KeepEmptyGames = true;
                    break;

                case "level":
                    splittingMode |= SplittingMode.Level;
                    break;

                case "match-of-tags":
                    filter.IncludeOfInGame.Neutral = true;
                    break;

                case "merge":
                    updateMode |= UpdateMode.Merge;
                    break;

                case "no-automatic-date":
                    noAutomaticDate = true;
                    break;

                case "nodump-column":
                    showNodumpColumn = true;
                    break;

                case "not-runnable":
                    filter.Runnable.Neutral = false;
                    break;

                case "no-store-header":
                    nostore = true;
                    break;

                case "one-rom-per-game":
                    datHeader.OneRom = true;
                    break;

                case "only-same":
                    onlySame = true;
                    break;

                case "quick":
                    quickScan = true;
                    break;

                case "quotes":
                    datHeader.Quotes = true;
                    break;

                case "remove-extensions":
                    datHeader.RemoveExtension = true;
                    break;

                case "remove-md5":
                    Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _excludeFieldListInput.Flags));
                    datHeader.ExcludeFields[(int)Field.MD5] = true;
                    break;

                case "remove-sha1":
                    Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _excludeFieldListInput.Flags));
                    datHeader.ExcludeFields[(int)Field.SHA1] = true;
                    break;

                case "remove-sha256":
                    Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _excludeFieldListInput.Flags));
                    datHeader.ExcludeFields[(int)Field.SHA256] = true;
                    break;

                case "remove-sha384":
                    Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _excludeFieldListInput.Flags));
                    datHeader.ExcludeFields[(int)Field.SHA384] = true;
                    break;

                case "remove-sha512":
                    Globals.Logger.User("This flag '{0}' is depreciated, please use {1} instead", feat.Key, String.Join(", ", _excludeFieldListInput.Flags));
                    datHeader.ExcludeFields[(int)Field.SHA512] = true;
                    break;

                case "remove-unicode":
                    removeUnicode = true;
                    break;

                case "reverse-base-name":
                    updateMode |= UpdateMode.ReverseBaseReplace;
                    break;

                case "romba":
                    datHeader.Romba = true;
                    break;

                case "roms":
                    datHeader.UseRomName = true;
                    break;

                case "runnable":
                    filter.Runnable.Neutral = true;
                    break;

                case "scan-all":
                    sevenzip = 0;
                    gz       = 0;
                    rar      = 0;
                    zip      = 0;
                    break;

                case "scene-date-strip":
                    datHeader.SceneDateStrip = true;
                    break;

                case "short":
                    shortname = true;
                    break;

                case "size":
                    splittingMode |= SplittingMode.Size;
                    break;

                case "skip-archives":
                    skipFileType = SkipFileType.Archive;
                    break;

                case "skip-files":
                    skipFileType = SkipFileType.File;
                    break;

                case "skip-first-output":
                    skipFirstOutput = true;
                    break;

                case "skip-md5":
                    omitFromScan |= Hash.MD5;
                    break;

                case "skip-sha1":
                    omitFromScan |= Hash.SHA1;
                    break;

                case "skip-sha256":
                    omitFromScan &= ~Hash.SHA256;     // This needs to be inverted later
                    break;

                case "skip-sha384":
                    omitFromScan &= ~Hash.SHA384;     // This needs to be inverted later
                    break;

                case "skip-sha512":
                    omitFromScan &= ~Hash.SHA512;     // This needs to be inverted later
                    break;

                case "single-set":
                    filter.Single.Neutral = true;
                    break;

                case "superdat":
                    datHeader.Type = "SuperDAT";
                    break;

                case "tar":
                    outputFormat = OutputFormat.TapeArchive;
                    break;

                case "torrent-7zip":
                    outputFormat = OutputFormat.Torrent7Zip;
                    break;

                case "torrent-gzip":
                    outputFormat = OutputFormat.TorrentGzip;
                    break;

                case "torrent-lrzip":
                    outputFormat = OutputFormat.TorrentLRZip;
                    break;

                case "torrent-lz4":
                    outputFormat = OutputFormat.TorrentLZ4;
                    break;

                case "torrent-rar":
                    outputFormat = OutputFormat.TorrentRar;
                    break;

                case "torrent-xz":
                    outputFormat = OutputFormat.TorrentXZ;
                    break;

                case "torrent-zip":
                    outputFormat = OutputFormat.TorrentZip;
                    break;

                case "torrent-zpaq":
                    outputFormat = OutputFormat.TorrentZPAQ;
                    break;

                case "torrent-zstd":
                    outputFormat = OutputFormat.TorrentZstd;
                    break;

                case "trim":
                    filter.Trim.Neutral = true;
                    break;

                case "type":
                    splittingMode |= SplittingMode.Type;
                    break;

                case "update-dat":
                    updateDat = true;
                    break;

                case "update-description":
                    replaceMode |= ReplaceMode.Description;
                    break;

                case "update-game-type":
                    replaceMode |= ReplaceMode.MachineType;
                    break;

                case "update-hashes":
                    replaceMode |= ReplaceMode.Hash;
                    break;

                case "update-manufacturer":
                    replaceMode |= ReplaceMode.Manufacturer;
                    break;

                case "update-names":
                    replaceMode |= ReplaceMode.ItemName;
                    break;

                case "update-parents":
                    replaceMode |= ReplaceMode.Parents;
                    break;

                case "update-year":
                    replaceMode |= ReplaceMode.Year;
                    break;

                    #endregion

                    #region User Int32 Inputs

                case "7z":
                    sevenzip = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : 1;
                    break;

                case "gz":
                    gz = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : 1;
                    break;

                case "rar":
                    rar = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : 1;
                    break;

                case "threads":
                    int val = (int)feat.Value.GetValue();
                    if (val != Int32.MinValue)
                    {
                        Globals.MaxThreads = val;
                    }
                    break;

                case "zip":
                    zip = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : 1;
                    break;

                    #endregion

                    #region User Int64 Inputs

                case "radix":
                    radix = (long)feat.Value.GetValue() == Int64.MinValue ? (long)feat.Value.GetValue() : 0;
                    break;

                    #endregion

                    #region User List<string> Inputs

                case "base-dat":
                    basePaths.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "crc":
                    filter.CRC.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "dat":
                    datfiles.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "exclude-field":     // TODO: Use this
                    foreach (string field in (List <string>)feat.Value.GetValue())
                    {
                        datHeader.ExcludeFields[(int)Utilities.GetField(field)] = true;
                    }
                    break;

                case "exta":
                    exta.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "extb":
                    extb.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "game-description":
                    filter.MachineDescription.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "game-name":
                    filter.MachineName.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "game-type":
                    foreach (string mach in (List <string>)feat.Value.GetValue())
                    {
                        filter.MachineTypes.Positive |= Utilities.GetMachineType(mach);
                    }
                    break;

                case "item-name":
                    filter.ItemName.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "item-type":
                    filter.ItemTypes.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "md5":
                    filter.MD5.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-crc":
                    filter.CRC.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-game-description":
                    filter.MachineDescription.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-game-name":
                    filter.MachineName.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-game-type":
                    foreach (string nmach in (List <string>)feat.Value.GetValue())
                    {
                        filter.MachineTypes.Negative |= Utilities.GetMachineType(nmach);
                    }
                    break;

                case "not-item-name":
                    filter.ItemName.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-item-type":
                    filter.ItemTypes.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-md5":
                    filter.MD5.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-sha1":
                    filter.SHA1.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-sha256":
                    filter.SHA256.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-sha384":
                    filter.SHA384.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-sha512":
                    filter.SHA512.NegativeSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "not-status":
                    foreach (string nstat in (List <string>)feat.Value.GetValue())
                    {
                        filter.ItemStatuses.Negative |= Utilities.GetItemStatus(nstat);
                    }
                    break;

                case "output-type":
                    foreach (string ot in (List <string>)feat.Value.GetValue())
                    {
                        DatFormat dftemp = Utilities.GetDatFormat(ot);
                        if (dftemp != DatFormat.Logiqx ||
                            (dftemp == DatFormat.Logiqx && (datHeader.DatFormat & DatFormat.LogiqxDepreciated) == 0))
                        {
                            datHeader.DatFormat |= dftemp;
                        }
                    }
                    break;

                case "report-type":
                    foreach (string rt in (List <string>)feat.Value.GetValue())
                    {
                        statDatFormat |= Utilities.GetStatFormat(rt);
                    }
                    break;

                case "sha1":
                    filter.SHA1.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "sha256":
                    filter.SHA256.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "sha384":
                    filter.SHA384.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "sha512":
                    filter.SHA512.PositiveSet.AddRange((List <string>)feat.Value.GetValue());
                    break;

                case "status":
                    foreach (string stat in (List <string>)feat.Value.GetValue())
                    {
                        filter.ItemStatuses.Positive |= Utilities.GetItemStatus(stat);
                    }
                    break;

                case "update-field":     // TODO: Use this
                    foreach (string field in (List <string>)feat.Value.GetValue())
                    {
                        updateFields.Add(Utilities.GetField(field));
                    }
                    break;

                    #endregion

                    #region User String Inputs

                case "add-extension":
                    datHeader.AddExtension = (string)feat.Value.GetValue();
                    break;

                case "author":
                    datHeader.Author = (string)feat.Value.GetValue();
                    break;

                case "category":
                    datHeader.Category = (string)feat.Value.GetValue();
                    break;

                case "comment":
                    datHeader.Comment = (string)feat.Value.GetValue();
                    break;

                case "date":
                    datHeader.Date = (string)feat.Value.GetValue();
                    break;

                case "description":
                    datHeader.Description = (string)feat.Value.GetValue();
                    break;

                case "email":
                    datHeader.Email = (string)feat.Value.GetValue();
                    break;

                case "equal":
                    filter.Size.Neutral = Utilities.GetSizeFromString((string)feat.Value.GetValue());
                    break;

                case "filename":
                    datHeader.FileName = (string)feat.Value.GetValue();
                    break;

                case "forcemerging":
                    datHeader.ForceMerging = Utilities.GetForceMerging((string)feat.Value.GetValue());
                    break;

                case "forcenodump":
                    datHeader.ForceNodump = Utilities.GetForceNodump((string)feat.Value.GetValue());
                    break;

                case "forcepacking":
                    datHeader.ForcePacking = Utilities.GetForcePacking((string)feat.Value.GetValue());
                    break;

                case "greater":
                    filter.Size.Positive = Utilities.GetSizeFromString((string)feat.Value.GetValue());
                    break;

                case "header":
                    datHeader.Header = (string)feat.Value.GetValue();
                    break;

                case "homepage":
                    datHeader.Homepage = (string)feat.Value.GetValue();
                    break;

                case "less":
                    filter.Size.Negative = Utilities.GetSizeFromString((string)feat.Value.GetValue());
                    break;

                case "name":
                    datHeader.Name = (string)feat.Value.GetValue();
                    break;

                case "output-dir":
                    outDir = (string)feat.Value.GetValue();
                    break;

                case "postfix":
                    datHeader.Postfix = (string)feat.Value.GetValue();
                    break;

                case "prefix":
                    datHeader.Prefix = (string)feat.Value.GetValue();
                    break;

                case "replace-extension":
                    datHeader.ReplaceExtension = (string)feat.Value.GetValue();
                    break;

                case "root":
                    datHeader.RootDir = (string)feat.Value.GetValue();
                    break;

                case "root-dir":
                    filter.Root.Neutral = (string)feat.Value.GetValue();
                    break;

                case "temp":
                    tempDir = (string)feat.Value.GetValue();
                    break;

                case "url":
                    datHeader.Url = (string)feat.Value.GetValue();
                    break;

                case "version":
                    datHeader.Version = (string)feat.Value.GetValue();
                    break;

                    #endregion
                }
            }

            // Now take care of each mode in succesion
            switch (feature)
            {
            case "Help":
                // No-op as this should be caught
                break;

            // Create a DAT from a directory or set of directories
            case "DATFromDir":
                VerifyInputs(inputs, feature);
                InitDatFromDir(inputs, datHeader, omitFromScan, noAutomaticDate, archivesAsFiles, chdsAsFiles,
                               skipFileType, addBlankFiles, addFileDates, tempDir, outDir, copyFiles, filter);
                break;

            // If we're in header extract and remove mode
            case "Extract":
                VerifyInputs(inputs, feature);
                InitExtractRemoveHeader(inputs, outDir, nostore);
                break;

            // If we're in header restore mode
            case "Restore":
                VerifyInputs(inputs, feature);
                InitReplaceHeader(inputs, outDir);
                break;

            case "Script":
                // No-op as this should be caught
                break;

            // If we're using the sorter
            case "Sort":
                InitSort(datfiles, inputs, outDir, depot, quickScan, addFileDates, delete, inverse,
                         outputFormat, datHeader.Romba, sevenzip, gz, rar, zip, updateDat, datHeader.Header,
                         splitType, chdsAsFiles, individual);
                break;

            // Split a DAT by the split type
            case "Split":
                VerifyInputs(inputs, feature);
                InitSplit(inputs, outDir, inplace, datHeader.DatFormat, splittingMode, exta, extb, shortname, basedat, radix);
                break;

            // Get statistics on input files
            case "Stats":
                VerifyInputs(inputs, feature);
                InitStats(inputs, datHeader.FileName, outDir, individual, showBaddumpColumn, showNodumpColumn, statDatFormat);
                break;

            // Convert, update, merge, diff, and filter a DAT or folder of DATs
            case "Update":
                VerifyInputs(inputs, feature);
                InitUpdate(inputs, basePaths, datHeader, updateMode, inplace, skipFirstOutput, noAutomaticDate, filter,
                           splitType, outDir, cleanGameNames, removeUnicode, descAsName, replaceMode, onlySame);
                break;

            // If we're using the verifier
            case "Verify":
                VerifyInputs(inputs, feature);
                InitVerify(datfiles, inputs, depot, hashOnly, quickScan, datHeader.Header, splitType, chdsAsFiles, individual, filter);
                break;

            // If nothing is set, show the help
            default:
                _help.OutputGenericHelp();
                break;
            }

            Globals.Logger.Close();
            return;
        }