+
+ // buffer for holding temporary substring when using any of the methods
+ // that take (char*,size_t) or (wchar_t*,size_t) arguments:
+ template<typename T>
+ struct SubstrBufFromType
+ {
+ T data;
+ size_t len;
+
+ SubstrBufFromType(const T& data_, size_t len_)
+ : data(data_), len(len_)
+ {
+ wxASSERT_MSG( len != npos, "must have real length" );
+ }
+ };
+
+#if wxUSE_UNICODE_UTF8
+ // even char* -> char* needs conversion, from locale charset to UTF-8
+ typedef SubstrBufFromType<wxCharBuffer> SubstrBufFromWC;
+ typedef SubstrBufFromType<wxCharBuffer> SubstrBufFromMB;
+#elif wxUSE_UNICODE_WCHAR
+ typedef SubstrBufFromType<const wchar_t*> SubstrBufFromWC;
+ typedef SubstrBufFromType<wxWCharBuffer> SubstrBufFromMB;
+#else
+ typedef SubstrBufFromType<const char*> SubstrBufFromMB;
+ typedef SubstrBufFromType<wxCharBuffer> SubstrBufFromWC;
+#endif
+
+
+ // Functions implementing primitive operations on string data; wxString
+ // methods and iterators are implemented in terms of it. The differences
+ // between UTF-8 and wchar_t* representations of the string are mostly
+ // contained here.
+
+#if wxUSE_UNICODE_UTF8
+ static SubstrBufFromMB ConvertStr(const char *psz, size_t nLength,
+ const wxMBConv& conv);
+ static SubstrBufFromWC ConvertStr(const wchar_t *pwz, size_t nLength,
+ const wxMBConv& conv);
+#elif wxUSE_UNICODE_WCHAR
+ static SubstrBufFromMB ConvertStr(const char *psz, size_t nLength,
+ const wxMBConv& conv);
+#else
+ static SubstrBufFromWC ConvertStr(const wchar_t *pwz, size_t nLength,
+ const wxMBConv& conv);
+#endif
+
+#if !wxUSE_UNICODE_UTF8 // wxUSE_UNICODE_WCHAR or !wxUSE_UNICODE
+ // returns C string encoded as the implementation expects:
+ #if wxUSE_UNICODE
+ static const wchar_t* ImplStr(const wchar_t* str)
+ { return str ? str : wxT(""); }
+ static const SubstrBufFromWC ImplStr(const wchar_t* str, size_t n)
+ { return SubstrBufFromWC(str, (str && n == npos) ? wxWcslen(str) : n); }
+ static wxWCharBuffer ImplStr(const char* str,
+ const wxMBConv& conv = wxConvLibc)
+ { return ConvertStr(str, npos, conv).data; }
+ static SubstrBufFromMB ImplStr(const char* str, size_t n,
+ const wxMBConv& conv = wxConvLibc)
+ { return ConvertStr(str, n, conv); }
+ #else
+ static const char* ImplStr(const char* str,
+ const wxMBConv& WXUNUSED(conv) = wxConvLibc)
+ { return str ? str : ""; }
+ static const SubstrBufFromMB ImplStr(const char* str, size_t n,
+ const wxMBConv& WXUNUSED(conv) = wxConvLibc)
+ { return SubstrBufFromMB(str, (str && n == npos) ? wxStrlen(str) : n); }
+ static wxCharBuffer ImplStr(const wchar_t* str)
+ { return ConvertStr(str, npos, wxConvLibc).data; }
+ static SubstrBufFromWC ImplStr(const wchar_t* str, size_t n)
+ { return ConvertStr(str, n, wxConvLibc); }
+ #endif
+
+ // translates position index in wxString to/from index in underlying
+ // wxStringImpl:
+ static size_t PosToImpl(size_t pos) { return pos; }
+ static void PosLenToImpl(size_t pos, size_t len,
+ size_t *implPos, size_t *implLen)
+ { *implPos = pos; *implLen = len; }
+ static size_t LenToImpl(size_t len) { return len; }
+ static size_t PosFromImpl(size_t pos) { return pos; }
+
+#else // wxUSE_UNICODE_UTF8
+
+ static wxCharBuffer ImplStr(const char* str,
+ const wxMBConv& conv = wxConvLibc)
+ { return ConvertStr(str, npos, conv).data; }
+ static SubstrBufFromMB ImplStr(const char* str, size_t n,
+ const wxMBConv& conv = wxConvLibc)
+ { return ConvertStr(str, n, conv); }
+
+ static wxCharBuffer ImplStr(const wchar_t* str)
+ { return ConvertStr(str, npos, wxMBConvUTF8()).data; }
+ static SubstrBufFromWC ImplStr(const wchar_t* str, size_t n)
+ { return ConvertStr(str, n, wxMBConvUTF8()); }
+
+ size_t PosToImpl(size_t pos) const
+ {
+ if ( pos == 0 || pos == npos )
+ return pos;
+ else
+ return (begin() + pos).impl() - m_impl.begin();
+ }
+
+ void PosLenToImpl(size_t pos, size_t len, size_t *implPos, size_t *implLen) const;
+
+ size_t LenToImpl(size_t len) const
+ {
+ size_t pos, len2;
+ PosLenToImpl(0, len, &pos, &len2);
+ return len2;
+ }
+
+ size_t PosFromImpl(size_t pos) const
+ {
+ if ( pos == 0 || pos == npos )
+ return pos;
+ else
+ return const_iterator(this, m_impl.begin() + pos) - begin();
+ }
+#endif // !wxUSE_UNICODE_UTF8/wxUSE_UNICODE_UTF8
+
+public:
+ // standard types
+ typedef wxUniChar value_type;
+ typedef wxUniChar char_type;
+ typedef wxUniCharRef reference;
+ typedef wxChar* pointer;
+ typedef const wxChar* const_pointer;
+
+ typedef size_t size_type;
+ typedef wxUniChar const_reference;
+
+#if wxUSE_STL
+ #if wxUSE_UNICODE_UTF8
+ // random access is not O(1), as required by Random Access Iterator
+ #define WX_STR_ITERATOR_TAG std::bidirectional_iterator_tag
+ #else
+ #define WX_STR_ITERATOR_TAG std::random_access_iterator_tag
+ #endif
+#else
+ #define WX_STR_ITERATOR_TAG void /* dummy type */
+#endif
+
+ #define WX_STR_ITERATOR_IMPL(iterator_name, pointer_type, reference_type) \
+ private: \
+ typedef wxStringImpl::iterator_name underlying_iterator; \
+ public: \
+ typedef WX_STR_ITERATOR_TAG iterator_category; \
+ typedef wxUniChar value_type; \
+ typedef int difference_type; \
+ typedef reference_type reference; \
+ typedef pointer_type pointer; \
+ \
+ reference operator[](size_t n) const { return *(*this + n); } \
+ \
+ iterator_name& operator++() \
+ { wxStringOperations::IncIter(m_cur); return *this; } \
+ iterator_name& operator--() \
+ { wxStringOperations::DecIter(m_cur); return *this; } \
+ iterator_name operator++(int) \
+ { \
+ iterator_name tmp = *this; \
+ wxStringOperations::IncIter(m_cur); \
+ return tmp; \
+ } \
+ iterator_name operator--(int) \
+ { \
+ iterator_name tmp = *this; \
+ wxStringOperations::DecIter(m_cur); \
+ return tmp; \
+ } \
+ \
+ iterator_name& operator+=(ptrdiff_t n) \
+ { \
+ m_cur = wxStringOperations::AddToIter(m_cur, n); \
+ return *this; \
+ } \
+ iterator_name& operator-=(ptrdiff_t n) \
+ { \
+ m_cur = wxStringOperations::AddToIter(m_cur, -n); \
+ return *this; \
+ } \
+ \
+ difference_type operator-(const iterator_name& i) const \
+ { return wxStringOperations::DiffIters(m_cur, i.m_cur); } \
+ \
+ bool operator==(const iterator_name& i) const \
+ { return m_cur == i.m_cur; } \
+ bool operator!=(const iterator_name& i) const \
+ { return m_cur != i.m_cur; } \
+ \
+ bool operator<(const iterator_name& i) const \
+ { return m_cur < i.m_cur; } \
+ bool operator>(const iterator_name& i) const \
+ { return m_cur > i.m_cur; } \
+ bool operator<=(const iterator_name& i) const \
+ { return m_cur <= i.m_cur; } \
+ bool operator>=(const iterator_name& i) const \
+ { return m_cur >= i.m_cur; } \
+ \
+ private: \
+ /* for internal wxString use only: */ \
+ underlying_iterator impl() const { return m_cur; } \
+ \
+ friend class wxString; \
+ friend class wxCStrData; \
+ \
+ private: \
+ underlying_iterator m_cur
+
+ class WXDLLIMPEXP_FWD_BASE const_iterator;
+
+#if wxUSE_UNICODE_UTF8
+ // NB: In UTF-8 build, (non-const) iterator needs to keep reference
+ // to the underlying wxStringImpl, because UTF-8 is variable-length
+ // encoding and changing the value pointer to by an iterator (using
+ // its operator*) requires calling wxStringImpl::replace() if the old
+ // and new values differ in their encoding's length.
+ //
+ // Furthermore, the replace() call may invalid all iterators for the
+ // string, so we have to keep track of outstanding iterators and update
+ // them if replace() happens.
+ //
+ // This is implemented by maintaining linked list of iterators for every
+ // string and traversing it in wxUniCharRef::operator=(). Head of the
+ // list is stored in wxString. (FIXME-UTF8)
+
+ class WXDLLIMPEXP_BASE iterator
+ {
+ WX_STR_ITERATOR_IMPL(iterator, wxChar*, wxUniCharRef);
+
+ public:
+ iterator() {}
+ iterator(const iterator& i)
+ : m_cur(i.m_cur), m_node(i.str(), &m_cur) {}
+ iterator& operator=(const iterator& i)
+ {
+ if (&i != this)
+ {
+ m_cur = i.m_cur;
+ m_node.set(i.str(), &m_cur);
+ }
+ return *this;
+ }
+
+ reference operator*()
+ { return wxUniCharRef::CreateForString(m_node, m_cur); }
+
+ iterator operator+(ptrdiff_t n) const
+ { return iterator(str(), wxStringOperations::AddToIter(m_cur, n)); }
+ iterator operator-(ptrdiff_t n) const
+ { return iterator(str(), wxStringOperations::AddToIter(m_cur, -n)); }
+
+ private:
+ iterator(wxString *str, underlying_iterator ptr)
+ : m_cur(ptr), m_node(str, &m_cur) {}
+
+ wxString* str() const { return wx_const_cast(wxString*, m_node.m_str); }
+
+ wxStringIteratorNode m_node;
+
+ friend class const_iterator;
+ };
+
+ class WXDLLIMPEXP_BASE const_iterator
+ {
+ // NB: reference_type is intentionally value, not reference, the character
+ // may be encoded differently in wxString data:
+ WX_STR_ITERATOR_IMPL(const_iterator, const wxChar*, wxUniChar);
+
+ public:
+ const_iterator() {}
+ const_iterator(const const_iterator& i)
+ : m_cur(i.m_cur), m_node(i.str(), &m_cur) {}
+ const_iterator(const iterator& i)
+ : m_cur(i.m_cur), m_node(i.str(), &m_cur) {}
+
+ const_iterator& operator=(const const_iterator& i)
+ {
+ if (&i != this)
+ {
+ m_cur = i.m_cur;
+ m_node.set(i.str(), &m_cur);
+ }
+ return *this;
+ }
+ const_iterator& operator=(const iterator& i)
+ { m_cur = i.m_cur; m_node.set(i.str(), &m_cur); return *this; }
+
+ reference operator*() const
+ { return wxStringOperations::DecodeChar(m_cur); }
+
+ const_iterator operator+(ptrdiff_t n) const
+ { return const_iterator(str(), wxStringOperations::AddToIter(m_cur, n)); }
+ const_iterator operator-(ptrdiff_t n) const
+ { return const_iterator(str(), wxStringOperations::AddToIter(m_cur, -n)); }
+
+ private:
+ // for internal wxString use only:
+ const_iterator(const wxString *str, underlying_iterator ptr)
+ : m_cur(ptr), m_node(str, &m_cur) {}
+
+ const wxString* str() const { return m_node.m_str; }
+
+ wxStringIteratorNode m_node;
+ };
+
+ size_t IterToImplPos(wxString::iterator i) const
+ { return wxStringImpl::const_iterator(i.impl()) - m_impl.begin(); }
+
+#else // !wxUSE_UNICODE_UTF8
+
+ class WXDLLIMPEXP_BASE iterator
+ {
+ WX_STR_ITERATOR_IMPL(iterator, wxChar*, wxUniCharRef);
+
+ public:
+ iterator() {}
+ iterator(const iterator& i) : m_cur(i.m_cur) {}
+
+ reference operator*()
+ { return wxUniCharRef::CreateForString(m_cur); }
+
+ iterator operator+(ptrdiff_t n) const
+ { return iterator(wxStringOperations::AddToIter(m_cur, n)); }
+ iterator operator-(ptrdiff_t n) const
+ { return iterator(wxStringOperations::AddToIter(m_cur, -n)); }
+
+ private:
+ // for internal wxString use only:
+ iterator(underlying_iterator ptr) : m_cur(ptr) {}
+ iterator(wxString *WXUNUSED(str), underlying_iterator ptr) : m_cur(ptr) {}
+
+ friend class const_iterator;
+ };
+
+ class WXDLLIMPEXP_BASE const_iterator
+ {
+ // NB: reference_type is intentionally value, not reference, the character
+ // may be encoded differently in wxString data:
+ WX_STR_ITERATOR_IMPL(const_iterator, const wxChar*, wxUniChar);
+
+ public:
+ const_iterator() {}
+ const_iterator(const const_iterator& i) : m_cur(i.m_cur) {}
+ const_iterator(const iterator& i) : m_cur(i.m_cur) {}
+
+ reference operator*() const
+ { return wxStringOperations::DecodeChar(m_cur); }
+
+ const_iterator operator+(ptrdiff_t n) const
+ { return const_iterator(wxStringOperations::AddToIter(m_cur, n)); }
+ const_iterator operator-(ptrdiff_t n) const
+ { return const_iterator(wxStringOperations::AddToIter(m_cur, -n)); }
+
+ private:
+ // for internal wxString use only:
+ const_iterator(underlying_iterator ptr) : m_cur(ptr) {}
+ const_iterator(const wxString *WXUNUSED(str), underlying_iterator ptr)
+ : m_cur(ptr) {}
+ };
+#endif // wxUSE_UNICODE_UTF8/!wxUSE_UNICODE_UTF8
+
+ #undef WX_STR_ITERATOR_TAG
+ #undef WX_STR_ITERATOR_IMPL
+
+ friend class iterator;
+ friend class const_iterator;
+
+ template <typename T>
+ class reverse_iterator_impl
+ {
+ public:
+ typedef T iterator_type;
+
+ typedef typename T::iterator_category iterator_category;
+ typedef typename T::value_type value_type;
+ typedef typename T::difference_type difference_type;
+ typedef typename T::reference reference;
+ typedef typename T::pointer *pointer;
+
+ reverse_iterator_impl() {}
+ reverse_iterator_impl(iterator_type i) : m_cur(i) {}
+ reverse_iterator_impl(const reverse_iterator_impl& ri)
+ : m_cur(ri.m_cur) {}
+
+ iterator_type base() const { return m_cur; }
+
+ reference operator*() const { return *(m_cur-1); }
+ reference operator[](size_t n) const { return *(*this + n); }
+
+ reverse_iterator_impl& operator++()
+ { --m_cur; return *this; }
+ reverse_iterator_impl operator++(int)
+ { reverse_iterator_impl tmp = *this; --m_cur; return tmp; }
+ reverse_iterator_impl& operator--()
+ { ++m_cur; return *this; }
+ reverse_iterator_impl operator--(int)
+ { reverse_iterator_impl tmp = *this; ++m_cur; return tmp; }
+
+ // NB: explicit <T> in the functions below is to keep BCC 5.5 happy
+ reverse_iterator_impl operator+(ptrdiff_t n) const
+ { return reverse_iterator_impl<T>(m_cur - n); }
+ reverse_iterator_impl operator-(ptrdiff_t n) const
+ { return reverse_iterator_impl<T>(m_cur + n); }
+ reverse_iterator_impl operator+=(ptrdiff_t n)
+ { m_cur -= n; return *this; }
+ reverse_iterator_impl operator-=(ptrdiff_t n)
+ { m_cur += n; return *this; }
+
+ unsigned operator-(const reverse_iterator_impl& i) const
+ { return i.m_cur - m_cur; }
+
+ bool operator==(const reverse_iterator_impl& ri) const
+ { return m_cur == ri.m_cur; }
+ bool operator!=(const reverse_iterator_impl& ri) const
+ { return !(*this == ri); }
+
+ bool operator<(const reverse_iterator_impl& i) const
+ { return m_cur > i.m_cur; }
+ bool operator>(const reverse_iterator_impl& i) const
+ { return m_cur < i.m_cur; }
+ bool operator<=(const reverse_iterator_impl& i) const
+ { return m_cur >= i.m_cur; }
+ bool operator>=(const reverse_iterator_impl& i) const
+ { return m_cur <= i.m_cur; }
+
+ private:
+ iterator_type m_cur;
+ };
+
+ typedef reverse_iterator_impl<iterator> reverse_iterator;
+ typedef reverse_iterator_impl<const_iterator> const_reverse_iterator;
+
+private:
+ // used to transform an expression built using c_str() (and hence of type
+ // wxCStrData) to an iterator into the string
+ static const_iterator CreateConstIterator(const wxCStrData& data)
+ {
+ return const_iterator(data.m_str,
+ (data.m_str->begin() + data.m_offset).impl());
+ }
+
+ // in UTF-8 STL build, creation from std::string requires conversion under
+ // non-UTF8 locales, so we can't have and use wxString(wxStringImpl) ctor;
+ // instead we define dummy type that lets us have wxString ctor for creation
+ // from wxStringImpl that couldn't be used by user code (in all other builds,
+ // "standard" ctors can be used):
+#if wxUSE_UNICODE_UTF8 && wxUSE_STL_BASED_WXSTRING
+ struct CtorFromStringImplTag {};
+
+ wxString(CtorFromStringImplTag* WXUNUSED(dummy), const wxStringImpl& src)
+ : m_impl(src) {}
+
+ static wxString FromImpl(const wxStringImpl& src)
+ { return wxString((CtorFromStringImplTag*)NULL, src); }
+#else
+ #if !wxUSE_STL_BASED_WXSTRING
+ wxString(const wxStringImpl& src) : m_impl(src) { }
+ // else: already defined as wxString(wxStdString) below
+ #endif
+ static wxString FromImpl(const wxStringImpl& src) { return wxString(src); }
+#endif
+