1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Image/BsColor.h"
4#include "Math/BsMath.h"
5#include "Math/BsMatrix3.h"
6#include "Math/BsMatrix4.h"
7#include "Math/BsQuaternion.h"
8#include "Math/BsVector2.h"
9#include "Math/BsVector3.h"
10#include "Math/BsVector4.h"
11#include "Math/BsVector2I.h"
12#include "Error/BsException.h"
13
14namespace bs
15{
16 const String StringUtil::BLANK;
17 const WString StringUtil::WBLANK;
18
19 void StringUtil::trim(String& str, bool left, bool right)
20 {
21 static const String delims = " \t\r";
22 trim(str, delims, left, right);
23 }
24
25 void StringUtil::trim(WString& str, bool left, bool right)
26 {
27 static const WString delims = L" \t\r";
28 trim(str, delims, left, right);
29 }
30
31 void StringUtil::trim(String& str, const String& delims, bool left, bool right)
32 {
33 if(right)
34 str.erase(str.find_last_not_of(delims)+1); // trim right
35 if(left)
36 str.erase(0, str.find_first_not_of(delims)); // trim left
37 }
38
39 void StringUtil::trim(WString& str, const WString& delims, bool left, bool right)
40 {
41 if(right)
42 str.erase(str.find_last_not_of(delims)+1); // trim right
43 if(left)
44 str.erase(0, str.find_first_not_of(delims)); // trim left
45 }
46
47 Vector<String> StringUtil::split(const String& str, const String& delims, unsigned int maxSplits)
48 {
49 return splitInternal<char>(str, delims, maxSplits);
50 }
51
52 Vector<WString> StringUtil::split(const WString& str, const WString& delims, unsigned int maxSplits)
53 {
54 return splitInternal<wchar_t>(str, delims, maxSplits);
55 }
56
57 Vector<String> StringUtil::tokenise(const String& str, const String& singleDelims, const String& doubleDelims, unsigned int maxSplits)
58 {
59 return tokeniseInternal<char>(str, singleDelims, doubleDelims, maxSplits);
60 }
61
62 Vector<WString> StringUtil::tokenise(const WString& str, const WString& singleDelims, const WString& doubleDelims, unsigned int maxSplits)
63 {
64 return tokeniseInternal<wchar_t>(str, singleDelims, doubleDelims, maxSplits);
65 }
66
67 void StringUtil::toLowerCase(String& str)
68 {
69 std::transform(str.begin(), str.end(), str.begin(), tolower);
70 }
71
72 void StringUtil::toLowerCase(WString& str)
73 {
74 std::transform(str.begin(), str.end(), str.begin(), tolower);
75 }
76
77 void StringUtil::toUpperCase(String& str)
78 {
79 std::transform(str.begin(), str.end(), str.begin(), toupper);
80 }
81
82 void StringUtil::toUpperCase(WString& str)
83 {
84 std::transform(str.begin(), str.end(), str.begin(), toupper);
85 }
86
87 bool StringUtil::startsWith(const String& str, const String& pattern, bool lowerCase)
88 {
89 return startsWithInternal<char>(str, pattern, lowerCase);
90 }
91
92 bool StringUtil::startsWith(const WString& str, const WString& pattern, bool lowerCase)
93 {
94 return startsWithInternal<wchar_t>(str, pattern, lowerCase);
95 }
96
97 bool StringUtil::endsWith(const String& str, const String& pattern, bool lowerCase)
98 {
99 return endsWithInternal<char>(str, pattern, lowerCase);
100 }
101
102 bool StringUtil::endsWith(const WString& str, const WString& pattern, bool lowerCase)
103 {
104 return endsWithInternal<wchar_t>(str, pattern, lowerCase);
105 }
106
107 bool StringUtil::match(const String& str, const String& pattern, bool caseSensitive)
108 {
109 return matchInternal<char>(str, pattern, caseSensitive);
110 }
111
112 bool StringUtil::match(const WString& str, const WString& pattern, bool caseSensitive)
113 {
114 return matchInternal<wchar_t>(str, pattern, caseSensitive);
115 }
116
117 const String StringUtil::replaceAll(const String& source, const String& replaceWhat, const String& replaceWithWhat)
118 {
119 return replaceAllInternal<char>(source, replaceWhat, replaceWithWhat);
120 }
121
122 const WString StringUtil::replaceAll(const WString& source, const WString& replaceWhat, const WString& replaceWithWhat)
123 {
124 return replaceAllInternal<wchar_t>(source, replaceWhat, replaceWithWhat);
125 }
126
127 /************************************************************************/
128 /* VARIOUS TO STRING CONVERSIONS */
129 /************************************************************************/
130
131 WString toWString(const String& source)
132 {
133 return WString(source.begin(), source.end());
134 }
135
136 WString toWString(const char* source)
137 {
138 return toWString(String(source));
139 }
140
141 WString toWString(float val, unsigned short precision,
142 unsigned short width, char fill, std::ios::fmtflags flags)
143 {
144 WStringStream stream;
145 stream.precision(precision);
146 stream.width(width);
147 stream.fill(fill);
148 if (flags)
149 stream.setf(flags);
150 stream << val;
151 return stream.str();
152 }
153
154 WString toWString(double val, unsigned short precision,
155 unsigned short width, char fill, std::ios::fmtflags flags)
156 {
157 WStringStream stream;
158 stream.precision(precision);
159 stream.width(width);
160 stream.fill(fill);
161 if (flags)
162 stream.setf(flags);
163 stream << val;
164 return stream.str();
165 }
166
167 WString toWString(Radian val, unsigned short precision,
168 unsigned short width, char fill, std::ios::fmtflags flags)
169 {
170 return toWString(val.valueRadians(), precision, width, fill, flags);
171 }
172
173 WString toWString(Degree val, unsigned short precision,
174 unsigned short width, char fill, std::ios::fmtflags flags)
175 {
176 return toWString(val.valueDegrees(), precision, width, fill, flags);
177 }
178
179 WString toWString(int val,
180 unsigned short width, char fill, std::ios::fmtflags flags)
181 {
182 WStringStream stream;
183 stream.width(width);
184 stream.fill(fill);
185 if (flags)
186 stream.setf(flags);
187 stream << val;
188 return stream.str();
189 }
190
191 WString toWString(unsigned int val, unsigned short width, char fill, std::ios::fmtflags flags)
192 {
193 WStringStream stream;
194 stream.width(width);
195 stream.fill(fill);
196 if (flags)
197 stream.setf(flags);
198 stream << val;
199 return stream.str();
200 }
201
202 WString toWString(INT64 val, unsigned short width, char fill, std::ios::fmtflags flags)
203 {
204 WStringStream stream;
205 stream.width(width);
206 stream.fill(fill);
207 if (flags)
208 stream.setf(flags);
209 stream << val;
210 return stream.str();
211 }
212
213 WString toWString(UINT64 val, unsigned short width, char fill, std::ios::fmtflags flags)
214 {
215 WStringStream stream;
216 stream.width(width);
217 stream.fill(fill);
218 if (flags)
219 stream.setf(flags);
220 stream << val;
221 return stream.str();
222 }
223
224 WString toWString(char val, unsigned short width, char fill, std::ios::fmtflags flags)
225 {
226 WStringStream stream;
227 stream.width(width);
228 stream.fill(fill);
229 if (flags)
230 stream.setf(flags);
231 stream << val;
232 return stream.str();
233 }
234
235 WString toWString(wchar_t val, unsigned short width, char fill, std::ios::fmtflags flags)
236 {
237 WStringStream stream;
238 stream.width(width);
239 stream.fill(fill);
240 if (flags)
241 stream.setf(flags);
242 stream << val;
243 return stream.str();
244 }
245
246 WString toWString(const Vector2& val)
247 {
248 WStringStream stream;
249 stream << val.x << L" " << val.y;
250 return stream.str();
251 }
252
253 WString toWString(const Vector2I& val)
254 {
255 WStringStream stream;
256 stream << val.x << L" " << val.y;
257 return stream.str();
258 }
259
260 WString toWString(const Vector3& val)
261 {
262 WStringStream stream;
263 stream << val.x << L" " << val.y << L" " << val.z;
264 return stream.str();
265 }
266
267 WString toWString(const Vector4& val)
268 {
269 WStringStream stream;
270 stream << val.x << L" " << val.y << L" " << val.z << L" " << val.w;
271 return stream.str();
272 }
273
274 WString toWString(const Matrix3& val)
275 {
276 WStringStream stream;
277 stream << val[0][0] << L" "
278 << val[0][1] << L" "
279 << val[0][2] << L" "
280 << val[1][0] << L" "
281 << val[1][1] << L" "
282 << val[1][2] << L" "
283 << val[2][0] << L" "
284 << val[2][1] << L" "
285 << val[2][2];
286 return stream.str();
287 }
288
289 WString toWString(bool val, bool yesNo)
290 {
291 if (val)
292 {
293 if (yesNo)
294 {
295 return L"yes";
296 }
297 else
298 {
299 return L"true";
300 }
301 }
302 else
303 if (yesNo)
304 {
305 return L"no";
306 }
307 else
308 {
309 return L"false";
310 }
311 }
312
313 WString toWString(const Matrix4& val)
314 {
315 WStringStream stream;
316 stream << val[0][0] << L" "
317 << val[0][1] << L" "
318 << val[0][2] << L" "
319 << val[0][3] << L" "
320 << val[1][0] << L" "
321 << val[1][1] << L" "
322 << val[1][2] << L" "
323 << val[1][3] << L" "
324 << val[2][0] << L" "
325 << val[2][1] << L" "
326 << val[2][2] << L" "
327 << val[2][3] << L" "
328 << val[3][0] << L" "
329 << val[3][1] << L" "
330 << val[3][2] << L" "
331 << val[3][3];
332 return stream.str();
333 }
334
335 WString toWString(const Quaternion& val)
336 {
337 WStringStream stream;
338 stream << val.w << L" " << val.x << L" " << val.y << L" " << val.z;
339 return stream.str();
340 }
341
342 WString toWString(const Color& val)
343 {
344 WStringStream stream;
345 stream << val.r << L" " << val.g << L" " << val.b << L" " << val.a;
346 return stream.str();
347 }
348
349 WString toWString(const Vector<bs::WString>& val)
350 {
351 WStringStream stream;
352 Vector<bs::WString>::const_iterator i, iend, ibegin;
353 ibegin = val.begin();
354 iend = val.end();
355 for (i = ibegin; i != iend; ++i)
356 {
357 if (i != ibegin)
358 stream << L" ";
359
360 stream << *i;
361 }
362 return stream.str();
363 }
364
365 String toString(const WString& source)
366 {
367 return String(source.begin(), source.end());
368 }
369
370 String toString(const wchar_t* source)
371 {
372 return toString(WString(source));
373 }
374
375 String toString(float val, unsigned short precision,
376 unsigned short width, char fill, std::ios::fmtflags flags)
377 {
378 StringStream stream;
379 stream.precision(precision);
380 stream.width(width);
381 stream.fill(fill);
382 if (flags)
383 stream.setf(flags);
384 stream << val;
385 return stream.str();
386 }
387
388 String toString(double val, unsigned short precision,
389 unsigned short width, char fill, std::ios::fmtflags flags)
390 {
391 StringStream stream;
392 stream.precision(precision);
393 stream.width(width);
394 stream.fill(fill);
395 if (flags)
396 stream.setf(flags);
397 stream << val;
398 return stream.str();
399 }
400
401 String toString(Radian val, unsigned short precision,
402 unsigned short width, char fill, std::ios::fmtflags flags)
403 {
404 return toString(val.valueRadians(), precision, width, fill, flags);
405 }
406
407 String toString(Degree val, unsigned short precision,
408 unsigned short width, char fill, std::ios::fmtflags flags)
409 {
410 return toString(val.valueDegrees(), precision, width, fill, flags);
411 }
412
413 String toString(int val,
414 unsigned short width, char fill, std::ios::fmtflags flags)
415 {
416 StringStream stream;
417 stream.width(width);
418 stream.fill(fill);
419 if (flags)
420 stream.setf(flags);
421 stream << val;
422 return stream.str();
423 }
424
425 String toString(unsigned int val, unsigned short width, char fill, std::ios::fmtflags flags)
426 {
427 StringStream stream;
428 stream.width(width);
429 stream.fill(fill);
430 if (flags)
431 stream.setf(flags);
432 stream << val;
433 return stream.str();
434 }
435
436 String toString(INT64 val,
437 unsigned short width, char fill, std::ios::fmtflags flags)
438 {
439 StringStream stream;
440 stream.width(width);
441 stream.fill(fill);
442 if (flags)
443 stream.setf(flags);
444 stream << val;
445 return stream.str();
446 }
447
448 String toString(UINT64 val, unsigned short width, char fill, std::ios::fmtflags flags)
449 {
450 StringStream stream;
451 stream.width(width);
452 stream.fill(fill);
453 if (flags)
454 stream.setf(flags);
455 stream << val;
456 return stream.str();
457 }
458
459 String toString(const Vector2& val)
460 {
461 StringStream stream;
462 stream << val.x << " " << val.y;
463 return stream.str();
464 }
465
466 String toString(const Vector2I& val)
467 {
468 StringStream stream;
469 stream << val.x << " " << val.y;
470 return stream.str();
471 }
472
473 String toString(const Vector3& val)
474 {
475 StringStream stream;
476 stream << val.x << " " << val.y << " " << val.z;
477 return stream.str();
478 }
479
480 String toString(const Vector4& val)
481 {
482 StringStream stream;
483 stream << val.x << " " << val.y << " " << val.z << " " << val.w;
484 return stream.str();
485 }
486
487 String toString(const Matrix3& val)
488 {
489 StringStream stream;
490 stream << val[0][0] << " "
491 << val[0][1] << " "
492 << val[0][2] << " "
493 << val[1][0] << " "
494 << val[1][1] << " "
495 << val[1][2] << " "
496 << val[2][0] << " "
497 << val[2][1] << " "
498 << val[2][2];
499 return stream.str();
500 }
501
502 String toString(bool val, bool yesNo)
503 {
504 if (val)
505 {
506 if (yesNo)
507 {
508 return "yes";
509 }
510 else
511 {
512 return "true";
513 }
514 }
515 else
516 if (yesNo)
517 {
518 return "no";
519 }
520 else
521 {
522 return "false";
523 }
524 }
525
526 String toString(const Matrix4& val)
527 {
528 StringStream stream;
529 stream << val[0][0] << " "
530 << val[0][1] << " "
531 << val[0][2] << " "
532 << val[0][3] << " "
533 << val[1][0] << " "
534 << val[1][1] << " "
535 << val[1][2] << " "
536 << val[1][3] << " "
537 << val[2][0] << " "
538 << val[2][1] << " "
539 << val[2][2] << " "
540 << val[2][3] << " "
541 << val[3][0] << " "
542 << val[3][1] << " "
543 << val[3][2] << " "
544 << val[3][3];
545 return stream.str();
546 }
547
548 String toString(const Quaternion& val)
549 {
550 StringStream stream;
551 stream << val.w << " " << val.x << " " << val.y << " " << val.z;
552 return stream.str();
553 }
554
555 String toString(const Color& val)
556 {
557 StringStream stream;
558 stream << val.r << " " << val.g << " " << val.b << " " << val.a;
559 return stream.str();
560 }
561
562 String toString(const Vector<bs::String>& val)
563 {
564 StringStream stream;
565 Vector<bs::String>::const_iterator i, iend, ibegin;
566 ibegin = val.begin();
567 iend = val.end();
568 for (i = ibegin; i != iend; ++i)
569 {
570 if (i != ibegin)
571 stream << " ";
572
573 stream << *i;
574 }
575 return stream.str();
576 }
577
578 float parseFloat(const String& val, float defaultValue)
579 {
580 // Use istringstream for direct correspondence with toString
581 StringStream str(val);
582 float ret = defaultValue;
583 str >> ret;
584
585 return ret;
586 }
587
588 INT32 parseINT32(const String& val, INT32 defaultValue)
589 {
590 // Use istringstream for direct correspondence with toString
591 StringStream str(val);
592 INT32 ret = defaultValue;
593 str >> ret;
594
595 return ret;
596 }
597
598 UINT32 parseUINT32(const String& val, UINT32 defaultValue)
599 {
600 // Use istringstream for direct correspondence with toString
601 StringStream str(val);
602 UINT32 ret = defaultValue;
603 str >> ret;
604
605 return ret;
606 }
607
608 INT64 parseINT64(const String& val, INT64 defaultValue)
609 {
610 // Use istringstream for direct correspondence with toString
611 StringStream str(val);
612 INT64 ret = defaultValue;
613 str >> ret;
614
615 return ret;
616 }
617
618 UINT64 parseUINT64(const String& val, UINT64 defaultValue)
619 {
620 // Use istringstream for direct correspondence with toString
621 StringStream str(val);
622 UINT64 ret = defaultValue;
623 str >> ret;
624
625 return ret;
626 }
627
628 bool parseBool(const String& val, bool defaultValue)
629 {
630 if ((StringUtil::startsWith(val, "true") || StringUtil::startsWith(val, "yes")
631 || StringUtil::startsWith(val, "1")))
632 return true;
633 else if ((StringUtil::startsWith(val, "false") || StringUtil::startsWith(val, "no")
634 || StringUtil::startsWith(val, "0")))
635 return false;
636 else
637 return defaultValue;
638 }
639
640 bool isNumber(const String& val)
641 {
642 StringStream str(val);
643 float tst;
644 str >> tst;
645 return !str.fail() && str.eof();
646 }
647
648 float parseFloat(const WString& val, float defaultValue)
649 {
650 // Use istringstream for direct correspondence with toString
651 WStringStream str(val);
652 float ret = defaultValue;
653 str >> ret;
654
655 return ret;
656 }
657
658 INT32 parseINT32(const WString& val, INT32 defaultValue)
659 {
660 // Use istringstream for direct correspondence with toString
661 WStringStream str(val);
662 INT32 ret = defaultValue;
663 str >> ret;
664
665 return ret;
666 }
667
668 UINT32 parseUINT32(const WString& val, UINT32 defaultValue)
669 {
670 // Use istringstream for direct correspondence with toString
671 WStringStream str(val);
672 UINT32 ret = defaultValue;
673 str >> ret;
674
675 return ret;
676 }
677
678 INT64 parseINT64(const WString& val, INT64 defaultValue)
679 {
680 // Use istringstream for direct correspondence with toString
681 WStringStream str(val);
682 INT64 ret = defaultValue;
683 str >> ret;
684
685 return ret;
686 }
687
688 UINT64 parseUINT64(const WString& val, UINT64 defaultValue)
689 {
690 // Use istringstream for direct correspondence with toString
691 WStringStream str(val);
692 UINT64 ret = defaultValue;
693 str >> ret;
694
695 return ret;
696 }
697
698 bool parseBool(const WString& val, bool defaultValue)
699 {
700 if ((StringUtil::startsWith(val, L"true") || StringUtil::startsWith(val, L"yes")
701 || StringUtil::startsWith(val, L"1")))
702 return true;
703 else if ((StringUtil::startsWith(val, L"false") || StringUtil::startsWith(val, L"no")
704 || StringUtil::startsWith(val, L"0")))
705 return false;
706 else
707 return defaultValue;
708 }
709
710 bool isNumber(const WString& val)
711 {
712 WStringStream str(val);
713 float tst;
714 str >> tst;
715 return !str.fail() && str.eof();
716 }
717
718 void __string_throwDataOverflowException()
719 {
720 BS_EXCEPT(InternalErrorException, "Data overflow! Size doesn't fit into 32 bits.");
721 }
722}
723