]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/string.cpp
Font updates
[wxWidgets.git] / src / common / string.cpp
index 134cd452c656474af06995071b94fd4a9c151b7b..77af363cb5f986680d60b0397c4cbf821e48c50c 100644 (file)
   #include <clib.h>
 #endif
 
   #include <clib.h>
 #endif
 
-#ifdef  WXSTRING_IS_WXOBJECT
-  IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject)
-#endif  //WXSTRING_IS_WXOBJECT
-
 #if wxUSE_UNICODE
 #if wxUSE_UNICODE
-#undef wxUSE_EXPERIMENTAL_PRINTF
-#define wxUSE_EXPERIMENTAL_PRINTF 1
+    #undef wxUSE_EXPERIMENTAL_PRINTF
+    #ifndef wvsnprintf
+        #define wxUSE_EXPERIMENTAL_PRINTF 1
+    #endif
 #endif
 
 // allocating extra space for each string consumes more memory but speeds up
 #endif
 
 // allocating extra space for each string consumes more memory but speeds up
@@ -188,46 +186,6 @@ wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
 
 #endif  //std::string compatibility
 
 
 #endif  //std::string compatibility
 
-extern int WXDLLEXPORT wxVsnprintf(wxChar *buf, size_t len,
-                                   const wxChar *format, va_list argptr)
-{
-#if wxUSE_UNICODE
-    // FIXME should use wvsnprintf() or whatever if it's available
-    wxString s;
-    int iLen = s.PrintfV(format, argptr);
-    if ( iLen != -1 )
-    {
-        wxStrncpy(buf, s.c_str(), len);
-        buf[len-1] = wxT('\0');
-    }
-
-    return iLen;
-#else // ANSI
-    // vsnprintf() will not terminate the string with '\0' if there is not
-    // enough place, but we want the string to always be NUL terminated
-    int rc = wxVsnprintfA(buf, len - 1, format, argptr);
-    if ( rc == -1 )
-    {
-        buf[len] = 0;
-    }
-
-    return rc;
-#endif // Unicode/ANSI
-}
-
-extern int WXDLLEXPORT wxSnprintf(wxChar *buf, size_t len,
-                                  const wxChar *format, ...)
-{
-    va_list argptr;
-    va_start(argptr, format);
-
-    int iLen = wxVsnprintf(buf, len, format, argptr);
-
-    va_end(argptr);
-
-    return iLen;
-}
-
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
@@ -271,7 +229,10 @@ wxString::wxString(wxChar ch, size_t nLength)
   Init();
 
   if ( nLength > 0 ) {
   Init();
 
   if ( nLength > 0 ) {
-    AllocBuffer(nLength);
+    if ( !AllocBuffer(nLength) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::wxString") );
+      return;
+    }
 
 #if wxUSE_UNICODE
     // memset only works on char
 
 #if wxUSE_UNICODE
     // memset only works on char
@@ -298,7 +259,10 @@ void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
 
   if ( nLength > 0 ) {
     // trailing '\0' is written in AllocBuffer()
 
   if ( nLength > 0 ) {
     // trailing '\0' is written in AllocBuffer()
-    AllocBuffer(nLength);
+    if ( !AllocBuffer(nLength) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::InitWith") );
+      return;
+    }
     memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
   }
 }
     memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
   }
 }
