diff options
author | Martin Reddy <lynx@lindenlab.com> | 2009-09-22 18:00:16 +0000 |
---|---|---|
committer | Martin Reddy <lynx@lindenlab.com> | 2009-09-22 18:00:16 +0000 |
commit | 12762053e5aff372a9f8d473c71aa81e805bb474 (patch) | |
tree | c2c29e3b178cc9c51b99bd94d2f478e96d8a7d30 | |
parent | be41bf82c6325fc45c7c6474645f384479e27091 (diff) |
EXT-944 EXT-1026: converted the LLUrlRegistry::findUrl() method to
work on an LLWString instead of a std::string, so that we don't have
to worry about character offsets for variable-length-encoded UTF-8
strings.
This was causing crashes whenever we would try to show a textbox with
a URL and foreign characters (> 1 byte chars). Damn, I suck!
-rw-r--r-- | indra/llui/lltextbase.cpp | 2 | ||||
-rw-r--r-- | indra/llui/lltextbox.cpp | 4 | ||||
-rw-r--r-- | indra/llui/lltexteditor.cpp | 11 | ||||
-rw-r--r-- | indra/llui/llurlaction.cpp | 4 | ||||
-rw-r--r-- | indra/llui/llurlentry.cpp | 44 | ||||
-rw-r--r-- | indra/llui/llurlentry.h | 4 | ||||
-rw-r--r-- | indra/llui/llurlregistry.cpp | 12 | ||||
-rw-r--r-- | indra/llui/llurlregistry.h | 3 | ||||
-rw-r--r-- | indra/llui/tests/llurlentry_test.cpp | 34 |
9 files changed, 61 insertions, 57 deletions
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index cb60b4fe36..325c7a8104 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -429,7 +429,7 @@ LLContextMenu *LLTextBase::createUrlContextMenu(const std::string &in_url) // work out the XUI menu file to use for this url LLUrlMatch match; std::string url = in_url; - if (! LLUrlRegistry::instance().findUrl(url, match)) + if (! LLUrlRegistry::instance().findUrl(utf8str_to_wstring(url), match)) { return NULL; } diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 810626268f..3cde42d75c 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -297,7 +297,7 @@ LLWString LLTextBox::getWrappedText(const LLStringExplicit& in_text, F32 max_wid // find the next Url in the text string LLUrlMatch match; - while ( LLUrlRegistry::instance().findUrl(wstring_to_utf8str(wtext), match)) + while ( LLUrlRegistry::instance().findUrl(wtext, match)) { S32 start = match.getStart(); S32 end = match.getEnd() + 1; @@ -573,7 +573,7 @@ void LLTextBox::updateDisplayTextAndSegments() LLWString text = mText.getWString(); // find the next Url in the text string - while ( LLUrlRegistry::instance().findUrl(wstring_to_utf8str(text), match, + while ( LLUrlRegistry::instance().findUrl(text, match, boost::bind(&LLTextBox::onUrlLabelUpdated, this, _1, _2)) ) { // work out the char offset for the start/end of the url diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 983777b747..f7680a0a2b 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -3525,7 +3525,7 @@ void LLTextEditor::appendStyledText(const std::string &new_text, S32 start=0,end=0; LLUrlMatch match; - std::string text = new_text; + LLWString text = utf8str_to_wstring(new_text); while ( LLUrlRegistry::instance().findUrl(text, match, boost::bind(&LLTextEditor::onUrlLabelUpdated, this, _1, _2)) ) { @@ -3549,8 +3549,8 @@ void LLTextEditor::appendStyledText(const std::string &new_text, { part = (S32)LLTextParser::MIDDLE; } - std::string subtext=text.substr(0,start); - appendHighlightedText(subtext,allow_undo, prepend_newline, part, style_params); + std::string subtext = wstring_to_utf8str(text.substr(0,start)); + appendHighlightedText(subtext, allow_undo, prepend_newline, part, style_params); prepend_newline = false; } @@ -3595,7 +3595,8 @@ void LLTextEditor::appendStyledText(const std::string &new_text, } } if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END; - if (end < (S32)text.length()) appendHighlightedText(text,allow_undo, prepend_newline, part, style_params); + if (end < (S32)text.length()) appendHighlightedText(wstring_to_utf8str(text), allow_undo, + prepend_newline, part, style_params); } else { @@ -4137,7 +4138,7 @@ void LLTextEditor::updateLinkSegments() LLUrlMatch match; LLStyleSP style = static_cast<LLStyleSP>(segment->getStyle()); std::string url_label = getText().substr(segment->getStart(), segment->getEnd()-segment->getStart()); - if (LLUrlRegistry::instance().findUrl(url_label, match)) + if (LLUrlRegistry::instance().findUrl(utf8str_to_wstring(url_label), match)) { LLStringUtil::trim(url_label); style->setLinkHREF(url_label); diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 3b689b93c0..7721d0e502 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -112,7 +112,7 @@ void LLUrlAction::clickAction(std::string url) void LLUrlAction::teleportToLocation(std::string url) { LLUrlMatch match; - if (LLUrlRegistry::instance().findUrl(url, match)) + if (LLUrlRegistry::instance().findUrl(utf8str_to_wstring(url), match)) { if (! match.getLocation().empty()) { @@ -129,7 +129,7 @@ void LLUrlAction::copyURLToClipboard(std::string url) void LLUrlAction::copyLabelToClipboard(std::string url) { LLUrlMatch match; - if (LLUrlRegistry::instance().findUrl(url, match)) + if (LLUrlRegistry::instance().findUrl(utf8str_to_wstring(url), match)) { LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel())); } diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index c20212c375..e4bcc27428 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -148,8 +148,8 @@ void LLUrlEntryBase::callObservers(const std::string &id, const std::string &lab // LLUrlEntryHTTP::LLUrlEntryHTTP() { - mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_http.xml"; mTooltip = LLTrans::getString("TooltipHttpUrl"); //mIcon = "gear.tga"; @@ -166,8 +166,8 @@ std::string LLUrlEntryHTTP::getLabel(const std::string &url, const LLUrlLabelCal // LLUrlEntryHTTPLabel::LLUrlEntryHTTPLabel() { - mPattern = boost::regex("\\[https?://\\S+[ \t]+[^\\]]+\\]", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"\\[https?://\\S+[ \t]+[^\\]]+\\]", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_http.xml"; mTooltip = LLTrans::getString("TooltipHttpUrl"); } @@ -188,8 +188,8 @@ std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) LLUrlEntrySLURL::LLUrlEntrySLURL() { // see http://slurl.com/about.php for details on the SLURL format - mPattern = boost::regex("http://slurl.com/secondlife/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"http://slurl.com/secondlife/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); } @@ -260,8 +260,8 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const // LLUrlEntryAgent::LLUrlEntryAgent() { - mPattern = boost::regex("secondlife:///app/agent/[\\da-f-]+/about", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"secondlife:///app/agent/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_agent.xml"; mTooltip = LLTrans::getString("TooltipAgentUrl"); } @@ -302,8 +302,8 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa // LLUrlEntryGroup::LLUrlEntryGroup() { - mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/about", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"secondlife:///app/group/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_group.xml"; mTooltip = LLTrans::getString("TooltipGroupUrl"); } @@ -344,8 +344,8 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa /// LLUrlEntryParcel::LLUrlEntryParcel() { - mPattern = boost::regex("secondlife:///app/parcel/[\\da-f-]+/about", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"secondlife:///app/parcel/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_parcel.xml"; mTooltip = LLTrans::getString("TooltipParcelUrl"); } @@ -360,8 +360,8 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC // LLUrlEntryPlace::LLUrlEntryPlace() { - mPattern = boost::regex("secondlife://\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"secondlife://\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); } @@ -416,8 +416,8 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const // LLUrlEntryTeleport::LLUrlEntryTeleport() { - mPattern = boost::regex("secondlife:///app/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"secondlife:///app/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_teleport.xml"; mTooltip = LLTrans::getString("TooltipTeleportUrl"); } @@ -488,8 +488,8 @@ std::string LLUrlEntryTeleport::getLocation(const std::string &url) const /// LLUrlEntryObjectIM::LLUrlEntryObjectIM() { - mPattern = boost::regex("secondlife:///app/objectim/[\\da-f-]+\\??\\S*", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"secondlife:///app/objectim/[\\da-f-]+\\??\\S*", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_objectim.xml"; mTooltip = LLTrans::getString("TooltipObjectIMUrl"); } @@ -532,8 +532,8 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const // LLUrlEntrySL::LLUrlEntrySL() { - mPattern = boost::regex("secondlife://(\\w+)?(:\\d+)?/\\S+", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"secondlife://(\\w+)?(:\\d+)?/\\S+", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slapp.xml"; mTooltip = LLTrans::getString("TooltipSLAPP"); } @@ -549,8 +549,8 @@ std::string LLUrlEntrySL::getLabel(const std::string &url, const LLUrlLabelCallb // LLUrlEntrySLLabel::LLUrlEntrySLLabel() { - mPattern = boost::regex("\\[secondlife://\\S+[ \t]+[^\\]]+\\]", - boost::regex::perl|boost::regex::icase); + mPattern = boost::wregex(L"\\[secondlife://\\S+[ \t]+[^\\]]+\\]", + boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slapp.xml"; mTooltip = LLTrans::getString("TooltipSLAPP"); } diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 54053872df..36758566ed 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -68,7 +68,7 @@ public: virtual ~LLUrlEntryBase(); /// Return the regex pattern that matches this Url - boost::regex getPattern() const { return mPattern; } + boost::wregex getPattern() const { return mPattern; } /// Return the url from a string that matched the regex virtual std::string getUrl(const std::string &string); @@ -102,7 +102,7 @@ protected: LLUrlLabelSignal *signal; } LLUrlEntryObserver; - boost::regex mPattern; + boost::wregex mPattern; std::string mIcon; std::string mMenuName; std::string mTooltip; diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index f2d340deb7..2ea3c59e03 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -75,9 +75,9 @@ void LLUrlRegistry::registerUrl(LLUrlEntryBase *url) } } -static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &end) +static bool matchRegex(const wchar_t *text, boost::wregex regex, U32 &start, U32 &end) { - boost::cmatch result; + boost::wcmatch result; bool found; // regex_search can potentially throw an exception, so check for it @@ -107,7 +107,7 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en } // ignore a terminating ')' when Url contains no matching '(' // see DEV-19842 for details - else if (text[end] == ')' && std::string(text+start, end-start).find('(') == std::string::npos) + else if (text[end] == ')' && LLWString(text+start, end-start).find('(') == std::string::npos) { end--; } @@ -115,10 +115,10 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en return true; } -bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) +bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) { // avoid costly regexes if there is clearly no URL in the text - if (text.find("://") == std::string::npos) + if (text.find(L"://") == std::string::npos) { return false; } @@ -149,7 +149,7 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL if (match_entry) { // fill in the LLUrlMatch object and return it - std::string url = text.substr(match_start, match_end - match_start + 1); + std::string url = wstring_to_utf8str(text.substr(match_start, match_end - match_start + 1)); match.setValues(match_start, match_end, match_entry->getUrl(url), match_entry->getLabel(url, cb), diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h index 84b033036c..bf5257d630 100644 --- a/indra/llui/llurlregistry.h +++ b/indra/llui/llurlregistry.h @@ -37,6 +37,7 @@ #include "llurlentry.h" #include "llurlmatch.h" #include "llsingleton.h" +#include "llstring.h" #include <string> #include <vector> @@ -74,7 +75,7 @@ public: /// get the next Url in an input string, starting at a given character offset /// your callback is invoked if the matched Url's label changes in the future - bool findUrl(const std::string &text, LLUrlMatch &match, + bool findUrl(const LLWString &text, LLUrlMatch &match, const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback); private: diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 1e7a0f7f2c..89a80f1e73 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -44,17 +44,19 @@ namespace namespace tut { - void testRegex(const std::string &testname, boost::regex regex, + void testRegex(const std::string &testname, boost::wregex regex, const char *text, const std::string &expected) { std::string url = ""; - boost::cmatch result; - bool found = boost::regex_search(text, result, regex); + boost::wcmatch result; + LLWString wtext = utf8str_to_wstring(text); + const wchar_t *wctext = wtext.c_str(); + bool found = boost::regex_search(wctext, result, regex); if (found) { - S32 start = static_cast<U32>(result[0].first - text); - S32 end = static_cast<U32>(result[0].second - text); - url = std::string(text+start, end-start); + S32 start = static_cast<U32>(result[0].first - wctext); + S32 end = static_cast<U32>(result[0].second - wctext); + url = wstring_to_utf8str(wtext.substr(start, end-start)); } ensure_equals(testname, url, expected); } @@ -66,7 +68,7 @@ namespace tut // test LLUrlEntryHTTP - standard http Urls // LLUrlEntryHTTP url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("no valid url", r, "htp://slurl.com/", @@ -145,7 +147,7 @@ namespace tut // test LLUrlEntryHTTPLabel - wiki-style http Urls with labels // LLUrlEntryHTTPLabel url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("invalid wiki url [1]", r, "[http://www.example.org]", @@ -187,7 +189,7 @@ namespace tut // test LLUrlEntrySLURL - second life URLs // LLUrlEntrySLURL url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("no valid slurl [1]", r, "htp://slurl.com/secondlife/Ahern/50/50/50/", @@ -259,7 +261,7 @@ namespace tut // test LLUrlEntryAgent - secondlife://app/agent Urls // LLUrlEntryAgent url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("Invalid Agent Url", r, "secondlife:///app/agent/0e346d8b-4433-4d66-XXXX-fd37083abc4c/about", @@ -285,7 +287,7 @@ namespace tut // test LLUrlEntryGroup - secondlife://app/group Urls // LLUrlEntryGroup url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("Invalid Group Url", r, "secondlife:///app/group/00005ff3-4044-c79f-XXXX-fb28ae0df991/about", @@ -311,7 +313,7 @@ namespace tut // test LLUrlEntryPlace - secondlife://<location> URLs // LLUrlEntryPlace url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("no valid slurl [1]", r, "secondlife://Ahern/FOO/50/", @@ -359,7 +361,7 @@ namespace tut // test LLUrlEntryParcel - secondlife://app/parcel Urls // LLUrlEntryParcel url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("Invalid Classified Url", r, "secondlife:///app/parcel/0000060e-4b39-e00b-XXXX-d98b1934e3a8/about", @@ -384,7 +386,7 @@ namespace tut // test LLUrlEntryTeleport - secondlife://app/teleport URLs // LLUrlEntryTeleport url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("no valid teleport [1]", r, "http://slurl.com/secondlife/Ahern/50/50/50/", @@ -460,7 +462,7 @@ namespace tut // test LLUrlEntrySL - general secondlife:// URLs // LLUrlEntrySL url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("no valid slapp [1]", r, "http:///app/", @@ -498,7 +500,7 @@ namespace tut // test LLUrlEntrySLLabel - general secondlife:// URLs with labels // LLUrlEntrySLLabel url; - boost::regex r = url.getPattern(); + boost::wregex r = url.getPattern(); testRegex("invalid wiki url [1]", r, "[secondlife:///app/]", |