diff --git a/src/jdlib/miscutil.cpp b/src/jdlib/miscutil.cpp index ffa5d7eb3..6fcd95eb1 100644 --- a/src/jdlib/miscutil.cpp +++ b/src/jdlib/miscutil.cpp @@ -837,12 +837,13 @@ std::string MISC::regex_unescape( const std::string& str ) } -// -// HTMLエスケープ -// -// include_url : URL中でもエスケープする( デフォルト = true ) -// -std::string MISC::html_escape( const std::string& str, const bool include_url ) +/** @brief HTMLで特別な意味を持つ記号(& " < >)を文字実体参照へエスケープする + * + * @param[in] str エスケープする入力 + * @param[in] completely URL中でもエスケープする( デフォルト = true ) + * @return エスケープした結果 + */ +std::string MISC::html_escape( const std::string& str, const bool completely ) { if( str.empty() ) return str; @@ -856,7 +857,7 @@ std::string MISC::html_escape( const std::string& str, const bool include_url ) char tmpchar = str.c_str()[ pos ]; // URL中はエスケープしない場合 - if( ! include_url ) + if( ! completely ) { // URLとして扱うかどうか // エスケープには影響がないので loose_url としておく @@ -875,17 +876,9 @@ std::string MISC::html_escape( const std::string& str, const bool include_url ) } } - // include_url = false でURL中ならエスケープしない + // completely = false でURL中ならエスケープしない if( is_url ) str_out += tmpchar; - else if( tmpchar == '&' ) - { - const int bufsize = 64; - char out_char[ bufsize ]; - int n_in, n_out; - const int type = DBTREE::decode_char( str.c_str() + pos, n_in, out_char, n_out, false ); - if( type == DBTREE::NODE_NONE ) str_out += "&"; - else str_out += tmpchar; - } + else if( tmpchar == '&' ) str_out += "&"; else if( tmpchar == '\"' ) str_out += """; else if( tmpchar == '<' ) str_out += "<"; else if( tmpchar == '>' ) str_out += ">"; diff --git a/src/jdlib/miscutil.h b/src/jdlib/miscutil.h index 985beb882..7ab6c23ca 100644 --- a/src/jdlib/miscutil.h +++ b/src/jdlib/miscutil.h @@ -138,9 +138,9 @@ namespace MISC // 正規表現のメタ文字をアンエスケープ std::string regex_unescape( const std::string& str ); - // HTMLエスケープ - // include_url : URL中でもエスケープする( デフォルト = true ) - std::string html_escape( const std::string& str, const bool include_url = true ); + // HTMLで特別な意味を持つ記号(& " < >)を文字実体参照へエスケープする + // completely : URL中でもエスケープする( デフォルト = true ) + std::string html_escape( const std::string& str, const bool completely = true ); // HTMLアンエスケープ std::string html_unescape( const std::string& str ); diff --git a/src/message/messageviewbase.cpp b/src/message/messageviewbase.cpp index 2912864bd..8900e09d2 100644 --- a/src/message/messageviewbase.cpp +++ b/src/message/messageviewbase.cpp @@ -880,8 +880,14 @@ void MessageViewBase::slot_switch_page( Gtk::Widget*, guint page ) // URLを除外してエスケープ const bool include_url = false; std::string msg; - if( m_text_message ) msg = MISC::html_escape( m_text_message->get_text(), include_url ); - msg = MISC::replace_str( msg, "\n", "
" ); + if( m_text_message ) { + msg = m_text_message->get_text(); + + constexpr bool completely = true; + msg = MISC::chref_decode( msg, completely ); + msg = MISC::html_escape( msg, include_url ); + msg = MISC::replace_str( msg, "\n", "
" ); + } std::stringstream ss; diff --git a/test/gtest_jdlib_miscutil.cpp b/test/gtest_jdlib_miscutil.cpp index d897b8916..807fe9392 100644 --- a/test/gtest_jdlib_miscutil.cpp +++ b/test/gtest_jdlib_miscutil.cpp @@ -329,6 +329,53 @@ TEST_F(ReplaceNewlinesToStrTest, replace_crlf) } +class HtmlEscapeTest : public ::testing::Test {}; + +TEST_F(HtmlEscapeTest, empty_data) +{ + EXPECT_EQ( "", MISC::html_escape( "", false ) ); + EXPECT_EQ( "", MISC::html_escape( "", true ) ); +} + +TEST_F(HtmlEscapeTest, not_escape) +{ + EXPECT_EQ( "hello world", MISC::html_escape( "hello world", false ) ); + EXPECT_EQ( "hello world", MISC::html_escape( "hello world", true ) ); +} + +TEST_F(HtmlEscapeTest, escape_amp) +{ + EXPECT_EQ( "hello&world", MISC::html_escape( "hello&world", false ) ); + EXPECT_EQ( "hello&world", MISC::html_escape( "hello&world", true ) ); +} + +TEST_F(HtmlEscapeTest, escape_quot) +{ + EXPECT_EQ( "hello"world", MISC::html_escape( "hello\"world", false ) ); + EXPECT_EQ( "hello"world", MISC::html_escape( "hello\"world", true ) ); +} + +TEST_F(HtmlEscapeTest, escape_lt) +{ + EXPECT_EQ( "hello<world", MISC::html_escape( "helloworld", false ) ); + EXPECT_EQ( "hello>world", MISC::html_escape( "hello>world", true ) ); +} + +TEST_F(HtmlEscapeTest, completely) +{ + // URLを含むテキスト + const std::string input = "& https://foobar.test/?a=b&c=d& &"; + EXPECT_EQ( "& https://foobar.test/?a=b&c=d& &", MISC::html_escape( input, true ) ); + EXPECT_EQ( "& https://foobar.test/?a=b&c=d& &", MISC::html_escape( input, false ) ); +} + + class IsUrlSchemeTest : public ::testing::Test {}; TEST_F(IsUrlSchemeTest, url_none)