summaryrefslogtreecommitdiffstats
path: root/lib/libUPnP/Neptune/Source/Core/NptStrings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libUPnP/Neptune/Source/Core/NptStrings.cpp')
-rw-r--r--lib/libUPnP/Neptune/Source/Core/NptStrings.cpp1205
1 files changed, 1205 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/Core/NptStrings.cpp b/lib/libUPnP/Neptune/Source/Core/NptStrings.cpp
new file mode 100644
index 0000000..819d9a2
--- /dev/null
+++ b/lib/libUPnP/Neptune/Source/Core/NptStrings.cpp
@@ -0,0 +1,1205 @@
+/*****************************************************************
+|
+| Neptune - String Objects
+|
+| Copyright (c) 2002-2008, Axiomatic Systems, LLC.
+| All rights reserved.
+|
+| Redistribution and use in source and binary forms, with or without
+| modification, are permitted provided that the following conditions are met:
+| * Redistributions of source code must retain the above copyright
+| notice, this list of conditions and the following disclaimer.
+| * Redistributions in binary form must reproduce the above copyright
+| notice, this list of conditions and the following disclaimer in the
+| documentation and/or other materials provided with the distribution.
+| * Neither the name of Axiomatic Systems nor the
+| names of its contributors may be used to endorse or promote products
+| derived from this software without specific prior written permission.
+|
+| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
+| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
+| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "NptConfig.h"
+#include "NptTypes.h"
+#include "NptConstants.h"
+#include "NptStrings.h"
+#include "NptResults.h"
+#include "NptUtils.h"
+#include "NptDebug.h"
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+#define NPT_STRINGS_WHITESPACE_CHARS "\r\n\t "
+
+const unsigned int NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE = 256;
+const unsigned int NPT_STRING_FORMAT_BUFFER_MAX_SIZE = 0x80000; // 512k
+
+/*----------------------------------------------------------------------
+| helpers
++---------------------------------------------------------------------*/
+inline char NPT_Uppercase(char x) {
+ return (x >= 'a' && x <= 'z') ? x&0xdf : x;
+}
+
+inline char NPT_Lowercase(char x) {
+ return (x >= 'A' && x <= 'Z') ? x^32 : x;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::EmptyString
++---------------------------------------------------------------------*/
+char NPT_String::EmptyString = '\0';
+
+/*----------------------------------------------------------------------
+| NPT_String::FromInteger
++---------------------------------------------------------------------*/
+NPT_String
+NPT_String::FromInteger(NPT_Int64 value)
+{
+ char str[32];
+ char* c = &str[31];
+ *c-- = '\0';
+
+ // handle the sign
+ bool negative = false;
+ if (value < 0) {
+ negative = true;
+ value = -value;
+ }
+
+ // process the digits
+ do {
+ int digit = (int)(value%10);
+ *c-- = '0'+digit;
+ value /= 10;
+ } while(value);
+
+ if (negative) {
+ *c = '-';
+ } else {
+ ++c;
+ }
+
+ return NPT_String(c);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::FromIntegerU
++---------------------------------------------------------------------*/
+NPT_String
+NPT_String::FromIntegerU(NPT_UInt64 value)
+{
+ char str[32];
+ char* c = &str[31];
+ *c = '\0';
+
+ // process the digits
+ do {
+ int digit = (int)(value%10);
+ *--c = '0'+digit;
+ value /= 10;
+ } while(value);
+
+ return NPT_String(c);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Format
++---------------------------------------------------------------------*/
+NPT_String
+NPT_String::Format(const char* format, ...)
+{
+ NPT_String result;
+ NPT_Size buffer_size = NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE; // default value
+
+ va_list args;
+
+ for(;;) {
+ /* try to format (it might not fit) */
+ result.Reserve(buffer_size);
+ char* buffer = result.UseChars();
+ va_start(args, format);
+ int f_result = NPT_FormatStringVN(buffer, buffer_size, format, args);
+ va_end(args);
+ if (f_result >= (int)(buffer_size)) f_result = -1;
+ if (f_result >= 0) {
+ result.SetLength(f_result);
+ break;
+ }
+
+ /* the buffer was too small, try something bigger */
+ /* (we don't trust the return value of NPT_FormatStringVN */
+ /* for the actual size needed) */
+ buffer_size *= 2;
+ if (buffer_size > NPT_STRING_FORMAT_BUFFER_MAX_SIZE) break;
+ }
+
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::NPT_String
++---------------------------------------------------------------------*/
+NPT_String::NPT_String(const char* str)
+{
+ if (str == NULL) {
+ m_Chars = NULL;
+ } else {
+ m_Chars = Buffer::Create(str);
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::NPT_String
++---------------------------------------------------------------------*/
+NPT_String::NPT_String(const char* str, NPT_Size length)
+{
+ if (str == NULL || length == 0) {
+ m_Chars = NULL;
+ } else {
+ for (unsigned int i=0; i<length-1; i++) {
+ if (str[i] == '\0') {
+ if (i == 0) {
+ m_Chars = NULL;
+ return;
+ }
+ length = i;
+ break;
+ }
+ }
+ m_Chars = Buffer::Create(str, length);
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::NPT_String
++---------------------------------------------------------------------*/
+NPT_String::NPT_String(const NPT_String& str)
+{
+ if (str.GetLength() == 0) {
+ m_Chars = NULL;
+ } else {
+ m_Chars = Buffer::Create(str.GetChars(), str.GetLength());
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::NPT_String
++---------------------------------------------------------------------*/
+NPT_String::NPT_String(char c, NPT_Cardinal repeat)
+{
+ if (repeat != 0) {
+ m_Chars = Buffer::Create(c, repeat);
+ } else {
+ m_Chars = NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::SetLength
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::SetLength(NPT_Size length, bool pad)
+{
+ // special case for 0
+ if (length == 0) {
+ Reset();
+ return NPT_SUCCESS;
+ }
+
+ // reserve the space
+ Reserve(length);
+
+ // pad with spaces if necessary
+ char* chars = UseChars();
+ if (pad) {
+ unsigned int current_length = GetLength();
+ if (length > current_length) {
+ unsigned int pad_length = length-current_length;
+ NPT_SetMemory(chars+current_length, ' ', pad_length);
+ }
+ }
+
+ // update the length and terminate the buffer
+ GetBuffer()->SetLength(length);
+ chars[length] = '\0';
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::PrepareToWrite
++---------------------------------------------------------------------*/
+inline char*
+NPT_String::PrepareToWrite(NPT_Size length)
+{
+ NPT_ASSERT(length != 0);
+ if (m_Chars == NULL || GetBuffer()->GetAllocated() < length) {
+ // the buffer is too small, we need to allocate a new one.
+ NPT_Size needed = length;
+ if (m_Chars != NULL) {
+ NPT_Size grow = GetBuffer()->GetAllocated()*2;
+ if (grow > length) needed = grow;
+ delete GetBuffer();
+ }
+ m_Chars = Buffer::Create(needed);
+ }
+ GetBuffer()->SetLength(length);
+ return m_Chars;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Reserve
++---------------------------------------------------------------------*/
+void
+NPT_String::Reserve(NPT_Size allocate)
+{
+ if (m_Chars == NULL || GetBuffer()->GetAllocated() < allocate) {
+ // the buffer is too small, we need to allocate a new one.
+ NPT_Size needed = allocate;
+ if (m_Chars != NULL) {
+ NPT_Size grow = GetBuffer()->GetAllocated()*2;
+ if (grow > allocate) needed = grow;
+ }
+ NPT_Size length = GetLength();
+ char* copy = Buffer::Create(needed, length);
+ if (m_Chars != NULL) {
+ CopyString(copy, m_Chars);
+ delete GetBuffer();
+ } else {
+ copy[0] = '\0';
+ }
+ m_Chars = copy;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Assign
++---------------------------------------------------------------------*/
+void
+NPT_String::Assign(const char* str, NPT_Size length)
+{
+ if (str == NULL || length == 0) {
+ Reset();
+ } else {
+ for (unsigned int i=0; i<length-1; i++) {
+ if (str[i] == '\0') {
+ if (i == 0) {
+ Reset();
+ return;
+ } else {
+ length = i;
+ break;
+ }
+ }
+ }
+ PrepareToWrite(length);
+ CopyBuffer(m_Chars, str, length);
+ m_Chars[length] = '\0';
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::operator=
++---------------------------------------------------------------------*/
+NPT_String&
+NPT_String::operator=(const char* str)
+{
+ if (str == NULL) {
+ Reset();
+ } else {
+ NPT_Size length = StringLength(str);
+ if (length == 0) {
+ Reset();
+ } else {
+ CopyString(PrepareToWrite(length), str);
+ }
+ }
+
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::operator=
++---------------------------------------------------------------------*/
+NPT_String&
+NPT_String::operator=(const NPT_String& str)
+{
+ // do nothing if we're assigning to ourselves
+ if (this != &str) {
+ Assign(str.GetChars(), str.GetLength());
+ }
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::GetHash32
++---------------------------------------------------------------------*/
+NPT_UInt32
+NPT_String::GetHash32() const
+{
+ return NPT_Fnv1aHashStr32(GetChars());
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::GetHash64
++---------------------------------------------------------------------*/
+NPT_UInt64
+NPT_String::GetHash64() const
+{
+ return NPT_Fnv1aHashStr64(GetChars());
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Append
++---------------------------------------------------------------------*/
+void
+NPT_String::Append(const char* str, NPT_Size length)
+{
+ // shortcut
+ if (str == NULL || length == 0) return;
+
+ // compute the new length
+ NPT_Size old_length = GetLength();
+ NPT_Size new_length = old_length + length;
+
+ // allocate enough space
+ Reserve(new_length);
+
+ // append the new string at the end of the current one
+ CopyBuffer(m_Chars+old_length, str, length);
+ m_Chars[new_length] = '\0';
+
+ // update the length
+ GetBuffer()->SetLength(new_length);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Compare
++---------------------------------------------------------------------*/
+int
+NPT_String::Compare(const char *s, bool ignore_case) const
+{
+ return NPT_String::Compare(GetChars(), s, ignore_case);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Compare
++---------------------------------------------------------------------*/
+int
+NPT_String::Compare(const char *s1, const char *s2, bool ignore_case)
+{
+ const char *r1 = s1;
+ const char *r2 = s2;
+
+ if (ignore_case) {
+ while (NPT_Uppercase(*r1) == NPT_Uppercase(*r2)) {
+ if (*r1++ == '\0') {
+ return 0;
+ }
+ r2++;
+ }
+ return NPT_Uppercase(*r1) - NPT_Uppercase(*r2);
+ } else {
+ while (*r1 == *r2) {
+ if (*r1++ == '\0') {
+ return 0;
+ }
+ r2++;
+ }
+ return (*r1 - *r2);
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::CompareN
++---------------------------------------------------------------------*/
+int
+NPT_String::CompareN(const char *s, NPT_Size count, bool ignore_case) const
+{
+ return NPT_String::CompareN(GetChars(), s, count, ignore_case);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::CompareN
++---------------------------------------------------------------------*/
+int
+NPT_String::CompareN(const char* s1, const char *s2, NPT_Size count, bool ignore_case)
+{
+ const char* me = s1;
+
+ if (ignore_case) {
+ for (unsigned int i=0; i<count; i++) {
+ if (NPT_Uppercase(me[i]) != NPT_Uppercase(s2[i])) {
+ return NPT_Uppercase(me[i]) - NPT_Uppercase(s2[i]);
+ }
+ }
+ return 0;
+ } else {
+ for (unsigned int i=0; i<count; i++) {
+ if (me[i] != s2[i]) {
+ return (me[i] - s2[i]);
+ }
+ }
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Split
++---------------------------------------------------------------------*/
+NPT_List<NPT_String>
+NPT_String::Split(const char* separator) const
+{
+ NPT_List<NPT_String> result;
+ NPT_Size separator_length = NPT_StringLength(separator);
+
+ // sepcial case for empty separators
+ if (separator_length == 0) {
+ result.Add(*this);
+ return result;
+ }
+
+ int current = 0;
+ int next;
+ do {
+ next = Find(separator, current);
+ unsigned int end = (next>=0?(unsigned int)next:GetLength());
+ result.Add(SubString(current, end-current));
+ current = next+separator_length;
+ } while (next >= 0);
+
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::SplitAny
++---------------------------------------------------------------------*/
+NPT_Array<NPT_String>
+NPT_String::SplitAny(const char* separator) const
+{
+ NPT_Array<NPT_String> result((GetLength()>>1)+1);
+
+ // sepcial case for empty separators
+ if (NPT_StringLength(separator) == 0) {
+ result.Add(*this);
+ return result;
+ }
+
+ int current = 0;
+ int next;
+ do {
+ next = FindAny(separator, current);
+ unsigned int end = (next>=0?(unsigned int)next:GetLength());
+ result.Add(SubString(current, end-current));
+ current = next+1;
+ } while (next >= 0);
+
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Join
++---------------------------------------------------------------------*/
+NPT_String
+NPT_String::Join(NPT_List<NPT_String>& args, const char* separator)
+{
+ NPT_String output;
+ NPT_List<NPT_String>::Iterator arg = args.GetFirstItem();
+ while (arg) {
+ output += *arg;
+ if (++arg) output += separator;
+ }
+
+ return output;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::SubString
++---------------------------------------------------------------------*/
+NPT_String
+NPT_String::SubString(NPT_Ordinal first, NPT_Size length) const
+{
+ if (first >= GetLength()) {
+ first = GetLength();
+ length = 0;
+ } else if (first+length >= GetLength()) {
+ length = GetLength()-first;
+ }
+ return NPT_String(GetChars()+first, length);
+}
+
+/*----------------------------------------------------------------------
+| NPT_StringStartsWith
+|
+| returns:
+| 1 if str starts with sub,
+| 0 if str is large enough but does not start with sub
+| -1 if str is too short to start with sub
++---------------------------------------------------------------------*/
+static inline int
+NPT_StringStartsWith(const char* str, const char* sub, bool ignore_case)
+{
+ if (ignore_case) {
+ while (NPT_Uppercase(*str) == NPT_Uppercase(*sub)) {
+ if (*str++ == '\0') {
+ return 1;
+ }
+ sub++;
+ }
+ } else {
+ while (*str == *sub) {
+ if (*str++ == '\0') {
+ return 1;
+ }
+ sub++;
+ }
+ }
+ return (*sub == '\0') ? 1 : (*str == '\0' ? -1 : 0);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::StartsWith
++---------------------------------------------------------------------*/
+bool
+NPT_String::StartsWith(const char *s, bool ignore_case) const
+{
+ if (s == NULL) return false;
+ return NPT_StringStartsWith(GetChars(), s, ignore_case) == 1;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::EndsWith
++---------------------------------------------------------------------*/
+bool
+NPT_String::EndsWith(const char *s, bool ignore_case) const
+{
+ if (s == NULL) return false;
+ NPT_Size str_length = NPT_StringLength(s);
+ if (str_length > GetLength()) return false;
+ return NPT_StringStartsWith(GetChars()+GetLength()-str_length, s, ignore_case) == 1;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Find
++---------------------------------------------------------------------*/
+int
+NPT_String::Find(const char* str, NPT_Ordinal start, bool ignore_case) const
+{
+ // check args
+ if (str == NULL || start >= GetLength()) return -1;
+
+ // skip to start position
+ const char* src = m_Chars + start;
+
+ // look for a substring
+ while (*src) {
+ int cmp = NPT_StringStartsWith(src, str, ignore_case);
+ switch (cmp) {
+ case -1:
+ // ref is too short, abort
+ return -1;
+ case 1:
+ // match
+ return (int)(src-m_Chars);
+ }
+ src++;
+ }
+
+ return -1;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Find
++---------------------------------------------------------------------*/
+int
+NPT_String::Find(char c, NPT_Ordinal start, bool ignore_case) const
+{
+ // check args
+ if (start >= GetLength()) return -1;
+
+ // skip to start position
+ const char* src = m_Chars + start;
+
+ // look for the character
+ if (ignore_case) {
+ while (*src) {
+ if (NPT_Uppercase(*src) == NPT_Uppercase(c)) {
+ return (int)(src-m_Chars);
+ }
+ src++;
+ }
+ } else {
+ while (*src) {
+ if (*src == c) return (int)(src-m_Chars);
+ src++;
+ }
+ }
+
+ return -1;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::FindAny
++---------------------------------------------------------------------*/
+int
+NPT_String::FindAny(const char* s, NPT_Ordinal start, bool ignore_case) const
+{
+ // check args
+ if (start >= GetLength()) return -1;
+
+ // skip to start position
+ const char* src = m_Chars + start;
+
+ // look for the character
+ if (ignore_case) {
+ while (*src) {
+ for (NPT_Size i=0; i<NPT_StringLength(s); i++) {
+ if (NPT_Uppercase(*src) == NPT_Uppercase(s[i])) {
+ return (int)(src-m_Chars);
+ }
+ }
+ src++;
+ }
+ } else {
+ while (*src) {
+ for (NPT_Size i=0; i<NPT_StringLength(s); i++) {
+ if (*src == s[i]) return (int)(src-m_Chars);
+ }
+ src++;
+ }
+ }
+
+ return -1;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ReverseFind
++---------------------------------------------------------------------*/
+int
+NPT_String::ReverseFind(const char* str, NPT_Ordinal start, bool ignore_case) const
+{
+ // check args
+ if (str == NULL || *str == '\0') return -1;
+
+ // look for a substring
+ NPT_Size my_length = GetLength();
+ NPT_Size str_length = NPT_StringLength(str);
+ int i=my_length-start-str_length;
+ const char* src = GetChars();
+ if (i<0) return -1;
+ for (;i>=0; i--) {
+ int cmp = NPT_StringStartsWith(src+i, str, ignore_case);
+ if (cmp == 1) {
+ // match
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ReverseFind
++---------------------------------------------------------------------*/
+int
+NPT_String::ReverseFind(char c, NPT_Ordinal start, bool ignore_case) const
+{
+ // check args
+ NPT_Size length = GetLength();
+ int i = length-start-1;
+ if (i < 0) return -1;
+
+ // look for the character
+ const char* src = GetChars();
+ if (ignore_case) {
+ for (;i>=0;i--) {
+ if (NPT_Uppercase(src[i]) == NPT_Uppercase(c)) {
+ return i;
+ }
+ }
+ } else {
+ for (;i>=0;i--) {
+ if (src[i] == c) return i;
+ }
+ }
+
+ return -1;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::MakeLowercase
++---------------------------------------------------------------------*/
+void
+NPT_String::MakeLowercase()
+{
+ // the source is the current buffer
+ const char* src = GetChars();
+
+ // convert all the characters of the existing buffer
+ char* dst = const_cast<char*>(src);
+ while (*dst != '\0') {
+ *dst = NPT_Lowercase(*dst);
+ dst++;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::MakeUppercase
++---------------------------------------------------------------------*/
+void
+NPT_String::MakeUppercase()
+{
+ // the source is the current buffer
+ const char* src = GetChars();
+
+ // convert all the characters of the existing buffer
+ char* dst = const_cast<char*>(src);
+ while (*dst != '\0') {
+ *dst = NPT_Uppercase(*dst);
+ dst++;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToLowercase
++---------------------------------------------------------------------*/
+NPT_String
+NPT_String::ToLowercase() const
+{
+ NPT_String result(*this);
+ result.MakeLowercase();
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToUppercase
++---------------------------------------------------------------------*/
+NPT_String
+NPT_String::ToUppercase() const
+{
+ NPT_String result(*this);
+ result.MakeUppercase();
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Replace
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::Replace(char a, char b)
+{
+ // check args
+ if (m_Chars == NULL || a == '\0' || b == '\0') return *this;
+
+ // we are going to modify the characters
+ char* src = m_Chars;
+
+ // process the buffer in place
+ while (*src) {
+ if (*src == a) *src = b;
+ src++;
+ }
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Replace
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::Replace(char a, const char* str)
+{
+ // check args
+ if (m_Chars == NULL || a == '\0' || str == NULL || str[0] == '\0') return *this;
+
+ // optimization
+ if (NPT_StringLength(str) == 1) return Replace(a, str[0]);
+
+ // we are going to create a new string
+ NPT_String dst;
+ char* src = m_Chars;
+
+ // reserve at least as much as input
+ dst.Reserve(GetLength());
+
+ // process the buffer
+ while (*src) {
+ if (*src == a) {
+ dst += str;
+ } else {
+ dst += *src;
+ }
+ src++;
+ }
+
+ Assign(dst.GetChars(), dst.GetLength());
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Replace
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::Replace(const char* before, const char* after)
+{
+ NPT_Size size_before = NPT_StringLength(before);
+ NPT_Size size_after = NPT_StringLength(after);
+ int index = Find(before);
+ while (index != NPT_STRING_SEARCH_FAILED) {
+ Erase(index, size_before);
+ Insert(after, index);
+ index = Find(before, index+size_after);
+ }
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Insert
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::Insert(const char* str, NPT_Ordinal where)
+{
+ // check args
+ if (str == NULL || where > GetLength()) return *this;
+
+ // measure the string to insert
+ NPT_Size str_length = StringLength(str);
+ if (str_length == 0) return *this;
+
+ // compute the size of the new string
+ NPT_Size old_length = GetLength();
+ NPT_Size new_length = str_length + GetLength();
+
+ // prepare to write the new string
+ char* src = m_Chars;
+ char* nst = Buffer::Create(new_length, new_length);
+ char* dst = nst;
+
+ // copy the beginning of the old string
+ if (where > 0) {
+ CopyBuffer(dst, src, where);
+ src += where;
+ dst += where;
+ }
+
+ // copy the inserted string
+ CopyString(dst, str);
+ dst += str_length;
+
+ // copy the end of the old string
+ if (old_length > where) {
+ CopyString(dst, src);
+ }
+
+ // use the new string
+ if (m_Chars) delete GetBuffer();
+ m_Chars = nst;
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Erase
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::Erase(NPT_Ordinal start, NPT_Cardinal count /* = 1 */)
+{
+ // check bounds
+ NPT_Size length = GetLength();
+ if (start+count > length) {
+ if (start >= length) return *this;
+ count = length-start;
+ }
+ if (count == 0) return *this;
+
+ CopyString(m_Chars+start, m_Chars+start+count);
+ GetBuffer()->SetLength(length-count);
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToInteger
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToInteger(int& value, bool relaxed) const
+{
+ return NPT_ParseInteger(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToInteger
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToInteger(unsigned int& value, bool relaxed) const
+{
+ return NPT_ParseInteger(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToInteger
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToInteger(long& value, bool relaxed) const
+{
+ return NPT_ParseInteger(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToInteger
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToInteger(unsigned long& value, bool relaxed) const
+{
+ return NPT_ParseInteger(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToInteger32
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToInteger32(NPT_Int32& value, bool relaxed) const
+{
+ return NPT_ParseInteger32(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToInteger32
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToInteger32(NPT_UInt32& value, bool relaxed) const
+{
+ return NPT_ParseInteger32(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToInteger64
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToInteger64(NPT_Int64& value, bool relaxed) const
+{
+ return NPT_ParseInteger64(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToInteger64
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToInteger64(NPT_UInt64& value, bool relaxed) const
+{
+ return NPT_ParseInteger64(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::ToFloat
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_String::ToFloat(float& value, bool relaxed) const
+{
+ return NPT_ParseFloat(GetChars(), value, relaxed);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::TrimLeft
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::TrimLeft()
+{
+ return TrimLeft(NPT_STRINGS_WHITESPACE_CHARS);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::TrimLeft
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::TrimLeft(char c)
+{
+ char s[2] = {c, 0};
+ return TrimLeft((const char*)s);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::TrimLeft
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::TrimLeft(const char* chars)
+{
+ if (m_Chars == NULL) return *this;
+ const char* s = m_Chars;
+ while (char c = *s) {
+ const char* x = chars;
+ while (*x) {
+ if (*x == c) break;
+ x++;
+ }
+ if (*x == 0) break; // not found
+ s++;
+ }
+ if (s == m_Chars) {
+ // nothing was trimmed
+ return *this;
+ }
+
+ // shift chars to the left
+ char* d = m_Chars;
+ GetBuffer()->SetLength(GetLength()-(NPT_Size)(s-d));
+ while ((*d++ = *s++)) {};
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::TrimRight
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::TrimRight()
+{
+ return TrimRight(NPT_STRINGS_WHITESPACE_CHARS);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::TrimRight
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::TrimRight(char c)
+{
+ char s[2] = {c, 0};
+ return TrimRight((const char*)s);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::TrimRight
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::TrimRight(const char* chars)
+{
+ if (m_Chars == NULL || m_Chars[0] == '\0') return *this;
+ char* tail = m_Chars+GetLength()-1;
+ char* s = tail;
+ while (s != m_Chars-1) {
+ const char* x = chars;
+ while (*x) {
+ if (*x == *s) {
+ *s = '\0';
+ break;
+ }
+ x++;
+ }
+ if (*x == 0) break; // not found
+ s--;
+ }
+ if (s == tail) {
+ // nothing was trimmed
+ return *this;
+ }
+ GetBuffer()->SetLength(1+(int)(s-m_Chars));
+ return *this;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Trim
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::Trim()
+{
+ TrimLeft();
+ return TrimRight();
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Trim
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::Trim(char c)
+{
+ char s[2] = {c, 0};
+ TrimLeft((const char*)s);
+ return TrimRight((const char*)s);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::Trim
++---------------------------------------------------------------------*/
+const NPT_String&
+NPT_String::Trim(const char* chars)
+{
+ TrimLeft(chars);
+ return TrimRight(chars);
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::operator+(const NPT_String&, const char*)
++---------------------------------------------------------------------*/
+NPT_String
+operator+(const NPT_String& s1, const char* s2)
+{
+ // shortcut
+ if (s2 == NULL) return NPT_String(s1);
+
+ // measure strings
+ NPT_Size s1_length = s1.GetLength();
+ NPT_Size s2_length = NPT_String::StringLength(s2);
+
+ // allocate space for the new string
+ NPT_String result;
+ char* start = result.PrepareToWrite(s1_length+s2_length);
+
+ // concatenate the two strings into the result
+ NPT_String::CopyBuffer(start, s1, s1_length);
+ NPT_String::CopyString(start+s1_length, s2);
+
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::operator+(const NPT_String& , const char*)
++---------------------------------------------------------------------*/
+NPT_String
+operator+(const char* s1, const NPT_String& s2)
+{
+ // shortcut
+ if (s1 == NULL) return NPT_String(s2);
+
+ // measure strings
+ NPT_Size s1_length = NPT_String::StringLength(s1);
+ NPT_Size s2_length = s2.GetLength();
+
+ // allocate space for the new string
+ NPT_String result;
+ char* start = result.PrepareToWrite(s1_length+s2_length);
+
+ // concatenate the two strings into the result
+ NPT_String::CopyBuffer(start, s1, s1_length);
+ NPT_String::CopyString(start+s1_length, s2.GetChars());
+
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| NPT_String::operator+(const NPT_String& , char)
++---------------------------------------------------------------------*/
+NPT_String
+operator+(const NPT_String& s1, char c)
+{
+ // allocate space for the new string
+ NPT_String result;
+ result.Reserve(s1.GetLength()+1);
+
+ // append
+ result = s1;
+ result += c;
+
+ return result;
+}
+