+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;
+}
+
+/// get all characters after the first occurence of ch
+/// (returns empty string if ch not found)
+wxString wxString::AfterFirst(wxChar ch) const
+{
+  wxString str;
+  int iPos = Find(ch);
+  if ( iPos != wxNOT_FOUND )
+    str = c_str() + iPos + 1;
+
+  return str;
+}
+
+// replace first (or all) occurences of some substring with another one
+size_t wxString::Replace(const wxChar *szOld,
+                  const wxChar *szNew, bool bReplaceAll)
+{
+    // if we tried to replace an empty string we'd enter an infinite loop below
+    wxCHECK_MSG( szOld && *szOld && szNew, 0,
+                 _T("wxString::Replace(): invalid parameter") );
+
+    size_t uiCount = 0;   // count of replacements made
+
+    size_t uiOldLen = wxStrlen(szOld);
+    size_t uiNewLen = wxStrlen(szNew);
+
+    size_t dwPos = 0;
+
+    while ( this->c_str()[dwPos] != wxT('\0') )
+    {
+        //DO NOT USE STRSTR HERE
+        //this string can contain embedded null characters,
+        //so strstr will function incorrectly
+        dwPos = find(szOld, dwPos);
+        if ( dwPos == npos )
+            break;                  // exit the loop
+        else
+        {
+            //replace this occurance of the old string with the new one
+            replace(dwPos, uiOldLen, szNew, uiNewLen);
+
+            //move up pos past the string that was replaced
+            dwPos += uiNewLen;
+
+            //increase replace count
+            ++uiCount;
+
+            // stop now?
+            if ( !bReplaceAll )
+                break;                  // exit the loop
+        }
+    }
+
+    return uiCount;