aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llstring.h
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llcommon/llstring.h')
-rw-r--r--linden/indra/llcommon/llstring.h1300
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
45const char LL_UNKNOWN_CHAR = '?';
46
47class LLVector3;
48class LLVector3d;
49class LLQuaternion;
50class LLUUID;
51class LLColor4;
52class 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)
56namespace std
57{
58template<>
59struct 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
145class LLStringOps
146{
147public:
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
182template <class T>
183class LLStringBase : public std::basic_string<T>
184{
185public:
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
236public:
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
327template<class T> LLStringBase<T> LLStringBase<T>::null;
328
329typedef LLStringBase<char> LLString;
330typedef LLStringBase<llwchar> LLWString;
331
332struct LLDictionaryLess
333{
334public:
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 */
354inline 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 */
365std::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 */
371U8 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.
381std::string rawstr_to_utf8(const std::string& raw);
382
383//
384// We should never use UTF16 except when communicating with Win32!
385//
386typedef std::basic_string<U16> llutf16string;
387
388LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
389LLWString utf16str_to_wstring(const llutf16string &utf16str);
390
391llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
392llutf16string wstring_to_utf16str(const LLWString &utf32str);
393
394llutf16string utf8str_to_utf16str ( const LLString& utf8str, S32 len);
395llutf16string utf8str_to_utf16str ( const LLString& utf8str );
396
397LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
398LLWString utf8str_to_wstring(const std::string &utf8str);
399// Same function, better name. JC
400inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
401
402// Special hack for llfilepicker.cpp:
403S32 utf16chars_to_utf8chars(const U16* inchars, char* outchars, S32* nchars8 = 0);
404S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar);
405S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
406
407//
408std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
409std::string wstring_to_utf8str(const LLWString &utf32str);
410
411std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
412std::string utf16str_to_utf8str(const llutf16string &utf16str);
413
414// Length of this UTF32 string in bytes when transformed to UTF8
415S32 wstring_utf8_length(const LLWString& wstr);
416
417// Length in bytes of this wide char in a UTF8 string
418S32 wchar_utf8_length(const llwchar wc);
419
420std::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 */
432std::string utf8str_truncate(const std::string& utf8str, const S32 max_len);
433
434std::string utf8str_trim(const std::string& utf8str);
435
436S32 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 */
447std::string utf8str_substChar(
448 const std::string& utf8str,
449 const llwchar target_char,
450 const llwchar replace_char);
451
452std::string utf8str_makeASCII(const std::string& utf8str);
453
454// Hack - used for evil notecards.
455std::string mbcsstring_makeASCII(const std::string& str);
456
457template <class T>
458std::ostream& operator<<(std::ostream &s, const LLStringBase<T> &str)
459{
460 s << ((std::basic_string<T>)str);
461 return s;
462}
463
464std::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 */
474namespace 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
526template<class T>
527S32 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
552template<class T>
553S32 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
578template<class T>
579S32 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
612template<class T>
613S32 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
654template<class T>
655BOOL 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
668template<class T>
669LLStringBase<T>::LLStringBase(const T* s ) : std::basic_string<T>()
670{
671 if (s) assign(s);
672}
673
674template<class T>
675LLStringBase<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
681template<class T>
682LLStringBase<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
695template<class T>
696LLStringBase<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
709template<class T>
710LLStringBase<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
723template<class T>
724LLStringBase<T>& LLStringBase<T>::assign(const LLStringBase<T>& s)
725{
726 std::basic_string<T>::assign(s);
727 return *this;
728}
729
730template<class T>
731LLStringBase<T>& LLStringBase<T>::assign(size_type n, const T& c)
732{
733 std::basic_string<T>::assign(n, c);
734 return *this;
735}
736
737template<class T>
738LLStringBase<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
747template<class T>
748LLStringBase<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
756template<class T>
757LLStringBase<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
767template<class T>
768void 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
781template<class T>
782void 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
795template<class T>
796void 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
810template<class T>
811void 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
829template<class T>
830void 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
870template<class T>
871void 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
891template<class T>
892void 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
904template<class T>
905void 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
924template<class T>
925void 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
950template<class T>
951BOOL 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
967template<class T>
968void 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
998template<class T>
999void 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
1012template<class T>
1013void 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
1028template<class T>
1029void 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
1050template<class T>
1051BOOL 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
1065template<class T>
1066BOOL 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
1090template<class T>
1091BOOL 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
1110template<class T>
1111BOOL 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
1147template<class T>
1148BOOL 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
1160template<class T>
1161BOOL 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
1173template<class T>
1174BOOL 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
1186template<class T>
1187BOOL 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
1199template<class T>
1200BOOL 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
1226template<class T>
1227BOOL 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
1253template<class T>
1254BOOL 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
1266template<class T>
1267BOOL 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
1293template<class T>
1294void 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