X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/de4983f3236c2043479abb21857aca958a7b61f0..737e53350cffa493e72691fd965ebd60d5349bf2:/include/wx/string.h diff --git a/include/wx/string.h b/include/wx/string.h index ebd2f0f774..9ab7f3f10a 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -209,7 +209,7 @@ inline int Stricmp(const char *psz1, const char *psz2) // Lightweight object returned by wxString::c_str() and implicitly convertible // to either const char* or const wchar_t*. -class WXDLLIMPEXP_BASE wxCStrData +class wxCStrData { private: // Ctors; for internal use by wxString and wxCStrData only @@ -246,8 +246,15 @@ public: operator const void*() const { return AsChar(); } // returns buffers that are valid as long as the associated wxString exists - inline const wxScopedCharBuffer AsCharBuf() const; - inline const wxScopedWCharBuffer AsWCharBuf() const; + const wxScopedCharBuffer AsCharBuf() const + { + return wxScopedCharBuffer::CreateNonOwned(AsChar()); + } + + const wxScopedWCharBuffer AsWCharBuf() const + { + return wxScopedWCharBuffer::CreateNonOwned(AsWChar()); + } inline wxString AsString() const; @@ -281,7 +288,7 @@ public: wxCStrData operator-(ptrdiff_t n) const { wxASSERT_MSG( n <= (ptrdiff_t)m_offset, - _T("attempt to construct address before the beginning of the string") ); + wxT("attempt to construct address before the beginning of the string") ); return wxCStrData(m_str, m_offset - n, m_owned); } @@ -401,6 +408,7 @@ protected: #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN // "non dll-interface class 'wxStringPrintfMixin' used as base interface // for dll-interface class 'wxString'" -- this is OK in our case + #pragma warning (push) #pragma warning (disable:4275) #endif @@ -997,8 +1005,8 @@ public: { return iterator(str(), wxStringOperations::AddToIter(m_cur, -n)); } private: - iterator(wxString *str, underlying_iterator ptr) - : m_cur(ptr), m_node(str, &m_cur) {} + iterator(wxString *wxstr, underlying_iterator ptr) + : m_cur(ptr), m_node(wxstr, &m_cur) {} wxString* str() const { return const_cast(m_node.m_str); } @@ -1042,8 +1050,8 @@ public: private: // for internal wxString use only: - const_iterator(const wxString *str, underlying_iterator ptr) - : m_cur(ptr), m_node(str, &m_cur) {} + const_iterator(const wxString *wxstr, underlying_iterator ptr) + : m_cur(ptr), m_node(wxstr, &m_cur) {} const wxString* str() const { return m_node.m_str; } @@ -1277,9 +1285,9 @@ public: { assign(pwz, nLength); } wxString(const wxScopedCharBuffer& buf) - { assign(buf.data()); } // FIXME-UTF8: fix for embedded NUL and buffer length + { assign(buf.data(), buf.length()); } wxString(const wxScopedWCharBuffer& buf) - { assign(buf.data()); } // FIXME-UTF8: fix for embedded NUL and buffer length + { assign(buf.data(), buf.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 @@ -1341,8 +1349,10 @@ public: #else // wxStringImpl is either not std::string or needs conversion operator wxStdWideString() const - // FIXME-UTF8: broken for embedded NULs - { return wxStdWideString(wc_str()); } + { + wxScopedWCharBuffer buf(wc_str()); + return wxStdWideString(buf.data(), buf.length()); + } #endif #if (!wxUSE_UNICODE || wxUSE_UTF8_LOCALE_ONLY) && wxUSE_STL_BASED_WXSTRING @@ -1351,8 +1361,10 @@ public: #else // wxStringImpl is either not std::string or needs conversion operator std::string() const - // FIXME-UTF8: broken for embedded NULs - { return std::string(mb_str()); } + { + wxScopedCharBuffer buf(mb_str()); + return std::string(buf.data(), buf.length()); + } #endif #endif // wxUSE_STL @@ -1501,14 +1513,14 @@ public: // get last character wxUniChar Last() const { - wxASSERT_MSG( !empty(), _T("wxString: index out of bounds") ); + wxASSERT_MSG( !empty(), wxT("wxString: index out of bounds") ); return *rbegin(); } // get writable last character wxUniCharRef Last() { - wxASSERT_MSG( !empty(), _T("wxString: index out of bounds") ); + wxASSERT_MSG( !empty(), wxT("wxString: index out of bounds") ); return *rbegin(); } @@ -1637,7 +1649,7 @@ public: if ( len ) *len = length(); - return wxCharTypeBuffer::CreateNonOwned(wx_str()); + return wxCharTypeBuffer::CreateNonOwned(wx_str(), length()); #endif // Unicode build kind } @@ -1706,8 +1718,8 @@ public: return FromImpl(wxStringImpl(utf8, len)); } - const char* utf8_str() const { return wx_str(); } - const char* ToUTF8() const { return wx_str(); } + const wxScopedCharBuffer utf8_str() const + { return wxCharBuffer::CreateNonOwned(m_impl.c_str(), m_impl.length()); } // this function exists in UTF-8 build only and returns the length of the // internal UTF-8 representation @@ -1723,7 +1735,6 @@ public: return s; } const wxScopedCharBuffer utf8_str() const { return mb_str(wxMBConvUTF8()); } - const wxScopedCharBuffer ToUTF8() const { return utf8_str(); } #else // ANSI static wxString FromUTF8(const char *utf8) { return wxString(wxMBConvUTF8().cMB2WC(utf8)); } @@ -1752,9 +1763,10 @@ public: } const wxScopedCharBuffer utf8_str() const { return wxMBConvUTF8().cWC2MB(wc_str()); } - const wxScopedCharBuffer ToUTF8() const { return utf8_str(); } #endif + const wxScopedCharBuffer ToUTF8() const { return utf8_str(); } + // functions for storing binary data in wxString: #if wxUSE_UNICODE static wxString From8BitData(const char *data, size_t len) @@ -1782,21 +1794,34 @@ public: // accepting the file names. The return value is always the same, but the // type differs because a function may either return pointer to the buffer // directly or have to use intermediate buffer for translation. + #if wxUSE_UNICODE + // this is an optimization: even though using mb_str(wxConvLibc) does the + // same thing (i.e. returns pointer to internal representation as locale is + // always an UTF-8 one) in wxUSE_UTF8_LOCALE_ONLY case, we can avoid the + // extra checks and the temporary buffer construction by providing a + // separate mb_str() overload #if wxUSE_UTF8_LOCALE_ONLY const char* mb_str() const { return wx_str(); } - const wxScopedCharBuffer mb_str(const wxMBConv& conv) const; -#else - const wxScopedCharBuffer mb_str(const wxMBConv& conv = wxConvLibc) const; -#endif + const wxScopedCharBuffer mb_str(const wxMBConv& conv) const + { + return AsCharBuf(conv); + } +#else // !wxUSE_UTF8_LOCALE_ONLY + const wxScopedCharBuffer mb_str(const wxMBConv& conv = wxConvLibc) const + { + return AsCharBuf(conv); + } +#endif // wxUSE_UTF8_LOCALE_ONLY/!wxUSE_UTF8_LOCALE_ONLY const wxWX2MBbuf mbc_str() const { return mb_str(*wxConvCurrent); } #if wxUSE_UNICODE_WCHAR const wchar_t* wc_str() const { return wx_str(); } #elif wxUSE_UNICODE_UTF8 - const wxScopedWCharBuffer wc_str() const; + const wxScopedWCharBuffer wc_str() const + { return AsWCharBuf(wxMBConvStrictUTF8()); } #endif // for compatibility with !wxUSE_UNICODE version const wxWX2WCbuf wc_str(const wxMBConv& WXUNUSED(conv)) const @@ -1809,16 +1834,16 @@ public: #endif // wxMBFILES/!wxMBFILES #else // ANSI - const wxChar* mb_str() const { return wx_str(); } + const char* mb_str() const { return wx_str(); } // for compatibility with wxUSE_UNICODE version const char* mb_str(const wxMBConv& WXUNUSED(conv)) const { return wx_str(); } const wxWX2MBbuf mbc_str() const { return mb_str(); } -#if wxUSE_WCHAR_T - const wxScopedWCharBuffer wc_str(const wxMBConv& conv = wxConvLibc) const; -#endif // wxUSE_WCHAR_T + const wxScopedWCharBuffer wc_str(const wxMBConv& conv = wxConvLibc) const + { return AsWCharBuf(conv); } + const wxScopedCharBuffer fn_str() const { return wxConvFile.cWC2WX( wc_str( wxConvLibc ) ); } #endif // Unicode/ANSI @@ -1921,10 +1946,10 @@ public: // from wxScopedWCharBuffer wxString& operator=(const wxScopedWCharBuffer& s) - { return operator=(s.data()); } // FIXME-UTF8: fix for embedded NULs + { return assign(s); } // from wxScopedCharBuffer wxString& operator=(const wxScopedCharBuffer& s) - { return operator=(s.data()); } // FIXME-UTF8: fix for embedded NULs + { return assign(s); } // string concatenation // in place concatenation @@ -1938,7 +1963,7 @@ public: { #if WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 wxASSERT_MSG( s.IsValid(), - _T("did you forget to call UngetWriteBuf()?") ); + wxT("did you forget to call UngetWriteBuf()?") ); #endif append(s); @@ -1960,9 +1985,9 @@ public: // string += buffer (i.e. from wxGetString) wxString& operator<<(const wxScopedWCharBuffer& s) - { return operator<<((const wchar_t *)s); } + { return append(s); } wxString& operator<<(const wxScopedCharBuffer& s) - { return operator<<((const char *)s); } + { return append(s); } // string += C string wxString& Append(const wxString& s) @@ -2032,36 +2057,36 @@ public: // stream-like functions // insert an int into string wxString& operator<<(int i) - { return (*this) << Format(_T("%d"), i); } + { return (*this) << Format(wxT("%d"), i); } // insert an unsigned int into string wxString& operator<<(unsigned int ui) - { return (*this) << Format(_T("%u"), ui); } + { return (*this) << Format(wxT("%u"), ui); } // insert a long into string wxString& operator<<(long l) - { return (*this) << Format(_T("%ld"), l); } + { return (*this) << Format(wxT("%ld"), l); } // insert an unsigned long into string wxString& operator<<(unsigned long ul) - { return (*this) << Format(_T("%lu"), ul); } + { return (*this) << Format(wxT("%lu"), ul); } #if defined wxLongLong_t && !defined wxLongLongIsLong // insert a long long if they exist and aren't longs wxString& operator<<(wxLongLong_t ll) { - const wxChar *fmt = _T("%") wxLongLongFmtSpec _T("d"); + const wxChar *fmt = wxT("%") wxLongLongFmtSpec wxT("d"); return (*this) << Format(fmt, ll); } // insert an unsigned long long wxString& operator<<(wxULongLong_t ull) { - const wxChar *fmt = _T("%") wxLongLongFmtSpec _T("u"); + const wxChar *fmt = wxT("%") wxLongLongFmtSpec wxT("u"); return (*this) << Format(fmt , ull); } #endif // wxLongLong_t && !wxLongLongIsLong // insert a float into string wxString& operator<<(float f) - { return (*this) << Format(_T("%f"), f); } + { return (*this) << Format(wxT("%f"), f); } // insert a double into string wxString& operator<<(double d) - { return (*this) << Format(_T("%g"), d); } + { return (*this) << Format(wxT("%g"), d); } // string comparison // case-sensitive comparison (returns a value < 0, = 0 or > 0) @@ -2248,7 +2273,7 @@ public: // convert to a double bool ToCDouble(double *val) const; #endif - + #ifndef wxNEEDS_WXSTRING_PRINTF_MIXIN // formatted input/output // as sprintf(), returns the number of characters written or < 0 on error @@ -2403,7 +2428,7 @@ public: CreateConstIterator(last).impl()) { wxASSERT_MSG( first.m_str == last.m_str, - _T("pointers must be into the same string") ); + wxT("pointers must be into the same string") ); } #endif // WXWIN_COMPATIBILITY_STRING_PTR_AS_ITER @@ -2464,9 +2489,9 @@ public: wxString& append(const wxCStrData& str) { return append(str.AsString()); } wxString& append(const wxScopedCharBuffer& str) - { return append(str.data()); } + { return append(str.data(), str.length()); } wxString& append(const wxScopedWCharBuffer& str) - { return append(str.data()); } + { return append(str.data(), str.length()); } wxString& append(const wxCStrData& str, size_t n) { return append(str.AsString(), 0, n); } wxString& append(const wxScopedCharBuffer& str, size_t n) @@ -2596,9 +2621,9 @@ public: wxString& assign(const wxCStrData& str) { return assign(str.AsString()); } wxString& assign(const wxScopedCharBuffer& str) - { return assign(str.data()); } + { return assign(str.data(), str.length()); } wxString& assign(const wxScopedWCharBuffer& str) - { return assign(str.data()); } + { return assign(str.data(), str.length()); } wxString& assign(const wxCStrData& str, size_t len) { return assign(str.AsString(), len); } wxString& assign(const wxScopedCharBuffer& str, size_t len) @@ -3352,9 +3377,9 @@ public: return *this; } wxString& operator+=(const wxScopedCharBuffer& s) - { return operator+=(s.data()); } + { return append(s); } wxString& operator+=(const wxScopedWCharBuffer& s) - { return operator+=(s.data()); } + { return append(s); } // string += char wxString& operator+=(wxUniChar ch) { @@ -3417,36 +3442,117 @@ private: wxStringImpl m_impl; // buffers for compatibility conversion from (char*)c_str() and - // (wchar_t*)c_str(): - // FIXME-UTF8: bechmark various approaches to keeping compatibility buffers + // (wchar_t*)c_str(): the pointers returned by these functions should remain + // valid until the string itself is modified for compatibility with the + // existing code and consistency with std::string::c_str() so returning a + // temporary buffer won't do and we need to cache the conversion results + + // TODO-UTF8: benchmark various approaches to keeping compatibility buffers template struct ConvertedBuffer { - ConvertedBuffer() : m_buf(NULL) {} + // notice that there is no need to initialize m_len here as it's unused + // as long as m_str is NULL + ConvertedBuffer() : m_str(NULL) {} ~ConvertedBuffer() - { free(m_buf); } + { free(m_str); } - operator T*() const { return m_buf; } + bool Extend(size_t len) + { + // add extra 1 for the trailing NUL + void * const str = realloc(m_str, sizeof(T)*(len + 1)); + if ( !str ) + return false; + + m_str = static_cast(str); + m_len = len; - ConvertedBuffer& operator=(T *str) + return true; + } + + const wxScopedCharTypeBuffer AsScopedBuffer() const { - free(m_buf); - m_buf = str; - return *this; + return wxScopedCharTypeBuffer::CreateNonOwned(m_str, m_len); } - T *m_buf; + T *m_str; // pointer to the string data + size_t m_len; // length, not size, i.e. in chars and without last NUL }; -#if wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY + + +#if wxUSE_UNICODE + // common mb_str() and wxCStrData::AsChar() helper: performs the conversion + // and returns either m_convertedToChar.m_str (in which case its m_len is + // also updated) or NULL if it failed + // + // there is an important exception: in wxUSE_UNICODE_UTF8 build if conv is a + // UTF-8 one, we return m_impl.c_str() directly, without doing any conversion + // as optimization and so the caller needs to check for this before using + // m_convertedToChar + // + // NB: AsChar() returns char* in any build, unlike mb_str() + const char *AsChar(const wxMBConv& conv) const; + + // mb_str() implementation helper + wxScopedCharBuffer AsCharBuf(const wxMBConv& conv) const + { +#if wxUSE_UNICODE_UTF8 + // avoid conversion if we can + if ( conv.IsUTF8() ) + { + return wxScopedCharBuffer::CreateNonOwned(m_impl.c_str(), + m_impl.length()); + } +#endif // wxUSE_UNICODE_UTF8 + + // call this solely in order to fill in m_convertedToChar as AsChar() + // updates it as a side effect: this is a bit ugly but it's a completely + // internal function so the users of this class shouldn't care or know + // about it and doing it like this, i.e. having a separate AsChar(), + // allows us to avoid the creation and destruction of a temporary buffer + // when using wxCStrData without duplicating any code + if ( !AsChar(conv) ) + { + // although it would be probably more correct to return NULL buffer + // from here if the conversion fails, a lot of existing code doesn't + // expect mb_str() (or wc_str()) to ever return NULL so return an + // empty string otherwise to avoid crashes in it + // + // also, some existing code does check for the conversion success and + // so asserting here would be bad too -- even if it does mean that + // silently losing data is possible for badly written code + return wxScopedCharBuffer::CreateNonOwned("", 0); + } + + return m_convertedToChar.AsScopedBuffer(); + } + ConvertedBuffer m_convertedToChar; -#endif +#endif // !wxUSE_UNICODE + #if !wxUSE_UNICODE_WCHAR + // common wc_str() and wxCStrData::AsWChar() helper for both UTF-8 and ANSI + // builds: converts the string contents into m_convertedToWChar and returns + // NULL if the conversion failed (this can only happen in ANSI build) + // + // NB: AsWChar() returns wchar_t* in any build, unlike wc_str() + const wchar_t *AsWChar(const wxMBConv& conv) const; + + // wc_str() implementation helper + wxScopedWCharBuffer AsWCharBuf(const wxMBConv& conv) const + { + if ( !AsWChar(conv) ) + return wxScopedWCharBuffer::CreateNonOwned(L"", 0); + + return m_convertedToWChar.AsScopedBuffer(); + } + ConvertedBuffer m_convertedToWChar; -#endif +#endif // !wxUSE_UNICODE_WCHAR #if wxUSE_UNICODE_UTF8 // FIXME-UTF8: (try to) move this elsewhere (TLS) or solve differently - // assigning to character pointer to by wxString::interator may + // assigning to character pointer to by wxString::iterator may // change the underlying wxStringImpl iterator, so we have to // keep track of all iterators and update them as necessary: struct wxStringIteratorNodeHead @@ -3471,7 +3577,7 @@ private: }; #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN - #pragma warning (default:4275) + #pragma warning (pop) #endif // string iterator operators that satisfy STL Random Access Iterator @@ -3540,9 +3646,10 @@ struct wxStringAsBufHelper { static wxScopedWCharBuffer Get(const wxString& s, size_t *len) { + const size_t length = s.length(); if ( len ) - *len = s.length(); - return wxScopedWCharBuffer::CreateNonOwned(s.wx_str()); + *len = length; + return wxScopedWCharBuffer::CreateNonOwned(s.wx_str(), length); } }; @@ -3553,9 +3660,10 @@ struct wxStringAsBufHelper { static wxScopedCharBuffer Get(const wxString& s, size_t *len) { + const size_t length = s.utf8_length(); if ( len ) - *len = s.utf8_length(); - return wxScopedCharBuffer::CreateNonOwned(s.wx_str()); + *len = length; + return wxScopedCharBuffer::CreateNonOwned(s.wx_str(), length); } }; @@ -3988,45 +4096,53 @@ inline wxCStrData::~wxCStrData() delete const_cast(m_str); // cast to silence warnings } -// simple cases for AsChar() and AsWChar(), the complicated ones are -// in string.cpp -#if wxUSE_UNICODE_WCHAR +// AsChar() and AsWChar() implementations simply forward to wxString methods + inline const wchar_t* wxCStrData::AsWChar() const { - return m_str->wx_str() + m_offset; -} -#endif // wxUSE_UNICODE_WCHAR + const wchar_t * const p = +#if wxUSE_UNICODE_WCHAR + m_str->wc_str(); +#elif wxUSE_UNICODE_UTF8 + m_str->AsWChar(wxMBConvStrictUTF8()); +#else + m_str->AsWChar(wxConvLibc); +#endif + // in Unicode build the string always has a valid Unicode representation + // and even if a conversion is needed (as in UTF8 case) it can't fail + // + // but in ANSI build the string contents might be not convertible to + // Unicode using the current locale encoding so we do need to check for + // errors #if !wxUSE_UNICODE -inline const char* wxCStrData::AsChar() const -{ - return m_str->wx_str() + m_offset; -} + if ( !p ) + { + // if conversion fails, return empty string and not NULL to avoid + // crashes in code written with either wxWidgets 2 wxString or + // std::string behaviour in mind: neither of them ever returns NULL + // from its c_str() and so we shouldn't neither + // + // notice that the same is done in AsChar() below and + // wxString::wc_str() and mb_str() for the same reasons + return L""; + } #endif // !wxUSE_UNICODE -#if wxUSE_UTF8_LOCALE_ONLY -inline const char* wxCStrData::AsChar() const -{ - return wxStringOperations::AddToIter(m_str->wx_str(), m_offset); -} -#endif // wxUSE_UTF8_LOCALE_ONLY - -inline const wxScopedCharBuffer wxCStrData::AsCharBuf() const -{ -#if !wxUSE_UNICODE - return wxScopedCharBuffer::CreateNonOwned(AsChar()); -#else - return AsString().mb_str(); -#endif + return p + m_offset; } -inline const wxScopedWCharBuffer wxCStrData::AsWCharBuf() const +inline const char* wxCStrData::AsChar() const { -#if wxUSE_UNICODE_WCHAR - return wxScopedWCharBuffer::CreateNonOwned(AsWChar()); -#else - return AsString().wc_str(); -#endif +#if wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY + const char * const p = m_str->AsChar(wxConvLibc); + if ( !p ) + return ""; +#else // !wxUSE_UNICODE || wxUSE_UTF8_LOCALE_ONLY + const char * const p = m_str->mb_str(); +#endif // wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY + + return p + m_offset; } inline wxString wxCStrData::AsString() const @@ -4049,7 +4165,7 @@ inline const wxStringCharType *wxCStrData::AsInternal() const inline wxUniChar wxCStrData::operator*() const { if ( m_str->empty() ) - return wxUniChar(_T('\0')); + return wxUniChar(wxT('\0')); else return (*m_str)[m_offset]; }