]> git.lizzy.rs Git - irrlicht.git/blob - include/irrString.h
Merging r6122 through r6127 from trunk to ogl-es branch
[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 "irrAllocator.h"\r
10 #include "irrMath.h"\r
11 #include <stdio.h>\r
12 #include <string.h>\r
13 #include <stdlib.h>\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, typename TAlloc = irrAllocator<T> >\r
37 class string;\r
38 static size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize);\r
39 inline s32 isdigit(s32 c);\r
40 \r
41 enum eLocaleID\r
42 {\r
43         IRR_LOCALE_ANSI = 0,\r
44         IRR_LOCALE_GERMAN = 1\r
45 };\r
46 \r
47 static eLocaleID locale_current = IRR_LOCALE_ANSI;\r
48 static inline void locale_set ( eLocaleID id )\r
49 {\r
50         locale_current = id;\r
51 }\r
52 \r
53 //! Returns a character converted to lower case\r
54 static inline u32 locale_lower ( u32 x )\r
55 {\r
56         switch ( locale_current )\r
57         {\r
58                 case IRR_LOCALE_GERMAN:\r
59                 case IRR_LOCALE_ANSI:\r
60                         break;\r
61         }\r
62         // ansi\r
63         return x >= 'A' && x <= 'Z' ? x + 0x20 : x;\r
64 }\r
65 \r
66 //! Returns a character converted to upper case\r
67 static inline u32 locale_upper ( u32 x )\r
68 {\r
69         switch ( locale_current )\r
70         {\r
71                 case IRR_LOCALE_GERMAN:\r
72                 case IRR_LOCALE_ANSI:\r
73                         break;\r
74         }\r
75 \r
76         // ansi\r
77         return x >= 'a' && x <= 'z' ? x + ( 'A' - 'a' ) : x;\r
78 }\r
79 \r
80 //! Convert this utf-8-encoded string to the platform's wchar.\r
81 /** The resulting string is always NULL-terminated and well-formed.\r
82 \param len The size of the output buffer in bytes.\r
83 */\r
84 IRRLICHT_API void utf8ToWchar(const char *in, wchar_t *out, const u64 len);\r
85 \r
86 //! Convert this wchar string to utf-8.\r
87 /** The resulting string is always NULL-terminated and well-formed.\r
88 \param len The size of the output buffer in bytes.\r
89 */\r
90 IRRLICHT_API void wcharToUtf8(const wchar_t *in, char *out, const u64 len);\r
91 \r
92 \r
93 template <typename T, typename TAlloc>\r
94 class string\r
95 {\r
96 public:\r
97 \r
98         typedef T char_type;\r
99 \r
100         //! Default constructor\r
101         string()\r
102         : array(0), allocated(1), used(1)\r
103         {\r
104                 array = allocator.allocate(1); // new T[1];\r
105                 array[0] = 0;\r
106         }\r
107 \r
108 \r
109         //! Constructor\r
110         string(const string<T,TAlloc>& other)\r
111         : array(0), allocated(0), used(0)\r
112         {\r
113                 *this = other;\r
114         }\r
115 \r
116         //! Constructor from other string types\r
117         template <class B, class A>\r
118         string(const string<B, A>& other)\r
119         : array(0), allocated(0), used(0)\r
120         {\r
121                 *this = other;\r
122         }\r
123 \r
124 \r
125         //! Constructs a string from a float\r
126         explicit string(const double number)\r
127         : array(0), allocated(0), used(0)\r
128         {\r
129                 c8 tmpbuf[255];\r
130                 snprintf_irr(tmpbuf, 255, "%0.6f", number);\r
131                 *this = tmpbuf;\r
132         }\r
133 \r
134 \r
135         //! Constructs a string from an int\r
136         explicit string(int number)\r
137         : array(0), allocated(0), used(0)\r
138         {\r
139                 // store if negative and make positive\r
140 \r
141                 bool negative = false;\r
142                 if (number < 0)\r
143                 {\r
144                         number *= -1;\r
145                         negative = true;\r
146                 }\r
147 \r
148                 // temporary buffer for 16 numbers\r
149 \r
150                 c8 tmpbuf[16]={0};\r
151                 u32 idx = 15;\r
152 \r
153                 // special case '0'\r
154 \r
155                 if (!number)\r
156                 {\r
157                         tmpbuf[14] = '0';\r
158                         *this = &tmpbuf[14];\r
159                         return;\r
160                 }\r
161 \r
162                 // add numbers\r
163 \r
164                 while(number && idx)\r
165                 {\r
166                         --idx;\r
167                         tmpbuf[idx] = (c8)('0' + (number % 10));\r
168                         number /= 10;\r
169                 }\r
170 \r
171                 // add sign\r
172 \r
173                 if (negative)\r
174                 {\r
175                         --idx;\r
176                         tmpbuf[idx] = '-';\r
177                 }\r
178 \r
179                 *this = &tmpbuf[idx];\r
180         }\r
181 \r
182 \r
183         //! Constructs a string from an unsigned int\r
184         explicit string(unsigned int number)\r
185         : array(0), allocated(0), used(0)\r
186         {\r
187                 // temporary buffer for 16 numbers\r
188 \r
189                 c8 tmpbuf[16]={0};\r
190                 u32 idx = 15;\r
191 \r
192                 // special case '0'\r
193 \r
194                 if (!number)\r
195                 {\r
196                         tmpbuf[14] = '0';\r
197                         *this = &tmpbuf[14];\r
198                         return;\r
199                 }\r
200 \r
201                 // add numbers\r
202 \r
203                 while(number && idx)\r
204                 {\r
205                         --idx;\r
206                         tmpbuf[idx] = (c8)('0' + (number % 10));\r
207                         number /= 10;\r
208                 }\r
209 \r
210                 *this = &tmpbuf[idx];\r
211         }\r
212 \r
213 \r
214         //! Constructs a string from a long\r
215         explicit string(long number)\r
216         : array(0), allocated(0), used(0)\r
217         {\r
218                 // store if negative and make positive\r
219 \r
220                 bool negative = false;\r
221                 if (number < 0)\r
222                 {\r
223                         number *= -1;\r
224                         negative = true;\r
225                 }\r
226 \r
227                 // temporary buffer for 16 numbers\r
228 \r
229                 c8 tmpbuf[16]={0};\r
230                 u32 idx = 15;\r
231 \r
232                 // special case '0'\r
233 \r
234                 if (!number)\r
235                 {\r
236                         tmpbuf[14] = '0';\r
237                         *this = &tmpbuf[14];\r
238                         return;\r
239                 }\r
240 \r
241                 // add numbers\r
242 \r
243                 while(number && idx)\r
244                 {\r
245                         --idx;\r
246                         tmpbuf[idx] = (c8)('0' + (number % 10));\r
247                         number /= 10;\r
248                 }\r
249 \r
250                 // add sign\r
251 \r
252                 if (negative)\r
253                 {\r
254                         --idx;\r
255                         tmpbuf[idx] = '-';\r
256                 }\r
257 \r
258                 *this = &tmpbuf[idx];\r
259         }\r
260 \r
261 \r
262         //! Constructs a string from an unsigned long\r
263         explicit string(unsigned long number)\r
264         : array(0), allocated(0), used(0)\r
265         {\r
266                 // temporary buffer for 16 numbers\r
267 \r
268                 c8 tmpbuf[16]={0};\r
269                 u32 idx = 15;\r
270 \r
271                 // special case '0'\r
272 \r
273                 if (!number)\r
274                 {\r
275                         tmpbuf[14] = '0';\r
276                         *this = &tmpbuf[14];\r
277                         return;\r
278                 }\r
279 \r
280                 // add numbers\r
281 \r
282                 while(number && idx)\r
283                 {\r
284                         --idx;\r
285                         tmpbuf[idx] = (c8)('0' + (number % 10));\r
286                         number /= 10;\r
287                 }\r
288 \r
289                 *this = &tmpbuf[idx];\r
290         }\r
291 \r
292 \r
293         //! Constructor for copying a string from a pointer with a given length\r
294         template <class B>\r
295         string(const B* const c, u32 length)\r
296         : array(0), allocated(0), used(0)\r
297         {\r
298                 if (!c)\r
299                 {\r
300                         // correctly init the string to an empty one\r
301                         *this="";\r
302                         return;\r
303                 }\r
304 \r
305                 allocated = used = length+1;\r
306                 array = allocator.allocate(used); // new T[used];\r
307 \r
308                 for (u32 l = 0; l<length; ++l)\r
309                         array[l] = (T)c[l];\r
310 \r
311                 array[length] = 0;\r
312         }\r
313 \r
314 \r
315         //! Constructor for Unicode and ASCII strings\r
316         template <class B>\r
317         string(const B* const c)\r
318         : array(0), allocated(0), used(0)\r
319         {\r
320                 *this = c;\r
321         }\r
322 \r
323 \r
324         //! Destructor\r
325         ~string()\r
326         {\r
327                 allocator.deallocate(array); // delete [] array;\r
328         }\r
329 \r
330 \r
331         //! Assignment operator\r
332         string<T,TAlloc>& operator=(const string<T,TAlloc>& other)\r
333         {\r
334                 if (this == &other)\r
335                         return *this;\r
336 \r
337                 used = other.size()+1;\r
338                 if (used>allocated)\r
339                 {\r
340                         allocator.deallocate(array); // delete [] array;\r
341                         allocated = used;\r
342                         array = allocator.allocate(used); //new T[used];\r
343                 }\r
344 \r
345                 const T* p = other.c_str();\r
346                 for (u32 i=0; i<used; ++i, ++p)\r
347                         array[i] = *p;\r
348 \r
349                 return *this;\r
350         }\r
351 \r
352         //! Assignment operator for other string types\r
353         template <class B, class A>\r
354         string<T,TAlloc>& operator=(const string<B,A>& other)\r
355         {\r
356                 *this = other.c_str();\r
357                 return *this;\r
358         }\r
359 \r
360 \r
361         //! Assignment operator for strings, ASCII and Unicode\r
362         template <class B>\r
363         string<T,TAlloc>& operator=(const B* const c)\r
364         {\r
365                 if (!c)\r
366                 {\r
367                         if (!array)\r
368                         {\r
369                                 array = allocator.allocate(1); //new T[1];\r
370                                 allocated = 1;\r
371                         }\r
372                         used = 1;\r
373                         array[0] = 0x0;\r
374                         return *this;\r
375                 }\r
376 \r
377                 if ((void*)c == (void*)array)\r
378                         return *this;\r
379 \r
380                 u32 len = 0;\r
381                 const B* p = c;\r
382                 do\r
383                 {\r
384                         ++len;\r
385                 } while(*p++);\r
386 \r
387                 // we'll keep the old string for a while, because the new\r
388                 // string could be a part of the current string.\r
389                 T* oldArray = array;\r
390 \r
391                 used = len;\r
392                 if (used>allocated)\r
393                 {\r
394                         allocated = used;\r
395                         array = allocator.allocate(used); //new T[used];\r
396                 }\r
397 \r
398                 for (u32 l = 0; l<len; ++l)\r
399                         array[l] = (T)c[l];\r
400 \r
401                 if (oldArray != array)\r
402                         allocator.deallocate(oldArray); // delete [] oldArray;\r
403 \r
404                 return *this;\r
405         }\r
406 \r
407 \r
408         //! Append operator for other strings\r
409         string<T,TAlloc> operator+(const string<T,TAlloc>& other) const\r
410         {\r
411                 string<T,TAlloc> str(*this);\r
412                 str.append(other);\r
413 \r
414                 return str;\r
415         }\r
416 \r
417 \r
418         //! Append operator for strings, ASCII and Unicode\r
419         template <class B>\r
420         string<T,TAlloc> operator+(const B* const c) const\r
421         {\r
422                 string<T,TAlloc> str(*this);\r
423                 str.append(c);\r
424 \r
425                 return str;\r
426         }\r
427 \r
428 \r
429         //! Direct access operator\r
430         T& operator [](const u32 index)\r
431         {\r
432                 _IRR_DEBUG_BREAK_IF(index>=used) // bad index\r
433                 return array[index];\r
434         }\r
435 \r
436 \r
437         //! Direct access operator\r
438         const T& operator [](const u32 index) const\r
439         {\r
440                 _IRR_DEBUG_BREAK_IF(index>=used) // bad index\r
441                 return array[index];\r
442         }\r
443 \r
444 \r
445         //! Equality operator\r
446         bool operator==(const T* const str) const\r
447         {\r
448                 if (!str)\r
449                         return false;\r
450 \r
451                 u32 i;\r
452                 for (i=0; array[i] && str[i]; ++i)\r
453                         if (array[i] != str[i])\r
454                                 return false;\r
455 \r
456                 return (!array[i] && !str[i]);\r
457         }\r
458 \r
459 \r
460         //! Equality operator\r
461         bool operator==(const string<T,TAlloc>& other) const\r
462         {\r
463                 for (u32 i=0; array[i] && other.array[i]; ++i)\r
464                         if (array[i] != other.array[i])\r
465                                 return false;\r
466 \r
467                 return used == other.used;\r
468         }\r
469 \r
470 \r
471         //! Is smaller comparator\r
472         bool operator<(const string<T,TAlloc>& other) const\r
473         {\r
474                 for (u32 i=0; array[i] && other.array[i]; ++i)\r
475                 {\r
476                         const s32 diff = array[i] - other.array[i];\r
477                         if (diff)\r
478                                 return (diff < 0);\r
479                 }\r
480 \r
481                 return (used < other.used);\r
482         }\r
483 \r
484 \r
485         //! Inequality operator\r
486         bool operator!=(const T* const str) const\r
487         {\r
488                 return !(*this == str);\r
489         }\r
490 \r
491 \r
492         //! Inequality operator\r
493         bool operator!=(const string<T,TAlloc>& other) const\r
494         {\r
495                 return !(*this == other);\r
496         }\r
497 \r
498 \r
499         //! Returns length of the string's content\r
500         /** \return Length of the string's content in characters, excluding\r
501         the trailing NUL. */\r
502         u32 size() const\r
503         {\r
504                 return used-1;\r
505         }\r
506 \r
507         //! Informs if the string is empty or not.\r
508         //! \return True if the string is empty, false if not.\r
509         bool empty() const\r
510         {\r
511                 return (size() == 0);\r
512         }\r
513 \r
514         void clear(bool releaseMemory=true)\r
515         {\r
516                 if ( releaseMemory )\r
517                 {\r
518                         reallocate(1);\r
519                 }\r
520                 array[0] = 0;\r
521                 used = 1;\r
522         }\r
523 \r
524         //! Returns character string\r
525         /** \return pointer to C-style NUL terminated string. */\r
526         const T* c_str() const\r
527         {\r
528                 return array;\r
529         }\r
530 \r
531 \r
532         //! Makes the string lower case.\r
533         string<T,TAlloc>& make_lower()\r
534         {\r
535                 for (u32 i=0; array[i]; ++i)\r
536                         array[i] = locale_lower ( array[i] );\r
537                 return *this;\r
538         }\r
539 \r
540 \r
541         //! Makes the string upper case.\r
542         string<T,TAlloc>& make_upper()\r
543         {\r
544                 for (u32 i=0; array[i]; ++i)\r
545                         array[i] = locale_upper ( array[i] );\r
546                 return *this;\r
547         }\r
548 \r
549 \r
550         //! Compares the strings ignoring case.\r
551         /** \param other: Other string to compare.\r
552         \return True if the strings are equal ignoring case. */\r
553         bool equals_ignore_case(const string<T,TAlloc>& other) const\r
554         {\r
555                 for(u32 i=0; array[i] && other[i]; ++i)\r
556                         if (locale_lower( array[i]) != locale_lower(other[i]))\r
557                                 return false;\r
558 \r
559                 return used == other.used;\r
560         }\r
561 \r
562         //! Compares the strings ignoring case.\r
563         /** \param other: Other string to compare.\r
564                 \param sourcePos: where to start to compare in the string\r
565         \return True if the strings are equal ignoring case. */\r
566         bool equals_substring_ignore_case(const string<T,TAlloc>&other, const s32 sourcePos = 0 ) const\r
567         {\r
568                 if ( (u32) sourcePos >= used )\r
569                         return false;\r
570 \r
571                 u32 i;\r
572                 for( i=0; array[sourcePos + i] && other[i]; ++i)\r
573                         if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))\r
574                                 return false;\r
575 \r
576                 return array[sourcePos + i] == 0 && other[i] == 0;\r
577         }\r
578 \r
579 \r
580         //! Compares the strings ignoring case.\r
581         /** \param other: Other string to compare.\r
582         \return True if this string is smaller ignoring case. */\r
583         bool lower_ignore_case(const string<T,TAlloc>& other) const\r
584         {\r
585                 for(u32 i=0; array[i] && other.array[i]; ++i)\r
586                 {\r
587                         s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );\r
588                         if ( diff )\r
589                                 return diff < 0;\r
590                 }\r
591 \r
592                 return used < other.used;\r
593         }\r
594 \r
595 \r
596         //! compares the first n characters of the strings\r
597         /** \param other Other string to compare.\r
598         \param n Number of characters to compare\r
599         \return True if the n first characters of both strings are equal. */\r
600         bool equalsn(const string<T,TAlloc>& other, u32 n) const\r
601         {\r
602                 u32 i;\r
603                 for(i=0; i < n && array[i] && other[i]; ++i)\r
604                         if (array[i] != other[i])\r
605                                 return false;\r
606 \r
607                 // if one (or both) of the strings was smaller then they\r
608                 // are only equal if they have the same length\r
609                 return (i == n) || (used == other.used);\r
610         }\r
611 \r
612 \r
613         //! compares the first n characters of the strings\r
614         /** \param str Other string to compare.\r
615         \param n Number of characters to compare\r
616         \return True if the n first characters of both strings are equal. */\r
617         bool equalsn(const T* const str, u32 n) const\r
618         {\r
619                 if (!str)\r
620                         return false;\r
621                 u32 i;\r
622                 for(i=0; i < n && array[i] && str[i]; ++i)\r
623                         if (array[i] != str[i])\r
624                                 return false;\r
625 \r
626                 // if one (or both) of the strings was smaller then they\r
627                 // are only equal if they have the same length\r
628                 return (i == n) || (array[i] == 0 && str[i] == 0);\r
629         }\r
630 \r
631 \r
632         //! Appends a character to this string\r
633         /** \param character: Character to append. */\r
634         string<T,TAlloc>& append(T character)\r
635         {\r
636                 if (used + 1 > allocated)\r
637                         reallocate(used + 1);\r
638 \r
639                 ++used;\r
640 \r
641                 array[used-2] = character;\r
642                 array[used-1] = 0;\r
643 \r
644                 return *this;\r
645         }\r
646 \r
647 \r
648         //! Appends a char string to this string\r
649         /** \param other: Char string to append. */\r
650         /** \param length: The length of the string to append. */\r
651         string<T,TAlloc>& append(const T* const other, u32 length=0xffffffff)\r
652         {\r
653                 if (!other)\r
654                         return *this;\r
655 \r
656                 u32 len = 0;\r
657                 const T* p = other;\r
658                 while(*p)\r
659                 {\r
660                         ++len;\r
661                         ++p;\r
662                 }\r
663                 if (len > length)\r
664                         len = length;\r
665 \r
666                 if (used + len > allocated)\r
667                         reallocate(used + len);\r
668 \r
669                 --used;\r
670                 ++len;\r
671 \r
672                 for (u32 l=0; l<len; ++l)\r
673                         array[l+used] = *(other+l);\r
674 \r
675                 used += len;\r
676 \r
677                 return *this;\r
678         }\r
679 \r
680 \r
681         //! Appends a string to this string\r
682         /** \param other: String to append. */\r
683         string<T,TAlloc>& append(const string<T,TAlloc>& other)\r
684         {\r
685                 if (other.size() == 0)\r
686                         return *this;\r
687 \r
688                 --used;\r
689                 const u32 len = other.size()+1;\r
690 \r
691                 if (used + len > allocated)\r
692                         reallocate(used + len);\r
693 \r
694                 for (u32 l=0; l<len; ++l)\r
695                         array[used+l] = other[l];\r
696 \r
697                 used += len;\r
698 \r
699                 return *this;\r
700         }\r
701 \r
702 \r
703         //! Appends a string of the length l to this string.\r
704         /** \param other: other String to append to this string.\r
705         \param length: How much characters of the other string to add to this one. */\r
706         string<T,TAlloc>& append(const string<T,TAlloc>& other, u32 length)\r
707         {\r
708                 if (other.size() == 0)\r
709                         return *this;\r
710 \r
711                 if (other.size() < length)\r
712                 {\r
713                         append(other);\r
714                         return *this;\r
715                 }\r
716 \r
717                 if (used + length > allocated)\r
718                         reallocate(used + length);\r
719 \r
720                 --used;\r
721 \r
722                 for (u32 l=0; l<length; ++l)\r
723                         array[l+used] = other[l];\r
724                 used += length;\r
725 \r
726                 // ensure proper termination\r
727                 array[used]=0;\r
728                 ++used;\r
729 \r
730                 return *this;\r
731         }\r
732 \r
733         //! Insert a certain amount of characters into the string before the given index\r
734         //\param pos Insert the characters before this index\r
735         //\param s String to insert. Must be at least of size n\r
736         //\param n Number of characters from string s to use.\r
737         string<T,TAlloc>& insert(u32 pos, const char* s, u32 n)\r
738         {\r
739                 if ( pos < used )\r
740                 {\r
741                         reserve(used+n);\r
742 \r
743                         // move stuff behind insert point\r
744                         const u32 end = used+n-1;\r
745                         for (u32 i=0; i<used-pos; ++i)\r
746                         {\r
747                                 array[end-i] = array[end-(i+n)];\r
748                         }\r
749                         used += n;\r
750 \r
751                         for (u32 i=0; i<n; ++i)\r
752                         {\r
753                                 array[pos+i] = s[i];\r
754                         }\r
755                 }\r
756 \r
757                 return *this;\r
758         }\r
759 \r
760         //! Reserves some memory.\r
761         /** \param count: Amount of characters to reserve. */\r
762         void reserve(u32 count)\r
763         {\r
764                 if (count < allocated)\r
765                         return;\r
766 \r
767                 reallocate(count);\r
768         }\r
769 \r
770 \r
771         //! finds first occurrence of character in string\r
772         /** \param c: Character to search for.\r
773         \return Position where the character has been found,\r
774         or -1 if not found. */\r
775         s32 findFirst(T c) const\r
776         {\r
777                 for (u32 i=0; i<used-1; ++i)\r
778                         if (array[i] == c)\r
779                                 return i;\r
780 \r
781                 return -1;\r
782         }\r
783 \r
784         //! finds first occurrence of a character of a list in string\r
785         /** \param c: List of characters to find. For example if the method\r
786         should find the first occurrence of 'a' or 'b', this parameter should be "ab".\r
787         \param count: Amount of characters in the list. Usually,\r
788         this should be strlen(c)\r
789         \return Position where one of the characters has been found,\r
790         or -1 if not found. */\r
791         s32 findFirstChar(const T* const c, u32 count=1) const\r
792         {\r
793                 if (!c || !count)\r
794                         return -1;\r
795 \r
796                 for (u32 i=0; i<used-1; ++i)\r
797                         for (u32 j=0; j<count; ++j)\r
798                                 if (array[i] == c[j])\r
799                                         return i;\r
800 \r
801                 return -1;\r
802         }\r
803 \r
804 \r
805         //! Finds first position of a character not in a given list.\r
806         /** \param c: List of characters not to find. For example if the method\r
807         should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".\r
808         \param count: Amount of characters in the list. Usually,\r
809         this should be strlen(c)\r
810         \return Position where the character has been found,\r
811         or -1 if not found. */\r
812         template <class B>\r
813         s32 findFirstCharNotInList(const B* const c, u32 count=1) const\r
814         {\r
815                 if (!c || !count)\r
816                         return -1;\r
817 \r
818                 for (u32 i=0; i<used-1; ++i)\r
819                 {\r
820                         u32 j;\r
821                         for (j=0; j<count; ++j)\r
822                                 if (array[i] == c[j])\r
823                                         break;\r
824 \r
825                         if (j==count)\r
826                                 return i;\r
827                 }\r
828 \r
829                 return -1;\r
830         }\r
831 \r
832         //! Finds last position of a character not in a given list.\r
833         /** \param c: List of characters not to find. For example if the method\r
834         should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".\r
835         \param count: Amount of characters in the list. Usually,\r
836         this should be strlen(c)\r
837         \return Position where the character has been found,\r
838         or -1 if not found. */\r
839         template <class B>\r
840         s32 findLastCharNotInList(const B* const c, u32 count=1) const\r
841         {\r
842                 if (!c || !count)\r
843                         return -1;\r
844 \r
845                 for (s32 i=(s32)(used-2); i>=0; --i)\r
846                 {\r
847                         u32 j;\r
848                         for (j=0; j<count; ++j)\r
849                                 if (array[i] == c[j])\r
850                                         break;\r
851 \r
852                         if (j==count)\r
853                                 return i;\r
854                 }\r
855 \r
856                 return -1;\r
857         }\r
858 \r
859         //! finds next occurrence of character in string\r
860         /** \param c: Character to search for.\r
861         \param startPos: Position in string to start searching.\r
862         \return Position where the character has been found,\r
863         or -1 if not found. */\r
864         s32 findNext(T c, u32 startPos) const\r
865         {\r
866                 for (u32 i=startPos; i<used-1; ++i)\r
867                         if (array[i] == c)\r
868                                 return i;\r
869 \r
870                 return -1;\r
871         }\r
872 \r
873 \r
874         //! finds last occurrence of character in string\r
875         /** \param c: Character to search for.\r
876         \param start: start to search reverse ( default = -1, on end )\r
877         \return Position where the character has been found,\r
878         or -1 if not found. */\r
879         s32 findLast(T c, s32 start = -1) const\r
880         {\r
881                 start = core::clamp ( start < 0 ? (s32)(used) - 2 : start, 0, (s32)(used) - 2 );\r
882                 for (s32 i=start; i>=0; --i)\r
883                         if (array[i] == c)\r
884                                 return i;\r
885 \r
886                 return -1;\r
887         }\r
888 \r
889         //! finds last occurrence of a character of a list in string\r
890         /** \param c: List of strings to find. For example if the method\r
891         should find the last occurrence of 'a' or 'b', this parameter should be "ab".\r
892         \param count: Amount of characters in the list. Usually,\r
893         this should be strlen(c)\r
894         \return Position where one of the characters has been found,\r
895         or -1 if not found. */\r
896         s32 findLastChar(const T* const c, u32 count=1) const\r
897         {\r
898                 if (!c || !count)\r
899                         return -1;\r
900 \r
901                 for (s32 i=(s32)used-2; i>=0; --i)\r
902                         for (u32 j=0; j<count; ++j)\r
903                                 if (array[i] == c[j])\r
904                                         return i;\r
905 \r
906                 return -1;\r
907         }\r
908 \r
909 \r
910         //! finds another string in this string\r
911         /** \param str: Another string\r
912         \param start: Start position of the search\r
913         \return Positions where the string has been found,\r
914         or -1 if not found. */\r
915         template <class B>\r
916         s32 find(const B* const str, const u32 start = 0) const\r
917         {\r
918                 if (str && *str)\r
919                 {\r
920                         u32 len = 0;\r
921 \r
922                         while (str[len])\r
923                                 ++len;\r
924 \r
925                         if (len > used-1)\r
926                                 return -1;\r
927 \r
928                         for (u32 i=start; i<used-len; ++i)\r
929                         {\r
930                                 u32 j=0;\r
931 \r
932                                 while(str[j] && array[i+j] == str[j])\r
933                                         ++j;\r
934 \r
935                                 if (!str[j])\r
936                                         return i;\r
937                         }\r
938                 }\r
939 \r
940                 return -1;\r
941         }\r
942 \r
943 \r
944         //! Returns a substring\r
945         /** \param begin Start of substring.\r
946         \param length Length of substring.\r
947         \param make_lower copy only lower case */\r
948         string<T> subString(u32 begin, s32 length, bool make_lower = false ) const\r
949         {\r
950                 // if start after string\r
951                 // or no proper substring length\r
952                 if ((length <= 0) || (begin>=size()))\r
953                         return string<T>("");\r
954                 // clamp length to maximal value\r
955                 if ((length+begin) > size())\r
956                         length = size()-begin;\r
957 \r
958                 string<T> o;\r
959                 o.reserve(length+1);\r
960 \r
961                 if ( !make_lower )\r
962                 {\r
963                         for (s32 i=0; i<length; ++i)\r
964                                 o.array[i] = array[i+begin];\r
965                 }\r
966                 else\r
967                 {\r
968                         for (s32 i=0; i<length; ++i)\r
969                                 o.array[i] = locale_lower ( array[i+begin] );\r
970                 }\r
971 \r
972                 o.array[length] = 0;\r
973                 o.used = length + 1;\r
974 \r
975                 return o;\r
976         }\r
977 \r
978 \r
979         //! Appends a character to this string\r
980         /** \param c Character to append. */\r
981         string<T,TAlloc>& operator += (T c)\r
982         {\r
983                 append(c);\r
984                 return *this;\r
985         }\r
986 \r
987 \r
988         //! Appends a char string to this string\r
989         /** \param c Char string to append. */\r
990         string<T,TAlloc>& operator += (const T* const c)\r
991         {\r
992                 append(c);\r
993                 return *this;\r
994         }\r
995 \r
996 \r
997         //! Appends a string to this string\r
998         /** \param other String to append. */\r
999         string<T,TAlloc>& operator += (const string<T,TAlloc>& other)\r
1000         {\r
1001                 append(other);\r
1002                 return *this;\r
1003         }\r
1004 \r
1005 \r
1006         //! Appends a string representation of a number to this string\r
1007         /** \param i Number to append. */\r
1008         string<T,TAlloc>& operator += (const int i)\r
1009         {\r
1010                 append(string<T,TAlloc>(i));\r
1011                 return *this;\r
1012         }\r
1013 \r
1014 \r
1015         //! Appends a string representation of a number to this string\r
1016         /** \param i Number to append. */\r
1017         string<T,TAlloc>& operator += (const unsigned int i)\r
1018         {\r
1019                 append(string<T,TAlloc>(i));\r
1020                 return *this;\r
1021         }\r
1022 \r
1023 \r
1024         //! Appends a string representation of a number to this string\r
1025         /** \param i Number to append. */\r
1026         string<T,TAlloc>& operator += (const long i)\r
1027         {\r
1028                 append(string<T,TAlloc>(i));\r
1029                 return *this;\r
1030         }\r
1031 \r
1032 \r
1033         //! Appends a string representation of a number to this string\r
1034         /** \param i Number to append. */\r
1035         string<T,TAlloc>& operator += (const unsigned long i)\r
1036         {\r
1037                 append(string<T,TAlloc>(i));\r
1038                 return *this;\r
1039         }\r
1040 \r
1041 \r
1042         //! Appends a string representation of a number to this string\r
1043         /** \param i Number to append. */\r
1044         string<T,TAlloc>& operator += (const double i)\r
1045         {\r
1046                 append(string<T,TAlloc>(i));\r
1047                 return *this;\r
1048         }\r
1049 \r
1050 \r
1051         //! Appends a string representation of a number to this string\r
1052         /** \param i Number to append. */\r
1053         string<T,TAlloc>& operator += (const float i)\r
1054         {\r
1055                 append(string<T,TAlloc>(i));\r
1056                 return *this;\r
1057         }\r
1058 \r
1059 \r
1060         //! Replaces all characters of a special type with another one\r
1061         /** \param toReplace Character to replace.\r
1062         \param replaceWith Character replacing the old one. */\r
1063         string<T,TAlloc>& replace(T toReplace, T replaceWith)\r
1064         {\r
1065                 for (u32 i=0; i<used-1; ++i)\r
1066                         if (array[i] == toReplace)\r
1067                                 array[i] = replaceWith;\r
1068                 return *this;\r
1069         }\r
1070 \r
1071 \r
1072         //! Replaces all instances of a string with another one.\r
1073         /** \param toReplace The string to replace.\r
1074         \param replaceWith The string replacing the old one. */\r
1075         string<T,TAlloc>& replace(const string<T,TAlloc>& toReplace, const string<T,TAlloc>& replaceWith)\r
1076         {\r
1077                 if (toReplace.size() == 0)\r
1078                         return *this;\r
1079 \r
1080                 const T* other = toReplace.c_str();\r
1081                 const T* replace = replaceWith.c_str();\r
1082                 const u32 other_size = toReplace.size();\r
1083                 const u32 replace_size = replaceWith.size();\r
1084 \r
1085                 // Determine the delta.  The algorithm will change depending on the delta.\r
1086                 s32 delta = replace_size - other_size;\r
1087 \r
1088                 // A character for character replace.  The string will not shrink or grow.\r
1089                 if (delta == 0)\r
1090                 {\r
1091                         s32 pos = 0;\r
1092                         while ((pos = find(other, pos)) != -1)\r
1093                         {\r
1094                                 for (u32 i = 0; i < replace_size; ++i)\r
1095                                         array[pos + i] = replace[i];\r
1096                                 ++pos;\r
1097                         }\r
1098                         return *this;\r
1099                 }\r
1100 \r
1101                 // We are going to be removing some characters.  The string will shrink.\r
1102                 if (delta < 0)\r
1103                 {\r
1104                         u32 i = 0;\r
1105                         for (u32 pos = 0; pos < used; ++i, ++pos)\r
1106                         {\r
1107                                 // Is this potentially a match?\r
1108                                 if (array[pos] == *other)\r
1109                                 {\r
1110                                         // Check to see if we have a match.\r
1111                                         u32 j;\r
1112                                         for (j = 0; j < other_size; ++j)\r
1113                                         {\r
1114                                                 if (array[pos + j] != other[j])\r
1115                                                         break;\r
1116                                         }\r
1117 \r
1118                                         // If we have a match, replace characters.\r
1119                                         if (j == other_size)\r
1120                                         {\r
1121                                                 for (j = 0; j < replace_size; ++j)\r
1122                                                         array[i + j] = replace[j];\r
1123                                                 i += replace_size - 1;\r
1124                                                 pos += other_size - 1;\r
1125                                                 continue;\r
1126                                         }\r
1127                                 }\r
1128 \r
1129                                 // No match found, just copy characters.\r
1130                                 array[i] = array[pos];\r
1131                         }\r
1132                         array[i-1] = 0;\r
1133                         used = i;\r
1134 \r
1135                         return *this;\r
1136                 }\r
1137 \r
1138                 // We are going to be adding characters, so the string size will increase.\r
1139                 // Count the number of times toReplace exists in the string so we can allocate the new size.\r
1140                 u32 find_count = 0;\r
1141                 s32 pos = 0;\r
1142                 while ((pos = find(other, pos)) != -1)\r
1143                 {\r
1144                         ++find_count;\r
1145                         ++pos;\r
1146                 }\r
1147 \r
1148                 // Re-allocate the string now, if needed.\r
1149                 u32 len = delta * find_count;\r
1150                 if (used + len > allocated)\r
1151                         reallocate(used + len);\r
1152 \r
1153                 // Start replacing.\r
1154                 pos = 0;\r
1155                 while ((pos = find(other, pos)) != -1)\r
1156                 {\r
1157                         T* start = array + pos + other_size - 1;\r
1158                         T* ptr   = array + used - 1;\r
1159                         T* end   = array + delta + used -1;\r
1160 \r
1161                         // Shift characters to make room for the string.\r
1162                         while (ptr != start)\r
1163                         {\r
1164                                 *end = *ptr;\r
1165                                 --ptr;\r
1166                                 --end;\r
1167                         }\r
1168 \r
1169                         // Add the new string now.\r
1170                         for (u32 i = 0; i < replace_size; ++i)\r
1171                                 array[pos + i] = replace[i];\r
1172 \r
1173                         pos += replace_size;\r
1174                         used += delta;\r
1175                 }\r
1176 \r
1177                 return *this;\r
1178         }\r
1179 \r
1180 \r
1181         //! Removes characters from a string.\r
1182         /** \param c: Character to remove. */\r
1183         string<T,TAlloc>& remove(T c)\r
1184         {\r
1185                 u32 pos = 0;\r
1186                 u32 found = 0;\r
1187                 for (u32 i=0; i<used-1; ++i)\r
1188                 {\r
1189                         if (array[i] == c)\r
1190                         {\r
1191                                 ++found;\r
1192                                 continue;\r
1193                         }\r
1194 \r
1195                         array[pos++] = array[i];\r
1196                 }\r
1197                 used -= found;\r
1198                 array[used-1] = 0;\r
1199                 return *this;\r
1200         }\r
1201 \r
1202 \r
1203         //! Removes a string from the string.\r
1204         /** \param toRemove: String to remove. */\r
1205         string<T,TAlloc>& remove(const string<T,TAlloc>& toRemove)\r
1206         {\r
1207                 u32 size = toRemove.size();\r
1208                 if ( size == 0 )\r
1209                         return *this;\r
1210                 u32 pos = 0;\r
1211                 u32 found = 0;\r
1212                 for (u32 i=0; i<used-1; ++i)\r
1213                 {\r
1214                         u32 j = 0;\r
1215                         while (j < size)\r
1216                         {\r
1217                                 if (array[i + j] != toRemove[j])\r
1218                                         break;\r
1219                                 ++j;\r
1220                         }\r
1221                         if (j == size)\r
1222                         {\r
1223                                 found += size;\r
1224                                 i += size - 1;\r
1225                                 continue;\r
1226                         }\r
1227 \r
1228                         array[pos++] = array[i];\r
1229                 }\r
1230                 used -= found;\r
1231                 array[used-1] = 0;\r
1232                 return *this;\r
1233         }\r
1234 \r
1235 \r
1236         //! Removes characters from a string.\r
1237         /** \param characters: Characters to remove. */\r
1238         string<T,TAlloc>& removeChars(const string<T,TAlloc> & characters)\r
1239         {\r
1240                 if (characters.size() == 0)\r
1241                         return *this;\r
1242 \r
1243                 u32 pos = 0;\r
1244                 u32 found = 0;\r
1245                 for (u32 i=0; i<used-1; ++i)\r
1246                 {\r
1247                         // Don't use characters.findFirst as it finds the \0,\r
1248                         // causing used to become incorrect.\r
1249                         bool docontinue = false;\r
1250                         for (u32 j=0; j<characters.size(); ++j)\r
1251                         {\r
1252                                 if (characters[j] == array[i])\r
1253                                 {\r
1254                                         ++found;\r
1255                                         docontinue = true;\r
1256                                         break;\r
1257                                 }\r
1258                         }\r
1259                         if (docontinue)\r
1260                                 continue;\r
1261 \r
1262                         array[pos++] = array[i];\r
1263                 }\r
1264                 used -= found;\r
1265                 array[used-1] = 0;\r
1266 \r
1267                 return *this;\r
1268         }\r
1269 \r
1270 \r
1271         //! Trims the string.\r
1272         /** Removes the specified characters (by default, Latin-1 whitespace)\r
1273         from the beginning and the end of the string. */\r
1274         string<T,TAlloc>& trim(const string<T,TAlloc> & whitespace = " \t\n\r")\r
1275         {\r
1276                 // find start and end of the substring without the specified characters\r
1277                 const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);\r
1278                 if (begin == -1)\r
1279                         return (*this="");\r
1280 \r
1281                 const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);\r
1282 \r
1283                 return (*this = subString(begin, (end +1) - begin));\r
1284         }\r
1285 \r
1286         //! Erase 0's at the end when a string ends with a floating point number\r
1287         /** After generating strings from floats we often end up with strings\r
1288                 ending up with lots of zeros which don't add any value. Erase 'em all.\r
1289                 Examples: "0.100000" becomes "0.1"\r
1290                       "10.000000" becomes "10"\r
1291                                   "foo 3.140000" becomes "foo 3.14"\r
1292                                   "no_num.000" stays "no_num.000"\r
1293                                   "1." stays "1."\r
1294         */\r
1295         string<T,TAlloc>& eraseTrailingFloatZeros(char decimalPoint='.')\r
1296         {\r
1297                 s32 i=findLastCharNotInList("0", 1);\r
1298                 if ( i > 0 && (u32)i < used-2 ) // non 0 must be found and not last char (also used is at least 2 when i > 0)\r
1299                 {\r
1300                         u32 eraseStart=i+1;\r
1301                         u32 dot=0;\r
1302                         if( core::isdigit(array[i]) )\r
1303                         {\r
1304                                 while( --i>0 && core::isdigit(array[i]) );\r
1305                                 if ( array[i] == decimalPoint )\r
1306                                         dot = i;\r
1307                         }\r
1308                         else if ( array[i] == decimalPoint )\r
1309                         {\r
1310                                 dot = i;\r
1311                                 eraseStart = i;\r
1312                         }\r
1313                         if ( dot > 0 && core::isdigit(array[dot-1]) )\r
1314                         {\r
1315                                 array[eraseStart] = 0;\r
1316                                 used = eraseStart+1;\r
1317                         }\r
1318                 }\r
1319                 return *this;\r
1320         }\r
1321 \r
1322         //! Erases a character from the string.\r
1323         /** May be slow, because all elements\r
1324         following after the erased element have to be copied.\r
1325         \param index: Index of element to be erased. */\r
1326         string<T,TAlloc>& erase(u32 index)\r
1327         {\r
1328                 _IRR_DEBUG_BREAK_IF(index>=used) // access violation\r
1329 \r
1330                 for (u32 i=index+1; i<used; ++i)\r
1331                         array[i-1] = array[i];\r
1332 \r
1333                 --used;\r
1334                 return *this;\r
1335         }\r
1336 \r
1337         //! verify the existing string.\r
1338         string<T,TAlloc>& validate()\r
1339         {\r
1340                 // terminate on existing null\r
1341                 for (u32 i=0; i<allocated; ++i)\r
1342                 {\r
1343                         if (array[i] == 0)\r
1344                         {\r
1345                                 used = i + 1;\r
1346                                 return *this;\r
1347                         }\r
1348                 }\r
1349 \r
1350                 // terminate\r
1351                 if ( allocated > 0 )\r
1352                 {\r
1353                         used = allocated;\r
1354                         array[used-1] = 0;\r
1355                 }\r
1356                 else\r
1357                 {\r
1358                         used = 0;\r
1359                 }\r
1360 \r
1361                 return *this;\r
1362         }\r
1363 \r
1364         //! gets the last char of a string or null\r
1365         T lastChar() const\r
1366         {\r
1367                 return used > 1 ? array[used-2] : 0;\r
1368         }\r
1369 \r
1370         //! Split string into parts (tokens).\r
1371         /** This method will split a string at certain delimiter characters\r
1372         into the container passed in as reference. The type of the container\r
1373         has to be given as template parameter. It must provide a push_back and\r
1374         a size method.\r
1375         \param ret The result container. Tokens are added, the container is not cleared.\r
1376         \param delimiter C-style string of delimiter characters\r
1377         \param countDelimiters Number of delimiter characters\r
1378         \param ignoreEmptyTokens Flag to avoid empty substrings in the result\r
1379         container. If two delimiters occur without a character in between or an\r
1380         empty substring would be placed in the result. Or if a delimiter is the last\r
1381         character an empty substring would be added at the end. If this flag is set,\r
1382         only non-empty strings are stored.\r
1383         \param keepSeparators Flag which allows to add the separator to the\r
1384         result string. If this flag is true, the concatenation of the\r
1385         substrings results in the original string. Otherwise, only the\r
1386         characters between the delimiters are returned.\r
1387         \return The number of resulting substrings\r
1388         */\r
1389         template<class container>\r
1390         u32 split(container& ret, const T* const delimiter, u32 countDelimiters=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const\r
1391         {\r
1392                 if (!delimiter)\r
1393                         return 0;\r
1394 \r
1395                 const u32 oldSize=ret.size();\r
1396 \r
1397                 u32 tokenStartIdx = 0;\r
1398                 for (u32 i=0; i<used; ++i)\r
1399                 {\r
1400                         for (u32 j=0; j<countDelimiters; ++j)\r
1401                         {\r
1402                                 if (array[i] == delimiter[j])\r
1403                                 {\r
1404                                         if (i - tokenStartIdx > 0)\r
1405                                                 ret.push_back(string<T,TAlloc>(&array[tokenStartIdx], i - tokenStartIdx));\r
1406                                         else if ( !ignoreEmptyTokens )\r
1407                                                 ret.push_back(string<T,TAlloc>());\r
1408                                         if ( keepSeparators )\r
1409                                         {\r
1410                                                 ret.push_back(string<T,TAlloc>(&array[i], 1));\r
1411                                         }\r
1412 \r
1413                                         tokenStartIdx = i+1;\r
1414                                         break;\r
1415                                 }\r
1416                         }\r
1417                 }\r
1418                 if ((used - 1) > tokenStartIdx)\r
1419                         ret.push_back(string<T,TAlloc>(&array[tokenStartIdx], (used - 1) - tokenStartIdx));\r
1420                  else if ( !ignoreEmptyTokens )\r
1421                 ret.push_back(string<T,TAlloc>());\r
1422 \r
1423                 return ret.size()-oldSize;\r
1424         }\r
1425 \r
1426         friend size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize);\r
1427 \r
1428 private:\r
1429 \r
1430         //! Reallocate the array, make it bigger or smaller\r
1431         void reallocate(u32 new_size)\r
1432         {\r
1433                 T* old_array = array;\r
1434 \r
1435                 array = allocator.allocate(new_size); //new T[new_size];\r
1436                 allocated = new_size;\r
1437 \r
1438                 const u32 amount = used < new_size ? used : new_size;\r
1439                 for (u32 i=0; i<amount; ++i)\r
1440                         array[i] = old_array[i];\r
1441 \r
1442                 if (allocated < used)\r
1443                         used = allocated;\r
1444 \r
1445                 allocator.deallocate(old_array); // delete [] old_array;\r
1446         }\r
1447 \r
1448         //--- member variables\r
1449 \r
1450         T* array;\r
1451         u32 allocated;\r
1452         u32 used;\r
1453         TAlloc allocator;\r
1454 };\r
1455 \r
1456 \r
1457 //! Typedef for character strings\r
1458 typedef string<c8> stringc;\r
1459 \r
1460 //! Typedef for wide character strings\r
1461 typedef string<wchar_t> stringw;\r
1462 \r
1463 //! Convert multibyte string to wide-character string\r
1464 /** Wrapper around mbstowcs from standard library, but directly using Irrlicht string class.\r
1465 What the function does exactly depends on the LC_CTYPE of the current c locale.\r
1466 \param destination Wide-character string receiving the converted source\r
1467 \param source multibyte string\r
1468 \return The number of wide characters written to destination, not including the eventual terminating null character or -1 when conversion failed */\r
1469 static inline size_t multibyteToWString(string<wchar_t>& destination, const core::string<c8>& source)\r
1470 {\r
1471         return multibyteToWString(destination, source.c_str(), (u32)source.size());\r
1472 }\r
1473 \r
1474 //! Convert multibyte string to wide-character string\r
1475 /** Wrapper around mbstowcs from standard library, but directly writing to Irrlicht string class.\r
1476 What the function does exactly depends on the LC_CTYPE of the current c locale.\r
1477 \param destination Wide-character string receiving the converted source\r
1478 \param source multibyte string\r
1479 \return The number of wide characters written to destination, not including the eventual terminating null character  or -1 when conversion failed. */\r
1480 static inline size_t multibyteToWString(string<wchar_t>& destination, const char* source)\r
1481 {\r
1482         const u32 s = source ? (u32)strlen(source) : 0;\r
1483         return multibyteToWString(destination, source, s);\r
1484 }\r
1485 \r
1486 //! Internally used by the other multibyteToWString functions\r
1487 static size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize)\r
1488 {\r
1489         if ( sourceSize )\r
1490         {\r
1491                 destination.reserve(sourceSize+1);\r
1492 #if defined(_MSC_VER)\r
1493 #pragma warning(push)\r
1494 #pragma warning(disable: 4996)  // 'mbstowcs': This function or variable may be unsafe. Consider using mbstowcs_s instead.\r
1495 #endif\r
1496                 const size_t written = mbstowcs(destination.array, source, (size_t)sourceSize);\r
1497 #if defined(_MSC_VER)\r
1498 #pragma warning(pop)\r
1499 #endif\r
1500                 if ( written != (size_t)-1 )\r
1501                 {\r
1502                         destination.used = (u32)written+1;\r
1503                         destination.array[destination.used-1] = 0;\r
1504                 }\r
1505                 else\r
1506                 {\r
1507                         // Likely character which got converted until the invalid character was encountered are in destination now.\r
1508                         // And it seems even 0-terminated, but I found no documentation anywhere that this (the 0-termination) is guaranteed :-(\r
1509                         destination.clear();\r
1510                 }\r
1511                 return written;\r
1512         }\r
1513         else\r
1514         {\r
1515                 destination.clear();\r
1516                 return 0;\r
1517         }\r
1518 }\r
1519 \r
1520 \r
1521 } // end namespace core\r
1522 } // end namespace irr\r
1523 \r
1524 #endif\r
1525 \r