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 | |
14 | namespace 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 | |