-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFileHasher.cpp
212 lines (190 loc) · 7.24 KB
/
FileHasher.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <chrono>
#include <iostream>
#include <sstream>
#include "./Hashing/HashingAlgorithm.h"
#include "./Hashing/MD5Hash.h"
#include "./Hashing/SHA1Hash.h"
#include "./Hashing/SHA256Hash.h"
#include "./Hashing/SHA512Hash.h"
using namespace std;
string GetProgramName(const string& pathToProgram)
{
string programName;
vector<string> elements;
istringstream f(pathToProgram);
// Get program name from command line argument containing program path
while (getline(f, programName, '\\'))
{
}
return programName;
}
void PrintHelp(const string& pathToProgram)
{
const string programName = GetProgramName(pathToProgram);
cout << "Program usage:" << endl;
cout << "\t- " << programName << " <HashAlgorithm> <PathToFile>" << endl;
}
int HandleCommandLineInput(const int argc, char** argv)
{
if (argc < 3)
{
PrintHelp(argv[0]);
return 1;
}
vector<string> arguments;
arguments.reserve(argc);
for (int i = 0; i < argc; i++)
{
arguments.emplace_back(argv[i]);
}
bool verbose = false;
if (const auto verbosePosition = find(arguments.begin(), arguments.end(), "-v"); verbosePosition != arguments.end())
{
verbose = true;
}
HashingAlgorithm* algorithm;
if (arguments[1] == "SHA256")
{
algorithm = new SHA256Hasher();
}
else if (arguments[1] == "SHA512")
{
algorithm = new SHA512Hasher();
}
else if (arguments[1] == "MD5")
{
algorithm = new MD5Hasher();
}
else if (arguments[1] == "SHA1")
{
algorithm = new SHA1Hasher();
}
else
{
if (verbose)
{
cout << "Invalid Hashing Algorithm!" << endl;
PrintHelp(arguments[0]);
}
return 1;
}
const size_t len = strnlen_s(arguments[2].c_str(), 1024U) + 1;
[[maybe_unused]] size_t fileSize = 0U;
size_t ret = 0U;
auto* widePath = new wchar_t[len];
mbstowcs_s(&ret, widePath, len, arguments[2].c_str(), len - 1);
const string hash = algorithm->CalculateFileHash(widePath);
delete[] widePath;
if (hash.empty())
{
if (verbose)
{
cout << "Invalid file path!" << endl;
PrintHelp(arguments[0]);
}
return 1;
}
cout << hash;
return 0;
}
int main(int argc, char** argv)
{
unique_ptr<HashingAlgorithm> sha256Hasher = make_unique<SHA256Hasher>();
unique_ptr<HashingAlgorithm> sha512Hasher = make_unique<SHA512Hasher>();
unique_ptr<HashingAlgorithm> md5Hasher = make_unique<MD5Hasher>();
unique_ptr<HashingAlgorithm> sha1Hasher = make_unique<SHA1Hasher>();
wstring path = L"C:/Dev/Cpp/FileHasher/test2";
if (argc > 1)
{
return HandleCommandLineInput(argc, argv);
}
while (true)
{
string input;
cin >> input;
if (input == "exit")
{
break;
}
if (input == "-path")
{
cout << "Enter path: ";
wcin >> path;
}
else if (input == "file")
{
/*
* Tested files (Release mode), times include reading file and hashing,
* so this may vary depending on harddrive (NVMe SSD for me). Tested only once:
* Size (using filesystem::file_size / 1000) and duration (using chrono::high_resolution_clock) :
* - 14847574 KB => 134895 ms
* - 5186093 KB => 45846 ms (27.9s were spent with File IO, and 17.9s with hashing)
* - 1039630 KB => 9304 ms (5.7s were spent with File IO, and 3.6s with hashing)
* - 431357 KB => 3820 ms (2.3s were spent with File IO, and 1.5s with hashing)
* - 103972 KB => 928 ms
* - 1245 KB => 11 ms
* - 115 KB => 1 ms
*
* New results after runtime and memory improvement
* (Tested multiple times, if results didn't vary too much first result was taken):
* Blocksize used: 16777216 (2^24) Bytes
* - 14847574 KB => 60012 ms
* - 5186093 KB => 19041 ms
* - 3770744 KB => 13883 ms
* - 1039630 KB => 3829 ms
* - 431357 KB => 1588 ms
* - 103972 KB => 385 ms
* - 1245 KB => 6 ms (6768 microseconds)
* - 115 KB => 2 ms (2494 microseconds)
*
* Blocksize used: 4096 (2^12) Bytes
* - 14847574 KB => 67985 ms
* - 5186093 KB => 23678 ms
* - 3770744 KB => 17276 ms
* - 1039630 KB => 4771 ms
* - 431357 KB => 1963 ms
* - 103972 KB => 475 ms
* - 1245 KB => 6 ms (6062 microseconds)
* - 115 KB => 0 ms (812 microseconds)
*
* Blocksize used: 4294967296 (2^32) Bytes
* - 14847574 KB => 56566 ms
* - 5186093 KB => 19465 ms
* - 3770744 KB => 14608 ms
* - 1039630 KB => 4205 ms
* - 431357 KB => 1855 ms
* - 103972 KB => 611 ms
* - 1245 KB => 219 ms
* - 115 KB => 215 ms
*/
// Hash the file "test", can be changed at runtime
size_t fileSize = 0;
auto start = chrono::high_resolution_clock::now();
string sha256Hash = sha256Hasher->CalculateFileHash(path.c_str(), fileSize);
auto end = chrono::high_resolution_clock::now();
cout << "File " << sha256Hasher->GetName() << ": " << sha256Hash << endl;
cout << "Took: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << " ms, with size: " << fileSize / 1000 << " KB" << endl;
cout << "Took: " << chrono::duration_cast<chrono::microseconds>(end - start).count() << " micros, with size: " << fileSize / 1000 << " KB" << endl;
start = chrono::high_resolution_clock::now();
string sha512Hash = sha512Hasher->CalculateFileHash(path.c_str());
end = chrono::high_resolution_clock::now();
cout << "File " << sha512Hasher->GetName() << ": " << sha512Hash << endl;
cout << "Took: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << " ms " << endl;
cout << "Took: " << chrono::duration_cast<chrono::microseconds>(end - start).count() << " micros" << endl;
start = chrono::high_resolution_clock::now();
string md5Hash = md5Hasher->CalculateFileHash(path.c_str());
end = chrono::high_resolution_clock::now();
cout << "File MD5: " << md5Hash << endl;
cout << "Took: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << " ms, with size: " << fileSize / 1000 << " KB" << endl;
start = chrono::high_resolution_clock::now();
string sha1Hash = sha1Hasher->CalculateFileHash(path.c_str());
end = chrono::high_resolution_clock::now();
cout << "File SHA1: " << sha1Hash << endl;
cout << "Took: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << " ms, with size: " << fileSize / 1000 << " KB" << endl;
}
else
{
cout << "Unknown command: " << input << endl;
}
}
}