diff options
Diffstat (limited to 'linden/indra/llcommon/llstring.h')
-rw-r--r-- | linden/indra/llcommon/llstring.h | 1300 |
1 files changed, 1300 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llstring.h b/linden/indra/llcommon/llstring.h new file mode 100644 index 0000000..a83b7cf --- /dev/null +++ b/linden/indra/llcommon/llstring.h | |||
@@ -0,0 +1,1300 @@ | |||
1 | /** | ||
2 | * @file llstring.h | ||
3 | * @brief String utility functions and LLString class. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLSTRING_H | ||
29 | #define LL_LLSTRING_H | ||
30 | |||
31 | #include "stdtypes.h" | ||
32 | #include "llerror.h" | ||
33 | #include <algorithm> | ||
34 | #include <map> | ||
35 | #include <stdio.h> | ||
36 | #include <ctype.h> | ||
37 | #include <stdlib.h> | ||
38 | #include <errno.h> | ||
39 | #include <math.h> | ||
40 | #if LL_LINUX | ||
41 | #include <wctype.h> | ||
42 | #include <wchar.h> | ||
43 | #endif | ||
44 | |||
45 | const char LL_UNKNOWN_CHAR = '?'; | ||
46 | |||
47 | class LLVector3; | ||
48 | class LLVector3d; | ||
49 | class LLQuaternion; | ||
50 | class LLUUID; | ||
51 | class LLColor4; | ||
52 | class LLColor4U; | ||
53 | |||
54 | #if (LL_DARWIN || (LL_LINUX && __GNUC__ > 2)) | ||
55 | // Template specialization of char_traits for U16s. Only necessary on Mac for now (exists on Windows, unused/broken on Linux/gcc2.95) | ||
56 | namespace std | ||
57 | { | ||
58 | template<> | ||
59 | struct char_traits<U16> | ||
60 | { | ||
61 | typedef U16 char_type; | ||
62 | typedef int int_type; | ||
63 | typedef streampos pos_type; | ||
64 | typedef streamoff off_type; | ||
65 | typedef mbstate_t state_type; | ||
66 | |||
67 | static void | ||
68 | assign(char_type& __c1, const char_type& __c2) | ||
69 | { __c1 = __c2; } | ||
70 | |||
71 | static bool | ||
72 | eq(const char_type& __c1, const char_type& __c2) | ||
73 | { return __c1 == __c2; } | ||
74 | |||
75 | static bool | ||
76 | lt(const char_type& __c1, const char_type& __c2) | ||
77 | { return __c1 < __c2; } | ||
78 | |||
79 | static int | ||
80 | compare(const char_type* __s1, const char_type* __s2, size_t __n) | ||
81 | { return memcmp(__s1, __s2, __n * sizeof(char_type)); } | ||
82 | |||
83 | static size_t | ||
84 | length(const char_type* __s) | ||
85 | { | ||
86 | const char_type *cur_char = __s; | ||
87 | while (*cur_char != 0) | ||
88 | { | ||
89 | ++cur_char; | ||
90 | } | ||
91 | return cur_char - __s; | ||
92 | } | ||
93 | |||
94 | static const char_type* | ||
95 | find(const char_type* __s, size_t __n, const char_type& __a) | ||
96 | { return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); } | ||
97 | |||
98 | static char_type* | ||
99 | move(char_type* __s1, const char_type* __s2, size_t __n) | ||
100 | { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); } | ||
101 | |||
102 | static char_type* | ||
103 | copy(char_type* __s1, const char_type* __s2, size_t __n) | ||
104 | { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } | ||
105 | |||
106 | static char_type* | ||
107 | assign(char_type* __s, size_t __n, char_type __a) | ||
108 | { | ||
109 | // This isn't right. | ||
110 | //return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type))); | ||
111 | |||
112 | // I don't think there's a standard 'memset' for 16-bit values. | ||
113 | // Do this the old-fashioned way. | ||
114 | |||
115 | size_t __i; | ||
116 | for(__i = 0; __i < __n; __i++) | ||
117 | { | ||
118 | __s[__i] = __a; | ||
119 | } | ||
120 | return __s; | ||
121 | } | ||
122 | |||
123 | static char_type | ||
124 | to_char_type(const int_type& __c) | ||
125 | { return static_cast<char_type>(__c); } | ||
126 | |||
127 | static int_type | ||
128 | to_int_type(const char_type& __c) | ||
129 | { return static_cast<int_type>(__c); } | ||
130 | |||
131 | static bool | ||
132 | eq_int_type(const int_type& __c1, const int_type& __c2) | ||
133 | { return __c1 == __c2; } | ||
134 | |||
135 | static int_type | ||
136 | eof() { return static_cast<int_type>(EOF); } | ||
137 | |||
138 | static int_type | ||
139 | not_eof(const int_type& __c) | ||
140 | { return (__c == eof()) ? 0 : __c; } | ||
141 | }; | ||
142 | }; | ||
143 | #endif | ||
144 | |||
145 | class LLStringOps | ||
146 | { | ||
147 | public: | ||
148 | static char toUpper(char elem) { return toupper(elem); } | ||
149 | static llwchar toUpper(llwchar elem) { return towupper(elem); } | ||
150 | |||
151 | static char toLower(char elem) { return tolower(elem); } | ||
152 | static llwchar toLower(llwchar elem) { return towlower(elem); } | ||
153 | |||
154 | static BOOL isSpace(char elem) { return isspace(elem) != 0; } | ||
155 | static BOOL isSpace(llwchar elem) { return iswspace(elem) != 0; } | ||
156 | |||
157 | static BOOL isUpper(char elem) { return isupper(elem) != 0; } | ||
158 | static BOOL isUpper(llwchar elem) { return iswupper(elem) != 0; } | ||
159 | |||
160 | static BOOL isLower(char elem) { return islower(elem) != 0; } | ||
161 | static BOOL isLower(llwchar elem) { return iswlower(elem) != 0; } | ||
162 | |||
163 | static S32 collate(const char* a, const char* b) { return strcoll(a, b); } | ||
164 | static S32 collate(const llwchar* a, const llwchar* b); | ||
165 | |||
166 | static BOOL isDigit(char a) { return isdigit(a) != 0; } | ||
167 | static BOOL isDigit(llwchar a) { return iswdigit(a) != 0; } | ||
168 | }; | ||
169 | |||
170 | //RN: I used a templated base class instead of a pure interface class to minimize code duplication | ||
171 | // but it might be worthwhile to just go with two implementations (LLString and LLWString) of | ||
172 | // an interface class, unless we can think of a good reason to have a std::basic_string polymorphic base | ||
173 | |||
174 | //**************************************************************** | ||
175 | // NOTA BENE: do *NOT* dynamically allocate memory inside of LLStringBase as the {*()^#%*)#%W^*)#%*)STL implentation | ||
176 | // of basic_string doesn't provide a virtual destructor. If we need to allocate resources specific to LLString | ||
177 | // then we should either customize std::basic_string to linden::basic_string or change LLString to be a wrapper | ||
178 | // that contains an instance of std::basic_string. Similarly, overriding methods defined in std::basic_string will *not* | ||
179 | // be called in a polymorphic manner (passing an instance of basic_string to a particular function) | ||
180 | //**************************************************************** | ||
181 | |||
182 | template <class T> | ||
183 | class LLStringBase : public std::basic_string<T> | ||
184 | { | ||
185 | public: | ||
186 | typedef typename std::basic_string<T>::size_type size_type; | ||
187 | |||
188 | // naming convention follows those set for LLUUID | ||
189 | // static LLStringBase null; // deprecated for std::string compliance | ||
190 | // static LLStringBase zero_length; // deprecated for std::string compliance | ||
191 | |||
192 | |||
193 | // standard constructors | ||
194 | LLStringBase() : std::basic_string<T>() {} | ||
195 | LLStringBase(const LLStringBase& s): std::basic_string<T>(s) {} | ||
196 | LLStringBase(const std::basic_string<T>& s) : std::basic_string<T>(s) {} | ||
197 | LLStringBase(const std::basic_string<T>& s, size_type pos, size_type n = std::basic_string<T>::npos) | ||
198 | : std::basic_string<T>(s, pos, n) {} | ||
199 | LLStringBase(size_type count, const T& c) : std::basic_string<T>() { assign(count, c);} | ||
200 | // custom constructors | ||
201 | LLStringBase(const T* s); | ||
202 | LLStringBase(const T* s, size_type n); | ||
203 | LLStringBase(const T* s, size_type pos, size_type n ); | ||
204 | |||
205 | #if LL_LINUX | ||
206 | void clear() { assign(null); } | ||
207 | |||
208 | LLStringBase<T>& assign(const T* s); | ||
209 | LLStringBase<T>& assign(const T* s, size_type n); | ||
210 | LLStringBase<T>& assign(const LLStringBase& s); | ||
211 | LLStringBase<T>& assign(size_type n, const T& c); | ||
212 | LLStringBase<T>& assign(const T* a, const T* b); | ||
213 | LLStringBase<T>& assign(typename LLStringBase<T>::iterator &it1, typename LLStringBase<T>::iterator &it2); | ||
214 | LLStringBase<T>& assign(typename LLStringBase<T>::const_iterator &it1, typename LLStringBase<T>::const_iterator &it2); | ||
215 | |||
216 | // workaround for bug in gcc2 STL headers. | ||
217 | #if ((__GNUC__ <= 2) && (!defined _STLPORT_VERSION)) | ||
218 | const T* c_str () const | ||
219 | { | ||
220 | if (length () == 0) | ||
221 | { | ||
222 | static const T zero = 0; | ||
223 | return &zero; | ||
224 | } | ||
225 | |||
226 | //terminate (); | ||
227 | { string_char_traits<T>::assign(const_cast<T*>(data())[length()], string_char_traits<T>::eos()); } | ||
228 | |||
229 | return data (); | ||
230 | } | ||
231 | #endif | ||
232 | #endif | ||
233 | |||
234 | bool operator==(const T* _Right) const { return _Right ? (std::basic_string<T>::compare(_Right) == 0) : this->empty(); } | ||
235 | |||
236 | public: | ||
237 | ///////////////////////////////////////////////////////////////////////////////////////// | ||
238 | // Static Utility functions that operate on std::strings | ||
239 | |||
240 | static LLStringBase null; | ||
241 | |||
242 | typedef std::map<std::string, std::string> format_map_t; | ||
243 | static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map); | ||
244 | |||
245 | static BOOL isValidIndex(const std::basic_string<T>& string, size_type i) | ||
246 | { | ||
247 | return !string.empty() && (0 <= i) && (i <= string.size()); | ||
248 | } | ||
249 | |||
250 | static void trimHead(std::basic_string<T>& string); | ||
251 | static void trimTail(std::basic_string<T>& string); | ||
252 | static void trim(std::basic_string<T>& string) { trimHead(string); trimTail(string); } | ||
253 | static void truncate(std::basic_string<T>& string, size_type count); | ||
254 | |||
255 | static void toUpper(std::basic_string<T>& string); | ||
256 | static void toLower(std::basic_string<T>& string); | ||
257 | |||
258 | // True if this is the head of s. | ||
259 | static BOOL isHead( const std::basic_string<T>& string, const T* s ); | ||
260 | |||
261 | static void addCRLF(std::basic_string<T>& string); | ||
262 | static void removeCRLF(std::basic_string<T>& string); | ||
263 | |||
264 | static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab ); | ||
265 | static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement ); | ||
266 | static void replaceChar( std::basic_string<T>& string, T target, T replacement ); | ||
267 | |||
268 | static BOOL containsNonprintable(const std::basic_string<T>& string); | ||
269 | static void stripNonprintable(std::basic_string<T>& string); | ||
270 | |||
271 | /** | ||
272 | * @brief Unsafe way to make ascii characters. You should probably | ||
273 | * only call this when interacting with the host operating system. | ||
274 | * The 1 byte LLString does not work correctly. | ||
275 | * The 2 and 4 byte LLString probably work, so LLWString::_makeASCII | ||
276 | * should work. | ||
277 | */ | ||
278 | static void _makeASCII(std::basic_string<T>& string); | ||
279 | |||
280 | static BOOL read(std::basic_string<T>& string, const char* filename); /*Flawfinder: ignore*/ | ||
281 | static BOOL write(std::basic_string<T>& string, const char* filename); | ||
282 | |||
283 | // Conversion to other data types | ||
284 | static BOOL convertToBOOL(const std::basic_string<T>& string, BOOL& value); | ||
285 | static BOOL convertToU8(const std::basic_string<T>& string, U8& value); | ||
286 | static BOOL convertToS8(const std::basic_string<T>& string, S8& value); | ||
287 | static BOOL convertToS16(const std::basic_string<T>& string, S16& value); | ||
288 | static BOOL convertToU16(const std::basic_string<T>& string, U16& value); | ||
289 | static BOOL convertToU32(const std::basic_string<T>& string, U32& value); | ||
290 | static BOOL convertToS32(const std::basic_string<T>& string, S32& value); | ||
291 | static BOOL convertToF32(const std::basic_string<T>& string, F32& value); | ||
292 | static BOOL convertToF64(const std::basic_string<T>& string, F64& value); | ||
293 | |||
294 | ///////////////////////////////////////////////////////////////////////////////////////// | ||
295 | // Utility functions for working with char*'s and strings | ||
296 | |||
297 | // Like strcmp but also handles empty strings. Uses | ||
298 | // current locale. | ||
299 | static S32 compareStrings(const T* lhs, const T* rhs); | ||
300 | |||
301 | // case insensitive version of above. Uses current locale on | ||
302 | // Win32, and falls back to a non-locale aware comparison on | ||
303 | // Linux. | ||
304 | static S32 compareInsensitive(const T* lhs, const T* rhs); | ||
305 | |||
306 | // Case sensitive comparison with good handling of numbers. Does not use current locale. | ||
307 | // a.k.a. strdictcmp() | ||
308 | static S32 compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b); | ||
309 | |||
310 | // Puts compareDict() in a form appropriate for LL container classes to use for sorting. | ||
311 | static BOOL precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b ); | ||
312 | |||
313 | // A replacement for strncpy. | ||
314 | // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds | ||
315 | // up to dst_size-1 characters of src. | ||
316 | static void copy(T* dst, const T* src, size_type dst_size); | ||
317 | |||
318 | // Copies src into dst at a given offset. | ||
319 | static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset); | ||
320 | |||
321 | #ifdef _DEBUG | ||
322 | static void testHarness(); | ||
323 | #endif | ||
324 | |||
325 | }; | ||
326 | |||
327 | template<class T> LLStringBase<T> LLStringBase<T>::null; | ||
328 | |||
329 | typedef LLStringBase<char> LLString; | ||
330 | typedef LLStringBase<llwchar> LLWString; | ||
331 | |||
332 | struct LLDictionaryLess | ||
333 | { | ||
334 | public: | ||
335 | bool operator()(const std::string& a, const std::string& b) | ||
336 | { | ||
337 | return (LLString::precedesDict(a, b) ? true : false); | ||
338 | } | ||
339 | }; | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Simple support functions | ||
344 | */ | ||
345 | |||
346 | /** | ||
347 | * @breif chop off the trailing characters in a string. | ||
348 | * | ||
349 | * This function works on bytes rather than glyphs, so this will | ||
350 | * incorrectly truncate non-single byte strings. | ||
351 | * Use utf8str_truncate() for utf8 strings | ||
352 | * @return a copy of in string minus the trailing count characters. | ||
353 | */ | ||
354 | inline std::string chop_tail_copy( | ||
355 | const std::string& in, | ||
356 | std::string::size_type count) | ||
357 | { | ||
358 | return std::string(in, 0, in.length() - count); | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * @brief Return a string constructed from in without crashing if the | ||
363 | * pointer is NULL. | ||
364 | */ | ||
365 | std::string ll_safe_string(const char* in); | ||
366 | |||
367 | /** | ||
368 | * @brief This translates a nybble stored as a hex value from 0-f back | ||
369 | * to a nybble in the low order bits of the return byte. | ||
370 | */ | ||
371 | U8 hex_as_nybble(char hex); | ||
372 | |||
373 | |||
374 | /** | ||
375 | * Unicode support | ||
376 | */ | ||
377 | |||
378 | // Make the incoming string a utf8 string. Replaces any unknown glyph | ||
379 | // with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest | ||
380 | // of the data may not be recovered. | ||
381 | std::string rawstr_to_utf8(const std::string& raw); | ||
382 | |||
383 | // | ||
384 | // We should never use UTF16 except when communicating with Win32! | ||
385 | // | ||
386 | typedef std::basic_string<U16> llutf16string; | ||
387 | |||
388 | LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); | ||
389 | LLWString utf16str_to_wstring(const llutf16string &utf16str); | ||
390 | |||
391 | llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); | ||
392 | llutf16string wstring_to_utf16str(const LLWString &utf32str); | ||
393 | |||
394 | llutf16string utf8str_to_utf16str ( const LLString& utf8str, S32 len); | ||
395 | llutf16string utf8str_to_utf16str ( const LLString& utf8str ); | ||
396 | |||
397 | LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); | ||
398 | LLWString utf8str_to_wstring(const std::string &utf8str); | ||
399 | // Same function, better name. JC | ||
400 | inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } | ||
401 | |||
402 | // Special hack for llfilepicker.cpp: | ||
403 | S32 utf16chars_to_utf8chars(const U16* inchars, char* outchars, S32* nchars8 = 0); | ||
404 | S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar); | ||
405 | S32 wchar_to_utf8chars(llwchar inchar, char* outchars); | ||
406 | |||
407 | // | ||
408 | std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); | ||
409 | std::string wstring_to_utf8str(const LLWString &utf32str); | ||
410 | |||
411 | std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); | ||
412 | std::string utf16str_to_utf8str(const llutf16string &utf16str); | ||
413 | |||
414 | // Length of this UTF32 string in bytes when transformed to UTF8 | ||
415 | S32 wstring_utf8_length(const LLWString& wstr); | ||
416 | |||
417 | // Length in bytes of this wide char in a UTF8 string | ||
418 | S32 wchar_utf8_length(const llwchar wc); | ||
419 | |||
420 | std::string utf8str_tolower(const std::string& utf8str); | ||
421 | |||
422 | /** | ||
423 | * @brief Properly truncate a utf8 string to a maximum byte count. | ||
424 | * | ||
425 | * The returned string may be less than max_len if the truncation | ||
426 | * happens in the middle of a glyph. If max_len is longer than the | ||
427 | * string passed in, the return value == utf8str. | ||
428 | * @param utf8str A valid utf8 string to truncate. | ||
429 | * @param max_len The maximum number of bytes in the returne | ||
430 | * @return Returns a valid utf8 string with byte count <= max_len. | ||
431 | */ | ||
432 | std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); | ||
433 | |||
434 | std::string utf8str_trim(const std::string& utf8str); | ||
435 | |||
436 | S32 utf8str_compare_insensitive( | ||
437 | const std::string& lhs, | ||
438 | const std::string& rhs); | ||
439 | |||
440 | /** | ||
441 | * @brief Replace all occurences of target_char with replace_char | ||
442 | * | ||
443 | * @param utf8str A utf8 string to process. | ||
444 | * @param target_char The wchar to be replaced | ||
445 | * @param replace_char The wchar which is written on replace | ||
446 | */ | ||
447 | std::string utf8str_substChar( | ||
448 | const std::string& utf8str, | ||
449 | const llwchar target_char, | ||
450 | const llwchar replace_char); | ||
451 | |||
452 | std::string utf8str_makeASCII(const std::string& utf8str); | ||
453 | |||
454 | // Hack - used for evil notecards. | ||
455 | std::string mbcsstring_makeASCII(const std::string& str); | ||
456 | |||
457 | template <class T> | ||
458 | std::ostream& operator<<(std::ostream &s, const LLStringBase<T> &str) | ||
459 | { | ||
460 | s << ((std::basic_string<T>)str); | ||
461 | return s; | ||
462 | } | ||
463 | |||
464 | std::ostream& operator<<(std::ostream &s, const LLWString &wstr); | ||
465 | |||
466 | |||
467 | /** | ||
468 | * Many of the 'strip' and 'replace' methods of LLStringBase need | ||
469 | * specialization to work with the signed char type. | ||
470 | * Sadly, it is not possible (AFAIK) to specialize a single method of | ||
471 | * a template class. | ||
472 | * That stuff should go here. | ||
473 | */ | ||
474 | namespace LLStringFn | ||
475 | { | ||
476 | /** | ||
477 | * @brief Replace all non-printable characters with replacement in | ||
478 | * string. | ||
479 | * | ||
480 | * @param [in,out] string the to modify. out value is the string | ||
481 | * with zero non-printable characters. | ||
482 | * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. | ||
483 | */ | ||
484 | void replace_nonprintable( | ||
485 | std::basic_string<char>& string, | ||
486 | char replacement); | ||
487 | |||
488 | /** | ||
489 | * @brief Replace all non-printable characters with replacement in | ||
490 | * a wide string. | ||
491 | * | ||
492 | * @param [in,out] string the to modify. out value is the string | ||
493 | * with zero non-printable characters. | ||
494 | * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. | ||
495 | */ | ||
496 | void replace_nonprintable( | ||
497 | std::basic_string<llwchar>& string, | ||
498 | llwchar replacement); | ||
499 | |||
500 | /** | ||
501 | * @brief Replace all non-printable characters and pipe characters | ||
502 | * with replacement in a string. | ||
503 | * | ||
504 | * @param [in,out] the string to modify. out value is the string | ||
505 | * with zero non-printable characters and zero pipe characters. | ||
506 | * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. | ||
507 | */ | ||
508 | void replace_nonprintable_and_pipe(std::basic_string<char>& str, | ||
509 | char replacement); | ||
510 | |||
511 | /** | ||
512 | * @brief Replace all non-printable characters and pipe characters | ||
513 | * with replacement in a wide string. | ||
514 | * | ||
515 | * @param [in,out] the string to modify. out value is the string | ||
516 | * with zero non-printable characters and zero pipe characters. | ||
517 | * @param The replacement wide character. use LL_UNKNOWN_CHAR if unsure. | ||
518 | */ | ||
519 | void replace_nonprintable_and_pipe(std::basic_string<llwchar>& str, | ||
520 | llwchar replacement); | ||
521 | } | ||
522 | |||
523 | //////////////////////////////////////////////////////////// | ||
524 | |||
525 | // static | ||
526 | template<class T> | ||
527 | S32 LLStringBase<T>::format(std::basic_string<T>& s, const format_map_t& fmt_map) | ||
528 | { | ||
529 | typedef typename std::basic_string<T>::size_type string_size_type_t; | ||
530 | S32 res = 0; | ||
531 | for (format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) | ||
532 | { | ||
533 | U32 fmtlen = iter->first.size(); | ||
534 | string_size_type_t n = 0; | ||
535 | while (1) | ||
536 | { | ||
537 | n = s.find(iter->first, n); | ||
538 | if (n == std::basic_string<T>::npos) | ||
539 | { | ||
540 | break; | ||
541 | } | ||
542 | s.erase(n, fmtlen); | ||
543 | s.insert(n, iter->second); | ||
544 | n += fmtlen; | ||
545 | ++res; | ||
546 | } | ||
547 | } | ||
548 | return res; | ||
549 | } | ||
550 | |||
551 | // static | ||
552 | template<class T> | ||
553 | S32 LLStringBase<T>::compareStrings(const T* lhs, const T* rhs) | ||
554 | { | ||
555 | S32 result; | ||
556 | if( lhs == rhs ) | ||
557 | { | ||
558 | result = 0; | ||
559 | } | ||
560 | else | ||
561 | if ( !lhs || !lhs[0] ) | ||
562 | { | ||
563 | result = ((!rhs || !rhs[0]) ? 0 : 1); | ||
564 | } | ||
565 | else | ||
566 | if ( !rhs || !rhs[0]) | ||
567 | { | ||
568 | result = -1; | ||
569 | } | ||
570 | else | ||
571 | { | ||
572 | result = LLStringOps::collate(lhs, rhs); | ||
573 | } | ||
574 | return result; | ||
575 | } | ||
576 | |||
577 | // static | ||
578 | template<class T> | ||
579 | S32 LLStringBase<T>::compareInsensitive(const T* lhs, const T* rhs ) | ||
580 | { | ||
581 | S32 result; | ||
582 | if( lhs == rhs ) | ||
583 | { | ||
584 | result = 0; | ||
585 | } | ||
586 | else | ||
587 | if ( !lhs || !lhs[0] ) | ||
588 | { | ||
589 | result = ((!rhs || !rhs[0]) ? 0 : 1); | ||
590 | } | ||
591 | else | ||
592 | if ( !rhs || !rhs[0] ) | ||
593 | { | ||
594 | result = -1; | ||
595 | } | ||
596 | else | ||
597 | { | ||
598 | LLStringBase<T> lhs_string(lhs); | ||
599 | LLStringBase<T> rhs_string(rhs); | ||
600 | LLStringBase<T>::toUpper(lhs_string); | ||
601 | LLStringBase<T>::toUpper(rhs_string); | ||
602 | result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); | ||
603 | } | ||
604 | return result; | ||
605 | } | ||
606 | |||
607 | |||
608 | // Case sensitive comparison with good handling of numbers. Does not use current locale. | ||
609 | // a.k.a. strdictcmp() | ||
610 | |||
611 | //static | ||
612 | template<class T> | ||
613 | S32 LLStringBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr) | ||
614 | { | ||
615 | const T* a = astr.c_str(); | ||
616 | const T* b = bstr.c_str(); | ||
617 | T ca, cb; | ||
618 | S32 ai, bi, cnt = 0; | ||
619 | S32 bias = 0; | ||
620 | |||
621 | ca = *(a++); | ||
622 | cb = *(b++); | ||
623 | while( ca && cb ){ | ||
624 | if( bias==0 ){ | ||
625 | if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } | ||
626 | if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } | ||
627 | }else{ | ||
628 | if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } | ||
629 | if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } | ||
630 | } | ||
631 | if( LLStringOps::isDigit(ca) ){ | ||
632 | if( cnt-->0 ){ | ||
633 | if( cb!=ca ) break; | ||
634 | }else{ | ||
635 | if( !LLStringOps::isDigit(cb) ) break; | ||
636 | for(ai=0; LLStringOps::isDigit(a[ai]); ai++); | ||
637 | for(bi=0; LLStringOps::isDigit(b[bi]); bi++); | ||
638 | if( ai<bi ){ ca=0; break; } | ||
639 | if( bi<ai ){ cb=0; break; } | ||
640 | if( ca!=cb ) break; | ||
641 | cnt = ai; | ||
642 | } | ||
643 | }else if( ca!=cb ){ break; | ||
644 | } | ||
645 | ca = *(a++); | ||
646 | cb = *(b++); | ||
647 | } | ||
648 | if( ca==cb ) ca += bias; | ||
649 | return ca-cb; | ||
650 | } | ||
651 | |||
652 | // Puts compareDict() in a form appropriate for LL container classes to use for sorting. | ||
653 | // static | ||
654 | template<class T> | ||
655 | BOOL LLStringBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b ) | ||
656 | { | ||
657 | if( a.size() && b.size() ) | ||
658 | { | ||
659 | return (LLStringBase<T>::compareDict(a.c_str(), b.c_str()) < 0); | ||
660 | } | ||
661 | else | ||
662 | { | ||
663 | return (!b.empty()); | ||
664 | } | ||
665 | } | ||
666 | |||
667 | // Constructors | ||
668 | template<class T> | ||
669 | LLStringBase<T>::LLStringBase(const T* s ) : std::basic_string<T>() | ||
670 | { | ||
671 | if (s) assign(s); | ||
672 | } | ||
673 | |||
674 | template<class T> | ||
675 | LLStringBase<T>::LLStringBase(const T* s, size_type n ) : std::basic_string<T>() | ||
676 | { | ||
677 | if (s) assign(s, n); | ||
678 | } | ||
679 | |||
680 | // Init from a substring | ||
681 | template<class T> | ||
682 | LLStringBase<T>::LLStringBase(const T* s, size_type pos, size_type n ) : std::basic_string<T>() | ||
683 | { | ||
684 | if( s ) | ||
685 | { | ||
686 | assign(s + pos, n); | ||
687 | } | ||
688 | else | ||
689 | { | ||
690 | assign(LLStringBase<T>::null); | ||
691 | } | ||
692 | } | ||
693 | |||
694 | #if LL_LINUX | ||
695 | template<class T> | ||
696 | LLStringBase<T>& LLStringBase<T>::assign(const T* s) | ||
697 | { | ||
698 | if (s) | ||
699 | { | ||
700 | std::basic_string<T>::assign(s); | ||
701 | } | ||
702 | else | ||
703 | { | ||
704 | assign(LLStringBase<T>::null); | ||
705 | } | ||
706 | return *this; | ||
707 | } | ||
708 | |||
709 | template<class T> | ||
710 | LLStringBase<T>& LLStringBase<T>::assign(const T* s, size_type n) | ||
711 | { | ||
712 | if (s) | ||
713 | { | ||
714 | std::basic_string<T>::assign(s, n); | ||
715 | } | ||
716 | else | ||
717 | { | ||
718 | assign(LLStringBase<T>::null); | ||
719 | } | ||
720 | return *this; | ||
721 | } | ||
722 | |||
723 | template<class T> | ||
724 | LLStringBase<T>& LLStringBase<T>::assign(const LLStringBase<T>& s) | ||
725 | { | ||
726 | std::basic_string<T>::assign(s); | ||
727 | return *this; | ||
728 | } | ||
729 | |||
730 | template<class T> | ||
731 | LLStringBase<T>& LLStringBase<T>::assign(size_type n, const T& c) | ||
732 | { | ||
733 | std::basic_string<T>::assign(n, c); | ||
734 | return *this; | ||
735 | } | ||
736 | |||
737 | template<class T> | ||
738 | LLStringBase<T>& LLStringBase<T>::assign(const T* a, const T* b) | ||
739 | { | ||
740 | if (a > b) | ||
741 | assign(LLStringBase<T>::null); | ||
742 | else | ||
743 | assign(a, (size_type) (b-a)); | ||
744 | return *this; | ||
745 | } | ||
746 | |||
747 | template<class T> | ||
748 | LLStringBase<T>& LLStringBase<T>::assign(typename LLStringBase<T>::iterator &it1, typename LLStringBase<T>::iterator &it2) | ||
749 | { | ||
750 | assign(LLStringBase<T>::null); | ||
751 | while(it1 != it2) | ||
752 | *this += *it1++; | ||
753 | return *this; | ||
754 | } | ||
755 | |||
756 | template<class T> | ||
757 | LLStringBase<T>& LLStringBase<T>::assign(typename LLStringBase<T>::const_iterator &it1, typename LLStringBase<T>::const_iterator &it2) | ||
758 | { | ||
759 | assign(LLStringBase<T>::null); | ||
760 | while(it1 != it2) | ||
761 | *this += *it1++; | ||
762 | return *this; | ||
763 | } | ||
764 | #endif | ||
765 | |||
766 | //static | ||
767 | template<class T> | ||
768 | void LLStringBase<T>::toUpper(std::basic_string<T>& string) | ||
769 | { | ||
770 | if( !string.empty() ) | ||
771 | { | ||
772 | std::transform( | ||
773 | string.begin(), | ||
774 | string.end(), | ||
775 | string.begin(), | ||
776 | (T(*)(T)) &LLStringOps::toUpper); | ||
777 | } | ||
778 | } | ||
779 | |||
780 | //static | ||
781 | template<class T> | ||
782 | void LLStringBase<T>::toLower(std::basic_string<T>& string) | ||
783 | { | ||
784 | if( !string.empty() ) | ||
785 | { | ||
786 | std::transform( | ||
787 | string.begin(), | ||
788 | string.end(), | ||
789 | string.begin(), | ||
790 | (T(*)(T)) &LLStringOps::toLower); | ||
791 | } | ||
792 | } | ||
793 | |||
794 | //static | ||
795 | template<class T> | ||
796 | void LLStringBase<T>::trimHead(std::basic_string<T>& string) | ||
797 | { | ||
798 | if( !string.empty() ) | ||
799 | { | ||
800 | size_type i = 0; | ||
801 | while( i < string.length() && LLStringOps::isSpace( string[i] ) ) | ||
802 | { | ||
803 | i++; | ||
804 | } | ||
805 | string.erase(0, i); | ||
806 | } | ||
807 | } | ||
808 | |||
809 | //static | ||
810 | template<class T> | ||
811 | void LLStringBase<T>::trimTail(std::basic_string<T>& string) | ||
812 | { | ||
813 | if( string.size() ) | ||
814 | { | ||
815 | size_type len = string.length(); | ||
816 | size_type i = len; | ||
817 | while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) | ||
818 | { | ||
819 | i--; | ||
820 | } | ||
821 | |||
822 | string.erase( i, len - i ); | ||
823 | } | ||
824 | } | ||
825 | |||
826 | |||
827 | // Replace line feeds with carriage return-line feed pairs. | ||
828 | //static | ||
829 | template<class T> | ||
830 | void LLStringBase<T>::addCRLF(std::basic_string<T>& string) | ||
831 | { | ||
832 | const T LF = 10; | ||
833 | const T CR = 13; | ||
834 | |||
835 | // Count the number of line feeds | ||
836 | size_type count = 0; | ||
837 | size_type len = string.size(); | ||
838 | size_type i; | ||
839 | for( i = 0; i < len; i++ ) | ||
840 | { | ||
841 | if( string[i] == LF ) | ||
842 | { | ||
843 | count++; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | // Insert a carriage return before each line feed | ||
848 | if( count ) | ||
849 | { | ||
850 | size_type size = len + count; | ||
851 | T *t = new T[size]; | ||
852 | size_type j = 0; | ||
853 | for( i = 0; i < len; ++i ) | ||
854 | { | ||
855 | if( string[i] == LF ) | ||
856 | { | ||
857 | t[j] = CR; | ||
858 | ++j; | ||
859 | } | ||
860 | t[j] = string[i]; | ||
861 | ++j; | ||
862 | } | ||
863 | |||
864 | string.assign(t, size); | ||
865 | } | ||
866 | } | ||
867 | |||
868 | // Remove all carriage returns | ||
869 | //static | ||
870 | template<class T> | ||
871 | void LLStringBase<T>::removeCRLF(std::basic_string<T>& string) | ||
872 | { | ||
873 | const T CR = 13; | ||
874 | |||
875 | size_type cr_count = 0; | ||
876 | size_type len = string.size(); | ||
877 | size_type i; | ||
878 | for( i = 0; i < len - cr_count; i++ ) | ||
879 | { | ||
880 | if( string[i+cr_count] == CR ) | ||
881 | { | ||
882 | cr_count++; | ||
883 | } | ||
884 | |||
885 | string[i] = string[i+cr_count]; | ||
886 | } | ||
887 | string.erase(i, cr_count); | ||
888 | } | ||
889 | |||
890 | //static | ||
891 | template<class T> | ||
892 | void LLStringBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement ) | ||
893 | { | ||
894 | size_type found_pos = 0; | ||
895 | for (found_pos = string.find(target, found_pos); | ||
896 | found_pos != std::basic_string<T>::npos; | ||
897 | found_pos = string.find(target, found_pos)) | ||
898 | { | ||
899 | string[found_pos] = replacement; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | //static | ||
904 | template<class T> | ||
905 | void LLStringBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement ) | ||
906 | { | ||
907 | const char LF = 10; | ||
908 | const S8 MIN = 32; | ||
909 | // const S8 MAX = 127; | ||
910 | |||
911 | size_type len = string.size(); | ||
912 | for( size_type i = 0; i < len; i++ ) | ||
913 | { | ||
914 | // No need to test MAX < mText[i] because we treat mText[i] as a signed char, | ||
915 | // which has a max value of 127. | ||
916 | if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) | ||
917 | { | ||
918 | string[i] = replacement; | ||
919 | } | ||
920 | } | ||
921 | } | ||
922 | |||
923 | //static | ||
924 | template<class T> | ||
925 | void LLStringBase<T>::replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab ) | ||
926 | { | ||
927 | llassert( spaces_per_tab >= 0 ); | ||
928 | |||
929 | const T TAB = '\t'; | ||
930 | const T SPACE = ' '; | ||
931 | |||
932 | LLStringBase<T> out_str; | ||
933 | // Replace tabs with spaces | ||
934 | for (size_type i = 0; i < string.length(); i++) | ||
935 | { | ||
936 | if (string[i] == TAB) | ||
937 | { | ||
938 | for (size_type j = 0; j < spaces_per_tab; j++) | ||
939 | out_str += SPACE; | ||
940 | } | ||
941 | else | ||
942 | { | ||
943 | out_str += string[i]; | ||
944 | } | ||
945 | } | ||
946 | string = out_str; | ||
947 | } | ||
948 | |||
949 | //static | ||
950 | template<class T> | ||
951 | BOOL LLStringBase<T>::containsNonprintable(const std::basic_string<T>& string) | ||
952 | { | ||
953 | const char MIN = 32; | ||
954 | BOOL rv = FALSE; | ||
955 | for (size_type i = 0; i < string.size(); i++) | ||
956 | { | ||
957 | if(string[i] < MIN) | ||
958 | { | ||
959 | rv = TRUE; | ||
960 | break; | ||
961 | } | ||
962 | } | ||
963 | return rv; | ||
964 | } | ||
965 | |||
966 | //static | ||
967 | template<class T> | ||
968 | void LLStringBase<T>::stripNonprintable(std::basic_string<T>& string) | ||
969 | { | ||
970 | const char MIN = 32; | ||
971 | size_type j = 0; | ||
972 | if (string.empty()) | ||
973 | { | ||
974 | return; | ||
975 | } | ||
976 | char* c_string = new char[string.size() + 1]; | ||
977 | if(c_string == NULL) | ||
978 | { | ||
979 | return; | ||
980 | } | ||
981 | strcpy(c_string, string.c_str()); /*Flawfinder: ignore*/ | ||
982 | char* write_head = &c_string[0]; | ||
983 | for (size_type i = 0; i < string.size(); i++) | ||
984 | { | ||
985 | char* read_head = &string[i]; | ||
986 | write_head = &c_string[j]; | ||
987 | if(!(*read_head < MIN)) | ||
988 | { | ||
989 | *write_head = *read_head; | ||
990 | ++j; | ||
991 | } | ||
992 | } | ||
993 | c_string[j]= '\0'; | ||
994 | string = c_string; | ||
995 | delete []c_string; | ||
996 | } | ||
997 | |||
998 | template<class T> | ||
999 | void LLStringBase<T>::_makeASCII(std::basic_string<T>& string) | ||
1000 | { | ||
1001 | // Replace non-ASCII chars with LL_UNKNOWN_CHAR | ||
1002 | for (size_type i = 0; i < string.length(); i++) | ||
1003 | { | ||
1004 | if (string[i] > 0x7f) | ||
1005 | { | ||
1006 | string[i] = LL_UNKNOWN_CHAR; | ||
1007 | } | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | // static | ||
1012 | template<class T> | ||
1013 | void LLStringBase<T>::copy( T* dst, const T* src, size_type dst_size ) | ||
1014 | { | ||
1015 | if( dst_size > 0 ) | ||
1016 | { | ||
1017 | size_type min_len = 0; | ||
1018 | if( src ) | ||
1019 | { | ||
1020 | min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ | ||
1021 | memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ | ||
1022 | } | ||
1023 | dst[min_len] = '\0'; | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | // static | ||
1028 | template<class T> | ||
1029 | void LLStringBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset) | ||
1030 | { | ||
1031 | llassert( offset <= dst.length() ); | ||
1032 | |||
1033 | // special case - append to end of string and avoid expensive (when strings are large) string manipulations | ||
1034 | if ( offset == dst.length() ) | ||
1035 | { | ||
1036 | dst += src; | ||
1037 | } | ||
1038 | else | ||
1039 | { | ||
1040 | LLWString tail = dst.substr(offset); | ||
1041 | |||
1042 | dst = dst.substr(0, offset); | ||
1043 | dst += src; | ||
1044 | dst += tail; | ||
1045 | }; | ||
1046 | } | ||
1047 | |||
1048 | // True if this is the head of s. | ||
1049 | //static | ||
1050 | template<class T> | ||
1051 | BOOL LLStringBase<T>::isHead( const std::basic_string<T>& string, const T* s ) | ||
1052 | { | ||
1053 | if( string.empty() ) | ||
1054 | { | ||
1055 | // Early exit | ||
1056 | return FALSE; | ||
1057 | } | ||
1058 | else | ||
1059 | { | ||
1060 | return (strncmp( s, string.c_str(), string.size() ) == 0); | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | //static | ||
1065 | template<class T> | ||
1066 | BOOL LLStringBase<T>::read(std::basic_string<T>& string, const char* filename) /*Flawfinder: ignore*/ | ||
1067 | { | ||
1068 | #ifdef LL_LINUX | ||
1069 | printf("STUBBED: LLStringBase<T>::read at %s:%d\n", __FILE__, __LINE__); | ||
1070 | #else | ||
1071 | llifstream ifs(filename, llifstream::binary); | ||
1072 | if (!ifs.is_open()) | ||
1073 | { | ||
1074 | llinfos << "Unable to open file" << filename << llendl; | ||
1075 | return FALSE; | ||
1076 | } | ||
1077 | |||
1078 | std::basic_ostringstream<T> oss; | ||
1079 | |||
1080 | oss << ifs.rdbuf(); | ||
1081 | |||
1082 | string = oss.str(); | ||
1083 | |||
1084 | ifs.close(); | ||
1085 | #endif | ||
1086 | return TRUE; | ||
1087 | } | ||
1088 | |||
1089 | //static | ||
1090 | template<class T> | ||
1091 | BOOL LLStringBase<T>::write(std::basic_string<T>& string, const char* filename) | ||
1092 | { | ||
1093 | #ifdef LL_LINUX | ||
1094 | printf("STUBBED: LLStringBase<T>::write at %s:%d\n", __FILE__, __LINE__); | ||
1095 | #else | ||
1096 | llofstream ofs(filename, llofstream::binary); | ||
1097 | if (!ofs.is_open()) | ||
1098 | { | ||
1099 | llinfos << "Unable to open file" << filename << llendl; | ||
1100 | return FALSE; | ||
1101 | } | ||
1102 | |||
1103 | ofs << string; | ||
1104 | |||
1105 | ofs.close(); | ||
1106 | #endif | ||
1107 | return TRUE; | ||
1108 | } | ||
1109 | |||
1110 | template<class T> | ||
1111 | BOOL LLStringBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value) | ||
1112 | { | ||
1113 | if( string.empty() ) | ||
1114 | { | ||
1115 | return FALSE; | ||
1116 | } | ||
1117 | |||
1118 | LLStringBase<T> temp( string ); | ||
1119 | trim(temp); | ||
1120 | if( | ||
1121 | (temp == "1") || | ||
1122 | (temp == "T") || | ||
1123 | (temp == "t") || | ||
1124 | (temp == "TRUE") || | ||
1125 | (temp == "true") || | ||
1126 | (temp == "True") ) | ||
1127 | { | ||
1128 | value = TRUE; | ||
1129 | return TRUE; | ||
1130 | } | ||
1131 | else | ||
1132 | if( | ||
1133 | (temp == "0") || | ||
1134 | (temp == "F") || | ||
1135 | (temp == "f") || | ||
1136 | (temp == "FALSE") || | ||
1137 | (temp == "false") || | ||
1138 | (temp == "False") ) | ||
1139 | { | ||
1140 | value = FALSE; | ||
1141 | return TRUE; | ||
1142 | } | ||
1143 | |||
1144 | return FALSE; | ||
1145 | } | ||
1146 | |||
1147 | template<class T> | ||
1148 | BOOL LLStringBase<T>::convertToU8(const std::basic_string<T>& string, U8& value) | ||
1149 | { | ||
1150 | S32 value32 = 0; | ||
1151 | BOOL success = convertToS32(string, value32); | ||
1152 | if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) | ||
1153 | { | ||
1154 | value = (U8) value32; | ||
1155 | return TRUE; | ||
1156 | } | ||
1157 | return FALSE; | ||
1158 | } | ||
1159 | |||
1160 | template<class T> | ||
1161 | BOOL LLStringBase<T>::convertToS8(const std::basic_string<T>& string, S8& value) | ||
1162 | { | ||
1163 | S32 value32 = 0; | ||
1164 | BOOL success = convertToS32(string, value32); | ||
1165 | if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) | ||
1166 | { | ||
1167 | value = (S8) value32; | ||
1168 | return TRUE; | ||
1169 | } | ||
1170 | return FALSE; | ||
1171 | } | ||
1172 | |||
1173 | template<class T> | ||
1174 | BOOL LLStringBase<T>::convertToS16(const std::basic_string<T>& string, S16& value) | ||
1175 | { | ||
1176 | S32 value32 = 0; | ||
1177 | BOOL success = convertToS32(string, value32); | ||
1178 | if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) | ||
1179 | { | ||
1180 | value = (S16) value32; | ||
1181 | return TRUE; | ||
1182 | } | ||
1183 | return FALSE; | ||
1184 | } | ||
1185 | |||
1186 | template<class T> | ||
1187 | BOOL LLStringBase<T>::convertToU16(const std::basic_string<T>& string, U16& value) | ||
1188 | { | ||
1189 | S32 value32 = 0; | ||
1190 | BOOL success = convertToS32(string, value32); | ||
1191 | if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) | ||
1192 | { | ||
1193 | value = (U16) value32; | ||
1194 | return TRUE; | ||
1195 | } | ||
1196 | return FALSE; | ||
1197 | } | ||
1198 | |||
1199 | template<class T> | ||
1200 | BOOL LLStringBase<T>::convertToU32(const std::basic_string<T>& string, U32& value) | ||
1201 | { | ||
1202 | if( string.empty() ) | ||
1203 | { | ||
1204 | return FALSE; | ||
1205 | } | ||
1206 | |||
1207 | LLStringBase<T> temp( string ); | ||
1208 | trim(temp); | ||
1209 | U32 v; | ||
1210 | std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); | ||
1211 | if(i_stream >> v) | ||
1212 | { | ||
1213 | //TODO: figure out overflow reporting here | ||
1214 | //if( ULONG_MAX == v ) | ||
1215 | //{ | ||
1216 | // // Underflow or overflow | ||
1217 | // return FALSE; | ||
1218 | //} | ||
1219 | |||
1220 | value = v; | ||
1221 | return TRUE; | ||
1222 | } | ||
1223 | return FALSE; | ||
1224 | } | ||
1225 | |||
1226 | template<class T> | ||
1227 | BOOL LLStringBase<T>::convertToS32(const std::basic_string<T>& string, S32& value) | ||
1228 | { | ||
1229 | if( string.empty() ) | ||
1230 | { | ||
1231 | return FALSE; | ||
1232 | } | ||
1233 | |||
1234 | LLStringBase<T> temp( string ); | ||
1235 | trim(temp); | ||
1236 | S32 v; | ||
1237 | std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); | ||
1238 | if(i_stream >> v) | ||
1239 | { | ||
1240 | //TODO: figure out overflow and underflow reporting here | ||
1241 | //if((LONG_MAX == v) || (LONG_MIN == v)) | ||
1242 | //{ | ||
1243 | // // Underflow or overflow | ||
1244 | // return FALSE; | ||
1245 | //} | ||
1246 | |||
1247 | value = v; | ||
1248 | return TRUE; | ||
1249 | } | ||
1250 | return FALSE; | ||
1251 | } | ||
1252 | |||
1253 | template<class T> | ||
1254 | BOOL LLStringBase<T>::convertToF32(const std::basic_string<T>& string, F32& value) | ||
1255 | { | ||
1256 | F64 value64 = 0.0; | ||
1257 | BOOL success = convertToF64(string, value64); | ||
1258 | if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) | ||
1259 | { | ||
1260 | value = (F32) value64; | ||
1261 | return TRUE; | ||
1262 | } | ||
1263 | return FALSE; | ||
1264 | } | ||
1265 | |||
1266 | template<class T> | ||
1267 | BOOL LLStringBase<T>::convertToF64(const std::basic_string<T>& string, F64& value) | ||
1268 | { | ||
1269 | if( string.empty() ) | ||
1270 | { | ||
1271 | return FALSE; | ||
1272 | } | ||
1273 | |||
1274 | LLStringBase<T> temp( string ); | ||
1275 | trim(temp); | ||
1276 | F64 v; | ||
1277 | std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); | ||
1278 | if(i_stream >> v) | ||
1279 | { | ||
1280 | //TODO: figure out overflow and underflow reporting here | ||
1281 | //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) | ||
1282 | //{ | ||
1283 | // // Underflow or overflow | ||
1284 | // return FALSE; | ||
1285 | //} | ||
1286 | |||
1287 | value = v; | ||
1288 | return TRUE; | ||
1289 | } | ||
1290 | return FALSE; | ||
1291 | } | ||
1292 | |||
1293 | template<class T> | ||
1294 | void LLStringBase<T>::truncate(std::basic_string<T>& string, size_type count) | ||
1295 | { | ||
1296 | size_type cur_size = string.size(); | ||
1297 | string.resize(count < cur_size ? count : cur_size); | ||
1298 | } | ||
1299 | |||
1300 | #endif // LL_STRING_H | ||