Skip to content

Commit ab508ee

Browse files
committed
Use main feature pattern
1 parent 31792fa commit ab508ee

File tree

2 files changed

+222
-161
lines changed

2 files changed

+222
-161
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using BinaryObjectScanner;
5+
using SabreTools.CommandLine;
6+
using SabreTools.CommandLine.Inputs;
7+
8+
namespace ProtectionScan.Features
9+
{
10+
internal sealed class MainFeature : Feature
11+
{
12+
#region Feature Definition
13+
14+
public const string DisplayName = "main";
15+
16+
/// <remarks>Flags are unused</remarks>
17+
private static readonly string[] _flags = [];
18+
19+
/// <remarks>Description is unused</remarks>
20+
private const string _description = "";
21+
22+
#endregion
23+
24+
#region Inputs
25+
26+
private const string _debugName = "debug";
27+
internal readonly FlagInput DebugInput = new(_debugName, ["-d", "--debug"], "Enable debug mode");
28+
29+
private const string _noArchivesName = "no-archives";
30+
internal readonly FlagInput NoArchivesInput = new(_noArchivesName, ["-na", "--no-archives"], "Disable scanning archives");
31+
32+
private const string _noContentsName = "no-contents";
33+
internal readonly FlagInput NoContentsInput = new(_noContentsName, ["-nc", "--no-contents"], "Disable scanning for content checks");
34+
35+
private const string _noPathsName = "no-paths";
36+
internal readonly FlagInput NoPathsInput = new(_noPathsName, ["-np", "--no-paths"], "Disable scanning for path checks");
37+
38+
private const string _noSubdirsName = "no-subdirs";
39+
internal readonly FlagInput NoSubdirsInput = new(_noSubdirsName, ["-ns", "--no-subdirs"], "Disable scanning subdirectories");
40+
41+
#endregion
42+
43+
public MainFeature()
44+
: base(DisplayName, _flags, _description)
45+
{
46+
RequiresInputs = true;
47+
48+
Add(DebugInput);
49+
Add(NoContentsInput);
50+
Add(NoArchivesInput);
51+
Add(NoPathsInput);
52+
Add(NoSubdirsInput);
53+
}
54+
55+
/// <inheritdoc/>
56+
public override bool Execute()
57+
{
58+
// Create progress indicator
59+
var fileProgress = new Progress<ProtectionProgress>();
60+
fileProgress.ProgressChanged += Changed;
61+
62+
// Create scanner for all paths
63+
var scanner = new Scanner(
64+
!GetBoolean(_noArchivesName),
65+
!GetBoolean(_noContentsName),
66+
!GetBoolean(_noPathsName),
67+
!GetBoolean(_noSubdirsName),
68+
!GetBoolean(_debugName),
69+
fileProgress);
70+
71+
// Loop through the input paths
72+
for (int i = 0; i < Inputs.Count; i++)
73+
{
74+
string arg = Inputs[i];
75+
GetAndWriteProtections(scanner, arg);
76+
}
77+
78+
return true;
79+
}
80+
81+
/// <inheritdoc/>
82+
public override bool VerifyInputs() => Inputs.Count > 0;
83+
84+
/// <summary>
85+
/// Protection progress changed handler
86+
/// </summary>
87+
private static void Changed(object? source, ProtectionProgress value)
88+
{
89+
string prefix = string.Empty;
90+
for (int i = 0; i < value.Depth; i++)
91+
{
92+
prefix += "--> ";
93+
}
94+
95+
Console.WriteLine($"{prefix}{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}");
96+
}
97+
98+
/// <summary>
99+
/// Wrapper to get and log protections for a single path
100+
/// </summary>
101+
/// <param name="scanner">Scanner object to use</param>
102+
/// <param name="path">File or directory path</param>
103+
private static void GetAndWriteProtections(Scanner scanner, string path)
104+
{
105+
// Normalize by getting the full path
106+
path = Path.GetFullPath(path);
107+
108+
// An invalid path can't be scanned
109+
if (!Directory.Exists(path) && !File.Exists(path))
110+
{
111+
Console.WriteLine($"{path} does not exist, skipping...");
112+
return;
113+
}
114+
115+
try
116+
{
117+
var protections = scanner.GetProtections(path);
118+
WriteProtectionResultFile(path, protections);
119+
}
120+
catch (Exception ex)
121+
{
122+
try
123+
{
124+
using var sw = new StreamWriter(File.OpenWrite($"exception-{DateTime.Now:yyyy-MM-dd_HHmmss.ffff}.txt"));
125+
sw.WriteLine(ex);
126+
}
127+
catch
128+
{
129+
Console.WriteLine("Could not open exception log file for writing. See original message below:");
130+
Console.WriteLine(ex);
131+
}
132+
}
133+
}
134+
135+
/// <summary>
136+
/// Write the protection results from a single path to file, if possible
137+
/// </summary>
138+
/// <param name="path">File or directory path</param>
139+
/// <param name="protections">Dictionary of protections found, if any</param>
140+
private static void WriteProtectionResultFile(string path, Dictionary<string, List<string>> protections)
141+
{
142+
if (protections == null)
143+
{
144+
Console.WriteLine($"No protections found for {path}");
145+
return;
146+
}
147+
148+
// Attempt to open a protection file for writing
149+
StreamWriter? sw = null;
150+
try
151+
{
152+
sw = new StreamWriter(File.OpenWrite($"protection-{DateTime.Now:yyyy-MM-dd_HHmmss.ffff}.txt"));
153+
}
154+
catch
155+
{
156+
Console.WriteLine("Could not open protection log file for writing. Only a console log will be provided.");
157+
}
158+
159+
// Sort the keys for consistent output
160+
string[] keys = [.. protections.Keys];
161+
Array.Sort(keys);
162+
163+
// Loop over all keys
164+
foreach (string key in keys)
165+
{
166+
// Skip over files with no protection
167+
var value = protections[key];
168+
if (value.Count == 0)
169+
continue;
170+
171+
// Sort the detected protections for consistent output
172+
string[] fileProtections = [.. value];
173+
Array.Sort(fileProtections);
174+
175+
// Format and output the line
176+
string line = $"{key}: {string.Join(", ", fileProtections)}";
177+
Console.WriteLine(line);
178+
sw?.WriteLine(line);
179+
}
180+
181+
// Dispose of the writer
182+
sw?.Dispose();
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)