Merge pull request #25959 from neo1973/TagLib_deprecation_warnings
[xbmc.git] / lib / libUPnP / Neptune / Source / Core / NptStrings.cpp
blob819d9a2029cdf5edea64220d8fb15ae3160f3a78
1 /*****************************************************************
3 | Neptune - String Objects
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of Axiomatic Systems nor the
16 | names of its contributors may be used to endorse or promote products
17 | derived from this software without specific prior written permission.
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 ****************************************************************/
32 /*----------------------------------------------------------------------
33 | includes
34 +---------------------------------------------------------------------*/
35 #include "NptConfig.h"
36 #include "NptTypes.h"
37 #include "NptConstants.h"
38 #include "NptStrings.h"
39 #include "NptResults.h"
40 #include "NptUtils.h"
41 #include "NptDebug.h"
43 /*----------------------------------------------------------------------
44 | constants
45 +---------------------------------------------------------------------*/
46 #define NPT_STRINGS_WHITESPACE_CHARS "\r\n\t "
48 const unsigned int NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE = 256;
49 const unsigned int NPT_STRING_FORMAT_BUFFER_MAX_SIZE = 0x80000; // 512k
51 /*----------------------------------------------------------------------
52 | helpers
53 +---------------------------------------------------------------------*/
54 inline char NPT_Uppercase(char x) {
55 return (x >= 'a' && x <= 'z') ? x&0xdf : x;
58 inline char NPT_Lowercase(char x) {
59 return (x >= 'A' && x <= 'Z') ? x^32 : x;
62 /*----------------------------------------------------------------------
63 | NPT_String::EmptyString
64 +---------------------------------------------------------------------*/
65 char NPT_String::EmptyString = '\0';
67 /*----------------------------------------------------------------------
68 | NPT_String::FromInteger
69 +---------------------------------------------------------------------*/
70 NPT_String
71 NPT_String::FromInteger(NPT_Int64 value)
73 char str[32];
74 char* c = &str[31];
75 *c-- = '\0';
77 // handle the sign
78 bool negative = false;
79 if (value < 0) {
80 negative = true;
81 value = -value;
84 // process the digits
85 do {
86 int digit = (int)(value%10);
87 *c-- = '0'+digit;
88 value /= 10;
89 } while(value);
91 if (negative) {
92 *c = '-';
93 } else {
94 ++c;
97 return NPT_String(c);
100 /*----------------------------------------------------------------------
101 | NPT_String::FromIntegerU
102 +---------------------------------------------------------------------*/
103 NPT_String
104 NPT_String::FromIntegerU(NPT_UInt64 value)
106 char str[32];
107 char* c = &str[31];
108 *c = '\0';
110 // process the digits
111 do {
112 int digit = (int)(value%10);
113 *--c = '0'+digit;
114 value /= 10;
115 } while(value);
117 return NPT_String(c);
120 /*----------------------------------------------------------------------
121 | NPT_String::Format
122 +---------------------------------------------------------------------*/
123 NPT_String
124 NPT_String::Format(const char* format, ...)
126 NPT_String result;
127 NPT_Size buffer_size = NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE; // default value
129 va_list args;
131 for(;;) {
132 /* try to format (it might not fit) */
133 result.Reserve(buffer_size);
134 char* buffer = result.UseChars();
135 va_start(args, format);
136 int f_result = NPT_FormatStringVN(buffer, buffer_size, format, args);
137 va_end(args);
138 if (f_result >= (int)(buffer_size)) f_result = -1;
139 if (f_result >= 0) {
140 result.SetLength(f_result);
141 break;
144 /* the buffer was too small, try something bigger */
145 /* (we don't trust the return value of NPT_FormatStringVN */
146 /* for the actual size needed) */
147 buffer_size *= 2;
148 if (buffer_size > NPT_STRING_FORMAT_BUFFER_MAX_SIZE) break;
151 return result;
154 /*----------------------------------------------------------------------
155 | NPT_String::NPT_String
156 +---------------------------------------------------------------------*/
157 NPT_String::NPT_String(const char* str)
159 if (str == NULL) {
160 m_Chars = NULL;
161 } else {
162 m_Chars = Buffer::Create(str);
166 /*----------------------------------------------------------------------
167 | NPT_String::NPT_String
168 +---------------------------------------------------------------------*/
169 NPT_String::NPT_String(const char* str, NPT_Size length)
171 if (str == NULL || length == 0) {
172 m_Chars = NULL;
173 } else {
174 for (unsigned int i=0; i<length-1; i++) {
175 if (str[i] == '\0') {
176 if (i == 0) {
177 m_Chars = NULL;
178 return;
180 length = i;
181 break;
184 m_Chars = Buffer::Create(str, length);
188 /*----------------------------------------------------------------------
189 | NPT_String::NPT_String
190 +---------------------------------------------------------------------*/
191 NPT_String::NPT_String(const NPT_String& str)
193 if (str.GetLength() == 0) {
194 m_Chars = NULL;
195 } else {
196 m_Chars = Buffer::Create(str.GetChars(), str.GetLength());
200 /*----------------------------------------------------------------------
201 | NPT_String::NPT_String
202 +---------------------------------------------------------------------*/
203 NPT_String::NPT_String(char c, NPT_Cardinal repeat)
205 if (repeat != 0) {
206 m_Chars = Buffer::Create(c, repeat);
207 } else {
208 m_Chars = NULL;
212 /*----------------------------------------------------------------------
213 | NPT_String::SetLength
214 +---------------------------------------------------------------------*/
215 NPT_Result
216 NPT_String::SetLength(NPT_Size length, bool pad)
218 // special case for 0
219 if (length == 0) {
220 Reset();
221 return NPT_SUCCESS;
224 // reserve the space
225 Reserve(length);
227 // pad with spaces if necessary
228 char* chars = UseChars();
229 if (pad) {
230 unsigned int current_length = GetLength();
231 if (length > current_length) {
232 unsigned int pad_length = length-current_length;
233 NPT_SetMemory(chars+current_length, ' ', pad_length);
237 // update the length and terminate the buffer
238 GetBuffer()->SetLength(length);
239 chars[length] = '\0';
241 return NPT_SUCCESS;
244 /*----------------------------------------------------------------------
245 | NPT_String::PrepareToWrite
246 +---------------------------------------------------------------------*/
247 inline char*
248 NPT_String::PrepareToWrite(NPT_Size length)
250 NPT_ASSERT(length != 0);
251 if (m_Chars == NULL || GetBuffer()->GetAllocated() < length) {
252 // the buffer is too small, we need to allocate a new one.
253 NPT_Size needed = length;
254 if (m_Chars != NULL) {
255 NPT_Size grow = GetBuffer()->GetAllocated()*2;
256 if (grow > length) needed = grow;
257 delete GetBuffer();
259 m_Chars = Buffer::Create(needed);
261 GetBuffer()->SetLength(length);
262 return m_Chars;
265 /*----------------------------------------------------------------------
266 | NPT_String::Reserve
267 +---------------------------------------------------------------------*/
268 void
269 NPT_String::Reserve(NPT_Size allocate)
271 if (m_Chars == NULL || GetBuffer()->GetAllocated() < allocate) {
272 // the buffer is too small, we need to allocate a new one.
273 NPT_Size needed = allocate;
274 if (m_Chars != NULL) {
275 NPT_Size grow = GetBuffer()->GetAllocated()*2;
276 if (grow > allocate) needed = grow;
278 NPT_Size length = GetLength();
279 char* copy = Buffer::Create(needed, length);
280 if (m_Chars != NULL) {
281 CopyString(copy, m_Chars);
282 delete GetBuffer();
283 } else {
284 copy[0] = '\0';
286 m_Chars = copy;
290 /*----------------------------------------------------------------------
291 | NPT_String::Assign
292 +---------------------------------------------------------------------*/
293 void
294 NPT_String::Assign(const char* str, NPT_Size length)
296 if (str == NULL || length == 0) {
297 Reset();
298 } else {
299 for (unsigned int i=0; i<length-1; i++) {
300 if (str[i] == '\0') {
301 if (i == 0) {
302 Reset();
303 return;
304 } else {
305 length = i;
306 break;
310 PrepareToWrite(length);
311 CopyBuffer(m_Chars, str, length);
312 m_Chars[length] = '\0';
316 /*----------------------------------------------------------------------
317 | NPT_String::operator=
318 +---------------------------------------------------------------------*/
319 NPT_String&
320 NPT_String::operator=(const char* str)
322 if (str == NULL) {
323 Reset();
324 } else {
325 NPT_Size length = StringLength(str);
326 if (length == 0) {
327 Reset();
328 } else {
329 CopyString(PrepareToWrite(length), str);
333 return *this;
336 /*----------------------------------------------------------------------
337 | NPT_String::operator=
338 +---------------------------------------------------------------------*/
339 NPT_String&
340 NPT_String::operator=(const NPT_String& str)
342 // do nothing if we're assigning to ourselves
343 if (this != &str) {
344 Assign(str.GetChars(), str.GetLength());
346 return *this;
349 /*----------------------------------------------------------------------
350 | NPT_String::GetHash32
351 +---------------------------------------------------------------------*/
352 NPT_UInt32
353 NPT_String::GetHash32() const
355 return NPT_Fnv1aHashStr32(GetChars());
358 /*----------------------------------------------------------------------
359 | NPT_String::GetHash64
360 +---------------------------------------------------------------------*/
361 NPT_UInt64
362 NPT_String::GetHash64() const
364 return NPT_Fnv1aHashStr64(GetChars());
367 /*----------------------------------------------------------------------
368 | NPT_String::Append
369 +---------------------------------------------------------------------*/
370 void
371 NPT_String::Append(const char* str, NPT_Size length)
373 // shortcut
374 if (str == NULL || length == 0) return;
376 // compute the new length
377 NPT_Size old_length = GetLength();
378 NPT_Size new_length = old_length + length;
380 // allocate enough space
381 Reserve(new_length);
383 // append the new string at the end of the current one
384 CopyBuffer(m_Chars+old_length, str, length);
385 m_Chars[new_length] = '\0';
387 // update the length
388 GetBuffer()->SetLength(new_length);
391 /*----------------------------------------------------------------------
392 | NPT_String::Compare
393 +---------------------------------------------------------------------*/
394 int
395 NPT_String::Compare(const char *s, bool ignore_case) const
397 return NPT_String::Compare(GetChars(), s, ignore_case);
400 /*----------------------------------------------------------------------
401 | NPT_String::Compare
402 +---------------------------------------------------------------------*/
403 int
404 NPT_String::Compare(const char *s1, const char *s2, bool ignore_case)
406 const char *r1 = s1;
407 const char *r2 = s2;
409 if (ignore_case) {
410 while (NPT_Uppercase(*r1) == NPT_Uppercase(*r2)) {
411 if (*r1++ == '\0') {
412 return 0;
414 r2++;
416 return NPT_Uppercase(*r1) - NPT_Uppercase(*r2);
417 } else {
418 while (*r1 == *r2) {
419 if (*r1++ == '\0') {
420 return 0;
422 r2++;
424 return (*r1 - *r2);
428 /*----------------------------------------------------------------------
429 | NPT_String::CompareN
430 +---------------------------------------------------------------------*/
431 int
432 NPT_String::CompareN(const char *s, NPT_Size count, bool ignore_case) const
434 return NPT_String::CompareN(GetChars(), s, count, ignore_case);
437 /*----------------------------------------------------------------------
438 | NPT_String::CompareN
439 +---------------------------------------------------------------------*/
440 int
441 NPT_String::CompareN(const char* s1, const char *s2, NPT_Size count, bool ignore_case)
443 const char* me = s1;
445 if (ignore_case) {
446 for (unsigned int i=0; i<count; i++) {
447 if (NPT_Uppercase(me[i]) != NPT_Uppercase(s2[i])) {
448 return NPT_Uppercase(me[i]) - NPT_Uppercase(s2[i]);
451 return 0;
452 } else {
453 for (unsigned int i=0; i<count; i++) {
454 if (me[i] != s2[i]) {
455 return (me[i] - s2[i]);
458 return 0;
462 /*----------------------------------------------------------------------
463 | NPT_String::Split
464 +---------------------------------------------------------------------*/
465 NPT_List<NPT_String>
466 NPT_String::Split(const char* separator) const
468 NPT_List<NPT_String> result;
469 NPT_Size separator_length = NPT_StringLength(separator);
471 // sepcial case for empty separators
472 if (separator_length == 0) {
473 result.Add(*this);
474 return result;
477 int current = 0;
478 int next;
479 do {
480 next = Find(separator, current);
481 unsigned int end = (next>=0?(unsigned int)next:GetLength());
482 result.Add(SubString(current, end-current));
483 current = next+separator_length;
484 } while (next >= 0);
486 return result;
489 /*----------------------------------------------------------------------
490 | NPT_String::SplitAny
491 +---------------------------------------------------------------------*/
492 NPT_Array<NPT_String>
493 NPT_String::SplitAny(const char* separator) const
495 NPT_Array<NPT_String> result((GetLength()>>1)+1);
497 // sepcial case for empty separators
498 if (NPT_StringLength(separator) == 0) {
499 result.Add(*this);
500 return result;
503 int current = 0;
504 int next;
505 do {
506 next = FindAny(separator, current);
507 unsigned int end = (next>=0?(unsigned int)next:GetLength());
508 result.Add(SubString(current, end-current));
509 current = next+1;
510 } while (next >= 0);
512 return result;
515 /*----------------------------------------------------------------------
516 | NPT_String::Join
517 +---------------------------------------------------------------------*/
518 NPT_String
519 NPT_String::Join(NPT_List<NPT_String>& args, const char* separator)
521 NPT_String output;
522 NPT_List<NPT_String>::Iterator arg = args.GetFirstItem();
523 while (arg) {
524 output += *arg;
525 if (++arg) output += separator;
528 return output;
531 /*----------------------------------------------------------------------
532 | NPT_String::SubString
533 +---------------------------------------------------------------------*/
534 NPT_String
535 NPT_String::SubString(NPT_Ordinal first, NPT_Size length) const
537 if (first >= GetLength()) {
538 first = GetLength();
539 length = 0;
540 } else if (first+length >= GetLength()) {
541 length = GetLength()-first;
543 return NPT_String(GetChars()+first, length);
546 /*----------------------------------------------------------------------
547 | NPT_StringStartsWith
549 | returns:
550 | 1 if str starts with sub,
551 | 0 if str is large enough but does not start with sub
552 | -1 if str is too short to start with sub
553 +---------------------------------------------------------------------*/
554 static inline int
555 NPT_StringStartsWith(const char* str, const char* sub, bool ignore_case)
557 if (ignore_case) {
558 while (NPT_Uppercase(*str) == NPT_Uppercase(*sub)) {
559 if (*str++ == '\0') {
560 return 1;
562 sub++;
564 } else {
565 while (*str == *sub) {
566 if (*str++ == '\0') {
567 return 1;
569 sub++;
572 return (*sub == '\0') ? 1 : (*str == '\0' ? -1 : 0);
575 /*----------------------------------------------------------------------
576 | NPT_String::StartsWith
577 +---------------------------------------------------------------------*/
578 bool
579 NPT_String::StartsWith(const char *s, bool ignore_case) const
581 if (s == NULL) return false;
582 return NPT_StringStartsWith(GetChars(), s, ignore_case) == 1;
585 /*----------------------------------------------------------------------
586 | NPT_String::EndsWith
587 +---------------------------------------------------------------------*/
588 bool
589 NPT_String::EndsWith(const char *s, bool ignore_case) const
591 if (s == NULL) return false;
592 NPT_Size str_length = NPT_StringLength(s);
593 if (str_length > GetLength()) return false;
594 return NPT_StringStartsWith(GetChars()+GetLength()-str_length, s, ignore_case) == 1;
597 /*----------------------------------------------------------------------
598 | NPT_String::Find
599 +---------------------------------------------------------------------*/
601 NPT_String::Find(const char* str, NPT_Ordinal start, bool ignore_case) const
603 // check args
604 if (str == NULL || start >= GetLength()) return -1;
606 // skip to start position
607 const char* src = m_Chars + start;
609 // look for a substring
610 while (*src) {
611 int cmp = NPT_StringStartsWith(src, str, ignore_case);
612 switch (cmp) {
613 case -1:
614 // ref is too short, abort
615 return -1;
616 case 1:
617 // match
618 return (int)(src-m_Chars);
620 src++;
623 return -1;
626 /*----------------------------------------------------------------------
627 | NPT_String::Find
628 +---------------------------------------------------------------------*/
630 NPT_String::Find(char c, NPT_Ordinal start, bool ignore_case) const
632 // check args
633 if (start >= GetLength()) return -1;
635 // skip to start position
636 const char* src = m_Chars + start;
638 // look for the character
639 if (ignore_case) {
640 while (*src) {
641 if (NPT_Uppercase(*src) == NPT_Uppercase(c)) {
642 return (int)(src-m_Chars);
644 src++;
646 } else {
647 while (*src) {
648 if (*src == c) return (int)(src-m_Chars);
649 src++;
653 return -1;
656 /*----------------------------------------------------------------------
657 | NPT_String::FindAny
658 +---------------------------------------------------------------------*/
660 NPT_String::FindAny(const char* s, NPT_Ordinal start, bool ignore_case) const
662 // check args
663 if (start >= GetLength()) return -1;
665 // skip to start position
666 const char* src = m_Chars + start;
668 // look for the character
669 if (ignore_case) {
670 while (*src) {
671 for (NPT_Size i=0; i<NPT_StringLength(s); i++) {
672 if (NPT_Uppercase(*src) == NPT_Uppercase(s[i])) {
673 return (int)(src-m_Chars);
676 src++;
678 } else {
679 while (*src) {
680 for (NPT_Size i=0; i<NPT_StringLength(s); i++) {
681 if (*src == s[i]) return (int)(src-m_Chars);
683 src++;
687 return -1;
690 /*----------------------------------------------------------------------
691 | NPT_String::ReverseFind
692 +---------------------------------------------------------------------*/
694 NPT_String::ReverseFind(const char* str, NPT_Ordinal start, bool ignore_case) const
696 // check args
697 if (str == NULL || *str == '\0') return -1;
699 // look for a substring
700 NPT_Size my_length = GetLength();
701 NPT_Size str_length = NPT_StringLength(str);
702 int i=my_length-start-str_length;
703 const char* src = GetChars();
704 if (i<0) return -1;
705 for (;i>=0; i--) {
706 int cmp = NPT_StringStartsWith(src+i, str, ignore_case);
707 if (cmp == 1) {
708 // match
709 return i;
713 return -1;
716 /*----------------------------------------------------------------------
717 | NPT_String::ReverseFind
718 +---------------------------------------------------------------------*/
720 NPT_String::ReverseFind(char c, NPT_Ordinal start, bool ignore_case) const
722 // check args
723 NPT_Size length = GetLength();
724 int i = length-start-1;
725 if (i < 0) return -1;
727 // look for the character
728 const char* src = GetChars();
729 if (ignore_case) {
730 for (;i>=0;i--) {
731 if (NPT_Uppercase(src[i]) == NPT_Uppercase(c)) {
732 return i;
735 } else {
736 for (;i>=0;i--) {
737 if (src[i] == c) return i;
741 return -1;
744 /*----------------------------------------------------------------------
745 | NPT_String::MakeLowercase
746 +---------------------------------------------------------------------*/
747 void
748 NPT_String::MakeLowercase()
750 // the source is the current buffer
751 const char* src = GetChars();
753 // convert all the characters of the existing buffer
754 char* dst = const_cast<char*>(src);
755 while (*dst != '\0') {
756 *dst = NPT_Lowercase(*dst);
757 dst++;
761 /*----------------------------------------------------------------------
762 | NPT_String::MakeUppercase
763 +---------------------------------------------------------------------*/
764 void
765 NPT_String::MakeUppercase()
767 // the source is the current buffer
768 const char* src = GetChars();
770 // convert all the characters of the existing buffer
771 char* dst = const_cast<char*>(src);
772 while (*dst != '\0') {
773 *dst = NPT_Uppercase(*dst);
774 dst++;
778 /*----------------------------------------------------------------------
779 | NPT_String::ToLowercase
780 +---------------------------------------------------------------------*/
781 NPT_String
782 NPT_String::ToLowercase() const
784 NPT_String result(*this);
785 result.MakeLowercase();
786 return result;
789 /*----------------------------------------------------------------------
790 | NPT_String::ToUppercase
791 +---------------------------------------------------------------------*/
792 NPT_String
793 NPT_String::ToUppercase() const
795 NPT_String result(*this);
796 result.MakeUppercase();
797 return result;
800 /*----------------------------------------------------------------------
801 | NPT_String::Replace
802 +---------------------------------------------------------------------*/
803 const NPT_String&
804 NPT_String::Replace(char a, char b)
806 // check args
807 if (m_Chars == NULL || a == '\0' || b == '\0') return *this;
809 // we are going to modify the characters
810 char* src = m_Chars;
812 // process the buffer in place
813 while (*src) {
814 if (*src == a) *src = b;
815 src++;
817 return *this;
820 /*----------------------------------------------------------------------
821 | NPT_String::Replace
822 +---------------------------------------------------------------------*/
823 const NPT_String&
824 NPT_String::Replace(char a, const char* str)
826 // check args
827 if (m_Chars == NULL || a == '\0' || str == NULL || str[0] == '\0') return *this;
829 // optimization
830 if (NPT_StringLength(str) == 1) return Replace(a, str[0]);
832 // we are going to create a new string
833 NPT_String dst;
834 char* src = m_Chars;
836 // reserve at least as much as input
837 dst.Reserve(GetLength());
839 // process the buffer
840 while (*src) {
841 if (*src == a) {
842 dst += str;
843 } else {
844 dst += *src;
846 src++;
849 Assign(dst.GetChars(), dst.GetLength());
850 return *this;
853 /*----------------------------------------------------------------------
854 | NPT_String::Replace
855 +---------------------------------------------------------------------*/
856 const NPT_String&
857 NPT_String::Replace(const char* before, const char* after)
859 NPT_Size size_before = NPT_StringLength(before);
860 NPT_Size size_after = NPT_StringLength(after);
861 int index = Find(before);
862 while (index != NPT_STRING_SEARCH_FAILED) {
863 Erase(index, size_before);
864 Insert(after, index);
865 index = Find(before, index+size_after);
867 return *this;
870 /*----------------------------------------------------------------------
871 | NPT_String::Insert
872 +---------------------------------------------------------------------*/
873 const NPT_String&
874 NPT_String::Insert(const char* str, NPT_Ordinal where)
876 // check args
877 if (str == NULL || where > GetLength()) return *this;
879 // measure the string to insert
880 NPT_Size str_length = StringLength(str);
881 if (str_length == 0) return *this;
883 // compute the size of the new string
884 NPT_Size old_length = GetLength();
885 NPT_Size new_length = str_length + GetLength();
887 // prepare to write the new string
888 char* src = m_Chars;
889 char* nst = Buffer::Create(new_length, new_length);
890 char* dst = nst;
892 // copy the beginning of the old string
893 if (where > 0) {
894 CopyBuffer(dst, src, where);
895 src += where;
896 dst += where;
899 // copy the inserted string
900 CopyString(dst, str);
901 dst += str_length;
903 // copy the end of the old string
904 if (old_length > where) {
905 CopyString(dst, src);
908 // use the new string
909 if (m_Chars) delete GetBuffer();
910 m_Chars = nst;
911 return *this;
914 /*----------------------------------------------------------------------
915 | NPT_String::Erase
916 +---------------------------------------------------------------------*/
917 const NPT_String&
918 NPT_String::Erase(NPT_Ordinal start, NPT_Cardinal count /* = 1 */)
920 // check bounds
921 NPT_Size length = GetLength();
922 if (start+count > length) {
923 if (start >= length) return *this;
924 count = length-start;
926 if (count == 0) return *this;
928 CopyString(m_Chars+start, m_Chars+start+count);
929 GetBuffer()->SetLength(length-count);
930 return *this;
933 /*----------------------------------------------------------------------
934 | NPT_String::ToInteger
935 +---------------------------------------------------------------------*/
936 NPT_Result
937 NPT_String::ToInteger(int& value, bool relaxed) const
939 return NPT_ParseInteger(GetChars(), value, relaxed);
942 /*----------------------------------------------------------------------
943 | NPT_String::ToInteger
944 +---------------------------------------------------------------------*/
945 NPT_Result
946 NPT_String::ToInteger(unsigned int& value, bool relaxed) const
948 return NPT_ParseInteger(GetChars(), value, relaxed);
951 /*----------------------------------------------------------------------
952 | NPT_String::ToInteger
953 +---------------------------------------------------------------------*/
954 NPT_Result
955 NPT_String::ToInteger(long& value, bool relaxed) const
957 return NPT_ParseInteger(GetChars(), value, relaxed);
960 /*----------------------------------------------------------------------
961 | NPT_String::ToInteger
962 +---------------------------------------------------------------------*/
963 NPT_Result
964 NPT_String::ToInteger(unsigned long& value, bool relaxed) const
966 return NPT_ParseInteger(GetChars(), value, relaxed);
969 /*----------------------------------------------------------------------
970 | NPT_String::ToInteger32
971 +---------------------------------------------------------------------*/
972 NPT_Result
973 NPT_String::ToInteger32(NPT_Int32& value, bool relaxed) const
975 return NPT_ParseInteger32(GetChars(), value, relaxed);
978 /*----------------------------------------------------------------------
979 | NPT_String::ToInteger32
980 +---------------------------------------------------------------------*/
981 NPT_Result
982 NPT_String::ToInteger32(NPT_UInt32& value, bool relaxed) const
984 return NPT_ParseInteger32(GetChars(), value, relaxed);
987 /*----------------------------------------------------------------------
988 | NPT_String::ToInteger64
989 +---------------------------------------------------------------------*/
990 NPT_Result
991 NPT_String::ToInteger64(NPT_Int64& value, bool relaxed) const
993 return NPT_ParseInteger64(GetChars(), value, relaxed);
996 /*----------------------------------------------------------------------
997 | NPT_String::ToInteger64
998 +---------------------------------------------------------------------*/
999 NPT_Result
1000 NPT_String::ToInteger64(NPT_UInt64& value, bool relaxed) const
1002 return NPT_ParseInteger64(GetChars(), value, relaxed);
1005 /*----------------------------------------------------------------------
1006 | NPT_String::ToFloat
1007 +---------------------------------------------------------------------*/
1008 NPT_Result
1009 NPT_String::ToFloat(float& value, bool relaxed) const
1011 return NPT_ParseFloat(GetChars(), value, relaxed);
1014 /*----------------------------------------------------------------------
1015 | NPT_String::TrimLeft
1016 +---------------------------------------------------------------------*/
1017 const NPT_String&
1018 NPT_String::TrimLeft()
1020 return TrimLeft(NPT_STRINGS_WHITESPACE_CHARS);
1023 /*----------------------------------------------------------------------
1024 | NPT_String::TrimLeft
1025 +---------------------------------------------------------------------*/
1026 const NPT_String&
1027 NPT_String::TrimLeft(char c)
1029 char s[2] = {c, 0};
1030 return TrimLeft((const char*)s);
1033 /*----------------------------------------------------------------------
1034 | NPT_String::TrimLeft
1035 +---------------------------------------------------------------------*/
1036 const NPT_String&
1037 NPT_String::TrimLeft(const char* chars)
1039 if (m_Chars == NULL) return *this;
1040 const char* s = m_Chars;
1041 while (char c = *s) {
1042 const char* x = chars;
1043 while (*x) {
1044 if (*x == c) break;
1045 x++;
1047 if (*x == 0) break; // not found
1048 s++;
1050 if (s == m_Chars) {
1051 // nothing was trimmed
1052 return *this;
1055 // shift chars to the left
1056 char* d = m_Chars;
1057 GetBuffer()->SetLength(GetLength()-(NPT_Size)(s-d));
1058 while ((*d++ = *s++)) {};
1059 return *this;
1062 /*----------------------------------------------------------------------
1063 | NPT_String::TrimRight
1064 +---------------------------------------------------------------------*/
1065 const NPT_String&
1066 NPT_String::TrimRight()
1068 return TrimRight(NPT_STRINGS_WHITESPACE_CHARS);
1071 /*----------------------------------------------------------------------
1072 | NPT_String::TrimRight
1073 +---------------------------------------------------------------------*/
1074 const NPT_String&
1075 NPT_String::TrimRight(char c)
1077 char s[2] = {c, 0};
1078 return TrimRight((const char*)s);
1081 /*----------------------------------------------------------------------
1082 | NPT_String::TrimRight
1083 +---------------------------------------------------------------------*/
1084 const NPT_String&
1085 NPT_String::TrimRight(const char* chars)
1087 if (m_Chars == NULL || m_Chars[0] == '\0') return *this;
1088 char* tail = m_Chars+GetLength()-1;
1089 char* s = tail;
1090 while (s != m_Chars-1) {
1091 const char* x = chars;
1092 while (*x) {
1093 if (*x == *s) {
1094 *s = '\0';
1095 break;
1097 x++;
1099 if (*x == 0) break; // not found
1100 s--;
1102 if (s == tail) {
1103 // nothing was trimmed
1104 return *this;
1106 GetBuffer()->SetLength(1+(int)(s-m_Chars));
1107 return *this;
1110 /*----------------------------------------------------------------------
1111 | NPT_String::Trim
1112 +---------------------------------------------------------------------*/
1113 const NPT_String&
1114 NPT_String::Trim()
1116 TrimLeft();
1117 return TrimRight();
1120 /*----------------------------------------------------------------------
1121 | NPT_String::Trim
1122 +---------------------------------------------------------------------*/
1123 const NPT_String&
1124 NPT_String::Trim(char c)
1126 char s[2] = {c, 0};
1127 TrimLeft((const char*)s);
1128 return TrimRight((const char*)s);
1131 /*----------------------------------------------------------------------
1132 | NPT_String::Trim
1133 +---------------------------------------------------------------------*/
1134 const NPT_String&
1135 NPT_String::Trim(const char* chars)
1137 TrimLeft(chars);
1138 return TrimRight(chars);
1141 /*----------------------------------------------------------------------
1142 | NPT_String::operator+(const NPT_String&, const char*)
1143 +---------------------------------------------------------------------*/
1144 NPT_String
1145 operator+(const NPT_String& s1, const char* s2)
1147 // shortcut
1148 if (s2 == NULL) return NPT_String(s1);
1150 // measure strings
1151 NPT_Size s1_length = s1.GetLength();
1152 NPT_Size s2_length = NPT_String::StringLength(s2);
1154 // allocate space for the new string
1155 NPT_String result;
1156 char* start = result.PrepareToWrite(s1_length+s2_length);
1158 // concatenate the two strings into the result
1159 NPT_String::CopyBuffer(start, s1, s1_length);
1160 NPT_String::CopyString(start+s1_length, s2);
1162 return result;
1165 /*----------------------------------------------------------------------
1166 | NPT_String::operator+(const NPT_String& , const char*)
1167 +---------------------------------------------------------------------*/
1168 NPT_String
1169 operator+(const char* s1, const NPT_String& s2)
1171 // shortcut
1172 if (s1 == NULL) return NPT_String(s2);
1174 // measure strings
1175 NPT_Size s1_length = NPT_String::StringLength(s1);
1176 NPT_Size s2_length = s2.GetLength();
1178 // allocate space for the new string
1179 NPT_String result;
1180 char* start = result.PrepareToWrite(s1_length+s2_length);
1182 // concatenate the two strings into the result
1183 NPT_String::CopyBuffer(start, s1, s1_length);
1184 NPT_String::CopyString(start+s1_length, s2.GetChars());
1186 return result;
1189 /*----------------------------------------------------------------------
1190 | NPT_String::operator+(const NPT_String& , char)
1191 +---------------------------------------------------------------------*/
1192 NPT_String
1193 operator+(const NPT_String& s1, char c)
1195 // allocate space for the new string
1196 NPT_String result;
1197 result.Reserve(s1.GetLength()+1);
1199 // append
1200 result = s1;
1201 result += c;
1203 return result;