diff --git a/Source/Core/Common/StringUtil.cpp b/Source/Core/Common/StringUtil.cpp index 9c57bf944a..77fcd731a1 100644 --- a/Source/Core/Common/StringUtil.cpp +++ b/Source/Core/Common/StringUtil.cpp @@ -5,6 +5,7 @@ #include "Common/StringUtil.h" #include +#include #include #include #include @@ -664,3 +665,21 @@ std::vector CommandLineToUtf8Argv(const wchar_t* command_line) return argv; } #endif + +std::string GetEscapedHtml(std::string html) +{ + static constexpr std::array, 5> replacements{{ + // Escape ampersand first to avoid escaping the ampersands in other replacements + {{"&", "&"}}, + {{"<", "<"}}, + {{">", ">"}}, + {{"\"", """}}, + {{"'", "'"}}, + }}; + + for (const auto& [unescaped, escaped] : replacements) + { + html = ReplaceAll(html, unescaped, escaped); + } + return html; +} diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index ada0eee3bd..6b7bd14361 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -242,3 +242,5 @@ inline bool IsPrintableCharacter(char c) #ifdef _WIN32 std::vector CommandLineToUtf8Argv(const wchar_t* command_line); #endif + +std::string GetEscapedHtml(std::string html); diff --git a/Source/Core/UICommon/AutoUpdate.cpp b/Source/Core/UICommon/AutoUpdate.cpp index 5808d3ac2e..f5898f592b 100644 --- a/Source/Core/UICommon/AutoUpdate.cpp +++ b/Source/Core/UICommon/AutoUpdate.cpp @@ -109,10 +109,10 @@ std::string GenerateChangelog(const picojson::array& versions) { changelog += ver_obj["shortrev"].get(); } - + const std::string escaped_description = + GetEscapedHtml(ver_obj["short_descr"].get()); changelog += " by () + "\">" + - ver_obj["author"].get() + " — " + - ver_obj["short_descr"].get(); + ver_obj["author"].get() + " — " + escaped_description; } else { diff --git a/Source/UnitTests/Common/StringUtilTest.cpp b/Source/UnitTests/Common/StringUtilTest.cpp index b9b186c131..fe837be455 100644 --- a/Source/UnitTests/Common/StringUtilTest.cpp +++ b/Source/UnitTests/Common/StringUtilTest.cpp @@ -105,3 +105,13 @@ TEST(StringUtil, ToString_TryParse_Roundtrip) DoRoundTripTest({0.0f, 1.0f, -1.0f, -0.5f, 0.5f, -1e-3f, 1e-3f, 1e3f, -1e3f}); DoRoundTripTest({0.0, 1.0, -1.0, -0.5, 0.5, -1e-3, 1e-3, 1e3, -1e3}); } + +TEST(StringUtil, GetEscapedHtml) +{ + static constexpr auto no_escape_needed = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "!@#$%^*()-_=+,./?;:[]{}| \\\t\n"; + EXPECT_EQ(GetEscapedHtml(no_escape_needed), no_escape_needed); + EXPECT_EQ(GetEscapedHtml("&<>'\""), "&<>'""); + EXPECT_EQ(GetEscapedHtml("&&&"), "&&&"); +}