mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-05 06:21:19 +12:00
Add all the files
This commit is contained in:
parent
e3db07a16a
commit
d60742f52b
1445 changed files with 430238 additions and 0 deletions
434
src/util/helpers/helpers.cpp
Normal file
434
src/util/helpers/helpers.cpp
Normal file
|
@ -0,0 +1,434 @@
|
|||
#include "helpers.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <random>
|
||||
|
||||
#include <wx/translation.h>
|
||||
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#include <TlHelp32.h>
|
||||
#endif
|
||||
|
||||
std::string& ltrim(std::string& str, const std::string& chars)
|
||||
{
|
||||
str.erase(0, str.find_first_not_of(chars));
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string& rtrim(std::string& str, const std::string& chars)
|
||||
{
|
||||
str.erase(str.find_last_not_of(chars) + 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string& trim(std::string& str, const std::string& chars)
|
||||
{
|
||||
return ltrim(rtrim(str, chars), chars);
|
||||
}
|
||||
|
||||
|
||||
std::string_view& ltrim(std::string_view& str, const std::string& chars)
|
||||
{
|
||||
str.remove_prefix(std::min(str.find_first_not_of(chars), str.size()));
|
||||
return str;
|
||||
}
|
||||
std::string_view& rtrim(std::string_view& str, const std::string& chars)
|
||||
{
|
||||
str.remove_suffix(std::max(str.size() - str.find_last_not_of(chars) - 1, (size_t)0));
|
||||
return str;
|
||||
}
|
||||
std::string_view& trim(std::string_view& str, const std::string& chars)
|
||||
{
|
||||
return ltrim(rtrim(str, chars), chars);
|
||||
}
|
||||
|
||||
#if BOOST_OS_WINDOWS > 0
|
||||
|
||||
std::wstring GetSystemErrorMessageW()
|
||||
{
|
||||
return GetSystemErrorMessageW(GetLastError());
|
||||
}
|
||||
|
||||
|
||||
std::wstring GetSystemErrorMessageW(DWORD error_code)
|
||||
{
|
||||
if(error_code == ERROR_SUCCESS)
|
||||
return {};
|
||||
|
||||
LPWSTR lpMsgBuf = nullptr;
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code, 0, (LPWSTR)&lpMsgBuf, 0, nullptr);
|
||||
if (lpMsgBuf)
|
||||
{
|
||||
std::wstring str = fmt::format(L"{}: {}", _("Error").ToStdWstring(), lpMsgBuf); // TRANSLATE
|
||||
LocalFree(lpMsgBuf);
|
||||
return str;
|
||||
}
|
||||
|
||||
return fmt::format(L"{}: {:#x}", _("Error code").ToStdWstring(), error_code);
|
||||
}
|
||||
|
||||
std::string GetSystemErrorMessage(DWORD error_code)
|
||||
{
|
||||
if(error_code == ERROR_SUCCESS)
|
||||
return {};
|
||||
|
||||
LPSTR lpMsgBuf = nullptr;
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code, 0, (LPSTR)&lpMsgBuf, 0, nullptr);
|
||||
if (lpMsgBuf)
|
||||
{
|
||||
std::string str = fmt::format("{}: {}", _("Error").ToStdString(), lpMsgBuf); // TRANSLATE
|
||||
LocalFree(lpMsgBuf);
|
||||
return str;
|
||||
}
|
||||
|
||||
return fmt::format("{}: {:#x}", _("Error code").ToStdString(), error_code);
|
||||
}
|
||||
|
||||
std::string GetSystemErrorMessage()
|
||||
{
|
||||
return GetSystemErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::string GetSystemErrorMessage()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::string GetSystemErrorMessage(const std::exception& ex)
|
||||
{
|
||||
const std::string msg = GetSystemErrorMessage();
|
||||
if(msg.empty())
|
||||
return ex.what();
|
||||
|
||||
return fmt::format("{}\n{}",msg, ex.what());
|
||||
}
|
||||
|
||||
std::string GetSystemErrorMessage(const std::error_code& ec)
|
||||
{
|
||||
const std::string msg = GetSystemErrorMessage();
|
||||
if(msg.empty())
|
||||
return ec.message();
|
||||
|
||||
return fmt::format("{}\n{}",msg, ec.message());
|
||||
}
|
||||
|
||||
#if BOOST_OS_WINDOWS > 0
|
||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
#pragma pack(push,8)
|
||||
typedef struct tagTHREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} THREADNAME_INFO;
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
void SetThreadName(const char* name)
|
||||
{
|
||||
#if BOOST_OS_WINDOWS > 0
|
||||
|
||||
#ifndef _PUBLIC_RELEASE
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = GetCurrentThreadId();
|
||||
info.dwFlags = 0;
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 6320 6322)
|
||||
__try {
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
pthread_setname_np(pthread_self(), name);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BOOST_OS_WINDOWS > 0
|
||||
std::pair<DWORD, DWORD> GetWindowsVersion()
|
||||
{
|
||||
using RtlGetVersion_t = LONG(*)(POSVERSIONINFOEXW);
|
||||
static RtlGetVersion_t pRtlGetVersion = nullptr;
|
||||
if(!pRtlGetVersion)
|
||||
pRtlGetVersion = (RtlGetVersion_t)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
|
||||
cemu_assert(pRtlGetVersion);
|
||||
|
||||
OSVERSIONINFOEXW version_info{};
|
||||
pRtlGetVersion(&version_info);
|
||||
return { version_info.dwMajorVersion, version_info.dwMinorVersion };
|
||||
}
|
||||
|
||||
bool IsWindows81OrGreater()
|
||||
{
|
||||
const auto [major, minor] = GetWindowsVersion();
|
||||
return major > 6 || (major == 6 && minor >= 3);
|
||||
}
|
||||
|
||||
bool IsWindows10OrGreater()
|
||||
{
|
||||
const auto [major, minor] = GetWindowsVersion();
|
||||
return major >= 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
fs::path GetParentProcess()
|
||||
{
|
||||
fs::path result;
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if(hSnapshot != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
|
||||
PROCESSENTRY32 pe{};
|
||||
pe.dwSize = sizeof(pe);
|
||||
for(BOOL ret = Process32First(hSnapshot, &pe); ret; ret = Process32Next(hSnapshot, &pe))
|
||||
{
|
||||
if(pe.th32ProcessID == pid)
|
||||
{
|
||||
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ParentProcessID);
|
||||
if(hProcess)
|
||||
{
|
||||
wchar_t tmp[MAX_PATH];
|
||||
DWORD size = std::size(tmp);
|
||||
if (QueryFullProcessImageNameW(hProcess, 0, tmp, &size) && size > 0)
|
||||
result = tmp;
|
||||
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
}
|
||||
#else
|
||||
assert_dbg();
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ltrim_copy(const std::string& s)
|
||||
{
|
||||
std::string result = s;
|
||||
ltrim(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string rtrim_copy(const std::string& s)
|
||||
{
|
||||
std::string result = s;
|
||||
rtrim(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t GetPhysicalCoreCount()
|
||||
{
|
||||
static uint32_t s_core_count = 0;
|
||||
if (s_core_count != 0)
|
||||
return s_core_count;
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
auto core_count = std::thread::hardware_concurrency();
|
||||
|
||||
// Get physical cores
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = nullptr;
|
||||
DWORD returnLength = 0;
|
||||
GetLogicalProcessorInformation(buffer, &returnLength);
|
||||
if (returnLength > 0)
|
||||
{
|
||||
buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);
|
||||
if (GetLogicalProcessorInformation(buffer, &returnLength))
|
||||
{
|
||||
uint32_t counter = 0;
|
||||
for (DWORD i = 0; i < returnLength / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i)
|
||||
{
|
||||
if (buffer[i].Relationship == RelationProcessorCore)
|
||||
++counter;
|
||||
}
|
||||
|
||||
if (counter > 0 && counter < core_count)
|
||||
core_count = counter;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
s_core_count = core_count;
|
||||
return core_count;
|
||||
#else
|
||||
return std::thread::hardware_concurrency();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TestWriteAccess(const fs::path& p)
|
||||
{
|
||||
// must be path and must exist
|
||||
if (!fs::exists(p) || !fs::is_directory(p))
|
||||
return false;
|
||||
|
||||
// retry 3 times
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
const auto filename = p / fmt::format("_{}.tmp", GenerateRandomString(8));
|
||||
if (fs::exists(filename))
|
||||
continue;
|
||||
|
||||
std::ofstream file(filename);
|
||||
if (!file.is_open()) // file couldn't be created
|
||||
break;
|
||||
|
||||
file.close();
|
||||
|
||||
std::error_code ec;
|
||||
fs::remove(filename, ec);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// make path relative to Cemu directory
|
||||
fs::path MakeRelativePath(const fs::path& path)
|
||||
{
|
||||
try
|
||||
{
|
||||
const fs::path base = ActiveSettings::GetPath();
|
||||
return fs::relative(path, base);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_DIRECTINPUT
|
||||
bool GUIDFromString(const char* string, GUID& guid)
|
||||
{
|
||||
unsigned long p0;
|
||||
int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
|
||||
const sint32 count = sscanf_s(string, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
|
||||
if (count != 11)
|
||||
return false;
|
||||
|
||||
guid.Data1 = p0;
|
||||
guid.Data2 = p1;
|
||||
guid.Data3 = p2;
|
||||
guid.Data4[0] = p3;
|
||||
guid.Data4[1] = p4;
|
||||
guid.Data4[2] = p5;
|
||||
guid.Data4[3] = p6;
|
||||
guid.Data4[4] = p7;
|
||||
guid.Data4[5] = p8;
|
||||
guid.Data4[6] = p9;
|
||||
guid.Data4[7] = p10;
|
||||
return count == 11;
|
||||
}
|
||||
|
||||
std::string StringFromGUID(const GUID& guid)
|
||||
{
|
||||
char temp[256];
|
||||
sprintf(temp, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
guid.Data1, guid.Data2, guid.Data3,
|
||||
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
|
||||
return std::string(temp);
|
||||
}
|
||||
|
||||
std::wstring WStringFromGUID(const GUID& guid)
|
||||
{
|
||||
wchar_t temp[256];
|
||||
swprintf_s(temp, L"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
guid.Data1, guid.Data2, guid.Data3,
|
||||
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
|
||||
|
||||
return std::wstring(temp);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<std::string_view> TokenizeView(std::string_view str, char delimiter)
|
||||
{
|
||||
std::vector<std::string_view> result;
|
||||
|
||||
size_t last_token_index = 0;
|
||||
for (auto index = str.find(delimiter); index != std::string_view::npos; index = str.find(delimiter, index + 1))
|
||||
{
|
||||
const auto token = str.substr(last_token_index, index - last_token_index);
|
||||
result.emplace_back(token);
|
||||
|
||||
last_token_index = index + 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const auto token = str.substr(last_token_index);
|
||||
result.emplace_back(token);
|
||||
}
|
||||
catch (const std::invalid_argument&) {}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> Tokenize(std::string_view str, char delimiter)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
size_t last_token_index = 0;
|
||||
for (auto index = str.find(delimiter); index != std::string_view::npos; index = str.find(delimiter, index + 1))
|
||||
{
|
||||
const auto token = str.substr(last_token_index, index - last_token_index);
|
||||
result.emplace_back(token);
|
||||
|
||||
last_token_index = index + 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const auto token = str.substr(last_token_index);
|
||||
result.emplace_back(token);
|
||||
}
|
||||
catch (const std::invalid_argument&) {}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GenerateRandomString(size_t length)
|
||||
{
|
||||
const std::string kCharacters{
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"1234567890" };
|
||||
return GenerateRandomString(length, kCharacters);
|
||||
}
|
||||
|
||||
std::string GenerateRandomString(size_t length, std::string_view characters)
|
||||
{
|
||||
assert(!characters.empty());
|
||||
std::stringstream result;
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<decltype(characters.size())> index_dist(0, characters.size() - 1);
|
||||
for (uint32_t i = 0; i < length; ++i)
|
||||
{
|
||||
result << characters[index_dist(gen)];
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue