From 54d0392375d28ba5771f64d012628b3fe39fffe5 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sun, 26 Jul 2026 10:32:32 +0200 Subject: [PATCH] General code cleanup + various smaller fixes --- src/Cemu/DiscordPresence/DiscordRPCLite.cpp | 56 +++++++++++++++---- src/Cemu/napi/napi_helper.cpp | 2 +- src/Cemu/ncrypto/ncrypto.cpp | 10 ++-- .../ExceptionHandler_win32.cpp | 4 +- src/config/CemuConfig.cpp | 1 + src/config/LaunchSettings.cpp | 28 +++++++--- .../EmulatedUSBDeviceFrame.cpp | 8 +++ src/gui/wxgui/components/wxGameList.cpp | 3 +- src/input/InputManager.cpp | 25 +++++---- src/input/api/SDL/SDLController.cpp | 3 + .../api/Wiimote/WiimoteControllerProvider.cpp | 5 +- src/main.cpp | 2 +- src/util/crypto/aes128.cpp | 1 + 13 files changed, 103 insertions(+), 45 deletions(-) diff --git a/src/Cemu/DiscordPresence/DiscordRPCLite.cpp b/src/Cemu/DiscordPresence/DiscordRPCLite.cpp index 5459d553..1cd9cbde 100644 --- a/src/Cemu/DiscordPresence/DiscordRPCLite.cpp +++ b/src/Cemu/DiscordPresence/DiscordRPCLite.cpp @@ -38,6 +38,32 @@ enum RPCOpcode : uint32_t OpcodePong = 4, }; +static std::string EscapeJSONString(std::string_view value) +{ + std::string escaped; + escaped.reserve(value.size() + 16); // original string length plus some extra space for escaped characters + for (unsigned char c : value) + { + switch (c) + { + case '"': escaped.append("\\\""); break; + case '\\': escaped.append("\\\\"); break; + case '\b': escaped.append("\\b"); break; + case '\f': escaped.append("\\f"); break; + case '\n': escaped.append("\\n"); break; + case '\r': escaped.append("\\r"); break; + case '\t': escaped.append("\\t"); break; + default: + if (c < 32) + escaped.append(shim::format("\\u{:04x}", c)); + else + escaped.push_back(c); + break; + } + } + return escaped; +} + #ifdef _WIN32 class NamedPipeImpl { @@ -307,9 +333,9 @@ class NamedPipe : public NamedPipeImpl { jsonPayload.append(R"("activity": {)"); if (!presence.state.empty()) - jsonPayload.append(shim::format(R"("state": "{}",)", presence.state)); + jsonPayload.append(shim::format(R"("state": "{}",)", EscapeJSONString(presence.state))); if (!presence.details.empty()) - jsonPayload.append(shim::format(R"("details": "{}",)", presence.details)); + jsonPayload.append(shim::format(R"("details": "{}",)", EscapeJSONString(presence.details))); if (presence.startTimestamp || presence.endTimestamp) { jsonPayload.append(R"("timestamps": {)"); @@ -321,13 +347,19 @@ class NamedPipe : public NamedPipeImpl jsonPayload.pop_back(); jsonPayload.append("},"); } - if (!presence.largeImageKey.empty() && !presence.largeImageText.empty() && !presence.smallImageKey.empty() && !presence.smallImageText.empty()) + if (!presence.largeImageKey.empty() || !presence.largeImageText.empty() || !presence.smallImageKey.empty() || !presence.smallImageText.empty()) { jsonPayload.append(R"("assets": {)"); - jsonPayload.append(shim::format(R"("large_image": "{}",)", presence.largeImageKey)); - jsonPayload.append(shim::format(R"("large_text": "{}",)", presence.largeImageText)); - jsonPayload.append(shim::format(R"("small_image": "{}",)", presence.smallImageKey)); - jsonPayload.append(shim::format(R"("small_text": "{}",)", presence.smallImageText)); + if (!presence.largeImageKey.empty()) + jsonPayload.append(shim::format(R"("large_image": "{}",)", EscapeJSONString(presence.largeImageKey))); + if (!presence.largeImageText.empty()) + jsonPayload.append(shim::format(R"("large_text": "{}",)", EscapeJSONString(presence.largeImageText))); + if (!presence.smallImageKey.empty()) + jsonPayload.append(shim::format(R"("small_image": "{}",)", EscapeJSONString(presence.smallImageKey))); + if (!presence.smallImageText.empty()) + jsonPayload.append(shim::format(R"("small_text": "{}",)", EscapeJSONString(presence.smallImageText))); + if (jsonPayload.back() == ',') + jsonPayload.pop_back(); jsonPayload.append("},"); } // party @@ -335,7 +367,7 @@ class NamedPipe : public NamedPipeImpl { jsonPayload.append(R"("party": {)"); if (!presence.partyId.empty()) - jsonPayload.append(shim::format(R"("id": "{}",)", presence.partyId)); + jsonPayload.append(shim::format(R"("id": "{}",)", EscapeJSONString(presence.partyId))); if (presence.partySize > 0 && presence.partyMax > 0) jsonPayload.append(shim::format(R"("size": [{}, {}],)", presence.partySize, presence.partyMax)); jsonPayload.append(R"("privacy": )").append(std::to_string(presence.partyPrivacy)).append(","); @@ -346,11 +378,11 @@ class NamedPipe : public NamedPipeImpl { jsonPayload.append(R"("secrets": {)"); if (!presence.matchSecret.empty()) - jsonPayload.append(shim::format(R"("match": "{}",)", presence.matchSecret)); + jsonPayload.append(shim::format(R"("match": "{}",)", EscapeJSONString(presence.matchSecret))); if (!presence.joinSecret.empty()) - jsonPayload.append(shim::format(R"("join": "{}",)", presence.joinSecret)); + jsonPayload.append(shim::format(R"("join": "{}",)", EscapeJSONString(presence.joinSecret))); if (!presence.spectateSecret.empty()) - jsonPayload.append(shim::format(R"("spectate": "{}",)", presence.spectateSecret)); + jsonPayload.append(shim::format(R"("spectate": "{}",)", EscapeJSONString(presence.spectateSecret))); if (jsonPayload.back() == ',') jsonPayload.pop_back(); jsonPayload.append("},"); @@ -649,7 +681,7 @@ void DiscordRPCLite::WorkerThread(std::string applicationId) { std::optional cmd = ParseJSONField(jsonText, "cmd"); std::optional evt = ParseJSONField(jsonText, "evt"); - if (CompareStringI(*cmd, "DISPATCH")) + if (cmd && CompareStringI(*cmd, "DISPATCH")) { if (evt && CompareStringI(*evt, "READY")) { diff --git a/src/Cemu/napi/napi_helper.cpp b/src/Cemu/napi/napi_helper.cpp index ce11e2fe..d7271d19 100644 --- a/src/Cemu/napi/napi_helper.cpp +++ b/src/Cemu/napi/napi_helper.cpp @@ -110,7 +110,7 @@ CURLcode _sslctx_function_CUSTOM(CURL* curl, void* sslctx, void* param) } for (auto& clientCertId : requestHelper->GetClientCertIds()) { - if (iosuCrypto_addCACertificate(sslctx, clientCertId) == false) + if (iosuCrypto_addClientCertificate(sslctx, clientCertId) == false) { cemuLog_log(LogType::Force, "Invalid client certificate ({})", clientCertId); } diff --git a/src/Cemu/ncrypto/ncrypto.cpp b/src/Cemu/ncrypto/ncrypto.cpp index 28b3bac9..bbd3dde8 100644 --- a/src/Cemu/ncrypto/ncrypto.cpp +++ b/src/Cemu/ncrypto/ncrypto.cpp @@ -122,10 +122,10 @@ namespace NCrypto for (size_t i = 0, j = 0; i < in_len;) { - uint32 a = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(inputStr[i++])]; - uint32 b = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(inputStr[i++])]; - uint32 c = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(inputStr[i++])]; - uint32 d = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(inputStr[i++])]; + uint32 a = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(inputStr[i++])]; + uint32 b = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(inputStr[i++])]; + uint32 c = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(inputStr[i++])]; + uint32 d = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(inputStr[i++])]; uint32 triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); @@ -296,7 +296,7 @@ namespace NCrypto cemu_assert_debug(extHeader->sectionTableEntrySize == 0x14); for (uint32 i = 0; i < extHeader->sectionTableNumEntries; i++) { - ETicketFileHeaderExtV1SectionHeader* sectHeader = (ETicketFileHeaderExtV1SectionHeader*)readStruct(0x2A4 + extHeader->sectionTableOffset, sizeof(ETicketFileHeaderExtV1SectionHeader)); + ETicketFileHeaderExtV1SectionHeader* sectHeader = (ETicketFileHeaderExtV1SectionHeader*)readStruct(0x2A4 + extHeader->sectionTableOffset + i * extHeader->sectionTableEntrySize, sizeof(ETicketFileHeaderExtV1SectionHeader)); if (!sectHeader) return false; if (sectHeader->type == ETicketFileHeaderExtV1SectionHeader::SECTION_TYPE_CONTENT_RIGHTS) diff --git a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp index 6b205d26..10e165cb 100644 --- a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp +++ b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp @@ -59,7 +59,7 @@ bool CreateMiniDump(CrashDump dump, EXCEPTION_POINTERS* pep) const auto temp_time = std::chrono::system_clock::to_time_t(now); const auto& time = *std::gmtime(&temp_time); - p /= fmt::format("crash_{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}.dmp", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_year, time.tm_hour, time.tm_min, time.tm_sec); + p /= fmt::format("crash_{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}.dmp", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); const auto hFile = CreateFileW(p.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) @@ -232,7 +232,7 @@ void createCrashlog(EXCEPTION_POINTERS* e, PCONTEXT context) const auto& time = *std::gmtime(&temp_time); fs::path p = ActiveSettings::GetUserDataPath("crashdump"); - p /= fmt::format("log_{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}.txt", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_year, time.tm_hour, time.tm_min, time.tm_sec); + p /= fmt::format("log_{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}.txt", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); std::error_code ec; fs::copy_file(ActiveSettings::GetUserDataPath("log.txt"), p, ec); diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index 139c290c..6985f1c5 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -302,6 +302,7 @@ XMLConfigParser CemuConfig::Save(XMLConfigParser& parser) config.set("mlc_path", mlc_path.GetValue().c_str()); config.set("permanent_storage", permanent_storage); config.set("proxy_server", proxy_server.GetValue().c_str()); + config.set("disable_screensaver", disable_screensaver); config.set("play_boot_sound", play_boot_sound); // config.set("cpu_mode", cpu_mode.GetValue()); diff --git a/src/config/LaunchSettings.cpp b/src/config/LaunchSettings.cpp index e12fdc62..1de64eeb 100644 --- a/src/config/LaunchSettings.cpp +++ b/src/config/LaunchSettings.cpp @@ -12,6 +12,7 @@ #include "util/crypto/aes128.h" #include "Cafe/Filesystem/FST/FST.h" +#include "Cafe/TitleList/TitleId.h" #include "util/helpers/StringHelpers.h" void requireConsole(); @@ -146,13 +147,14 @@ std::optional LaunchSettings::HandleCommandline(const std::vector(); + auto titleParam = vm["title-id"].as(); try { - - if (title_param.starts_with('=')){ - title_param.erase(title_param.begin()); - } - s_load_title_id = std::stoull(title_param, nullptr, 16); + if (titleParam.starts_with('=')) + titleParam.erase(titleParam.begin()); + TitleId titleId; + if (!TitleIdParser::ParseFromStr(titleParam, titleId)) + std::cerr << "Invalid title id format"; + s_load_title_id = titleId; } catch (std::invalid_argument const& e) { @@ -220,14 +222,22 @@ std::optional LaunchSettings::HandleCommandline(const std::vector>()) { - size_t colon_location = argument.find(L':'); - if (colon_location == std::wstring::npos) + sint32 winDriveColonOffset = 0; +#if BOOST_OS_WINDOWS + // on Windows a path may start with \\?\C:\ or C:\ (where C can be an arbitrary drive letter), but the delimiter is also a colon, so filter out the drive colon + static const std::wregex winDrivePrefixRegex(LR"(^(?:\\\\\?\\)?[A-Za-z]:)"); + std::wsmatch winDrivePrefixMatch; + if (std::regex_search(argument, winDrivePrefixMatch, winDrivePrefixRegex)) + winDriveColonOffset = static_cast(winDrivePrefixMatch.length()); +#endif + size_t colonLocation = argument.find(L':', winDriveColonOffset); + if (colonLocation == std::wstring::npos) { std::cerr << "Argument for a mount expects to be in the format: `path on host:path in emulated system`, was not: `" << boost::nowide::narrow(argument) << "`\n"; continue; } - s_cos_mounts[argument.substr(0, colon_location)] = argument.substr(colon_location + 1); + s_cos_mounts[argument.substr(0, colonLocation)] = argument.substr(colonLocation + 1); } } diff --git a/src/gui/wxgui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp b/src/gui/wxgui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp index 5015fc5d..c1d4b81b 100644 --- a/src/gui/wxgui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp +++ b/src/gui/wxgui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp @@ -556,6 +556,7 @@ CreateInfinityFigureDialog::CreateInfinityFigureDialog(wxWindow* parent, uint8 s wxMessageDialog idError(this, "Error Converting Figure Number!", "Number Entered is Invalid"); idError.ShowModal(); this->EndModal(0); + return; } uint32 figNum = longFigNum & 0xFFFFFFFF; auto figure = nsyshid::g_infinitybase.FindFigure(figNum); @@ -565,7 +566,10 @@ CreateInfinityFigureDialog::CreateInfinityFigureDialog(wxWindow* parent, uint8 s "BIN files (*.bin)|*.bin", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (saveFileDialog.ShowModal() == wxID_CANCEL) + { this->EndModal(0); + return; + } m_filePath = saveFileDialog.GetPath(); @@ -723,6 +727,7 @@ CreateDimensionFigureDialog::CreateDimensionFigureDialog(wxWindow* parent) wxMessageDialog idError(this, "Error Converting Figure Number!", "Number Entered is Invalid"); idError.ShowModal(); this->EndModal(0); + return; } uint16 figNum = longFigNum & 0xFFFF; auto figure = nsyshid::g_dimensionstoypad.FindFigure(figNum); @@ -732,7 +737,10 @@ CreateDimensionFigureDialog::CreateDimensionFigureDialog(wxWindow* parent) "BIN files (*.bin)|*.bin", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (saveFileDialog.ShowModal() == wxID_CANCEL) + { this->EndModal(0); + return; + } m_filePath = saveFileDialog.GetPath(); diff --git a/src/gui/wxgui/components/wxGameList.cpp b/src/gui/wxgui/components/wxGameList.cpp index a1e5142d..68c9762d 100644 --- a/src/gui/wxgui/components/wxGameList.cpp +++ b/src/gui/wxgui/components/wxGameList.cpp @@ -833,8 +833,7 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event) if (!QueryIconForTitle(title_id, icon_large, icon_small)) break; auto icon = m_image_list_data.GetIcon(icon_large); - auto newClipboardData = wxBitmapDataObject(icon); - wxClipboard::Get()->SetData(&newClipboardData); + wxClipboard::Get()->SetData(new wxBitmapDataObject(icon)); wxClipboard::Get()->Close(); } break; diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp index 44973d8d..42b1db26 100644 --- a/src/input/InputManager.cpp +++ b/src/input/InputManager.cpp @@ -678,9 +678,12 @@ EmulatedControllerPtr InputManager::delete_controller(size_t player_index, bool { controller = {}; - std::error_code ec{}; - fs::remove(ActiveSettings::GetConfigPath("controllerProfiles/controller{}.xml", player_index), ec); - fs::remove(ActiveSettings::GetConfigPath("controllerProfiles/controller{}.txt", player_index), ec); + if(delete_profile) + { + std::error_code ec{}; + fs::remove(ActiveSettings::GetConfigPath("controllerProfiles/controller{}.xml", player_index), ec); + fs::remove(ActiveSettings::GetConfigPath("controllerProfiles/controller{}.txt", player_index), ec); + } return result; } @@ -840,7 +843,7 @@ std::optional InputManager::get_left_down_mouse_info(bool* is_pad) *is_pad = false; { - std::shared_lock lock(m_main_mouse.m_mutex); + std::unique_lock lock(m_main_mouse.m_mutex); if (std::exchange(m_main_mouse.left_down_toggle, false)) return m_main_mouse.position; @@ -849,7 +852,7 @@ std::optional InputManager::get_left_down_mouse_info(bool* is_pad) } { - std::shared_lock lock(m_main_touch.m_mutex); + std::unique_lock lock(m_main_touch.m_mutex); if (std::exchange(m_main_touch.left_down_toggle, false)) return m_main_touch.position; @@ -861,7 +864,7 @@ std::optional InputManager::get_left_down_mouse_info(bool* is_pad) *is_pad = true; { - std::shared_lock lock(m_pad_mouse.m_mutex); + std::unique_lock lock(m_pad_mouse.m_mutex); if (std::exchange(m_pad_mouse.left_down_toggle, false)) return m_pad_mouse.position; @@ -870,7 +873,7 @@ std::optional InputManager::get_left_down_mouse_info(bool* is_pad) } { - std::shared_lock lock(m_pad_touch.m_mutex); + std::unique_lock lock(m_pad_touch.m_mutex); if (std::exchange(m_pad_touch.left_down_toggle, false)) return m_pad_touch.position; @@ -887,7 +890,7 @@ std::optional InputManager::get_right_down_mouse_info(bool* is_pad) *is_pad = false; { - std::shared_lock lock(m_main_mouse.m_mutex); + std::unique_lock lock(m_main_mouse.m_mutex); if (std::exchange(m_main_mouse.right_down_toggle, false)) return m_main_mouse.position; @@ -896,7 +899,7 @@ std::optional InputManager::get_right_down_mouse_info(bool* is_pad) } { - std::shared_lock lock(m_main_touch.m_mutex); + std::unique_lock lock(m_main_touch.m_mutex); if (std::exchange(m_main_touch.right_down_toggle, false)) return m_main_touch.position; @@ -908,7 +911,7 @@ std::optional InputManager::get_right_down_mouse_info(bool* is_pad) *is_pad = true; { - std::shared_lock lock(m_pad_mouse.m_mutex); + std::unique_lock lock(m_pad_mouse.m_mutex); if (std::exchange(m_pad_mouse.right_down_toggle, false)) return m_pad_mouse.position; @@ -917,7 +920,7 @@ std::optional InputManager::get_right_down_mouse_info(bool* is_pad) } { - std::shared_lock lock(m_pad_touch.m_mutex); + std::unique_lock lock(m_pad_touch.m_mutex); if (std::exchange(m_pad_touch.right_down_toggle, false)) return m_pad_touch.position; diff --git a/src/input/api/SDL/SDLController.cpp b/src/input/api/SDL/SDLController.cpp index 4d181369..77b04172 100644 --- a/src/input/api/SDL/SDLController.cpp +++ b/src/input/api/SDL/SDLController.cpp @@ -60,7 +60,10 @@ bool SDLController::connect() SDL_JoystickID *gamepad_ids = SDL_GetGamepads(&gamepad_count); if (!gamepad_ids || index < 0 || index >= gamepad_count) + { + SDL_free(gamepad_ids); return false; + } m_diid = gamepad_ids[index]; SDL_free(gamepad_ids); diff --git a/src/input/api/Wiimote/WiimoteControllerProvider.cpp b/src/input/api/Wiimote/WiimoteControllerProvider.cpp index 76b8f63b..7fa90fbd 100644 --- a/src/input/api/Wiimote/WiimoteControllerProvider.cpp +++ b/src/input/api/Wiimote/WiimoteControllerProvider.cpp @@ -775,8 +775,9 @@ void WiimoteControllerProvider::rotate_ir(WiimoteState& wiimote_state) continue; // move to center, rotate and move back dot.pos -= 0.5f; - dot.pos.x = (dot.pos.x * cos) + (dot.pos.y * (-sin)); - dot.pos.y = (dot.pos.x * sin) + (dot.pos.y * cos); + auto tmp = dot.pos; + dot.pos.x = (tmp.x * cos) + (tmp.y * (-sin)); + dot.pos.y = (tmp.x * sin) + (tmp.y * cos); dot.pos += 0.5f; } } diff --git a/src/main.cpp b/src/main.cpp index fe7c3245..5372acdd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -106,7 +106,7 @@ void WindowsInitCwd() executablePath.resize(i); else executablePath.clear(); - SetCurrentDirectoryW(executablePath.c_str()); + SetCurrentDirectoryW(fs::path(executablePath).parent_path().c_str()); // set high priority SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); #endif diff --git a/src/util/crypto/aes128.cpp b/src/util/crypto/aes128.cpp index e11b4b44..f87494b7 100644 --- a/src/util/crypto/aes128.cpp +++ b/src/util/crypto/aes128.cpp @@ -800,6 +800,7 @@ void (*AES128_CBC_decrypt)(uint8* output, uint8* input, uint32 length, const uin // AES128-CTR encrypt/decrypt void AES128CTR_transform(uint8* data, sint32 length, uint8* key, uint8* nonceIv) { + cemu_assert_debug(length >= 0 && (length&15) == 0); // length must be a multiple of 16 for (sint32 i = 0; i < length; i += 16) { uint8* d = data + i;