]> git.lizzy.rs Git - irrlicht.git/blob - include/irrString.h
Drop IrrCompileConfig (#163)
[irrlicht.git] / include / irrString.h
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine" and the "irrXML" project.\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h\r
4 \r
5 #ifndef __IRR_STRING_H_INCLUDED__\r
6 #define __IRR_STRING_H_INCLUDED__\r
7 \r
8 #include "irrTypes.h"\r
9 #include <string>\r
10 #include <algorithm>\r
11 #include <cstdio>\r
12 #include <cstring>\r
13 #include <cwchar>\r
14 \r
15 namespace irr\r
16 {\r
17 namespace core\r
18 {\r
19 \r
20 //! Very simple string class with some useful features.\r
21 /** string<c8> and string<wchar_t> both accept Unicode AND ASCII/Latin-1,\r
22 so you can assign Unicode to string<c8> and ASCII/Latin-1 to string<wchar_t>\r
23 (and the other way round) if you want to.\r
24 \r
25 However, note that the conversation between both is not done using any encoding.\r
26 This means that c8 strings are treated as ASCII/Latin-1, not UTF-8, and\r
27 are simply expanded to the equivalent wchar_t, while Unicode/wchar_t\r
28 characters are truncated to 8-bit ASCII/Latin-1 characters, discarding all\r
29 other information in the wchar_t.\r
30 \r
31 Helper functions for converting between UTF-8 and wchar_t are provided\r
32 outside the string class for explicit use.\r
33 */\r
34 \r
35 // forward declarations\r
36 template <typename T>\r
37 class string;\r
38 static size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize);\r
39 static size_t wStringToMultibyte(string<c8>& destination, const wchar_t* source, u32 sourceSize);\r
40 \r
41 //! Returns a character converted to lower case\r
42 static inline u32 locale_lower ( u32 x )\r
43 {\r
44         // ansi\r
45         return x >= 'A' && x <= 'Z' ? x + 0x20 : x;\r
46 }\r
47 \r
48 //! Returns a character converted to upper case\r
49 static inline u32 locale_upper ( u32 x )\r
50 {\r
51         // ansi\r
52         return x >= 'a' && x <= 'z' ? x + ( 'A' - 'a' ) : x;\r
53 }\r
54 \r
55 \r
56 template <typename T>\r
57 class string\r
58 {\r
59 public:\r
60 \r
61         typedef T char_type;\r
62 \r
63         //! Default constructor\r
64         string()\r
65         {}\r
66 \r
67 \r
68         //! Copy constructor\r
69         string(const string<T>& other)\r
70         {\r
71                 *this = other;\r
72         }\r
73 \r
74         //! Constructor from other string types\r
75         template <class B>\r
76         string(const string<B>& other)\r
77         {\r
78                 *this = other;\r
79         }\r
80 \r
81 \r
82         //! Constructs a string from a float\r
83         explicit string(const double number)\r
84         {\r
85                 c8 tmpbuf[32];\r
86                 snprintf_irr(tmpbuf, sizeof(tmpbuf), "%0.6f", number);\r
87                 str = tmpbuf;\r
88         }\r
89 \r
90 \r
91         //! Constructs a string from an int\r
92         explicit string(int number)\r
93         {\r
94                 str = std::to_string(number);\r
95         }\r
96 \r
97 \r
98         //! Constructs a string from an unsigned int\r
99         explicit string(unsigned int number)\r
100         {\r
101                 str = std::to_string(number);\r
102         }\r
103 \r
104 \r
105         //! Constructs a string from a long\r
106         explicit string(long number)\r
107         {\r
108                 str = std::to_string(number);\r
109         }\r
110 \r
111 \r
112         //! Constructs a string from an unsigned long\r
113         explicit string(unsigned long number)\r
114         {\r
115                 str = std::to_string(number);\r
116         }\r
117 \r
118 \r
119         //! Constructor for copying a string from a pointer with a given length\r
120         template <class B>\r
121         string(const B* const c, u32 length)\r
122         {\r
123                 if (!c)\r
124                         return;\r
125 \r
126                 str.resize(length);\r
127                 for (u32 l = 0; l<length; ++l)\r
128                         str[l] = (T)c[l];\r
129         }\r
130 \r
131 \r
132         //! Constructor for Unicode and ASCII strings\r
133         template <class B>\r
134         string(const B* const c)\r
135         {\r
136                 *this = c;\r
137         }\r
138 \r
139 \r
140         //! Destructor\r
141         ~string()\r
142         {}\r
143 \r
144 \r
145         //! Assignment operator\r
146         string<T>& operator=(const string<T>& other)\r
147         {\r
148                 if (this == &other)\r
149                         return *this;\r
150 \r
151                 str = other.str;\r
152                 return *this;\r
153         }\r
154 \r
155         //! Assignment operator for other string types\r
156         template <class B>\r
157         string<T>& operator=(const string<B>& other)\r
158         {\r
159                 *this = other.c_str();\r
160                 return *this;\r
161         }\r
162 \r
163 \r
164         //! Assignment operator for strings, ASCII and Unicode\r
165         template <class B>\r
166         string<T>& operator=(const B* const c)\r
167         {\r
168                 if (!c)\r
169                 {\r
170                         clear();\r
171                         return *this;\r
172                 }\r
173 \r
174                 // no longer allowed!\r
175                 _IRR_DEBUG_BREAK_IF((void*)c == (void*)c_str());\r
176 \r
177                 u32 len = calclen(c);\r
178                 str.resize(len);\r
179                 for (u32 l = 0; l<len; ++l)\r
180                         str[l] = (T)c[l];\r
181 \r
182                 return *this;\r
183         }\r
184 \r
185 \r
186         //! Append operator for other strings\r
187         string<T> operator+(const string<T>& other) const\r
188         {\r
189                 string<T> tmp(*this);\r
190                 tmp.append(other);\r
191 \r
192                 return tmp;\r
193         }\r
194 \r
195 \r
196         //! Append operator for strings, ASCII and Unicode\r
197         template <class B>\r
198         string<T> operator+(const B* const c) const\r
199         {\r
200                 string<T> tmp(*this);\r
201                 tmp.append(c);\r
202 \r
203                 return tmp;\r
204         }\r
205 \r
206 \r
207         //! Direct access operator\r
208         T& operator [](const u32 index)\r
209         {\r
210                 return str[index];\r
211         }\r
212 \r
213 \r
214         //! Direct access operator\r
215         const T& operator [](const u32 index) const\r
216         {\r
217                 return str[index];\r
218         }\r
219 \r
220 \r
221         //! Equality operator\r
222         bool operator==(const T* const other) const\r
223         {\r
224                 if (!other)\r
225                         return false;\r
226                 return !cmp(c_str(), other);\r
227         }\r
228 \r
229 \r
230         //! Equality operator\r
231         bool operator==(const string<T>& other) const\r
232         {\r
233                 return str == other.str;\r
234         }\r
235 \r
236 \r
237         //! Is smaller comparator\r
238         bool operator<(const string<T>& other) const\r
239         {\r
240                 return str < other.str;\r
241         }\r
242 \r
243 \r
244         //! Inequality operator\r
245         bool operator!=(const T* const other) const\r
246         {\r
247                 return !(*this == other);\r
248         }\r
249 \r
250 \r
251         //! Inequality operator\r
252         bool operator!=(const string<T>& other) const\r
253         {\r
254                 return !(*this == other);\r
255         }\r
256 \r
257 \r
258         //! Returns length of the string's content\r
259         /** \return Length of the string's content in characters, excluding\r
260         the trailing NUL. */\r
261         u32 size() const\r
262         {\r
263                 return str.size();\r
264         }\r
265 \r
266         //! Informs if the string is empty or not.\r
267         //! \return True if the string is empty, false if not.\r
268         bool empty() const\r
269         {\r
270                 return str.empty();\r
271         }\r
272 \r
273         void clear(bool releaseMemory=true)\r
274         {\r
275                 if (releaseMemory) {\r
276                         stl_type empty;\r
277                         std::swap(str, empty);\r
278                 } else {\r
279                         str.clear();\r
280                 }\r
281         }\r
282 \r
283         //! Returns character string\r
284         /** \return pointer to C-style NUL terminated string. */\r
285         const T* c_str() const\r
286         {\r
287                 return str.c_str();\r
288         }\r
289 \r
290 \r
291         //! Makes the string lower case.\r
292         string<T>& make_lower()\r
293         {\r
294                 std::transform(str.begin(), str.end(), str.begin(), [](const T& c) {\r
295                         return locale_lower(c);\r
296                 });\r
297                 return *this;\r
298         }\r
299 \r
300 \r
301         //! Makes the string upper case.\r
302         string<T>& make_upper()\r
303         {\r
304                 std::transform(str.begin(), str.end(), str.begin(), [](const T& c) {\r
305                         return locale_upper(c);\r
306                 });\r
307                 return *this;\r
308         }\r
309 \r
310 \r
311         //! Compares the strings ignoring case.\r
312         /** \param other: Other string to compare.\r
313         \return True if the strings are equal ignoring case. */\r
314         bool equals_ignore_case(const string<T>& other) const\r
315         {\r
316                 const T* array = c_str();\r
317                 for(u32 i=0; array[i] && other[i]; ++i)\r
318                         if (locale_lower(array[i]) != locale_lower(other[i]))\r
319                                 return false;\r
320 \r
321                 return size() == other.size();\r
322         }\r
323 \r
324         //! Compares the strings ignoring case.\r
325         /** \param other: Other string to compare.\r
326                 \param sourcePos: where to start to compare in the string\r
327         \return True if the strings are equal ignoring case. */\r
328         bool equals_substring_ignore_case(const string<T>&other, const u32 sourcePos = 0 ) const\r
329         {\r
330                 if ( sourcePos >= size() + 1 )\r
331                         return false;\r
332 \r
333                 const T* array = c_str();\r
334                 u32 i;\r
335                 for(i=0; array[sourcePos + i] && other[i]; ++i)\r
336                         if (locale_lower(array[sourcePos + i]) != locale_lower(other[i]))\r
337                                 return false;\r
338 \r
339                 return array[sourcePos + i] == 0 && other[i] == 0;\r
340         }\r
341 \r
342 \r
343         //! Compares the strings ignoring case.\r
344         /** \param other: Other string to compare.\r
345         \return True if this string is smaller ignoring case. */\r
346         bool lower_ignore_case(const string<T>& other) const\r
347         {\r
348                 const T* array = c_str();\r
349                 for(u32 i=0; array[i] && other[i]; ++i)\r
350                 {\r
351                         s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other[i] );\r
352                         if ( diff )\r
353                                 return diff < 0;\r
354                 }\r
355 \r
356                 return size() < other.size();\r
357         }\r
358 \r
359 \r
360         //! compares the first n characters of the strings\r
361         /** \param other Other string to compare.\r
362         \param n Number of characters to compare\r
363         \return True if the n first characters of both strings are equal. */\r
364         bool equalsn(const string<T>& other, u32 n) const\r
365         {\r
366                 const T* array = c_str();\r
367                 u32 i;\r
368                 for(i=0; i < n && array[i] && other[i]; ++i)\r
369                         if (array[i] != other[i])\r
370                                 return false;\r
371 \r
372                 // if one (or both) of the strings was smaller then they\r
373                 // are only equal if they have the same length\r
374                 return (i == n) || (size() == other.size());\r
375         }\r
376 \r
377 \r
378         //! compares the first n characters of the strings\r
379         /** \param str Other string to compare.\r
380         \param n Number of characters to compare\r
381         \return True if the n first characters of both strings are equal. */\r
382         bool equalsn(const T* const other, u32 n) const\r
383         {\r
384                 if (!other)\r
385                         return false;\r
386                 const T* array = c_str();\r
387                 u32 i;\r
388                 for(i=0; i < n && array[i] && other[i]; ++i)\r
389                         if (array[i] != other[i])\r
390                                 return false;\r
391 \r
392                 // if one (or both) of the strings was smaller then they\r
393                 // are only equal if they have the same length\r
394                 return (i == n) || (array[i] == 0 && other[i] == 0);\r
395         }\r
396 \r
397 \r
398         //! Appends a character to this string\r
399         /** \param character: Character to append. */\r
400         string<T>& append(T character)\r
401         {\r
402                 str.append(1, character);\r
403                 return *this;\r
404         }\r
405 \r
406 \r
407         //! Appends a char string to this string\r
408         /** \param other: Char string to append. */\r
409         /** \param length: The length of the string to append. */\r
410         string<T>& append(const T* const other, u32 length=0xffffffff)\r
411         {\r
412                 if (!other)\r
413                         return *this;\r
414 \r
415                 u32 len = calclen(other);\r
416                 if (len > length)\r
417                         len = length;\r
418 \r
419                 str.append(other, len);\r
420                 return *this;\r
421         }\r
422 \r
423 \r
424         //! Appends a string to this string\r
425         /** \param other: String to append. */\r
426         string<T>& append(const string<T>& other)\r
427         {\r
428                 str.append(other.str);\r
429                 return *this;\r
430         }\r
431 \r
432 \r
433         //! Appends a string of the length l to this string.\r
434         /** \param other: other String to append to this string.\r
435         \param length: How much characters of the other string to add to this one. */\r
436         string<T>& append(const string<T>& other, u32 length)\r
437         {\r
438                 if (other.size() < length)\r
439                         append(other);\r
440                 else\r
441                         str.append(other.c_str(), length);\r
442                 return *this;\r
443         }\r
444 \r
445         //! Insert a certain amount of characters into the string before the given index\r
446         //\param pos Insert the characters before this index\r
447         //\param s String to insert. Must be at least of size n\r
448         //\param n Number of characters from string s to use.\r
449         string<T>& insert(u32 pos, const T* s, u32 n)\r
450         {\r
451                 if ( pos < size()+1 )\r
452                 {\r
453                         str.insert(pos, s, n);\r
454                 }\r
455 \r
456                 return *this;\r
457         }\r
458 \r
459         //! Reserves some memory.\r
460         /** \param count: Amount of characters to reserve, including\r
461         the trailing NUL. */\r
462         void reserve(u32 count)\r
463         {\r
464                 if (count == 0)\r
465                         return;\r
466                 str.reserve(count - 1);\r
467         }\r
468 \r
469 \r
470         //! finds first occurrence of character in string\r
471         /** \param c: Character to search for.\r
472         \return Position where the character has been found,\r
473         or -1 if not found. */\r
474         s32 findFirst(T c) const\r
475         {\r
476                 auto r = str.find(c);\r
477                 return pos_from_stl(r);\r
478         }\r
479 \r
480         //! finds first occurrence of a character of a list in string\r
481         /** \param c: List of characters to find. For example if the method\r
482         should find the first occurrence of 'a' or 'b', this parameter should be "ab".\r
483         \param count: Amount of characters in the list. Usually,\r
484         this should be strlen(c)\r
485         \return Position where one of the characters has been found,\r
486         or -1 if not found. */\r
487         s32 findFirstChar(const T* const c, u32 count=1) const\r
488         {\r
489                 if (!c || !count)\r
490                         return -1;\r
491 \r
492                 auto r = str.find_first_of(c, 0, count);\r
493                 return pos_from_stl(r);\r
494         }\r
495 \r
496 \r
497         //! Finds first position of a character not in a given list.\r
498         /** \param c: List of characters not to find. For example if the method\r
499         should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".\r
500         \param count: Amount of characters in the list. Usually,\r
501         this should be strlen(c)\r
502         \return Position where the character has been found,\r
503         or -1 if not found. */\r
504         s32 findFirstCharNotInList(const T* const c, u32 count=1) const\r
505         {\r
506                 if (!c || !count)\r
507                         return -1;\r
508 \r
509                 auto r = str.find_first_not_of(c, 0, count);\r
510                 return pos_from_stl(r);\r
511         }\r
512 \r
513         //! Finds last position of a character not in a given list.\r
514         /** \param c: List of characters not to find. For example if the method\r
515         should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".\r
516         \param count: Amount of characters in the list. Usually,\r
517         this should be strlen(c)\r
518         \return Position where the character has been found,\r
519         or -1 if not found. */\r
520         s32 findLastCharNotInList(const T* const c, u32 count=1) const\r
521         {\r
522                 if (!c || !count)\r
523                         return -1;\r
524 \r
525                 auto r = str.find_last_not_of(c, npos, count);\r
526                 return pos_from_stl(r);\r
527         }\r
528 \r
529         //! finds next occurrence of character in string\r
530         /** \param c: Character to search for.\r
531         \param startPos: Position in string to start searching.\r
532         \return Position where the character has been found,\r
533         or -1 if not found. */\r
534         s32 findNext(T c, u32 startPos) const\r
535         {\r
536                 auto r = str.find(c, startPos);\r
537                 return pos_from_stl(r);\r
538         }\r
539 \r
540 \r
541         //! finds last occurrence of character in string\r
542         /** \param c: Character to search for.\r
543         \param start: start to search reverse ( default = -1, on end )\r
544         \return Position where the character has been found,\r
545         or -1 if not found. */\r
546         s32 findLast(T c, s32 start = -1) const\r
547         {\r
548                 auto r = str.rfind(c, pos_to_stl(start));\r
549                 return pos_from_stl(r);\r
550         }\r
551 \r
552         //! finds last occurrence of a character of a list in string\r
553         /** \param c: List of strings to find. For example if the method\r
554         should find the last occurrence of 'a' or 'b', this parameter should be "ab".\r
555         \param count: Amount of characters in the list. Usually,\r
556         this should be strlen(c)\r
557         \return Position where one of the characters has been found,\r
558         or -1 if not found. */\r
559         s32 findLastChar(const T* const c, u32 count=1) const\r
560         {\r
561                 if (!c || !count)\r
562                         return -1;\r
563 \r
564                 auto r = str.find_last_of(c, npos, count);\r
565                 return pos_from_stl(r);\r
566         }\r
567 \r
568 \r
569         //! finds another string in this string\r
570         /** \param str: Another string\r
571         \param start: Start position of the search\r
572         \return Positions where the string has been found,\r
573         or -1 if not found. */\r
574         s32 find(const T* const other, const u32 start = 0) const\r
575         {\r
576                 if (other && *other)\r
577                 {\r
578                         auto r = str.find(other, start);\r
579                         return pos_from_stl(r);\r
580                 }\r
581 \r
582                 return -1;\r
583         }\r
584 \r
585 \r
586         //! Returns a substring\r
587         /** \param begin Start of substring.\r
588         \param length Length of substring.\r
589         \param make_lower copy only lower case */\r
590         string<T> subString(u32 begin, s32 length, bool make_lower = false ) const\r
591         {\r
592                 // if start after string\r
593                 // or no proper substring length\r
594                 if ((length <= 0) || (begin>=size()))\r
595                         return string<T>("");\r
596 \r
597                 string<T> o = str.substr(begin, length);\r
598                 if (make_lower)\r
599                         o.make_lower();\r
600                 return o;\r
601         }\r
602 \r
603 \r
604         //! Appends a character to this string\r
605         /** \param c Character to append. */\r
606         string<T>& operator += (T c)\r
607         {\r
608                 append(c);\r
609                 return *this;\r
610         }\r
611 \r
612 \r
613         //! Appends a char string to this string\r
614         /** \param c Char string to append. */\r
615         string<T>& operator += (const T* const c)\r
616         {\r
617                 append(c);\r
618                 return *this;\r
619         }\r
620 \r
621 \r
622         //! Appends a string to this string\r
623         /** \param other String to append. */\r
624         string<T>& operator += (const string<T>& other)\r
625         {\r
626                 append(other);\r
627                 return *this;\r
628         }\r
629 \r
630 \r
631         //! Appends a string representation of a number to this string\r
632         /** \param i Number to append. */\r
633         string<T>& operator += (const int i)\r
634         {\r
635                 append(string<T>(i));\r
636                 return *this;\r
637         }\r
638 \r
639 \r
640         //! Appends a string representation of a number to this string\r
641         /** \param i Number to append. */\r
642         string<T>& operator += (const unsigned int i)\r
643         {\r
644                 append(string<T>(i));\r
645                 return *this;\r
646         }\r
647 \r
648 \r
649         //! Appends a string representation of a number to this string\r
650         /** \param i Number to append. */\r
651         string<T>& operator += (const long i)\r
652         {\r
653                 append(string<T>(i));\r
654                 return *this;\r
655         }\r
656 \r
657 \r
658         //! Appends a string representation of a number to this string\r
659         /** \param i Number to append. */\r
660         string<T>& operator += (const unsigned long i)\r
661         {\r
662                 append(string<T>(i));\r
663                 return *this;\r
664         }\r
665 \r
666 \r
667         //! Appends a string representation of a number to this string\r
668         /** \param i Number to append. */\r
669         string<T>& operator += (const double i)\r
670         {\r
671                 append(string<T>(i));\r
672                 return *this;\r
673         }\r
674 \r
675 \r
676         //! Appends a string representation of a number to this string\r
677         /** \param i Number to append. */\r
678         string<T>& operator += (const float i)\r
679         {\r
680                 append(string<T>(i));\r
681                 return *this;\r
682         }\r
683 \r
684 \r
685         //! Replaces all characters of a special type with another one\r
686         /** \param toReplace Character to replace.\r
687         \param replaceWith Character replacing the old one. */\r
688         string<T>& replace(T toReplace, T replaceWith)\r
689         {\r
690                 std::replace(str.begin(), str.end(), toReplace, replaceWith);\r
691                 return *this;\r
692         }\r
693 \r
694 \r
695         //! Replaces all instances of a string with another one.\r
696         /** \param toReplace The string to replace.\r
697         \param replaceWith The string replacing the old one. */\r
698         string<T>& replace(const string<T>& toReplace, const string<T>& replaceWith)\r
699         {\r
700                 size_type pos = 0;\r
701             while ((pos = str.find(toReplace.str, pos)) != npos) {\r
702                  str.replace(pos, toReplace.size(), replaceWith.str);\r
703                  pos += replaceWith.size();\r
704             }\r
705 \r
706                 return *this;\r
707         }\r
708 \r
709 \r
710         //! Removes a character from a string.\r
711         /** \param c: Character to remove. */\r
712         string<T>& remove(T c)\r
713         {\r
714                 str.erase(std::remove(str.begin(), str.end(), c), str.end());\r
715                 return *this;\r
716         }\r
717 \r
718 \r
719         //! Removes a string from the string.\r
720         /** \param toRemove: String to remove. */\r
721         string<T>& remove(const string<T>& toRemove)\r
722         {\r
723                 u32 size = toRemove.size();\r
724                 if ( size == 0 )\r
725                         return *this;\r
726                 u32 pos = 0;\r
727                 u32 found = 0;\r
728                 for (u32 i=0; i<str.size(); ++i)\r
729                 {\r
730                         u32 j = 0;\r
731                         while (j < size)\r
732                         {\r
733                                 if (str[i + j] != toRemove[j])\r
734                                         break;\r
735                                 ++j;\r
736                         }\r
737                         if (j == size)\r
738                         {\r
739                                 found += size;\r
740                                 i += size - 1;\r
741                                 continue;\r
742                         }\r
743 \r
744                         str[pos++] = str[i];\r
745                 }\r
746                 str.resize(str.size() - found);\r
747                 return *this;\r
748         }\r
749 \r
750 \r
751         //! Removes characters from a string.\r
752         /** \param characters: Characters to remove. */\r
753         string<T>& removeChars(const string<T> & characters)\r
754         {\r
755                 if (characters.size() == 0)\r
756                         return *this;\r
757 \r
758                 for (u32 i = 0; i < characters.size(); i++)\r
759                         remove(characters[i]);\r
760                 return *this;\r
761         }\r
762 \r
763 \r
764         //! Trims the string.\r
765         /** Removes the specified characters (by default, Latin-1 whitespace)\r
766         from the beginning and the end of the string. */\r
767         string<T>& trim(const string<T> & whitespace = " \t\n\r")\r
768         {\r
769                 // find start and end of the substring without the specified characters\r
770                 const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.size());\r
771                 if (begin == -1)\r
772                         return (*this="");\r
773 \r
774                 const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.size());\r
775 \r
776                 return (*this = subString(begin, (end +1) - begin));\r
777         }\r
778 \r
779         //! Erases a character from the string.\r
780         /** May be slow, because all elements\r
781         following after the erased element have to be copied.\r
782         \param index: Index of element to be erased. */\r
783         string<T>& erase(u32 index)\r
784         {\r
785                 str.erase(str.begin() + index);\r
786                 return *this;\r
787         }\r
788 \r
789         //! verify the existing string.\r
790         string<T>& validate()\r
791         {\r
792                 // truncate to existing null\r
793                 u32 len = calclen(c_str());\r
794                 if (len != size())\r
795                         str.resize(len);\r
796 \r
797                 return *this;\r
798         }\r
799 \r
800         //! gets the last char of a string or null\r
801         T lastChar() const\r
802         {\r
803                 return !str.empty() ? str.back() : 0;\r
804         }\r
805 \r
806         //! Split string into parts (tokens).\r
807         /** This method will split a string at certain delimiter characters\r
808         into the container passed in as reference. The type of the container\r
809         has to be given as template parameter. It must provide a push_back and\r
810         a size method.\r
811         \param ret The result container. Tokens are added, the container is not cleared.\r
812         \param delimiter C-style string of delimiter characters\r
813         \param countDelimiters Number of delimiter characters\r
814         \param ignoreEmptyTokens Flag to avoid empty substrings in the result\r
815         container. If two delimiters occur without a character in between or an\r
816         empty substring would be placed in the result. Or if a delimiter is the last\r
817         character an empty substring would be added at the end. If this flag is set,\r
818         only non-empty strings are stored.\r
819         \param keepSeparators Flag which allows to add the separator to the\r
820         result string. If this flag is true, the concatenation of the\r
821         substrings results in the original string. Otherwise, only the\r
822         characters between the delimiters are returned.\r
823         \return The number of resulting substrings\r
824         */\r
825         template<class container>\r
826         u32 split(container& ret, const T* const delimiter, u32 countDelimiters=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const\r
827         {\r
828                 if (!delimiter)\r
829                         return 0;\r
830 \r
831                 const u32 oldSize=ret.size();\r
832 \r
833                 u32 tokenStartIdx = 0;\r
834                 for (u32 i=0; i<size()+1; ++i)\r
835                 {\r
836                         for (u32 j=0; j<countDelimiters; ++j)\r
837                         {\r
838                                 if (str[i] == delimiter[j])\r
839                                 {\r
840                                         if (i - tokenStartIdx > 0)\r
841                                                 ret.push_back(string<T>(&str[tokenStartIdx], i - tokenStartIdx));\r
842                                         else if ( !ignoreEmptyTokens )\r
843                                                 ret.push_back(string<T>());\r
844                                         if ( keepSeparators )\r
845                                         {\r
846                                                 ret.push_back(string<T>(&str[i], 1));\r
847                                         }\r
848 \r
849                                         tokenStartIdx = i+1;\r
850                                         break;\r
851                                 }\r
852                         }\r
853                 }\r
854                 if (size() > tokenStartIdx)\r
855                         ret.push_back(string<T>(&str[tokenStartIdx], size() - tokenStartIdx));\r
856                 else if (!ignoreEmptyTokens)\r
857                         ret.push_back(string<T>());\r
858 \r
859                 return ret.size()-oldSize;\r
860         }\r
861 \r
862         friend size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize);\r
863         friend size_t wStringToMultibyte(string<c8>& destination, const wchar_t* source, u32 sourceSize);\r
864 \r
865 private:\r
866 \r
867         typedef std::basic_string<T> stl_type;\r
868 \r
869         //! Private constructor\r
870         string(stl_type &&str) : str(str)\r
871         {}\r
872 \r
873         //! strlen wrapper\r
874         template <typename U>\r
875         static inline u32 calclen(const U* p) {\r
876                 u32 len = 0;\r
877                 while (*p++)\r
878                         len++;\r
879                 return len;\r
880         }\r
881         static inline u32 calclen(const char* p) {\r
882                 return strlen(p);\r
883         }\r
884         static inline u32 calclen(const wchar_t* p) {\r
885                 return wcslen(p);\r
886         }\r
887 \r
888         //! strcmp wrapper\r
889         template <typename U>\r
890         static inline int cmp(const U* p, const U* p2) {\r
891                 while (*p && *p == *p2)\r
892                         p++, p2++;\r
893                 return (int)*p - (int)*p2;\r
894         }\r
895         static inline int cmp(const char* p, const char* p2) {\r
896                 return strcmp(p, p2);\r
897         }\r
898         static inline int cmp(const wchar_t* p, const wchar_t* p2) {\r
899                 return wcscmp(p, p2);\r
900         }\r
901 \r
902         typedef typename stl_type::size_type size_type;\r
903         static const size_type npos = stl_type::npos;\r
904 \r
905         static inline s32 pos_from_stl(size_type pos) {\r
906                 return pos == npos ? -1 : (s32)pos;\r
907         }\r
908         static inline size_type pos_to_stl(s32 pos) {\r
909                 return pos == -1 ? npos : (size_type)pos;\r
910         }\r
911 \r
912         stl_type str;\r
913 };\r
914 \r
915 \r
916 //! Typedef for character strings\r
917 typedef string<c8> stringc;\r
918 \r
919 //! Typedef for wide character strings\r
920 typedef string<wchar_t> stringw;\r
921 \r
922 //! Convert multibyte string to wide-character string\r
923 /** Wrapper around mbstowcs from standard library, but directly using Irrlicht string class.\r
924 What the function does exactly depends on the LC_CTYPE of the current c locale.\r
925 \param destination Wide-character string receiving the converted source\r
926 \param source multibyte string\r
927 \return The number of wide characters written to destination, not including the eventual terminating null character or -1 when conversion failed */\r
928 static inline size_t multibyteToWString(string<wchar_t>& destination, const core::string<c8>& source)\r
929 {\r
930         return multibyteToWString(destination, source.c_str(), (u32)source.size());\r
931 }\r
932 \r
933 //! Convert multibyte string to wide-character string\r
934 /** Wrapper around mbstowcs from standard library, but directly writing to Irrlicht string class.\r
935 What the function does exactly depends on the LC_CTYPE of the current c locale.\r
936 \param destination Wide-character string receiving the converted source\r
937 \param source multibyte string\r
938 \return The number of wide characters written to destination, not including the eventual terminating null character  or -1 when conversion failed. */\r
939 static inline size_t multibyteToWString(string<wchar_t>& destination, const char* source)\r
940 {\r
941         const u32 s = source ? (u32)strlen(source) : 0;\r
942         return multibyteToWString(destination, source, s);\r
943 }\r
944 \r
945 //! Internally used by the other multibyteToWString functions\r
946 static size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize)\r
947 {\r
948         if ( sourceSize )\r
949         {\r
950                 destination.str.resize(sourceSize+1);\r
951 #if defined(_MSC_VER)\r
952 #pragma warning(push)\r
953 #pragma warning(disable: 4996)  // 'mbstowcs': This function or variable may be unsafe. Consider using mbstowcs_s instead.\r
954 #endif\r
955                 const size_t written = mbstowcs(&destination[0], source, (size_t)sourceSize);\r
956 #if defined(_MSC_VER)\r
957 #pragma warning(pop)\r
958 #endif\r
959                 if ( written != (size_t)-1 )\r
960                 {\r
961                         destination.str.resize(written);\r
962                 }\r
963                 else\r
964                 {\r
965                         // Likely character which got converted until the invalid character was encountered are in destination now.\r
966                         // And it seems even 0-terminated, but I found no documentation anywhere that this (the 0-termination) is guaranteed :-(\r
967                         destination.clear();\r
968                 }\r
969                 return written;\r
970         }\r
971         else\r
972         {\r
973                 destination.clear();\r
974                 return 0;\r
975         }\r
976 }\r
977 \r
978 //! Same as multibyteToWString, but the other way around\r
979 static inline size_t wStringToMultibyte(string<c8>& destination, const core::string<wchar_t>& source)\r
980 {\r
981         return wStringToMultibyte(destination, source.c_str(), (u32)source.size());\r
982 }\r
983 \r
984 //! Same as multibyteToWString, but the other way around\r
985 static inline size_t wStringToMultibyte(string<c8>& destination, const wchar_t* source)\r
986 {\r
987         const u32 s = source ? (u32)wcslen(source) : 0;\r
988         return wStringToMultibyte(destination, source, s);\r
989 }\r
990 \r
991 //! Same as multibyteToWString, but the other way around\r
992 static size_t wStringToMultibyte(string<c8>& destination, const wchar_t* source, u32 sourceSize)\r
993 {\r
994         if ( sourceSize )\r
995         {\r
996                 destination.str.resize(sizeof(wchar_t)*sourceSize+1);\r
997 #if defined(_MSC_VER)\r
998 #pragma warning(push)\r
999 #pragma warning(disable: 4996)  // 'wcstombs': This function or variable may be unsafe. Consider using wcstombs_s instead.\r
1000 #endif\r
1001                 const size_t written = wcstombs(&destination[0], source, destination.size());\r
1002 #if defined(_MSC_VER)\r
1003 #pragma warning(pop)\r
1004 #endif\r
1005                 if ( written != (size_t)-1 )\r
1006                 {\r
1007                         destination.str.resize(written);\r
1008                 }\r
1009                 else\r
1010                 {\r
1011                         // Likely character which got converted until the invalid character was encountered are in destination now.\r
1012                         // And it seems even 0-terminated, but I found no documentation anywhere that this (the 0-termination) is guaranteed :-(\r
1013                         destination.clear();\r
1014                 }\r
1015                 return written;\r
1016         }\r
1017         else\r
1018         {\r
1019                 destination.clear();\r
1020                 return 0;\r
1021         }\r
1022 }\r
1023 \r
1024 \r
1025 } // end namespace core\r
1026 } // end namespace irr\r
1027 \r
1028 #endif\r
1029 \r