Skip to content

Commit d42af9b

Browse files
committed
Consistency matching cleanup
1 parent 8672fea commit d42af9b

File tree

4 files changed

+196
-146
lines changed

4 files changed

+196
-146
lines changed

Hasher/Features/ListFeature.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ internal sealed class ListFeature : Feature
1010

1111
public const string DisplayName = "list";
1212

13-
private static readonly string[] _flags = ["list"];
13+
private static readonly string[] _flags = ["--list"];
1414

1515
private const string _description = "List all available hashes and quit";
1616

@@ -49,4 +49,4 @@ public override bool Execute()
4949
/// <inheritdoc/>
5050
public override bool VerifyInputs() => true;
5151
}
52-
}
52+
}

Hasher/Features/MainFeature.cs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
using SabreTools.CommandLine;
6+
using SabreTools.CommandLine.Inputs;
7+
using SabreTools.Hashing;
8+
9+
namespace Hasher.Features
10+
{
11+
internal sealed class MainFeature : Feature
12+
{
13+
#region Feature Definition
14+
15+
public const string DisplayName = "main";
16+
17+
/// <remarks>Flags are unused</remarks>
18+
private static readonly string[] _flags = [];
19+
20+
/// <remarks>Description is unused</remarks>
21+
private const string _description = "";
22+
23+
#endregion
24+
25+
#region Inputs
26+
27+
private const string _debugName = "debug";
28+
internal readonly FlagInput DebugInput = new(_debugName, ["-d", "--debug"], "Enable debug mode");
29+
30+
private const string _typeName = "type";
31+
internal readonly StringListInput TypeInput = new(_typeName, ["-t", "--type"], "Select included hashes");
32+
33+
#endregion
34+
35+
public MainFeature()
36+
: base(DisplayName, _flags, _description)
37+
{
38+
RequiresInputs = true;
39+
40+
Add(DebugInput);
41+
Add(TypeInput);
42+
}
43+
44+
/// <inheritdoc/>
45+
public override bool Execute()
46+
{
47+
// Get the required variables
48+
bool debug = GetBoolean(_debugName);
49+
List<HashType> hashTypes = GetHashTypes(GetStringList(_typeName));
50+
51+
// Loop through all of the input files
52+
for (int i = 0; i < Inputs.Count; i++)
53+
{
54+
string arg = Inputs[i];
55+
PrintPathHashes(arg, hashTypes, debug);
56+
}
57+
58+
return true;
59+
}
60+
61+
/// <inheritdoc/>
62+
public override bool VerifyInputs() => true;
63+
64+
/// <summary>
65+
/// Derive a list of hash types from a list of strings
66+
/// </summary>
67+
private static List<HashType> GetHashTypes(List<string> types)
68+
{
69+
List<HashType> hashTypes = [];
70+
if (types.Count == 0)
71+
{
72+
hashTypes.Add(HashType.CRC32);
73+
hashTypes.Add(HashType.MD5);
74+
hashTypes.Add(HashType.SHA1);
75+
hashTypes.Add(HashType.SHA256);
76+
}
77+
else if (types.Contains("all"))
78+
{
79+
hashTypes = [.. (HashType[])Enum.GetValues(typeof(HashType))];
80+
}
81+
else
82+
{
83+
foreach (string typeString in types)
84+
{
85+
HashType? hashType = typeString.GetHashType();
86+
if (hashType != null && !hashTypes.Contains(hashType.Value))
87+
hashTypes.Add(item: hashType.Value);
88+
}
89+
}
90+
91+
return hashTypes;
92+
}
93+
94+
/// <summary>
95+
/// Wrapper to print hashes for a single path
96+
/// </summary>
97+
/// <param name="path">File or directory path</param>
98+
/// <param name="hashTypes">Set of hashes to retrieve</param>
99+
/// <param name="debug">Enable debug output</param>
100+
private static void PrintPathHashes(string path, List<HashType> hashTypes, bool debug)
101+
{
102+
Console.WriteLine($"Checking possible path: {path}");
103+
104+
// Check if the file or directory exists
105+
if (File.Exists(path))
106+
{
107+
PrintFileHashes(path, hashTypes, debug);
108+
}
109+
else if (Directory.Exists(path))
110+
{
111+
foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
112+
{
113+
PrintFileHashes(file, hashTypes, debug);
114+
}
115+
}
116+
else
117+
{
118+
Console.WriteLine($"{path} does not exist, skipping...");
119+
}
120+
}
121+
122+
/// <summary>
123+
/// Print information for a single file, if possible
124+
/// </summary>
125+
/// <param name="file">File path</param>
126+
/// <param name="hashTypes">Set of hashes to retrieve</param>
127+
/// <param name="debug">Enable debug output</param>
128+
private static void PrintFileHashes(string file, List<HashType> hashTypes, bool debug)
129+
{
130+
Console.WriteLine($"Attempting to hash {file}, this may take a while...");
131+
Console.WriteLine();
132+
133+
// If the file doesn't exist
134+
if (!File.Exists(file))
135+
{
136+
Console.WriteLine($"{file} does not exist, skipping...");
137+
return;
138+
}
139+
140+
try
141+
{
142+
// Get all file hashes for flexibility
143+
var hashes = HashTool.GetFileHashes(file);
144+
if (hashes == null)
145+
{
146+
if (debug) Console.WriteLine($"Hashes for {file} could not be retrieved");
147+
return;
148+
}
149+
150+
// Output subset of available hashes
151+
var builder = new StringBuilder();
152+
foreach (HashType hashType in hashTypes)
153+
{
154+
// TODO: Make helper to pretty-print hash type names
155+
if (hashes.TryGetValue(hashType, out string? hash) && hash != null)
156+
builder.AppendLine($"{hashType}: {hash}");
157+
}
158+
159+
// Create and print the output data
160+
string hashData = builder.ToString();
161+
Console.WriteLine(hashData);
162+
}
163+
catch (Exception ex)
164+
{
165+
Console.WriteLine(debug ? ex : "[Exception opening file, please try again]");
166+
return;
167+
}
168+
}
169+
}
170+
}

