Switch to wstring for paths on windows

This commit is contained in:
Tixx 2024-11-13 23:39:20 +01:00
parent 676084f283
commit 5e448dc34f
No known key found for this signature in database
GPG Key ID: EC6E7A2BAABF0B8C
12 changed files with 303 additions and 176 deletions

View File

@ -9,7 +9,7 @@
#include <string> #include <string>
class HTTP { class HTTP {
public: public:
static bool Download(const std::string& IP, const std::string& Path); static bool Download(const std::string& IP, const std::wstring& Path);
static std::string Post(const std::string& IP, const std::string& Fields); static std::string Post(const std::string& IP, const std::string& Fields);
static std::string Get(const std::string& IP); static std::string Get(const std::string& IP);
static bool ProgressBar(size_t c, size_t t); static bool ProgressBar(size_t c, size_t t);

View File

@ -14,4 +14,11 @@ void debug(const std::string& toPrint);
void error(const std::string& toPrint); void error(const std::string& toPrint);
void info(const std::string& toPrint); void info(const std::string& toPrint);
void warn(const std::string& toPrint); void warn(const std::string& toPrint);
void except(const std::wstring& toPrint);
void fatal(const std::wstring& toPrint);
void debug(const std::wstring& toPrint);
void error(const std::wstring& toPrint);
void info(const std::wstring& toPrint);
void warn(const std::wstring& toPrint);
std::string getDate(); std::string getDate();

View File

@ -6,9 +6,9 @@
#pragma once #pragma once
#include <string> #include <string>
void PreGame(const std::string& GamePath); void PreGame(const std::wstring& GamePath);
std::string CheckVer(const std::string& path); std::string CheckVer(const std::wstring& path);
void InitGame(const std::string& Dir); void InitGame(const std::wstring& Dir);
std::string GetGameDir(); std::wstring GetGameDir();
void LegitimacyCheck(); void LegitimacyCheck();
void CheckLocalKey(); void CheckLocalKey();

View File

@ -10,9 +10,9 @@
#include <vector> #include <vector>
void InitLauncher(); void InitLauncher();
std::string GetEP(const char* P = nullptr); std::wstring GetEP(const wchar_t* P = nullptr);
std::string GetGamePath(); std::wstring GetGamePath();
std::string GetVer(); std::string GetVer();
std::string GetPatch(); std::string GetPatch();
std::string GetEN(); std::wstring GetEN();
void ConfigInit(); void ConfigInit();

View File

@ -7,6 +7,11 @@
#pragma once #pragma once
#include <map> #include <map>
#include <regex> #include <regex>
#include <filesystem>
#include <fstream>
#include <locale>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <string> #include <string>
#include <vector> #include <vector>
@ -112,4 +117,132 @@ namespace Utils {
return ini; return ini;
} }
inline std::string ToString(const std::wstring& w) {
return std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>>().to_bytes(w);
}
inline std::wstring ToWString(const std::string& s) {
return std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>>().from_bytes(s);
}
inline std::string GetSha256HashReallyFast(const std::string& filename) {
try {
EVP_MD_CTX* mdctx;
const EVP_MD* md;
uint8_t sha256_value[EVP_MAX_MD_SIZE];
md = EVP_sha256();
if (md == nullptr) {
throw std::runtime_error("EVP_sha256() failed");
}
mdctx = EVP_MD_CTX_new();
if (mdctx == nullptr) {
throw std::runtime_error("EVP_MD_CTX_new() failed");
}
if (!EVP_DigestInit_ex2(mdctx, md, NULL)) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestInit_ex2() failed");
}
std::ifstream stream(filename, std::ios::binary);
const size_t FileSize = std::filesystem::file_size(filename);
size_t Read = 0;
std::vector<char> Data;
while (Read < FileSize) {
Data.resize(size_t(std::min<size_t>(FileSize - Read, 4096)));
size_t RealDataSize = Data.size();
stream.read(Data.data(), std::streamsize(Data.size()));
if (stream.eof() || stream.fail()) {
RealDataSize = size_t(stream.gcount());
}
Data.resize(RealDataSize);
if (RealDataSize == 0) {
break;
}
if (RealDataSize > 0 && !EVP_DigestUpdate(mdctx, Data.data(), Data.size())) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestUpdate() failed");
}
Read += RealDataSize;
}
unsigned int sha256_len = 0;
if (!EVP_DigestFinal_ex(mdctx, sha256_value, &sha256_len)) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestFinal_ex() failed");
}
EVP_MD_CTX_free(mdctx);
std::string result;
for (size_t i = 0; i < sha256_len; i++) {
char buf[3];
sprintf(buf, "%02x", sha256_value[i]);
buf[2] = 0;
result += buf;
}
return result;
} catch (const std::exception& e) {
error("Sha256 hashing of '" + filename + "' failed: " + e.what());
return "";
}
}
inline std::string GetSha256HashReallyFast(const std::wstring& filename) {
try {
EVP_MD_CTX* mdctx;
const EVP_MD* md;
uint8_t sha256_value[EVP_MAX_MD_SIZE];
md = EVP_sha256();
if (md == nullptr) {
throw std::runtime_error("EVP_sha256() failed");
}
mdctx = EVP_MD_CTX_new();
if (mdctx == nullptr) {
throw std::runtime_error("EVP_MD_CTX_new() failed");
}
if (!EVP_DigestInit_ex2(mdctx, md, NULL)) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestInit_ex2() failed");
}
std::wifstream stream(filename, std::ios::binary);
const size_t FileSize = std::filesystem::file_size(filename);
size_t Read = 0;
std::vector<wchar_t> Data;
while (Read < FileSize) {
Data.resize(size_t(std::min<size_t>(FileSize - Read, 4096)));
size_t RealDataSize = Data.size();
stream.read(Data.data(), std::streamsize(Data.size()));
if (stream.eof() || stream.fail()) {
RealDataSize = size_t(stream.gcount());
}
Data.resize(RealDataSize);
if (RealDataSize == 0) {
break;
}
if (RealDataSize > 0 && !EVP_DigestUpdate(mdctx, Data.data(), Data.size())) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestUpdate() failed");
}
Read += RealDataSize;
}
unsigned int sha256_len = 0;
if (!EVP_DigestFinal_ex(mdctx, sha256_value, &sha256_len)) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestFinal_ex() failed");
}
EVP_MD_CTX_free(mdctx);
std::string result;
for (size_t i = 0; i < sha256_len; i++) {
char buf[3];
sprintf(buf, "%02x", sha256_value[i]);
buf[2] = 0;
result += buf;
}
return result;
} catch (const std::exception& e) {
error(L"Sha256 hashing of '" + filename + L"' failed: " + ToWString(e.what()));
return "";
}
}
}; };

