diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index f796fce8b6..9d1ef32547 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -112,6 +112,7 @@ std::string SanitizeString(std::string_view input, StringRestriction restriction // First, remove any chars not in A-Za-z0-9_-. This will effectively get rid of any Unicode char, emojis etc too. std::string sanitized; sanitized.reserve(input.size()); + bool lastWasLineBreak = false; for (auto c : input) { switch (restriction) { case StringRestriction::None: @@ -125,6 +126,17 @@ std::string SanitizeString(std::string_view input, StringRestriction restriction sanitized.push_back(c); } break; + case StringRestriction::NoLineBreaksOrSpecials: + if (c >= 32) { + sanitized.push_back(c); + lastWasLineBreak = false; + } else if (c == 10 || c == 13) { + // Collapse line breaks/feeds to single spaces. + if (!lastWasLineBreak) { + sanitized.push_back(' '); + } + lastWasLineBreak = true; + } } } diff --git a/Common/StringUtils.h b/Common/StringUtils.h index d0f6fadc5f..57ceef547b 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -79,6 +79,7 @@ bool containsNoCase(std::string_view haystack, std::string_view needle); enum class StringRestriction { None, AlphaNumDashUnderscore, // Used for infrastructure usernames + NoLineBreaksOrSpecials, // Used for savedata UI. Removes line breaks, backslashes and similar. }; std::string SanitizeString(std::string_view username, StringRestriction restriction, int minLength, int maxLength); diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index c95ca373ba..0716f4e022 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -698,7 +698,10 @@ UI::EventReturn SavedataScreen::OnSavedataButtonClick(UI::EventParams &e) { if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) { return UI::EVENT_DONE; } - SavedataPopupScreen *popupScreen = new SavedataPopupScreen(gamePath_, Path(e.s), ginfo->GetTitle()); + + // Sanitize the title. + std::string title = SanitizeString(ginfo->GetTitle(), StringRestriction::NoLineBreaksOrSpecials, 0, 200); + SavedataPopupScreen *popupScreen = new SavedataPopupScreen(gamePath_, Path(e.s), title); if (e.v) { popupScreen->SetPopupOrigin(e.v); }