diff --git a/src/core/memory_card.cpp b/src/core/memory_card.cpp index 6fdd3767f..9a6217479 100644 --- a/src/core/memory_card.cpp +++ b/src/core/memory_card.cpp @@ -24,6 +24,20 @@ MemoryCard::~MemoryCard() SaveIfChanged(false); } +std::string MemoryCard::SanitizeGameTitleForFileName(const std::string_view& name) +{ + std::string ret(name); + + const u32 len = static_cast(ret.length()); + for (u32 i = 0; i < len; i++) + { + if (ret[i] == '\\' || ret[i] == '/' || ret[i] == '?' || ret[i] == '*') + ret[i] = '_'; + } + + return ret; +} + TickCount MemoryCard::GetSaveDelayInTicks() { return System::GetTicksPerSecond() * SAVE_DELAY_IN_SECONDS; diff --git a/src/core/memory_card.h b/src/core/memory_card.h index c8cd6f014..f1257f6bf 100644 --- a/src/core/memory_card.h +++ b/src/core/memory_card.h @@ -15,6 +15,8 @@ public: MemoryCard(); ~MemoryCard(); + static std::string SanitizeGameTitleForFileName(const std::string_view& name); + static std::unique_ptr Create(); static std::unique_ptr Open(std::string_view filename); diff --git a/src/core/system.cpp b/src/core/system.cpp index 01210d588..510f3886d 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1815,7 +1815,8 @@ void UpdateMemoryCards() } else { - card = MemoryCard::Open(g_host_interface->GetGameMemoryCardPath(s_running_game_title.c_str(), i)); + card = MemoryCard::Open(g_host_interface->GetGameMemoryCardPath( + MemoryCard::SanitizeGameTitleForFileName(s_running_game_title).c_str(), i)); } } break; diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index 6a659699e..e228170e7 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -8,6 +8,7 @@ #include "core/cheats.h" #include "core/controller.h" #include "core/gpu.h" +#include "core/memory_card.h" #include "core/system.h" #include "frontend-common/fullscreen_ui.h" #include "frontend-common/game_list.h" @@ -1045,7 +1046,8 @@ void QtHostInterface::populateGameListContextMenu(const GameListEntry* entry, QW paths[i] = QString::fromStdString(GetGameMemoryCardPath(entry->code.c_str(), i)); break; case MemoryCardType::PerGameTitle: - paths[i] = QString::fromStdString(GetGameMemoryCardPath(entry->title.c_str(), i)); + paths[i] = QString::fromStdString( + GetGameMemoryCardPath(MemoryCard::SanitizeGameTitleForFileName(entry->title).c_str(), i)); break; default: break;