diff options
Diffstat (limited to 'indra/llcommon/llstring.h')
-rw-r--r-- | indra/llcommon/llstring.h | 713 |
1 files changed, 346 insertions, 367 deletions
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 88d7e88edc..7e41e787b5 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1,53 +1,58 @@ /** * @file llstring.h - * @brief String utility functions and LLString class. + * @brief String utility functions and std::string class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LL_LLSTRING_H #define LL_LLSTRING_H +#include <string> +#include <cstdio> +#include <locale> +#include <iomanip> +#include "llsd.h" +#include "llfasttimer.h" + #if LL_LINUX || LL_SOLARIS #include <wctype.h> #include <wchar.h> #endif +#include <string.h> + +#if LL_SOLARIS +// stricmp and strnicmp do not exist on Solaris: +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif + const char LL_UNKNOWN_CHAR = '?'; -class LLVector3; -class LLVector3d; -class LLQuaternion; -class LLUUID; -class LLColor4; -class LLColor4U; +#if LL_DARWIN || LL_LINUX || LL_SOLARIS +// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) +#include <cstring> -#if (LL_DARWIN || LL_SOLARIS || (LL_LINUX && __GNUC__ > 2)) -// Template specialization of char_traits for U16s. Only necessary on Mac for now (exists on Windows, unused/broken on Linux/gcc2.95) namespace std { template<> @@ -137,107 +142,121 @@ struct char_traits<U16> }; #endif -class LLStringOps +class LL_COMMON_API LLStringOps { +private: + static long sPacificTimeOffset; + static long sLocalTimeOffset; + static bool sPacificDaylightTime; + + static std::map<std::string, std::string> datetimeToCodes; + public: - static char toUpper(char elem) { return toupper(elem); } + static std::vector<std::string> sWeekDayList; + static std::vector<std::string> sWeekDayShortList; + static std::vector<std::string> sMonthList; + static std::vector<std::string> sMonthShortList; + static std::string sDayFormat; + + static std::string sAM; + static std::string sPM; + + static char toUpper(char elem) { return toupper((unsigned char)elem); } static llwchar toUpper(llwchar elem) { return towupper(elem); } - static char toLower(char elem) { return tolower(elem); } + static char toLower(char elem) { return tolower((unsigned char)elem); } static llwchar toLower(llwchar elem) { return towlower(elem); } - static BOOL isSpace(char elem) { return isspace(elem) != 0; } - static BOOL isSpace(llwchar elem) { return iswspace(elem) != 0; } + static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } + static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } + + static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } + static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } + + static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } + static bool isLower(llwchar elem) { return iswlower(elem) != 0; } - static BOOL isUpper(char elem) { return isupper(elem) != 0; } - static BOOL isUpper(llwchar elem) { return iswupper(elem) != 0; } + static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } + static bool isDigit(llwchar a) { return iswdigit(a) != 0; } - static BOOL isLower(char elem) { return islower(elem) != 0; } - static BOOL isLower(llwchar elem) { return iswlower(elem) != 0; } + static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } + static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } + static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } static S32 collate(const char* a, const char* b) { return strcoll(a, b); } static S32 collate(const llwchar* a, const llwchar* b); - static BOOL isDigit(char a) { return isdigit(a) != 0; } - static BOOL isDigit(llwchar a) { return iswdigit(a) != 0; } + static void setupDatetimeInfo(bool pacific_daylight_time); + + static void setupWeekDaysNames(const std::string& data); + static void setupWeekDaysShortNames(const std::string& data); + static void setupMonthNames(const std::string& data); + static void setupMonthShortNames(const std::string& data); + static void setupDayFormat(const std::string& data); + + + static long getPacificTimeOffset(void) { return sPacificTimeOffset;} + static long getLocalTimeOffset(void) { return sLocalTimeOffset;} + // Is the Pacific time zone (aka server time zone) + // currently in daylight savings time? + static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} + + static std::string getDatetimeCode (std::string key); }; -//RN: I used a templated base class instead of a pure interface class to minimize code duplication -// but it might be worthwhile to just go with two implementations (LLString and LLWString) of -// an interface class, unless we can think of a good reason to have a std::basic_string polymorphic base +/** + * @brief Return a string constructed from in without crashing if the + * pointer is NULL. + */ +LL_COMMON_API std::string ll_safe_string(const char* in); +LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); -//**************************************************************** -// NOTA BENE: do *NOT* dynamically allocate memory inside of LLStringBase as the {*()^#%*)#%W^*)#%*)STL implentation -// of basic_string doesn't provide a virtual destructor. If we need to allocate resources specific to LLString -// then we should either customize std::basic_string to linden::basic_string or change LLString to be a wrapper -// that contains an instance of std::basic_string. Similarly, overriding methods defined in std::basic_string will *not* -// be called in a polymorphic manner (passing an instance of basic_string to a particular function) -//**************************************************************** -template <class T> -class LLStringBase : public std::basic_string<T> +// Allowing assignments from non-strings into format_map_t is apparently +// *really* error-prone, so subclass std::string with just basic c'tors. +class LLFormatMapString { public: - typedef typename std::basic_string<T>::size_type size_type; - - // naming convention follows those set for LLUUID -// static LLStringBase null; // deprecated for std::string compliance -// static LLStringBase zero_length; // deprecated for std::string compliance + LLFormatMapString() {}; + LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; + LLFormatMapString(const std::string& s) : mString(s) {}; + operator std::string() const { return mString; } + bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } + std::size_t length() const { return mString.length(); } - - // standard constructors - LLStringBase() : std::basic_string<T>() {} - LLStringBase(const LLStringBase& s): std::basic_string<T>(s) {} - LLStringBase(const std::basic_string<T>& s) : std::basic_string<T>(s) {} - LLStringBase(const std::basic_string<T>& s, size_type pos, size_type n = std::basic_string<T>::npos) - : std::basic_string<T>(s, pos, n) {} - LLStringBase(size_type count, const T& c) : std::basic_string<T>() { assign(count, c);} - // custom constructors - LLStringBase(const T* s); - LLStringBase(const T* s, size_type n); - LLStringBase(const T* s, size_type pos, size_type n ); - -#if LL_LINUX || LL_SOLARIS - void clear() { assign(null); } - - LLStringBase<T>& assign(const T* s); - LLStringBase<T>& assign(const T* s, size_type n); - LLStringBase<T>& assign(const LLStringBase& s); - LLStringBase<T>& assign(size_type n, const T& c); - LLStringBase<T>& assign(const T* a, const T* b); - LLStringBase<T>& assign(typename LLStringBase<T>::iterator &it1, typename LLStringBase<T>::iterator &it2); - LLStringBase<T>& assign(typename LLStringBase<T>::const_iterator &it1, typename LLStringBase<T>::const_iterator &it2); - - // workaround for bug in gcc2 STL headers. - #if ((__GNUC__ <= 2) && (!defined _STLPORT_VERSION)) - const T* c_str () const - { - if (length () == 0) - { - static const T zero = 0; - return &zero; - } - - //terminate (); - { string_char_traits<T>::assign(const_cast<T*>(data())[length()], string_char_traits<T>::eos()); } - - return data (); - } - #endif -#endif +private: + std::string mString; +}; - bool operator==(const T* _Right) const { return _Right ? (std::basic_string<T>::compare(_Right) == 0) : this->empty(); } +template <class T> +class LLStringUtilBase +{ +private: + static std::string sLocale; + +public: + typedef typename std::basic_string<T>::size_type size_type; public: ///////////////////////////////////////////////////////////////////////////////////////// // Static Utility functions that operate on std::strings - static LLStringBase null; + static const std::basic_string<T> null; - typedef std::map<std::string, std::string> format_map_t; - static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map); + typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; + LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims); + LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals); + LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch); + LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions); + LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions); + LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions); + LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions); + LL_COMMON_API static void setLocale (std::string inLocale); + LL_COMMON_API static std::string getLocale (void); - static BOOL isValidIndex(const std::basic_string<T>& string, size_type i) + static bool isValidIndex(const std::basic_string<T>& string, size_type i) { return !string.empty() && (0 <= i) && (i <= string.size()); } @@ -252,22 +271,41 @@ public: // True if this is the head of s. static BOOL isHead( const std::basic_string<T>& string, const T* s ); - + + /** + * @brief Returns true if string starts with substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool startsWith( + const std::basic_string<T>& string, + const std::basic_string<T>& substr); + + /** + * @brief Returns true if string ends in substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool endsWith( + const std::basic_string<T>& string, + const std::basic_string<T>& substr); + static void addCRLF(std::basic_string<T>& string); static void removeCRLF(std::basic_string<T>& string); static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab ); static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement ); static void replaceChar( std::basic_string<T>& string, T target, T replacement ); - + static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement ); + static BOOL containsNonprintable(const std::basic_string<T>& string); static void stripNonprintable(std::basic_string<T>& string); /** * @brief Unsafe way to make ascii characters. You should probably * only call this when interacting with the host operating system. - * The 1 byte LLString does not work correctly. - * The 2 and 4 byte LLString probably work, so LLWString::_makeASCII + * The 1 byte std::string does not work correctly. + * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII * should work. */ static void _makeASCII(std::basic_string<T>& string); @@ -289,11 +327,13 @@ public: // Like strcmp but also handles empty strings. Uses // current locale. static S32 compareStrings(const T* lhs, const T* rhs); + static S32 compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs); // case insensitive version of above. Uses current locale on // Win32, and falls back to a non-locale aware comparison on // Linux. static S32 compareInsensitive(const T* lhs, const T* rhs); + static S32 compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs); // Case sensitive comparison with good handling of numbers. Does not use current locale. // a.k.a. strdictcmp() @@ -314,27 +354,33 @@ public: // Copies src into dst at a given offset. static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset); + static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } + + #ifdef _DEBUG - static void testHarness(); + LL_COMMON_API static void testHarness(); #endif +private: + LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens); }; -template<class T> LLStringBase<T> LLStringBase<T>::null; +template<class T> const std::basic_string<T> LLStringUtilBase<T>::null; +template<class T> std::string LLStringUtilBase<T>::sLocale; -typedef LLStringBase<char> LLString; -typedef LLStringBase<llwchar> LLWString; +typedef LLStringUtilBase<char> LLStringUtil; +typedef LLStringUtilBase<llwchar> LLWStringUtil; +typedef std::basic_string<llwchar> LLWString; //@ Use this where we want to disallow input in the form of "foo" // This is used to catch places where english text is embedded in the code // instead of in a translatable XUI file. -class LLStringExplicit : public LLString +class LLStringExplicit : public std::string { public: - explicit LLStringExplicit(const char* s) : LLString(s) {} - LLStringExplicit(const LLString& s) : LLString(s) {} - LLStringExplicit(const std::string& s) : LLString(s) {} - LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : LLString(s, pos, n) {} + explicit LLStringExplicit(const char* s) : std::string(s) {} + LLStringExplicit(const std::string& s) : std::string(s) {} + LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} }; struct LLDictionaryLess @@ -342,7 +388,7 @@ struct LLDictionaryLess public: bool operator()(const std::string& a, const std::string& b) { - return (LLString::precedesDict(a, b) ? true : false); + return (LLStringUtil::precedesDict(a, b) ? true : false); } }; @@ -357,7 +403,7 @@ public: * This function works on bytes rather than glyphs, so this will * incorrectly truncate non-single byte strings. * Use utf8str_truncate() for utf8 strings - * @return a copy of in string minus the trailing count characters. + * @return a copy of in string minus the trailing count bytes. */ inline std::string chop_tail_copy( const std::string& in, @@ -367,16 +413,10 @@ inline std::string chop_tail_copy( } /** - * @brief Return a string constructed from in without crashing if the - * pointer is NULL. - */ -std::string ll_safe_string(const char* in); - -/** * @brief This translates a nybble stored as a hex value from 0-f back * to a nybble in the low order bits of the return byte. */ -U8 hex_as_nybble(char hex); +LL_COMMON_API U8 hex_as_nybble(char hex); /** * @brief read the contents of a file into a string. @@ -387,64 +427,62 @@ U8 hex_as_nybble(char hex); * @param filename The full name of the file to read. * @return Returns true on success. If false, str is unmodified. */ -bool _read_file_into_string(std::string& str, const char* filename); +LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename); +LL_COMMON_API bool iswindividual(llwchar elem); /** * Unicode support */ // Make the incoming string a utf8 string. Replaces any unknown glyph -// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest +// with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest // of the data may not be recovered. -std::string rawstr_to_utf8(const std::string& raw); +LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); // // We should never use UTF16 except when communicating with Win32! // typedef std::basic_string<U16> llutf16string; -LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); -LLWString utf16str_to_wstring(const llutf16string &utf16str); +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); -llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); -llutf16string wstring_to_utf16str(const LLWString &utf32str); +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); -llutf16string utf8str_to_utf16str ( const LLString& utf8str, S32 len); -llutf16string utf8str_to_utf16str ( const LLString& utf8str ); +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); -LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); -LLWString utf8str_to_wstring(const std::string &utf8str); +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); // Same function, better name. JC inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } -// Special hack for llfilepicker.cpp: -S32 utf16chars_to_utf8chars(const U16* inchars, char* outchars, S32* nchars8 = 0); -S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar); -S32 wchar_to_utf8chars(llwchar inchar, char* outchars); - // -std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); -std::string wstring_to_utf8str(const LLWString &utf32str); +LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); + +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); -std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); -std::string utf16str_to_utf8str(const llutf16string &utf16str); +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); // Length of this UTF32 string in bytes when transformed to UTF8 -S32 wstring_utf8_length(const LLWString& wstr); +LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); // Length in bytes of this wide char in a UTF8 string -S32 wchar_utf8_length(const llwchar wc); +LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); -std::string utf8str_tolower(const std::string& utf8str); +LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str); // Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. -S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); +LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); // Length in utf16string (UTF-16) of wlen wchars beginning at woffset. -S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); +LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); // Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.) -S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); +LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); /** * @brief Properly truncate a utf8 string to a maximum byte count. @@ -456,11 +494,11 @@ S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset * @param max_len The maximum number of bytes in the return value. * @return Returns a valid utf8 string with byte count <= max_len. */ -std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); +LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); -std::string utf8str_trim(const std::string& utf8str); +LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); -S32 utf8str_compare_insensitive( +LL_COMMON_API S32 utf8str_compare_insensitive( const std::string& lhs, const std::string& rhs); @@ -471,28 +509,19 @@ S32 utf8str_compare_insensitive( * @param target_char The wchar to be replaced * @param replace_char The wchar which is written on replace */ -std::string utf8str_substChar( +LL_COMMON_API std::string utf8str_substChar( const std::string& utf8str, const llwchar target_char, const llwchar replace_char); -std::string utf8str_makeASCII(const std::string& utf8str); +LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); // Hack - used for evil notecards. -std::string mbcsstring_makeASCII(const std::string& str); +LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); -std::string utf8str_removeCRLF(const std::string& utf8str); +LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); -template <class T> -std::ostream& operator<<(std::ostream &s, const LLStringBase<T> &str) -{ - s << ((std::basic_string<T>)str); - return s; -} - -std::ostream& operator<<(std::ostream &s, const LLWString &wstr); - #if LL_WINDOWS /* @name Windows string helpers */ @@ -515,20 +544,40 @@ std::ostream& operator<<(std::ostream &s, const LLWString &wstr); * formatted string. * */ -int safe_snprintf(char* str, size_t size, const char* format, ...); + +// Deal with the differeneces on Windows +namespace snprintf_hack +{ + LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); +} + +using snprintf_hack::snprintf; /** * @brief Convert a wide string to std::string * * This replaces the unsafe W2A macro from ATL. */ -std::string ll_convert_wide_to_string(const wchar_t* in); +LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page); + +/** + * Converts a string to wide string. + * + * It will allocate memory for result string with "new []". Don't forget to release it with "delete []". + */ +LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page); + +/** + * Converts incoming string into urf8 string + * + */ +LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in); //@} #endif // LL_WINDOWS /** - * Many of the 'strip' and 'replace' methods of LLStringBase need + * Many of the 'strip' and 'replace' methods of LLStringUtilBase need * specialization to work with the signed char type. * Sadly, it is not possible (AFAIK) to specialize a single method of * a template class. @@ -539,81 +588,62 @@ namespace LLStringFn /** * @brief Replace all non-printable characters with replacement in * string. + * NOTE - this will zap non-ascii * * @param [in,out] string the to modify. out value is the string * with zero non-printable characters. * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. */ - void replace_nonprintable( + LL_COMMON_API void replace_nonprintable_in_ascii( std::basic_string<char>& string, char replacement); - /** - * @brief Replace all non-printable characters with replacement in - * a wide string. - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - void replace_nonprintable( - std::basic_string<llwchar>& string, - llwchar replacement); /** * @brief Replace all non-printable characters and pipe characters * with replacement in a string. + * NOTE - this will zap non-ascii * * @param [in,out] the string to modify. out value is the string * with zero non-printable characters and zero pipe characters. * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. */ - void replace_nonprintable_and_pipe(std::basic_string<char>& str, + LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str, char replacement); + /** - * @brief Replace all non-printable characters and pipe characters - * with replacement in a wide string. + * @brief Remove all characters that are not allowed in XML 1.0. + * Returns a copy of the string with those characters removed. + * Works with US ASCII and UTF-8 encoded strings. JC + */ + LL_COMMON_API std::string strip_invalid_xml(const std::string& input); + + + /** + * @brief Replace all control characters (0 <= c < 0x20) with replacement in + * string. This is safe for utf-8 * - * @param [in,out] the string to modify. out value is the string - * with zero non-printable characters and zero pipe characters. - * @param The replacement wide character. use LL_UNKNOWN_CHAR if unsure. + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. */ - void replace_nonprintable_and_pipe(std::basic_string<llwchar>& str, - llwchar replacement); + LL_COMMON_API void replace_ascii_controlchars( + std::basic_string<char>& string, + char replacement); } //////////////////////////////////////////////////////////// +// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp. +// There is no LLWStringUtil::format implementation currently. +// Calling thse for anything other than LLStringUtil will produce link errors. + +//////////////////////////////////////////////////////////// -// static -template<class T> -S32 LLStringBase<T>::format(std::basic_string<T>& s, const format_map_t& fmt_map) -{ - typedef typename std::basic_string<T>::size_type string_size_type_t; - S32 res = 0; - for (format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) - { - U32 fmtlen = iter->first.size(); - string_size_type_t n = 0; - while (1) - { - n = s.find(iter->first, n); - if (n == std::basic_string<T>::npos) - { - break; - } - s.erase(n, fmtlen); - s.insert(n, iter->second); - n += fmtlen; - ++res; - } - } - return res; -} // static template<class T> -S32 LLStringBase<T>::compareStrings(const T* lhs, const T* rhs) +S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs) { S32 result; if( lhs == rhs ) @@ -637,9 +667,16 @@ S32 LLStringBase<T>::compareStrings(const T* lhs, const T* rhs) return result; } +//static +template<class T> +S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs) +{ + return LLStringOps::collate(lhs.c_str(), rhs.c_str()); +} + // static template<class T> -S32 LLStringBase<T>::compareInsensitive(const T* lhs, const T* rhs ) +S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs ) { S32 result; if( lhs == rhs ) @@ -658,22 +695,32 @@ S32 LLStringBase<T>::compareInsensitive(const T* lhs, const T* rhs ) } else { - LLStringBase<T> lhs_string(lhs); - LLStringBase<T> rhs_string(rhs); - LLStringBase<T>::toUpper(lhs_string); - LLStringBase<T>::toUpper(rhs_string); + std::basic_string<T> lhs_string(lhs); + std::basic_string<T> rhs_string(rhs); + LLStringUtilBase<T>::toUpper(lhs_string); + LLStringUtilBase<T>::toUpper(rhs_string); result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); } return result; } +//static +template<class T> +S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs) +{ + std::basic_string<T> lhs_string(lhs); + std::basic_string<T> rhs_string(rhs); + LLStringUtilBase<T>::toUpper(lhs_string); + LLStringUtilBase<T>::toUpper(rhs_string); + return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); +} // Case sensitive comparison with good handling of numbers. Does not use current locale. // a.k.a. strdictcmp() //static template<class T> -S32 LLStringBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr) +S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr) { const T* a = astr.c_str(); const T* b = bstr.c_str(); @@ -712,8 +759,9 @@ S32 LLStringBase<T>::compareDict(const std::basic_string<T>& astr, const std::ba return ca-cb; } +// static template<class T> -S32 LLStringBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr) +S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr) { const T* a = astr.c_str(); const T* b = bstr.c_str(); @@ -748,11 +796,11 @@ S32 LLStringBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, co // Puts compareDict() in a form appropriate for LL container classes to use for sorting. // static template<class T> -BOOL LLStringBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b ) +BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b ) { if( a.size() && b.size() ) { - return (LLStringBase<T>::compareDict(a.c_str(), b.c_str()) < 0); + return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0); } else { @@ -760,108 +808,9 @@ BOOL LLStringBase<T>::precedesDict( const std::basic_string<T>& a, const std::ba } } -// Constructors -template<class T> -LLStringBase<T>::LLStringBase(const T* s ) : std::basic_string<T>() -{ - if (s) assign(s); -} - -template<class T> -LLStringBase<T>::LLStringBase(const T* s, size_type n ) : std::basic_string<T>() -{ - if (s) assign(s, n); -} - -// Init from a substring -template<class T> -LLStringBase<T>::LLStringBase(const T* s, size_type pos, size_type n ) : std::basic_string<T>() -{ - if( s ) - { - assign(s + pos, n); - } - else - { - assign(LLStringBase<T>::null); - } -} - -#if LL_LINUX || LL_SOLARIS -template<class T> -LLStringBase<T>& LLStringBase<T>::assign(const T* s) -{ - if (s) - { - std::basic_string<T>::assign(s); - } - else - { - assign(LLStringBase<T>::null); - } - return *this; -} - -template<class T> -LLStringBase<T>& LLStringBase<T>::assign(const T* s, size_type n) -{ - if (s) - { - std::basic_string<T>::assign(s, n); - } - else - { - assign(LLStringBase<T>::null); - } - return *this; -} - -template<class T> -LLStringBase<T>& LLStringBase<T>::assign(const LLStringBase<T>& s) -{ - std::basic_string<T>::assign(s); - return *this; -} - -template<class T> -LLStringBase<T>& LLStringBase<T>::assign(size_type n, const T& c) -{ - std::basic_string<T>::assign(n, c); - return *this; -} - -template<class T> -LLStringBase<T>& LLStringBase<T>::assign(const T* a, const T* b) -{ - if (a > b) - assign(LLStringBase<T>::null); - else - assign(a, (size_type) (b-a)); - return *this; -} - -template<class T> -LLStringBase<T>& LLStringBase<T>::assign(typename LLStringBase<T>::iterator &it1, typename LLStringBase<T>::iterator &it2) -{ - assign(LLStringBase<T>::null); - while(it1 != it2) - *this += *it1++; - return *this; -} - -template<class T> -LLStringBase<T>& LLStringBase<T>::assign(typename LLStringBase<T>::const_iterator &it1, typename LLStringBase<T>::const_iterator &it2) -{ - assign(LLStringBase<T>::null); - while(it1 != it2) - *this += *it1++; - return *this; -} -#endif - //static template<class T> -void LLStringBase<T>::toUpper(std::basic_string<T>& string) +void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string) { if( !string.empty() ) { @@ -875,7 +824,7 @@ void LLStringBase<T>::toUpper(std::basic_string<T>& string) //static template<class T> -void LLStringBase<T>::toLower(std::basic_string<T>& string) +void LLStringUtilBase<T>::toLower(std::basic_string<T>& string) { if( !string.empty() ) { @@ -889,7 +838,7 @@ void LLStringBase<T>::toLower(std::basic_string<T>& string) //static template<class T> -void LLStringBase<T>::trimHead(std::basic_string<T>& string) +void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string) { if( !string.empty() ) { @@ -904,7 +853,7 @@ void LLStringBase<T>::trimHead(std::basic_string<T>& string) //static template<class T> -void LLStringBase<T>::trimTail(std::basic_string<T>& string) +void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string) { if( string.size() ) { @@ -923,7 +872,7 @@ void LLStringBase<T>::trimTail(std::basic_string<T>& string) // Replace line feeds with carriage return-line feed pairs. //static template<class T> -void LLStringBase<T>::addCRLF(std::basic_string<T>& string) +void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string) { const T LF = 10; const T CR = 13; @@ -958,13 +907,14 @@ void LLStringBase<T>::addCRLF(std::basic_string<T>& string) } string.assign(t, size); + delete[] t; } } // Remove all carriage returns //static template<class T> -void LLStringBase<T>::removeCRLF(std::basic_string<T>& string) +void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string) { const T CR = 13; @@ -985,20 +935,31 @@ void LLStringBase<T>::removeCRLF(std::basic_string<T>& string) //static template<class T> -void LLStringBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement ) +void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement ) { size_type found_pos = 0; - for (found_pos = string.find(target, found_pos); - found_pos != std::basic_string<T>::npos; - found_pos = string.find(target, found_pos)) + while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) { string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement } } //static template<class T> -void LLStringBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement ) +void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement ) +{ + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target + } +} + +//static +template<class T> +void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement ) { const char LF = 10; const S8 MIN = 32; @@ -1018,12 +979,12 @@ void LLStringBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T r //static template<class T> -void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab ) +void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab ) { const T TAB = '\t'; const T SPACE = ' '; - LLStringBase<T> out_str; + std::basic_string<T> out_str; // Replace tabs with spaces for (size_type i = 0; i < str.length(); i++) { @@ -1042,7 +1003,7 @@ void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_typ //static template<class T> -BOOL LLStringBase<T>::containsNonprintable(const std::basic_string<T>& string) +BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string) { const char MIN = 32; BOOL rv = FALSE; @@ -1059,7 +1020,7 @@ BOOL LLStringBase<T>::containsNonprintable(const std::basic_string<T>& string) //static template<class T> -void LLStringBase<T>::stripNonprintable(std::basic_string<T>& string) +void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string) { const char MIN = 32; size_type j = 0; @@ -1067,14 +1028,15 @@ void LLStringBase<T>::stripNonprintable(std::basic_string<T>& string) { return; } - char* c_string = new char[string.size() + 1]; + size_t src_size = string.size(); + char* c_string = new char[src_size + 1]; if(c_string == NULL) { return; } - strcpy(c_string, string.c_str()); /*Flawfinder: ignore*/ + copy(c_string, string.c_str(), src_size+1); char* write_head = &c_string[0]; - for (size_type i = 0; i < string.size(); i++) + for (size_type i = 0; i < src_size; i++) { char* read_head = &string[i]; write_head = &c_string[j]; @@ -1090,7 +1052,7 @@ void LLStringBase<T>::stripNonprintable(std::basic_string<T>& string) } template<class T> -void LLStringBase<T>::_makeASCII(std::basic_string<T>& string) +void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string) { // Replace non-ASCII chars with LL_UNKNOWN_CHAR for (size_type i = 0; i < string.length(); i++) @@ -1104,7 +1066,7 @@ void LLStringBase<T>::_makeASCII(std::basic_string<T>& string) // static template<class T> -void LLStringBase<T>::copy( T* dst, const T* src, size_type dst_size ) +void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size ) { if( dst_size > 0 ) { @@ -1120,7 +1082,7 @@ void LLStringBase<T>::copy( T* dst, const T* src, size_type dst_size ) // static template<class T> -void LLStringBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset) +void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset) { if ( offset == dst.length() ) { @@ -1141,7 +1103,7 @@ void LLStringBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_strin // True if this is the head of s. //static template<class T> -BOOL LLStringBase<T>::isHead( const std::basic_string<T>& string, const T* s ) +BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s ) { if( string.empty() ) { @@ -1154,15 +1116,39 @@ BOOL LLStringBase<T>::isHead( const std::basic_string<T>& string, const T* s ) } } +// static +template<class T> +bool LLStringUtilBase<T>::startsWith( + const std::basic_string<T>& string, + const std::basic_string<T>& substr) +{ + if(string.empty() || (substr.empty())) return false; + if(0 == string.find(substr)) return true; + return false; +} + +// static +template<class T> +bool LLStringUtilBase<T>::endsWith( + const std::basic_string<T>& string, + const std::basic_string<T>& substr) +{ + if(string.empty() || (substr.empty())) return false; + std::string::size_type idx = string.rfind(substr); + if(std::string::npos == idx) return false; + return (idx == (string.size() - substr.size())); +} + + template<class T> -BOOL LLStringBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value) +BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value) { if( string.empty() ) { return FALSE; } - LLStringBase<T> temp( string ); + std::basic_string<T> temp( string ); trim(temp); if( (temp == "1") || @@ -1192,7 +1178,7 @@ BOOL LLStringBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& va } template<class T> -BOOL LLStringBase<T>::convertToU8(const std::basic_string<T>& string, U8& value) +BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value) { S32 value32 = 0; BOOL success = convertToS32(string, value32); @@ -1205,7 +1191,7 @@ BOOL LLStringBase<T>::convertToU8(const std::basic_string<T>& string, U8& value) } template<class T> -BOOL LLStringBase<T>::convertToS8(const std::basic_string<T>& string, S8& value) +BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value) { S32 value32 = 0; BOOL success = convertToS32(string, value32); @@ -1218,7 +1204,7 @@ BOOL LLStringBase<T>::convertToS8(const std::basic_string<T>& string, S8& value) } template<class T> -BOOL LLStringBase<T>::convertToS16(const std::basic_string<T>& string, S16& value) +BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value) { S32 value32 = 0; BOOL success = convertToS32(string, value32); @@ -1231,7 +1217,7 @@ BOOL LLStringBase<T>::convertToS16(const std::basic_string<T>& string, S16& valu } template<class T> -BOOL LLStringBase<T>::convertToU16(const std::basic_string<T>& string, U16& value) +BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value) { S32 value32 = 0; BOOL success = convertToS32(string, value32); @@ -1244,26 +1230,19 @@ BOOL LLStringBase<T>::convertToU16(const std::basic_string<T>& string, U16& valu } template<class T> -BOOL LLStringBase<T>::convertToU32(const std::basic_string<T>& string, U32& value) +BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value) { if( string.empty() ) { return FALSE; } - LLStringBase<T> temp( string ); + std::basic_string<T> temp( string ); trim(temp); U32 v; std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); if(i_stream >> v) { - //TODO: figure out overflow reporting here - //if( ULONG_MAX == v ) - //{ - // // Underflow or overflow - // return FALSE; - //} - value = v; return TRUE; } @@ -1271,14 +1250,14 @@ BOOL LLStringBase<T>::convertToU32(const std::basic_string<T>& string, U32& valu } template<class T> -BOOL LLStringBase<T>::convertToS32(const std::basic_string<T>& string, S32& value) +BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value) { if( string.empty() ) { return FALSE; } - LLStringBase<T> temp( string ); + std::basic_string<T> temp( string ); trim(temp); S32 v; std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); @@ -1298,7 +1277,7 @@ BOOL LLStringBase<T>::convertToS32(const std::basic_string<T>& string, S32& valu } template<class T> -BOOL LLStringBase<T>::convertToF32(const std::basic_string<T>& string, F32& value) +BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value) { F64 value64 = 0.0; BOOL success = convertToF64(string, value64); @@ -1311,14 +1290,14 @@ BOOL LLStringBase<T>::convertToF32(const std::basic_string<T>& string, F32& valu } template<class T> -BOOL LLStringBase<T>::convertToF64(const std::basic_string<T>& string, F64& value) +BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value) { if( string.empty() ) { return FALSE; } - LLStringBase<T> temp( string ); + std::basic_string<T> temp( string ); trim(temp); F64 v; std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); @@ -1338,7 +1317,7 @@ BOOL LLStringBase<T>::convertToF64(const std::basic_string<T>& string, F64& valu } template<class T> -void LLStringBase<T>::truncate(std::basic_string<T>& string, size_type count) +void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count) { size_type cur_size = string.size(); string.resize(count < cur_size ? count : cur_size); |