Hasher/Program.cs

Lines changed: 22 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,18 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.IO;
4-
using System.Text;
53
using Hasher.Features;
64
using SabreTools.CommandLine;
75
using SabreTools.CommandLine.Features;
8-
using SabreTools.CommandLine.Inputs;
9-
using SabreTools.Hashing;
106

117
namespace Hasher
128
{
139
public static class Program
1410
{
15-
#region Constants
16-
17-
private const string _debugName = "debug";
18-
private const string _typeName = "type";
19-
20-
#endregion
21-
2211
public static void Main(string[] args)
2312
{
2413
// Create the command set
25-
var commandSet = CreateCommands();
14+
var mainFeature = new MainFeature();
15+
var commandSet = CreateCommands(mainFeature);
2616

2717
// If we have no args, show the help and quit
2818
if (args == null || args.Length == 0)
@@ -38,39 +28,33 @@ public static void Main(string[] args)
3828
var topLevel = commandSet.GetTopLevel(featureName);
3929
switch (topLevel)
4030
{
31+
// Standalone Options
4132
case Help help: help.ProcessArgs(args, 0, commandSet); return;
4233
case ListFeature lf: lf.Execute(); return;
43-
}
4434

45-
// Loop through and process the options
46-
int firstFileIndex = 0;
47-
for (; firstFileIndex < args.Length; firstFileIndex++)
48-
{
49-
string arg = args[firstFileIndex];
50-
51-
var input = commandSet.GetTopLevel(arg);
52-
if (input == null)
35+
// Default Behavior
36+
default:
37+
if (!mainFeature.ProcessArgs(args, 0))
38+
{
39+
commandSet.OutputAllHelp();
40+
return;
41+
}
42+
else if (!mainFeature.VerifyInputs())
43+
{
44+
Console.Error.WriteLine("At least one input is required");
45+
commandSet.OutputAllHelp();
46+
return;
47+
}
48+
49+
mainFeature.Execute();
5350
break;
54-
55-
input.ProcessInput(args, ref firstFileIndex);
56-
}
57-
58-
// Get the required variables
59-
bool debug = commandSet.GetBoolean(_debugName);
60-
List<HashType> hashTypes = GetHashTypes(commandSet.GetStringList(_typeName));
61-
62-
// Loop through all of the input files
63-
for (int i = firstFileIndex; i < args.Length; i++)
64-
{
65-
string arg = args[i];
66-
PrintPathHashes(arg, hashTypes, debug);
6751
}
6852
}
6953

7054
/// <summary>
7155
/// Create the command set for the program
7256
/// </summary>
73-
private static CommandSet CreateCommands()
57+
private static CommandSet CreateCommands(MainFeature mainFeature)
7458
{
7559
List<string> header = [
7660
"File Hashing Program",
@@ -90,118 +74,14 @@ private static CommandSet CreateCommands()
9074
var commandSet = new CommandSet(header, footer);
9175

9276
// Standalone Options
93-
commandSet.Add(new Help());
77+
commandSet.Add(new Help(["-?", "-h", "--help"]));
9478
commandSet.Add(new ListFeature());
9579

9680
// Hasher Options
97-
commandSet.Add(new FlagInput(_debugName, ["-d", "--debug"], "Enable debug mode"));
98-
commandSet.Add(new StringListInput(_typeName, ["-t", "--type"], "Select included hashes"));
81+
commandSet.Add(mainFeature.DebugInput);
82+
commandSet.Add(mainFeature.TypeInput);
9983

10084
return commandSet;
10185
}
102-
103-
/// <inheritdoc/>
104-
private static List<HashType> GetHashTypes(List<string> types)
105-
{
106-
List<HashType> hashTypes = [];
107-
if (types.Count == 0)
108-
{
109-
hashTypes.Add(HashType.CRC32);
110-
hashTypes.Add(HashType.MD5);
111-
hashTypes.Add(HashType.SHA1);
112-
hashTypes.Add(HashType.SHA256);
113-
}
114-
else if (types.Contains("all"))
115-
{
116-
hashTypes = [.. (HashType[])Enum.GetValues(typeof(HashType))];
117-
}
118-
else
119-
{
120-
foreach (string typeString in types)
121-
{
122-
HashType? hashType = typeString.GetHashType();
123-
if (hashType != null && !hashTypes.Contains(hashType.Value))
124-
hashTypes.Add(item: hashType.Value);
125-
}
126-
}
127-
128-
return hashTypes;
129-
}
130-
131-
/// <summary>
132-
/// Wrapper to print hashes for a single path
133-
/// </summary>
134-
/// <param name="path">File or directory path</param>
135-
/// <param name="hashTypes">Set of hashes to retrieve</param>
136-
/// <param name="debug">Enable debug output</param>
137-
private static void PrintPathHashes(string path, List<HashType> hashTypes, bool debug)
138-
{
139-
Console.WriteLine($"Checking possible path: {path}");
140-
141-
// Check if the file or directory exists
142-
if (File.Exists(path))
143-
{
144-
PrintFileHashes(path, hashTypes, debug);
145-
}
146-
else if (Directory.Exists(path))
147-
{
148-
foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
149-
{
150-
PrintFileHashes(file, hashTypes, debug);
151-
}
152-
}
153-
else
154-
{
155-
Console.WriteLine($"{path} does not exist, skipping...");
156-
}
157-
}
158-
159-
/// <summary>
160-
/// Print information for a single file, if possible
161-
/// </summary>
162-
/// <param name="file">File path</param>
163-
/// <param name="hashTypes">Set of hashes to retrieve</param>
164-
/// <param name="debug">Enable debug output</param>
165-
private static void PrintFileHashes(string file, List<HashType> hashTypes, bool debug)
166-
{
167-
Console.WriteLine($"Attempting to hash {file}, this may take a while...");
168-
Console.WriteLine();
169-
170-
// If the file doesn't exist
171-
if (!File.Exists(file))
172-
{
173-
Console.WriteLine($"{file} does not exist, skipping...");
174-
return;
175-
}
176-
177-
try
178-
{
179-
// Get all file hashes for flexibility
180-
var hashes = HashTool.GetFileHashes(file);
181-
if (hashes == null)
182-
{
183-
if (debug) Console.WriteLine($"Hashes for {file} could not be retrieved");
184-
return;
185-
}
186-
187-
// Output subset of available hashes
188-
var builder = new StringBuilder();
189-
foreach (HashType hashType in hashTypes)
190-
{
191-
// TODO: Make helper to pretty-print hash type names
192-
if (hashes.TryGetValue(hashType, out string? hash) && hash != null)
193-
builder.AppendLine($"{hashType}: {hash}");
194-
}
195-
196-
// Create and print the output data
197-
string hashData = builder.ToString();
198-
Console.WriteLine(hashData);
199-
}
200-
catch (Exception ex)
201-
{
202-
Console.WriteLine(debug ? ex : "[Exception opening file, please try again]");
203-
return;
204-
}
205-
}
20686
}
20787
}

0 commit comments

Comments
 (0)