]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/string.h
use different strings for wchar_t and UTF-8-based Unicode builds
[wxWidgets.git] / include / wx / string.h
index c5283522d57be2d9b25e3fee888ec3bd9e7f9618..0a72bfe3206dacfb33d94b37044935577a9cfc1f 100644 (file)
@@ -65,6 +65,11 @@ class WXDLLIMPEXP_FWD_BASE wxString;
     #define WXWIN_COMPATIBILITY_STRING_PTR_AS_ITER 1
 #endif
 
+namespace wxPrivate
+{
+    template <typename T> struct wxStringAsBufHelper;
+}
+
 // ---------------------------------------------------------------------------
 // macros
 // ---------------------------------------------------------------------------
@@ -953,8 +958,11 @@ public:
   wxString(const wxWCharBuffer& buf)
     { assign(buf.data()); } // FIXME-UTF8: fix for embedded NUL and buffer length
 
+    // NB: this version uses m_impl.c_str() to force making a copy of the
+    //     string, so that "wxString(str.c_str())" idiom for passing strings
+    //     between threads works
   wxString(const wxCStrData& cstr)
-      : m_impl(cstr.AsString().m_impl) { }
+      : m_impl(cstr.AsString().m_impl.c_str()) { }
 
     // as we provide both ctors with this signature for both char and unsigned
     // char string, we need to provide one for wxCStrData to resolve ambiguity
@@ -1014,6 +1022,13 @@ public:
   #endif
 #endif // wxUSE_STL
 
+  wxString Clone() const
+  {
+      // make a deep copy of the string, i.e. the returned string will have
+      // ref count = 1 with refcounted implementation
+      return wxString::FromImpl(wxStringImpl(m_impl.c_str(), m_impl.length()));
+  }
+
   // first valid index position
   const_iterator begin() const { return const_iterator(this, m_impl.begin()); }
   iterator begin() { return iterator(this, m_impl.begin()); }
@@ -1201,6 +1216,30 @@ public:
         { return mb_str(conv); }
     wxWritableWCharBuffer wchar_str() const { return wc_str(); }
 
+    // conversion to the buffer of the given type T (= char or wchar_t) and
+    // also optionally return the buffer length
+    //
+    // this is mostly/only useful for the template functions
+    //
+    // FIXME-VC6: the second argument only exists for VC6 which doesn't support
+    //            explicit template function selection, do not use it unless
+    //            you must support VC6!
+    template <typename T>
+    wxCharTypeBuffer<T> tchar_str(size_t *len = NULL,
+                                  T * WXUNUSED(dummy) = NULL) const
+    {
+#if wxUSE_UNICODE
+        // we need a helper dispatcher depending on type
+        return wxPrivate::wxStringAsBufHelper<T>::Get(*this, len);
+#else // ANSI
+        // T can only be char in ANSI build
+        if ( len )
+            *len = length();
+
+        return wxCharTypeBuffer<T>::CreateNonOwned(wx_str());
+#endif // Unicode build kind
+    }
+
     // conversion to/from plain (i.e. 7 bit) ASCII: this is useful for
     // converting numbers or strings which are certain not to contain special
     // chars (typically system functions, X atoms, environment variables etc.)
@@ -1229,7 +1268,7 @@ public:
 
     // conversion to/from UTF-8:
 #if wxUSE_UNICODE_UTF8
-    static wxString FromUTF8(const char *utf8)
+    static wxString FromUTF8Unchecked(const char *utf8)
     {
       if ( !utf8 )
           return wxEmptyString;
@@ -1237,23 +1276,51 @@ public:
       wxASSERT( wxStringOperations::IsValidUtf8String(utf8) );
       return FromImpl(wxStringImpl(utf8));
     }
-    static wxString FromUTF8(const char *utf8, size_t len)
+    static wxString FromUTF8Unchecked(const char *utf8, size_t len)
     {
       if ( !utf8 )
           return wxEmptyString;
       if ( len == npos )
-          return FromUTF8(utf8);
+          return FromUTF8Unchecked(utf8);
 
       wxASSERT( wxStringOperations::IsValidUtf8String(utf8, len) );
       return FromImpl(wxStringImpl(utf8, len));
     }
+
+    static wxString FromUTF8(const char *utf8)
+    {
+        if ( !utf8 || !wxStringOperations::IsValidUtf8String(utf8) )
+            return "";
+
+        return FromImpl(wxStringImpl(utf8));
+    }
+    static wxString FromUTF8(const char *utf8, size_t len)
+    {
+        if ( len == npos )
+            return FromUTF8(utf8);
+
+        if ( !utf8 || !wxStringOperations::IsValidUtf8String(utf8, len) )
+            return "";
+
+        return FromImpl(wxStringImpl(utf8, len));
+    }
+
     const char* utf8_str() const { return wx_str(); }
     const char* ToUTF8() const { return wx_str(); }
