1 /** \file lvstring.h
2     \brief string classes interface
3 
4     CoolReader Engine
5 
6     (c) Vadim Lopatin, 2000-2006
7     This source code is distributed under the terms of
8     GNU General Public License.
9 
10     See LICENSE file for details.
11 */
12 
13 #ifndef __LV_STRING_H_INCLUDED__
14 #define __LV_STRING_H_INCLUDED__
15 
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include "lvtypes.h"
20 #include "lvmemman.h"
21 
22 // (Note: some of these 0x have lowercase hex digit, to avoid
23 // 'redefined' warnings as they are already defined in lowercase
24 // in antiword/wordconst.h.)
25 
26 /// Unicode spaces
27 #define UNICODE_NO_BREAK_SPACE            0x00A0
28 #define UNICODE_ZERO_WIDTH_NO_BREAK_SPACE 0xfeff
29 #define UNICODE_WORD_JOINER      0x2060
30 // All chars from U+2000 to U+200B allow wrap after, except U+2007
31 #define UNICODE_EN_QUAD          0x2000
32 #define UNICODE_FIGURE_SPACE     0x2007
33 #define UNICODE_ZERO_WIDTH_SPACE 0x200b
34 
35 #ifdef USE_ATOMIC_REFCOUNT
36 #include <atomic>
37 #endif
38 /// Unicode hyphens
39 #define UNICODE_SOFT_HYPHEN_CODE 0x00AD
40 #define UNICODE_ARMENIAN_HYPHEN  0x058A
41 // All chars from U+2010 to U+2014 allow deprecated wrap after, except U+2011
42 #define UNICODE_HYPHEN           0x2010
43 #define UNICODE_NO_BREAK_HYPHEN  0x2011
44 #define UNICODE_EM_DASH          0x2014
45 
46 // Punctuation and CJK ranges
47 #define UNICODE_GENERAL_PUNCTUATION_BEGIN 0x2000
48 #define UNICODE_GENERAL_PUNCTUATION_END 0x206F
49 #define UNICODE_CJK_IDEOGRAPHS_BEGIN 0x3041
50 #define UNICODE_CJK_IDEOGRAPHS_END 0x02CEAF
51 #define UNICODE_CJK_IDEOGRAPHIC_SPACE 0x3000
52 #define UNICODE_CJK_PUNCTUATION_BEGIN 0x3000
53 #define UNICODE_CJK_PUNCTUATION_END 0x303F
54 // These may be wrong as this block contain katakana and hangul
55 // letters, as well as ascii full-width chars:
56 #define UNICODE_CJK_PUNCTUATION_HALF_AND_FULL_WIDTH_BEGIN 0xFF01
57 #define UNICODE_CJK_PUNCTUATION_HALF_AND_FULL_WIDTH_END 0xFFEE
58 
59 #define UNICODE_ASCII_FULL_WIDTH_BEGIN 0xFF01
60 #define UNICODE_ASCII_FULL_WIDTH_END 0xFF5E
61 #define UNICODE_ASCII_FULL_WIDTH_OFFSET 0xFEE0 // substract or add to convert to/from ASCII
62 
63 
64 /// strlen for lChar16
65 int lStr_len(const lChar16 * str);
66 /// strlen for lChar32
67 int lStr_len(const lChar32 * str);
68 /// strlen for lChar8
69 int lStr_len(const lChar8 * str);
70 /// strnlen for lChar16
71 int lStr_nlen(const lChar16 * str, int maxcount);
72 /// strnlen for lChar32
73 int lStr_nlen(const lChar32 * str, int maxcount);
74 /// strnlen for lChar8
75 int lStr_nlen(const lChar8 * str, int maxcount);
76 /// strcpy for lChar16
77 int lStr_cpy(lChar16 * dst, const lChar16 * src);
78 /// strcpy for lChar32
79 int lStr_cpy(lChar32 * dst, const lChar32 * src);
80 /// strcpy for lChar16 -> lChar8
81 int lStr_cpy(lChar16 * dst, const lChar8 * src);
82 /// strcpy for lChar32 -> lChar8
83 int lStr_cpy(lChar32 * dst, const lChar8 * src);
84 /// strcpy for lChar8
85 int lStr_cpy(lChar8 * dst, const lChar8 * src);
86 /// strncpy for lChar16
87 int lStr_ncpy(lChar16 * dst, const lChar16 * src, int maxcount);
88 /// strncpy for lChar32
89 int lStr_ncpy(lChar32 * dst, const lChar32 * src, int maxcount);
90 /// strncpy for lChar8
91 int lStr_ncpy(lChar8 * dst, const lChar8 * src, int maxcount);
92 /// memcpy for lChar16
93 void   lStr_memcpy(lChar16 * dst, const lChar16 * src, int count);
94 /// memcpy for lChar32
95 void   lStr_memcpy(lChar32 * dst, const lChar32 * src, int count);
96 /// memcpy for lChar8
97 void   lStr_memcpy(lChar8 * dst, const lChar8 * src, int count);
98 /// memset for lChar16
99 void   lStr_memset(lChar16 * dst, lChar16 value, int count);
100 /// memset for lChar32
101 void   lStr_memset(lChar32 * dst, lChar32 value, int count);
102 /// memset for lChar8
103 void   lStr_memset(lChar8 * dst, lChar8 value, int count);
104 /// strcmp for lChar16
105 int    lStr_cmp(const lChar16 * str1, const lChar16 * str2);
106 /// strcmp for lChar32
107 int    lStr_cmp(const lChar32 * str1, const lChar32 * str2);
108 /// strcmp for lChar32 <> lChar8
109 int    lStr_cmp(const lChar32 * str1, const lChar8 * str2);
110 /// strcmp for lChar16 <> lChar8
111 int    lStr_cmp(const lChar16 * str1, const lChar8 * str2);
112 /// strcmp for lChar8 <> lChar16
113 int    lStr_cmp(const lChar8 * str1, const lChar16 * str2);
114 /// strcmp for lChar16 <> lChar32
115 int    lStr_cmp(const lChar16 * str1, const lChar32 * str2);
116 /// strcmp for lChar8 <> lChar32
117 int    lStr_cmp(const lChar8 * str1, const lChar32 * str2);
118 /// strcmp for lChar32 <> lChar16
119 int    lStr_cmp(const lChar32 * str1, const lChar16 * str2);
120 /// strcmp for lChar8
121 int    lStr_cmp(const lChar8 * str1, const lChar8 * str2);
122 /// convert string to uppercase
123 void lStr_uppercase( lChar8 * str, int len );
124 /// convert string to lowercase
125 void lStr_lowercase( lChar8 * str, int len );
126 /// convert string to uppercase
127 void lStr_uppercase( lChar32 * str, int len );
128 /// convert string to lowercase
129 void lStr_lowercase( lChar32 * str, int len );
130 /// convert string to be capitalized
131 void lStr_capitalize( lChar32 * str, int len );
132 /// convert string to use full width chars
133 void lStr_fullWidthChars( lChar32 * str, int len );
134 /// calculates CRC32 for buffer contents
135 lUInt32 lStr_crc32( lUInt32 prevValue, const void * buf, int size );
136 
137 // converts 0..15 to 0..f
138 char toHexDigit( int c );
139 // returns 0..15 if c is hex digit, -1 otherwise
140 int hexDigit( int c );
141 // decode LEN hex digits, return decoded number, -1 if invalid
142 int decodeHex( const lChar32 * str, int len );
143 // decode LEN decimal digits, return decoded number, -1 if invalid
144 int decodeDecimal( const lChar32 * str, int len );
145 
146 
147 #define CH_PROP_UPPER       0x0001 ///< uppercase alpha character flag
148 #define CH_PROP_LOWER       0x0002 ///< lowercase alpha character flag
149 #define CH_PROP_ALPHA       0x0003 ///< alpha flag is combination of uppercase and lowercase flags
150 #define CH_PROP_DIGIT       0x0004 ///< digit character flag
151 #define CH_PROP_PUNCT       0x0008 ///< pubctuation character flag
152 #define CH_PROP_SPACE       0x0010 ///< space character flag
153 #define CH_PROP_HYPHEN      0x0020 ///< hyphenation character flag
154 #define CH_PROP_VOWEL       0x0040 ///< vowel character flag
155 #define CH_PROP_CONSONANT   0x0080 ///< consonant character flag
156 #define CH_PROP_SIGN        0x0100 ///< sign character flag
157 #define CH_PROP_ALPHA_SIGN  0x0200 ///< alpha sign character flag
158 #define CH_PROP_DASH        0x0400 ///< minus, emdash, endash, ... (- signs)
159 #define CH_PROP_CJK         0x0800 ///< CJK ideographs
160 #define CH_PROP_AVOID_WRAP_AFTER   0x1000 ///< avoid wrap on following space
161 #define CH_PROP_AVOID_WRAP_BEFORE  0x2000 ///< avoid wrap on preceding space
162 
163 /// retrieve character properties mask array for wide c-string
164 void lStr_getCharProps( const lChar32 * str, int sz, lUInt16 * props );
165 /// retrieve character properties mask for single wide character
166 lUInt16 lGetCharProps( lChar32 ch );
167 /// find alpha sequence bounds
168 void lStr_findWordBounds( const lChar32 * str, int sz, int pos, int & start, int & end );
169 // is char a word separator
170 bool lStr_isWordSeparator( lChar32 ch );
171 
172 
173 // must be power of 2
174 #define CONST_STRING_BUFFER_SIZE 4096
175 #define CONST_STRING_BUFFER_MASK (CONST_STRING_BUFFER_SIZE - 1)
176 #define CONST_STRING_BUFFER_HASH_MULT 31
177 
178 
179 struct lstring8_chunk_t {
180     friend class lString8;
181     friend class lString32;
182     friend struct lstring_chunk_slice_t;
183 public:
lstring8_chunk_tlstring8_chunk_t184     lstring8_chunk_t(lChar8 * _buf8) : buf8(_buf8), size(1), len(0)
185     {
186         refCount = 1;
187     }
data8lstring8_chunk_t188     const lChar8 * data8() const { return buf8; }
189 private:
190     lChar8  * buf8; // z-string
191     lInt32 size;   // 0 for free chunk
192     lInt32 len;    // count of chars in string
193 #ifdef USE_ATOMIC_REFCOUNT
194     std::atomic_int refCount; // atomic reference counter
195 #else
196     int refCount;      // reference counter
197 #endif
198 
lstring8_chunk_tlstring8_chunk_t199     lstring8_chunk_t() {}
200 
201     // chunk allocation functions
202     static lstring8_chunk_t * alloc();
203     static void free( lstring8_chunk_t * pChunk );
204 
205 };
206 
207 struct lstring32_chunk_t {
208     friend class lString8;
209     friend class lString32;
210     friend class lString32Collection;
211     friend struct lstring_chunk_slice_t;
212 public:
lstring32_chunk_tlstring32_chunk_t213     lstring32_chunk_t(lChar32 * _buf32) : buf32(_buf32), size(1), len(0)
214     {
215         refCount = 1;
216     }
data32lstring32_chunk_t217     const lChar32 * data32() const { return buf32; }
218 private:
219     lChar32 * buf32; // z-string
220     lInt32 size;   // 0 for free chunk
221     lInt32 len;    // count of chars in string
222 #ifdef USE_ATOMIC_REFCOUNT
223     std::atomic_int refCount; // atomic reference counter
224 #else
225     int refCount;      // reference counter
226 #endif
227 
lstring32_chunk_tlstring32_chunk_t228     lstring32_chunk_t() {}
229 
230     // chunk allocation functions
231     static lstring32_chunk_t * alloc();
232     static void free( lstring32_chunk_t * pChunk );
233 };
234 
235 struct lstring16_chunk_t {
236     friend class lString8;
237     friend class lString16;
238     friend struct lstring_chunk_slice_t;
239 public:
lstring16_chunk_tlstring16_chunk_t240     lstring16_chunk_t(lChar16 * _buf16) : buf16(_buf16), size(1), len(0)
241     {
242         refCount = 1;
243     }
data16lstring16_chunk_t244     const lChar16 * data16() const { return buf16; }
245 private:
246     lChar16 * buf16;  // z-string
247     lInt32 size;      // 0 for free chunk
248     lInt32 len;       // count of chars in string
249 #ifdef USE_ATOMIC_REFCOUNT
250     std::atomic_int refCount; // atomic reference counter
251 #else
252     int refCount;      // reference counter
253 #endif
254 
lstring16_chunk_tlstring16_chunk_t255     lstring16_chunk_t() {}
256 
257     // chunk allocation functions
258     static lstring16_chunk_t * alloc();
259     static void free( lstring16_chunk_t * pChunk );
260 };
261 
262 
263 namespace fmt {
264     class decimal {
265         lInt64 value;
266     public:
decimal(lInt64 v)267         explicit decimal(lInt64 v) : value(v) { }
get()268         lInt64 get() const { return value; }
269     };
270 
271     class hex {
272         lUInt64 value;
273     public:
hex(lInt64 v)274         explicit hex(lInt64 v) : value(v) { }
get()275         lUInt64 get() const { return value; }
276     };
277 }
278 
279 
280 /**
281     \brief lChar8 string
282 
283     Reference counting, copy-on-write implementation of 8-bit string.
284     Interface is similar to STL strings
285 
286 */
287 class lString8
288 {
289     friend class lString8Collection;
290     friend const lString8 & cs8(const char * str);
291 public:
292     // typedefs for STL compatibility
293     typedef lChar8              value_type;      ///< character type
294     typedef int                 size_type;       ///< size type
295     typedef int                 difference_type; ///< difference type
296     typedef value_type *        pointer;         ///< pointer to char type
297     typedef value_type &        reference;       ///< reference to char type
298     typedef const value_type *  const_pointer;   ///< pointer to const char type
299     typedef const value_type &  const_reference; ///< reference to const char type
300 
301     typedef lstring8_chunk_t    lstring_chunk_t; ///< data container
302 
303     class decimal {
304         lInt64 value;
305     public:
decimal(lInt64 v)306         explicit decimal(lInt64 v) : value(v) { }
get()307         lInt64 get() { return value; }
308     };
309 
310     class hex {
311         lUInt64 value;
312     public:
hex(lInt64 v)313         explicit hex(lInt64 v) : value(v) { }
get()314         lUInt64 get() { return value; }
315     };
316 
317 private:
318     lstring_chunk_t * pchunk;
319     static lstring_chunk_t * EMPTY_STR_8;
320     void alloc(size_type sz);
321     void free();
addref()322     inline void addref() const {
323 #ifdef USE_ATOMIC_REFCOUNT
324         pchunk->refCount.fetch_add(1);
325 #else
326         ++pchunk->refCount;
327 #endif
328     }
release()329     inline void release() {
330 #ifdef USE_ATOMIC_REFCOUNT
331         if (pchunk->refCount.fetch_sub(1) <= 1)
332             free();
333 #else
334         if (--pchunk->refCount==0) free();
335 #endif
336     }
refCount()337     inline int refCount() {
338         return pchunk->refCount;
339     }
lString8(lstring_chunk_t * chunk)340     explicit lString8(lstring_chunk_t * chunk) : pchunk(chunk) { addref(); }
341 public:
342     /// default constrictor
lString8()343     explicit lString8() : pchunk(EMPTY_STR_8) { addref(); }
344     /// constructor of empty string with buffer of specified size
lString8(int size)345     explicit lString8( int size ) : pchunk(EMPTY_STR_8) { addref(); reserve(size); }
346     /// copy constructor
lString8(const lString8 & str)347     lString8(const lString8 & str) : pchunk(str.pchunk) { addref(); }
348     /// constructor from C string
349     explicit lString8(const value_type * str);
350     /// constructor from 16-bit C string
351     explicit lString8(const lChar32 * str);
352     /// constructor from string of specified length
353     explicit lString8(const value_type * str, size_type count);
354     /// fragment copy constructor
355     explicit lString8(const lString8 & str, size_type offset, size_type count);
356     /// destructor
~lString8()357     ~lString8() { release(); }
358 
359     /// copy assignment
assign(const lString8 & str)360     lString8 & assign(const lString8 & str)
361     {
362         if (pchunk!=str.pchunk)
363         {
364             release();
365             pchunk = str.pchunk;
366             addref();
367         }
368         return *this;
369     }
370     /// C-string assignment
371     lString8 & assign(const value_type * str);
372     /// C-string fragment assignment
373     lString8 & assign(const value_type * str, size_type count);
374     /// string fragment assignment
375     lString8 & assign(const lString8 & str, size_type offset, size_type count);
376     /// C-string assignment
377     lString8 & operator = (const value_type * str) { return assign(str); }
378     /// string copy assignment
379     lString8 & operator = (const lString8 & str) { return assign(str); }
380     /// erase part of string
381     lString8 & erase(size_type offset, size_type count);
382     /// append C-string
383     lString8 & append(const value_type * str);
384     /// append C-string fragment
385     lString8 & append(const value_type * str, size_type count);
386     /// append string
387     lString8 & append(const lString8 & str);
388     /// append string fragment
389     lString8 & append(const lString8 & str, size_type offset, size_type count);
390     /// append repeated character
391     lString8 & append(size_type count, value_type ch);
392     /// append decimal number
393     lString8 & appendDecimal(lInt64 v);
394     /// append hex number
395     lString8 & appendHex(lUInt64 v);
396     /// insert C-string
397     lString8 & insert(size_type p0, const value_type * str);
398     /// insert C-string fragment
399     lString8 & insert(size_type p0, const value_type * str, size_type count);
400     /// insert string
401     lString8 & insert(size_type p0, const lString8 & str);
402     /// insert string fragment
403     lString8 & insert(size_type p0, const lString8 & str, size_type offset, size_type count);
404     /// insert repeated character
405     lString8 & insert(size_type p0, size_type count, value_type ch);
406     /// replace fragment with C-string
407     lString8 & replace(size_type p0, size_type n0, const value_type * str);
408     /// replace fragment with C-string fragment
409     lString8 & replace(size_type p0, size_type n0, const value_type * str, size_type count);
410     /// replace fragment with string
411     lString8 & replace(size_type p0, size_type n0, const lString8 & str);
412     /// replace fragment with string fragment
413     lString8 & replace(size_type p0, size_type n0, const lString8 & str, size_type offset, size_type count);
414     /// replace fragment with repeated character
415     lString8 & replace(size_type p0, size_type n0, size_type count, value_type ch);
416     /// make string uppercase
417     lString8 & uppercase();
418     /// make string lowercase
419     lString8 & lowercase();
420     /// compare with another string
compare(const lString8 & str)421     int compare(const lString8& str) const { return lStr_cmp(pchunk->buf8, str.pchunk->buf8); }
422     /// compare part of string with another string
423     int compare(size_type p0, size_type n0, const lString8& str) const;
424     /// compare part of string with fragment of another string
425     int compare(size_type p0, size_type n0, const lString8& str, size_type pos, size_type n) const;
426     /// compare with C-string
compare(const value_type * s)427     int compare(const value_type *s) const  { return lStr_cmp(pchunk->buf8, s); }
428     /// compare part of string with C-string
429     int compare(size_type p0, size_type n0, const value_type *s) const;
430     /// compare part of string with C-string fragment
431     int compare(size_type p0, size_type n0, const value_type *s, size_type pos) const;
432     /// find position of char inside string, -1 if not found
433     int pos(lChar8 ch) const;
434     /// find position of char inside string starting from specified position, -1 if not found
435     int pos(lChar8 ch, int start) const;
436     /// find position of substring inside string, -1 if not found
437     int pos(const lString8 & subStr) const;
438     /// find position of substring inside string, -1 if not found
439     int pos(const char * subStr) const;
440     /// find position of substring inside string starting from right, -1 if not found
441     int rpos(const char * subStr) const;
442     /// find position of substring inside string starting from specified position, -1 if not found
443     int pos(const lString8 & subStr, int startPos) const;
444     /// find position of substring inside string starting from specified position, -1 if not found
445     int pos(const char * subStr, int startPos) const;
446 
447     /// substring
448     lString8 substr(size_type pos, size_type n) const;
449     /// substring from position to end of string
substr(size_type pos)450     lString8 substr(size_type pos) const { return substr(pos, length() - pos); }
451 
452     /// append single character
453     lString8 & operator << (value_type ch) { return append(1, ch); }
454     /// append C-string
455     lString8 & operator << (const value_type * str) { return append(str); }
456     /// append string
457     lString8 & operator << (const lString8 & str) { return append(str); }
458     /// append decimal number
459     lString8 & operator << (const fmt::decimal v) { return appendDecimal(v.get()); }
460     /// append hex number
461     lString8 & operator << (const fmt::hex v) { return appendHex(v.get()); }
462 
463     /// returns true if string starts with specified substring
464     bool startsWith ( const lString8 & substring ) const;
465     /// returns true if string starts with specified substring
466     bool startsWith ( const char * substring ) const;
467 
468     /// returns last character
lastChar()469     value_type lastChar() { return empty() ? 0 : at(length()-1); }
470     /// returns first character
firstChar()471     value_type firstChar() { return empty() ? 0 : at(0); }
472 
473     /// calculate hash
474     lUInt32 getHash() const;
475 
476     /// get character at specified position with range check
at(size_type pos)477     value_type & at(size_type pos) {
478     	if (pos > pchunk->len)
479     		crFatalError();
480     	return modify()[pos];
481     }
482     /// get character at specified position without range check
483     value_type operator [] ( size_type pos ) const { return pchunk->buf8[pos]; }
484     /// get reference to character at specified position
485     value_type & operator [] ( size_type pos ) { return modify()[pos]; }
486 
487     /// ensures that reference count is 1
488     void  lock( size_type newsize );
489     /// returns pointer to modifable string buffer
modify()490     value_type * modify() { if (refCount()>1) lock(pchunk->len); return pchunk->buf8; }
491     /// clear string
clear()492     void  clear() { release(); pchunk = EMPTY_STR_8; addref(); }
493     /// clear string, set buffer size
494     void  reset( size_type size );
495     /// returns character count
length()496     size_type   length() const { return pchunk->len; }
497     /// returns buffer size
size()498     size_type   size() const { return pchunk->len; }
499     /// changes buffer size
500     void  resize(size_type count = 0, value_type e = 0);
501     /// returns maximum number of chars that can fit into buffer
capacity()502     size_type   capacity() const { return pchunk->size-1; }
503     /// reserve space for specified amount of chars
504     void  reserve(size_type count = 0);
505     /// returns true if string is empty
empty()506     bool  empty() const { return pchunk->len==0; }
507     /// returns true if string is empty
508     bool  operator !() const { return pchunk->len==0; }
509     /// swaps content of two strings
swap(lString8 & str)510     void  swap( lString8 & str ) { lstring_chunk_t * tmp = pchunk;
511                 pchunk=str.pchunk; str.pchunk=tmp; }
512     /// pack string (free unused buffer space)
513     lString8 & pack();
514 
515     /// remove spaces from begin and end of string
516     lString8 & trim();
517     /// convert to integer
518     int atoi() const;
519     /// convert to 64 bit integer
520     lInt64 atoi64() const;
521 
522     /// returns C-string
c_str()523     const value_type * c_str() const { return pchunk->buf8; }
524     /// returns C-string
data()525     const value_type * data() const { return pchunk->buf8; }
526 
527     /// append string
528     lString8 & operator += ( lString8 s ) { return append(s); }
529     /// append C-string
530     lString8 & operator += ( const value_type * s ) { return append(s); }
531     /// append single character
532     lString8 & operator += ( value_type ch ) { return append(1, ch); }
533     /// append decimal
534     lString8 & operator += ( fmt::decimal v ) { return appendDecimal(v.get()); }
535     /// append hex
536     lString8 & operator += ( fmt::hex v ) { return appendHex(v.get()); }
537 
538     /// returns true if string ends with specified substring
539     bool endsWith( const lChar8 * substring ) const;
540 
541     /// constructs string representation of integer
542     static lString8 itoa( int i );
543     /// constructs string representation of unsigned integer
544     static lString8 itoa( unsigned int i );
545     // constructs string representation of 64 bit integer
546     static lString8 itoa( lInt64 n );
547 
548     static const lString8 empty_str;
549 
550     friend class lString32Collection;
551 };
552 
553 /**
554     \brief Wide character (lChar16) string.
555     Intended primarily for WINAPI.
556 
557    Reference counting, copy-on-write implementation.
558    Interface is similar to STL strings.
559 
560 */
561 class lString16
562 {
563 public:
564     // typedefs for STL compatibility
565     typedef lChar16             value_type;
566     typedef int                 size_type;
567     typedef int                 difference_type;
568     typedef value_type *        pointer;
569     typedef value_type &        reference;
570     typedef const value_type *  const_pointer;
571     typedef const value_type &  const_reference;
572 
573     typedef lstring16_chunk_t   lstring_chunk_t; ///< data container
574 
575 private:
576     lstring_chunk_t * pchunk;
577     static lstring_chunk_t * EMPTY_STR_16;
578     void alloc(size_type sz);
579     void free();
addref()580     inline void addref() const {
581 #ifdef USE_ATOMIC_REFCOUNT
582         pchunk->refCount.fetch_add(1);
583 #else
584         ++pchunk->refCount;
585 #endif
586     }
release()587     inline void release() {
588 #ifdef USE_ATOMIC_REFCOUNT
589         if (pchunk->refCount.fetch_sub(1) <= 1)
590             free();
591 #else
592         if (--pchunk->refCount==0) free();
593 #endif
594     }
refCount()595     inline int refCount() {
596         return pchunk->refCount;
597     }
598 public:
lString16(lstring_chunk_t * chunk)599     explicit lString16(lstring_chunk_t * chunk) : pchunk(chunk) { addref(); }
600     /// empty string constructor
lString16()601     explicit lString16() : pchunk(EMPTY_STR_16) { addref(); }
602     /// copy constructor
lString16(const lString16 & str)603     lString16(const lString16 & str) : pchunk(str.pchunk) { addref(); }
604     /// constructor from wide c-string
605     lString16(const value_type * str);
606     /// constructor from 8bit c-string (ASCII only)
607     explicit lString16(const lChar8 * str);
608     /// constructor from 8bit (ASCII only) character array fragment
609     explicit lString16(const lChar8 * str, size_type count);
610     /// constructor from wide character array fragment
611     explicit lString16(const value_type * str, size_type count);
612     /// constructor from another string substring
613     explicit lString16(const lString16 & str, size_type offset, size_type count);
614     /// desctructor
~lString16()615     ~lString16() { release(); }
616 
617     /// assignment from string
assign(const lString16 & str)618     lString16 & assign(const lString16 & str)
619     {
620         if (pchunk!=str.pchunk)
621         {
622             release();
623             pchunk = str.pchunk;
624             addref();
625         }
626         return *this;
627     }
628     /// assignment from c-string
629     lString16 & assign(const value_type * str);
630     /// assignment from 8bit c-string (ASCII only)
631     lString16 & assign(const lChar8 * str);
632     /// assignment from character array fragment
633     lString16 & assign(const value_type * str, size_type count);
634     /// assignment from 8-bit character array fragment (ASCII only)
635     lString16 & assign(const lChar8 * str, size_type count);
636     /// assignment from string fragment
637     lString16 & assign(const lString16 & str, size_type offset, size_type count);
638     /// assignment from c-string
639     lString16 & operator = (const value_type * str) { return assign(str); }
640     /// assignment from string 8bit ASCII only
641     lString16 & operator = (const lChar8 * str) { return assign(str); }
642     /// assignment from string
643     lString16 & operator = (const lString16 & str) { return assign(str); }
644     lString16 & erase(size_type offset, size_type count);
645 
646     lString16 & append(const value_type * str);
647     lString16 & append(const value_type * str, size_type count);
648     lString16 & append(const lChar8 * str);
649     lString16 & append(const lChar8 * str, size_type count);
650     lString16 & append(const lString16 & str);
651     lString16 & append(const lString16 & str, size_type offset, size_type count);
652     lString16 & append(size_type count, value_type ch);
653     /// append decimal number
654     lString16 & appendDecimal(lInt64 v);
655     /// append hex number
656     lString16 & appendHex(lUInt64 v);
657     lString16 & insert(size_type p0, const value_type * str);
658     lString16 & insert(size_type p0, const value_type * str, size_type count);
659     lString16 & insert(size_type p0, const lString16 & str);
660     lString16 & insert(size_type p0, size_type count, value_type ch);
661     /// compare with another string
compare(const lString16 & str)662     int compare(const lString16& str) const { return lStr_cmp(pchunk->buf16, str.pchunk->buf16); }
compare(const value_type * s)663     int compare(const value_type *s) const  { return lStr_cmp(pchunk->buf16, s); }
compare(const lChar8 * s)664     int compare(const lChar8 *s) const  { return lStr_cmp(pchunk->buf16, s); }
665 
666     /// returns n characters beginning with pos
667     lString16 substr(size_type pos, size_type n) const;
668     /// returns part of string from specified position to end of string
substr(size_type pos)669     lString16 substr(size_type pos) const { return substr(pos, length()-pos); }
670     /// replaces first found occurence of pattern
671     bool replace(const lString16 & findStr, const lString16 & replaceStr);
672     /// replaces first found occurence of "$N" pattern with string, where N=index
673     bool replaceParam(int index, const lString16 & replaceStr);
674     /// replaces first found occurence of "$N" pattern with itoa of integer, where N=index
675     bool replaceIntParam(int index, int replaceNumber);
676 
677     /// append single character
678     lString16 & operator << (value_type ch) { return append(1, ch); }
679     /// append c-string
680     lString16 & operator << (const value_type * str) { return append(str); }
681     /// append 8-bit c-string (ASCII only)
682     lString16 & operator << (const lChar8 * str) { return append(str); }
683     /// append string
684     lString16 & operator << (const lString16 & str) { return append(str); }
685     /// append decimal number
686     lString16 & operator << (const fmt::decimal v) { return appendDecimal(v.get()); }
687     /// append hex number
688     lString16 & operator << (const fmt::hex v) { return appendHex(v.get()); }
689 
690     /// returns true if string starts with specified substring
691     bool startsWith (const lString16 & substring) const;
692     /// returns true if string starts with specified substring
693     bool startsWith (const lChar16 * substring) const;
694     /// returns true if string starts with specified substring (8bit ASCII only)
695     bool startsWith (const lChar8 * substring) const;
696     /// returns true if string ends with specified substring
697     bool endsWith(const lChar16 * substring) const;
698     /// returns true if string ends with specified substring (8-bit ASCII only)
699     bool endsWith(const lChar8 * substring) const;
700     /// returns true if string ends with specified substring
701     bool endsWith (const lString16 & substring) const;
702     /// returns true if string starts with specified substring, case insensitive
703     bool startsWithNoCase (const lString16 & substring) const;
704 
705     /// returns last character
lastChar()706     value_type lastChar() { return empty() ? 0 : at(length()-1); }
707     /// returns first character
firstChar()708     value_type firstChar() { return empty() ? 0 : at(0); }
709 
710     /// calculates hash for string
711     lUInt32 getHash() const;
712     /// returns character at specified position, with index bounds checking, fatal error if fails
at(size_type pos)713     value_type & at( size_type pos ) { if ((unsigned)pos > (unsigned)pchunk->len) crFatalError(); return modify()[pos]; }
714     /// returns character at specified position, without index bounds checking
715     value_type operator [] ( size_type pos ) const { return pchunk->buf16[pos]; }
716     /// returns reference to specified character position (lvalue)
717     value_type & operator [] ( size_type pos ) { return modify()[pos]; }
718     /// resizes string, copies if several references exist
719     void  lock( size_type newsize );
720     /// returns writable pointer to string buffer
modify()721     value_type * modify() { if (refCount()>1) lock(pchunk->len); return pchunk->buf16; }
722     /// clears string contents
clear()723     void  clear() { release(); pchunk = EMPTY_STR_16; addref(); }
724     /// resets string, allocates space for specified amount of characters
725     void  reset( size_type size );
726     /// returns string length, in characters
length()727     size_type   length() const { return pchunk->len; }
728     /// returns string length, in characters
size()729     size_type   size() const { return pchunk->len; }
730     /// resizes string buffer, appends with specified character if buffer is being extended
731     void  resize(size_type count = 0, value_type e = 0);
732     /// returns string buffer size
capacity()733     size_type   capacity() const { return pchunk->size-1; }
734     /// ensures string buffer can hold at least count characters
735     void  reserve(size_type count = 0);
736     /// erase all extra characters from end of string after size
737     void  limit( size_type size );
738     /// returns true if string is empty
empty()739     bool  empty() const { return pchunk->len==0; }
740     /// swaps two string variables contents
swap(lString16 & str)741     void  swap( lString16 & str ) { lstring_chunk_t * tmp = pchunk;
742                 pchunk=str.pchunk; str.pchunk=tmp; }
743     /// trims all unused space at end of string (sets size to length)
744     lString16 & pack();
745 
746     /// trims non alpha at beginning and end of string
747     lString16 & trimNonAlpha();
748     /// trims spaces at beginning and end of string
749     lString16 & trim();
750     /// converts to integer
751     int atoi() const;
752     /// converts to integer, returns true if success
753     bool atoi( int &n ) const;
754     /// converts to 64 bit integer, returns true if success
755     bool atoi( lInt64 &n ) const;
756     /// returns constant c-string pointer
c_str()757     const value_type * c_str() const { return pchunk->buf16; }
758     /// returns constant c-string pointer, same as c_str()
data()759     const value_type * data() const { return pchunk->buf16; }
760     /// appends string
761     lString16 & operator += ( lString16 s ) { return append(s); }
762     /// appends c-string
763     lString16 & operator += ( const value_type * s ) { return append(s); }
764     /// append C-string
765     lString16 & operator += ( const lChar8 * s ) { return append(s); }
766     /// appends single character
767     lString16 & operator += ( value_type ch ) { return append(1, ch); }
768     /// append decimal
769     lString16 & operator += ( fmt::decimal v ) { return appendDecimal(v.get()); }
770     /// append hex
771     lString16 & operator += ( fmt::hex v ) { return appendHex(v.get()); }
772 
773     /// constructs string representation of integer
774     static lString16 itoa( int i );
775     /// constructs string representation of unsigned integer
776     static lString16 itoa( unsigned int i );
777     /// constructs string representation of 64 bit integer
778     static lString16 itoa( lInt64 i );
779     /// constructs string representation of unsigned 64 bit integer
780     static lString16 itoa( lUInt64 i );
781 
782     /// empty string global instance
783     static const lString16 empty_str;
784 };
785 
786 
787 /**
788     \brief Wide character (lChar32) string.
789 
790    Reference counting, copy-on-write implementation.
791    Interface is similar to STL strings.
792 
793 */
794 class lString32
795 {
796     friend const lString32 & cs32(const char * str);
797     friend const lString32 & cs32(const lChar32 * str);
798 public:
799     // typedefs for STL compatibility
800     typedef lChar32             value_type;
801     typedef int                 size_type;
802     typedef int                 difference_type;
803     typedef value_type *        pointer;
804     typedef value_type &        reference;
805     typedef const value_type *  const_pointer;
806     typedef const value_type &  const_reference;
807 
808     typedef lstring32_chunk_t    lstring_chunk_t; ///< data container
809 
810 private:
811     lstring_chunk_t * pchunk;
812     static lstring_chunk_t * EMPTY_STR_32;
813     void alloc(size_type sz);
814     void free();
addref()815     inline void addref() const {
816 #ifdef USE_ATOMIC_REFCOUNT
817         pchunk->refCount.fetch_add(1);
818 #else
819         ++pchunk->refCount;
820 #endif
821     }
release()822     inline void release() {
823 #ifdef USE_ATOMIC_REFCOUNT
824         if (pchunk->refCount.fetch_sub(1) <= 1)
825             free();
826 #else
827         if (--pchunk->refCount==0) free();
828 #endif
829     }
refCount()830     inline int refCount() {
831         return pchunk->refCount;
832     }
833 public:
lString32(lstring_chunk_t * chunk)834     explicit lString32(lstring_chunk_t * chunk) : pchunk(chunk) { addref(); }
835     /// empty string constructor
lString32()836     explicit lString32() : pchunk(EMPTY_STR_32) { addref(); }
837     /// copy constructor
lString32(const lString32 & str)838     lString32(const lString32 & str) : pchunk(str.pchunk) { addref(); }
839     /// constructor from wide c-string
840     lString32(const value_type * str);
841     /// constructor from 8bit c-string (ASCII only)
842     explicit lString32(const lChar8 * str);
843     /// constructor from 8bit (ASCII only) character array fragment
844     explicit lString32(const lChar8 * str, size_type count);
845     /// constructor from wide character array fragment
846     explicit lString32(const value_type * str, size_type count);
847     /// constructor from another string substring
848     explicit lString32(const lString32 & str, size_type offset, size_type count);
849     /// desctructor
~lString32()850     ~lString32() { release(); }
851 
852     /// assignment from string
assign(const lString32 & str)853     lString32 & assign(const lString32 & str)
854     {
855         if (pchunk!=str.pchunk)
856         {
857             release();
858             pchunk = str.pchunk;
859             addref();
860         }
861         return *this;
862     }
863     /// assignment from c-string
864     lString32 & assign(const value_type * str);
865     /// assignment from 8bit c-string (ASCII only)
866     lString32 & assign(const lChar8 * str);
867     /// assignment from character array fragment
868     lString32 & assign(const value_type * str, size_type count);
869     /// assignment from 8-bit character array fragment (ASCII only)
870     lString32 & assign(const lChar8 * str, size_type count);
871     /// assignment from string fragment
872     lString32 & assign(const lString32 & str, size_type offset, size_type count);
873     /// assignment from c-string
874     lString32 & operator = (const value_type * str) { return assign(str); }
875     /// assignment from string 8bit ASCII only
876     lString32 & operator = (const lChar8 * str) { return assign(str); }
877     /// assignment from string
878     lString32 & operator = (const lString32 & str) { return assign(str); }
879     lString32 & erase(size_type offset, size_type count);
880 
881     lString32 & append(const value_type * str);
882     lString32 & append(const value_type * str, size_type count);
883     lString32 & append(const lChar8 * str);
884     lString32 & append(const lChar8 * str, size_type count);
885     lString32 & append(const lString32 & str);
886     lString32 & append(const lString32 & str, size_type offset, size_type count);
887     lString32 & append(size_type count, value_type ch);
888     /// append decimal number
889     lString32 & appendDecimal(lInt64 v);
890     /// append hex number
891     lString32 & appendHex(lUInt64 v);
892     lString32 & insert(size_type p0, const value_type * str);
893     lString32 & insert(size_type p0, const value_type * str, size_type count);
894     lString32 & insert(size_type p0, const lString32 & str);
895     lString32 & insert(size_type p0, const lString32 & str, size_type offset, size_type count);
896     lString32 & insert(size_type p0, size_type count, value_type ch);
897     lString32 & replace(size_type p0, size_type n0, const value_type * str);
898     lString32 & replace(size_type p0, size_type n0, const value_type * str, size_type count);
899     lString32 & replace(size_type p0, size_type n0, const lString32 & str);
900     lString32 & replace(size_type p0, size_type n0, const lString32 & str, size_type offset, size_type count);
901     /// replace range of string with character ch repeated count times
902     lString32 & replace(size_type p0, size_type n0, size_type count, value_type ch);
903     /// make string uppercase
904     lString32 & uppercase();
905     /// make string lowercase
906     lString32 & lowercase();
907     /// make string capitalized
908     lString32 & capitalize();
909     /// make string use full width chars
910     lString32 & fullWidthChars();
911     /// compare with another string
compare(const lString32 & str)912     int compare(const lString32& str) const { return lStr_cmp(pchunk->buf32, str.pchunk->buf32); }
913     /// compare subrange with another string
914     int compare(size_type p0, size_type n0, const lString32& str) const;
915     /// compare subrange with substring of another string
916     int compare(size_type p0, size_type n0, const lString32& str, size_type pos, size_type n) const;
compare(const value_type * s)917     int compare(const value_type *s) const  { return lStr_cmp(pchunk->buf32, s); }
compare(const lChar8 * s)918     int compare(const lChar8 *s) const  { return lStr_cmp(pchunk->buf32, s); }
919     int compare(size_type p0, size_type n0, const value_type *s) const;
920     int compare(size_type p0, size_type n0, const value_type *s, size_type pos) const;
921 
922     /// split string into two strings using delimiter
923     bool split2( const lString32 & delim, lString32 & value1, lString32 & value2 );
924     /// split string into two strings using delimiter
925     bool split2( const lChar32 * delim, lString32 & value1, lString32 & value2 );
926     /// split string into two strings using delimiter
927     bool split2( const lChar8 * delim, lString32 & value1, lString32 & value2 );
928 
929     /// returns n characters beginning with pos
930     lString32 substr(size_type pos, size_type n) const;
931     /// returns part of string from specified position to end of string
substr(size_type pos)932     lString32 substr(size_type pos) const { return substr(pos, length()-pos); }
933     /// replaces first found occurence of pattern
934     bool replace(const lString32 & findStr, const lString32 & replaceStr);
935     /// replaces first found occurence of "$N" pattern with string, where N=index
936     bool replaceParam(int index, const lString32 & replaceStr);
937     /// replaces first found occurence of "$N" pattern with itoa of integer, where N=index
938     bool replaceIntParam(int index, int replaceNumber);
939 
940     /// find position of char inside string, -1 if not found
941     int pos(lChar32 ch) const;
942     /// find position of char inside string starting from specified position, -1 if not found
943     int pos(lChar32 ch, int start) const;
944     /// find position of substring inside string, -1 if not found
945     int pos(lString32 subStr) const;
946     /// find position of substring inside string starting from specified position, -1 if not found
947     int pos(const lString32 & subStr, int start) const;
948     /// find position of substring inside string, -1 if not found
949     int pos(const lChar32 * subStr) const;
950     /// find position of substring inside string (8bit ASCII only), -1 if not found
951     int pos(const lChar8 * subStr) const;
952     /// find position of substring inside string starting from specified position, -1 if not found
953     int pos(const lChar32 * subStr, int start) const;
954     /// find position of substring inside string (8bit ASCII only) starting from specified position, -1 if not found
955     int pos(const lChar8 * subStr, int start) const;
956 
957     /// find position of substring inside string, right to left, return -1 if not found
958     int rpos(lString32 subStr) const;
959 
960     /// append single character
961     lString32 & operator << (value_type ch) { return append(1, ch); }
962     /// append c-string
963     lString32 & operator << (const value_type * str) { return append(str); }
964     /// append 8-bit c-string (ASCII only)
965     lString32 & operator << (const lChar8 * str) { return append(str); }
966     /// append string
967     lString32 & operator << (const lString32 & str) { return append(str); }
968     /// append decimal number
969     lString32 & operator << (const fmt::decimal v) { return appendDecimal(v.get()); }
970     /// append hex number
971     lString32 & operator << (const fmt::hex v) { return appendHex(v.get()); }
972 
973     /// returns true if string starts with specified substring
974     bool startsWith (const lString32 & substring) const;
975     /// returns true if string starts with specified substring
976     bool startsWith (const lChar32 * substring) const;
977     /// returns true if string starts with specified substring (8bit ASCII only)
978     bool startsWith (const lChar8 * substring) const;
979     /// returns true if string ends with specified substring
980     bool endsWith(const lChar32 * substring) const;
981     /// returns true if string ends with specified substring (8-bit ASCII only)
982     bool endsWith(const lChar8 * substring) const;
983     /// returns true if string ends with specified substring
984     bool endsWith (const lString32 & substring) const;
985     /// returns true if string starts with specified substring, case insensitive
986     bool startsWithNoCase (const lString32 & substring) const;
987 
988     /// returns last character
lastChar()989     value_type lastChar() { return empty() ? 0 : at(length()-1); }
990     /// returns first character
firstChar()991     value_type firstChar() { return empty() ? 0 : at(0); }
992 
993     /// calculates hash for string
994     lUInt32 getHash() const;
995     /// returns character at specified position, with index bounds checking, fatal error if fails
at(size_type pos)996     value_type & at( size_type pos ) { if ((unsigned)pos > (unsigned)pchunk->len) crFatalError(); return modify()[pos]; }
997     /// returns character at specified position, without index bounds checking
998     value_type operator [] ( size_type pos ) const { return pchunk->buf32[pos]; }
999     /// returns reference to specified character position (lvalue)
1000     value_type & operator [] ( size_type pos ) { return modify()[pos]; }
1001     /// resizes string, copies if several references exist
1002     void  lock( size_type newsize );
1003     /// returns writable pointer to string buffer
modify()1004     value_type * modify() { if (refCount()>1) lock(pchunk->len); return pchunk->buf32; }
1005     /// clears string contents
clear()1006     void  clear() { release(); pchunk = EMPTY_STR_32; addref(); }
1007     /// resets string, allocates space for specified amount of characters
1008     void  reset( size_type size );
1009     /// returns string length, in characters
length()1010     size_type   length() const { return pchunk->len; }
1011     /// returns string length, in characters
size()1012     size_type   size() const { return pchunk->len; }
1013     /// resizes string buffer, appends with specified character if buffer is being extended
1014     void  resize(size_type count = 0, value_type e = 0);
1015     /// returns string buffer size
capacity()1016     size_type   capacity() const { return pchunk->size-1; }
1017     /// ensures string buffer can hold at least count characters
1018     void  reserve(size_type count = 0);
1019     /// erase all extra characters from end of string after size
1020     void  limit( size_type size );
1021     /// returns true if string is empty
empty()1022     bool  empty() const { return pchunk->len==0; }
1023     /// swaps two string variables contents
swap(lString32 & str)1024     void  swap( lString32 & str ) { lstring_chunk_t * tmp = pchunk;
1025                 pchunk=str.pchunk; str.pchunk=tmp; }
1026     /// trims all unused space at end of string (sets size to length)
1027     lString32 & pack();
1028 
1029     /// trims non alpha at beginning and end of string
1030     lString32 & trimNonAlpha();
1031     /// trims spaces at beginning and end of string
1032     lString32 & trim();
1033     /// trims duplicate space characters inside string and (optionally) at end and beginning of string
1034     lString32 & trimDoubleSpaces( bool allowStartSpace, bool allowEndSpace, bool removeEolHyphens=false );
1035     /// converts to integer
1036     int atoi() const;
1037     /// converts to integer, returns true if success
1038     bool atoi( int &n ) const;
1039     /// converts to 64 bit integer, returns true if success
1040     bool atoi( lInt64 &n ) const;
1041     /// returns constant c-string pointer
c_str()1042     const value_type * c_str() const { return pchunk->buf32; }
1043     /// returns constant c-string pointer, same as c_str()
data()1044     const value_type * data() const { return pchunk->buf32; }
1045     /// appends string
1046     lString32 & operator += ( lString32 s ) { return append(s); }
1047     /// appends c-string
1048     lString32 & operator += ( const value_type * s ) { return append(s); }
1049     /// append C-string
1050     lString32 & operator += ( const lChar8 * s ) { return append(s); }
1051     /// appends single character
1052     lString32 & operator += ( value_type ch ) { return append(1, ch); }
1053     /// append decimal
1054     lString32 & operator += ( fmt::decimal v ) { return appendDecimal(v.get()); }
1055     /// append hex
1056     lString32 & operator += ( fmt::hex v ) { return appendHex(v.get()); }
1057 
1058     /// constructs string representation of integer
1059     static lString32 itoa( int i );
1060     /// constructs string representation of unsigned integer
1061     static lString32 itoa( unsigned int i );
1062     /// constructs string representation of 64 bit integer
1063     static lString32 itoa( lInt64 i );
1064     /// constructs string representation of unsigned 64 bit integer
1065     static lString32 itoa( lUInt64 i );
1066 
1067     /// empty string global instance
1068     static const lString32 empty_str;
1069 
1070     friend class lString32Collection;
1071 };
1072 
1073 /// calculates hash for wide string
getHash(const lString32 & s)1074 inline lUInt32 getHash( const lString32 & s )
1075 {
1076     return s.getHash();
1077 }
1078 
getHash(const lString16 & s)1079 inline lUInt32 getHash( const lString16 & s )
1080 {
1081     return s.getHash();
1082 }
1083 
1084 /// calculates hash for string
getHash(const lString8 & s)1085 inline lUInt32 getHash( const lString8 & s )
1086 {
1087     return s.getHash();
1088 }
1089 
1090 /// get reference to atomic constant string for string literal e.g. cs8("abc") -- fast and memory effective replacement of lString8("abc")
1091 const lString8 & cs8(const char * str);
1092 /// get reference to atomic constant wide string for string literal e.g. cs32("abc") -- fast and memory effective replacement of lString32("abc")
1093 const lString32 & cs32(const char * str);
1094 /// get reference to atomic constant wide string for string literal e.g. cs32(L"abc") -- fast and memory effective replacement of lString32(L"abc")
1095 const lString32 & cs32(const lChar32 * str);
1096 
1097 /// calculates hash for wide c-string
1098 lUInt32 calcStringHash( const lChar16 * s );
1099 lUInt32 calcStringHash( const lChar32 * s );
1100 
1101 /// returns true if two wide strings are equal
1102 inline bool operator == (const lString16& s1, const lString16& s2 )
1103     { return s1.compare(s2)==0; }
1104 /// returns true if two wide strings are equal
1105 inline bool operator == (const lString32& s1, const lString32& s2 )
1106     { return s1.compare(s2)==0; }
1107 /// returns true if wide strings is equal to wide c-string
1108 inline bool operator == (const lString16& s1, const lChar16 * s2 )
1109     { return s1.compare(s2)==0; }
1110 /// returns true if wide strings is equal to wide c-string
1111 inline bool operator == (const lString32& s1, const lChar32 * s2 )
1112     { return s1.compare(s2)==0; }
1113 /// returns true if wide strings is equal to wide c-string
1114 inline bool operator == (const lString16& s1, const lChar8 * s2 )
1115     { return s1.compare(s2)==0; }
1116 /// returns true if wide strings is equal to wide c-string
1117 inline bool operator == (const lString32& s1, const lChar8 * s2 )
1118     { return s1.compare(s2)==0; }
1119 /// returns true if wide strings is equal to wide c-string
1120 inline bool operator == (const lChar32 * s1, const lString32& s2 )
1121     { return s2.compare(s1)==0; }
1122 /// returns true if wide strings is equal to wide c-string
1123 inline bool operator == (const lChar16 * s1, const lString16& s2 )
1124     { return s2.compare(s1)==0; }
1125 
1126 /// returns true if wide strings is equal to wide c-string
1127 inline bool operator == (const lString16& s1, const lString8& s2 )
1128     { return lStr_cmp(s2.c_str(), s1.c_str())==0; }
1129 /// returns true if wide strings is equal to wide c-string
1130 inline bool operator == (const lString32& s1, const lString16& s2 )
1131     { return lStr_cmp(s2.c_str(), s1.c_str())==0; }
1132 /// returns true if wide strings is equal to wide c-string
1133 inline bool operator == (const lString32& s1, const lString8& s2 )
1134     { return lStr_cmp(s2.c_str(), s1.c_str())==0; }
1135 /// returns true if wide strings is equal to wide c-string
1136 inline bool operator == (const lString8& s1, const lString32& s2 )
1137     { return lStr_cmp(s2.c_str(), s1.c_str())==0; }
1138 /// returns true if wide strings is equal to wide c-string
1139 inline bool operator == (const lString16& s1, const lString32& s2 )
1140     { return lStr_cmp(s2.c_str(), s1.c_str())==0; }
1141 
1142 inline bool operator != (const lString16& s1, const lString16& s2 )
1143     { return s1.compare(s2)!=0; }
1144 inline bool operator != (const lString32& s1, const lString32& s2 )
1145     { return s1.compare(s2)!=0; }
1146 inline bool operator != (const lString16& s1, const lChar16 * s2 )
1147     { return s1.compare(s2)!=0; }
1148 inline bool operator != (const lString32& s1, const lChar32 * s2 )
1149     { return s1.compare(s2)!=0; }
1150 inline bool operator != (const lString16& s1, const lChar8 * s2 )
1151     { return s1.compare(s2)!=0; }
1152 inline bool operator != (const lString32& s1, const lChar8 * s2 )
1153     { return s1.compare(s2)!=0; }
1154 inline bool operator != (const lChar16 * s1, const lString16& s2 )
1155     { return s2.compare(s1)!=0; }
1156 inline bool operator != (const lChar32 * s1, const lString32& s2 )
1157     { return s2.compare(s1)!=0; }
1158 inline bool operator != (const lChar8 * s1, const lString16& s2 )
1159     { return s2.compare(s1)!=0; }
1160 inline bool operator != (const lChar8 * s1, const lString32& s2 )
1161     { return s2.compare(s1)!=0; }
1162 inline lString32 operator + (const lString32 &s1, const lString32 &s2) { lString32 s(s1); s.append(s2); return s; }
1163 inline lString32 operator + (const lString32 &s1, const lChar32 * s2) { lString32 s(s1); s.append(s2); return s; }
1164 inline lString32 operator + (const lString32 &s1, const lChar8 * s2) { lString32 s(s1); s.append(s2); return s; }
1165 inline lString32 operator + (const lChar32 * s1,  const lString32 &s2) { lString32 s(s1); s.append(s2); return s; }
1166 inline lString32 operator + (const lChar8 * s1,  const lString32 &s2) { lString32 s(s1); s.append(s2); return s; }
1167 inline lString32 operator + (const lString32 &s1, fmt::decimal v) { lString32 s(s1); s.appendDecimal(v.get()); return s; }
1168 inline lString32 operator + (const lString32 &s1, fmt::hex v) { lString32 s(s1); s.appendHex(v.get()); return s; }
1169 
1170 inline bool operator == (const lString8& s1, const lString8& s2 )
1171     { return s1.compare(s2)==0; }
1172 inline bool operator == (const lString8& s1, const lChar8 * s2 )
1173     { return s1.compare(s2)==0; }
1174 inline bool operator == (const lChar8 * s1, const lString8& s2 )
1175     { return s2.compare(s1)==0; }
1176 inline bool operator != (const lString8& s1, const lString8& s2 )
1177     { return s1.compare(s2)!=0; }
1178 inline bool operator != (const lString8& s1, const lChar8 * s2 )
1179     { return s1.compare(s2)!=0; }
1180 inline bool operator != (const lChar8 * s1, const lString8& s2 )
1181     { return s2.compare(s1)!=0; }
1182 inline lString8 operator + (const lString8 &s1, const lString8 &s2)
1183     { lString8 s(s1); s.append(s2); return s; }
1184 inline lString8 operator + (const lString8 &s1, const lChar8 * s2)
1185     { lString8 s(s1); s.append(s2); return s; }
1186 inline lString8 operator + (const lString8 &s1, fmt::decimal v)
1187     { lString8 s(s1); s.appendDecimal(v.get()); return s; }
1188 inline lString8 operator + (const lString8 &s1, fmt::hex v)
1189     { lString8 s(s1); s.appendHex(v.get()); return s; }
1190 
1191 
1192 lString8  UnicodeToTranslit( const lString32 & str );
1193 /// converts wide unicode string to local 8-bit encoding
1194 lString8  UnicodeToLocal( const lString32 & str );
1195 /// converts wide unicode string to utf-8 string
1196 lString8  UnicodeToUtf8( const lString32 & str );
1197 /// converts wide unicode string to utf-16 string
1198 lString16  UnicodeToUtf16( const lString32 & str );
1199 /// converts wide unicode string to utf-8 string
1200 lString8 UnicodeToUtf8(const lChar32 * s, int count);
1201 /// converts wide unicode string to utf-16 string
1202 lString16 UnicodeToUtf16(const lChar32 * s, int count);
1203 /// converts wide unicode string to wtf-8 string
1204 lString8  UnicodeToWtf8( const lString32 & str );
1205 /// converts wide unicode string to wtf-8 string
1206 lString8 UnicodeToWtf8(const lChar32 * s, int count);
1207 /// converts unicode string to 8-bit string using specified conversion table
1208 lString8  UnicodeTo8Bit( const lString32 & str, const lChar8 * * table );
1209 /// converts 8-bit string to unicode string using specified conversion table for upper 128 characters
1210 lString32 ByteToUnicode( const lString8 & str, const lChar32 * table );
1211 /// converts 8-bit string in local encoding to wide unicode string
1212 lString32 LocalToUnicode( const lString8 & str );
1213 /// converts utf-8 string to wide unicode string
1214 lString32 Utf8ToUnicode( const lString8 & str );
1215 /// converts utf-8 c-string to wide unicode string
1216 lString32 Utf8ToUnicode( const char * s );
1217 /// converts utf-8 string fragment to wide unicode string
1218 lString32 Utf8ToUnicode( const char * s, int sz );
1219 /// converts utf-8 string fragment to wide unicode string
1220 void Utf8ToUnicode(const lUInt8 * src,  int &srclen, lChar32 * dst, int &dstlen);
1221 /// converts utf-16 string to wide unicode string
1222 lString32 Utf16ToUnicode( const lString16 & str );
1223 /// converts utf-16 c-string to wide unicode string
1224 lString32 Utf16ToUnicode( const lChar16 * s );
1225 /// converts utf-16 string fragment to wide unicode string
1226 lString32 Utf16ToUnicode( const lChar16 * s, int sz );
1227 /// converts utf-16 string fragment to wide unicode string
1228 void Utf16ToUnicode(const lChar16 * src,  int &srclen, lChar32 * dst, int &dstlen);
1229 /// converts wtf-8 string to wide unicode string
1230 lString32 Wtf8ToUnicode( const lString8 & str );
1231 /// converts utf-8 c-string to wide unicode string
1232 lString32 Wtf8ToUnicode( const char * s );
1233 /// converts utf-8 string fragment to wide unicode string
1234 lString32 Wtf8ToUnicode( const char * s, int sz );
1235 /// decodes path like "file%20name" to "file name"
1236 lString32 DecodeHTMLUrlString( lString32 s );
1237 /// truncates string by specified size, appends ... if truncated, prefers to wrap whole words
1238 void limitStringSize(lString32 & str, int maxSize);
1239 
1240 int TrimDoubleSpaces(lChar32 * buf, int len,  bool allowStartSpace, bool allowEndSpace, bool removeEolHyphens);
1241 
1242 /// remove soft-hyphens from string
1243 lString32 removeSoftHyphens( lString32 s );
1244 
1245 
1246 #define LCSTR(x) (UnicodeToUtf8(x).c_str())
1247 bool splitIntegerList( lString32 s, lString32 delim, int & value1, int & value2 );
1248 
1249 #if LDOM_USE_OWN_MEM_MAN==1
1250 void free_ls_storage();
1251 #endif
1252 
1253 #endif  // __LV_STRING_H_INCLUDED__
1254