-
-
Notifications
You must be signed in to change notification settings - Fork 16
/
WinUtils.cpp
325 lines (252 loc) · 8.85 KB
/
WinUtils.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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#include "Log.h"
#include "OSCompatibilityLayer.h"
#include "iconvlite.h"
#include <Windows.h>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
#pragma warning(disable : 4996) // suppress warnings about wcscmp()
namespace commonItems
{
std::set<std::string> GetAllFilesInFolderRecursive(const std::string& path)
{
auto validatedPath = path;
if (validatedPath.ends_with('/') || validatedPath.ends_with('\\'))
validatedPath = validatedPath.substr(0, validatedPath.size() - 1); // remove the trailing slash
const auto origPathStr = fs::u8path(validatedPath).native();
if (const auto tempPath = fs::u8path(path); !fs::exists(tempPath) || !fs::is_directory(tempPath))
{
return {};
}
std::set<std::string> fileNames;
for (const auto& p: fs::recursive_directory_iterator(fs::u8path(validatedPath)))
{
if (!p.is_directory())
{
const auto currentPath = p.path().native();
const auto requestedPath = currentPath.substr(origPathStr.length() + 1, currentPath.length() - origPathStr.length() - 1);
auto utf8_path = UTF16ToUTF8(requestedPath);
std::ranges::replace(utf8_path, '\\', '/');
fileNames.insert(utf8_path);
}
}
return fileNames;
}
std::string GetLastErrorString()
{
const DWORD errorCode = GetLastError();
constexpr DWORD errorBufferSize = 256;
if (wchar_t errorBuffer[errorBufferSize]; static_cast<bool>(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
nullptr,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errorBuffer,
errorBufferSize - 1,
nullptr)))
{
return UTF16ToUTF8(errorBuffer);
}
return "Unknown error";
}
std::string convertUTF8ToASCII(const std::string& UTF8)
{
const int requiredSize = WideCharToMultiByte(20127 /*US-ASCII (7-bit)*/, 0, convertUTF8ToUTF16(UTF8).c_str(), -1, nullptr, 0, "0", nullptr);
char* asciiArray = new char[requiredSize];
if (0 == WideCharToMultiByte(20127 /*US-ASCII (7-bit)*/, 0, convertUTF8ToUTF16(UTF8).c_str(), -1, asciiArray, requiredSize, "0", nullptr))
{
Log(LogLevel::Error) << "Could not translate string to ASCII - " << GetLastErrorString();
}
std::string returnable(asciiArray);
delete[] asciiArray;
return returnable;
}
std::string convertUTF8To8859_15(const std::string& UTF8)
{
const int requiredSize = WideCharToMultiByte(28605 /*8859-15*/, 0, convertUTF8ToUTF16(UTF8).c_str(), -1, nullptr, 0, "0", nullptr);
char* asciiArray = new char[requiredSize];
if (0 == WideCharToMultiByte(28605 /*8859-15*/, 0, convertUTF8ToUTF16(UTF8).c_str(), -1, asciiArray, requiredSize, "0", nullptr))
{
Log(LogLevel::Error) << "Could not translate string to ASCII - " << GetLastErrorString();
}
std::string returnable(asciiArray);
delete[] asciiArray;
return returnable;
}
std::string convertUTF8ToWin125_(const std::string& UTF8, const int codepage)
{
const int requiredSize = WideCharToMultiByte(codepage, 0, convertUTF8ToUTF16(UTF8).c_str(), -1, nullptr, 0, "0", nullptr);
char* asciiArray = new char[requiredSize];
if (0 == WideCharToMultiByte(codepage, 0, convertUTF8ToUTF16(UTF8).c_str(), -1, asciiArray, requiredSize, "0", nullptr))
{
Log(LogLevel::Error) << "Could not translate string to ASCII - " << GetLastErrorString();
}
std::string returnable(asciiArray);
delete[] asciiArray;
return returnable;
}
std::string convertUTF8ToWin1252(const std::string& UTF8)
{
return convertUTF8ToWin125_(UTF8, 1252);
}
std::string convertUTF8ToWin1251(const std::string& UTF8)
{
return convertUTF8ToWin125_(UTF8, 1251);
}
std::string convertUTF8ToWin1250(const std::string& UTF8)
{
return convertUTF8ToWin125_(UTF8, 1250);
}
std::string convert8859_15ToASCII(const std::string& input)
{
return convertUTF8ToASCII(convert8859_15ToUTF8(input));
}
std::string convert8859_15ToUTF8(const std::string& input)
{
return UTF16ToUTF8(convert8859_15ToUTF16(input));
}
std::wstring convert8859_15ToUTF16(const std::string& input)
{
const int requiredSize = MultiByteToWideChar(28605 /* 8859-15*/, MB_PRECOMPOSED, input.c_str(), -1, nullptr, 0);
auto* wideKeyArray = new wchar_t[requiredSize];
if (0 == MultiByteToWideChar(28605 /* 8859-15*/, MB_PRECOMPOSED, input.c_str(), -1, wideKeyArray, requiredSize))
{
Log(LogLevel::Error) << "Could not translate string to UTF-16 - " << GetLastErrorString();
}
std::wstring returnable(wideKeyArray);
delete[] wideKeyArray;
return returnable;
}
std::string convertWin1252ToASCII(const std::string& Win1252)
{
return convertUTF8ToASCII(convertWin1252ToUTF8(Win1252));
}
std::string convertWin1252ToUTF8(const std::string& Win1252)
{
return UTF16ToUTF8(convertWin1252ToUTF16(Win1252));
}
std::string convertWin1250ToUTF8(const std::string& Win1250)
{
return UTF16ToUTF8(convertWin1250ToUTF16(Win1250));
}
std::wstring convertWin1250ToUTF16(const std::string& Win1250)
{
const int requiredSize = MultiByteToWideChar(1250, MB_PRECOMPOSED, Win1250.c_str(), -1, nullptr, 0);
auto* wideKeyArray = new wchar_t[requiredSize];
if (0 == MultiByteToWideChar(1250, MB_PRECOMPOSED, Win1250.c_str(), -1, wideKeyArray, requiredSize))
{
Log(LogLevel::Error) << "Could not translate string to UTF-16 - " << GetLastErrorString();
}
std::wstring returnable(wideKeyArray);
delete[] wideKeyArray;
return returnable;
}
std::wstring convertWin1252ToUTF16(const std::string& Win1252)
{
const int requiredSize = MultiByteToWideChar(1252, MB_PRECOMPOSED, Win1252.c_str(), -1, nullptr, 0);
auto* wideKeyArray = new wchar_t[requiredSize];
if (0 == MultiByteToWideChar(1252, MB_PRECOMPOSED, Win1252.c_str(), -1, wideKeyArray, requiredSize))
{
Log(LogLevel::Error) << "Could not translate string to UTF-16 - " << GetLastErrorString();
}
std::wstring returnable(wideKeyArray);
delete[] wideKeyArray;
return returnable;
}
std::wstring convertUTF8ToUTF16(const std::string& UTF8)
{
const int requiredSize = MultiByteToWideChar(CP_UTF8, 0, UTF8.c_str(), -1, nullptr, 0);
if (requiredSize == 0)
{
Log(LogLevel::Error) << "Could not translate string to UTF-16 - " << GetLastErrorString();
}
auto* wideKeyArray = new wchar_t[requiredSize];
if (0 == MultiByteToWideChar(CP_UTF8, 0, UTF8.c_str(), -1, wideKeyArray, requiredSize))
{
Log(LogLevel::Error) << "Could not translate string to UTF-16 - " << GetLastErrorString();
}
std::wstring returnable(wideKeyArray);
delete[] wideKeyArray;
return returnable;
}
std::string convertToUTF8(const std::wstring& input)
{
return UTF16ToUTF8(input);
}
void WriteToConsole(const LogLevel level, const std::string& logMessage)
{
if (level == LogLevel::Debug)
{ // Don't log debug messages to console.
return;
}
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); // a handle to the console window
if (console != INVALID_HANDLE_VALUE)
{
CONSOLE_SCREEN_BUFFER_INFO oldConsoleInfo; // the current (soon to be outdated) console data
if (static_cast<bool>(GetConsoleScreenBufferInfo(console, &oldConsoleInfo)))
{
WORD color;
switch (level)
{
case LogLevel::Error:
color = FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
case LogLevel::Warning:
color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break;
case LogLevel::Info:
color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
break;
case LogLevel::Debug:
case LogLevel::Notice:
case LogLevel::Progress:
default:
color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
break;
}
SetConsoleTextAttribute(console, color);
DWORD bytesWritten = 0;
WriteConsoleW(console, convertUTF8ToUTF16(logMessage).c_str(), static_cast<DWORD>(logMessage.size()), &bytesWritten, nullptr);
// Restore old console color.
SetConsoleTextAttribute(console, oldConsoleInfo.wAttributes);
return;
}
}
std::cout << logMessage;
}
std::string convertWin1251ToUTF8(const std::string& Win1251)
{
return cp2utf(Win1251);
}
std::string convertUTF8toWin1251(const std::string& UTF8)
{
return utf2cp(UTF8);
}
std::optional<std::wstring> getSteamInstallPath(const std::string& steamID)
{
if (steamID.empty())
return std::nullopt;
wchar_t value[255];
value[0] = 0;
DWORD BufferSize = 8192;
std::wstring registryPath = convertUTF8ToUTF16(R"(SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Steam App )" + steamID);
const std::wstring installPath = convertUTF8ToUTF16(R"(InstallLocation)");
RegGetValue(HKEY_LOCAL_MACHINE, registryPath.c_str(), installPath.c_str(), RRF_RT_ANY, nullptr, static_cast<PVOID>(&value), &BufferSize);
if (value[0] != 0)
{
if (auto result = std::wstring(value); result.length() > 2)
{
return result;
}
}
registryPath = convertUTF8ToUTF16(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App )" + steamID);
RegGetValue(HKEY_LOCAL_MACHINE, registryPath.c_str(), installPath.c_str(), RRF_RT_ANY, nullptr, static_cast<PVOID>(&value), &BufferSize);
if (value[0] != 0)
{
if (auto result = std::wstring(value); result.length() > 2)
{
return result;
}
}
return std::nullopt;
}
} // namespace commonItems