+
+    // this function exists in UTF-8 build only and returns the length of the
+    // internal UTF-8 representation
+    size_t utf8_length() const { return m_impl.length(); }
 #elif wxUSE_UNICODE_WCHAR
-    static wxString FromUTF8(const char *utf8)
-      { return wxString(utf8, wxMBConvUTF8()); }
-    static wxString FromUTF8(const char *utf8, size_t len)
+    static wxString FromUTF8(const char *utf8, size_t len = npos)
       { return wxString(utf8, wxMBConvUTF8(), len); }
+    static wxString FromUTF8Unchecked(const char *utf8, size_t len = npos)
+    {
+        const wxString s(utf8, wxMBConvUTF8(), len);
+        wxASSERT_MSG( !utf8 || !*utf8 || !s.empty(),
+                      "string must be valid UTF-8" );
+        return s;
+    }
     const wxCharBuffer utf8_str() const { return mb_str(wxMBConvUTF8()); }
     const wxCharBuffer ToUTF8() const { return utf8_str(); }
 #else // ANSI
@@ -1261,9 +1328,20 @@ public:
       { return wxString(wxMBConvUTF8().cMB2WC(utf8)); }
     static wxString FromUTF8(const char *utf8, size_t len)
     {
-      size_t wlen;
-      wxWCharBuffer buf(wxMBConvUTF8().cMB2WC(utf8, len == npos ? wxNO_LEN : len, &wlen));
-      return wxString(buf.data(), wlen);
+        size_t wlen;
+        wxWCharBuffer buf(wxMBConvUTF8().cMB2WC(utf8, len == npos ? wxNO_LEN : len, &wlen));
+        return wxString(buf.data(), wlen);
+    }
+    static wxString FromUTF8Unchecked(const char *utf8, size_t len = npos)
+    {
+        size_t wlen;
+        wxWCharBuffer buf(wxMBConvUTF8().cMB2WC(utf8,
+                                                len == npos ? wxNO_LEN : len,
+                                                &wlen));
+        wxASSERT_MSG( !utf8 || !*utf8 || wlen,
+                      "string must be valid UTF-8" );
+
+        return wxString(buf.data(), wlen);
     }
     const wxCharBuffer utf8_str() const
       { return wxMBConvUTF8().cWC2MB(wc_str()); }
@@ -1308,7 +1386,7 @@ public:
     const wxWX2MBbuf mbc_str() const { return mb_str(*wxConvCurrent); }
 
 #if wxUSE_UNICODE_WCHAR
-    const wxChar* wc_str() const { return wx_str(); }
+    const wchar_t* wc_str() const { return wx_str(); }
 #elif wxUSE_UNICODE_UTF8
     const wxWCharBuffer wc_str() const;
 #endif
@@ -1326,7 +1404,7 @@ public:
     const wxChar* mb_str() const { return wx_str(); }
 
     // for compatibility with wxUSE_UNICODE version
-    const wxChar* mb_str(const wxMBConv& WXUNUSED(conv)) const { return wx_str(); }
+    const char* mb_str(const wxMBConv& WXUNUSED(conv)) const { return wx_str(); }
 
     const wxWX2MBbuf mbc_str() const { return mb_str(); }
 
@@ -1336,6 +1414,15 @@ public:
     const wxCharBuffer fn_str() const { return wxConvFile.cWC2WX( wc_str( wxConvLibc ) ); }
 #endif // Unicode/ANSI
 
+#if wxUSE_UNICODE_UTF8
+    const wxWCharBuffer t_str() const { return wc_str(); }
+#elif wxUSE_UNICODE_WCHAR
+    const wchar_t* t_str() const { return wx_str(); }
+#else
+    const char* t_str() const { return wx_str(); }
+#endif 
+
+
   // overloaded assignment
     // from another wxString
   wxString& operator=(const wxString& stringSrc)
@@ -2705,6 +2792,67 @@ inline wxString operator+(wchar_t ch, const wxString& string)
 
 #define wxGetEmptyString() wxString()
 