@@ -328,7 +292,10 @@ wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
 
   // empty?
   if ( (nLen != 0) && (nLen != (size_t)-1) ) {
 
   // empty?
   if ( (nLen != 0) && (nLen != (size_t)-1) ) {
-    AllocBuffer(nLen);
+    if ( !AllocBuffer(nLen) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::wxString") );
+      return;
+    }
     conv.MB2WC(m_pchData, psz, nLen);
   }
   else {
     conv.MB2WC(m_pchData, psz, nLen);
   }
   else {
@@ -354,7 +321,10 @@ wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
 
   // empty?
   if ( (nLen != 0) && (nLen != (size_t)-1) ) {
 
   // empty?
   if ( (nLen != 0) && (nLen != (size_t)-1) ) {
-    AllocBuffer(nLen);
+    if ( !AllocBuffer(nLen) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::wxString") );
+      return;
+    }
     conv.WC2MB(m_pchData, pwz, nLen);
   }
   else {
     conv.WC2MB(m_pchData, pwz, nLen);
   }
   else {
@@ -370,7 +340,7 @@ wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
 // ---------------------------------------------------------------------------
 
 // allocates memory needed to store a C string of length nLen
 // ---------------------------------------------------------------------------
 
 // allocates memory needed to store a C string of length nLen
-void wxString::AllocBuffer(size_t nLen)
+bool wxString::AllocBuffer(size_t nLen)
 {
   // allocating 0 sized buffer doesn't make sense, all empty strings should
   // reuse g_strEmpty
 {
   // allocating 0 sized buffer doesn't make sense, all empty strings should
   // reuse g_strEmpty
@@ -387,30 +357,42 @@ void wxString::AllocBuffer(size_t nLen)
   // 2) sizeof(wxStringData) for housekeeping info
   wxStringData* pData = (wxStringData*)
     malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
   // 2) sizeof(wxStringData) for housekeeping info
   wxStringData* pData = (wxStringData*)
     malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
+
+  if ( pData == NULL ) {
+    // allocation failures are handled by the caller
+    return FALSE;
+  }
+
   pData->nRefs        = 1;
   pData->nDataLength  = nLen;
   pData->nAllocLength = nLen + EXTRA_ALLOC;
   m_pchData           = pData->data();  // data starts after wxStringData
   m_pchData[nLen]     = wxT('\0');
   pData->nRefs        = 1;
   pData->nDataLength  = nLen;
   pData->nAllocLength = nLen + EXTRA_ALLOC;
   m_pchData           = pData->data();  // data starts after wxStringData
   m_pchData[nLen]     = wxT('\0');
+  return TRUE;
 }
 
 // must be called before changing this string
 }
 
 // must be called before changing this string
-void wxString::CopyBeforeWrite()
+bool wxString::CopyBeforeWrite()
 {
   wxStringData* pData = GetStringData();
 
   if ( pData->IsShared() ) {
     pData->Unlock();                // memory not freed because shared
     size_t nLen = pData->nDataLength;
 {
   wxStringData* pData = GetStringData();
 
   if ( pData->IsShared() ) {
     pData->Unlock();                // memory not freed because shared
     size_t nLen = pData->nDataLength;
-    AllocBuffer(nLen);
+    if ( !AllocBuffer(nLen) ) {
+      // allocation failures are handled by the caller
+      return FALSE;
+    }
     memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
   }
 
   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
     memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
   }
 
   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
+
+  return TRUE;
 }
 
 // must be called before replacing contents of this string
 }
 
 // must be called before replacing contents of this string
-void wxString::AllocBeforeWrite(size_t nLen)
+bool wxString::AllocBeforeWrite(size_t nLen)
 {
   wxASSERT( nLen != 0 );  // doesn't make any sense
 
 {
   wxASSERT( nLen != 0 );  // doesn't make any sense
 
@@ -419,7 +401,10 @@ void wxString::AllocBeforeWrite(size_t nLen)
   if ( pData->IsShared() || pData->IsEmpty() ) {
     // can't work with old buffer, get new one
     pData->Unlock();
   if ( pData->IsShared() || pData->IsEmpty() ) {
     // can't work with old buffer, get new one
     pData->Unlock();
-    AllocBuffer(nLen);
+    if ( !AllocBuffer(nLen) ) {
+      // allocation failures are handled by the caller
+      return FALSE;
+    }
   }
   else {
     if ( nLen > pData->nAllocLength ) {
   }
   else {
     if ( nLen > pData->nAllocLength ) {
@@ -429,15 +414,13 @@ void wxString::AllocBeforeWrite(size_t nLen)
 
       nLen += EXTRA_ALLOC;
 
 
       nLen += EXTRA_ALLOC;
 
-      wxStringData *pDataOld = pData;
       pData = (wxStringData*)
           realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
       pData = (wxStringData*)
           realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
-      if ( !pData ) {
-        // out of memory
-        free(pDataOld);
 
 
-        // FIXME we're going to crash...
-        return;
+      if ( pData == NULL ) {
+        // allocation failures are handled by the caller
+        // keep previous data since reallocation failed
+        return FALSE;
       }
 
       pData->nAllocLength = nLen;
       }
 
       pData->nAllocLength = nLen;
@@ -449,10 +432,12 @@ void wxString::AllocBeforeWrite(size_t nLen)
   }
 
   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
   }
 
   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
+
+  return TRUE;
 }
 
 // allocate enough memory for nLen characters
 }
 
 // allocate enough memory for nLen characters
-void wxString::Alloc(size_t nLen)
+bool wxString::Alloc(size_t nLen)
 {
   wxStringData *pData = GetStringData();
   if ( pData->nAllocLength <= nLen ) {
 {
   wxStringData *pData = GetStringData();
   if ( pData->nAllocLength <= nLen ) {
@@ -460,7 +445,13 @@ void wxString::Alloc(size_t nLen)
       nLen += EXTRA_ALLOC;
 
       wxStringData* pData = (wxStringData*)
       nLen += EXTRA_ALLOC;
 
       wxStringData* pData = (wxStringData*)
-        malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
+          malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
+
+      if ( pData == NULL ) {
+        // allocation failure handled by caller
+        return FALSE;
+      }
+
       pData->nRefs = 1;
       pData->nDataLength = 0;
       pData->nAllocLength = nLen;
       pData->nRefs = 1;
       pData->nDataLength = 0;
       pData->nAllocLength = nLen;
@@ -470,42 +461,47 @@ void wxString::Alloc(size_t nLen)
     else if ( pData->IsShared() ) {
       pData->Unlock();                // memory not freed because shared
       size_t nOldLen = pData->nDataLength;
     else if ( pData->IsShared() ) {
       pData->Unlock();                // memory not freed because shared
       size_t nOldLen = pData->nDataLength;
-      AllocBuffer(nLen);
+      if ( !AllocBuffer(nLen) ) {
+        // allocation failure handled by caller
+        return FALSE;
+      }
       memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
     }
     else {
       nLen += EXTRA_ALLOC;
 
       memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
     }
     else {
       nLen += EXTRA_ALLOC;
 
-      wxStringData *pDataOld = pData;
-      wxStringData *p = (wxStringData *)
+      pData = (wxStringData *)
         realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
 
         realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
 
-      if ( p == NULL ) {
-        // don't leak memory
-        free(pDataOld);
-
-        // FIXME what to do on memory error?
-        return;
+      if ( pData == NULL ) {
+        // allocation failure handled by caller
+        // keep previous data since reallocation failed
+        return FALSE;
       }
 
       // it's not important if the pointer changed or not (the check for this
       // is not faster than assigning to m_pchData in all cases)
       }
 
       // it's not important if the pointer changed or not (the check for this
       // is not faster than assigning to m_pchData in all cases)
-      p->nAllocLength = nLen;
-      m_pchData = p->data();
+      pData->nAllocLength = nLen;
+      m_pchData = pData->data();
     }
   }
   //else: we've already got enough
     }
   }
   //else: we've already got enough
+  return TRUE;
 }
 
 // shrink to minimal size (releasing extra memory)
 }
 
 // shrink to minimal size (releasing extra memory)
-void wxString::Shrink()
+bool wxString::Shrink()
 {
   wxStringData *pData = GetStringData();
 
   size_t nLen = pData->nDataLength;
   void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
 
 {
   wxStringData *pData = GetStringData();
 
   size_t nLen = pData->nDataLength;
   void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
 
-  wxASSERT_MSG( p != NULL, _T("can't free memory?") );
+  if ( p == NULL) {
+      wxFAIL_MSG( _T("out of memory reallocating wxString data") );
+      // keep previous data since reallocation failed
+      return FALSE;
+  }
 
   if ( p != pData )
   {
 
   if ( p != pData )
   {
@@ -517,12 +513,17 @@ void wxString::Shrink()
   }
 
   pData->nAllocLength = nLen;
   }
 
   pData->nAllocLength = nLen;
+
+  return TRUE;
 }
 
 // get the pointer to writable buffer of (at least) nLen bytes
 wxChar *wxString::GetWriteBuf(size_t nLen)
 {
 }
 
 // get the pointer to writable buffer of (at least) nLen bytes
 wxChar *wxString::GetWriteBuf(size_t nLen)
 {
-  AllocBeforeWrite(nLen);
+  if ( !AllocBeforeWrite(nLen) ) {
+    // allocation failure handled by caller
+    return NULL;
+  }
 
   wxASSERT( GetStringData()->nRefs == 1 );
   GetStringData()->Validate(FALSE);
 
   wxASSERT( GetStringData()->nRefs == 1 );
   GetStringData()->Validate(FALSE);
@@ -554,17 +555,21 @@ void wxString::UngetWriteBuf(size_t nLen)
 // ---------------------------------------------------------------------------
 
 // helper function: does real copy
 // ---------------------------------------------------------------------------
 
 // helper function: does real copy
-void wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
+bool wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
 {
   if ( nSrcLen == 0 ) {
     Reinit();
   }
   else {
 {
   if ( nSrcLen == 0 ) {
     Reinit();
   }
   else {
-    AllocBeforeWrite(nSrcLen);
+    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');
   }
     memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
     GetStringData()->nDataLength = nSrcLen;
     m_pchData[nSrcLen] = wxT('\0');
   }
+  return TRUE;
 }
 
 // assigns one string to another
 }
 
 // assigns one string to another
@@ -591,7 +596,9 @@ wxString& wxString::operator=(const wxString& stringSrc)
 // assigns a single character
 wxString& wxString::operator=(wxChar ch)
 {
 // assigns a single character
 wxString& wxString::operator=(wxChar ch)
 {
-  AssignCopy(1, &ch);
+  if ( !AssignCopy(1, &ch) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::operator=(wxChar)") );
+  }
   return *this;
 }
 
   return *this;
 }
 
@@ -599,7 +606,9 @@ wxString& wxString::operator=(wxChar ch)
 // assigns C string
 wxString& wxString::operator=(const wxChar *psz)
 {
 // assigns C string
 wxString& wxString::operator=(const wxChar *psz)
 {
-  AssignCopy(wxStrlen(psz), psz);
+  if ( !AssignCopy(wxStrlen(psz), psz) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::operator=(const wxChar *)") );
+  }
   return *this;
 }
 
   return *this;
 }
 
@@ -628,7 +637,7 @@ wxString& wxString::operator=(const wchar_t *pwz)
 // ---------------------------------------------------------------------------
 
 // add something to this string
 // ---------------------------------------------------------------------------
 
 // add something to this string
-void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
+bool wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
 {
   STATISTICS_ADD(SummandLength, nSrcLen);
 
 {
   STATISTICS_ADD(SummandLength, nSrcLen);
 
@@ -644,7 +653,10 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
 
       // we have to allocate another buffer
       wxStringData* pOldData = GetStringData();
 
       // we have to allocate another buffer
       wxStringData* pOldData = GetStringData();
-      AllocBuffer(nNewLen);
+      if ( !AllocBuffer(nNewLen) ) {
+          // allocation failure handled by caller
+          return FALSE;
+      }
       memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
       pOldData->Unlock();
     }
       memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
       pOldData->Unlock();
     }
@@ -652,7 +664,10 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
       STATISTICS_ADD(ConcatHit, 0);
 
       // we have to grow the buffer
       STATISTICS_ADD(ConcatHit, 0);
 
       // we have to grow the buffer
-      Alloc(nNewLen);
+      if ( !Alloc(nNewLen) ) {
+          // allocation failure handled by caller
+          return FALSE;
+      }
     }
     else {
       STATISTICS_ADD(ConcatHit, 1);
     }
     else {
       STATISTICS_ADD(ConcatHit, 1);
@@ -670,6 +685,7 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
     GetStringData()->nDataLength = nNewLen; // and fix the length
   }
   //else: the string to append was empty
     GetStringData()->nDataLength = nNewLen; // and fix the length
   }
   //else: the string to append was empty
+  return TRUE;
 }
 
 /*
 }
 
 /*
@@ -679,57 +695,61 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
  *  C str  + string      and      string + C str
  */
 
  *  C str  + string      and      string + C str
  */
 
-wxString operator+(const wxString& string1, const wxString& string2)
+wxString operator+(const wxString& str1, const wxString& str2)
 {
 {
-  wxASSERT( string1.GetStringData()->IsValid() );
-  wxASSERT( string2.GetStringData()->IsValid() );
+  wxASSERT( str1.GetStringData()->IsValid() );
+  wxASSERT( str2.GetStringData()->IsValid() );
 
 
-  wxString s = string1;
-  s += string2;
+  wxString s = str1;
+  s += str2;
 
   return s;
 }
 
 
   return s;
 }
 
-wxString operator+(const wxString& string, wxChar ch)
+wxString operator+(const wxString& str, wxChar ch)
 {
 {
-  wxASSERT( string.GetStringData()->IsValid() );
+  wxASSERT( str.GetStringData()->IsValid() );
 
 
-  wxString s = string;
+  wxString s = str;
   s += ch;
 
   return s;
 }
 
   s += ch;
 
   return s;
 }
 
-wxString operator+(wxChar ch, const wxString& string)
+wxString operator+(wxChar ch, const wxString& str)
 {
 {
-  wxASSERT( string.GetStringData()->IsValid() );
+  wxASSERT( str.GetStringData()->IsValid() );
 
   wxString s = ch;
 
   wxString s = ch;
-  s += string;
+  s += str;
 
   return s;
 }
 
 
   return s;
 }
 
-wxString operator+(const wxString& string, const wxChar *psz)
+wxString operator+(const wxString& str, const wxChar *psz)
 {
 {
-  wxASSERT( string.GetStringData()->IsValid() );
+  wxASSERT( str.GetStringData()->IsValid() );
 
   wxString s;
 
   wxString s;
-  s.Alloc(wxStrlen(psz) + string.Len());
-  s = string;
+  if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+  }
+  s = str;
   s += psz;
 
   return s;
 }
 
   s += psz;
 
   return s;
 }
 
-wxString operator+(const wxChar *psz, const wxString& string)
+wxString operator+(const wxChar *psz, const wxString& str)
 {
 {
-  wxASSERT( string.GetStringData()->IsValid() );
+  wxASSERT( str.GetStringData()->IsValid() );
 
   wxString s;
 
   wxString s;
-  s.Alloc(wxStrlen(psz) + string.Len());
+  if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+  }
   s = psz;
   s = psz;
-  s += string;
+  s += str;
 
   return s;
 }
 
   return s;
 }
@@ -738,20 +758,73 @@ wxString operator+(const wxChar *psz, const wxString& string)
 // other common string functions
 // ===========================================================================
 
 // other common string functions
 // ===========================================================================
 
+#if wxUSE_UNICODE
+
+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;
+}
+
+const wxCharBuffer wxString::ToAscii() const
+{
+    // this will allocate enough space for the terminating NUL too
+    wxCharBuffer buffer(length());
+
+    signed char *dest = (signed char *)buffer.data();
+
+    const wchar_t *pwc = c_str();
+    for ( ;; )
+    {
+        *dest++ = *pwc > SCHAR_MAX ? '_' : *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
+
 // ---------------------------------------------------------------------------
 // simple sub-string extraction
 // ---------------------------------------------------------------------------
 
 // helper function: clone the data attached to this string
 // ---------------------------------------------------------------------------
 // simple sub-string extraction
 // ---------------------------------------------------------------------------
 
 // helper function: clone the data attached to this string
-void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
+bool wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
 {
   if ( nCopyLen == 0 ) {
     dest.Init();
   }
   else {
 {
   if ( nCopyLen == 0 ) {
     dest.Init();
   }
   else {
-    dest.AllocBuffer(nCopyLen);
+    if ( !dest.AllocBuffer(nCopyLen) ) {
+      // allocation failure handled by caller
+      return FALSE;
+    }
     memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
   }
     memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
   }
+  return TRUE;
 }
 
 // extract string of length nCount starting at nFirst
 }
 
 // extract string of length nCount starting at nFirst
@@ -779,7 +852,9 @@ wxString wxString::Mid(size_t nFirst, size_t nCount) const
   }
 
   wxString dest;
   }
 
   wxString dest;
-  AllocCopy(dest, nCount, nFirst);
+  if ( !AllocCopy(dest, nCount, nFirst) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::Mid") );
+  }
 
   return dest;
 }
 
   return dest;
 }