View File

@ -4,10 +4,9 @@
SPDX-License-Identifier: AGPL-3.0-or-later SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h>
#include <shlobj.h> #include <shlobj.h>
#include <windows.h>
#elif defined(__linux__) #elif defined(__linux__)
#include "vdf_parser.hpp" #include "vdf_parser.hpp"
#include <pwd.h> #include <pwd.h>
@ -29,8 +28,8 @@
unsigned long GamePID = 0; unsigned long GamePID = 0;
#if defined(_WIN32) #if defined(_WIN32)
std::string QueryKey(HKEY hKey, int ID); std::wstring QueryKey(HKEY hKey, int ID);
std::string GetGamePath() { std::wstring GetGamePath() {
static std::filesystem::path Path; static std::filesystem::path Path;
if (!Path.empty()) if (!Path.empty())
return Path.string(); return Path.string();
@ -59,7 +58,6 @@ std::string GetGamePath() {
} else } else
debug("Successfully parsed startup.ini"); debug("Successfully parsed startup.ini");
std::string userPath; std::string userPath;
if (ini.contains("filesystem") && ini["filesystem"].contains("UserPath")) if (ini.contains("filesystem") && ini["filesystem"].contains("UserPath"))
userPath = ini["filesystem"]["UserPath"]; userPath = ini["filesystem"]["UserPath"];
@ -82,22 +80,24 @@ std::string GetGamePath() {
Path = QueryKey(hKey, 4); Path = QueryKey(hKey, 4);
if (Path.empty()) { if (Path.empty()) {
char appDataPath[MAX_PATH]; wchar_t* appDataPath = new wchar_t[MAX_PATH];
HRESULT result = SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, appDataPath); HRESULT result = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, appDataPath);
if (!SUCCEEDED(result)) { if (!SUCCEEDED(result)) {
fatal("Cannot get Local Appdata directory"); fatal("Cannot get Local Appdata directory");
} }
Path = std::filesystem::path(appDataPath) / "BeamNG.drive"; Path = std::filesystem::path(appDataPath) / "BeamNG.drive";
delete[] appDataPath;
} }
} }
} }
std::string Ver = CheckVer(GetGameDir()); std::string Ver = CheckVer(GetGameDir());
Ver = Ver.substr(0, Ver.find('.', Ver.find('.') + 1)); Ver = Ver.substr(0, Ver.find('.', Ver.find('.') + 1));
Path = Path / (Ver + "\\"); Path += Utils::ToWString(Ver) + L"\\";
return Path.string(); return Path;
} }
#elif defined(__linux__) #elif defined(__linux__)
std::string GetGamePath() { std::string GetGamePath() {
@ -114,24 +114,24 @@ std::string GetGamePath() {
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)
void StartGame(std::string Dir) { void StartGame(std::wstring Dir) {
BOOL bSuccess = FALSE; BOOL bSuccess = FALSE;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
STARTUPINFO si = { 0 }; STARTUPINFOW si = { 0 };
si.cb = sizeof(si); si.cb = sizeof(si);
std::string BaseDir = Dir; //+"\\Bin64"; std::wstring BaseDir = Dir; //+"\\Bin64";
// Dir += R"(\Bin64\BeamNG.drive.x64.exe)"; // Dir += R"(\Bin64\BeamNG.drive.x64.exe)";
Dir += "\\BeamNG.drive.exe"; Dir += L"\\BeamNG.drive.exe";
std::string gameArgs = ""; std::wstring gameArgs = L"";
for (int i = 0; i < options.game_arguments_length; i++) { for (int i = 0; i < options.game_arguments_length; i++) {
gameArgs += " "; gameArgs += L" ";
gameArgs += options.game_arguments[i]; gameArgs += Utils::ToWString(options.game_arguments[i]);
} }
debug("BeamNG executable path: " + Dir); debug("BeamNG executable path: " + Dir);
bSuccess = CreateProcessA(nullptr, (LPSTR)(Dir + gameArgs).c_str(), nullptr, nullptr, TRUE, 0, nullptr, BaseDir.c_str(), &si, &pi); bSuccess = CreateProcessW(nullptr, (wchar_t*)(Dir + gameArgs).c_str(), nullptr, nullptr, TRUE, 0, nullptr, BaseDir.c_str(), &si, &pi);
if (bSuccess) { if (bSuccess) {
info("Game Launched!"); info("Game Launched!");
GamePID = pi.dwProcessId; GamePID = pi.dwProcessId;
@ -144,7 +144,8 @@ void StartGame(std::string Dir) {
LPVOID lpErrorMsgBuffer; LPVOID lpErrorMsgBuffer;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpErrorMsgBuffer, 0, nullptr) == 0) { MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpErrorMsgBuffer, 0, nullptr)
== 0) {
err = "Unknown error code: " + std::to_string(dw); err = "Unknown error code: " + std::to_string(dw);
} else { } else {
err = "Error " + std::to_string(dw) + ": " + (char*)lpErrorMsgBuffer; err = "Error " + std::to_string(dw) + ": " + (char*)lpErrorMsgBuffer;
@ -186,7 +187,7 @@ void StartGame(std::string Dir) {
} }
#endif #endif
void InitGame(const std::string& Dir) { void InitGame(const std::wstring& Dir) {
if (!options.no_launch) { if (!options.no_launch) {
std::thread Game(StartGame, Dir); std::thread Game(StartGame, Dir);
Game.detach(); Game.detach();

View File

@ -7,6 +7,7 @@
#include "Logger.h" #include "Logger.h"
#include "Startup.h" #include "Startup.h"
#include "Utils.h"
#include <chrono> #include <chrono>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -36,7 +37,7 @@ std::string getDate() {
} }
void InitLog() { void InitLog() {
std::ofstream LFS; std::ofstream LFS;
LFS.open(GetEP() + "Launcher.log"); LFS.open(GetEP() + L"Launcher.log");
if (!LFS.is_open()) { if (!LFS.is_open()) {
error("logger file init failed!"); error("logger file init failed!");
} else } else
@ -44,7 +45,13 @@ void InitLog() {
} }
void addToLog(const std::string& Line) { void addToLog(const std::string& Line) {
std::ofstream LFS; std::ofstream LFS;
LFS.open(GetEP() + "Launcher.log", std::ios_base::app); LFS.open(GetEP() + L"Launcher.log", std::ios_base::app);
LFS << Line.c_str();
LFS.close();
}
void addToLog(const std::wstring& Line) {
std::wofstream LFS;
LFS.open(GetEP() + L"Launcher.log", std::ios_base::app);
LFS << Line.c_str(); LFS << Line.c_str();
LFS.close(); LFS.close();
} }
@ -82,3 +89,39 @@ void except(const std::string& toPrint) {
std::cout << Print; std::cout << Print;
addToLog(Print); addToLog(Print);
} }
void info(const std::wstring& toPrint) {
std::wstring Print = Utils::ToWString(getDate()) + L"[INFO] " + toPrint + L"\n";
std::wcout << Print;
addToLog(Print);
}
void debug(const std::wstring& toPrint) {
std::wstring Print = Utils::ToWString(getDate()) + L"[DEBUG] " + toPrint + L"\n";
if (options.verbose) {
std::wcout << Print;
}
addToLog(Print);
}
void warn(const std::wstring& toPrint) {
std::wstring Print = Utils::ToWString(getDate()) + L"[WARN] " + toPrint + L"\n";
std::wcout << Print;
addToLog(Print);
}
void error(const std::wstring& toPrint) {
std::wstring Print = Utils::ToWString(getDate()) + L"[ERROR] " + toPrint + L"\n";
std::wcout << Print;
addToLog(Print);
}
void fatal(const std::wstring& toPrint) {
std::wstring Print = Utils::ToWString(getDate()) + L"[FATAL] " + toPrint + L"\n";
std::wcout << Print;
addToLog(Print);
std::this_thread::sleep_for(std::chrono::seconds(5));
std::exit(1);
}
void except(const std::wstring& toPrint) {
std::wstring Print = Utils::ToWString(getDate()) + L"[EXCEP] " + toPrint + L"\n";
std::wcout << Print;
addToLog(Print);
}

View File

@ -127,7 +127,7 @@ std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
return Ret; return Ret;
} }
bool HTTP::Download(const std::string& IP, const std::string& Path) { bool HTTP::Download(const std::string& IP, const std::wstring& Path) {
static std::mutex Lock; static std::mutex Lock;
std::scoped_lock Guard(Lock); std::scoped_lock Guard(Lock);
@ -145,7 +145,7 @@ bool HTTP::Download(const std::string& IP, const std::string& Path) {
File.close(); File.close();
info("Download Complete!"); info("Download Complete!");
} else { } else {
error("Failed to open file directory: " + Path); error(L"Failed to open file directory: " + Path);
return false; return false;
} }

View File

@ -301,68 +301,6 @@ void InvalidResource(const std::string& File) {
Terminate = true; Terminate = true;
} }
std::string GetSha256HashReallyFast(const std::string& filename) {
try {
EVP_MD_CTX* mdctx;
const EVP_MD* md;
uint8_t sha256_value[EVP_MAX_MD_SIZE];
md = EVP_sha256();
if (md == nullptr) {
throw std::runtime_error("EVP_sha256() failed");
}
mdctx = EVP_MD_CTX_new();
if (mdctx == nullptr) {
throw std::runtime_error("EVP_MD_CTX_new() failed");
}
if (!EVP_DigestInit_ex2(mdctx, md, NULL)) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestInit_ex2() failed");
}
std::ifstream stream(filename, std::ios::binary);
const size_t FileSize = std::filesystem::file_size(filename);
size_t Read = 0;
std::vector<char> Data;
while (Read < FileSize) {
Data.resize(size_t(std::min<size_t>(FileSize - Read, 4096)));
size_t RealDataSize = Data.size();
stream.read(Data.data(), std::streamsize(Data.size()));
if (stream.eof() || stream.fail()) {
RealDataSize = size_t(stream.gcount());
}
Data.resize(RealDataSize);
if (RealDataSize == 0) {
break;
}
if (RealDataSize > 0 && !EVP_DigestUpdate(mdctx, Data.data(), Data.size())) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestUpdate() failed");
}
Read += RealDataSize;
}
unsigned int sha256_len = 0;
if (!EVP_DigestFinal_ex(mdctx, sha256_value, &sha256_len)) {
EVP_MD_CTX_free(mdctx);
throw std::runtime_error("EVP_DigestFinal_ex() failed");
}
EVP_MD_CTX_free(mdctx);
std::string result;
for (size_t i = 0; i < sha256_len; i++) {
char buf[3];
sprintf(buf, "%02x", sha256_value[i]);
buf[2] = 0;
result += buf;
}
return result;
} catch (const std::exception& e) {
error("Sha256 hashing of '" + filename + "' failed: " + e.what());
return "";
}
}
struct ModInfo { struct ModInfo {
static std::pair<bool, std::vector<ModInfo>> ParseModInfosFromPacket(const std::string& packet) { static std::pair<bool, std::vector<ModInfo>> ParseModInfosFromPacket(const std::string& packet) {
bool success = false; bool success = false;
@ -507,13 +445,13 @@ void NewSyncResources(SOCKET Sock, const std::string& Mods, const std::vector<Mo
} }
auto FileName = std::filesystem::path(ModInfoIter->FileName).stem().string() + "-" + ModInfoIter->Hash.substr(0, 8) + std::filesystem::path(ModInfoIter->FileName).extension().string(); auto FileName = std::filesystem::path(ModInfoIter->FileName).stem().string() + "-" + ModInfoIter->Hash.substr(0, 8) + std::filesystem::path(ModInfoIter->FileName).extension().string();
auto PathToSaveTo = (fs::path(CachingDirectory) / FileName).string(); auto PathToSaveTo = (fs::path(CachingDirectory) / FileName).string();
if (fs::exists(PathToSaveTo) && GetSha256HashReallyFast(PathToSaveTo) == ModInfoIter->Hash) { if (fs::exists(PathToSaveTo) && Utils::GetSha256HashReallyFast(PathToSaveTo) == ModInfoIter->Hash) {
debug("Mod '" + FileName + "' found in cache"); debug("Mod '" + FileName + "' found in cache");
UpdateUl(false, std::to_string(ModNo) + "/" + std::to_string(TotalMods) + ": " + ModInfoIter->FileName); UpdateUl(false, std::to_string(ModNo) + "/" + std::to_string(TotalMods) + ": " + ModInfoIter->FileName);
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
try { try {
if (!fs::exists(GetGamePath() + "mods/multiplayer")) { if (!fs::exists(GetGamePath() + L"mods/multiplayer")) {
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + L"mods/multiplayer");
} }
auto modname = ModInfoIter->FileName; auto modname = ModInfoIter->FileName;
#if defined(__linux__) #if defined(__linux__)
@ -630,8 +568,8 @@ void NewSyncResources(SOCKET Sock, const std::string& Mods, const std::vector<Mo
} }
} while (fs::file_size(PathToSaveTo) != ModInfoIter->FileSize && !Terminate); } while (fs::file_size(PathToSaveTo) != ModInfoIter->FileSize && !Terminate);
if (!Terminate) { if (!Terminate) {
if (!fs::exists(GetGamePath() + "mods/multiplayer")) { if (!fs::exists(GetGamePath() + L"mods/multiplayer")) {
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + L"mods/multiplayer");
} }
// Linux version of the game doesnt support uppercase letters in mod names // Linux version of the game doesnt support uppercase letters in mod names
@ -729,8 +667,8 @@ void SyncResources(SOCKET Sock) {
UpdateUl(false, std::to_string(Pos) + "/" + std::to_string(Amount) + ": " + PathToSaveTo.substr(PathToSaveTo.find_last_of('/'))); UpdateUl(false, std::to_string(Pos) + "/" + std::to_string(Amount) + ": " + PathToSaveTo.substr(PathToSaveTo.find_last_of('/')));
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
try { try {
if (!fs::exists(GetGamePath() + "mods/multiplayer")) { if (!fs::exists(GetGamePath() + L"mods/multiplayer")) {
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + L"mods/multiplayer");
} }
auto modname = PathToSaveTo.substr(PathToSaveTo.find_last_of('/')); auto modname = PathToSaveTo.substr(PathToSaveTo.find_last_of('/'));
#if defined(__linux__) #if defined(__linux__)
@ -739,8 +677,8 @@ void SyncResources(SOCKET Sock) {
c = ::tolower(c); c = ::tolower(c);
} }
#endif #endif
auto name = GetGamePath() + "mods/multiplayer" + modname; auto name = GetGamePath() + L"mods/multiplayer" + Utils::ToWString(modname);
auto tmp_name = name + ".tmp"; auto tmp_name = name + L".tmp";
fs::copy_file(PathToSaveTo, tmp_name, fs::copy_options::overwrite_existing); fs::copy_file(PathToSaveTo, tmp_name, fs::copy_options::overwrite_existing);
fs::rename(tmp_name, name); fs::rename(tmp_name, name);
UpdateModUsage(modname); UpdateModUsage(modname);
@ -787,8 +725,8 @@ void SyncResources(SOCKET Sock) {
} }
} while (fs::file_size(PathToSaveTo) != std::stoull(*FS) && !Terminate); } while (fs::file_size(PathToSaveTo) != std::stoull(*FS) && !Terminate);
if (!Terminate) { if (!Terminate) {
if (!fs::exists(GetGamePath() + "mods/multiplayer")) { if (!fs::exists(GetGamePath() + L"mods/multiplayer")) {
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + L"mods/multiplayer");
} }
// Linux version of the game doesnt support uppercase letters in mod names // Linux version of the game doesnt support uppercase letters in mod names
@ -798,7 +736,7 @@ void SyncResources(SOCKET Sock) {
} }
#endif #endif
fs::copy_file(PathToSaveTo, GetGamePath() + "mods/multiplayer" + FName, fs::copy_options::overwrite_existing); fs::copy_file(PathToSaveTo, GetGamePath() + L"mods/multiplayer" + Utils::ToWString(FName), fs::copy_options::overwrite_existing);
UpdateModUsage(FN->substr(pos)); UpdateModUsage(FN->substr(pos));
} }
WaitForConfirm(); WaitForConfirm();

View File

@ -23,7 +23,7 @@
#define MAX_VALUE_NAME 16383 #define MAX_VALUE_NAME 16383
int TraceBack = 0; int TraceBack = 0;
std::string GameDir; std::wstring GameDir;
void lowExit(int code) { void lowExit(int code) {
TraceBack = 0; TraceBack = 0;
@ -33,7 +33,7 @@ void lowExit(int code) {
exit(2); exit(2);
} }
std::string GetGameDir() { std::wstring GetGameDir() {
#if defined(_WIN32) #if defined(_WIN32)
return GameDir.substr(0, GameDir.find_last_of('\\')); return GameDir.substr(0, GameDir.find_last_of('\\'));
#elif defined(__linux__) #elif defined(__linux__)
@ -44,8 +44,8 @@ std::string GetGameDir() {
LONG OpenKey(HKEY root, const char* path, PHKEY hKey) { LONG OpenKey(HKEY root, const char* path, PHKEY hKey) {
return RegOpenKeyEx(root, reinterpret_cast<LPCSTR>(path), 0, KEY_READ, hKey); return RegOpenKeyEx(root, reinterpret_cast<LPCSTR>(path), 0, KEY_READ, hKey);
} }
std::string QueryKey(HKEY hKey, int ID) { std::wstring QueryKey(HKEY hKey, int ID) {
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name wchar_t* achKey; // buffer for subkey name
DWORD cbName; // size of name string DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string DWORD cchClassName = MAX_PATH; // size of class string
@ -60,7 +60,7 @@ std::string QueryKey(HKEY hKey, int ID) {
DWORD i, retCode; DWORD i, retCode;
TCHAR achValue[MAX_VALUE_NAME]; wchar_t* achValue = new wchar_t[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME; DWORD cchValue = MAX_VALUE_NAME;
retCode = RegQueryInfoKey( retCode = RegQueryInfoKey(
@ -82,9 +82,9 @@ std::string QueryKey(HKEY hKey, int ID) {
if (cSubKeys) { if (cSubKeys) {
for (i = 0; i < cSubKeys; i++) { for (i = 0; i < cSubKeys; i++) {
cbName = MAX_KEY_LENGTH; cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKey, i, achKey, &cbName, nullptr, nullptr, nullptr, &ftLastWriteTime); retCode = RegEnumKeyExW(hKey, i, achKey, &cbName, nullptr, nullptr, nullptr, &ftLastWriteTime);
if (retCode == ERROR_SUCCESS) { if (retCode == ERROR_SUCCESS) {
if (strcmp(achKey, "Steam App 284160") == 0) { if (wcscmp(achKey, L"Steam App 284160") == 0) {
return achKey; return achKey;
} }
} }
@ -94,36 +94,37 @@ std::string QueryKey(HKEY hKey, int ID) {
for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++) { for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++) {
cchValue = MAX_VALUE_NAME; cchValue = MAX_VALUE_NAME;
achValue[0] = '\0'; achValue[0] = '\0';
retCode = RegEnumValue(hKey, i, achValue, &cchValue, nullptr, nullptr, nullptr, nullptr); retCode = RegEnumValueW(hKey, i, achValue, &cchValue, nullptr, nullptr, nullptr, nullptr);
if (retCode == ERROR_SUCCESS) { if (retCode == ERROR_SUCCESS) {
DWORD lpData = cbMaxValueData; DWORD lpData = cbMaxValueData;
buffer[0] = '\0'; buffer[0] = '\0';
LONG dwRes = RegQueryValueEx(hKey, achValue, nullptr, nullptr, buffer, &lpData); LONG dwRes = RegQueryValueExW(hKey, achValue, nullptr, nullptr, buffer, &lpData);
std::string data = (char*)(buffer); std::wstring data = (wchar_t*)(buffer);
std::string key = achValue; std::wstring key = achValue;
switch (ID) { switch (ID) {
case 1: case 1:
if (key == "SteamExe") { if (key == L"SteamExe") {
auto p = data.find_last_of("/\\"); auto p = data.find_last_of(L"/\\");
if (p != std::string::npos) { if (p != std::string::npos) {
return data.substr(0, p); return data.substr(0, p);
} }
} }
break; break;
case 2: case 2:
if (key == "Name" && data == "BeamNG.drive") if (key == L"Name" && data == L"BeamNG.drive")
return data; return data;
break; break;
case 3: case 3:
if (key == "rootpath") if (key == L"rootpath")
return data; return data;
break; break;
case 4: case 4:
if (key == "userpath_override") if (key == L"userpath_override")
return data; return data;
case 5: case 5:
if (key == "Local AppData") if (key == L"Local AppData")
return data; return data;
default: default:
break; break;
@ -131,8 +132,9 @@ std::string QueryKey(HKEY hKey, int ID) {
} }
} }
} }
delete[] achValue;
delete[] buffer; delete[] buffer;
return ""; return L"";
} }
#endif #endif
@ -159,7 +161,7 @@ void FileList(std::vector<std::string>& a, const std::string& Path) {
} }
void LegitimacyCheck() { void LegitimacyCheck() {
#if defined(_WIN32) #if defined(_WIN32)
std::string Result; std::wstring Result;
std::string K3 = R"(Software\BeamNG\BeamNG.drive)"; std::string K3 = R"(Software\BeamNG\BeamNG.drive)";
HKEY hKey; HKEY hKey;
LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K3.c_str(), &hKey); LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K3.c_str(), &hKey);
@ -229,11 +231,12 @@ void LegitimacyCheck() {
} }
#endif #endif
} }
std::string CheckVer(const std::string& dir) { std::string CheckVer(const std::wstring& dir) {
std::string temp;
#if defined(_WIN32) #if defined(_WIN32)
std::string temp, Path = dir + "\\integrity.json"; std::wstring Path = dir + L"\\integrity.json";
#elif defined(__linux__) #elif defined(__linux__)
std::string temp, Path = dir + "/integrity.json"; std::wstring Path = dir + L"/integrity.json";
#endif #endif
std::ifstream f(Path.c_str(), std::ios::binary); std::ifstream f(Path.c_str(), std::ios::binary);
int Size = int(std::filesystem::file_size(Path)); int Size = int(std::filesystem::file_size(Path));

View File

@ -19,13 +19,14 @@
#include "Http.h" #include "Http.h"
#include "Logger.h" #include "Logger.h"
#include "Network/network.hpp" #include "Network/network.hpp"
#include "Options.h"
#include "Security/Init.h" #include "Security/Init.h"
#include "Startup.h" #include "Startup.h"
#include "Utils.h"
#include "hashpp.h" #include "hashpp.h"
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <thread> #include <thread>
#include "Options.h"
extern int TraceBack; extern int TraceBack;
int ProxyPort = 0; int ProxyPort = 0;
@ -72,11 +73,11 @@ Version::Version(const std::array<uint8_t, 3>& v)
: Version(v[0], v[1], v[2]) { : Version(v[0], v[1], v[2]) {
} }
std::string GetEN() { std::wstring GetEN() {
#if defined(_WIN32) #if defined(_WIN32)
return "BeamMP-Launcher.exe"; return L"BeamMP-Launcher.exe";
#elif defined(__linux__) #elif defined(__linux__)
return "BeamMP-Launcher"; return L"BeamMP-Launcher";
#endif #endif
} }
@ -87,34 +88,34 @@ std::string GetPatch() {
return ".1"; return ".1";
} }
std::string GetEP(const char* P) { std::wstring GetEP(const wchar_t* P) {
static std::string Ret = [&]() { static std::wstring Ret = [&]() {
std::string path(P); std::wstring path(P);
return path.substr(0, path.find_last_of("\\/") + 1); return path.substr(0, path.find_last_of(L"\\/") + 1);
}(); }();
return Ret; return Ret;
} }
#if defined(_WIN32) #if defined(_WIN32)
void ReLaunch() { void ReLaunch() {
std::string Arg; std::wstring Arg;
for (int c = 2; c <= options.argc; c++) { for (int c = 2; c <= options.argc; c++) {
Arg += options.argv[c - 1]; Arg += Utils::ToWString(options.argv[c - 1]);
Arg += " "; Arg += L" ";
} }
info("Relaunch!"); info("Relaunch!");
system("cls"); system("cls");
ShellExecute(nullptr, "runas", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL); ShellExecuteW(nullptr, L"runas", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
ShowWindow(GetConsoleWindow(), 0); ShowWindow(GetConsoleWindow(), 0);
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
exit(1); exit(1);
} }
void URelaunch() { void URelaunch() {
std::string Arg; std::wstring Arg;
for (int c = 2; c <= options.argc; c++) { for (int c = 2; c <= options.argc; c++) {
Arg += options.argv[c - 1]; Arg += Utils::ToWString(options.argv[c - 1]);
Arg += " "; Arg += L" ";
} }
ShellExecute(nullptr, "open", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL); ShellExecuteW(nullptr, L"open", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
ShowWindow(GetConsoleWindow(), 0); ShowWindow(GetConsoleWindow(), 0);
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
exit(1); exit(1);
@ -149,16 +150,16 @@ void URelaunch() {
void CheckName() { void CheckName() {
#if defined(_WIN32) #if defined(_WIN32)
std::string DN = GetEN(), CDir = options.executable_name, FN = CDir.substr(CDir.find_last_of('\\') + 1); std::wstring DN = GetEN(), CDir = Utils::ToWString(options.executable_name), FN = CDir.substr(CDir.find_last_of('\\') + 1);
#elif defined(__linux__) #elif defined(__linux__)
std::string DN = GetEN(), CDir = options.executable_name, FN = CDir.substr(CDir.find_last_of('/') + 1); std::wstring DN = GetEN(), CDir = Utils::ToWString(options.executable_name), FN = CDir.substr(CDir.find_last_of('/') + 1);
#endif #endif
if (FN != DN) { if (FN != DN) {
if (fs::exists(DN)) if (fs::exists(DN))
remove(DN.c_str()); _wremove(DN.c_str());
if (fs::exists(DN)) if (fs::exists(DN))
ReLaunch(); ReLaunch();
std::rename(FN.c_str(), DN.c_str()); _wrename(FN.c_str(), DN.c_str());
URelaunch(); URelaunch();
} }
} }
@ -169,9 +170,9 @@ void CheckForUpdates(const std::string& CV) {
"https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey); "https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey);
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower); transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back"); std::wstring EP(GetEP() + GetEN()), Back(GetEP() + L"BeamMP-Launcher.back");
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, EP); std::string FileHash = Utils::GetSha256HashReallyFast(EP);
if (FileHash != LatestHash && IsOutdated(Version(VersionStrToInts(GetVer() + GetPatch())), Version(VersionStrToInts(LatestVersion)))) { if (FileHash != LatestHash && IsOutdated(Version(VersionStrToInts(GetVer() + GetPatch())), Version(VersionStrToInts(LatestVersion)))) {
if (!options.no_update) { if (!options.no_update) {
@ -251,7 +252,7 @@ size_t DirCount(const std::filesystem::path& path) {
return (size_t)std::distance(std::filesystem::directory_iterator { path }, std::filesystem::directory_iterator {}); return (size_t)std::distance(std::filesystem::directory_iterator { path }, std::filesystem::directory_iterator {});
} }
void CheckMP(const std::string& Path) { void CheckMP(const std::wstring& Path) {
if (!fs::exists(Path)) if (!fs::exists(Path))
return; return;
size_t c = DirCount(fs::path(Path)); size_t c = DirCount(fs::path(Path));
@ -271,7 +272,7 @@ void CheckMP(const std::string& Path) {
} }
void EnableMP() { void EnableMP() {
std::string File(GetGamePath() + "mods/db.json"); std::wstring File(GetGamePath() + L"mods/db.json");
if (!fs::exists(File)) if (!fs::exists(File))
return; return;
auto Size = fs::file_size(File); auto Size = fs::file_size(File);
@ -294,18 +295,18 @@ void EnableMP() {
ofs << d.dump(); ofs << d.dump();
ofs.close(); ofs.close();
} else { } else {
error("Failed to write " + File); error(L"Failed to write " + File);
} }
} }
} }
} }
void PreGame(const std::string& GamePath) { void PreGame(const std::wstring& GamePath) {
std::string GameVer = CheckVer(GamePath); std::string GameVer = CheckVer(GamePath);
info("Game Version : " + GameVer); info("Game Version : " + GameVer);
CheckMP(GetGamePath() + "mods/multiplayer"); CheckMP(GetGamePath() + L"mods/multiplayer");
info("Game user path: " + GetGamePath()); info(L"Game user path: " + GetGamePath());
if (!options.no_download) { if (!options.no_download) {
std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/mod?branch=" + Branch + "&pk=" + PublicKey); std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/mod?branch=" + Branch + "&pk=" + PublicKey);
@ -315,21 +316,21 @@ void PreGame(const std::string& GamePath) {
LatestHash.end()); LatestHash.end());
try { try {
if (!fs::exists(GetGamePath() + "mods/multiplayer")) { if (!fs::exists(GetGamePath() + L"mods/multiplayer")) {
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + L"mods/multiplayer");
} }
EnableMP(); EnableMP();
} catch (std::exception& e) { } catch (std::exception& e) {
fatal(e.what()); fatal(e.what());
} }
#if defined(_WIN32) #if defined(_WIN32)
std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)"); std::wstring ZipPath(GetGamePath() + LR"(mods\multiplayer\BeamMP.zip)");
#elif defined(__linux__) #elif defined(__linux__)
// Linux version of the game cant handle mods with uppercase names // Linux version of the game cant handle mods with uppercase names
std::string ZipPath(GetGamePath() + R"(mods/multiplayer/beammp.zip)"); std::wstring ZipPath(GetGamePath() + LR"(mods/multiplayer/beammp.zip)");
#endif #endif
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, ZipPath); std::string FileHash = Utils::GetSha256HashReallyFast(ZipPath);
if (FileHash != LatestHash) { if (FileHash != LatestHash) {
info("Downloading BeamMP Update " + LatestHash); info("Downloading BeamMP Update " + LatestHash);
@ -339,7 +340,7 @@ void PreGame(const std::string& GamePath) {
ZipPath); ZipPath);
} }
std::string Target(GetGamePath() + "mods/unpacked/beammp"); std::wstring Target(GetGamePath() + L"mods/unpacked/beammp");
if (fs::is_directory(Target) && !fs::is_directory(Target + "/.git")) { if (fs::is_directory(Target) && !fs::is_directory(Target + "/.git")) {
fs::remove_all(Target); fs::remove_all(Target);

View File

@ -9,6 +9,7 @@
#include "Network/network.hpp" #include "Network/network.hpp"
#include "Security/Init.h" #include "Security/Init.h"
#include "Startup.h" #include "Startup.h"
#include "Utils.h"
#include <curl/curl.h> #include <curl/curl.h>
#include <iostream> #include <iostream>
#include <thread> #include <thread>
@ -37,7 +38,7 @@ int main(int argc, const char** argv) try {
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
GetEP(argv[0]); GetEP(Utils::ToWString(std::string(argv[0])).c_str());
InitLog(); InitLog();
ConfigInit(); ConfigInit();