Skip to content

Commit 699942b

Browse files
committed
Add hash dumper command line tool
1 parent 316770f commit 699942b

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

HashDumper/HashDumper.csproj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
13+
<PackageReference Include="System.CommandLine.NamingConventionBinder" Version="2.0.0-beta4.22272.1" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="..\Yura.Shared\Yura.Shared.csproj" />
18+
</ItemGroup>
19+
20+
</Project>

HashDumper/Program.cs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System.CommandLine;
2+
using System.CommandLine.NamingConventionBinder;
3+
using System.Text.Json;
4+
using Yura.Shared.Archive;
5+
using Yura.Shared.IO;
6+
7+
// Define all command line options
8+
var command = new RootCommand("Scan a folder for archives and dump all unique hashes")
9+
{
10+
new Argument<DirectoryInfo>(
11+
name: "path",
12+
description: "The path of the folder to scan"),
13+
14+
new Argument<FileInfo>(
15+
name: "output",
16+
description: "The path of the output file"),
17+
18+
new Option<Game>(
19+
name: "--game",
20+
description: "The game of the files",
21+
getDefaultValue: () => Game.Legend),
22+
23+
new Option<Endianness>(
24+
name: "--endianness",
25+
description: "The endianness of the files",
26+
getDefaultValue: () => Endianness.LittleEndian),
27+
28+
new Option<string>(
29+
name: "--pattern",
30+
description: "The pattern of the archives to scan",
31+
getDefaultValue: () => "*.000"),
32+
33+
new Option<OutputFormat>(
34+
name: "--output-format",
35+
description: "The format to output the data in",
36+
getDefaultValue: () => OutputFormat.Text),
37+
};
38+
39+
command.Handler = CommandHandler.Create(Execute);
40+
41+
// Run the command
42+
await command.InvokeAsync(args);
43+
44+
static void Execute(
45+
DirectoryInfo path, FileInfo output, Game game, Endianness endianness, string pattern, OutputFormat outputFormat)
46+
{
47+
List<ulong> hashes = [];
48+
49+
foreach (var file in path.GetFiles(pattern))
50+
{
51+
Console.WriteLine(file.Name);
52+
53+
// Open the archive
54+
var options = new ArchiveOptions
55+
{
56+
Path = file.FullName,
57+
Endianness = endianness
58+
};
59+
60+
var archive = Create(game, options);
61+
archive.Open();
62+
63+
// Add all hashes
64+
foreach (var record in archive.Records)
65+
{
66+
if (!hashes.Contains(record.Hash))
67+
{
68+
hashes.Add(record.Hash);
69+
}
70+
}
71+
}
72+
73+
// Write the output
74+
switch (outputFormat)
75+
{
76+
case OutputFormat.Text:
77+
File.WriteAllLines(output.FullName, hashes.Select(hash => hash.ToString("X8")));
78+
79+
break;
80+
case OutputFormat.Json:
81+
File.WriteAllText(output.FullName, JsonSerializer.Serialize(hashes));
82+
83+
break;
84+
}
85+
}
86+
87+
static ArchiveFile Create(Game game, ArchiveOptions options) => game switch
88+
{
89+
Game.Defiance => new DefianceArchive(options),
90+
Game.Legend => new LegendArchive(options),
91+
Game.DeusEx => new DeusExArchive(options),
92+
Game.Tiger => new TigerArchive(options),
93+
94+
_ => throw new NotImplementedException()
95+
};
96+
97+
enum Game
98+
{
99+
Defiance,
100+
Legend,
101+
DeusEx,
102+
Tiger
103+
}
104+
105+
enum OutputFormat
106+
{
107+
Text,
108+
Json
109+
}

Yura.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yura.Shared", "Yura.Shared\
99
EndProject
1010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yura.Test", "Yura.Test\Yura.Test.csproj", "{AD8EDAE9-3B48-4437-AAA3-AEAD7127FDA0}"
1111
EndProject
12+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashDumper", "HashDumper\HashDumper.csproj", "{5BF4385A-9099-45BC-9805-E654C5ABA033}"
13+
EndProject
1214
Global
1315
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1416
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,10 @@ Global
2729
{AD8EDAE9-3B48-4437-AAA3-AEAD7127FDA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
2830
{AD8EDAE9-3B48-4437-AAA3-AEAD7127FDA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
2931
{AD8EDAE9-3B48-4437-AAA3-AEAD7127FDA0}.Release|Any CPU.Build.0 = Release|Any CPU
32+
{5BF4385A-9099-45BC-9805-E654C5ABA033}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33+
{5BF4385A-9099-45BC-9805-E654C5ABA033}.Debug|Any CPU.Build.0 = Debug|Any CPU
34+
{5BF4385A-9099-45BC-9805-E654C5ABA033}.Release|Any CPU.ActiveCfg = Release|Any CPU
35+
{5BF4385A-9099-45BC-9805-E654C5ABA033}.Release|Any CPU.Build.0 = Release|Any CPU
3036
EndGlobalSection
3137
GlobalSection(SolutionProperties) = preSolution
3238
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)