@@ -820,7 +895,9 @@ wxString wxString::Right(size_t nCount) const
     nCount = GetStringData()->nDataLength;
 
   wxString dest;
     nCount = GetStringData()->nDataLength;
 
   wxString dest;
-  AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount);
+  if ( !AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::Right") );
+  }
   return dest;
 }
 
   return dest;
 }
 
@@ -845,7 +922,9 @@ wxString wxString::Left(size_t nCount) const
     nCount = GetStringData()->nDataLength;
 
   wxString dest;
     nCount = GetStringData()->nDataLength;
 
   wxString dest;
-  AllocCopy(dest, nCount, 0);
+  if ( !AllocCopy(dest, nCount, 0) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::Left") );
+  }
   return dest;
 }
 
   return dest;
 }
 
@@ -906,7 +985,10 @@ size_t wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplace
     }
     else {
       // take chars before match
     }
     else {
       // take chars before match
-      strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent);
+      if ( !strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent) ) {
+        wxFAIL_MSG( _T("out of memory in wxString::Replace") );
+        return 0;
+      }
       strTemp += szNew;
       pCurrent = pSubstr + uiOldLen;  // restart after match
 
       strTemp += szNew;
       pCurrent = pSubstr + uiOldLen;  // restart after match
 
@@ -972,7 +1054,10 @@ wxString wxString::Strip(stripType w) const
 
 wxString& wxString::MakeUpper()
 {
 
 wxString& wxString::MakeUpper()
 {
-  CopyBeforeWrite();
+  if ( !CopyBeforeWrite() ) {
+    wxFAIL_MSG( _T("out of memory in wxString::MakeUpper") );
+    return *this;
+  }
 
   for ( wxChar *p = m_pchData; *p; p++ )
     *p = (wxChar)wxToupper(*p);
 
   for ( wxChar *p = m_pchData; *p; p++ )
     *p = (wxChar)wxToupper(*p);
@@ -982,7 +1067,10 @@ wxString& wxString::MakeUpper()
 
 wxString& wxString::MakeLower()
 {
 
 wxString& wxString::MakeLower()
 {
-  CopyBeforeWrite();
+  if ( !CopyBeforeWrite() ) {
+    wxFAIL_MSG( _T("out of memory in wxString::MakeLower") );
+    return *this;
+  }
 
   for ( wxChar *p = m_pchData; *p; p++ )
     *p = (wxChar)wxTolower(*p);
 
   for ( wxChar *p = m_pchData; *p; p++ )
     *p = (wxChar)wxTolower(*p);
@@ -1014,7 +1102,10 @@ wxString& wxString::Trim(bool bFromRight)
      )
   {
     // ok, there is at least one space to trim
      )
   {
     // ok, there is at least one space to trim
-    CopyBeforeWrite();
+    if ( !CopyBeforeWrite() ) {
+      wxFAIL_MSG( _T("out of memory in wxString::Trim") );
+      return *this;
+    }
 
     if ( bFromRight )
     {
 
     if ( bFromRight )
     {
@@ -1064,7 +1155,10 @@ wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
 wxString& wxString::Truncate(size_t uiLen)
 {
   if ( uiLen < Len() ) {
 wxString& wxString::Truncate(size_t uiLen)
 {
   if ( uiLen < Len() ) {
-    CopyBeforeWrite();
+    if ( !CopyBeforeWrite() ) {
+      wxFAIL_MSG( _T("out of memory in wxString::Truncate") );
+      return *this;
+    }
 
     *(m_pchData + uiLen) = wxT('\0');
     GetStringData()->nDataLength = uiLen;
 
     *(m_pchData + uiLen) = wxT('\0');
     GetStringData()->nDataLength = uiLen;
@@ -1101,6 +1195,7 @@ int wxString::Find(const wxChar *pszSub) const
 bool wxString::ToLong(long *val, int base) const
 {
     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToLong") );
 bool wxString::ToLong(long *val, int base) const
 {
     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToLong") );
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
     const wxChar *start = c_str();
     wxChar *end;
 
     const wxChar *start = c_str();
     wxChar *end;
@@ -1114,6 +1209,7 @@ bool wxString::ToLong(long *val, int base) const
 bool wxString::ToULong(unsigned long *val, int base) const
 {
     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToULong") );
 bool wxString::ToULong(unsigned long *val, int base) const
 {
     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToULong") );
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
     const wxChar *start = c_str();
     wxChar *end;
 
     const wxChar *start = c_str();
     wxChar *end;
@@ -1653,7 +1749,7 @@ void wxString::swap(wxString& str)
     // ref count always stays positive
     wxString tmp = str;
     str = *this;
     // ref count always stays positive
     wxString tmp = str;
     str = *this;
-    *this = str;
+    *this = tmp;
 }
 
 wxString& wxString::insert(size_t nPos, const wxString& str)
 }
 
 wxString& wxString::insert(size_t nPos, const wxString& str)
@@ -1950,7 +2046,7 @@ void wxArrayString::Copy(const wxArrayString& src)
 }
 
 // grow the array
 }
 
 // grow the array
-void wxArrayString::Grow()
+void wxArrayString::Grow(size_t nIncrement)
 {
   // only do it if no more place
   if ( m_nCount == m_nSize ) {
 {
   // only do it if no more place
   if ( m_nCount == m_nSize ) {
@@ -1969,10 +2065,12 @@ void wxArrayString::Grow()
       // otherwise when it's called for the first time, nIncrement would be 0
       // and the array would never be expanded
       // add 50% but not too much
       // otherwise when it's called for the first time, nIncrement would be 0
       // and the array would never be expanded
       // add 50% but not too much
-      size_t nIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
+      size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
                           ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
                           ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
-      if ( nIncrement > ARRAY_MAXSIZE_INCREMENT )
-        nIncrement = ARRAY_MAXSIZE_INCREMENT;
+      if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT )
+        ndefIncrement = ARRAY_MAXSIZE_INCREMENT;
+      if ( nIncrement < ndefIncrement )
+        nIncrement = ndefIncrement;
       m_nSize += nIncrement;
       wxChar **pNew = new wxChar *[m_nSize];
 
       m_nSize += nIncrement;
       wxChar **pNew = new wxChar *[m_nSize];
 
@@ -2024,8 +2122,6 @@ wxArrayString::~wxArrayString()
 // pre-allocates memory (frees the previous data!)
 void wxArrayString::Alloc(size_t nSize)
 {
 // pre-allocates memory (frees the previous data!)
 void wxArrayString::Alloc(size_t nSize)
 {
-  wxASSERT( nSize > 0 );
-
   // only if old buffer was not big enough
   if ( nSize > m_nSize ) {
     Free();
   // only if old buffer was not big enough
   if ( nSize > m_nSize ) {
     Free();
@@ -2117,7 +2213,7 @@ int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
 }
 
 // add item at the end
 }
 
 // add item at the end
-size_t wxArrayString::Add(const wxString& str)
+size_t wxArrayString::Add(const wxString& str, size_t nInsert)
 {
   if ( m_autoSort ) {
     // insert the string at the correct position to keep the array sorted
 {
   if ( m_autoSort ) {
     // insert the string at the correct position to keep the array sorted
@@ -2141,41 +2237,49 @@ size_t wxArrayString::Add(const wxString& str)
 
     wxASSERT_MSG( lo == hi, wxT("binary search broken") );
 
 
     wxASSERT_MSG( lo == hi, wxT("binary search broken") );
 
-    Insert(str, lo);
+    Insert(str, lo, nInsert);
 
     return (size_t)lo;
   }
   else {
     wxASSERT( str.GetStringData()->IsValid() );
 
 
     return (size_t)lo;
   }
   else {
     wxASSERT( str.GetStringData()->IsValid() );
 
-    Grow();
+    Grow(nInsert);
 
 
-    // the string data must not be deleted!
-    str.GetStringData()->Lock();
-
-    // just append
-    m_pItems[m_nCount] = (wxChar *)str.c_str(); // const_cast
+    for (size_t i = 0; i < nInsert; i++)
+    {
+        // the string data must not be deleted!
+        str.GetStringData()->Lock();
 
 
-    return m_nCount++;
+        // just append
+        m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast
+    }
+    size_t ret = m_nCount;
+    m_nCount += nInsert;
+    return ret;
   }
 }
 
 // add item at the given position
   }
 }
 
 // add item at the given position
-void wxArrayString::Insert(const wxString& str, size_t nIndex)
+void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
 {
   wxASSERT( str.GetStringData()->IsValid() );
 
   wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
 {
   wxASSERT( str.GetStringData()->IsValid() );
 
   wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
+  wxCHECK_RET( m_nCount <= m_nCount + nInsert,
+               wxT("array size overflow in wxArrayString::Insert") );
 
 
-  Grow();
+  Grow(nInsert);
 
 
-  memmove(&m_pItems[nIndex + 1], &m_pItems[nIndex],
+  memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],
           (m_nCount - nIndex)*sizeof(wxChar *));
 
           (m_nCount - nIndex)*sizeof(wxChar *));
 
-  str.GetStringData()->Lock();
-  m_pItems[nIndex] = (wxChar *)str.c_str();
-
-  m_nCount++;
+  for (size_t i = 0; i < nInsert; i++)
+  {
+      str.GetStringData()->Lock();
+      m_pItems[nIndex + i] = (wxChar *)str.c_str();
+  }
+  m_nCount += nInsert;
 }
 
 // expand the array
 }
 
 // expand the array
@@ -2189,16 +2293,19 @@ void wxArrayString::SetCount(size_t count)
 }
 
 // removes item from array (by index)
 }
 
 // removes item from array (by index)
-void wxArrayString::Remove(size_t nIndex)
+void wxArrayString::Remove(size_t nIndex, size_t nRemove)
 {
 {
-  wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Remove") );
+  wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") );
+  wxCHECK_RET( nIndex + nRemove <= m_nCount,
+               wxT("removing too many elements in wxArrayString::Remove") );
 
   // release our lock
 
   // release our lock
-  Item(nIndex).GetStringData()->Unlock();
+  for (size_t i = 0; i < nRemove; i++)
+      Item(nIndex + i).GetStringData()->Unlock();
 
 
-  memmove(&m_pItems[nIndex], &m_pItems[nIndex + 1],
-          (m_nCount - nIndex - 1)*sizeof(wxChar *));
-  m_nCount--;
+  memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],
+          (m_nCount - nIndex - nRemove)*sizeof(wxChar *));
+  m_nCount -= nRemove;
 }
 
 // removes item from array (by value)
 }
 
 // removes item from array (by value)