summaryrefslogtreecommitdiff
path: root/indra/llcommon/llstring.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llstring.h')
-rw-r--r--indra/llcommon/llstring.h713
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);