Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/include/OgreUTFString.h @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 89.7 KB
Line 
1// Modified from OpenGUI under lenient license
2// Original copyright details and licensing below:
3// OpenGUI (http://opengui.sourceforge.net)
4// This source code is released under the BSD License
5
6// Permission is given to the Ogre project to use the contents of file within its
7// source and binary applications, as well as any derivative works, in accordance
8// with the terms of any license under which Ogre is or will be distributed.
9//
10// Ogre may relicense its copy of this file, as well as any OpenGUI released updates
11// to this file, under any terms that it deems fit, and is not required to maintain
12// the original BSD licensing terms of this file, however OpenGUI retains the right
13// to present its copy of this file under the terms of any license under which
14// OpenGUI is distributed.
15//
16// Ogre is not required to release to OpenGUI any future changes that it makes to
17// this file, and understands and agrees that any such changes that are released
18// back to OpenGUI will become available under the terms of any license under which
19// OpenGUI is distributed.
20//
21// For brevity, this permission text may be removed from this file if desired.
22// The original record kept within the SourceForge (http://sourceforge.net/) tracker
23// is sufficient.
24//
25// - Eric Shorkey (zero/zeroskill) <opengui@rightbracket.com> [January 20th, 2007]
26
27#ifndef __OGRE_UTFSTRING_H__
28#define __OGRE_UTFSTRING_H__
29
30
31#include "OgrePrerequisites.h"
32
33#if OGRE_UNICODE_SUPPORT
34
35// these are explained later
36#include <iterator>
37#include <string>
38#include <stdexcept>
39
40// Workaround for VC7:
41//      when build with /MD or /MDd, VC7 have both std::basic_string<unsigned short> and
42// basic_string<__wchar_t> instantiated in msvcprt[d].lib/MSVCP71[D].dll, but the header
43// files tells compiler that only one of them is over there (based on /Zc:wchar_t compile
44// option). And since this file used both of them, causing compiler instantiating another
45// one in user object code, which lead to duplicate symbols with msvcprt.lib/MSVCP71[D].dll.
46//
47#if OGRE_COMPILER == OGRE_COMPILER_MSVC && (1300 <= OGRE_COMP_VER && OGRE_COMP_VER <= 1310)
48
49# if defined(_DLL_CPPLIB)
50
51namespace std
52{
53    template class _CRTIMP2 basic_string<unsigned short, char_traits<unsigned short>,
54            allocator<unsigned short> >;
55
56    template class _CRTIMP2 basic_string<__wchar_t, char_traits<__wchar_t>,
57            allocator<__wchar_t> >;
58}
59
60# endif // defined(_DLL_CPPLIB)
61
62#endif  // OGRE_COMPILER == OGRE_COMPILER_MSVC && OGRE_COMP_VER == 1300
63
64
65namespace Ogre {
66
67        /* READ THIS NOTICE BEFORE USING IN YOUR OWN APPLICATIONS
68        =NOTICE=
69        This class is not a complete Unicode solution. It purposefully does not
70        provide certain functionality, such as proper lexical sorting for
71        Unicode values. It does provide comparison operators for the sole purpose
72        of using UTFString as an index with std::map and other operator< sorted
73        containers, but it should NOT be relied upon for meaningful lexical
74        operations, such as alphabetical sorts. If you need this type of
75        functionality, look into using ICU instead (http://icu.sourceforge.net/).
76
77        =REQUIREMENTS=
78        There are a few requirements for proper operation. They are fairly small,
79        and shouldn't restrict usage on any reasonable target.
80        * Compiler must support unsigned 16-bit integer types
81        * Compiler must support signed 32-bit integer types
82        * wchar_t must be either UTF-16 or UTF-32 encoding, and specified as such
83            using the WCHAR_UTF16 macro as outlined below.
84        * You must include <iterator>, <string>, and <wchar>. Probably more, but
85            these are the most obvious.
86
87        =REQUIRED PREPROCESSOR MACROS=
88        This class requires two preprocessor macros to be defined in order to
89        work as advertised.
90        INT32 - must be mapped to a signed 32 bit integer (ex. #define INT32 int)
91        UINT16 - must be mapped to an unsigned 16 bit integer (ex. #define UINT32 unsigned short)
92
93        Additionally, a third macro should be defined to control the evaluation of wchar_t:
94        WCHAR_UTF16 - should be defined when wchar_t represents UTF-16 code points,
95            such as in Windows. Otherwise it is assumed that wchar_t is a 32-bit
96                integer representing UTF-32 code points.
97        */
98
99        // THIS IS A VERY BRIEF AUTO DETECTION. YOU MAY NEED TO TWEAK THIS
100#ifdef __STDC_ISO_10646__
101// for any compiler that provides this, wchar_t is guaranteed to hold any Unicode value with a single code point (32-bit or larger)
102// so we can safely skip the rest of the testing
103#else // #ifdef __STDC_ISO_10646__
104#if defined( __WIN32__ ) || defined( _WIN32 )
105#define WCHAR_UTF16 // All currently known Windows platforms utilize UTF-16 encoding in wchar_t
106#else // #if defined( __WIN32__ ) || defined( _WIN32 )
107#if WCHAR_MAX <= 0xFFFF // this is a last resort fall back test; WCHAR_MAX is defined in <wchar.h>
108#define WCHAR_UTF16 // best we can tell, wchar_t is not larger than 16-bit
109#endif // #if WCHAR_MAX <= 0xFFFF
110#endif // #if defined( __WIN32__ ) || defined( _WIN32 )
111#endif // #ifdef __STDC_ISO_10646__
112
113
114// OGRE_IS_NATIVE_WCHAR_T means that wchar_t isn't a typedef of
115// uint16 or uint32.
116#if OGRE_COMPILER == OGRE_COMPILER_MSVC
117
118// Don't define wchar_t related functions since it'll duplicate
119// with UTFString::code_point related functions when compile
120// without /Zc:wchar_t, because in this case both of them are
121// a typedef of uint16.
122# if defined(_NATIVE_WCHAR_T_DEFINED)
123#   define OGRE_IS_NATIVE_WCHAR_T      1
124# else
125#   define OGRE_IS_NATIVE_WCHAR_T      0
126# endif
127
128#else   // OGRE_COMPILER != OGRE_COMPILER_MSVC
129
130// Assumed wchar_t is natively for other compilers
131#   define OGRE_IS_NATIVE_WCHAR_T     1
132
133#endif  // OGRE_COMPILER == OGRE_COMPILER_MSVC
134
135        //! A UTF-16 string with implicit conversion to/from std::string and std::wstring
136        /*! This class provides a complete 1 to 1 map of most std::string functions (at least to my
137        knowledge). Implicit conversions allow this string class to work with all common C++ string
138        formats, with specialty functions defined where implicit conversion would cause potential
139        problems or is otherwise unavailable.
140
141        Some additional functionality is present to assist in working with characters using the
142        32-bit UTF-32 encoding. (Which is guaranteed to fit any Unicode character into a single
143        code point.) \b Note: Reverse iterators do not have this functionality due to the
144        ambiguity that surrounds working with UTF-16 in reverse. (Such as, where should an
145        iterator point to represent the beginning of a surrogate pair?)
146
147
148        \par Supported Input Types
149        The supported string types for input, and their assumed encoding schemes, are:
150        - std::string (UTF-8)
151        - char* (UTF-8)
152        - std::wstring (autodetected UTF-16 / UTF-32 based on compiler)
153        - wchar_t* (autodetected UTF-16 / UTF-32 based on compiler)
154
155
156        \see
157        - For additional information on UTF-16 encoding: http://en.wikipedia.org/wiki/UTF-16
158        - For additional information on UTF-8 encoding: http://en.wikipedia.org/wiki/UTF-8
159        - For additional information on UTF-32 encoding: http://en.wikipedia.org/wiki/UTF-32
160        */
161        class UTFString {
162                // constants used in UTF-8 conversions
163                static const unsigned char _lead1 = 0xC0;      //110xxxxx
164                static const unsigned char _lead1_mask = 0x1F; //00011111
165                static const unsigned char _lead2 = 0xE0;      //1110xxxx
166                static const unsigned char _lead2_mask = 0x0F; //00001111
167                static const unsigned char _lead3 = 0xF0;      //11110xxx
168                static const unsigned char _lead3_mask = 0x07; //00000111
169                static const unsigned char _lead4 = 0xF8;      //111110xx
170                static const unsigned char _lead4_mask = 0x03; //00000011
171                static const unsigned char _lead5 = 0xFC;      //1111110x
172                static const unsigned char _lead5_mask = 0x01; //00000001
173                static const unsigned char _cont = 0x80;       //10xxxxxx
174                static const unsigned char _cont_mask = 0x3F;  //00111111
175
176        public:
177                //! size type used to indicate string size and character positions within the string
178                typedef size_t size_type;
179                //! the usual constant representing: not found, no limit, etc
180                static const size_type npos = ~0;
181
182                //! a single 32-bit Unicode character
183                typedef uint32 unicode_char;
184
185                //! a single UTF-16 code point
186                typedef uint16 code_point;
187
188                //! value type typedef for use in iterators
189                typedef code_point value_type;
190
191                typedef std::basic_string<code_point> dstring; // data string
192
193                //! string type used for returning UTF-32 formatted data
194                typedef std::basic_string<unicode_char> utf32string;
195
196                //! This exception is used when invalid data streams are encountered
197        class invalid_data: public std::runtime_error { /* i don't know why the beautifier is freaking out on this line */
198                public:
199                        //! constructor takes a string message that can be later retrieved by the what() function
200                        explicit invalid_data( const std::string& _Message ): std::runtime_error( _Message ) {
201                                /* The thing is, Bob, it's not that I'm lazy, it's that I just don't care. */
202                        }
203                };
204
205                //#########################################################################
206                //! base iterator class for UTFString
207        class _base_iterator: public std::iterator<std::random_access_iterator_tag, value_type> { /* i don't know why the beautifier is freaking out on this line */
208                        friend class UTFString;
209                protected:
210                        _base_iterator() {
211                                mString = 0;
212                        }
213
214                        void _seekFwd( size_type c ) {
215                                mIter += c;
216                        }
217                        void _seekRev( size_type c ) {
218                                mIter -= c;
219                        }
220                        void _become( const _base_iterator& i ) {
221                                mIter = i.mIter;
222                                mString = i.mString;
223                        }
224                        bool _test_begin() const {
225                                return mIter == mString->mData.begin();
226                        }
227                        bool _test_end() const {
228                                return mIter == mString->mData.end();
229                        }
230                        size_type _get_index() const {
231                                return mIter - mString->mData.begin();
232                        }
233                        void _jump_to( size_type index ) {
234                                mIter = mString->mData.begin() + index;
235                        }
236
237                        unicode_char _getCharacter() const {
238                                size_type current_index = _get_index();
239                                return mString->getChar( current_index );
240                        }
241                        int _setCharacter( unicode_char uc ) {
242                                size_type current_index = _get_index();
243                                int change = mString->setChar( current_index, uc );
244                                _jump_to( current_index );
245                                return change;
246                        }
247
248                        void _moveNext() {
249                                _seekFwd( 1 ); // move 1 code point forward
250                                if ( _test_end() ) return; // exit if we hit the end
251                                if ( _utf16_surrogate_follow( mIter[0] ) ) {
252                                        // landing on a follow code point means we might be part of a bigger character
253                                        // so we test for that
254                                        code_point lead_half = 0;
255                                        //NB: we can't possibly be at the beginning here, so no need to test
256                                        lead_half = mIter[-1]; // check the previous code point to see if we're part of a surrogate pair
257                                        if ( _utf16_surrogate_lead( lead_half ) ) {
258                                                _seekFwd( 1 ); // if so, then advance 1 more code point
259                                        }
260                                }
261                        }
262                        void _movePrev() {
263                                _seekRev( 1 ); // move 1 code point backwards
264                                if ( _test_begin() ) return; // exit if we hit the beginning
265                                if ( _utf16_surrogate_follow( mIter[0] ) ) {
266                                        // landing on a follow code point means we might be part of a bigger character
267                                        // so we test for that
268                                        code_point lead_half = 0;
269                                        lead_half = mIter[-1]; // check the previous character to see if we're part of a surrogate pair
270                                        if ( _utf16_surrogate_lead( lead_half ) ) {
271                                                _seekRev( 1 ); // if so, then rewind 1 more code point
272                                        }
273                                }
274                        }
275
276                        dstring::iterator mIter;
277                        UTFString* mString;
278                };
279
280                //#########################################################################
281                // FORWARD ITERATORS
282                //#########################################################################
283                class _const_fwd_iterator; // forward declaration
284
285                //! forward iterator for UTFString
286        class _fwd_iterator: public _base_iterator { /* i don't know why the beautifier is freaking out on this line */
287                        friend class _const_fwd_iterator;
288                public:
289                        _fwd_iterator() {}
290                        _fwd_iterator( const _fwd_iterator& i ) {
291                                _become( i );
292                        }
293
294                        //! pre-increment
295                        _fwd_iterator& operator++() {
296                                _seekFwd( 1 );
297                                return *this;
298                        }
299                        //! post-increment
300                        _fwd_iterator operator++( int ) {
301                                _fwd_iterator tmp( *this );
302                                _seekFwd( 1 );
303                                return tmp;
304                        }
305
306                        //! pre-decrement
307                        _fwd_iterator& operator--() {
308                                _seekRev( 1 );
309                                return *this;
310                        }
311                        //! post-decrement
312                        _fwd_iterator operator--( int ) {
313                                _fwd_iterator tmp( *this );
314                                _seekRev( 1 );
315                                return tmp;
316                        }
317
318                        //! addition operator
319                        _fwd_iterator operator+( size_type n ) {
320                                _fwd_iterator tmp( *this );
321                                tmp._seekFwd( n );
322                                return tmp;
323                        }
324                        //! addition operator
325                        _fwd_iterator operator+( difference_type n ) {
326                                _fwd_iterator tmp( *this );
327                                if ( n < 0 )
328                                        tmp._seekRev( -n );
329                                else
330                                        tmp._seekFwd( n );
331                                return tmp;
332                        }
333                        //! subtraction operator
334                        _fwd_iterator operator-( size_type n ) {
335                                _fwd_iterator tmp( *this );
336                                tmp._seekRev( n );
337                                return tmp;
338                        }
339                        //! subtraction operator
340                        _fwd_iterator operator-( difference_type n ) {
341                                _fwd_iterator tmp( *this );
342                                if ( n < 0 )
343                                        tmp._seekFwd( -n );
344                                else
345                                        tmp._seekRev( n );
346                                return tmp;
347                        }
348
349                        //! addition assignment operator
350                        _fwd_iterator& operator+=( size_type n ) {
351                                _seekFwd( n );
352                                return *this;
353                        }
354                        //! addition assignment operator
355                        _fwd_iterator& operator+=( difference_type n ) {
356                                if ( n < 0 )
357                                        _seekRev( -n );
358                                else
359                                        _seekFwd( n );
360                                return *this;
361                        }
362                        //! subtraction assignment operator
363                        _fwd_iterator& operator-=( size_type n ) {
364                                _seekRev( n );
365                                return *this;
366                        }
367                        //! subtraction assignment operator
368                        _fwd_iterator& operator-=( difference_type n ) {
369                                if ( n < 0 )
370                                        _seekFwd( -n );
371                                else
372                                        _seekRev( n );
373                                return *this;
374                        }
375
376                        //! dereference operator
377                        value_type& operator*() const {
378                                return *mIter;
379                        }
380
381                        //! dereference at offset operator
382                        value_type& operator[]( size_type n ) const {
383                                _fwd_iterator tmp( *this );
384                                tmp += n;
385                                return *tmp;
386                        }
387                        //! dereference at offset operator
388                        value_type& operator[]( difference_type n ) const {
389                                _fwd_iterator tmp( *this );
390                                tmp += n;
391                                return *tmp;
392                        }
393
394                        //! advances to the next Unicode character, honoring surrogate pairs in the UTF-16 stream
395                        _fwd_iterator& moveNext() {
396                                _moveNext();
397                                return *this;
398                        }
399                        //! rewinds to the previous Unicode character, honoring surrogate pairs in the UTF-16 stream
400                        _fwd_iterator& movePrev() {
401                                _movePrev();
402                                return *this;
403                        }
404                        //! Returns the Unicode value of the character at the current position (decodes surrogate pairs if needed)
405                        unicode_char getCharacter() const {
406                                return _getCharacter();
407                        }
408                        //! Sets the Unicode value of the character at the current position (adding a surrogate pair if needed); returns the amount of string length change caused by the operation
409                        int setCharacter( unicode_char uc ) {
410                                return _setCharacter( uc );
411                        }
412                };
413
414
415
416                //#########################################################################
417                //! const forward iterator for UTFString
418        class _const_fwd_iterator: public _base_iterator { /* i don't know why the beautifier is freaking out on this line */
419                public:
420                        _const_fwd_iterator() {}
421                        _const_fwd_iterator( const _const_fwd_iterator& i ) {
422                                _become( i );
423                        }
424                        _const_fwd_iterator( const _fwd_iterator& i ) {
425                                _become( i );
426                        }
427
428                        //! pre-increment
429                        _const_fwd_iterator& operator++() {
430                                _seekFwd( 1 );
431                                return *this;
432                        }
433                        //! post-increment
434                        _const_fwd_iterator operator++( int ) {
435                                _const_fwd_iterator tmp( *this );
436                                _seekFwd( 1 );
437                                return tmp;
438                        }
439
440                        //! pre-decrement
441                        _const_fwd_iterator& operator--() {
442                                _seekRev( 1 );
443                                return *this;
444                        }
445                        //! post-decrement
446                        _const_fwd_iterator operator--( int ) {
447                                _const_fwd_iterator tmp( *this );
448                                _seekRev( 1 );
449                                return tmp;
450                        }
451
452                        //! addition operator
453                        _const_fwd_iterator operator+( size_type n ) {
454                                _const_fwd_iterator tmp( *this );
455                                tmp._seekFwd( n );
456                                return tmp;
457                        }
458                        //! addition operator
459                        _const_fwd_iterator operator+( difference_type n ) {
460                                _const_fwd_iterator tmp( *this );
461                                if ( n < 0 )
462                                        tmp._seekRev( -n );
463                                else
464                                        tmp._seekFwd( n );
465                                return tmp;
466                        }
467                        //! subtraction operator
468                        _const_fwd_iterator operator-( size_type n ) {
469                                _const_fwd_iterator tmp( *this );
470                                tmp._seekRev( n );
471                                return tmp;
472                        }
473                        //! subtraction operator
474                        _const_fwd_iterator operator-( difference_type n ) {
475                                _const_fwd_iterator tmp( *this );
476                                if ( n < 0 )
477                                        tmp._seekFwd( -n );
478                                else
479                                        tmp._seekRev( n );
480                                return tmp;
481                        }
482
483                        //! addition assignment operator
484                        _const_fwd_iterator& operator+=( size_type n ) {
485                                _seekFwd( n );
486                                return *this;
487                        }
488                        //! addition assignment operator
489                        _const_fwd_iterator& operator+=( difference_type n ) {
490                                if ( n < 0 )
491                                        _seekRev( -n );
492                                else
493                                        _seekFwd( n );
494                                return *this;
495                        }
496                        //! subtraction assignment operator
497                        _const_fwd_iterator& operator-=( size_type n ) {
498                                _seekRev( n );
499                                return *this;
500                        }
501                        //! subtraction assignment operator
502                        _const_fwd_iterator& operator-=( difference_type n ) {
503                                if ( n < 0 )
504                                        _seekFwd( -n );
505                                else
506                                        _seekRev( n );
507                                return *this;
508                        }
509
510                        //! dereference operator
511                        const value_type& operator*() const {
512                                return *mIter;
513                        }
514
515                        //! dereference at offset operator
516                        const value_type& operator[]( size_type n ) const {
517                                _const_fwd_iterator tmp( *this );
518                                tmp += n;
519                                return *tmp;
520                        }
521                        //! dereference at offset operator
522                        const value_type& operator[]( difference_type n ) const {
523                                _const_fwd_iterator tmp( *this );
524                                tmp += n;
525                                return *tmp;
526                        }
527
528                        //! advances to the next Unicode character, honoring surrogate pairs in the UTF-16 stream
529                        _const_fwd_iterator& moveNext() {
530                                _moveNext();
531                                return *this;
532                        }
533                        //! rewinds to the previous Unicode character, honoring surrogate pairs in the UTF-16 stream
534                        _const_fwd_iterator& movePrev() {
535                                _movePrev();
536                                return *this;
537                        }
538                        //! Returns the Unicode value of the character at the current position (decodes surrogate pairs if needed)
539                        unicode_char getCharacter() const {
540                                return _getCharacter();
541                        }
542
543                        //! difference operator
544                        friend size_type operator-( const _const_fwd_iterator& left, const _const_fwd_iterator& right );
545                        //! equality operator
546                        friend bool operator==( const _const_fwd_iterator& left, const _const_fwd_iterator& right );
547                        //! inequality operator
548                        friend bool operator!=( const _const_fwd_iterator& left, const _const_fwd_iterator& right );
549                        //! less than
550                        friend bool operator<( const _const_fwd_iterator& left, const _const_fwd_iterator& right );
551                        //! less than or equal
552                        friend bool operator<=( const _const_fwd_iterator& left, const _const_fwd_iterator& right );
553                        //! greater than
554                        friend bool operator>( const _const_fwd_iterator& left, const _const_fwd_iterator& right );
555                        //! greater than or equal
556                        friend bool operator>=( const _const_fwd_iterator& left, const _const_fwd_iterator& right );
557
558                };
559
560                //#########################################################################
561                // REVERSE ITERATORS
562                //#########################################################################
563                class _const_rev_iterator; // forward declaration
564                //! forward iterator for UTFString
565        class _rev_iterator: public _base_iterator { /* i don't know why the beautifier is freaking out on this line */
566                        friend class _const_rev_iterator;
567                public:
568                        _rev_iterator() {}
569                        _rev_iterator( const _rev_iterator& i ) {
570                                _become( i );
571                        }
572
573                        //! pre-increment
574                        _rev_iterator& operator++() {
575                                _seekRev( 1 );
576                                return *this;
577                        }
578                        //! post-increment
579                        _rev_iterator operator++( int ) {
580                                _rev_iterator tmp( *this );
581                                _seekRev( 1 );
582                                return tmp;
583                        }
584
585                        //! pre-decrement
586                        _rev_iterator& operator--() {
587                                _seekFwd( 1 );
588                                return *this;
589                        }
590                        //! post-decrement
591                        _rev_iterator operator--( int ) {
592                                _rev_iterator tmp( *this );
593                                _seekFwd( 1 );
594                                return tmp;
595                        }
596
597                        //! addition operator
598                        _rev_iterator operator+( size_type n ) {
599                                _rev_iterator tmp( *this );
600                                tmp._seekRev( n );
601                                return tmp;
602                        }
603                        //! addition operator
604                        _rev_iterator operator+( difference_type n ) {
605                                _rev_iterator tmp( *this );
606                                if ( n < 0 )
607                                        tmp._seekFwd( -n );
608                                else
609                                        tmp._seekRev( n );
610                                return tmp;
611                        }
612                        //! subtraction operator
613                        _rev_iterator operator-( size_type n ) {
614                                _rev_iterator tmp( *this );
615                                tmp._seekFwd( n );
616                                return tmp;
617                        }
618                        //! subtraction operator
619                        _rev_iterator operator-( difference_type n ) {
620                                _rev_iterator tmp( *this );
621                                if ( n < 0 )
622                                        tmp._seekRev( -n );
623                                else
624                                        tmp._seekFwd( n );
625                                return tmp;
626                        }
627
628                        //! addition assignment operator
629                        _rev_iterator& operator+=( size_type n ) {
630                                _seekRev( n );
631                                return *this;
632                        }
633                        //! addition assignment operator
634                        _rev_iterator& operator+=( difference_type n ) {
635                                if ( n < 0 )
636                                        _seekFwd( -n );
637                                else
638                                        _seekRev( n );
639                                return *this;
640                        }
641                        //! subtraction assignment operator
642                        _rev_iterator& operator-=( size_type n ) {
643                                _seekFwd( n );
644                                return *this;
645                        }
646                        //! subtraction assignment operator
647                        _rev_iterator& operator-=( difference_type n ) {
648                                if ( n < 0 )
649                                        _seekRev( -n );
650                                else
651                                        _seekFwd( n );
652                                return *this;
653                        }
654
655                        //! dereference operator
656                        value_type& operator*() const {
657                                return mIter[-1];
658                        }
659
660                        //! dereference at offset operator
661                        value_type& operator[]( size_type n ) const {
662                                _rev_iterator tmp( *this );
663                                tmp -= n;
664                                return *tmp;
665                        }
666                        //! dereference at offset operator
667                        value_type& operator[]( difference_type n ) const {
668                                _rev_iterator tmp( *this );
669                                tmp -= n;
670                                return *tmp;
671                        }
672                };
673                //#########################################################################
674                //! const reverse iterator for UTFString
675        class _const_rev_iterator: public _base_iterator { /* i don't know why the beautifier is freaking out on this line */
676                public:
677                        _const_rev_iterator() {}
678                        _const_rev_iterator( const _const_rev_iterator& i ) {
679                                _become( i );
680                        }
681                        _const_rev_iterator( const _rev_iterator& i ) {
682                                _become( i );
683                        }
684                        //! pre-increment
685                        _const_rev_iterator& operator++() {
686                                _seekRev( 1 );
687                                return *this;
688                        }
689                        //! post-increment
690                        _const_rev_iterator operator++( int ) {
691                                _const_rev_iterator tmp( *this );
692                                _seekRev( 1 );
693                                return tmp;
694                        }
695
696                        //! pre-decrement
697                        _const_rev_iterator& operator--() {
698                                _seekFwd( 1 );
699                                return *this;
700                        }
701                        //! post-decrement
702                        _const_rev_iterator operator--( int ) {
703                                _const_rev_iterator tmp( *this );
704                                _seekFwd( 1 );
705                                return tmp;
706                        }
707
708                        //! addition operator
709                        _const_rev_iterator operator+( size_type n ) {
710                                _const_rev_iterator tmp( *this );
711                                tmp._seekRev( n );
712                                return tmp;
713                        }
714                        //! addition operator
715                        _const_rev_iterator operator+( difference_type n ) {
716                                _const_rev_iterator tmp( *this );
717                                if ( n < 0 )
718                                        tmp._seekFwd( -n );
719                                else
720                                        tmp._seekRev( n );
721                                return tmp;
722                        }
723                        //! subtraction operator
724                        _const_rev_iterator operator-( size_type n ) {
725                                _const_rev_iterator tmp( *this );
726                                tmp._seekFwd( n );
727                                return tmp;
728                        }
729                        //! subtraction operator
730                        _const_rev_iterator operator-( difference_type n ) {
731                                _const_rev_iterator tmp( *this );
732                                if ( n < 0 )
733                                        tmp._seekRev( -n );
734                                else
735                                        tmp._seekFwd( n );
736                                return tmp;
737                        }
738
739                        //! addition assignment operator
740                        _const_rev_iterator& operator+=( size_type n ) {
741                                _seekRev( n );
742                                return *this;
743                        }
744                        //! addition assignment operator
745                        _const_rev_iterator& operator+=( difference_type n ) {
746                                if ( n < 0 )
747                                        _seekFwd( -n );
748                                else
749                                        _seekRev( n );
750                                return *this;
751                        }
752                        //! subtraction assignment operator
753                        _const_rev_iterator& operator-=( size_type n ) {
754                                _seekFwd( n );
755                                return *this;
756                        }
757                        //! subtraction assignment operator
758                        _const_rev_iterator& operator-=( difference_type n ) {
759                                if ( n < 0 )
760                                        _seekRev( -n );
761                                else
762                                        _seekFwd( n );
763                                return *this;
764                        }
765
766                        //! dereference operator
767                        const value_type& operator*() const {
768                                return mIter[-1];
769                        }
770
771                        //! dereference at offset operator
772                        const value_type& operator[]( size_type n ) const {
773                                _const_rev_iterator tmp( *this );
774                                tmp -= n;
775                                return *tmp;
776                        }
777                        //! dereference at offset operator
778                        const value_type& operator[]( difference_type n ) const {
779                                _const_rev_iterator tmp( *this );
780                                tmp -= n;
781                                return *tmp;
782                        }
783
784                        //! difference operator
785                        friend size_type operator-( const _const_rev_iterator& left, const _const_rev_iterator& right );
786                        //! equality operator
787                        friend bool operator==( const _const_rev_iterator& left, const _const_rev_iterator& right );
788                        //! inequality operator
789                        friend bool operator!=( const _const_rev_iterator& left, const _const_rev_iterator& right );
790                        //! less than
791                        friend bool operator<( const _const_rev_iterator& left, const _const_rev_iterator& right );
792                        //! less than or equal
793                        friend bool operator<=( const _const_rev_iterator& left, const _const_rev_iterator& right );
794                        //! greater than
795                        friend bool operator>( const _const_rev_iterator& left, const _const_rev_iterator& right );
796                        //! greater than or equal
797                        friend bool operator>=( const _const_rev_iterator& left, const _const_rev_iterator& right );
798                };
799                //#########################################################################
800
801                typedef _fwd_iterator iterator;                     //!< iterator
802                typedef _rev_iterator reverse_iterator;             //!< reverse iterator
803                typedef _const_fwd_iterator const_iterator;         //!< const iterator
804                typedef _const_rev_iterator const_reverse_iterator; //!< const reverse iterator
805
806
807                //!\name Constructors/Destructor
808                //@{
809                //! default constructor, creates an empty string
810                UTFString() {
811                        _init();
812                }
813                //! copy constructor
814                UTFString( const UTFString& copy ) {
815                        _init();
816                        mData = copy.mData;
817                }
818                //! \a length copies of \a ch
819                UTFString( size_type length, const code_point& ch ) {
820                        _init();
821                        assign( length, ch );
822                }
823                //! duplicate of nul-terminated sequence \a str
824                UTFString( const code_point* str ) {
825                        _init();
826                        assign( str );
827                }
828                //! duplicate of \a str, \a length code points long
829                UTFString( const code_point* str, size_type length ) {
830                        _init();
831                        assign( str, length );
832                }
833                //! substring of \a str starting at \a index and \a length code points long
834                UTFString( const UTFString& str, size_type index, size_type length ) {
835                        _init();
836                        assign( str, index, length );
837                }
838#if OGRE_IS_NATIVE_WCHAR_T
839                //! duplicate of nul-terminated \c wchar_t array
840                UTFString( const wchar_t* w_str ) {
841                        _init();
842                        assign( w_str );
843                }
844                //! duplicate of \a w_str, \a length characters long
845                UTFString( const wchar_t* w_str, size_type length ) {
846                        _init();
847                        assign( w_str, length );
848                }
849#endif
850                //! duplicate of \a wstr
851                UTFString( const std::wstring& wstr ) {
852                        _init();
853                        assign( wstr );
854                }
855                //! duplicate of nul-terminated C-string \a c_str (UTF-8 encoding)
856                UTFString( const char* c_str ) {
857                        _init();
858                        assign( c_str );
859                }
860                //! duplicate of \a c_str, \a length characters long (UTF-8 encoding)
861                UTFString( const char* c_str, size_type length ) {
862                        _init();
863                        assign( c_str, length );
864                }
865                //! duplicate of \a str (UTF-8 encoding)
866                UTFString( const std::string& str ) {
867                        _init();
868                        assign( str );
869                }
870                //! destructor
871                ~UTFString() {
872                        _cleanBuffer();
873                }
874                //@}
875
876                //////////////////////////////////////////////////////////////////////////
877
878                //!\name Utility functions
879                //@{
880                //! Returns the number of code points in the current string
881                size_type size() const {
882                        return mData.size();
883                }
884                //! Returns the number of code points in the current string
885                size_type length() const {
886                        return size();
887                }
888                //! Returns the number of Unicode characters in the string
889                /*! Executes in linear time. */
890                size_type length_Characters() const {
891                        const_iterator i = begin(), ie = end();
892                        size_type c = 0;
893                        while ( i != ie ) {
894                                i.moveNext();
895                                ++c;
896                        }
897                        return c;
898                }
899                //! returns the maximum number of UTF-16 code points that the string can hold
900                size_type max_size() const {
901                        return mData.max_size();
902                }
903                //! sets the capacity of the string to at least \a size code points
904                void reserve( size_type size ) {
905                        mData.reserve( size );
906                }
907                //! changes the size of the string to \a size, filling in any new area with \a val
908                void resize( size_type num, const code_point& val = 0 ) {
909                        mData.resize( num, val );
910                }
911                //! exchanges the elements of the current string with those of \a from
912                void swap( UTFString& from ) {
913                        mData.swap( from.mData );
914                }
915                //! returns \c true if the string has no elements, \c false otherwise
916                bool empty() const {
917                        return mData.empty();
918                }
919                //! returns a pointer to the first character in the current string
920                const code_point* c_str() const {
921                        return mData.c_str();
922                }
923                //! returns a pointer to the first character in the current string
924                const code_point* data() const {
925                        return c_str();
926                }
927                //! returns the number of elements that the string can hold before it will need to allocate more space
928                size_type capacity() const {
929                        return mData.capacity();
930                }
931                //! deletes all of the elements in the string
932                void clear() {
933                        mData.clear();
934                }
935                //! returns a substring of the current string, starting at \a index, and \a num characters long.
936                /*! If \a num is omitted, it will default to \c UTFString::npos, and the substr() function will simply return the remainder of the string starting at \a index. */
937                UTFString substr( size_type index, size_type num = npos ) const {
938                        // this could avoid the extra copy if we used a private specialty constructor
939                        dstring data = mData.substr( index, num );
940                        UTFString tmp;
941                        tmp.mData.swap( data );
942                        return tmp;
943                }
944                //! appends \a val to the end of the string
945                void push_back( unicode_char val ) {
946                        code_point cp[2];
947                        size_t c = _utf32_to_utf16( val, cp );
948                        if ( c > 0 ) push_back( cp[0] );
949                        if ( c > 1 ) push_back( cp[1] );
950                }
951#if OGRE_IS_NATIVE_WCHAR_T
952                //! appends \a val to the end of the string
953                void push_back( wchar_t val ) {
954                        // we do this because the Unicode method still preserves UTF-16 code points
955                        mData.push_back( static_cast<unicode_char>( val ) );
956                }
957#endif
958                //! appends \a val to the end of the string
959                /*! This can be used to push surrogate pair code points, you'll just need to push them
960                one after the other. */
961                void push_back( code_point val ) {
962                        mData.push_back( val );
963                }
964                //! appends \a val to the end of the string
965                /*! Limited to characters under the 127 value barrier. */
966                void push_back( char val ) {
967                        mData.push_back( static_cast<code_point>( val ) );
968                }
969                //! returns \c true if the given Unicode character \a ch is in this string
970                bool inString( unicode_char ch ) const {
971                        const_iterator i, ie = end();
972                        for ( i = begin(); i != ie; i.moveNext() ) {
973                                if ( i.getCharacter() == ch )
974                                        return true;
975                        }
976                        return false;
977                }
978                //@}
979
980                //////////////////////////////////////////////////////////////////////////
981
982                //!\name Stream variations
983                //@{
984                //! returns the current string in UTF-8 form within a std::string
985                const std::string& asUTF8() const {
986                        _load_buffer_UTF8();
987                        return *m_buffer.mStrBuffer;
988                }
989                //! returns the current string in UTF-8 form as a nul-terminated char array
990                const char* asUTF8_c_str() const {
991                        _load_buffer_UTF8();
992                        return m_buffer.mStrBuffer->c_str();
993                }
994                //! returns the current string in UTF-32 form within a utf32string
995                const utf32string& asUTF32() const {
996                        _load_buffer_UTF32();
997                        return *m_buffer.mUTF32StrBuffer;
998                }
999                //! returns the current string in UTF-32 form as a nul-terminated unicode_char array
1000                const unicode_char* asUTF32_c_str() const {
1001                        _load_buffer_UTF32();
1002                        return m_buffer.mUTF32StrBuffer->c_str();
1003                }
1004                //! returns the current string in the native form of std::wstring
1005                const std::wstring& asWStr() const {
1006                        _load_buffer_WStr();
1007                        return *m_buffer.mWStrBuffer;
1008                }
1009                //! returns the current string in the native form of a nul-terminated wchar_t array
1010                const wchar_t* asWStr_c_str() const {
1011                        _load_buffer_WStr();
1012                        return m_buffer.mWStrBuffer->c_str();
1013                }
1014                //@}
1015
1016                //////////////////////////////////////////////////////////////////////////
1017
1018                //!\name Single Character Access
1019                //@{
1020                //! returns a reference to the element in the string at index \c loc
1021                code_point& at( size_type loc ) {
1022                        return mData.at( loc );
1023                }
1024                //! returns a reference to the element in the string at index \c loc
1025                const code_point& at( size_type loc ) const {
1026                        return mData.at( loc );
1027                }
1028                //! returns the data point \a loc evaluated as a UTF-32 value
1029                /*! This function will will only properly decode surrogate pairs when \a loc points to the index
1030                of a lead code point that is followed by a trailing code point. Evaluating the trailing code point
1031                itself, or pointing to a code point that is a sentinel value (part of a broken pair) will return
1032                the value of just that code point (not a valid Unicode value, but useful as a sentinel value). */
1033                unicode_char getChar( size_type loc ) const {
1034                        const code_point* ptr = c_str();
1035                        unicode_char uc;
1036                        size_t l = _utf16_char_length( ptr[loc] );
1037                        code_point cp[2] = { /* blame the code beautifier */
1038                                                                   0, 0
1039                                                           };
1040                        cp[0] = ptr[loc];
1041
1042                        if ( l == 2 && ( loc + 1 ) < mData.length() ) {
1043                                cp[1] = ptr[loc+1];
1044                        }
1045                        _utf16_to_utf32( cp, uc );
1046                        return uc;
1047                }
1048                //! sets the value of the character at \a loc to the Unicode value \a ch (UTF-32)
1049                /*! Providing sentinel values (values between U+D800-U+DFFF) are accepted, but you should be aware
1050                that you can also unwittingly create a valid surrogate pair if you don't pay attention to what you
1051                are doing. \note This operation may also lengthen the string if a surrogate pair is needed to
1052                represent the value given, but one is not available to replace; or alternatively shorten the string
1053                if an existing surrogate pair is replaced with a character that is representable without a surrogate
1054                pair. The return value will signify any lengthening or shortening performed, returning 0 if no change
1055                was made, -1 if the string was shortened, or 1 if the string was lengthened. Any single call can
1056                only change the string length by + or - 1. */
1057                int setChar( size_type loc, unicode_char ch ) {
1058                        code_point cp[2] = { /* blame the code beautifier */
1059                                                                   0, 0
1060                                                           };
1061                        size_t l = _utf32_to_utf16( ch, cp );
1062                        unicode_char existingChar = getChar( loc );
1063                        size_t existingSize = _utf16_char_length( existingChar );
1064                        size_t newSize = _utf16_char_length( ch );
1065
1066                        if ( newSize > existingSize ) {
1067                                at( loc ) = cp[0];
1068                                insert( loc + 1, 1, cp[1] );
1069                                return 1;
1070                        }
1071                        if ( newSize < existingSize ) {
1072                                erase( loc, 1 );
1073                                at( loc ) = cp[0];
1074                                return -1;
1075                        }
1076
1077                        // newSize == existingSize
1078                        at( loc ) = cp[0];
1079                        if ( l == 2 ) at( loc + 1 ) = cp[1];
1080                        return 0;
1081                }
1082                //@}
1083
1084                //////////////////////////////////////////////////////////////////////////
1085
1086                //!\name iterator acquisition
1087                //@{
1088                //! returns an iterator to the first element of the string
1089                iterator begin() {
1090                        iterator i;
1091                        i.mIter = mData.begin();
1092                        i.mString = this;
1093                        return i;
1094                }
1095                //! returns an iterator to the first element of the string
1096                const_iterator begin() const {
1097                        const_iterator i;
1098                        i.mIter = const_cast<UTFString*>( this )->mData.begin();
1099                        i.mString = const_cast<UTFString*>( this );
1100                        return i;
1101                }
1102                //! returns an iterator just past the end of the string
1103                iterator end() {
1104                        iterator i;
1105                        i.mIter = mData.end();
1106                        i.mString = this;
1107                        return i;
1108                }
1109                //! returns an iterator just past the end of the string
1110                const_iterator end() const {
1111                        const_iterator i;
1112                        i.mIter = const_cast<UTFString*>( this )->mData.end();
1113                        i.mString = const_cast<UTFString*>( this );
1114                        return i;
1115                }
1116                //! returns a reverse iterator to the last element of the string
1117                reverse_iterator rbegin() {
1118                        reverse_iterator i;
1119                        i.mIter = mData.end();
1120                        i.mString = this;
1121                        return i;
1122                }
1123                //! returns a reverse iterator to the last element of the string
1124                const_reverse_iterator rbegin() const {
1125                        const_reverse_iterator i;
1126                        i.mIter = const_cast<UTFString*>( this )->mData.end();
1127                        i.mString = const_cast<UTFString*>( this );
1128                        return i;
1129                }
1130                //! returns a reverse iterator just past the beginning of the string
1131                reverse_iterator rend() {
1132                        reverse_iterator i;
1133                        i.mIter = mData.begin();
1134                        i.mString = this;
1135                        return i;
1136                }
1137                //! returns a reverse iterator just past the beginning of the string
1138                const_reverse_iterator rend() const {
1139                        const_reverse_iterator i;
1140                        i.mIter = const_cast<UTFString*>( this )->mData.begin();
1141                        i.mString = const_cast<UTFString*>( this );
1142                        return i;
1143                }
1144                //@}
1145
1146                //////////////////////////////////////////////////////////////////////////
1147
1148                //!\name assign
1149                //@{
1150                //! gives the current string the values from \a start to \a end
1151                UTFString& assign( iterator start, iterator end ) {
1152                        mData.assign( start.mIter, end.mIter );
1153                        return *this;
1154                }
1155                //! assign \a str to the current string
1156                UTFString& assign( const UTFString& str ) {
1157                        mData.assign( str.mData );
1158                        return *this;
1159                }
1160                //! assign the nul-terminated \a str to the current string
1161                UTFString& assign( const code_point* str ) {
1162                        mData.assign( str );
1163                        return *this;
1164                }
1165                //! assign the first \a num characters of \a str to the current string
1166                UTFString& assign( const code_point* str, size_type num ) {
1167                        mData.assign( str, num );
1168                        return *this;
1169                }
1170                //! assign \a len entries from \a str to the current string, starting at \a index
1171                UTFString& assign( const UTFString& str, size_type index, size_type len ) {
1172                        mData.assign( str.mData, index, len );
1173                        return *this;
1174                }
1175                //! assign \a num copies of \a ch to the current string
1176                UTFString& assign( size_type num, const code_point& ch ) {
1177                        mData.assign( num, ch );
1178                        return *this;
1179                }
1180                //! assign \a wstr to the current string (\a wstr is treated as a UTF-16 stream)
1181                UTFString& assign( const std::wstring& wstr ) {
1182                        mData.clear();
1183                        mData.reserve( wstr.length() ); // best guess bulk allocate
1184#ifdef WCHAR_UTF16 // if we're already working in UTF-16, this is easy
1185                        code_point tmp;
1186                        std::wstring::const_iterator i, ie = wstr.end();
1187                        for ( i = wstr.begin(); i != ie; i++ ) {
1188                                tmp = static_cast<code_point>( *i );
1189                                mData.push_back( tmp );
1190                        }
1191#else // otherwise we do it the safe way (which is still 100% safe to pass UTF-16 through, just slower)
1192                        code_point cp[3] = {0, 0, 0};
1193                        unicode_char tmp;
1194                        std::wstring::const_iterator i, ie = wstr.end();
1195                        for ( i = wstr.begin(); i != ie; i++ ) {
1196                                tmp = static_cast<unicode_char>( *i );
1197                                size_t l = _utf32_to_utf16( tmp, cp );
1198                                if ( l > 0 ) mData.push_back( cp[0] );
1199                                if ( l > 1 ) mData.push_back( cp[1] );
1200                        }
1201#endif
1202                        return *this;
1203                }
1204#if OGRE_IS_NATIVE_WCHAR_T
1205                //! assign \a w_str to the current string
1206                UTFString& assign( const wchar_t* w_str ) {
1207                        std::wstring tmp;
1208                        tmp.assign( w_str );
1209                        return assign( tmp );
1210                }
1211                //! assign the first \a num characters of \a w_str to the current string
1212                UTFString& assign( const wchar_t* w_str, size_type num ) {
1213                        std::wstring tmp;
1214                        tmp.assign( w_str, num );
1215                        return assign( tmp );
1216                }
1217#endif
1218                //! assign \a str to the current string (\a str is treated as a UTF-8 stream)
1219                UTFString& assign( const std::string& str ) {
1220                        size_type len = _verifyUTF8( str );
1221                        clear(); // empty our contents, if there are any
1222                        reserve( len ); // best guess bulk capacity growth
1223
1224                        // This is a 3 step process, converting each byte in the UTF-8 stream to UTF-32,
1225                        // then converting it to UTF-16, then finally appending the data buffer
1226
1227                        unicode_char uc;          // temporary Unicode character buffer
1228                        unsigned char utf8buf[7]; // temporary UTF-8 buffer
1229                        utf8buf[6] = 0;
1230                        size_t utf8len;           // UTF-8 length
1231                        code_point utf16buff[3];  // temporary UTF-16 buffer
1232                        utf16buff[2] = 0;
1233                        size_t utf16len;          // UTF-16 length
1234
1235                        std::string::const_iterator i, ie = str.end();
1236                        for ( i = str.begin(); i != ie; i++ ) {
1237                                utf8len = _utf8_char_length( static_cast<unsigned char>( *i ) ); // estimate bytes to load
1238                                for ( size_t j = 0; j < utf8len; j++ ) { // load the needed UTF-8 bytes
1239                                        utf8buf[j] = ( static_cast<unsigned char>( *( i + j ) ) ); // we don't increment 'i' here just in case the estimate is wrong (shouldn't happen, but we're being careful)
1240                                }
1241                                utf8buf[utf8len] = 0; // nul terminate so we throw an exception before running off the end of the buffer
1242                                utf8len = _utf8_to_utf32( utf8buf, uc ); // do the UTF-8 -> UTF-32 conversion
1243                                i += utf8len - 1; // we subtract 1 for the increment of the 'for' loop
1244
1245                                utf16len = _utf32_to_utf16( uc, utf16buff ); // UTF-32 -> UTF-16 conversion
1246                                append( utf16buff, utf16len ); // append the characters to the string
1247                        }
1248                        return *this;
1249                }
1250                //! assign \a c_str to the current string (\a c_str is treated as a UTF-8 stream)
1251                UTFString& assign( const char* c_str ) {
1252                        std::string tmp( c_str );
1253                        return assign( tmp );
1254                }
1255                //! assign the first \a num characters of \a c_str to the current string (\a c_str is treated as a UTF-8 stream)
1256                UTFString& assign( const char* c_str, size_type num ) {
1257                        std::string tmp;
1258                        tmp.assign( c_str, num );
1259                        return assign( tmp );
1260                }
1261                //@}
1262
1263                //////////////////////////////////////////////////////////////////////////
1264
1265                //!\name append
1266                //@{
1267                //! appends \a str on to the end of the current string
1268                UTFString& append( const UTFString& str ) {
1269                        mData.append( str.mData );
1270                        return *this;
1271                }
1272                //! appends \a str on to the end of the current string
1273                UTFString& append( const code_point* str ) {
1274                        mData.append( str );
1275                        return *this;
1276                }
1277                //! appends a substring of \a str starting at \a index that is \a len characters long on to the end of the current string
1278                UTFString& append( const UTFString& str, size_type index, size_type len ) {
1279                        mData.append( str.mData, index, len );
1280                        return *this;
1281                }
1282                //! appends \a num characters of \a str on to the end of the current string
1283                UTFString& append( const code_point* str, size_type num ) {
1284                        mData.append( str, num );
1285                        return *this;
1286                }
1287                //! appends \a num repetitions of \a ch on to the end of the current string
1288                UTFString& append( size_type num, code_point ch ) {
1289                        mData.append( num, ch );
1290                        return *this;
1291                }
1292                //! appends the sequence denoted by \a start and \a end on to the end of the current string
1293                UTFString& append( iterator start, iterator end ) {
1294                        mData.append( start.mIter, end.mIter );
1295                        return *this;
1296                }
1297#if OGRE_IS_NATIVE_WCHAR_T
1298                //! appends \a num characters of \a str on to the end of the current string
1299                UTFString& append( const wchar_t* w_str, size_type num ) {
1300                        std::wstring tmp( w_str, num );
1301                        return append( tmp );
1302                }
1303                //! appends \a num repetitions of \a ch on to the end of the current string
1304                UTFString& append( size_type num, wchar_t ch ) {
1305                        return append( num, static_cast<unicode_char>( ch ) );
1306                }
1307#endif
1308                //! appends \a num characters of \a str on to the end of the current string  (UTF-8 encoding)
1309                UTFString& append( const char* c_str, size_type num ) {
1310                        UTFString tmp( c_str, num );
1311                        append( tmp );
1312                        return *this;
1313                }
1314                //! appends \a num repetitions of \a ch on to the end of the current string (Unicode values less than 128)
1315                UTFString& append( size_type num, char ch ) {
1316                        append( num, static_cast<code_point>( ch ) );
1317                        return *this;
1318                }
1319                //! appends \a num repetitions of \a ch on to the end of the current string (Full Unicode spectrum)
1320                UTFString& append( size_type num, unicode_char ch ) {
1321                        code_point cp[2] = {0, 0};
1322                        if ( _utf32_to_utf16( ch, cp ) == 2 ) {
1323                                for ( size_type i = 0; i < num; i++ ) {
1324                                        append( 1, cp[0] );
1325                                        append( 1, cp[1] );
1326                                }
1327                        } else {
1328                                for ( size_type i = 0; i < num; i++ ) {
1329                                        append( 1, cp[0] );
1330                                }
1331                        }
1332                        return *this;
1333                }
1334                //@}
1335
1336                //////////////////////////////////////////////////////////////////////////
1337
1338                //!\name insert
1339                //@{
1340                //! inserts \a ch before the code point denoted by \a i
1341                iterator insert( iterator i, const code_point& ch ) {
1342                        iterator ret;
1343                        ret.mIter = mData.insert( i.mIter, ch );
1344                        ret.mString = this;
1345                        return ret;
1346                }
1347                //! inserts \a str into the current string, at location \a index
1348                UTFString& insert( size_type index, const UTFString& str ) {
1349                        mData.insert( index, str.mData );
1350                        return *this;
1351                }
1352                //! inserts \a str into the current string, at location \a index
1353                UTFString& insert( size_type index, const code_point* str ) {
1354                        mData.insert( index, str );
1355                        return *this;
1356                }
1357                //! inserts a substring of \a str (starting at \a index2 and \a num code points long) into the current string, at location \a index1
1358                UTFString& insert( size_type index1, const UTFString& str, size_type index2, size_type num ) {
1359                        mData.insert( index1, str.mData, index2, num );
1360                        return *this;
1361                }
1362                //! inserts the code points denoted by \a start and \a end into the current string, before the code point specified by \a i
1363                void insert( iterator i, iterator start, iterator end ) {
1364                        mData.insert( i.mIter, start.mIter, end.mIter );
1365                }
1366                //! inserts \a num code points of \a str into the current string, at location \a index
1367                UTFString& insert( size_type index, const code_point* str, size_type num ) {
1368                        mData.insert( index, str, num );
1369                        return *this;
1370                }
1371#if OGRE_IS_NATIVE_WCHAR_T
1372                //! inserts \a num code points of \a str into the current string, at location \a index
1373                UTFString& insert( size_type index, const wchar_t* w_str, size_type num ) {
1374                        UTFString tmp( w_str, num );
1375                        insert( index, tmp );
1376                        return *this;
1377                }
1378#endif
1379                //! inserts \a num code points of \a str into the current string, at location \a index
1380                UTFString& insert( size_type index, const char* c_str, size_type num ) {
1381                        UTFString tmp( c_str, num );
1382                        insert( index, tmp );
1383                        return *this;
1384                }
1385                //! inserts \a num copies of \a ch into the current string, at location \a index
1386                UTFString& insert( size_type index, size_type num, code_point ch ) {
1387                        mData.insert( index, num, ch );
1388                        return *this;
1389                }
1390#if OGRE_IS_NATIVE_WCHAR_T
1391                //! inserts \a num copies of \a ch into the current string, at location \a index
1392                UTFString& insert( size_type index, size_type num, wchar_t ch ) {
1393                        insert( index, num, static_cast<unicode_char>( ch ) );
1394                        return *this;
1395                }
1396#endif
1397                //! inserts \a num copies of \a ch into the current string, at location \a index
1398                UTFString& insert( size_type index, size_type num, char ch ) {
1399                        insert( index, num, static_cast<code_point>( ch ) );
1400                        return *this;
1401                }
1402                //! inserts \a num copies of \a ch into the current string, at location \a index
1403                UTFString& insert( size_type index, size_type num, unicode_char ch ) {
1404                        code_point cp[3] = {0, 0, 0};
1405                        size_t l = _utf32_to_utf16( ch, cp );
1406                        if ( l == 1 ) {
1407                                return insert( index, num, cp[0] );
1408                        }
1409                        for ( size_type c = 0; c < num; c++ ) {
1410                                // insert in reverse order to preserve ordering after insert
1411                                insert( index, 1, cp[1] );
1412                                insert( index, 1, cp[0] );
1413                        }
1414                        return *this;
1415                }
1416                //! inserts \a num copies of \a ch into the current string, before the code point denoted by \a i
1417                void insert( iterator i, size_type num, const code_point& ch ) {
1418                        mData.insert( i.mIter, num, ch );
1419                }
1420#if OGRE_IS_NATIVE_WCHAR_T
1421                //! inserts \a num copies of \a ch into the current string, before the code point denoted by \a i
1422                void insert( iterator i, size_type num, const wchar_t& ch ) {
1423                        insert( i, num, static_cast<unicode_char>( ch ) );
1424                }
1425#endif
1426                //! inserts \a num copies of \a ch into the current string, before the code point denoted by \a i
1427                void insert( iterator i, size_type num, const char& ch ) {
1428                        insert( i, num, static_cast<code_point>( ch ) );
1429                }
1430                //! inserts \a num copies of \a ch into the current string, before the code point denoted by \a i
1431                void insert( iterator i, size_type num, const unicode_char& ch ) {
1432                        code_point cp[3] = {0, 0, 0};
1433                        size_t l = _utf32_to_utf16( ch, cp );
1434                        if ( l == 1 ) {
1435                                insert( i, num, cp[0] );
1436                        } else {
1437                                for ( size_type c = 0; c < num; c++ ) {
1438                                        // insert in reverse order to preserve ordering after insert
1439                                        insert( i, 1, cp[1] );
1440                                        insert( i, 1, cp[0] );
1441                                }
1442                        }
1443                }
1444                //@}
1445
1446                //////////////////////////////////////////////////////////////////////////
1447
1448                //!\name erase
1449                //@{
1450                //! removes the code point pointed to by \a loc, returning an iterator to the next character
1451                iterator erase( iterator loc ) {
1452                        iterator ret;
1453                        ret.mIter = mData.erase( loc.mIter );
1454                        ret.mString = this;
1455                        return ret;
1456                }
1457                //! removes the code points between \a start and \a end (including the one at \a start but not the one at \a end), returning an iterator to the code point after the last code point removed
1458                iterator erase( iterator start, iterator end ) {
1459                        iterator ret;
1460                        ret.mIter = mData.erase( start.mIter, end.mIter );
1461                        ret.mString = this;
1462                        return ret;
1463                }
1464                //! removes \a num code points from the current string, starting at \a index
1465                UTFString& erase( size_type index = 0, size_type num = npos ) {
1466                        if ( num == npos )
1467                                mData.erase( index );
1468                        else
1469                                mData.erase( index, num );
1470                        return *this;
1471                }
1472                //@}
1473
1474                //////////////////////////////////////////////////////////////////////////
1475
1476                //!\name replace
1477                //@{
1478                //! replaces up to \a num1 code points of the current string (starting at \a index1) with \a str
1479                UTFString& replace( size_type index1, size_type num1, const UTFString& str ) {
1480                        mData.replace( index1, num1, str.mData, 0, npos );
1481                        return *this;
1482                }
1483                //! replaces up to \a num1 code points of the current string (starting at \a index1) with up to \a num2 code points from \a str
1484                UTFString& replace( size_type index1, size_type num1, const UTFString& str, size_type num2 ) {
1485                        mData.replace( index1, num1, str.mData, 0, num2 );
1486                        return *this;
1487                }
1488                //! replaces up to \a num1 code points of the current string (starting at \a index1) with up to \a num2 code points from \a str beginning at \a index2
1489                UTFString& replace( size_type index1, size_type num1, const UTFString& str, size_type index2, size_type num2 ) {
1490                        mData.replace( index1, num1, str.mData, index2, num2 );
1491                        return *this;
1492                }
1493                //! replaces code points in the current string from \a start to \a end with \a num code points from \a str
1494                UTFString& replace( iterator start, iterator end, const UTFString& str, size_type num = npos ) {
1495                        _const_fwd_iterator st(start); //Work around for gcc, allow it to find correct overload
1496
1497                        size_type index1 = begin() - st;
1498                        size_type num1 = end - st;
1499                        return replace( index1, num1, str, 0, num );
1500                }
1501                //! replaces up to \a num1 code points in the current string (beginning at \a index) with \c num2 copies of \c ch
1502                UTFString& replace( size_type index, size_type num1, size_type num2, code_point ch ) {
1503                        mData.replace( index, num1, num2, ch );
1504                        return *this;
1505                }
1506                //! replaces the code points in the current string from \a start to \a end with \a num copies of \a ch
1507                UTFString& replace( iterator start, iterator end, size_type num, code_point ch ) {
1508                        _const_fwd_iterator st(start); //Work around for gcc, allow it to find correct overload
1509
1510                        size_type index1 = begin() - st;
1511                        size_type num1 = end - st;
1512                        return replace( index1, num1, num, ch );
1513                }
1514                //@}
1515
1516                //////////////////////////////////////////////////////////////////////////
1517
1518                //!\name compare
1519                //@{
1520                //! compare \a str to the current string
1521                int compare( const UTFString& str ) const {
1522                        return mData.compare( str.mData );
1523                }
1524                //! compare \a str to the current string
1525                int compare( const code_point* str ) const {
1526                        return mData.compare( str );
1527                }
1528                //! compare \a str to a substring of the current string, starting at \a index for \a length characters
1529                int compare( size_type index, size_type length, const UTFString& str ) const {
1530                        return mData.compare( index, length, str.mData );
1531                }
1532                //! compare a substring of \a str to a substring of the current string, where \a index2 and \a length2 refer to \a str and \a index and \a length refer to the current string
1533                int compare( size_type index, size_type length, const UTFString& str, size_type index2, size_type length2 ) const {
1534                        return mData.compare( index, length, str.mData, index2, length2 );
1535                }
1536                //! compare a substring of \a str to a substring of the current string, where the substring of \a str begins at zero and is \a length2 characters long, and the substring of the current string begins at \a index and is \a length  characters long
1537                int compare( size_type index, size_type length, const code_point* str, size_type length2 ) const {
1538                        return mData.compare( index, length, str, length2 );
1539                }
1540#if OGRE_IS_NATIVE_WCHAR_T
1541                //! compare a substring of \a str to a substring of the current string, where the substring of \a str begins at zero and is \a length2 elements long, and the substring of the current string begins at \a index and is \a length characters long
1542                int compare( size_type index, size_type length, const wchar_t* w_str, size_type length2 ) const {
1543                        UTFString tmp( w_str, length2 );
1544                        return compare( index, length, tmp );
1545                }
1546#endif
1547                //! compare a substring of \a str to a substring of the current string, where the substring of \a str begins at zero and is \a length2 <b>UTF-8 code points</b> long, and the substring of the current string begins at \a index and is \a length characters long
1548                int compare( size_type index, size_type length, const char* c_str, size_type length2 ) const {
1549                        UTFString tmp( c_str, length2 );
1550                        return compare( index, length, tmp );
1551                }
1552                //@}
1553
1554                //////////////////////////////////////////////////////////////////////////
1555
1556                //!\name find & rfind
1557                //@{
1558                //! returns the index of the first occurrence of \a str within the current string, starting at \a index; returns \c UTFString::npos if nothing is found
1559                /*! \a str is a UTF-16 encoded string, but through implicit casting can also be a UTF-8 encoded string (const char* or std::string) */
1560                size_type find( const UTFString& str, size_type index = 0 ) const {
1561                        return mData.find( str.c_str(), index );
1562                }
1563                //! returns the index of the first occurrence of \a str within the current string and within \a length code points, starting at \a index; returns \c UTFString::npos if nothing is found
1564                /*! \a cp_str is a UTF-16 encoded string */
1565                size_type find( const code_point* cp_str, size_type index, size_type length ) const {
1566                        UTFString tmp( cp_str );
1567                        return mData.find( tmp.c_str(), index, length );
1568                }
1569                //! returns the index of the first occurrence of \a str within the current string and within \a length code points, starting at \a index; returns \c UTFString::npos if nothing is found
1570                /*! \a cp_str is a UTF-8 encoded string */
1571                size_type find( const char* c_str, size_type index, size_type length ) const {
1572                        UTFString tmp( c_str );
1573                        return mData.find( tmp.c_str(), index, length );
1574                }
1575#if OGRE_IS_NATIVE_WCHAR_T
1576                //! returns the index of the first occurrence of \a str within the current string and within \a length code points, starting at \a index; returns \c UTFString::npos if nothing is found
1577                /*! \a cp_str is a UTF-16 encoded string */
1578                size_type find( const wchar_t* w_str, size_type index, size_type length ) const {
1579                        UTFString tmp( w_str );
1580                        return mData.find( tmp.c_str(), index, length );
1581                }
1582#endif
1583                //! returns the index of the first occurrence \a ch within the current string, starting at \a index; returns \c UTFString::npos if nothing is found
1584                /*! \a ch is only capable of representing Unicode values up to U+007F (127) */
1585                size_type find( char ch, size_type index = 0 ) const {
1586                        return find( static_cast<code_point>( ch ), index );
1587                }
1588                //! returns the index of the first occurrence \a ch within the current string, starting at \a index; returns \c UTFString::npos if nothing is found
1589                /*! \a ch is only capable of representing Unicode values up to U+FFFF (65535) */
1590                size_type find( code_point ch, size_type index = 0 ) const {
1591                        return mData.find( ch, index );
1592                }
1593#if OGRE_IS_NATIVE_WCHAR_T
1594                //! returns the index of the first occurrence \a ch within the current string, starting at \a index; returns \c UTFString::npos if nothing is found
1595                /*! \a ch is only capable of representing Unicode values up to U+FFFF (65535) */
1596                size_type find( wchar_t ch, size_type index = 0 ) const {
1597                        return find( static_cast<unicode_char>( ch ), index );
1598                }
1599#endif
1600                //! returns the index of the first occurrence \a ch within the current string, starting at \a index; returns \c UTFString::npos if nothing is found
1601                /*! \a ch can fully represent any Unicode character */
1602                size_type find( unicode_char ch, size_type index = 0 ) const {
1603                        code_point cp[3] = {0, 0, 0};
1604                        size_t l = _utf32_to_utf16( ch, cp );
1605                        return find( UTFString( cp, l ), index );
1606                }
1607
1608                //! returns the location of the first occurrence of \a str in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1609                size_type rfind( const UTFString& str, size_type index = 0 ) const {
1610                        return mData.rfind( str.c_str(), index );
1611                }
1612                //! returns the location of the first occurrence of \a str in the current string, doing a reverse search from \a index, searching at most \a num characters; returns \c UTFString::npos if nothing is found
1613                size_type rfind( const code_point* cp_str, size_type index, size_type num ) const {
1614                        UTFString tmp( cp_str );
1615                        return mData.rfind( tmp.c_str(), index, num );
1616                }
1617                //! returns the location of the first occurrence of \a str in the current string, doing a reverse search from \a index, searching at most \a num characters; returns \c UTFString::npos if nothing is found
1618                size_type rfind( const char* c_str, size_type index, size_type num ) const {
1619                        UTFString tmp( c_str );
1620                        return mData.rfind( tmp.c_str(), index, num );
1621                }
1622#if OGRE_IS_NATIVE_WCHAR_T
1623                //! returns the location of the first occurrence of \a str in the current string, doing a reverse search from \a index, searching at most \a num characters; returns \c UTFString::npos if nothing is found
1624                size_type rfind( const wchar_t* w_str, size_type index, size_type num ) const {
1625                        UTFString tmp( w_str );
1626                        return mData.rfind( tmp.c_str(), index, num );
1627                }
1628#endif
1629                //! returns the location of the first occurrence of \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1630                size_type rfind( char ch, size_type index = 0 ) const {
1631                        return rfind( static_cast<code_point>( ch ), index );
1632                }
1633                //! returns the location of the first occurrence of \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1634                size_type rfind( code_point ch, size_type index ) const {
1635                        return mData.rfind( ch, index );
1636                }
1637#if OGRE_IS_NATIVE_WCHAR_T
1638                //! returns the location of the first occurrence of \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1639                size_type rfind( wchar_t ch, size_type index = 0 ) const {
1640                        return rfind( static_cast<unicode_char>( ch ), index );
1641                }
1642#endif
1643                //! returns the location of the first occurrence of \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1644                size_type rfind( unicode_char ch, size_type index = 0 ) const {
1645                        code_point cp[3] = {0, 0, 0};
1646                        size_t l = _utf32_to_utf16( ch, cp );
1647                        return rfind( UTFString( cp, l ), index );
1648                }
1649                //@}
1650
1651                //////////////////////////////////////////////////////////////////////////
1652
1653                //!\name find_first/last_(not)_of
1654                //@{
1655                //! Returns the index of the first character within the current string that matches \b any character in \a str, beginning the search at \a index and searching at most \a num characters; returns \c UTFString::npos if nothing is found
1656                size_type find_first_of( const UTFString &str, size_type index = 0, size_type num = npos ) const {
1657                        size_type i = 0;
1658                        const size_type len = length();
1659                        while ( i < num && ( index + i ) < len ) {
1660                                unicode_char ch = getChar( index + i );
1661                                if ( str.inString( ch ) )
1662                                        return index + i;
1663                                i += _utf16_char_length( ch ); // increment by the Unicode character length
1664                        }
1665                        return npos;
1666                }
1667                //! returns the index of the first occurrence of \a ch in the current string, starting the search at \a index; returns \c UTFString::npos if nothing is found
1668                size_type find_first_of( code_point ch, size_type index = 0 ) const {
1669                        UTFString tmp;
1670                        tmp.assign( 1, ch );
1671                        return find_first_of( tmp, index );
1672                }
1673                //! returns the index of the first occurrence of \a ch in the current string, starting the search at \a index; returns \c UTFString::npos if nothing is found
1674                size_type find_first_of( char ch, size_type index = 0 ) const {
1675                        return find_first_of( static_cast<code_point>( ch ), index );
1676                }
1677#if OGRE_IS_NATIVE_WCHAR_T
1678                //! returns the index of the first occurrence of \a ch in the current string, starting the search at \a index; returns \c UTFString::npos if nothing is found
1679                size_type find_first_of( wchar_t ch, size_type index = 0 ) const {
1680                        return find_first_of( static_cast<unicode_char>( ch ), index );
1681                }
1682#endif
1683                //! returns the index of the first occurrence of \a ch in the current string, starting the search at \a index; returns \c UTFString::npos if nothing is found
1684                size_type find_first_of( unicode_char ch, size_type index = 0 ) const {
1685                        code_point cp[3] = {0, 0, 0};
1686                        size_t l = _utf32_to_utf16( ch, cp );
1687                        return find_first_of( UTFString( cp, l ), index );
1688                }
1689
1690                //! returns the index of the first character within the current string that does not match any character in \a str, beginning the search at \a index and searching at most \a num characters; returns \c UTFString::npos if nothing is found
1691                size_type find_first_not_of( const UTFString& str, size_type index = 0, size_type num = npos ) const {
1692                        size_type i = 0;
1693                        const size_type len = length();
1694                        while ( i < num && ( index + i ) < len ) {
1695                                unicode_char ch = getChar( index + i );
1696                                if ( !str.inString( ch ) )
1697                                        return index + i;
1698                                i += _utf16_char_length( ch ); // increment by the Unicode character length
1699                        }
1700                        return npos;
1701                }
1702                //! returns the index of the first character within the current string that does not match \a ch, starting the search at \a index; returns \c UTFString::npos if nothing is found
1703                size_type find_first_not_of( code_point ch, size_type index = 0 ) const {
1704                        UTFString tmp;
1705                        tmp.assign( 1, ch );
1706                        return find_first_not_of( tmp, index );
1707                }
1708                //! returns the index of the first character within the current string that does not match \a ch, starting the search at \a index; returns \c UTFString::npos if nothing is found
1709                size_type find_first_not_of( char ch, size_type index = 0 ) const {
1710                        return find_first_not_of( static_cast<code_point>( ch ), index );
1711                }
1712#if OGRE_IS_NATIVE_WCHAR_T
1713                //! returns the index of the first character within the current string that does not match \a ch, starting the search at \a index; returns \c UTFString::npos if nothing is found
1714                size_type find_first_not_of( wchar_t ch, size_type index = 0 ) const {
1715                        return find_first_not_of( static_cast<unicode_char>( ch ), index );
1716                }
1717#endif
1718                //! returns the index of the first character within the current string that does not match \a ch, starting the search at \a index; returns \c UTFString::npos if nothing is found
1719                size_type find_first_not_of( unicode_char ch, size_type index = 0 ) const {
1720                        code_point cp[3] = {0, 0, 0};
1721                        size_t l = _utf32_to_utf16( ch, cp );
1722                        return find_first_not_of( UTFString( cp, l ), index );
1723                }
1724
1725                //! returns the index of the first character within the current string that matches any character in \a str, doing a reverse search from \a index and searching at most \a num characters; returns \c UTFString::npos if nothing is found
1726                size_type find_last_of( const UTFString& str, size_type index = npos, size_type num = npos ) const {
1727                        size_type i = 0;
1728                        const size_type len = length();
1729                        if ( index > len ) index = len - 1;
1730
1731                        while ( i < num && ( index - i ) != npos ) {
1732                                size_type j = index - i;
1733                                // careful to step full Unicode characters
1734                                if ( j != 0 && _utf16_surrogate_follow( at( j ) ) && _utf16_surrogate_lead( at( j - 1 ) ) ) {
1735                                        j = index - ++i;
1736                                }
1737                                // and back to the usual dull test
1738                                unicode_char ch = getChar( j );
1739                                if ( str.inString( ch ) )
1740                                        return j;
1741                                i++;
1742                        }
1743                        return npos;
1744                }
1745                //! returns the index of the first occurrence of \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1746                size_type find_last_of( code_point ch, size_type index = npos ) const {
1747                        UTFString tmp;
1748                        tmp.assign( 1, ch );
1749                        return find_last_of( tmp, index );
1750                }
1751                //! returns the index of the first occurrence of \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1752                size_type find_last_of( char ch, size_type index = npos ) const {
1753                        return find_last_of( static_cast<code_point>( ch ), index );
1754                }
1755#if OGRE_IS_NATIVE_WCHAR_T
1756                //! returns the index of the first occurrence of \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1757                size_type find_last_of( wchar_t ch, size_type index = npos ) const {
1758                        return find_last_of( static_cast<unicode_char>( ch ), index );
1759                }
1760#endif
1761                //! returns the index of the first occurrence of \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1762                size_type find_last_of( unicode_char ch, size_type index = npos ) const {
1763                        code_point cp[3] = {0, 0, 0};
1764                        size_t l = _utf32_to_utf16( ch, cp );
1765                        return find_last_of( UTFString( cp, l ), index );
1766                }
1767
1768                //! returns the index of the last character within the current string that does not match any character in \a str, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1769                size_type find_last_not_of( const UTFString& str, size_type index = npos, size_type num = npos ) const {
1770                        size_type i = 0;
1771                        const size_type len = length();
1772                        if ( index > len ) index = len - 1;
1773
1774                        while ( i < num && ( index - i ) != npos ) {
1775                                size_type j = index - i;
1776                                // careful to step full Unicode characters
1777                                if ( j != 0 && _utf16_surrogate_follow( at( j ) ) && _utf16_surrogate_lead( at( j - 1 ) ) ) {
1778                                        j = index - ++i;
1779                                }
1780                                // and back to the usual dull test
1781                                unicode_char ch = getChar( j );
1782                                if ( !str.inString( ch ) )
1783                                        return j;
1784                                i++;
1785                        }
1786                        return npos;
1787                }
1788                //! returns the index of the last occurrence of a character that does not match \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1789                size_type find_last_not_of( code_point ch, size_type index = npos ) const {
1790                        UTFString tmp;
1791                        tmp.assign( 1, ch );
1792                        return find_last_not_of( tmp, index );
1793                }
1794                //! returns the index of the last occurrence of a character that does not match \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1795                size_type find_last_not_of( char ch, size_type index = npos ) const {
1796                        return find_last_not_of( static_cast<code_point>( ch ), index );
1797                }
1798#if OGRE_IS_NATIVE_WCHAR_T
1799                //! returns the index of the last occurrence of a character that does not match \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1800                size_type find_last_not_of( wchar_t ch, size_type index = npos ) const {
1801                        return find_last_not_of( static_cast<unicode_char>( ch ), index );
1802                }
1803#endif
1804                //! returns the index of the last occurrence of a character that does not match \a ch in the current string, doing a reverse search from \a index; returns \c UTFString::npos if nothing is found
1805                size_type find_last_not_of( unicode_char ch, size_type index = npos ) const {
1806                        code_point cp[3] = {0, 0, 0};
1807                        size_t l = _utf32_to_utf16( ch, cp );
1808                        return find_last_not_of( UTFString( cp, l ), index );
1809                }
1810                //@}
1811
1812                //////////////////////////////////////////////////////////////////////////
1813
1814                //!\name Operators
1815                //@{
1816                //! less than operator
1817                bool operator<( const UTFString& right ) const {
1818                        return compare( right ) < 0;
1819                }
1820                //! less than or equal operator
1821                bool operator<=( const UTFString& right ) const {
1822                        return compare( right ) <= 0;
1823                }
1824                //! greater than operator
1825                bool operator>( const UTFString& right ) const {
1826                        return compare( right ) > 0;
1827                }
1828                //! greater than or equal operator
1829                bool operator>=( const UTFString& right ) const {
1830                        return compare( right ) >= 0;
1831                }
1832                //! equality operator
1833                bool operator==( const UTFString& right ) const {
1834                        return compare( right ) == 0;
1835                }
1836                //! inequality operator
1837                bool operator!=( const UTFString& right ) const {
1838                        return !operator==( right );
1839                }
1840                //! assignment operator, implicitly casts all compatible types
1841                UTFString& operator=( const UTFString& s ) {
1842                        return assign( s );
1843                }
1844                //! assignment operator
1845                UTFString& operator=( code_point ch ) {
1846                        clear();
1847                        return append( 1, ch );
1848                }
1849                //! assignment operator
1850                UTFString& operator=( char ch ) {
1851                        clear();
1852                        return append( 1, ch );
1853                }
1854#if OGRE_IS_NATIVE_WCHAR_T
1855                //! assignment operator
1856                UTFString& operator=( wchar_t ch ) {
1857                        clear();
1858                        return append( 1, ch );
1859                }
1860#endif
1861                //! assignment operator
1862                UTFString& operator=( unicode_char ch ) {
1863                        clear();
1864                        return append( 1, ch );
1865                }
1866                //! code point dereference operator
1867                code_point& operator[]( size_type index ) {
1868                        return at( index );
1869                }
1870                //! code point dereference operator
1871                const code_point& operator[]( size_type index ) const {
1872                        return at( index );
1873                }
1874                //@}
1875
1876                //////////////////////////////////////////////////////////////////////////
1877
1878                //!\name Implicit Cast Operators
1879                //@{
1880                //! implicit cast to std::string
1881                operator std::string() const {
1882                        return std::string( asUTF8() );
1883                }
1884                //! implicit cast to std::wstring
1885                operator std::wstring() const {
1886                        return std::wstring( asWStr() );
1887                }
1888                //@}
1889
1890                //////////////////////////////////////////////////////////////////////////
1891
1892                //!\name UTF-16 character encoding/decoding
1893                //@{
1894                //! returns \c true if \a cp does not match the signature for the lead of follow code point of a surrogate pair in a UTF-16 sequence
1895                static bool _utf16_independent_char( code_point cp ) {
1896                        if ( 0xD800 <= cp && cp <= 0xDFFF ) // tests if the cp is within the surrogate pair range
1897                                return false; // it matches a surrogate pair signature
1898                        return true; // everything else is a standalone code point
1899                }
1900                //! returns \c true if \a cp matches the signature of a surrogate pair lead character
1901                static bool _utf16_surrogate_lead( code_point cp ) {
1902                        if ( 0xD800 <= cp && cp <= 0xDBFF ) // tests if the cp is within the 2nd word of a surrogate pair
1903                                return true; // it is a 1st word
1904                        return false; // it isn't
1905                }
1906                //! returns \c true if \a cp matches the signature of a surrogate pair following character
1907                static bool _utf16_surrogate_follow( code_point cp ) {
1908                        if ( 0xDC00 <= cp && cp <= 0xDFFF ) // tests if the cp is within the 2nd word of a surrogate pair
1909                                return true; // it is a 2nd word
1910                        return false; // everything else isn't
1911                }
1912                //! estimates the number of UTF-16 code points in the sequence starting with \a cp
1913                static size_t _utf16_char_length( code_point cp ) {
1914                        if ( 0xD800 <= cp && cp <= 0xDBFF ) // test if cp is the beginning of a surrogate pair
1915                                return 2; // if it is, then we are 2 words long
1916                        return 1; // otherwise we are only 1 word long
1917                }
1918                //! returns the number of UTF-16 code points needed to represent the given UTF-32 character \a cp
1919                static size_t _utf16_char_length( unicode_char uc ) {
1920                        if ( uc > 0xFFFF ) // test if uc is greater than the single word maximum
1921                                return 2; // if so, we need a surrogate pair
1922                        return 1; // otherwise we can stuff it into a single word
1923                }
1924                //! converts the given UTF-16 character buffer \a in_cp to a single UTF-32 Unicode character \a out_uc, returns the number of code points used to create the output character (2 for surrogate pairs, otherwise 1)
1925                /*! This function does it's best to prevent error conditions, verifying complete
1926                surrogate pairs before applying the algorithm. In the event that half of a pair
1927                is found it will happily generate a value in the 0xD800 - 0xDFFF range, which is
1928                normally an invalid Unicode value but we preserve them for use as sentinel values. */
1929                static size_t _utf16_to_utf32( const code_point in_cp[2], unicode_char& out_uc ) {
1930                        const code_point& cp1 = in_cp[0];
1931                        const code_point& cp2 = in_cp[1];
1932                        bool wordPair = false;
1933
1934                        // does it look like a surrogate pair?
1935                        if ( 0xD800 <= cp1 && cp1 <= 0xDBFF ) {
1936                                // looks like one, but does the other half match the algorithm as well?
1937                                if ( 0xDC00 <= cp2 && cp2 <= 0xDFFF )
1938                                        wordPair = true; // yep!
1939                        }
1940
1941                        if ( !wordPair ) { // if we aren't a 100% authentic surrogate pair, then just copy the value
1942                                out_uc = cp1;
1943                                return 1;
1944                        }
1945
1946                        unsigned short cU = cp1, cL = cp2; // copy upper and lower words of surrogate pair to writable buffers
1947                        cU -= 0xD800; // remove the encoding markers
1948                        cL -= 0xDC00;
1949
1950                        out_uc = ( cU & 0x03FF ) << 10; // grab the 10 upper bits and set them in their proper location
1951                        out_uc |= ( cL & 0x03FF ); // combine in the lower 10 bits
1952                        out_uc += 0x10000; // add back in the value offset
1953
1954                        return 2; // this whole operation takes to words, so that's what we'll return
1955                }
1956                //! writes the given UTF-32 \a uc_in to the buffer location \a out_cp using UTF-16 encoding, returns the number of code points used to encode the input (always 1 or 2)
1957                /*! This function, like its counterpart, will happily create invalid UTF-16 surrogate pairs. These
1958                invalid entries will be created for any value of \c in_uc that falls in the range U+D800 - U+DFFF.
1959                These are generally useful as sentinel values to represent various program specific conditions.
1960                \note This function will also pass through any single UTF-16 code point without modification,
1961                making it a safe method of ensuring a stream that is unknown UTF-32 or UTF-16 is truly UTF-16.*/
1962                static size_t _utf32_to_utf16( const unicode_char& in_uc, code_point out_cp[2] ) {
1963                        if ( in_uc <= 0xFFFF ) { // we blindly preserve sentinel values because our decoder understands them
1964                                out_cp[0] = in_uc;
1965                                return 1;
1966                        }
1967                        unicode_char uc = in_uc; // copy to writable buffer
1968                        unsigned short tmp; // single code point buffer
1969                        uc -= 0x10000; // subtract value offset
1970
1971                        //process upper word
1972                        tmp = ( uc >> 10 ) & 0x03FF; // grab the upper 10 bits
1973                        tmp += 0xD800; // add encoding offset
1974                        out_cp[0] = tmp; // write
1975
1976                        // process lower word
1977                        tmp = uc & 0x03FF; // grab the lower 10 bits
1978                        tmp += 0xDC00; // add encoding offset
1979                        out_cp[1] = tmp; // write
1980
1981                        return 2; // return used word count (2 for surrogate pairs)
1982                }
1983                //@}
1984
1985                //////////////////////////////////////////////////////////////////////////
1986
1987                //!\name UTF-8 character encoding/decoding
1988                //@{
1989                //! returns \c true if \a cp is the beginning of a UTF-8 sequence
1990                static bool _utf8_start_char( unsigned char cp ) {
1991                        return ( cp & ~_cont_mask ) != _cont;
1992                }
1993                //! estimates the number of UTF-8 code points in the sequence starting with \a cp
1994                static size_t _utf8_char_length( unsigned char cp ) {
1995                        if ( !( cp & 0x80 ) ) return 1;
1996                        if (( cp & ~_lead1_mask ) == _lead1 ) return 2;
1997                        if (( cp & ~_lead2_mask ) == _lead2 ) return 3;
1998                        if (( cp & ~_lead3_mask ) == _lead3 ) return 4;
1999                        if (( cp & ~_lead4_mask ) == _lead4 ) return 5;
2000                        if (( cp & ~_lead5_mask ) == _lead5 ) return 6;
2001                        throw invalid_data( "invalid UTF-8 sequence header value" );
2002                }
2003                //! returns the number of UTF-8 code points needed to represent the given UTF-32 character \a cp
2004                static size_t _utf8_char_length( unicode_char uc ) {
2005                        /*
2006                        7 bit:  U-00000000 - U-0000007F: 0xxxxxxx
2007                        11 bit: U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
2008                        16 bit: U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
2009                        21 bit: U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
2010                        26 bit: U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
2011                        31 bit: U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
2012                        */
2013                        if ( !( uc & ~0x0000007F ) ) return 1;
2014                        if ( !( uc & ~0x000007FF ) ) return 2;
2015                        if ( !( uc & ~0x0000FFFF ) ) return 3;
2016                        if ( !( uc & ~0x001FFFFF ) ) return 4;
2017                        if ( !( uc & ~0x03FFFFFF ) ) return 5;
2018                        if ( !( uc & ~0x7FFFFFFF ) ) return 6;
2019                        throw invalid_data( "invalid UTF-32 value" );
2020                }
2021
2022                //! converts the given UTF-8 character buffer to a single UTF-32 Unicode character, returns the number of bytes used to create the output character (maximum of 6)
2023                static size_t _utf8_to_utf32( const unsigned char in_cp[6], unicode_char& out_uc ) {
2024                        size_t len = _utf8_char_length( in_cp[0] );
2025                        if ( len == 1 ) { // if we are only 1 byte long, then just grab it and exit
2026                                out_uc = in_cp[0];
2027                                return 1;
2028                        }
2029
2030                        unicode_char c = 0; // temporary buffer
2031                        size_t i = 0;
2032                        switch ( len ) { // load header byte
2033                        case 6:
2034                                c = in_cp[i] & _lead5_mask;
2035                                break;
2036                        case 5:
2037                                c = in_cp[i] & _lead4_mask;
2038                                break;
2039                        case 4:
2040                                c = in_cp[i] & _lead3_mask;
2041                                break;
2042                        case 3:
2043                                c = in_cp[i] & _lead2_mask;
2044                                break;
2045                        case 2:
2046                                c = in_cp[i] & _lead1_mask;
2047                                break;
2048                        }
2049
2050                        for ( ++i; i < len; i++ ) { // load each continuation byte
2051                                if (( in_cp[i] & ~_cont_mask ) != _cont )
2052                                        throw invalid_data( "bad UTF-8 continuation byte" );
2053                                c <<= 6;
2054                                c |= ( in_cp[i] & _cont_mask );
2055                        }
2056
2057                        out_uc = c; // write the final value and return the used byte length
2058                        return len;
2059                }
2060                //! writes the given UTF-32 \a uc_in to the buffer location \a out_cp using UTF-8 encoding, returns the number of bytes used to encode the input
2061                static size_t _utf32_to_utf8( const unicode_char& in_uc, unsigned char out_cp[6] ) {
2062                        size_t len = _utf8_char_length( in_uc ); // predict byte length of sequence
2063                        unicode_char c = in_uc; // copy to temp buffer
2064
2065                        //stuff all of the lower bits
2066                        for ( size_t i = len - 1; i > 0; i-- ) {
2067                                out_cp[i] = (( c ) & _cont_mask ) | _cont;
2068                                c >>= 6;
2069                        }
2070
2071                        //now write the header byte
2072                        switch ( len ) {
2073                        case 6:
2074                                out_cp[0] = (( c ) & _lead5_mask ) | _lead5;
2075                                break;
2076                        case 5:
2077                                out_cp[0] = (( c ) & _lead4_mask ) | _lead4;
2078                                break;
2079                        case 4:
2080                                out_cp[0] = (( c ) & _lead3_mask ) | _lead3;
2081                                break;
2082                        case 3:
2083                                out_cp[0] = (( c ) & _lead2_mask ) | _lead2;
2084                                break;
2085                        case 2:
2086                                out_cp[0] = (( c ) & _lead1_mask ) | _lead1;
2087                                break;
2088                        case 1:
2089                        default:
2090                                out_cp[0] = ( c ) & 0x7F;
2091                                break;
2092                        }
2093
2094                        // return the byte length of the sequence
2095                        return len;
2096                }
2097
2098                //! verifies a UTF-8 stream, returning the total number of Unicode characters found
2099                static size_type _verifyUTF8( const unsigned char* c_str ) {
2100                        std::string tmp( reinterpret_cast<const char*>( c_str ) );
2101                        return _verifyUTF8( tmp );
2102                }
2103                //! verifies a UTF-8 stream, returning the total number of Unicode characters found
2104                static size_type _verifyUTF8( const std::string& str ) {
2105                        std::string::const_iterator i, ie = str.end();
2106                        i = str.begin();
2107                        size_type length = 0;
2108
2109                        while ( i != ie ) {
2110                                // characters pass until we find an extended sequence
2111                                if (( *i ) & 0x80 ) {
2112                                        unsigned char c = ( *i );
2113                                        size_t contBytes = 0;
2114
2115                                        // get continuation byte count and test for overlong sequences
2116                                        if (( c & ~_lead1_mask ) == _lead1 ) { // 1 additional byte
2117                                                if ( c == _lead1 ) throw invalid_data( "overlong UTF-8 sequence" );
2118                                                contBytes = 1;
2119
2120                                        } else if (( c & ~_lead2_mask ) == _lead2 ) { // 2 additional bytes
2121                                                contBytes = 2;
2122                                                if ( c == _lead2 ) { // possible overlong UTF-8 sequence
2123                                                        c = ( *( i + 1 ) ); // look ahead to next byte in sequence
2124                                                        if (( c & _lead2 ) == _cont ) throw invalid_data( "overlong UTF-8 sequence" );
2125                                                }
2126
2127                                        } else if (( c & ~_lead3_mask ) == _lead3 ) { // 3 additional bytes
2128                                                contBytes = 3;
2129                                                if ( c == _lead3 ) { // possible overlong UTF-8 sequence
2130                                                        c = ( *( i + 1 ) ); // look ahead to next byte in sequence
2131                                                        if (( c & _lead3 ) == _cont ) throw invalid_data( "overlong UTF-8 sequence" );
2132                                                }
2133
2134                                        } else if (( c & ~_lead4_mask ) == _lead4 ) { // 4 additional bytes
2135                                                contBytes = 4;
2136                                                if ( c == _lead4 ) { // possible overlong UTF-8 sequence
2137                                                        c = ( *( i + 1 ) ); // look ahead to next byte in sequence
2138                                                        if (( c & _lead4 ) == _cont ) throw invalid_data( "overlong UTF-8 sequence" );
2139                                                }
2140
2141                                        } else if (( c & ~_lead5_mask ) == _lead5 ) { // 5 additional bytes
2142                                                contBytes = 5;
2143                                                if ( c == _lead5 ) { // possible overlong UTF-8 sequence
2144                                                        c = ( *( i + 1 ) ); // look ahead to next byte in sequence
2145                                                        if (( c & _lead5 ) == _cont ) throw invalid_data( "overlong UTF-8 sequence" );
2146                                                }
2147                                        }
2148
2149                                        // check remaining continuation bytes for
2150                                        while ( contBytes-- ) {
2151                                                c = ( *( ++i ) ); // get next byte in sequence
2152                                                if (( c & ~_cont_mask ) != _cont )
2153                                                        throw invalid_data( "bad UTF-8 continuation byte" );
2154                                        }
2155                                }
2156                                length++;
2157                                i++;
2158                        }
2159                        return length;
2160                }
2161                //@}
2162
2163        private:
2164                //template<class ITER_TYPE> friend class _iterator;
2165                dstring mData;
2166
2167                //! buffer data type identifier
2168                enum BufferType {
2169                        bt_none,
2170                        bt_string,
2171                        bt_wstring,
2172                        bt_utf32string
2173                };
2174
2175                //! common constructor operations
2176                void _init() {
2177                        m_buffer.mVoidBuffer = 0;
2178                        m_bufferType = bt_none;
2179                        m_bufferSize = 0;
2180                }
2181
2182                ///////////////////////////////////////////////////////////////////////
2183                // Scratch buffer
2184                //! auto cleans the scratch buffer using the proper delete for the stored type
2185                void _cleanBuffer() const {
2186                        if ( m_buffer.mVoidBuffer != 0 ) {
2187                                switch ( m_bufferType ) {
2188                                case bt_string:
2189                                        delete m_buffer.mStrBuffer;
2190                                        break;
2191                                case bt_wstring:
2192                                        delete m_buffer.mWStrBuffer;
2193                                        break;
2194                                case bt_utf32string:
2195                                        delete m_buffer.mUTF32StrBuffer;
2196                                        break;
2197                                case bt_none: // under the worse of circumstances, this is all we can do, and hope it works out
2198                                default:
2199                                        //delete m_buffer.mVoidBuffer;
2200                                        // delete void* is undefined, don't do that
2201                                        assert("This should never happen - mVoidBuffer should never contain something if we "
2202                                                "don't know the type");
2203                                        break;
2204                                }
2205                                m_buffer.mVoidBuffer = 0;
2206                                m_bufferSize = 0;
2207                        }
2208                }
2209
2210                //! create a std::string in the scratch buffer area
2211                void _getBufferStr() const {
2212                        if ( m_bufferType != bt_string ) {
2213                                _cleanBuffer();
2214                                m_buffer.mStrBuffer = new std::string();
2215                                m_bufferType = bt_string;
2216                        }
2217                        m_buffer.mStrBuffer->clear();
2218                }
2219                //! create a std::wstring in the scratch buffer area
2220                void _getBufferWStr() const {
2221                        if ( m_bufferType != bt_wstring ) {
2222                                _cleanBuffer();
2223                                m_buffer.mWStrBuffer = new std::wstring();
2224                                m_bufferType = bt_wstring;
2225                        }
2226                        m_buffer.mWStrBuffer->clear();
2227                }
2228                //! create a utf32string in the scratch buffer area
2229                void _getBufferUTF32Str() const {
2230                        if ( m_bufferType != bt_utf32string ) {
2231                                _cleanBuffer();
2232                                m_buffer.mUTF32StrBuffer = new utf32string();
2233                                m_bufferType = bt_utf32string;
2234                        }
2235                        m_buffer.mUTF32StrBuffer->clear();
2236                }
2237
2238                void _load_buffer_UTF8() const {
2239                        _getBufferStr();
2240                        std::string& buffer = ( *m_buffer.mStrBuffer );
2241                        buffer.reserve( length() );
2242
2243                        unsigned char utf8buf[6];
2244                        char* charbuf = ( char* )utf8buf;
2245                        unicode_char c;
2246                        size_t len;
2247
2248                        const_iterator i, ie = end();
2249                        for ( i = begin(); i != ie; i.moveNext() ) {
2250                                c = i.getCharacter();
2251                                len = _utf32_to_utf8( c, utf8buf );
2252                                size_t j = 0;
2253                                while ( j < len )
2254                                        buffer.push_back( charbuf[j++] );
2255                        }
2256                }
2257                void _load_buffer_WStr() const {
2258                        _getBufferWStr();
2259                        std::wstring& buffer = ( *m_buffer.mWStrBuffer );
2260                        buffer.reserve( length() ); // may over reserve, but should be close enough
2261#ifdef WCHAR_UTF16 // wchar_t matches UTF-16
2262                        const_iterator i, ie = end();
2263                        for ( i = begin(); i != ie; ++i ) {
2264                                buffer.push_back(( wchar_t )( *i ) );
2265                        }
2266#else // wchar_t fits UTF-32
2267                        unicode_char c;
2268                        const_iterator i, ie = end();
2269                        for ( i = begin(); i != ie; i.moveNext() ) {
2270                                c = i.getCharacter();
2271                                buffer.push_back(( wchar_t )c );
2272                        }
2273#endif
2274                }
2275                void _load_buffer_UTF32() const {
2276                        _getBufferUTF32Str();
2277                        utf32string& buffer = ( *m_buffer.mUTF32StrBuffer );
2278                        buffer.reserve( length() ); // may over reserve, but should be close enough
2279
2280                        unicode_char c;
2281
2282                        const_iterator i, ie = end();
2283                        for ( i = begin(); i != ie; i.moveNext() ) {
2284                                c = i.getCharacter();
2285                                buffer.push_back( c );
2286                        }
2287                }
2288
2289                mutable BufferType m_bufferType; // identifies the data type held in m_buffer
2290                mutable size_t m_bufferSize; // size of the CString buffer
2291
2292                // multi-purpose buffer used everywhere we need a throw-away buffer
2293                union {
2294                        mutable void* mVoidBuffer;
2295                        mutable std::string* mStrBuffer;
2296                        mutable std::wstring* mWStrBuffer;
2297                        mutable utf32string* mUTF32StrBuffer;
2298                }
2299                m_buffer;
2300        };
2301
2302        //! string addition operator \relates UTFString
2303        inline UTFString operator+( const UTFString& s1, const UTFString& s2 ) {
2304                return UTFString( s1 ).append( s2 );
2305        }
2306        //! string addition operator \relates UTFString
2307        inline UTFString operator+( const UTFString& s1, UTFString::code_point c ) {
2308                return UTFString( s1 ).append( 1, c );
2309        }
2310        //! string addition operator \relates UTFString
2311        inline UTFString operator+( const UTFString& s1, UTFString::unicode_char c ) {
2312                return UTFString( s1 ).append( 1, c );
2313        }
2314        //! string addition operator \relates UTFString
2315        inline UTFString operator+( const UTFString& s1, char c ) {
2316                return UTFString( s1 ).append( 1, c );
2317        }
2318#if OGRE_IS_NATIVE_WCHAR_T
2319        //! string addition operator \relates UTFString
2320        inline UTFString operator+( const UTFString& s1, wchar_t c ) {
2321                return UTFString( s1 ).append( 1, c );
2322        }
2323#endif
2324        //! string addition operator \relates UTFString
2325        inline UTFString operator+( UTFString::code_point c, const UTFString& s2 ) {
2326                return UTFString().append( 1, c ).append( s2 );
2327        }
2328        //! string addition operator \relates UTFString
2329        inline UTFString operator+( UTFString::unicode_char c, const UTFString& s2 ) {
2330                return UTFString().append( 1, c ).append( s2 );
2331        }
2332        //! string addition operator \relates UTFString
2333        inline UTFString operator+( char c, const UTFString& s2 ) {
2334                return UTFString().append( 1, c ).append( s2 );
2335        }
2336#if OGRE_IS_NATIVE_WCHAR_T
2337        //! string addition operator \relates UTFString
2338        inline UTFString operator+( wchar_t c, const UTFString& s2 ) {
2339                return UTFString().append( 1, c ).append( s2 );
2340        }
2341#endif
2342
2343        // (const) forward iterator common operators
2344        inline UTFString::size_type operator-( const UTFString::_const_fwd_iterator& left, const UTFString::_const_fwd_iterator& right ) {
2345                return ( left.mIter - right.mIter );
2346        }
2347        inline bool operator==( const UTFString::_const_fwd_iterator& left, const UTFString::_const_fwd_iterator& right ) {
2348                return left.mIter == right.mIter;
2349        }
2350        inline bool operator!=( const UTFString::_const_fwd_iterator& left, const UTFString::_const_fwd_iterator& right ) {
2351                return left.mIter != right.mIter;
2352        }
2353        inline bool operator<( const UTFString::_const_fwd_iterator& left, const UTFString::_const_fwd_iterator& right ) {
2354                return left.mIter < right.mIter;
2355        }
2356        inline bool operator<=( const UTFString::_const_fwd_iterator& left, const UTFString::_const_fwd_iterator& right ) {
2357                return left.mIter <= right.mIter;
2358        }
2359        inline bool operator>( const UTFString::_const_fwd_iterator& left, const UTFString::_const_fwd_iterator& right ) {
2360                return left.mIter > right.mIter;
2361        }
2362        inline bool operator>=( const UTFString::_const_fwd_iterator& left, const UTFString::_const_fwd_iterator& right ) {
2363                return left.mIter >= right.mIter;
2364        }
2365
2366        // (const) reverse iterator common operators
2367        // NB: many of these operations are evaluated in reverse because this is a reverse iterator wrapping a forward iterator
2368        inline UTFString::size_type operator-( const UTFString::_const_rev_iterator& left, const UTFString::_const_rev_iterator& right ) {
2369                return ( right.mIter - left.mIter );
2370        }
2371        inline bool operator==( const UTFString::_const_rev_iterator& left, const UTFString::_const_rev_iterator& right ) {
2372                return left.mIter == right.mIter;
2373        }
2374        inline bool operator!=( const UTFString::_const_rev_iterator& left, const UTFString::_const_rev_iterator& right ) {
2375                return left.mIter != right.mIter;
2376        }
2377        inline bool operator<( const UTFString::_const_rev_iterator& left, const UTFString::_const_rev_iterator& right ) {
2378                return right.mIter < left.mIter;
2379        }
2380        inline bool operator<=( const UTFString::_const_rev_iterator& left, const UTFString::_const_rev_iterator& right ) {
2381                return right.mIter <= left.mIter;
2382        }
2383        inline bool operator>( const UTFString::_const_rev_iterator& left, const UTFString::_const_rev_iterator& right ) {
2384                return right.mIter > left.mIter;
2385        }
2386        inline bool operator>=( const UTFString::_const_rev_iterator& left, const UTFString::_const_rev_iterator& right ) {
2387                return right.mIter >= left.mIter;
2388        }
2389
2390        //! std::ostream write operator \relates UTFString
2391        inline std::ostream& operator << ( std::ostream& os, const UTFString& s ) {
2392                return os << s.asUTF8();
2393        }
2394
2395        //! std::wostream write operator \relates UTFString
2396        inline std::wostream& operator << ( std::wostream& os, const UTFString& s ) {
2397                return os << s.asWStr();
2398        }
2399
2400
2401
2402} // namespace Ogre{
2403
2404#endif // OGRE_UNICODE_SUPPORT
2405
2406#endif
Note: See TracBrowser for help on using the repository browser.