diff options
author | Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> | 2024-03-12 18:30:33 +0100 |
---|---|---|
committer | Guru <alexandrgproductengine@lindenlab.com> | 2024-03-18 21:19:57 +0100 |
commit | 15734c19783fc5fc38e5c1cba485d756285161e0 (patch) | |
tree | 00f2c0586781b2abe32baa12ee2bb283b2839fef /indra/llui/lltextvalidate.cpp | |
parent | b40ff113c50afc1e012183928e94b2c86252a61f (diff) |
viewer#961 Add a notification appearing when user tries to insert a disallowed character
Diffstat (limited to 'indra/llui/lltextvalidate.cpp')
-rw-r--r-- | indra/llui/lltextvalidate.cpp | 764 |
1 files changed, 443 insertions, 321 deletions
diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index bfe0a5bb5d..9e27ed6232 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -27,330 +27,452 @@ // Text editor widget to let users enter a single line. #include "linden_common.h" - + #include "lltextvalidate.h" + +#include "llnotificationsutil.h" +#include "lltrans.h" + #include "llresmgr.h" // for LLLocale namespace LLTextValidate { - void ValidateTextNamedFuncs::declareValues() - { - declare("ascii", validateASCII); - declare("float", validateFloat); - declare("int", validateInt); - declare("positive_s32", validatePositiveS32); - declare("non_negative_s32", validateNonNegativeS32); - declare("alpha_num", validateAlphaNum); - declare("alpha_num_space", validateAlphaNumSpace); - declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe); - declare("ascii_printable_no_space", validateASCIIPrintableNoSpace); - declare("ascii_with_newline", validateASCIIWithNewLine); - } - - // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. - // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for - // the simple reasons that intermediate states may be invalid even if the final result is valid. - // - bool validateFloat(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - bool success = TRUE; - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); - S32 len = trimmed.length(); - if( 0 < len ) - { - // May be a comma or period, depending on the locale - llwchar decimal_point = (llwchar)LLResMgr::getInstance()->getDecimalPoint(); - - S32 i = 0; - - // First character can be a negative sign - if( '-' == trimmed[0] ) - { - i++; - } - - for( ; i < len; i++ ) - { - if( (decimal_point != trimmed[i] ) && !LLStringOps::isDigit( trimmed[i] ) ) - { - success = FALSE; - break; - } - } - } - - return success; - } - - // Limits what characters can be used to [1234567890-] with [-] only valid in the first position. - // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for - // the simple reasons that intermediate states may be invalid even if the final result is valid. - // - bool validateInt(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - bool success = TRUE; - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); - S32 len = trimmed.length(); - if( 0 < len ) - { - S32 i = 0; - - // First character can be a negative sign - if( '-' == trimmed[0] ) - { - i++; - } - - for( ; i < len; i++ ) - { - if( !LLStringOps::isDigit( trimmed[i] ) ) - { - success = FALSE; - break; - } - } - } - - return success; - } - - bool validatePositiveS32(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); - S32 len = trimmed.length(); - bool success = TRUE; - if(0 < len) - { - if(('-' == trimmed[0]) || ('0' == trimmed[0])) - { - success = FALSE; - } - S32 i = 0; - while(success && (i < len)) - { - if(!LLStringOps::isDigit(trimmed[i++])) - { - success = FALSE; - } - } - } - if (success) - { - S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10); - if (val <= 0) - { - success = FALSE; - } - } - return success; - } - - bool validateNonNegativeS32(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - LLWString trimmed = str; - LLWStringUtil::trim(trimmed); - S32 len = trimmed.length(); - bool success = TRUE; - if(0 < len) - { - if('-' == trimmed[0]) - { - success = FALSE; - } - S32 i = 0; - while(success && (i < len)) - { - if(!LLStringOps::isDigit(trimmed[i++])) - { - success = FALSE; - } - } - } - if (success) - { - S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10); - if (val < 0) - { - success = FALSE; - } - } - return success; - } - - bool validateNonNegativeS32NoSpace(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - LLWString test_str = str; - S32 len = test_str.length(); - bool success = TRUE; - if(0 < len) - { - if('-' == test_str[0]) - { - success = FALSE; - } - S32 i = 0; - while(success && (i < len)) - { - if(!LLStringOps::isDigit(test_str[i]) || LLStringOps::isSpace(test_str[i++])) - { - success = FALSE; - } - } - } - if (success) - { - S32 val = strtol(wstring_to_utf8str(test_str).c_str(), NULL, 10); - if (val < 0) - { - success = FALSE; - } - } - return success; - } - - bool validateAlphaNum(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - bool rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - if( !LLStringOps::isAlnum((char)str[len]) ) - { - rv = FALSE; - break; - } - } - return rv; - } - - bool validateAlphaNumSpace(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - bool rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - if(!(LLStringOps::isAlnum((char)str[len]) || (' ' == str[len]))) - { - rv = FALSE; - break; - } - } - return rv; - } - - // Used for most names of things stored on the server, due to old file-formats - // that used the pipe (|) for multiline text storage. Examples include - // inventory item names, parcel names, object names, etc. - bool validateASCIIPrintableNoPipe(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - llwchar wc = str[len]; - if (wc < 0x20 - || wc > 0x7f - || wc == '|') - { - rv = FALSE; - break; - } - if(!(wc == ' ' - || LLStringOps::isAlnum((char)wc) - || LLStringOps::isPunct((char)wc) ) ) - { - rv = FALSE; - break; - } - } - return rv; - } - - - // Used for avatar names - bool validateASCIIPrintableNoSpace(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - llwchar wc = str[len]; - if (wc < 0x20 - || wc > 0x7f - || LLStringOps::isSpace(wc)) - { - rv = FALSE; - break; - } - if( !(LLStringOps::isAlnum((char)str[len]) || - LLStringOps::isPunct((char)str[len]) ) ) - { - rv = FALSE; - break; - } - } - return rv; - } - - bool validateASCII(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - while(len--) - { - if (str[len] < 0x20 || str[len] > 0x7f) - { - rv = FALSE; - break; - } - } - return rv; - } - - bool validateASCIINoLeadingSpace(const LLWString &str) - { - if (LLStringOps::isSpace(str[0])) - { - return FALSE; - } - return validateASCII(str); - } - - // Used for multiline text stored on the server. - // Example is landmark description in Places SP. - bool validateASCIIWithNewLine(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - while(len--) - { - if ((str[len] < 0x20 && str[len] != 0xA) || str[len] > 0x7f) - { - rv = FALSE; - break; - } - } - return rv; - } + +static S32 strtol(const std::string& str) { return ::strtol(str.c_str(), NULL, 10); } +static S32 strtol(const LLWString& str) { return ::strtol(wstring_to_utf8str(str).c_str(), NULL, 10); } + +static LLSD llsd(const std::string& str) { return LLSD(str); } +static LLSD llsd(const LLWString& str) { return LLSD(wstring_to_utf8str(str)); } +template <class CHAR> +LLSD llsd(CHAR ch) { return llsd(std::basic_string<CHAR>(1, ch)); } + +void ValidatorImpl::setLastErrorShowTime() +{ + mLastErrorShowTime = (U32Seconds)LLTimer::getTotalTime(); +} + +void Validator::showLastErrorUsingTimeout(U32 timeout) +{ + if (mImpl && (U32Seconds)LLTimer::getTotalTime() >= mImpl->getLastErrorShowTime() + timeout) + { + mImpl->setLastErrorShowTime(); + std::string reason = LLTrans::getString(mImpl->getLastErrorName(), mImpl->getLastErrorValues()); + LLNotificationsUtil::add("InvalidKeystroke", LLSD().with("REASON", reason)); + } } + +// Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. +// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for +// the simple reasons that intermediate states may be invalid even if the final result is valid. +class ValidatorFloat : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR> &str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + // May be a comma or period, depending on the locale + CHAR decimal_point = LLResMgr::getInstance()->getDecimalPoint(); + + S32 i = 0; + + // First character can be a negative sign + if ('-' == trimmed.front()) + { + i++; + } + + for (; i < len; i++) + { + CHAR ch = trimmed[i]; + if ((decimal_point != ch) && !LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigitOrDot", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorFloatImpl; +Validator validateFloat(validatorFloatImpl); + +// Limits what characters can be used to [1234567890-] with [-] only valid in the first position. +// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for +// the simple reasons that intermediate states may be invalid even if the final result is valid. +class ValidatorInt : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR> &str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + S32 i = 0; + + // First character can be a negative sign + if ('-' == trimmed.front()) + { + i++; + } + + for (; i < len; i++) + { + CHAR ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorIntImpl; +Validator validateInt(validatorIntImpl); + +class ValidatorPositiveS32 : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + CHAR ch = trimmed.front(); + + if (('-' == ch) || ('0' == ch)) + { + return setError("Validator_ShouldNotBeMinusOrZero", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(trimmed); + if (val <= 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorPositiveS32Impl; +Validator validatePositiveS32(validatorPositiveS32Impl); + +class ValidatorNonNegativeS32 : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + CHAR ch = trimmed.front(); + + if ('-' == ch) + { + return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(trimmed); + if (val < 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorNonNegativeS32Impl; +Validator validateNonNegativeS32(validatorNonNegativeS32Impl); + +class ValidatorNonNegativeS32NoSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> test_str = str; + S32 len = test_str.length(); + if (0 < len) + { + CHAR ch = test_str.front(); + + if ('-' == ch) + { + return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = test_str[i]; + if (!LLStringOps::isDigit(ch) || LLStringOps::isSpace(ch)) + { + return setError("Validator_ShouldBeDigitNotSpace", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(test_str); + if (val < 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(test_str))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorNonNegativeS32NoSpaceImpl; +Validator validateNonNegativeS32NoSpace(validatorNonNegativeS32NoSpaceImpl); + +class ValidatorAlphaNum : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (!LLStringOps::isAlnum(ch)) + { + return setError("Validator_ShouldBeDigitOrAlpha", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorAlphaNumImpl; +Validator validateAlphaNum(validatorAlphaNumImpl); + +class ValidatorAlphaNumSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (!LLStringOps::isAlnum(ch) && (' ' != ch)) + { + return setError("Validator_ShouldBeDigitOrAlphaOrSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorAlphaNumSpaceImpl; +Validator validateAlphaNumSpace(validatorAlphaNumSpaceImpl); + +// Used for most names of things stored on the server, due to old file-formats +// that used the pipe (|) for multiline text storage. Examples include +// inventory item names, parcel names, object names, etc. +class ValidatorASCIIPrintableNoPipe : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch < 0x20 || ch > 0x7f || ch == '|' || + (ch != ' ' && !LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch))) + { + return setError("Validator_ShouldBeDigitOrAlphaOrPunct", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIPrintableNoPipeImpl; +Validator validateASCIIPrintableNoPipe(validatorASCIIPrintableNoPipeImpl); + +// Used for avatar names +class ValidatorASCIIPrintableNoSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch <= 0x20 || ch > 0x7f || LLStringOps::isSpace(ch) || + (!LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch))) + { + return setError("Validator_ShouldBeDigitOrAlphaOrPunctNotSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIPrintableNoSpaceImpl; +Validator validateASCIIPrintableNoSpace(validatorASCIIPrintableNoSpaceImpl); + +class ValidatorASCII : public ValidatorImpl +{ +protected: + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch < 0x20 || ch > 0x7f) + { + return setError("Validator_ShouldBeASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIImpl; +Validator validateASCII(validatorASCIIImpl); + +class ValidatorASCIINoLeadingSpace : public ValidatorASCII +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + if (LLStringOps::isSpace(str.front())) + { + return false; + } + + return ValidatorASCII::validate<CHAR>(str); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIINoLeadingSpaceImpl; +Validator validateASCIINoLeadingSpace(validatorASCIINoLeadingSpaceImpl); + +class ValidatorASCIIWithNewLine : public ValidatorImpl +{ + // Used for multiline text stored on the server. + // Example is landmark description in Places SP. + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if ((ch < 0x20 && ch != 0xA) || ch > 0x7f) + { + return setError("Validator_ShouldBeNewLineOrASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIWithNewLineImpl; +Validator validateASCIIWithNewLine(validatorASCIIWithNewLineImpl); + +void Validators::declareValues() +{ + declare("ascii", validateASCII); + declare("float", validateFloat); + declare("int", validateInt); + declare("positive_s32", validatePositiveS32); + declare("non_negative_s32", validateNonNegativeS32); + declare("alpha_num", validateAlphaNum); + declare("alpha_num_space", validateAlphaNumSpace); + declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe); + declare("ascii_printable_no_space", validateASCIIPrintableNoSpace); + declare("ascii_with_newline", validateASCIIWithNewLine); +} + +} // namespace LLTextValidate |