using System; using System.Collections.Generic; using System.IO; using System.Text; using SabreTools.CommandLine; using SabreTools.CommandLine.Inputs; using SabreTools.Hashing; namespace Hasher.Features { internal sealed class MainFeature : Feature { #region Feature Definition public const string DisplayName = "main"; /// Flags are unused private static readonly string[] _flags = []; /// Description is unused private const string _description = ""; #endregion #region Inputs private const string _debugName = "debug"; internal readonly FlagInput DebugInput = new(_debugName, ["-d", "--debug"], "Enable debug mode"); private const string _typeName = "type"; internal readonly StringListInput TypeInput = new(_typeName, ["-t", "--type"], "Select included hashes"); #endregion public MainFeature() : base(DisplayName, _flags, _description) { RequiresInputs = true; Add(DebugInput); Add(TypeInput); } /// public override bool Execute() { // Get the required variables bool debug = GetBoolean(_debugName); List hashTypes = GetHashTypes(GetStringList(_typeName)); // Loop through all of the input files for (int i = 0; i < Inputs.Count; i++) { string arg = Inputs[i]; PrintPathHashes(arg, hashTypes, debug); } return true; } /// public override bool VerifyInputs() => true; /// /// Derive a list of hash types from a list of strings /// private static List GetHashTypes(List types) { List hashTypes = []; if (types.Count == 0) { hashTypes.Add(HashType.CRC32); hashTypes.Add(HashType.MD5); hashTypes.Add(HashType.SHA1); hashTypes.Add(HashType.SHA256); } else if (types.Contains("all")) { hashTypes = [.. HashType.AllHashes]; } else { foreach (string typeString in types) { string? hashType = typeString.GetHashType(); if (hashType is not null && !hashTypes.Contains(hashType)) hashTypes.Add(item: hashType); } } return hashTypes; } /// /// Wrapper to print hashes for a single path /// /// File or directory path /// Set of hashes to retrieve /// Enable debug output private static void PrintPathHashes(string path, List hashTypes, bool debug) { Console.WriteLine($"Checking possible path: {path}"); // Check if the file or directory exists if (File.Exists(path)) { PrintFileHashes(path, hashTypes, debug); } else if (Directory.Exists(path)) { foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories)) { PrintFileHashes(file, hashTypes, debug); } } else { Console.WriteLine($"{path} does not exist, skipping..."); } } /// /// Print information for a single file, if possible /// /// File path /// Set of hashes to retrieve /// Enable debug output private static void PrintFileHashes(string file, List hashTypes, bool debug) { Console.WriteLine($"Attempting to hash {file}, this may take a while..."); Console.WriteLine(); // If the file doesn't exist if (!File.Exists(file)) { Console.WriteLine($"{file} does not exist, skipping..."); return; } try { // Get all file hashes for flexibility var hashes = HashTool.GetFileHashes(file); if (hashes is null) { if (debug) Console.WriteLine($"Hashes for {file} could not be retrieved"); return; } // Output subset of available hashes var builder = new StringBuilder(); foreach (string hashType in hashTypes) { // TODO: Make helper to pretty-print hash type names if (hashes.TryGetValue(hashType, out string? hash) && hash is not null) builder.AppendLine($"{hashType}: {hash}"); } // Create and print the output data string hashData = builder.ToString(); Console.WriteLine(hashData); } catch (Exception ex) { Console.WriteLine(debug ? ex : "[Exception opening file, please try again]"); return; } } } }