1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22
23 #include "../Precompiled.h"
24
25 #include "../IO/Log.h"
26
27 #include <cstdio>
28
29 #include "../DebugNew.h"
30
31 #ifdef _MSC_VER
32 #pragma warning(disable:6293)
33 #endif
34
35 namespace Urho3D
36 {
37
38 char String::endZero = 0;
39
40 const String String::EMPTY;
41
String(const WString & str)42 String::String(const WString& str) :
43 length_(0),
44 capacity_(0),
45 buffer_(&endZero)
46 {
47 SetUTF8FromWChar(str.CString());
48 }
49
String(int value)50 String::String(int value) :
51 length_(0),
52 capacity_(0),
53 buffer_(&endZero)
54 {
55 char tempBuffer[CONVERSION_BUFFER_LENGTH];
56 sprintf(tempBuffer, "%d", value);
57 *this = tempBuffer;
58 }
59
String(short value)60 String::String(short value) :
61 length_(0),
62 capacity_(0),
63 buffer_(&endZero)
64 {
65 char tempBuffer[CONVERSION_BUFFER_LENGTH];
66 sprintf(tempBuffer, "%d", value);
67 *this = tempBuffer;
68 }
69
String(long value)70 String::String(long value) :
71 length_(0),
72 capacity_(0),
73 buffer_(&endZero)
74 {
75 char tempBuffer[CONVERSION_BUFFER_LENGTH];
76 sprintf(tempBuffer, "%ld", value);
77 *this = tempBuffer;
78 }
79
String(long long value)80 String::String(long long value) :
81 length_(0),
82 capacity_(0),
83 buffer_(&endZero)
84 {
85 char tempBuffer[CONVERSION_BUFFER_LENGTH];
86 sprintf(tempBuffer, "%lld", value);
87 *this = tempBuffer;
88 }
89
String(unsigned value)90 String::String(unsigned value) :
91 length_(0),
92 capacity_(0),
93 buffer_(&endZero)
94 {
95 char tempBuffer[CONVERSION_BUFFER_LENGTH];
96 sprintf(tempBuffer, "%u", value);
97 *this = tempBuffer;
98 }
99
String(unsigned short value)100 String::String(unsigned short value) :
101 length_(0),
102 capacity_(0),
103 buffer_(&endZero)
104 {
105 char tempBuffer[CONVERSION_BUFFER_LENGTH];
106 sprintf(tempBuffer, "%u", value);
107 *this = tempBuffer;
108 }
109
String(unsigned long value)110 String::String(unsigned long value) :
111 length_(0),
112 capacity_(0),
113 buffer_(&endZero)
114 {
115 char tempBuffer[CONVERSION_BUFFER_LENGTH];
116 sprintf(tempBuffer, "%lu", value);
117 *this = tempBuffer;
118 }
119
String(unsigned long long value)120 String::String(unsigned long long value) :
121 length_(0),
122 capacity_(0),
123 buffer_(&endZero)
124 {
125 char tempBuffer[CONVERSION_BUFFER_LENGTH];
126 sprintf(tempBuffer, "%llu", value);
127 *this = tempBuffer;
128 }
129
String(float value)130 String::String(float value) :
131 length_(0),
132 capacity_(0),
133 buffer_(&endZero)
134 {
135 char tempBuffer[CONVERSION_BUFFER_LENGTH];
136 sprintf(tempBuffer, "%g", value);
137 *this = tempBuffer;
138 }
139
String(double value)140 String::String(double value) :
141 length_(0),
142 capacity_(0),
143 buffer_(&endZero)
144 {
145 char tempBuffer[CONVERSION_BUFFER_LENGTH];
146 sprintf(tempBuffer, "%.15g", value);
147 *this = tempBuffer;
148 }
149
String(bool value)150 String::String(bool value) :
151 length_(0),
152 capacity_(0),
153 buffer_(&endZero)
154 {
155 if (value)
156 *this = "true";
157 else
158 *this = "false";
159 }
160
String(char value)161 String::String(char value) :
162 length_(0),
163 capacity_(0),
164 buffer_(&endZero)
165 {
166 Resize(1);
167 buffer_[0] = value;
168 }
169
String(char value,unsigned length)170 String::String(char value, unsigned length) :
171 length_(0),
172 capacity_(0),
173 buffer_(&endZero)
174 {
175 Resize(length);
176 for (unsigned i = 0; i < length; ++i)
177 buffer_[i] = value;
178 }
179
operator +=(int rhs)180 String& String::operator +=(int rhs)
181 {
182 return *this += String(rhs);
183 }
184
operator +=(short rhs)185 String& String::operator +=(short rhs)
186 {
187 return *this += String(rhs);
188 }
189
operator +=(long rhs)190 String& String::operator +=(long rhs)
191 {
192 return *this += String(rhs);
193 }
194
operator +=(long long rhs)195 String& String::operator +=(long long rhs)
196 {
197 return *this += String(rhs);
198 }
199
operator +=(unsigned rhs)200 String& String::operator +=(unsigned rhs)
201 {
202 return *this += String(rhs);
203 }
204
operator +=(unsigned short rhs)205 String& String::operator +=(unsigned short rhs)
206 {
207 return *this += String(rhs);
208 }
209
operator +=(unsigned long rhs)210 String& String::operator +=(unsigned long rhs)
211 {
212 return *this += String(rhs);
213 }
214
operator +=(unsigned long long rhs)215 String& String::operator +=(unsigned long long rhs)
216 {
217 return *this += String(rhs);
218 }
219
operator +=(float rhs)220 String& String::operator +=(float rhs)
221 {
222 return *this += String(rhs);
223 }
224
operator +=(bool rhs)225 String& String::operator +=(bool rhs)
226 {
227 return *this += String(rhs);
228 }
229
Replace(char replaceThis,char replaceWith,bool caseSensitive)230 void String::Replace(char replaceThis, char replaceWith, bool caseSensitive)
231 {
232 if (caseSensitive)
233 {
234 for (unsigned i = 0; i < length_; ++i)
235 {
236 if (buffer_[i] == replaceThis)
237 buffer_[i] = replaceWith;
238 }
239 }
240 else
241 {
242 replaceThis = (char)tolower(replaceThis);
243 for (unsigned i = 0; i < length_; ++i)
244 {
245 if (tolower(buffer_[i]) == replaceThis)
246 buffer_[i] = replaceWith;
247 }
248 }
249 }
250
Replace(const String & replaceThis,const String & replaceWith,bool caseSensitive)251 void String::Replace(const String& replaceThis, const String& replaceWith, bool caseSensitive)
252 {
253 unsigned nextPos = 0;
254
255 while (nextPos < length_)
256 {
257 unsigned pos = Find(replaceThis, nextPos, caseSensitive);
258 if (pos == NPOS)
259 break;
260 Replace(pos, replaceThis.length_, replaceWith);
261 nextPos = pos + replaceWith.length_;
262 }
263 }
264
Replace(unsigned pos,unsigned length,const String & replaceWith)265 void String::Replace(unsigned pos, unsigned length, const String& replaceWith)
266 {
267 // If substring is illegal, do nothing
268 if (pos + length > length_)
269 return;
270
271 Replace(pos, length, replaceWith.buffer_, replaceWith.length_);
272 }
273
Replace(unsigned pos,unsigned length,const char * replaceWith)274 void String::Replace(unsigned pos, unsigned length, const char* replaceWith)
275 {
276 // If substring is illegal, do nothing
277 if (pos + length > length_)
278 return;
279
280 Replace(pos, length, replaceWith, CStringLength(replaceWith));
281 }
282
Replace(const String::Iterator & start,const String::Iterator & end,const String & replaceWith)283 String::Iterator String::Replace(const String::Iterator& start, const String::Iterator& end, const String& replaceWith)
284 {
285 unsigned pos = (unsigned)(start - Begin());
286 if (pos >= length_)
287 return End();
288 unsigned length = (unsigned)(end - start);
289 Replace(pos, length, replaceWith);
290
291 return Begin() + pos;
292 }
293
Replaced(char replaceThis,char replaceWith,bool caseSensitive) const294 String String::Replaced(char replaceThis, char replaceWith, bool caseSensitive) const
295 {
296 String ret(*this);
297 ret.Replace(replaceThis, replaceWith, caseSensitive);
298 return ret;
299 }
300
Replaced(const String & replaceThis,const String & replaceWith,bool caseSensitive) const301 String String::Replaced(const String& replaceThis, const String& replaceWith, bool caseSensitive) const
302 {
303 String ret(*this);
304 ret.Replace(replaceThis, replaceWith, caseSensitive);
305 return ret;
306 }
307
Append(const String & str)308 String& String::Append(const String& str)
309 {
310 return *this += str;
311 }
312
Append(const char * str)313 String& String::Append(const char* str)
314 {
315 return *this += str;
316 }
317
Append(char c)318 String& String::Append(char c)
319 {
320 return *this += c;
321 }
322
Append(const char * str,unsigned length)323 String& String::Append(const char* str, unsigned length)
324 {
325 if (str)
326 {
327 unsigned oldLength = length_;
328 Resize(oldLength + length);
329 CopyChars(&buffer_[oldLength], str, length);
330 }
331 return *this;
332 }
333
Insert(unsigned pos,const String & str)334 void String::Insert(unsigned pos, const String& str)
335 {
336 if (pos > length_)
337 pos = length_;
338
339 if (pos == length_)
340 (*this) += str;
341 else
342 Replace(pos, 0, str);
343 }
344
Insert(unsigned pos,char c)345 void String::Insert(unsigned pos, char c)
346 {
347 if (pos > length_)
348 pos = length_;
349
350 if (pos == length_)
351 (*this) += c;
352 else
353 {
354 unsigned oldLength = length_;
355 Resize(length_ + 1);
356 MoveRange(pos + 1, pos, oldLength - pos);
357 buffer_[pos] = c;
358 }
359 }
360
Insert(const String::Iterator & dest,const String & str)361 String::Iterator String::Insert(const String::Iterator& dest, const String& str)
362 {
363 unsigned pos = (unsigned)(dest - Begin());
364 if (pos > length_)
365 pos = length_;
366 Insert(pos, str);
367
368 return Begin() + pos;
369 }
370
Insert(const String::Iterator & dest,const String::Iterator & start,const String::Iterator & end)371 String::Iterator String::Insert(const String::Iterator& dest, const String::Iterator& start, const String::Iterator& end)
372 {
373 unsigned pos = (unsigned)(dest - Begin());
374 if (pos > length_)
375 pos = length_;
376 unsigned length = (unsigned)(end - start);
377 Replace(pos, 0, &(*start), length);
378
379 return Begin() + pos;
380 }
381
Insert(const String::Iterator & dest,char c)382 String::Iterator String::Insert(const String::Iterator& dest, char c)
383 {
384 unsigned pos = (unsigned)(dest - Begin());
385 if (pos > length_)
386 pos = length_;
387 Insert(pos, c);
388
389 return Begin() + pos;
390 }
391
Erase(unsigned pos,unsigned length)392 void String::Erase(unsigned pos, unsigned length)
393 {
394 Replace(pos, length, String::EMPTY);
395 }
396
Erase(const String::Iterator & it)397 String::Iterator String::Erase(const String::Iterator& it)
398 {
399 unsigned pos = (unsigned)(it - Begin());
400 if (pos >= length_)
401 return End();
402 Erase(pos);
403
404 return Begin() + pos;
405 }
406
Erase(const String::Iterator & start,const String::Iterator & end)407 String::Iterator String::Erase(const String::Iterator& start, const String::Iterator& end)
408 {
409 unsigned pos = (unsigned)(start - Begin());
410 if (pos >= length_)
411 return End();
412 unsigned length = (unsigned)(end - start);
413 Erase(pos, length);
414
415 return Begin() + pos;
416 }
417
Resize(unsigned newLength)418 void String::Resize(unsigned newLength)
419 {
420 if (!capacity_)
421 {
422 // If zero length requested, do not allocate buffer yet
423 if (!newLength)
424 return;
425
426 // Calculate initial capacity
427 capacity_ = newLength + 1;
428 if (capacity_ < MIN_CAPACITY)
429 capacity_ = MIN_CAPACITY;
430
431 buffer_ = new char[capacity_];
432 }
433 else
434 {
435 if (newLength && capacity_ < newLength + 1)
436 {
437 // Increase the capacity with half each time it is exceeded
438 while (capacity_ < newLength + 1)
439 capacity_ += (capacity_ + 1) >> 1;
440
441 char* newBuffer = new char[capacity_];
442 // Move the existing data to the new buffer, then delete the old buffer
443 if (length_)
444 CopyChars(newBuffer, buffer_, length_);
445 delete[] buffer_;
446
447 buffer_ = newBuffer;
448 }
449 }
450
451 buffer_[newLength] = 0;
452 length_ = newLength;
453 }
454
Reserve(unsigned newCapacity)455 void String::Reserve(unsigned newCapacity)
456 {
457 if (newCapacity < length_ + 1)
458 newCapacity = length_ + 1;
459 if (newCapacity == capacity_)
460 return;
461
462 char* newBuffer = new char[newCapacity];
463 // Move the existing data to the new buffer, then delete the old buffer
464 CopyChars(newBuffer, buffer_, length_ + 1);
465 if (capacity_)
466 delete[] buffer_;
467
468 capacity_ = newCapacity;
469 buffer_ = newBuffer;
470 }
471
Compact()472 void String::Compact()
473 {
474 if (capacity_)
475 Reserve(length_ + 1);
476 }
477
Clear()478 void String::Clear()
479 {
480 Resize(0);
481 }
482
Swap(String & str)483 void String::Swap(String& str)
484 {
485 Urho3D::Swap(length_, str.length_);
486 Urho3D::Swap(capacity_, str.capacity_);
487 Urho3D::Swap(buffer_, str.buffer_);
488 }
489
Substring(unsigned pos) const490 String String::Substring(unsigned pos) const
491 {
492 if (pos < length_)
493 {
494 String ret;
495 ret.Resize(length_ - pos);
496 CopyChars(ret.buffer_, buffer_ + pos, ret.length_);
497
498 return ret;
499 }
500 else
501 return String();
502 }
503
Substring(unsigned pos,unsigned length) const504 String String::Substring(unsigned pos, unsigned length) const
505 {
506 if (pos < length_)
507 {
508 String ret;
509 if (pos + length > length_)
510 length = length_ - pos;
511 ret.Resize(length);
512 CopyChars(ret.buffer_, buffer_ + pos, ret.length_);
513
514 return ret;
515 }
516 else
517 return String();
518 }
519
Trimmed() const520 String String::Trimmed() const
521 {
522 unsigned trimStart = 0;
523 unsigned trimEnd = length_;
524
525 while (trimStart < trimEnd)
526 {
527 char c = buffer_[trimStart];
528 if (c != ' ' && c != 9)
529 break;
530 ++trimStart;
531 }
532 while (trimEnd > trimStart)
533 {
534 char c = buffer_[trimEnd - 1];
535 if (c != ' ' && c != 9)
536 break;
537 --trimEnd;
538 }
539
540 return Substring(trimStart, trimEnd - trimStart);
541 }
542
ToLower() const543 String String::ToLower() const
544 {
545 String ret(*this);
546 for (unsigned i = 0; i < ret.length_; ++i)
547 ret[i] = (char)tolower(buffer_[i]);
548
549 return ret;
550 }
551
ToUpper() const552 String String::ToUpper() const
553 {
554 String ret(*this);
555 for (unsigned i = 0; i < ret.length_; ++i)
556 ret[i] = (char)toupper(buffer_[i]);
557
558 return ret;
559 }
560
Split(char separator,bool keepEmptyStrings) const561 Vector<String> String::Split(char separator, bool keepEmptyStrings) const
562 {
563 return Split(CString(), separator, keepEmptyStrings);
564 }
565
Join(const Vector<String> & subStrings,const String & glue)566 void String::Join(const Vector<String>& subStrings, const String& glue)
567 {
568 *this = Joined(subStrings, glue);
569 }
570
Find(char c,unsigned startPos,bool caseSensitive) const571 unsigned String::Find(char c, unsigned startPos, bool caseSensitive) const
572 {
573 if (caseSensitive)
574 {
575 for (unsigned i = startPos; i < length_; ++i)
576 {
577 if (buffer_[i] == c)
578 return i;
579 }
580 }
581 else
582 {
583 c = (char)tolower(c);
584 for (unsigned i = startPos; i < length_; ++i)
585 {
586 if (tolower(buffer_[i]) == c)
587 return i;
588 }
589 }
590
591 return NPOS;
592 }
593
Find(const String & str,unsigned startPos,bool caseSensitive) const594 unsigned String::Find(const String& str, unsigned startPos, bool caseSensitive) const
595 {
596 if (!str.length_ || str.length_ > length_)
597 return NPOS;
598
599 char first = str.buffer_[0];
600 if (!caseSensitive)
601 first = (char)tolower(first);
602
603 for (unsigned i = startPos; i <= length_ - str.length_; ++i)
604 {
605 char c = buffer_[i];
606 if (!caseSensitive)
607 c = (char)tolower(c);
608
609 if (c == first)
610 {
611 unsigned skip = NPOS;
612 bool found = true;
613 for (unsigned j = 1; j < str.length_; ++j)
614 {
615 c = buffer_[i + j];
616 char d = str.buffer_[j];
617 if (!caseSensitive)
618 {
619 c = (char)tolower(c);
620 d = (char)tolower(d);
621 }
622
623 if (skip == NPOS && c == first)
624 skip = i + j - 1;
625
626 if (c != d)
627 {
628 found = false;
629 if (skip != NPOS)
630 i = skip;
631 break;
632 }
633 }
634 if (found)
635 return i;
636 }
637 }
638
639 return NPOS;
640 }
641
FindLast(char c,unsigned startPos,bool caseSensitive) const642 unsigned String::FindLast(char c, unsigned startPos, bool caseSensitive) const
643 {
644 if (startPos >= length_)
645 startPos = length_ - 1;
646
647 if (caseSensitive)
648 {
649 for (unsigned i = startPos; i < length_; --i)
650 {
651 if (buffer_[i] == c)
652 return i;
653 }
654 }
655 else
656 {
657 c = (char)tolower(c);
658 for (unsigned i = startPos; i < length_; --i)
659 {
660 if (tolower(buffer_[i]) == c)
661 return i;
662 }
663 }
664
665 return NPOS;
666 }
667
FindLast(const String & str,unsigned startPos,bool caseSensitive) const668 unsigned String::FindLast(const String& str, unsigned startPos, bool caseSensitive) const
669 {
670 if (!str.length_ || str.length_ > length_)
671 return NPOS;
672 if (startPos > length_ - str.length_)
673 startPos = length_ - str.length_;
674
675 char first = str.buffer_[0];
676 if (!caseSensitive)
677 first = (char)tolower(first);
678
679 for (unsigned i = startPos; i < length_; --i)
680 {
681 char c = buffer_[i];
682 if (!caseSensitive)
683 c = (char)tolower(c);
684
685 if (c == first)
686 {
687 bool found = true;
688 for (unsigned j = 1; j < str.length_; ++j)
689 {
690 c = buffer_[i + j];
691 char d = str.buffer_[j];
692 if (!caseSensitive)
693 {
694 c = (char)tolower(c);
695 d = (char)tolower(d);
696 }
697
698 if (c != d)
699 {
700 found = false;
701 break;
702 }
703 }
704 if (found)
705 return i;
706 }
707 }
708
709 return NPOS;
710 }
711
StartsWith(const String & str,bool caseSensitive) const712 bool String::StartsWith(const String& str, bool caseSensitive) const
713 {
714 return Find(str, 0, caseSensitive) == 0;
715 }
716
EndsWith(const String & str,bool caseSensitive) const717 bool String::EndsWith(const String& str, bool caseSensitive) const
718 {
719 unsigned pos = FindLast(str, Length() - 1, caseSensitive);
720 return pos != NPOS && pos == Length() - str.Length();
721 }
722
Compare(const String & str,bool caseSensitive) const723 int String::Compare(const String& str, bool caseSensitive) const
724 {
725 return Compare(CString(), str.CString(), caseSensitive);
726 }
727
Compare(const char * str,bool caseSensitive) const728 int String::Compare(const char* str, bool caseSensitive) const
729 {
730 return Compare(CString(), str, caseSensitive);
731 }
732
SetUTF8FromLatin1(const char * str)733 void String::SetUTF8FromLatin1(const char* str)
734 {
735 char temp[7];
736
737 Clear();
738
739 if (!str)
740 return;
741
742 while (*str)
743 {
744 char* dest = temp;
745 EncodeUTF8(dest, (unsigned)*str++);
746 *dest = 0;
747 Append(temp);
748 }
749 }
750
SetUTF8FromWChar(const wchar_t * str)751 void String::SetUTF8FromWChar(const wchar_t* str)
752 {
753 char temp[7];
754
755 Clear();
756
757 if (!str)
758 return;
759
760 #ifdef _WIN32
761 while (*str)
762 {
763 unsigned unicodeChar = DecodeUTF16(str);
764 char* dest = temp;
765 EncodeUTF8(dest, unicodeChar);
766 *dest = 0;
767 Append(temp);
768 }
769 #else
770 while (*str)
771 {
772 char* dest = temp;
773 EncodeUTF8(dest, (unsigned)*str++);
774 *dest = 0;
775 Append(temp);
776 }
777 #endif
778 }
779
LengthUTF8() const780 unsigned String::LengthUTF8() const
781 {
782 unsigned ret = 0;
783
784 const char* src = buffer_;
785 if (!src)
786 return ret;
787 const char* end = buffer_ + length_;
788
789 while (src < end)
790 {
791 DecodeUTF8(src);
792 ++ret;
793 }
794
795 return ret;
796 }
797
ByteOffsetUTF8(unsigned index) const798 unsigned String::ByteOffsetUTF8(unsigned index) const
799 {
800 unsigned byteOffset = 0;
801 unsigned utfPos = 0;
802
803 while (utfPos < index && byteOffset < length_)
804 {
805 NextUTF8Char(byteOffset);
806 ++utfPos;
807 }
808
809 return byteOffset;
810 }
811
NextUTF8Char(unsigned & byteOffset) const812 unsigned String::NextUTF8Char(unsigned& byteOffset) const
813 {
814 if (!buffer_)
815 return 0;
816
817 const char* src = buffer_ + byteOffset;
818 unsigned ret = DecodeUTF8(src);
819 byteOffset = (unsigned)(src - buffer_);
820
821 return ret;
822 }
823
AtUTF8(unsigned index) const824 unsigned String::AtUTF8(unsigned index) const
825 {
826 unsigned byteOffset = ByteOffsetUTF8(index);
827 return NextUTF8Char(byteOffset);
828 }
829
ReplaceUTF8(unsigned index,unsigned unicodeChar)830 void String::ReplaceUTF8(unsigned index, unsigned unicodeChar)
831 {
832 unsigned utfPos = 0;
833 unsigned byteOffset = 0;
834
835 while (utfPos < index && byteOffset < length_)
836 {
837 NextUTF8Char(byteOffset);
838 ++utfPos;
839 }
840
841 if (utfPos < index)
842 return;
843
844 unsigned beginCharPos = byteOffset;
845 NextUTF8Char(byteOffset);
846
847 char temp[7];
848 char* dest = temp;
849 EncodeUTF8(dest, unicodeChar);
850 *dest = 0;
851
852 Replace(beginCharPos, byteOffset - beginCharPos, temp, (unsigned)(dest - temp));
853 }
854
AppendUTF8(unsigned unicodeChar)855 String& String::AppendUTF8(unsigned unicodeChar)
856 {
857 char temp[7];
858 char* dest = temp;
859 EncodeUTF8(dest, unicodeChar);
860 *dest = 0;
861 return Append(temp);
862 }
863
SubstringUTF8(unsigned pos) const864 String String::SubstringUTF8(unsigned pos) const
865 {
866 unsigned utf8Length = LengthUTF8();
867 unsigned byteOffset = ByteOffsetUTF8(pos);
868 String ret;
869
870 while (pos < utf8Length)
871 {
872 ret.AppendUTF8(NextUTF8Char(byteOffset));
873 ++pos;
874 }
875
876 return ret;
877 }
878
SubstringUTF8(unsigned pos,unsigned length) const879 String String::SubstringUTF8(unsigned pos, unsigned length) const
880 {
881 unsigned utf8Length = LengthUTF8();
882 unsigned byteOffset = ByteOffsetUTF8(pos);
883 unsigned endPos = pos + length;
884 String ret;
885
886 while (pos < endPos && pos < utf8Length)
887 {
888 ret.AppendUTF8(NextUTF8Char(byteOffset));
889 ++pos;
890 }
891
892 return ret;
893 }
894
EncodeUTF8(char * & dest,unsigned unicodeChar)895 void String::EncodeUTF8(char*& dest, unsigned unicodeChar)
896 {
897 if (unicodeChar < 0x80)
898 *dest++ = unicodeChar;
899 else if (unicodeChar < 0x800)
900 {
901 dest[0] = (char)(0xc0 | ((unicodeChar >> 6) & 0x1f));
902 dest[1] = (char)(0x80 | (unicodeChar & 0x3f));
903 dest += 2;
904 }
905 else if (unicodeChar < 0x10000)
906 {
907 dest[0] = (char)(0xe0 | ((unicodeChar >> 12) & 0xf));
908 dest[1] = (char)(0x80 | ((unicodeChar >> 6) & 0x3f));
909 dest[2] = (char)(0x80 | (unicodeChar & 0x3f));
910 dest += 3;
911 }
912 else if (unicodeChar < 0x200000)
913 {
914 dest[0] = (char)(0xf0 | ((unicodeChar >> 18) & 0x7));
915 dest[1] = (char)(0x80 | ((unicodeChar >> 12) & 0x3f));
916 dest[2] = (char)(0x80 | ((unicodeChar >> 6) & 0x3f));
917 dest[3] = (char)(0x80 | (unicodeChar & 0x3f));
918 dest += 4;
919 }
920 else if (unicodeChar < 0x4000000)
921 {
922 dest[0] = (char)(0xf8 | ((unicodeChar >> 24) & 0x3));
923 dest[1] = (char)(0x80 | ((unicodeChar >> 18) & 0x3f));
924 dest[2] = (char)(0x80 | ((unicodeChar >> 12) & 0x3f));
925 dest[3] = (char)(0x80 | ((unicodeChar >> 6) & 0x3f));
926 dest[4] = (char)(0x80 | (unicodeChar & 0x3f));
927 dest += 5;
928 }
929 else
930 {
931 dest[0] = (char)(0xfc | ((unicodeChar >> 30) & 0x1));
932 dest[1] = (char)(0x80 | ((unicodeChar >> 24) & 0x3f));
933 dest[2] = (char)(0x80 | ((unicodeChar >> 18) & 0x3f));
934 dest[3] = (char)(0x80 | ((unicodeChar >> 12) & 0x3f));
935 dest[4] = (char)(0x80 | ((unicodeChar >> 6) & 0x3f));
936 dest[5] = (char)(0x80 | (unicodeChar & 0x3f));
937 dest += 6;
938 }
939 }
940
941 #define GET_NEXT_CONTINUATION_BYTE(ptr) *ptr; if ((unsigned char)*ptr < 0x80 || (unsigned char)*ptr >= 0xc0) return '?'; else ++ptr;
942
DecodeUTF8(const char * & src)943 unsigned String::DecodeUTF8(const char*& src)
944 {
945 if (src == 0)
946 return 0;
947
948 unsigned char char1 = *src++;
949
950 // Check if we are in the middle of a UTF8 character
951 if (char1 >= 0x80 && char1 < 0xc0)
952 {
953 while ((unsigned char)*src >= 0x80 && (unsigned char)*src < 0xc0)
954 ++src;
955 return '?';
956 }
957
958 if (char1 < 0x80)
959 return char1;
960 else if (char1 < 0xe0)
961 {
962 unsigned char char2 = GET_NEXT_CONTINUATION_BYTE(src);
963 return (unsigned)((char2 & 0x3f) | ((char1 & 0x1f) << 6));
964 }
965 else if (char1 < 0xf0)
966 {
967 unsigned char char2 = GET_NEXT_CONTINUATION_BYTE(src);
968 unsigned char char3 = GET_NEXT_CONTINUATION_BYTE(src);
969 return (unsigned)((char3 & 0x3f) | ((char2 & 0x3f) << 6) | ((char1 & 0xf) << 12));
970 }
971 else if (char1 < 0xf8)
972 {
973 unsigned char char2 = GET_NEXT_CONTINUATION_BYTE(src);
974 unsigned char char3 = GET_NEXT_CONTINUATION_BYTE(src);
975 unsigned char char4 = GET_NEXT_CONTINUATION_BYTE(src);
976 return (unsigned)((char4 & 0x3f) | ((char3 & 0x3f) << 6) | ((char2 & 0x3f) << 12) | ((char1 & 0x7) << 18));
977 }
978 else if (char1 < 0xfc)
979 {
980 unsigned char char2 = GET_NEXT_CONTINUATION_BYTE(src);
981 unsigned char char3 = GET_NEXT_CONTINUATION_BYTE(src);
982 unsigned char char4 = GET_NEXT_CONTINUATION_BYTE(src);
983 unsigned char char5 = GET_NEXT_CONTINUATION_BYTE(src);
984 return (unsigned)((char5 & 0x3f) | ((char4 & 0x3f) << 6) | ((char3 & 0x3f) << 12) | ((char2 & 0x3f) << 18) |
985 ((char1 & 0x3) << 24));
986 }
987 else
988 {
989 unsigned char char2 = GET_NEXT_CONTINUATION_BYTE(src);
990 unsigned char char3 = GET_NEXT_CONTINUATION_BYTE(src);
991 unsigned char char4 = GET_NEXT_CONTINUATION_BYTE(src);
992 unsigned char char5 = GET_NEXT_CONTINUATION_BYTE(src);
993 unsigned char char6 = GET_NEXT_CONTINUATION_BYTE(src);
994 return (unsigned)((char6 & 0x3f) | ((char5 & 0x3f) << 6) | ((char4 & 0x3f) << 12) | ((char3 & 0x3f) << 18) |
995 ((char2 & 0x3f) << 24) | ((char1 & 0x1) << 30));
996 }
997 }
998
999 #ifdef _WIN32
EncodeUTF16(wchar_t * & dest,unsigned unicodeChar)1000 void String::EncodeUTF16(wchar_t*& dest, unsigned unicodeChar)
1001 {
1002 if (unicodeChar < 0x10000)
1003 *dest++ = unicodeChar;
1004 else
1005 {
1006 unicodeChar -= 0x10000;
1007 *dest++ = 0xd800 | ((unicodeChar >> 10) & 0x3ff);
1008 *dest++ = 0xdc00 | (unicodeChar & 0x3ff);
1009 }
1010 }
1011
DecodeUTF16(const wchar_t * & src)1012 unsigned String::DecodeUTF16(const wchar_t*& src)
1013 {
1014 if (src == 0)
1015 return 0;
1016
1017 unsigned short word1 = *src++;
1018
1019 // Check if we are at a low surrogate
1020 if (word1 >= 0xdc00 && word1 < 0xe000)
1021 {
1022 while (*src >= 0xdc00 && *src < 0xe000)
1023 ++src;
1024 return '?';
1025 }
1026
1027 if (word1 < 0xd800 || word1 >= 0xe000)
1028 return word1;
1029 else
1030 {
1031 unsigned short word2 = *src++;
1032 if (word2 < 0xdc00 || word2 >= 0xe000)
1033 {
1034 --src;
1035 return '?';
1036 }
1037 else
1038 return (((word1 & 0x3ff) << 10) | (word2 & 0x3ff)) + 0x10000;
1039 }
1040 }
1041 #endif
1042
Split(const char * str,char separator,bool keepEmptyStrings)1043 Vector<String> String::Split(const char* str, char separator, bool keepEmptyStrings)
1044 {
1045 Vector<String> ret;
1046 const char* strEnd = str + String::CStringLength(str);
1047
1048 for (const char* splitEnd = str; splitEnd != strEnd; ++splitEnd)
1049 {
1050 if (*splitEnd == separator)
1051 {
1052 const ptrdiff_t splitLen = splitEnd - str;
1053 if (splitLen > 0 || keepEmptyStrings)
1054 ret.Push(String(str, splitLen));
1055 str = splitEnd + 1;
1056 }
1057 }
1058
1059 const ptrdiff_t splitLen = strEnd - str;
1060 if (splitLen > 0 || keepEmptyStrings)
1061 ret.Push(String(str, splitLen));
1062
1063 return ret;
1064 }
1065
Joined(const Vector<String> & subStrings,const String & glue)1066 String String::Joined(const Vector<String>& subStrings, const String& glue)
1067 {
1068 if (subStrings.Empty())
1069 return String();
1070
1071 String joinedString(subStrings[0]);
1072 for (unsigned i = 1; i < subStrings.Size(); ++i)
1073 joinedString.Append(glue).Append(subStrings[i]);
1074
1075 return joinedString;
1076 }
1077
AppendWithFormat(const char * formatString,...)1078 String& String::AppendWithFormat(const char* formatString, ...)
1079 {
1080 va_list args;
1081 va_start(args, formatString);
1082 AppendWithFormatArgs(formatString, args);
1083 va_end(args);
1084 return *this;
1085 }
1086
AppendWithFormatArgs(const char * formatString,va_list args)1087 String& String::AppendWithFormatArgs(const char* formatString, va_list args)
1088 {
1089 int pos = 0, lastPos = 0;
1090 int length = (int)strlen(formatString);
1091
1092 while (true)
1093 {
1094 // Scan the format string and find %a argument where a is one of d, f, s ...
1095 while (pos < length && formatString[pos] != '%') pos++;
1096 Append(formatString + lastPos, (unsigned)(pos - lastPos));
1097 if (pos >= length)
1098 return *this;
1099
1100 char format = formatString[pos + 1];
1101 pos += 2;
1102 lastPos = pos;
1103
1104 switch (format)
1105 {
1106 // Integer
1107 case 'd':
1108 case 'i':
1109 {
1110 int arg = va_arg(args, int);
1111 Append(String(arg));
1112 break;
1113 }
1114
1115 // Unsigned
1116 case 'u':
1117 {
1118 unsigned arg = va_arg(args, unsigned);
1119 Append(String(arg));
1120 break;
1121 }
1122
1123 // Unsigned long
1124 case 'l':
1125 {
1126 unsigned long arg = va_arg(args, unsigned long);
1127 Append(String(arg));
1128 break;
1129 }
1130
1131 // Real
1132 case 'f':
1133 {
1134 double arg = va_arg(args, double);
1135 Append(String(arg));
1136 break;
1137 }
1138
1139 // Character
1140 case 'c':
1141 {
1142 int arg = va_arg(args, int);
1143 Append((char)arg);
1144 break;
1145 }
1146
1147 // C string
1148 case 's':
1149 {
1150 char* arg = va_arg(args, char*);
1151 Append(arg);
1152 break;
1153 }
1154
1155 // Hex
1156 case 'x':
1157 {
1158 char buf[CONVERSION_BUFFER_LENGTH];
1159 int arg = va_arg(args, int);
1160 int arglen = ::sprintf(buf, "%x", arg);
1161 Append(buf, (unsigned)arglen);
1162 break;
1163 }
1164
1165 // Pointer
1166 case 'p':
1167 {
1168 char buf[CONVERSION_BUFFER_LENGTH];
1169 int arg = va_arg(args, int);
1170 int arglen = ::sprintf(buf, "%p", reinterpret_cast<void*>(arg));
1171 Append(buf, (unsigned)arglen);
1172 break;
1173 }
1174
1175 case '%':
1176 {
1177 Append("%", 1);
1178 break;
1179 }
1180
1181 default:
1182 URHO3D_LOGWARNINGF("Unsupported format specifier: '%c'", format);
1183 break;
1184 }
1185 }
1186 }
1187
Compare(const char * lhs,const char * rhs,bool caseSensitive)1188 int String::Compare(const char* lhs, const char* rhs, bool caseSensitive)
1189 {
1190 if (!lhs || !rhs)
1191 return lhs ? 1 : (rhs ? -1 : 0);
1192
1193 if (caseSensitive)
1194 return strcmp(lhs, rhs);
1195 else
1196 {
1197 for (;;)
1198 {
1199 char l = (char)tolower(*lhs);
1200 char r = (char)tolower(*rhs);
1201 if (!l || !r)
1202 return l ? 1 : (r ? -1 : 0);
1203 if (l < r)
1204 return -1;
1205 if (l > r)
1206 return 1;
1207
1208 ++lhs;
1209 ++rhs;
1210 }
1211 }
1212 }
1213
Replace(unsigned pos,unsigned length,const char * srcStart,unsigned srcLength)1214 void String::Replace(unsigned pos, unsigned length, const char* srcStart, unsigned srcLength)
1215 {
1216 int delta = (int)srcLength - (int)length;
1217
1218 if (pos + length < length_)
1219 {
1220 if (delta < 0)
1221 {
1222 MoveRange(pos + srcLength, pos + length, length_ - pos - length);
1223 Resize(length_ + delta);
1224 }
1225 if (delta > 0)
1226 {
1227 Resize(length_ + delta);
1228 MoveRange(pos + srcLength, pos + length, length_ - pos - length - delta);
1229 }
1230 }
1231 else
1232 Resize(length_ + delta);
1233
1234 CopyChars(buffer_ + pos, srcStart, srcLength);
1235 }
1236
WString()1237 WString::WString() :
1238 length_(0),
1239 buffer_(0)
1240 {
1241 }
1242
WString(const String & str)1243 WString::WString(const String& str) :
1244 length_(0),
1245 buffer_(0)
1246 {
1247 #ifdef _WIN32
1248 unsigned neededSize = 0;
1249 wchar_t temp[3];
1250
1251 unsigned byteOffset = 0;
1252 while (byteOffset < str.Length())
1253 {
1254 wchar_t* dest = temp;
1255 String::EncodeUTF16(dest, str.NextUTF8Char(byteOffset));
1256 neededSize += dest - temp;
1257 }
1258
1259 Resize(neededSize);
1260
1261 byteOffset = 0;
1262 wchar_t* dest = buffer_;
1263 while (byteOffset < str.Length())
1264 String::EncodeUTF16(dest, str.NextUTF8Char(byteOffset));
1265 #else
1266 Resize(str.LengthUTF8());
1267
1268 unsigned byteOffset = 0;
1269 wchar_t* dest = buffer_;
1270 while (byteOffset < str.Length())
1271 *dest++ = (wchar_t)str.NextUTF8Char(byteOffset);
1272 #endif
1273 }
1274
~WString()1275 WString::~WString()
1276 {
1277 delete[] buffer_;
1278 }
1279
Resize(unsigned newLength)1280 void WString::Resize(unsigned newLength)
1281 {
1282 if (!newLength)
1283 {
1284 delete[] buffer_;
1285 buffer_ = 0;
1286 length_ = 0;
1287 }
1288 else
1289 {
1290 wchar_t* newBuffer = new wchar_t[newLength + 1];
1291 if (buffer_)
1292 {
1293 unsigned copyLength = length_ < newLength ? length_ : newLength;
1294 memcpy(newBuffer, buffer_, copyLength * sizeof(wchar_t));
1295 delete[] buffer_;
1296 }
1297 newBuffer[newLength] = 0;
1298 buffer_ = newBuffer;
1299 length_ = newLength;
1300 }
1301 }
1302
1303 }
1304