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 "../Core/StringUtils.h"
26
27 #include <cstdio>
28
29 #include "../DebugNew.h"
30
31 namespace Urho3D
32 {
33
34 static const String base64_chars =
35 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
36 "abcdefghijklmnopqrstuvwxyz"
37 "0123456789+/";
38
CountElements(const char * buffer,char separator)39 unsigned CountElements(const char* buffer, char separator)
40 {
41 if (!buffer)
42 return 0;
43
44 const char* endPos = buffer + String::CStringLength(buffer);
45 const char* pos = buffer;
46 unsigned ret = 0;
47
48 while (pos < endPos)
49 {
50 if (*pos != separator)
51 break;
52 ++pos;
53 }
54
55 while (pos < endPos)
56 {
57 const char* start = pos;
58
59 while (start < endPos)
60 {
61 if (*start == separator)
62 break;
63
64 ++start;
65 }
66
67 if (start == endPos)
68 {
69 ++ret;
70 break;
71 }
72
73 const char* end = start;
74
75 while (end < endPos)
76 {
77 if (*end != separator)
78 break;
79
80 ++end;
81 }
82
83 ++ret;
84 pos = end;
85 }
86
87 return ret;
88 }
89
ToBool(const String & source)90 bool ToBool(const String& source)
91 {
92 return ToBool(source.CString());
93 }
94
ToBool(const char * source)95 bool ToBool(const char* source)
96 {
97 unsigned length = String::CStringLength(source);
98
99 for (unsigned i = 0; i < length; ++i)
100 {
101 char c = (char)tolower(source[i]);
102 if (c == 't' || c == 'y' || c == '1')
103 return true;
104 else if (c != ' ' && c != '\t')
105 break;
106 }
107
108 return false;
109 }
110
ToInt(const String & source,int base)111 int ToInt(const String& source, int base)
112 {
113 return ToInt(source.CString(), base);
114 }
115
ToInt(const char * source,int base)116 int ToInt(const char* source, int base)
117 {
118 if (!source)
119 return 0;
120
121 // Shield against runtime library assert by converting illegal base values to 0 (autodetect)
122 if (base < 2 || base > 36)
123 base = 0;
124
125 return (int)strtol(source, 0, base);
126 }
127
ToInt64(const char * source,int base)128 long long ToInt64(const char* source, int base)
129 {
130 if (!source)
131 return 0;
132
133 // Shield against runtime library assert by converting illegal base values to 0 (autodetect)
134 if (base < 2 || base > 36)
135 base = 0;
136
137 return strtoll(source, 0, base);
138 }
139
ToInt64(const String & source,int base)140 long long ToInt64(const String& source, int base)
141 {
142 return ToInt64(source.CString(), base);
143 }
144
ToUInt(const String & source,int base)145 unsigned ToUInt(const String& source, int base)
146 {
147 return ToUInt(source.CString(), base);
148 }
149
ToUInt64(const char * source,int base)150 unsigned long long ToUInt64(const char* source, int base)
151 {
152 if (!source)
153 return 0;
154
155 // Shield against runtime library assert by converting illegal base values to 0 (autodetect)
156 if (base < 2 || base > 36)
157 base = 0;
158
159 return strtoull(source, 0, base);
160 }
161
ToUInt64(const String & source,int base)162 unsigned long long ToUInt64(const String& source, int base)
163 {
164 return ToUInt64(source.CString(), base);
165 }
166
ToUInt(const char * source,int base)167 unsigned ToUInt(const char* source, int base)
168 {
169 if (!source)
170 return 0;
171
172 if (base < 2 || base > 36)
173 base = 0;
174
175 return (unsigned)strtoul(source, 0, base);
176 }
177
ToFloat(const String & source)178 float ToFloat(const String& source)
179 {
180 return ToFloat(source.CString());
181 }
182
ToFloat(const char * source)183 float ToFloat(const char* source)
184 {
185 if (!source)
186 return 0;
187
188 return (float)strtod(source, 0);
189 }
190
ToDouble(const String & source)191 double ToDouble(const String& source)
192 {
193 return ToDouble(source.CString());
194 }
195
ToDouble(const char * source)196 double ToDouble(const char* source)
197 {
198 if (!source)
199 return 0;
200
201 return strtod(source, 0);
202 }
203
ToColor(const String & source)204 Color ToColor(const String& source)
205 {
206 return ToColor(source.CString());
207 }
208
ToColor(const char * source)209 Color ToColor(const char* source)
210 {
211 Color ret;
212
213 unsigned elements = CountElements(source, ' ');
214 if (elements < 3)
215 return ret;
216
217 char* ptr = (char*)source;
218 ret.r_ = (float)strtod(ptr, &ptr);
219 ret.g_ = (float)strtod(ptr, &ptr);
220 ret.b_ = (float)strtod(ptr, &ptr);
221 if (elements > 3)
222 ret.a_ = (float)strtod(ptr, &ptr);
223
224 return ret;
225 }
226
ToIntRect(const String & source)227 IntRect ToIntRect(const String& source)
228 {
229 return ToIntRect(source.CString());
230 }
231
ToIntRect(const char * source)232 IntRect ToIntRect(const char* source)
233 {
234 IntRect ret(IntRect::ZERO);
235
236 unsigned elements = CountElements(source, ' ');
237 if (elements < 4)
238 return ret;
239
240 char* ptr = (char*)source;
241 ret.left_ = (int)strtol(ptr, &ptr, 10);
242 ret.top_ = (int)strtol(ptr, &ptr, 10);
243 ret.right_ = (int)strtol(ptr, &ptr, 10);
244 ret.bottom_ = (int)strtol(ptr, &ptr, 10);
245
246 return ret;
247 }
248
ToIntVector2(const String & source)249 IntVector2 ToIntVector2(const String& source)
250 {
251 return ToIntVector2(source.CString());
252 }
253
ToIntVector2(const char * source)254 IntVector2 ToIntVector2(const char* source)
255 {
256 IntVector2 ret(IntVector2::ZERO);
257
258 unsigned elements = CountElements(source, ' ');
259 if (elements < 2)
260 return ret;
261
262 char* ptr = (char*)source;
263 ret.x_ = (int)strtol(ptr, &ptr, 10);
264 ret.y_ = (int)strtol(ptr, &ptr, 10);
265
266 return ret;
267 }
268
ToIntVector3(const String & source)269 IntVector3 ToIntVector3(const String& source)
270 {
271 return ToIntVector3(source.CString());
272 }
273
ToIntVector3(const char * source)274 IntVector3 ToIntVector3(const char* source)
275 {
276 IntVector3 ret(IntVector3::ZERO);
277
278 unsigned elements = CountElements(source, ' ');
279 if (elements < 3)
280 return ret;
281
282 char* ptr = (char*)source;
283 ret.x_ = (int)strtol(ptr, &ptr, 10);
284 ret.y_ = (int)strtol(ptr, &ptr, 10);
285 ret.z_ = (int)strtol(ptr, &ptr, 10);
286
287 return ret;
288 }
289
ToRect(const String & source)290 Rect ToRect(const String& source)
291 {
292 return ToRect(source.CString());
293 }
294
ToRect(const char * source)295 Rect ToRect(const char* source)
296 {
297 Rect ret(Rect::ZERO);
298
299 unsigned elements = CountElements(source, ' ');
300 if (elements < 4)
301 return ret;
302
303 char* ptr = (char*)source;
304 ret.min_.x_ = (float)strtod(ptr, &ptr);
305 ret.min_.y_ = (float)strtod(ptr, &ptr);
306 ret.max_.x_ = (float)strtod(ptr, &ptr);
307 ret.max_.y_ = (float)strtod(ptr, &ptr);
308
309 return ret;
310 }
311
ToQuaternion(const String & source)312 Quaternion ToQuaternion(const String& source)
313 {
314 return ToQuaternion(source.CString());
315 }
316
ToQuaternion(const char * source)317 Quaternion ToQuaternion(const char* source)
318 {
319 unsigned elements = CountElements(source, ' ');
320 char* ptr = (char*)source;
321
322 if (elements < 3)
323 return Quaternion::IDENTITY;
324 else if (elements < 4)
325 {
326 // 3 coords specified: conversion from Euler angles
327 float x, y, z;
328 x = (float)strtod(ptr, &ptr);
329 y = (float)strtod(ptr, &ptr);
330 z = (float)strtod(ptr, &ptr);
331
332 return Quaternion(x, y, z);
333 }
334 else
335 {
336 // 4 coords specified: full quaternion
337 Quaternion ret;
338 ret.w_ = (float)strtod(ptr, &ptr);
339 ret.x_ = (float)strtod(ptr, &ptr);
340 ret.y_ = (float)strtod(ptr, &ptr);
341 ret.z_ = (float)strtod(ptr, &ptr);
342
343 return ret;
344 }
345 }
346
ToVector2(const String & source)347 Vector2 ToVector2(const String& source)
348 {
349 return ToVector2(source.CString());
350 }
351
ToVector2(const char * source)352 Vector2 ToVector2(const char* source)
353 {
354 Vector2 ret(Vector2::ZERO);
355
356 unsigned elements = CountElements(source, ' ');
357 if (elements < 2)
358 return ret;
359
360 char* ptr = (char*)source;
361 ret.x_ = (float)strtod(ptr, &ptr);
362 ret.y_ = (float)strtod(ptr, &ptr);
363
364 return ret;
365 }
366
ToVector3(const String & source)367 Vector3 ToVector3(const String& source)
368 {
369 return ToVector3(source.CString());
370 }
371
ToVector3(const char * source)372 Vector3 ToVector3(const char* source)
373 {
374 Vector3 ret(Vector3::ZERO);
375
376 unsigned elements = CountElements(source, ' ');
377 if (elements < 3)
378 return ret;
379
380 char* ptr = (char*)source;
381 ret.x_ = (float)strtod(ptr, &ptr);
382 ret.y_ = (float)strtod(ptr, &ptr);
383 ret.z_ = (float)strtod(ptr, &ptr);
384
385 return ret;
386 }
387
ToVector4(const String & source,bool allowMissingCoords)388 Vector4 ToVector4(const String& source, bool allowMissingCoords)
389 {
390 return ToVector4(source.CString(), allowMissingCoords);
391 }
392
ToVector4(const char * source,bool allowMissingCoords)393 Vector4 ToVector4(const char* source, bool allowMissingCoords)
394 {
395 Vector4 ret(Vector4::ZERO);
396
397 unsigned elements = CountElements(source, ' ');
398 char* ptr = (char*)source;
399
400 if (!allowMissingCoords)
401 {
402 if (elements < 4)
403 return ret;
404
405 ret.x_ = (float)strtod(ptr, &ptr);
406 ret.y_ = (float)strtod(ptr, &ptr);
407 ret.z_ = (float)strtod(ptr, &ptr);
408 ret.w_ = (float)strtod(ptr, &ptr);
409
410 return ret;
411 }
412 else
413 {
414 if (elements > 0)
415 ret.x_ = (float)strtod(ptr, &ptr);
416 if (elements > 1)
417 ret.y_ = (float)strtod(ptr, &ptr);
418 if (elements > 2)
419 ret.z_ = (float)strtod(ptr, &ptr);
420 if (elements > 3)
421 ret.w_ = (float)strtod(ptr, &ptr);
422
423 return ret;
424 }
425 }
426
ToVectorVariant(const String & source)427 Variant ToVectorVariant(const String& source)
428 {
429 return ToVectorVariant(source.CString());
430 }
431
ToVectorVariant(const char * source)432 Variant ToVectorVariant(const char* source)
433 {
434 Variant ret;
435 unsigned elements = CountElements(source, ' ');
436
437 switch (elements)
438 {
439 case 1:
440 ret.FromString(VAR_FLOAT, source);
441 break;
442
443 case 2:
444 ret.FromString(VAR_VECTOR2, source);
445 break;
446
447 case 3:
448 ret.FromString(VAR_VECTOR3, source);
449 break;
450
451 case 4:
452 ret.FromString(VAR_VECTOR4, source);
453 break;
454
455 case 9:
456 ret.FromString(VAR_MATRIX3, source);
457 break;
458
459 case 12:
460 ret.FromString(VAR_MATRIX3X4, source);
461 break;
462
463 case 16:
464 ret.FromString(VAR_MATRIX4, source);
465 break;
466
467 default:
468 // Illegal input. Return variant remains empty
469 break;
470 }
471
472 return ret;
473 }
474
ToMatrix3(const String & source)475 Matrix3 ToMatrix3(const String& source)
476 {
477 return ToMatrix3(source.CString());
478 }
479
ToMatrix3(const char * source)480 Matrix3 ToMatrix3(const char* source)
481 {
482 Matrix3 ret(Matrix3::ZERO);
483
484 unsigned elements = CountElements(source, ' ');
485 if (elements < 9)
486 return ret;
487
488 char* ptr = (char*)source;
489 ret.m00_ = (float)strtod(ptr, &ptr);
490 ret.m01_ = (float)strtod(ptr, &ptr);
491 ret.m02_ = (float)strtod(ptr, &ptr);
492 ret.m10_ = (float)strtod(ptr, &ptr);
493 ret.m11_ = (float)strtod(ptr, &ptr);
494 ret.m12_ = (float)strtod(ptr, &ptr);
495 ret.m20_ = (float)strtod(ptr, &ptr);
496 ret.m21_ = (float)strtod(ptr, &ptr);
497 ret.m22_ = (float)strtod(ptr, &ptr);
498
499 return ret;
500 }
501
ToMatrix3x4(const String & source)502 Matrix3x4 ToMatrix3x4(const String& source)
503 {
504 return ToMatrix3x4(source.CString());
505 }
506
ToMatrix3x4(const char * source)507 Matrix3x4 ToMatrix3x4(const char* source)
508 {
509 Matrix3x4 ret(Matrix3x4::ZERO);
510
511 unsigned elements = CountElements(source, ' ');
512 if (elements < 12)
513 return ret;
514
515 char* ptr = (char*)source;
516 ret.m00_ = (float)strtod(ptr, &ptr);
517 ret.m01_ = (float)strtod(ptr, &ptr);
518 ret.m02_ = (float)strtod(ptr, &ptr);
519 ret.m03_ = (float)strtod(ptr, &ptr);
520 ret.m10_ = (float)strtod(ptr, &ptr);
521 ret.m11_ = (float)strtod(ptr, &ptr);
522 ret.m12_ = (float)strtod(ptr, &ptr);
523 ret.m13_ = (float)strtod(ptr, &ptr);
524 ret.m20_ = (float)strtod(ptr, &ptr);
525 ret.m21_ = (float)strtod(ptr, &ptr);
526 ret.m22_ = (float)strtod(ptr, &ptr);
527 ret.m23_ = (float)strtod(ptr, &ptr);
528
529 return ret;
530 }
531
ToMatrix4(const String & source)532 Matrix4 ToMatrix4(const String& source)
533 {
534 return ToMatrix4(source.CString());
535 }
536
ToMatrix4(const char * source)537 Matrix4 ToMatrix4(const char* source)
538 {
539 Matrix4 ret(Matrix4::ZERO);
540
541 unsigned elements = CountElements(source, ' ');
542 if (elements < 16)
543 return ret;
544
545 char* ptr = (char*)source;
546 ret.m00_ = (float)strtod(ptr, &ptr);
547 ret.m01_ = (float)strtod(ptr, &ptr);
548 ret.m02_ = (float)strtod(ptr, &ptr);
549 ret.m03_ = (float)strtod(ptr, &ptr);
550 ret.m10_ = (float)strtod(ptr, &ptr);
551 ret.m11_ = (float)strtod(ptr, &ptr);
552 ret.m12_ = (float)strtod(ptr, &ptr);
553 ret.m13_ = (float)strtod(ptr, &ptr);
554 ret.m20_ = (float)strtod(ptr, &ptr);
555 ret.m21_ = (float)strtod(ptr, &ptr);
556 ret.m22_ = (float)strtod(ptr, &ptr);
557 ret.m23_ = (float)strtod(ptr, &ptr);
558 ret.m30_ = (float)strtod(ptr, &ptr);
559 ret.m31_ = (float)strtod(ptr, &ptr);
560 ret.m32_ = (float)strtod(ptr, &ptr);
561 ret.m33_ = (float)strtod(ptr, &ptr);
562
563 return ret;
564 }
565
ToString(void * value)566 String ToString(void* value)
567 {
568 return ToStringHex((unsigned)(size_t)value);
569 }
570
ToStringHex(unsigned value)571 String ToStringHex(unsigned value)
572 {
573 char tempBuffer[CONVERSION_BUFFER_LENGTH];
574 sprintf(tempBuffer, "%08x", value);
575 return String(tempBuffer);
576 }
577
BufferToString(String & dest,const void * data,unsigned size)578 void BufferToString(String& dest, const void* data, unsigned size)
579 {
580 // Precalculate needed string size
581 const unsigned char* bytes = (const unsigned char*)data;
582 unsigned length = 0;
583 for (unsigned i = 0; i < size; ++i)
584 {
585 // Room for separator
586 if (i)
587 ++length;
588
589 // Room for the value
590 if (bytes[i] < 10)
591 ++length;
592 else if (bytes[i] < 100)
593 length += 2;
594 else
595 length += 3;
596 }
597
598 dest.Resize(length);
599 unsigned index = 0;
600
601 // Convert values
602 for (unsigned i = 0; i < size; ++i)
603 {
604 if (i)
605 dest[index++] = ' ';
606
607 if (bytes[i] < 10)
608 {
609 dest[index++] = '0' + bytes[i];
610 }
611 else if (bytes[i] < 100)
612 {
613 dest[index++] = (char)('0' + bytes[i] / 10);
614 dest[index++] = (char)('0' + bytes[i] % 10);
615 }
616 else
617 {
618 dest[index++] = (char)('0' + bytes[i] / 100);
619 dest[index++] = (char)('0' + bytes[i] % 100 / 10);
620 dest[index++] = (char)('0' + bytes[i] % 10);
621 }
622 }
623 }
624
StringToBuffer(PODVector<unsigned char> & dest,const String & source)625 void StringToBuffer(PODVector<unsigned char>& dest, const String& source)
626 {
627 StringToBuffer(dest, source.CString());
628 }
629
StringToBuffer(PODVector<unsigned char> & dest,const char * source)630 void StringToBuffer(PODVector<unsigned char>& dest, const char* source)
631 {
632 if (!source)
633 {
634 dest.Clear();
635 return;
636 }
637
638 unsigned size = CountElements(source, ' ');
639 dest.Resize(size);
640
641 bool inSpace = true;
642 unsigned index = 0;
643 unsigned value = 0;
644
645 // Parse values
646 const char* ptr = source;
647 while (*ptr)
648 {
649 if (inSpace && *ptr != ' ')
650 {
651 inSpace = false;
652 value = (unsigned)(*ptr - '0');
653 }
654 else if (!inSpace && *ptr != ' ')
655 {
656 value *= 10;
657 value += *ptr - '0';
658 }
659 else if (!inSpace && *ptr == ' ')
660 {
661 dest[index++] = (unsigned char)value;
662 inSpace = true;
663 }
664
665 ++ptr;
666 }
667
668 // Write the final value
669 if (!inSpace && index < size)
670 dest[index] = (unsigned char)value;
671 }
672
GetStringListIndex(const String & value,const String * strings,unsigned defaultIndex,bool caseSensitive)673 unsigned GetStringListIndex(const String& value, const String* strings, unsigned defaultIndex, bool caseSensitive)
674 {
675 return GetStringListIndex(value.CString(), strings, defaultIndex, caseSensitive);
676 }
677
GetStringListIndex(const char * value,const String * strings,unsigned defaultIndex,bool caseSensitive)678 unsigned GetStringListIndex(const char* value, const String* strings, unsigned defaultIndex, bool caseSensitive)
679 {
680 unsigned i = 0;
681
682 while (!strings[i].Empty())
683 {
684 if (!strings[i].Compare(value, caseSensitive))
685 return i;
686 ++i;
687 }
688
689 return defaultIndex;
690 }
691
GetStringListIndex(const char * value,const char ** strings,unsigned defaultIndex,bool caseSensitive)692 unsigned GetStringListIndex(const char* value, const char** strings, unsigned defaultIndex, bool caseSensitive)
693 {
694 unsigned i = 0;
695
696 while (strings[i])
697 {
698 if (!String::Compare(value, strings[i], caseSensitive))
699 return i;
700 ++i;
701 }
702
703 return defaultIndex;
704 }
705
ToString(const char * formatString,...)706 String ToString(const char* formatString, ...)
707 {
708 String ret;
709 va_list args;
710 va_start(args, formatString);
711 ret.AppendWithFormatArgs(formatString, args);
712 va_end(args);
713 return ret;
714 }
715
IsAlpha(unsigned ch)716 bool IsAlpha(unsigned ch)
717 {
718 return ch < 256 ? isalpha(ch) != 0 : false;
719 }
720
IsDigit(unsigned ch)721 bool IsDigit(unsigned ch)
722 {
723 return ch < 256 ? isdigit(ch) != 0 : false;
724 }
725
ToUpper(unsigned ch)726 unsigned ToUpper(unsigned ch)
727 {
728 return (unsigned)toupper(ch);
729 }
730
ToLower(unsigned ch)731 unsigned ToLower(unsigned ch)
732 {
733 return (unsigned)tolower(ch);
734 }
735
GetFileSizeString(unsigned long long memorySize)736 String GetFileSizeString(unsigned long long memorySize)
737 {
738 static const char* memorySizeStrings = "kMGTPE";
739
740 String output;
741
742 if (memorySize < 1024)
743 {
744 output = String(memorySize) + " b";
745 }
746 else
747 {
748 const int exponent = (int)(log((double)memorySize) / log(1024.0));
749 const double majorValue = ((double)memorySize) / pow(1024.0, exponent);
750 char buffer[64];
751 memset(buffer, 0, 64);
752 sprintf(buffer, "%.1f", majorValue);
753 output = buffer;
754 output += " ";
755 output += memorySizeStrings[exponent - 1];
756 }
757
758 return output;
759 }
760
761 // Implementation of base64 decoding originally by Ren� Nyffenegger.
762 // Modified by Konstantin Guschin and Lasse Oorni
763
764 /*
765 base64.cpp and base64.h
766
767 Copyright (C) 2004-2017 Ren� Nyffenegger
768
769 This source code is provided 'as-is', without any express or implied
770 warranty. In no event will the author be held liable for any damages
771 arising from the use of this software.
772
773 Permission is granted to anyone to use this software for any purpose,
774 including commercial applications, and to alter it and redistribute it
775 freely, subject to the following restrictions:
776
777 1. The origin of this source code must not be misrepresented; you must not
778 claim that you wrote the original source code. If you use this source code
779 in a product, an acknowledgment in the product documentation would be
780 appreciated but is not required.
781
782 2. Altered source versions must be plainly marked as such, and must not be
783 misrepresented as being the original source code.
784
785 3. This notice may not be removed or altered from any source distribution.
786
787 Ren� Nyffenegger rene.nyffenegger@adp-gmbh.ch
788
789 */
790
IsBase64(char c)791 static inline bool IsBase64(char c) {
792 return (isalnum(c) || (c == '+') || (c == '/'));
793 }
794
DecodeBase64(String encodedString)795 PODVector<unsigned char> DecodeBase64(String encodedString)
796 {
797 int inLen = encodedString.Length();
798 int i = 0;
799 int j = 0;
800 int in_ = 0;
801 unsigned char charArray4[4], charArray3[3];
802 PODVector<unsigned char> ret;
803
804 while (inLen-- && (encodedString[in_] != '=') && IsBase64(encodedString[in_]))
805 {
806 charArray4[i++] = encodedString[in_];
807 in_++;
808
809 if (i == 4)
810 {
811 for (i = 0; i < 4; i++)
812 charArray4[i] = base64_chars.Find(charArray4[i]);
813
814 charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4);
815 charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2);
816 charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3];
817
818 for (i = 0; (i < 3); i++)
819 ret.Push(charArray3[i]);
820
821 i = 0;
822 }
823 }
824
825 if (i)
826 {
827 for (j = i; j <4; j++)
828 charArray4[j] = 0;
829
830 for (j = 0; j <4; j++)
831 charArray4[j] = base64_chars.Find(charArray4[j]);
832
833 charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4);
834 charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2);
835 charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3];
836
837 for (j = 0; (j < i - 1); j++)
838 ret.Push(charArray3[j]);
839 }
840
841 return ret;
842 }
843
844 }
845