+ wxStringBase strTmp;
+ strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
+
+ //This is kind of inefficient, but its pretty good considering...
+ //we don't want to use character access operators here because on STL
+ //it will freeze the reference count of strTmp, which means a deep copy
+ //at the end when swap is called
+ //
+ //Also, we can't use append with the full character pointer and must
+ //do it manually because this string can contain null characters
+ for(size_t i1 = 0; i1 < nStart; ++i1)
+ strTmp.append(1, this->c_str()[i1]);
+
+ //its safe to do the full version here because
+ //sz must be a normal c string
+ strTmp.append(sz);
+
+ for(size_t i2 = nStart + nLen; i2 < length(); ++i2)
+ strTmp.append(1, this->c_str()[i2]);
+
+ swap(strTmp);
+ return *this;
+}
+
+wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
+ size_t nCount, wxChar ch)
+{
+ return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
+}
+
+wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
+ const wxStringBase& str,
+ size_t nStart2, size_t nLen2)
+{
+ return replace(nStart, nLen, str.substr(nStart2, nLen2));
+}
+
+wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
+ const wxChar* sz, size_t nCount)
+{
+ return replace(nStart, nLen, wxStringBase(sz, nCount).c_str());
+}
+
+wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const
+{
+ if ( nLen == npos )
+ nLen = length() - nStart;
+ return wxStringBase(*this, nStart, nLen);
+}
+
+// assigns one string to another
+wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
+{
+ wxASSERT( stringSrc.GetStringData()->IsValid() );
+
+ // don't copy string over itself
+ if ( m_pchData != stringSrc.m_pchData ) {
+ if ( stringSrc.GetStringData()->IsEmpty() ) {
+ Reinit();
+ }
+ else {
+ // adjust references
+ GetStringData()->Unlock();
+ m_pchData = stringSrc.m_pchData;
+ GetStringData()->Lock();
+ }
+ }
+
+ return *this;
+}
+
+// assigns a single character
+wxStringBase& wxStringBase::operator=(wxChar ch)
+{
+ if ( !AssignCopy(1, &ch) ) {
+ wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
+ }
+ return *this;
+}
+
+// assigns C string
+wxStringBase& wxStringBase::operator=(const wxChar *psz)
+{
+ if ( !AssignCopy(wxStrlen(psz), psz) ) {
+ wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") );
+ }
+ return *this;
+}
+
+// helper function: does real copy
+bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
+{
+ if ( nSrcLen == 0 ) {
+ Reinit();
+ }
+ else {
+ if ( !AllocBeforeWrite(nSrcLen) ) {
+ // allocation failure handled by caller
+ return false;
+ }
+ memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
+ GetStringData()->nDataLength = nSrcLen;
+ m_pchData[nSrcLen] = wxT('\0');
+ }
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+// string concatenation
+// ---------------------------------------------------------------------------
+
+// add something to this string
+bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
+ size_t nMaxLen)
+{
+ STATISTICS_ADD(SummandLength, nSrcLen);
+
+ nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
+
+ // concatenating an empty string is a NOP
+ if ( nSrcLen > 0 ) {
+ wxStringData *pData = GetStringData();
+ size_t nLen = pData->nDataLength;
+ size_t nNewLen = nLen + nSrcLen;
+
+ // alloc new buffer if current is too small
+ if ( pData->IsShared() ) {
+ STATISTICS_ADD(ConcatHit, 0);
+
+ // we have to allocate another buffer
+ wxStringData* pOldData = GetStringData();
+ if ( !AllocBuffer(nNewLen) ) {
+ // allocation failure handled by caller
+ return false;
+ }
+ memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
+ pOldData->Unlock();
+ }
+ else if ( nNewLen > pData->nAllocLength ) {
+ STATISTICS_ADD(ConcatHit, 0);
+
+ reserve(nNewLen);
+ // we have to grow the buffer
+ if ( capacity() < nNewLen ) {
+ // allocation failure handled by caller
+ return false;
+ }
+ }
+ else {
+ STATISTICS_ADD(ConcatHit, 1);
+
+ // the buffer is already big enough
+ }
+
+ // should be enough space
+ wxASSERT( nNewLen <= GetStringData()->nAllocLength );
+
+ // fast concatenation - all is done in our buffer
+ memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
+
+ m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
+ GetStringData()->nDataLength = nNewLen; // and fix the length
+ }
+ //else: the string to append was empty
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+// simple sub-string extraction
+// ---------------------------------------------------------------------------
+
+// helper function: clone the data attached to this string
+bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
+{
+ if ( nCopyLen == 0 ) {
+ dest.Init();
+ }
+ else {
+ if ( !dest.AllocBuffer(nCopyLen) ) {
+ // allocation failure handled by caller
+ return false;
+ }
+ memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
+ }
+ return true;
+}
+
+#endif // !wxUSE_STL
+
+#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
+
+#if !wxUSE_STL
+ #define STRINGCLASS wxStringBase
+#else
+ #define STRINGCLASS wxString
+#endif
+
+static inline int wxDoCmp(const wxChar* s1, size_t l1,
+ const wxChar* s2, size_t l2)
+{
+ if( l1 == l2 )
+ return wxTmemcmp(s1, s2, l1);
+ else if( l1 < l2 )
+ {
+ int ret = wxTmemcmp(s1, s2, l1);
+ return ret == 0 ? -1 : ret;
+ }
+ else
+ {
+ int ret = wxTmemcmp(s1, s2, l2);
+ return ret == 0 ? +1 : ret;
+ }
+}
+
+int STRINGCLASS::compare(const wxStringBase& str) const
+{
+ return ::wxDoCmp(data(), length(), str.data(), str.length());
+}
+
+int STRINGCLASS::compare(size_t nStart, size_t nLen,
+ const wxStringBase& str) const
+{
+ wxASSERT(nStart <= length());
+ size_type strLen = length() - nStart;
+ nLen = strLen < nLen ? strLen : nLen;
+ return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length());
+}
+
+int STRINGCLASS::compare(size_t nStart, size_t nLen,
+ const wxStringBase& str,
+ size_t nStart2, size_t nLen2) const
+{
+ wxASSERT(nStart <= length());
+ wxASSERT(nStart2 <= str.length());
+ size_type strLen = length() - nStart,
+ strLen2 = str.length() - nStart2;
+ nLen = strLen < nLen ? strLen : nLen;
+ nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
+ return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2);
+}
+
+int STRINGCLASS::compare(const wxChar* sz) const
+{
+ size_t nLen = wxStrlen(sz);
+ return ::wxDoCmp(data(), length(), sz, nLen);
+}
+
+int STRINGCLASS::compare(size_t nStart, size_t nLen,
+ const wxChar* sz, size_t nCount) const
+{
+ wxASSERT(nStart <= length());
+ size_type strLen = length() - nStart;
+ nLen = strLen < nLen ? strLen : nLen;
+ if( nCount == npos )
+ nCount = wxStrlen(sz);
+
+ return ::wxDoCmp(data() + nStart, nLen, sz, nCount);
+}
+
+#undef STRINGCLASS
+
+#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
+
+// ===========================================================================
+// wxString class core
+// ===========================================================================
+
+// ---------------------------------------------------------------------------
+// construction and conversion
+// ---------------------------------------------------------------------------
+
+#if wxUSE_UNICODE
+
+// from multibyte string
+wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength)
+{
+ // anything to do?
+ if ( psz && nLength != 0 )
+ {
+ if ( nLength == npos )
+ {
+ nLength = wxNO_LEN;
+ }
+
+ size_t nLenWide;
+ wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide);
+
+ if ( nLenWide )
+ assign(wbuf, nLenWide);
+ }
+}
+
+//Convert wxString in Unicode mode to a multi-byte string
+const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
+{
+ return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL);
+}
+
+#else // ANSI
+
+#if wxUSE_WCHAR_T
+
+// from wide string
+wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength)
+{
+ // anything to do?
+ if ( pwz && nLength != 0 )
+ {
+ if ( nLength == npos )
+ {
+ nLength = wxNO_LEN;
+ }
+
+ size_t nLenMB;
+ wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB);
+
+ if ( nLenMB )
+ assign(buf, nLenMB);
+ }
+}
+
+//Converts this string to a wide character string if unicode
+//mode is not enabled and wxUSE_WCHAR_T is enabled
+const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
+{
+ return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL);
+}
+
+#endif // wxUSE_WCHAR_T
+
+#endif // Unicode/ANSI
+
+// shrink to minimal size (releasing extra memory)
+bool wxString::Shrink()
+{
+ wxString tmp(begin(), end());
+ swap(tmp);
+ return tmp.length() == length();
+}
+
+#if !wxUSE_STL
+// get the pointer to writable buffer of (at least) nLen bytes
+wxChar *wxString::GetWriteBuf(size_t nLen)
+{
+ if ( !AllocBeforeWrite(nLen) ) {
+ // allocation failure handled by caller
+ return NULL;
+ }
+
+ wxASSERT( GetStringData()->nRefs == 1 );
+ GetStringData()->Validate(false);
+
+ return m_pchData;
+}
+
+// put string back in a reasonable state after GetWriteBuf
+void wxString::UngetWriteBuf()
+{
+ GetStringData()->nDataLength = wxStrlen(m_pchData);
+ GetStringData()->Validate(true);
+}
+
+void wxString::UngetWriteBuf(size_t nLen)
+{
+ GetStringData()->nDataLength = nLen;
+ GetStringData()->Validate(true);
+}
+#endif
+
+// ---------------------------------------------------------------------------
+// data access
+// ---------------------------------------------------------------------------
+
+// all functions are inline in string.h
+
+// ---------------------------------------------------------------------------
+// assignment operators
+// ---------------------------------------------------------------------------
+
+#if !wxUSE_UNICODE
+
+// same as 'signed char' variant
+wxString& wxString::operator=(const unsigned char* psz)
+{
+ *this = (const char *)psz;
+ return *this;
+}
+
+#if wxUSE_WCHAR_T
+wxString& wxString::operator=(const wchar_t *pwz)
+{
+ wxString str(pwz);
+ swap(str);
+ return *this;
+}
+#endif
+
+#endif
+
+/*
+ * concatenation functions come in 5 flavours:
+ * string + string
+ * char + string and string + char
+ * C str + string and string + C str
+ */
+
+wxString operator+(const wxString& str1, const wxString& str2)
+{
+#if !wxUSE_STL
+ wxASSERT( str1.GetStringData()->IsValid() );
+ wxASSERT( str2.GetStringData()->IsValid() );
+#endif
+
+ wxString s = str1;
+ s += str2;
+
+ return s;
+}
+
+wxString operator+(const wxString& str, wxChar ch)
+{
+#if !wxUSE_STL
+ wxASSERT( str.GetStringData()->IsValid() );
+#endif
+
+ wxString s = str;
+ s += ch;
+
+ return s;
+}
+
+wxString operator+(wxChar ch, const wxString& str)
+{
+#if !wxUSE_STL
+ wxASSERT( str.GetStringData()->IsValid() );
+#endif
+
+ wxString s = ch;
+ s += str;
+
+ return s;
+}
+
+wxString operator+(const wxString& str, const wxChar *psz)
+{
+#if !wxUSE_STL
+ wxASSERT( str.GetStringData()->IsValid() );
+#endif
+
+ wxString s;
+ if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
+ wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+ }
+ s += str;
+ s += psz;
+
+ return s;
+}
+
+wxString operator+(const wxChar *psz, const wxString& str)
+{
+#if !wxUSE_STL
+ wxASSERT( str.GetStringData()->IsValid() );
+#endif
+
+ wxString s;
+ if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
+ wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+ }
+ s = psz;
+ s += str;
+
+ return s;
+}
+
+// ===========================================================================
+// other common string functions
+// ===========================================================================
+
+int wxString::Cmp(const wxString& s) const
+{
+ return compare(s);
+}
+
+int wxString::Cmp(const wxChar* psz) const
+{
+ return compare(psz);
+}
+
+static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1,
+ const wxChar* s2, size_t l2)
+{
+ size_t i;
+
+ if( l1 == l2 )
+ {
+ for(i = 0; i < l1; ++i)
+ {
+ if(wxTolower(s1[i]) != wxTolower(s2[i]))
+ break;
+ }
+ return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
+ }
+ else if( l1 < l2 )
+ {
+ for(i = 0; i < l1; ++i)
+ {
+ if(wxTolower(s1[i]) != wxTolower(s2[i]))
+ break;
+ }
+ return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
+ }
+ else
+ {
+ for(i = 0; i < l2; ++i)
+ {
+ if(wxTolower(s1[i]) != wxTolower(s2[i]))
+ break;
+ }
+ return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1;
+ }
+}
+
+int wxString::CmpNoCase(const wxString& s) const
+{
+ return wxDoCmpNoCase(data(), length(), s.data(), s.length());
+}
+
+int wxString::CmpNoCase(const wxChar* psz) const
+{
+ int nLen = wxStrlen(psz);
+
+ return wxDoCmpNoCase(data(), length(), psz, nLen);
+}
+
+
+#if wxUSE_UNICODE
+
+#ifdef __MWERKS__
+#ifndef __SCHAR_MAX__
+#define __SCHAR_MAX__ 127
+#endif
+#endif
+
+wxString wxString::FromAscii(const char *ascii)
+{
+ if (!ascii)
+ return wxEmptyString;
+
+ size_t len = strlen( ascii );
+ wxString res;
+
+ if ( len )
+ {
+ wxStringBuffer buf(res, len);
+
+ wchar_t *dest = buf;
+
+ for ( ;; )
+ {
+ if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
+ break;
+ }
+ }
+
+ return res;
+}
+
+wxString wxString::FromAscii(const char ascii)
+{
+ // What do we do with '\0' ?
+
+ wxString res;
+ res += (wchar_t)(unsigned char) ascii;
+
+ return res;
+}
+
+const wxCharBuffer wxString::ToAscii() const
+{
+ // this will allocate enough space for the terminating NUL too
+ wxCharBuffer buffer(length());
+
+
+ char *dest = buffer.data();
+
+ const wchar_t *pwc = c_str();
+ for ( ;; )
+ {
+ *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc);
+
+ // the output string can't have embedded NULs anyhow, so we can safely
+ // stop at first of them even if we do have any
+ if ( !*pwc++ )
+ break;
+ }
+
+ return buffer;
+}
+
+#endif // Unicode
+
+// extract string of length nCount starting at nFirst
+wxString wxString::Mid(size_t nFirst, size_t nCount) const
+{
+ size_t nLen = length();
+
+ // default value of nCount is npos and means "till the end"
+ if ( nCount == npos )
+ {
+ nCount = nLen - nFirst;
+ }
+
+ // out-of-bounds requests return sensible things
+ if ( nFirst + nCount > nLen )
+ {
+ nCount = nLen - nFirst;
+ }
+
+ if ( nFirst > nLen )
+ {
+ // AllocCopy() will return empty string
+ return wxEmptyString;
+ }
+
+ wxString dest(*this, nFirst, nCount);
+ if ( dest.length() != nCount )
+ {
+ wxFAIL_MSG( _T("out of memory in wxString::Mid") );
+ }
+
+ return dest;
+}
+
+// check that the string starts with prefix and return the rest of the string
+// in the provided pointer if it is not NULL, otherwise return false
+bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
+{
+ wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
+
+ // first check if the beginning of the string matches the prefix: note
+ // that we don't have to check that we don't run out of this string as
+ // when we reach the terminating NUL, either prefix string ends too (and
+ // then it's ok) or we break out of the loop because there is no match
+ const wxChar *p = c_str();
+ while ( *prefix )
+ {
+ if ( *prefix++ != *p++ )
+ {
+ // no match
+ return false;
+ }
+ }
+
+ if ( rest )
+ {
+ // put the rest of the string into provided pointer
+ *rest = p;
+ }
+
+ return true;
+}
+
+
+// check that the string ends with suffix and return the rest of it in the
+// provided pointer if it is not NULL, otherwise return false
+bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
+{
+ wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
+
+ int start = length() - wxStrlen(suffix);
+ if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 )
+ return false;
+
+ if ( rest )
+ {
+ // put the rest of the string into provided pointer
+ rest->assign(*this, 0, start);
+ }
+
+ return true;
+}
+
+
+// extract nCount last (rightmost) characters
+wxString wxString::Right(size_t nCount) const
+{
+ if ( nCount > length() )
+ nCount = length();
+
+ wxString dest(*this, length() - nCount, nCount);
+ if ( dest.length() != nCount ) {
+ wxFAIL_MSG( _T("out of memory in wxString::Right") );
+ }
+ return dest;
+}
+
+// get all characters after the last occurence of ch
+// (returns the whole string if ch not found)
+wxString wxString::AfterLast(wxChar ch) const
+{
+ wxString str;
+ int iPos = Find(ch, true);
+ if ( iPos == wxNOT_FOUND )
+ str = *this;
+ else
+ str = c_str() + iPos + 1;
+
+ return str;
+}
+
+// extract nCount first (leftmost) characters
+wxString wxString::Left(size_t nCount) const
+{
+ if ( nCount > length() )
+ nCount = length();
+
+ wxString dest(*this, 0, nCount);
+ if ( dest.length() != nCount ) {
+ wxFAIL_MSG( _T("out of memory in wxString::Left") );
+ }
+ return dest;
+}
+
+// get all characters before the first occurence of ch
+// (returns the whole string if ch not found)
+wxString wxString::BeforeFirst(wxChar ch) const
+{
+ int iPos = Find(ch);
+ if ( iPos == wxNOT_FOUND ) iPos = length();
+ return wxString(*this, 0, iPos);
+}
+
+/// get all characters before the last occurence of ch
+/// (returns empty string if ch not found)
+wxString wxString::BeforeLast(wxChar ch) const
+{
+ wxString str;
+ int iPos = Find(ch, true);
+ if ( iPos != wxNOT_FOUND && iPos != 0 )
+ str = wxString(c_str(), iPos);
+
+ return str;