+// ----------------------------------------------------------------------------
+// helper functions which couldn't be defined inline
+// ----------------------------------------------------------------------------
+
+namespace wxPrivate
+{
+
+#if wxUSE_UNICODE_WCHAR
+
+template <>
+struct wxStringAsBufHelper<char>
+{
+    static wxCharBuffer Get(const wxString& s, size_t *len)
+    {
+        wxCharBuffer buf(s.mb_str());
+        if ( len )
+            *len = buf ? strlen(buf) : 0;
+        return buf;
+    }
+};
+
+template <>
+struct wxStringAsBufHelper<wchar_t>
+{
+    static wxWCharBuffer Get(const wxString& s, size_t *len)
+    {
+        if ( len )
+            *len = s.length();
+        return wxWCharBuffer::CreateNonOwned(s.wx_str());
+    }
+};
+
+#elif wxUSE_UNICODE_UTF8
+
+template <>
+struct wxStringAsBufHelper<char>
+{
+    static wxCharBuffer Get(const wxString& s, size_t *len)
+    {
+        if ( len )
+            *len = s.utf8_length();
+        return wxCharBuffer::CreateNonOwned(s.wx_str());
+    }
+};
+
+template <>
+struct wxStringAsBufHelper<wchar_t>
+{
+    static wxWCharBuffer Get(const wxString& s, size_t *len)
+    {
+        wxWCharBuffer wbuf(s.wc_str());
+        if ( len )
+            *len = wxWcslen(wbuf);
+        return wbuf;
+    }
+};
+
+#endif // Unicode build kind
+
+} // namespace wxPrivate
+
 // ----------------------------------------------------------------------------
 // wxStringBuffer: a tiny class allowing to get a writable pointer into string
 // ----------------------------------------------------------------------------
@@ -2772,8 +2920,30 @@ public:
 
     wxStringTypeBufferBase(wxString& str, size_t lenWanted = 1024)
         : m_str(str), m_buf(lenWanted)
-        { }
-
+    {
+        // for compatibility with old wxStringBuffer which provided direct
+        // access to wxString internal buffer, initialize ourselves with the
+        // string initial contents
+
+        // FIXME-VC6: remove the ugly (CharType *)NULL and use normal
+        //            tchar_str<CharType>
+        size_t len;
+        const wxCharTypeBuffer<CharType> buf(str.tchar_str(&len, (CharType *)NULL));
+        if ( buf )
+        {
+            if ( len > lenWanted )
+            {
+                // in this case there is not enough space for terminating NUL,
+                // ensure that we still put it there
+                m_buf.data()[lenWanted] = 0;
+                len = lenWanted - 1;
+            }
+
+            memcpy(m_buf.data(), buf, (len + 1)*sizeof(CharType));
+        }
+        //else: conversion failed, this can happen when trying to get Unicode
+        //      string contents into a char string
+    }
 
     operator CharType*() { return m_buf.data(); }
 
@@ -2784,22 +2954,25 @@ protected:
 
 template<typename T>
 class WXDLLIMPEXP_BASE wxStringTypeBufferLengthBase
+    : public wxStringTypeBufferBase<T>
 {
 public:
-    typedef T CharType;
-
     wxStringTypeBufferLengthBase(wxString& str, size_t lenWanted = 1024)
-        : m_str(str), m_buf(lenWanted), m_len(0), m_lenSet(false)
+        : wxStringTypeBufferBase<T>(str, lenWanted),
+          m_len(0),
+          m_lenSet(false)
         { }
 
-    operator CharType*() { return m_buf.data(); }
+    ~wxStringTypeBufferLengthBase()
+    {
+        wxASSERT_MSG( this->m_lenSet, "forgot to call SetLength()" );
+    }
+
     void SetLength(size_t length) { m_len = length; m_lenSet = true; }
 
 protected:
-    wxString& m_str;
-    wxCharTypeBuffer<CharType> m_buf;
-    size_t        m_len;
-    bool          m_lenSet;
+    size_t m_len;
+    bool m_lenSet;
 };
 
 template<typename T>
@@ -2807,7 +2980,9 @@ class wxStringTypeBuffer : public wxStringTypeBufferBase<T>
 {
 public:
     wxStringTypeBuffer(wxString& str, size_t lenWanted = 1024)
-        : wxStringTypeBufferBase<T>(str, lenWanted) {}
+        : wxStringTypeBufferBase<T>(str, lenWanted)
+        { }
+
     ~wxStringTypeBuffer()
     {
         this->m_str.assign(this->m_buf.data());
@@ -2821,11 +2996,11 @@ class wxStringTypeBufferLength : public wxStringTypeBufferLengthBase<T>
 {
 public:
     wxStringTypeBufferLength(wxString& str, size_t lenWanted = 1024)
-        : wxStringTypeBufferLengthBase<T>(str, lenWanted) {}
+        : wxStringTypeBufferLengthBase<T>(str, lenWanted)
+        { }
 
     ~wxStringTypeBufferLength()
     {
-        wxASSERT(this->m_lenSet);
         this->m_str.assign(this->m_buf.data(), this->m_len);
     }
 
@@ -2859,12 +3034,12 @@ public:
 
     ~wxStringInternalBufferLength()
     {
-        wxASSERT(m_lenSet);
         m_str.m_impl.assign(m_buf.data(), m_len);
     }
 
     DECLARE_NO_COPY_CLASS(wxStringInternalBufferLength)
 };
+
 #endif // wxUSE_STL_BASED_WXSTRING