KJS

ustring.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 1999-2000 Harri Porten ([email protected])
4  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
5  * Copyright (C) 2007 Cameron Zwarich ([email protected])
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 #include "ustring.h"
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include "wtf/DisallowCType.h"
29 #include "wtf/ASCIICType.h"
30 #if HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
33 #include <limits.h>
34 
35 #include "operations.h"
36 #include "function.h"
37 #include "identifier.h"
38 #include <math.h>
39 #include "dtoa.h"
40 #include "commonunicode.h"
41 
42 
43 using std::max;
44 
45 // GCC cstring uses these automatically, but not all implementations do.
46 using std::strlen;
47 using std::strcpy;
48 using std::strncpy;
49 using std::memset;
50 using std::memcpy;
51 
52 using namespace WTF;
53 
54 namespace KJS
55 {
56 
57 extern const double NaN;
58 extern const double Inf;
59 
60 static inline size_t overflowIndicator()
61 {
62  return std::numeric_limits<size_t>::max();
63 }
64 static inline size_t maxUChars()
65 {
66  // We don't want strings to get too crazy, since OOM hurts... and since we use 32-bit lengths
67  // on 64-bit, too, keeping this small prevents overflows.
68  return 0xFFFFFFF;
69 }
70 
71 static inline UChar *allocChars(size_t length)
72 {
73  assert(length);
74  if (length > maxUChars()) {
75  return nullptr;
76  }
77  return static_cast<UChar *>(fastMalloc(sizeof(UChar) * length));
78 }
79 
80 static inline UChar *reallocChars(UChar *buffer, size_t length)
81 {
82  ASSERT(length);
83  if (length > maxUChars()) {
84  return nullptr;
85  }
86  return static_cast<UChar *>(fastRealloc(buffer, sizeof(UChar) * length));
87 }
88 
89 CString::CString(const char *c)
90 {
91  length = strlen(c);
92  data = new char[length + 1];
93  memcpy(data, c, length + 1);
94 }
95 
96 CString::CString(const char *c, size_t len)
97 {
98  length = len;
99  data = new char[len + 1];
100  memcpy(data, c, len);
101  data[len] = 0;
102 }
103 
104 CString::CString(const CString &b)
105 {
106  length = b.length;
107  if (length > 0 && b.data) {
108  data = new char[length + 1];
109  memcpy(data, b.data, length + 1);
110  } else {
111  data = nullptr;
112  }
113 }
114 
115 CString::~CString()
116 {
117  delete [] data;
118 }
119 
120 CString &CString::operator=(const char *c)
121 {
122  if (data) {
123  delete [] data;
124  }
125  length = strlen(c);
126  data = new char[length + 1];
127  memcpy(data, c, length + 1);
128 
129  return *this;
130 }
131 
132 CString &CString::operator=(const CString &str)
133 {
134  if (this == &str) {
135  return *this;
136  }
137 
138  if (data) {
139  delete [] data;
140  }
141  length = str.length;
142  if (str.data) {
143  data = new char[length + 1];
144  memcpy(data, str.data, length + 1);
145  } else {
146  data = nullptr;
147  }
148 
149  return *this;
150 }
151 
152 bool operator==(const CString &c1, const CString &c2)
153 {
154  size_t len = c1.size();
155  return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0);
156 }
157 
158 // Hack here to avoid a global with a constructor; point to an unsigned short instead of a UChar.
159 static unsigned short almostUChar;
160 UString::Rep UString::Rep::null = { 0, 0, 1, 0, 0, &UString::Rep::null, 0, nullptr, 0, 0, 0, 0 };
161 UString::Rep UString::Rep::empty = { 0, 0, 1, 0, 0, &UString::Rep::empty, 0, reinterpret_cast<UChar *>(&almostUChar), 0, 0, 0, 0 };
162 const int normalStatBufferSize = 4096;
163 static char *statBuffer = nullptr; // FIXME: This buffer is never deallocated.
164 static int statBufferSize = 0;
165 
166 PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar *d, int length)
167 {
168  UChar *copyD = allocChars(length);
169  memcpy(copyD, d, length * sizeof(UChar));
170 
171  return create(copyD, length);
172 }
173 
174 PassRefPtr<UString::Rep> UString::Rep::create(UChar *d, int l)
175 {
176  Rep *r = new Rep;
177  r->offset = 0;
178  r->len = l;
179  r->rc = 1;
180  r->_hash = 0;
181  r->isIdentifier = 0;
182  r->baseString = r;
183  r->reportedCost = 0;
184  r->buf = d;
185  r->usedCapacity = l;
186  r->capacity = l;
187  r->usedPreCapacity = 0;
188  r->preCapacity = 0;
189 
190  // steal the single reference this Rep was created with
191  return adoptRef(r);
192 }
193 
194 PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<Rep> base, int offset, int length)
195 {
196  assert(base);
197 
198  int baseOffset = base->offset;
199 
200  base = base->baseString;
201 
202  assert(-(offset + baseOffset) <= base->usedPreCapacity);
203  assert(offset + baseOffset + length <= base->usedCapacity);
204 
205  Rep *r = new Rep;
206  r->offset = baseOffset + offset;
207  r->len = length;
208  r->rc = 1;
209  r->_hash = 0;
210  r->isIdentifier = 0;
211  r->baseString = base.releaseRef();
212  r->reportedCost = 0;
213  r->buf = nullptr;
214  r->usedCapacity = 0;
215  r->capacity = 0;
216  r->usedPreCapacity = 0;
217  r->preCapacity = 0;
218 
219  // steal the single reference this Rep was created with
220  return adoptRef(r);
221 }
222 
223 void UString::Rep::destroy()
224 {
225  if (isIdentifier) {
226  Identifier::remove(this);
227  }
228  if (baseString != this) {
229  baseString->deref();
230  } else {
231  fastFree(buf);
232  }
233  delete this;
234 }
235 
236 // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
237 // or anything like that.
238 const unsigned PHI = 0x9e3779b9U;
239 
240 // Paul Hsieh's SuperFastHash
241 // http://www.azillionmonkeys.com/qed/hash.html
242 unsigned UString::Rep::computeHash(const UChar *s, int len)
243 {
244  unsigned l = len;
245  uint32_t hash = PHI;
246  uint32_t tmp;
247 
248  int rem = l & 1;
249  l >>= 1;
250 
251  // Main loop
252  for (; l > 0; l--) {
253  hash += s[0].uc;
254  tmp = (s[1].uc << 11) ^ hash;
255  hash = (hash << 16) ^ tmp;
256  s += 2;
257  hash += hash >> 11;
258  }
259 
260  // Handle end case
261  if (rem) {
262  hash += s[0].uc;
263  hash ^= hash << 11;
264  hash += hash >> 17;
265  }
266 
267  // Force "avalanching" of final 127 bits
268  hash ^= hash << 3;
269  hash += hash >> 5;
270  hash ^= hash << 2;
271  hash += hash >> 15;
272  hash ^= hash << 10;
273 
274  // this avoids ever returning a hash code of 0, since that is used to
275  // signal "hash not computed yet", using a value that is likely to be
276  // effectively the same as 0 when the low bits are masked
277  if (hash == 0) {
278  hash = 0x80000000;
279  }
280 
281  return hash;
282 }
283 
284 // Paul Hsieh's SuperFastHash
285 // http://www.azillionmonkeys.com/qed/hash.html
286 unsigned UString::Rep::computeHash(const char *s, int len)
287 {
288  // This hash is designed to work on 16-bit chunks at a time. But since the normal case
289  // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
290  // were 16-bit chunks, which should give matching results
291 
292  uint32_t hash = PHI;
293  uint32_t tmp;
294  unsigned l = len;
295 
296  int rem = l & 1;
297  l >>= 1;
298 
299  // Main loop
300  for (; l > 0; l--) {
301  hash += (unsigned char)s[0];
302  tmp = ((unsigned char)s[1] << 11) ^ hash;
303  hash = (hash << 16) ^ tmp;
304  s += 2;
305  hash += hash >> 11;
306  }
307 
308  // Handle end case
309  if (rem) {
310  hash += (unsigned char)s[0];
311  hash ^= hash << 11;
312  hash += hash >> 17;
313  }
314 
315  // Force "avalanching" of final 127 bits
316  hash ^= hash << 3;
317  hash += hash >> 5;
318  hash ^= hash << 2;
319  hash += hash >> 15;
320  hash ^= hash << 10;
321 
322  // this avoids ever returning a hash code of 0, since that is used to
323  // signal "hash not computed yet", using a value that is likely to be
324  // effectively the same as 0 when the low bits are masked
325  if (hash == 0) {
326  hash = 0x80000000;
327  }
328 
329  return hash;
330 }
331 
332 unsigned UString::Rep::computeHash(const char *s)
333 {
334  return computeHash(s, strlen(s));
335 }
336 
337 // put these early so they can be inlined
338 inline size_t UString::expandedSize(size_t size, size_t otherSize) const
339 {
340  // Do the size calculation in two parts, returning overflowIndicator if
341  // we overflow the maximum value that we can handle.
342 
343  if (size > maxUChars()) {
344  return overflowIndicator();
345  }
346 
347  size_t expandedSize = ((size + 10) / 10 * 11) + 1;
348  if (maxUChars() - expandedSize < otherSize) {
349  return overflowIndicator();
350  }
351 
352  return expandedSize + otherSize;
353 }
354 
355 inline int UString::usedCapacity() const
356 {
357  return m_rep->baseString->usedCapacity;
358 }
359 
360 inline int UString::usedPreCapacity() const
361 {
362  return m_rep->baseString->usedPreCapacity;
363 }
364 
365 void UString::expandCapacity(int requiredLength)
366 {
367  Rep *r = m_rep->baseString;
368 
369  if (requiredLength > r->capacity) {
370  size_t newCapacity = expandedSize(requiredLength, r->preCapacity);
371  UChar *oldBuf = r->buf;
372  r->buf = reallocChars(r->buf, newCapacity);
373  if (!r->buf) {
374  r->buf = oldBuf;
375  m_rep = &Rep::null;
376  return;
377  }
378  r->capacity = newCapacity - r->preCapacity;
379  }
380  if (requiredLength > r->usedCapacity) {
381  r->usedCapacity = requiredLength;
382  }
383 }
384 
385 void UString::expandPreCapacity(int requiredPreCap)
386 {
387  Rep *r = m_rep->baseString;
388 
389  if (requiredPreCap > r->preCapacity) {
390  size_t newCapacity = expandedSize(requiredPreCap, r->capacity);
391  int delta = newCapacity - r->capacity - r->preCapacity;
392 
393  UChar *newBuf = allocChars(newCapacity);
394  if (!newBuf) {
395  m_rep = &Rep::null;
396  return;
397  }
398  memcpy(newBuf + delta, r->buf, (r->capacity + r->preCapacity) * sizeof(UChar));
399  fastFree(r->buf);
400  r->buf = newBuf;
401 
402  r->preCapacity = newCapacity - r->capacity;
403  }
404  if (requiredPreCap > r->usedPreCapacity) {
405  r->usedPreCapacity = requiredPreCap;
406  }
407 }
408 
409 UString::UString(Empty)
410  : m_rep(&Rep::empty)
411 {
412 }
413 
415  : m_rep(Rep::create(allocChars(1), 1))
416 {
417  m_rep->buf[0] = static_cast<unsigned char>(c);
418 }
419 
420 UString::UString(const char *c)
421 {
422  if (!c) {
423  m_rep = &Rep::null;
424  return;
425  }
426 
427  if (!c[0]) {
428  m_rep = &Rep::empty;
429  return;
430  }
431 
432  size_t length = strlen(c);
433  UChar *d = allocChars(length);
434  if (!d) {
435  m_rep = &Rep::null;
436  } else {
437  for (size_t i = 0; i < length; i++) {
438  d[i].uc = c[i];
439  }
440  m_rep = Rep::create(d, static_cast<int>(length));
441  }
442 }
443 
444 UString::UString(const char *c, size_t length)
445 {
446  if (!c) {
447  m_rep = &Rep::null;
448  return;
449  }
450 
451  if (length == 0) {
452  m_rep = &Rep::empty;
453  return;
454  }
455 
456  UChar *d = allocChars(length);
457  if (!d) {
458  m_rep = &Rep::null;
459  } else {
460  for (size_t i = 0; i < length; i++) {
461  d[i].uc = c[i];
462  }
463  m_rep = Rep::create(d, static_cast<int>(length));
464  }
465 }
466 
467 UString::UString(const UChar *c, int length)
468 {
469  if (length == 0) {
470  m_rep = &Rep::empty;
471  } else {
472  m_rep = Rep::createCopying(c, length);
473  }
474 }
475 
476 UString::UString(UChar *c, int length, bool copy)
477 {
478  if (length == 0) {
479  m_rep = &Rep::empty;
480  } else if (copy) {
481  m_rep = Rep::createCopying(c, length);
482  } else {
483  m_rep = Rep::create(c, length);
484  }
485 }
486 
487 UString::UString(const Vector<UChar> &buffer)
488 {
489  if (!buffer.size()) {
490  m_rep = &Rep::empty;
491  } else {
492  m_rep = Rep::createCopying(buffer.data(), buffer.size());
493  }
494 }
495 
496 UString::UString(const UString &a, const UString &b)
497 {
498  int aSize = a.size();
499  int aOffset = a.m_rep->offset;
500  int bSize = b.size();
501  int bOffset = b.m_rep->offset;
502  int length = aSize + bSize;
503 
504  // possible cases:
505 
506  if (aSize == 0) {
507  // a is empty
508  m_rep = b.m_rep;
509  } else if (bSize == 0) {
510  // b is empty
511  m_rep = a.m_rep;
512  } else if (aOffset + aSize == a.usedCapacity() && aSize >= minShareSize && 4 * aSize >= bSize &&
513  (-bOffset != b.usedPreCapacity() || aSize >= bSize)) {
514  // - a reaches the end of its buffer so it qualifies for shared append
515  // - also, it's at least a quarter the length of b - appending to a much shorter
516  // string does more harm than good
517  // - however, if b qualifies for prepend and is longer than a, we'd rather prepend
518  UString x(a);
519  x.expandCapacity(aOffset + length);
520  if (a.data() && x.data()) {
521  memcpy(const_cast<UChar *>(a.data() + aSize), b.data(), bSize * sizeof(UChar));
522  m_rep = Rep::create(a.m_rep, 0, length);
523  } else {
524  m_rep = &Rep::null;
525  }
526  } else if (-bOffset == b.usedPreCapacity() && bSize >= minShareSize && 4 * bSize >= aSize) {
527  // - b reaches the beginning of its buffer so it qualifies for shared prepend
528  // - also, it's at least a quarter the length of a - prepending to a much shorter
529  // string does more harm than good
530  UString y(b);
531  y.expandPreCapacity(-bOffset + aSize);
532  if (b.data() && y.data()) {
533  memcpy(const_cast<UChar *>(b.data() - aSize), a.data(), aSize * sizeof(UChar));
534  m_rep = Rep::create(b.m_rep, -aSize, length);
535  } else {
536  m_rep = &Rep::null;
537  }
538  } else {
539  // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
540  size_t newCapacity = expandedSize(length, 0);
541  UChar *d = allocChars(newCapacity);
542  if (!d) {
543  m_rep = &Rep::null;
544  } else {
545  memcpy(d, a.data(), aSize * sizeof(UChar));
546  memcpy(d + aSize, b.data(), bSize * sizeof(UChar));
547  m_rep = Rep::create(d, length);
548  m_rep->capacity = newCapacity;
549  }
550  }
551 }
552 
554 {
555  static UString *n = new UString;
556  return *n;
557 }
558 
560 {
561  UChar buf[1 + sizeof(i) * 3];
562  UChar *end = buf + sizeof(buf) / sizeof(UChar);
563  UChar *p = end;
564 
565  if (i == 0) {
566  *--p = '0';
567  } else if (i == INT_MIN) {
568  char minBuf[1 + sizeof(i) * 3];
569  sprintf(minBuf, "%d", INT_MIN);
570  return UString(minBuf);
571  } else {
572  bool negative = false;
573  if (i < 0) {
574  negative = true;
575  i = -i;
576  }
577  while (i) {
578  *--p = (unsigned short)((i % 10) + '0');
579  i /= 10;
580  }
581  if (negative) {
582  *--p = '-';
583  }
584  }
585 
586  return UString(p, static_cast<int>(end - p));
587 }
588 
589 UString UString::from(unsigned int u)
590 {
591  UChar buf[sizeof(u) * 3];
592  UChar *end = buf + sizeof(buf) / sizeof(UChar);
593  UChar *p = end;
594 
595  if (u == 0) {
596  *--p = '0';
597  } else {
598  while (u) {
599  *--p = (unsigned short)((u % 10) + '0');
600  u /= 10;
601  }
602  }
603 
604  return UString(p, static_cast<int>(end - p));
605 }
606 
608 {
609  UChar buf[1 + sizeof(l) * 3];
610  UChar *end = buf + sizeof(buf) / sizeof(UChar);
611  UChar *p = end;
612 
613  if (l == 0) {
614  *--p = '0';
615  } else if (l == LONG_MIN) {
616  char minBuf[1 + sizeof(l) * 3];
617  sprintf(minBuf, "%ld", LONG_MIN);
618  return UString(minBuf);
619  } else {
620  bool negative = false;
621  if (l < 0) {
622  negative = true;
623  l = -l;
624  }
625  while (l) {
626  *--p = (unsigned short)((l % 10) + '0');
627  l /= 10;
628  }
629  if (negative) {
630  *--p = '-';
631  }
632  }
633 
634  return UString(p, static_cast<int>(end - p));
635 }
636 
638 {
639  // avoid ever printing -NaN, in JS conceptually there is only one NaN value
640  if (isNaN(d)) {
641  return UString("NaN", 3);
642  }
643 
644  char buf[80];
645  int decimalPoint;
646  int sign;
647 
648  char *result = kjs_dtoa(d, 0, 0, &decimalPoint, &sign, nullptr);
649  int length = static_cast<int>(strlen(result));
650 
651  int i = 0;
652  if (sign) {
653  buf[i++] = '-';
654  }
655 
656  if (decimalPoint <= 0 && decimalPoint > -6) {
657  buf[i++] = '0';
658  buf[i++] = '.';
659  for (int j = decimalPoint; j < 0; j++) {
660  buf[i++] = '0';
661  }
662  strcpy(buf + i, result);
663  i += length;
664  } else if (decimalPoint <= 21 && decimalPoint > 0) {
665  if (length <= decimalPoint) {
666  strcpy(buf + i, result);
667  i += length;
668  for (int j = 0; j < decimalPoint - length; j++) {
669  buf[i++] = '0';
670  }
671 // buf[i] = '\0';
672  } else {
673  strncpy(buf + i, result, decimalPoint);
674  i += decimalPoint;
675  buf[i++] = '.';
676  strcpy(buf + i, result + decimalPoint);
677  i += length - decimalPoint;
678  }
679  } else if (result[0] < '0' || result[0] > '9') {
680  strcpy(buf + i, result);
681  i += length;
682  } else {
683  buf[i++] = result[0];
684  if (length > 1) {
685  buf[i++] = '.';
686  strcpy(buf + i, result + 1);
687  i += length - 1;
688  }
689 
690  buf[i++] = 'e';
691  buf[i++] = (decimalPoint >= 0) ? '+' : '-';
692  // decimalPoint can't be more than 3 digits decimal given the
693  // nature of float representation
694  int exponential = decimalPoint - 1;
695  if (exponential < 0) {
696  exponential = exponential * -1;
697  }
698  if (exponential >= 100) {
699  buf[i++] = '0' + exponential / 100;
700  }
701  if (exponential >= 10) {
702  buf[i++] = '0' + (exponential % 100) / 10;
703  }
704  buf[i++] = '0' + exponential % 10;
705 // buf[i++] = '\0';
706  }
707 
708  kjs_freedtoa(result);
709 
710  return UString(buf, i);
711 }
712 
713 UString UString::spliceSubstringsWithSeparators(const Range *substringRanges, int rangeCount, const UString *separators, int separatorCount) const
714 {
715  if (rangeCount == 1 && separatorCount == 0) {
716  int thisSize = size();
717  int position = substringRanges[0].position;
718  int length = substringRanges[0].length;
719  if (position <= 0 && length >= thisSize) {
720  return *this;
721  }
722  return UString::Rep::create(m_rep, maxInt(0, position), minInt(thisSize, length));
723  }
724 
725  int totalLength = 0;
726  for (int i = 0; i < rangeCount; i++) {
727  totalLength += substringRanges[i].length;
728  }
729  for (int i = 0; i < separatorCount; i++) {
730  totalLength += separators[i].size();
731  }
732 
733  if (totalLength == 0) {
734  return "";
735  }
736 
737  UChar *buffer = allocChars(totalLength);
738  if (!buffer) {
739  return null();
740  }
741 
742  int maxCount = max(rangeCount, separatorCount);
743  int bufferPos = 0;
744  for (int i = 0; i < maxCount; i++) {
745  if (i < rangeCount) {
746  memcpy(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length * sizeof(UChar));
747  bufferPos += substringRanges[i].length;
748  }
749  if (i < separatorCount) {
750  memcpy(buffer + bufferPos, separators[i].data(), separators[i].size() * sizeof(UChar));
751  bufferPos += separators[i].size();
752  }
753  }
754 
755  return UString::Rep::create(buffer, totalLength);
756 }
757 
758 // Append a sub-string of <subStr> to this string.
759 // Equivalent to append(subStr.substr(subPos, subLength))
760 
761 UString &UString::append(const UString &subStr, int subPos, int subLength)
762 {
763  int subSize = subStr.size();
764 
765  if (subPos < 0) {
766  subPos = 0;
767  } else if (subPos >= subSize) {
768  subPos = subSize;
769  }
770  if (subLength < 0) {
771  subLength = subSize;
772  }
773  if (subPos + subLength >= subSize) {
774  subLength = subSize - subPos;
775  }
776 
777  return append(UString(subStr.data() + subPos, subLength));
778 }
779 
781 {
782  int thisSize = size();
783  int thisOffset = m_rep->offset;
784  int tSize = t.size();
785  int length = thisSize + tSize;
786 
787  // possible cases:
788  if (thisSize == 0) {
789  // this is empty
790  *this = t;
791  } else if (tSize == 0) {
792  // t is empty
793  } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
794  // this is direct and has refcount of 1 (so we can just alter it directly)
795  expandCapacity(thisOffset + length);
796  if (data()) {
797  memcpy(const_cast<UChar *>(data() + thisSize), t.data(), tSize * sizeof(UChar));
798  m_rep->len = length;
799  m_rep->_hash = 0;
800  }
801  } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) {
802  // this reaches the end of the buffer - extend it if it's long enough to append to
803  expandCapacity(thisOffset + length);
804  if (data()) {
805  memcpy(const_cast<UChar *>(data() + thisSize), t.data(), tSize * sizeof(UChar));
806  m_rep = Rep::create(m_rep, 0, length);
807  }
808  } else {
809  // this is shared with someone using more capacity, gotta make a whole new string
810  size_t newCapacity = expandedSize(length, 0);
811  UChar *d = allocChars(newCapacity);
812  if (!d) {
813  m_rep = &Rep::null;
814  } else {
815  memcpy(d, data(), thisSize * sizeof(UChar));
816  memcpy(const_cast<UChar *>(d + thisSize), t.data(), tSize * sizeof(UChar));
817  m_rep = Rep::create(d, length);
818  m_rep->capacity = newCapacity;
819  }
820  }
821 
822  return *this;
823 }
824 
825 UString &UString::append(const char *t)
826 {
827  int thisSize = size();
828  int thisOffset = m_rep->offset;
829  int tSize = static_cast<int>(strlen(t));
830  int length = thisSize + tSize;
831 
832  // possible cases:
833  if (thisSize == 0) {
834  // this is empty
835  *this = t;
836  } else if (tSize == 0) {
837  // t is empty, we'll just return *this below.
838  } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
839  // this is direct and has refcount of 1 (so we can just alter it directly)
840  expandCapacity(thisOffset + length);
841  UChar *d = const_cast<UChar *>(data());
842  if (d) {
843  for (int i = 0; i < tSize; ++i) {
844  d[thisSize + i] = t[i];
845  }
846  m_rep->len = length;
847  m_rep->_hash = 0;
848  }
849  } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) {
850  // this string reaches the end of the buffer - extend it
851  expandCapacity(thisOffset + length);
852  UChar *d = const_cast<UChar *>(data());
853  if (d) {
854  for (int i = 0; i < tSize; ++i) {
855  d[thisSize + i] = t[i];
856  }
857  m_rep = Rep::create(m_rep, 0, length);
858  }
859  } else {
860  // this is shared with someone using more capacity, gotta make a whole new string
861  size_t newCapacity = expandedSize(length, 0);
862  UChar *d = allocChars(newCapacity);
863  if (!d) {
864  m_rep = &Rep::null;
865  } else {
866  memcpy(d, data(), thisSize * sizeof(UChar));
867  for (int i = 0; i < tSize; ++i) {
868  d[thisSize + i] = t[i];
869  }
870  m_rep = Rep::create(d, length);
871  m_rep->capacity = newCapacity;
872  }
873  }
874 
875  return *this;
876 }
877 
878 UString &UString::append(unsigned short c)
879 {
880  int thisOffset = m_rep->offset;
881  int length = size();
882 
883  // possible cases:
884  if (length == 0) {
885  // this is empty - must make a new m_rep because we don't want to pollute the shared empty one
886  size_t newCapacity = expandedSize(1, 0);
887  UChar *d = allocChars(newCapacity);
888  if (!d) {
889  m_rep = &Rep::null;
890  } else {
891  d[0] = c;
892  m_rep = Rep::create(d, 1);
893  m_rep->capacity = newCapacity;
894  }
895  } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
896  // this is direct and has refcount of 1 (so we can just alter it directly)
897  expandCapacity(thisOffset + length + 1);
898  UChar *d = const_cast<UChar *>(data());
899  if (d) {
900  d[length] = c;
901  m_rep->len = length + 1;
902  m_rep->_hash = 0;
903  }
904  } else if (thisOffset + length == usedCapacity() && length >= minShareSize) {
905  // this reaches the end of the string - extend it and share
906  expandCapacity(thisOffset + length + 1);
907  UChar *d = const_cast<UChar *>(data());
908  if (d) {
909  d[length] = c;
910  m_rep = Rep::create(m_rep, 0, length + 1);
911  }
912  } else {
913  // this is shared with someone using more capacity, gotta make a whole new string
914  size_t newCapacity = expandedSize(length + 1, 0);
915  UChar *d = allocChars(newCapacity);
916  if (!d) {
917  m_rep = &Rep::null;
918  } else {
919  memcpy(d, data(), length * sizeof(UChar));
920  d[length] = c;
921  m_rep = Rep::create(d, length + 1);
922  m_rep->capacity = newCapacity;
923  }
924  }
925 
926  return *this;
927 }
928 
930 {
931  return ascii();
932 }
933 
934 char *UString::ascii() const
935 {
936  // Never make the buffer smaller than normalStatBufferSize.
937  // Thus we almost never need to reallocate.
938  int length = size();
939  int neededSize = length + 1;
940  if (neededSize < normalStatBufferSize) {
941  neededSize = normalStatBufferSize;
942  }
943  if (neededSize != statBufferSize) {
944  delete [] statBuffer;
945  statBuffer = new char [neededSize];
946  statBufferSize = neededSize;
947  }
948 
949  const UChar *p = data();
950  char *q = statBuffer;
951  const UChar *limit = p + length;
952  while (p != limit) {
953  *q = static_cast<char>(p->uc);
954  ++p;
955  ++q;
956  }
957  *q = '\0';
958 
959  return statBuffer;
960 }
961 
962 UString &UString::operator=(Empty)
963 {
964  m_rep = &Rep::empty;
965 
966  return *this;
967 }
968 
969 UString &UString::operator=(const char *c)
970 {
971  set(c, c ? strlen(c) : 0);
972 
973  return *this;
974 }
975 
976 void UString::set(const char *c, int l)
977 {
978  if (!c) {
979  m_rep = &Rep::null;
980  return;
981  }
982 
983  if (l == 0) {
984  m_rep = &Rep::empty;
985  return;
986  }
987 
988  UChar *d;
989  if (m_rep->rc == 1 && l <= m_rep->capacity && m_rep->baseIsSelf() && m_rep->offset == 0 && m_rep->preCapacity == 0) {
990  d = m_rep->buf;
991  m_rep->_hash = 0;
992  m_rep->len = l;
993  } else {
994  d = allocChars(l);
995  if (!d) {
996  m_rep = &Rep::null;
997  return;
998  }
999  m_rep = Rep::create(d, l);
1000  }
1001  for (int i = 0; i < l; i++) {
1002  d[i].uc = static_cast<unsigned char>(c[i]);
1003  }
1004 }
1005 
1006 bool UString::is8Bit() const
1007 {
1008  const UChar *u = data();
1009  const UChar *limit = u + size();
1010  while (u < limit) {
1011  if (u->uc > 0xFF) {
1012  return false;
1013  }
1014  ++u;
1015  }
1016 
1017  return true;
1018 }
1019 
1020 const UChar UString::operator[](int pos) const
1021 {
1022  if (pos >= size()) {
1023  return '\0';
1024  }
1025  return data()[pos];
1026 }
1027 
1028 double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
1029 {
1030  double d;
1031 
1032  const int length = size();
1033  int leadingSpaces = 0;
1034 
1035  // skip leading white space
1036  while (leadingSpaces < length && CommonUnicode::isStrWhiteSpace(data()[leadingSpaces].uc)) {
1037  ++leadingSpaces;
1038  }
1039 
1040  UString whitespaceSkipped = substr(leadingSpaces, length - leadingSpaces);
1041 
1042  // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
1043  // after the number, so is8Bit is too strict a check.
1044  if (!whitespaceSkipped.is8Bit()) {
1045  return NaN;
1046  }
1047 
1048  const char *c = whitespaceSkipped.ascii();
1049 
1050  // empty string ?
1051  if (*c == '\0') {
1052  return tolerateEmptyString ? 0.0 : NaN;
1053  }
1054 
1055  // hex number ?
1056  if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) {
1057  const char *firstDigitPosition = c + 2;
1058  c++;
1059  d = 0.0;
1060  while (*(++c)) {
1061  if (*c >= '0' && *c <= '9') {
1062  d = d * 16.0 + *c - '0';
1063  } else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f')) {
1064  d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
1065  } else {
1066  break;
1067  }
1068  }
1069 
1070  if (d >= mantissaOverflowLowerBound) {
1071  d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16);
1072  }
1073  } else {
1074  // regular number ?
1075  char *end;
1076  d = kjs_strtod(c, &end);
1077  if ((d != 0.0 || end != c) && d != Inf && d != -Inf) {
1078  c = end;
1079  } else {
1080  double sign = 1.0;
1081 
1082  if (*c == '+') {
1083  c++;
1084  } else if (*c == '-') {
1085  sign = -1.0;
1086  c++;
1087  }
1088 
1089  // We used strtod() to do the conversion. However, strtod() handles
1090  // infinite values slightly differently than JavaScript in that it
1091  // converts the string "inf" with any capitalization to infinity,
1092  // whereas the ECMA spec requires that it be converted to NaN.
1093 
1094  if (strncmp(c, "Infinity", 8) == 0) {
1095  d = sign * Inf;
1096  c += 8;
1097  } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i') {
1098  c = end;
1099  } else {
1100  return NaN;
1101  }
1102  }
1103  }
1104 
1105  // allow trailing white space
1106  while (isASCIISpace(*c)) {
1107  c++;
1108  }
1109  // don't allow anything after - unless tolerant=true
1110  if (!tolerateTrailingJunk && *c != '\0') {
1111  d = NaN;
1112  }
1113 
1114  return d;
1115 }
1116 
1117 #ifdef __FAST_MATH__
1118 # error "KJS does not work correctly with -ffast-math"
1119 #endif
1120 
1121 double UString::toDouble(bool tolerateTrailingJunk) const
1122 {
1123  return toDouble(tolerateTrailingJunk, true);
1124 }
1125 
1126 double UString::toDouble() const
1127 {
1128  return toDouble(false, true);
1129 }
1130 
1131 uint32_t UString::toStrictUInt32(bool *ok) const
1132 {
1133  if (ok) {
1134  *ok = false;
1135  }
1136 
1137  // Empty string is not OK.
1138  int len = m_rep->len;
1139  if (len == 0) {
1140  return 0;
1141  }
1142  const UChar *p = m_rep->data();
1143  unsigned short c = p->unicode();
1144 
1145  // If the first digit is 0, only 0 itself is OK.
1146  if (c == '0') {
1147  if (len == 1 && ok) {
1148  *ok = true;
1149  }
1150  return 0;
1151  }
1152 
1153  // Convert to UInt32, checking for overflow.
1154  uint32_t i = 0;
1155  while (1) {
1156  // Process character, turning it into a digit.
1157  if (c < '0' || c > '9') {
1158  return 0;
1159  }
1160  const unsigned d = c - '0';
1161 
1162  // Multiply by 10, checking for overflow out of 32 bits.
1163  if (i > 0xFFFFFFFFU / 10) {
1164  return 0;
1165  }
1166  i *= 10;
1167 
1168  // Add in the digit, checking for overflow out of 32 bits.
1169  const unsigned max = 0xFFFFFFFFU - d;
1170  if (i > max) {
1171  return 0;
1172  }
1173  i += d;
1174 
1175  // Handle end of string.
1176  if (--len == 0) {
1177  if (ok) {
1178  *ok = true;
1179  }
1180  return i;
1181  }
1182 
1183  // Get next character.
1184  c = (++p)->unicode();
1185  }
1186 }
1187 
1188 int UString::find(const UString &f, int pos) const
1189 {
1190  int sz = size();
1191  int fsz = f.size();
1192  if (sz < fsz) {
1193  return -1;
1194  }
1195  if (pos < 0) {
1196  pos = 0;
1197  }
1198  if (fsz == 0) {
1199  return pos;
1200  }
1201  const UChar *data_ = data();
1202  const UChar *end = data_ + sz - fsz;
1203  int fsizeminusone = (fsz - 1) * sizeof(UChar);
1204  const UChar *fdata = f.data();
1205  unsigned short fchar = fdata->uc;
1206  ++fdata;
1207  for (const UChar *c = data_ + pos; c <= end; c++)
1208  if (c->uc == fchar && !memcmp(c + 1, fdata, fsizeminusone)) {
1209  return (c - data_);
1210  }
1211 
1212  return -1;
1213 }
1214 
1215 int UString::find(UChar ch, int pos) const
1216 {
1217  if (pos < 0) {
1218  pos = 0;
1219  }
1220  const UChar *data_ = data();
1221  const UChar *end = data_ + size();
1222  for (const UChar *c = data_ + pos; c < end; c++)
1223  if (*c == ch) {
1224  return (c - data_);
1225  }
1226 
1227  return -1;
1228 }
1229 
1230 int UString::rfind(const UString &f, int pos) const
1231 {
1232  int sz = size();
1233  int fsz = f.size();
1234  if (sz < fsz) {
1235  return -1;
1236  }
1237  if (pos < 0) {
1238  pos = 0;
1239  }
1240  if (pos > sz - fsz) {
1241  pos = sz - fsz;
1242  }
1243  if (fsz == 0) {
1244  return pos;
1245  }
1246  int fsizeminusone = (fsz - 1) * sizeof(UChar);
1247  const UChar *fdata = f.data();
1248  const UChar *data_ = data();
1249  for (const UChar *c = data_ + pos; c >= data_; c--) {
1250  if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone)) {
1251  return (c - data_);
1252  }
1253  }
1254 
1255  return -1;
1256 }
1257 
1258 int UString::rfind(UChar ch, int pos) const
1259 {
1260  if (isEmpty()) {
1261  return -1;
1262  }
1263  if (pos + 1 >= size()) {
1264  pos = size() - 1;
1265  }
1266  const UChar *data_ = data();
1267  for (const UChar *c = data_ + pos; c >= data_; c--) {
1268  if (*c == ch) {
1269  return (c - data_);
1270  }
1271  }
1272 
1273  return -1;
1274 }
1275 
1276 UString UString::substr(int pos, int len) const
1277 {
1278  int s = size();
1279 
1280  if (pos < 0) {
1281  pos = 0;
1282  } else if (pos >= s) {
1283  pos = s;
1284  }
1285  if (len < 0) {
1286  len = s;
1287  }
1288  if (pos + len >= s) {
1289  len = s - pos;
1290  }
1291 
1292  if (pos == 0 && len == s) {
1293  return *this;
1294  }
1295 
1296  return UString(Rep::create(m_rep, pos, len));
1297 }
1298 
1300  return ::KJS::maxUChars();
1301 }
1302 
1303 void UString::copyForWriting()
1304 {
1305  int l = size();
1306  if (!l) {
1307  return; // Not going to touch anything anyway.
1308  }
1309  if (m_rep->rc > 1 || !m_rep->baseIsSelf()) {
1310  UChar *n = allocChars(l);
1311  memcpy(n, data(), l * sizeof(UChar));
1312  m_rep = Rep::create(n, l);
1313  }
1314 }
1315 
1316 bool operator==(const UString &s1, const UString &s2)
1317 {
1318 #if 0
1319  if (s1.m_rep == s2.m_rep) {
1320  return true;
1321  }
1322 #endif
1323 
1324  if (s1.m_rep->len != s2.m_rep->len) {
1325  return false;
1326  }
1327 
1328  return (memcmp(s1.m_rep->data(), s2.m_rep->data(),
1329  s1.m_rep->len * sizeof(UChar)) == 0);
1330 }
1331 
1332 bool operator==(const UString &s1, const char *s2)
1333 {
1334  if (s2 == nullptr) {
1335  return s1.isEmpty();
1336  }
1337 
1338  const UChar *u = s1.data();
1339  const UChar *uend = u + s1.size();
1340  while (u != uend && *s2) {
1341  if (u->uc != (unsigned char)*s2) {
1342  return false;
1343  }
1344  s2++;
1345  u++;
1346  }
1347 
1348  return u == uend && *s2 == 0;
1349 }
1350 
1351 bool operator<(const UString &s1, const UString &s2)
1352 {
1353  const int l1 = s1.size();
1354  const int l2 = s2.size();
1355  const int lmin = l1 < l2 ? l1 : l2;
1356  const UChar *c1 = s1.data();
1357  const UChar *c2 = s2.data();
1358  int l = 0;
1359  while (l < lmin && *c1 == *c2) {
1360  c1++;
1361  c2++;
1362  l++;
1363  }
1364  if (l < lmin) {
1365  return (c1->uc < c2->uc);
1366  }
1367 
1368  return (l1 < l2);
1369 }
1370 
1371 bool UString::equal(const UString::Rep *r, const UString::Rep *b)
1372 {
1373  if (r == b) {
1374  return true;
1375  }
1376 
1377  int length = r->len;
1378  if (length != b->len) {
1379  return false;
1380  }
1381 
1382  const UChar *d = r->data();
1383  const UChar *s = b->data();
1384  for (int i = 0; i != length; ++i)
1385  if (d[i].uc != s[i].uc) {
1386  return false;
1387  }
1388  return true;
1389 }
1390 
1391 int compare(const UString &s1, const UString &s2)
1392 {
1393  const int l1 = s1.size();
1394  const int l2 = s2.size();
1395  const int lmin = l1 < l2 ? l1 : l2;
1396  const UChar *c1 = s1.data();
1397  const UChar *c2 = s2.data();
1398  int l = 0;
1399  while (l < lmin && *c1 == *c2) {
1400  c1++;
1401  c2++;
1402  l++;
1403  }
1404 
1405  if (l < lmin) {
1406  return (c1->uc > c2->uc) ? 1 : -1;
1407  }
1408 
1409  if (l1 == l2) {
1410  return 0;
1411  }
1412 
1413  return (l1 > l2) ? 1 : -1;
1414 }
1415 
1416 inline int inlineUTF8SequenceLengthNonASCII(char b0)
1417 {
1418  if ((b0 & 0xC0) != 0xC0) {
1419  return 0;
1420  }
1421  if ((b0 & 0xE0) == 0xC0) {
1422  return 2;
1423  }
1424  if ((b0 & 0xF0) == 0xE0) {
1425  return 3;
1426  }
1427  if ((b0 & 0xF8) == 0xF0) {
1428  return 4;
1429  }
1430  return 0;
1431 }
1432 
1433 int UTF8SequenceLengthNonASCII(char b0)
1434 {
1435  return inlineUTF8SequenceLengthNonASCII(b0);
1436 }
1437 
1438 inline int inlineUTF8SequenceLength(char b0)
1439 {
1440  return (b0 & 0x80) == 0 ? 1 : UTF8SequenceLengthNonASCII(b0);
1441 }
1442 
1443 // Given a first byte, gives the length of the UTF-8 sequence it begins.
1444 // Returns 0 for bytes that are not legal starts of UTF-8 sequences.
1445 // Only allows sequences of up to 4 bytes, since that works for all Unicode characters (U-00000000 to U-0010FFFF).
1446 int UTF8SequenceLength(char b0)
1447 {
1448  return (b0 & 0x80) == 0 ? 1 : inlineUTF8SequenceLengthNonASCII(b0);
1449 }
1450 
1451 // Takes a null-terminated C-style string with a UTF-8 sequence in it and converts it to a character.
1452 // Only allows Unicode characters (U-00000000 to U-0010FFFF).
1453 // Returns -1 if the sequence is not valid (including presence of extra bytes).
1454 int decodeUTF8Sequence(const char *sequence)
1455 {
1456  // Handle 0-byte sequences (never valid).
1457  const unsigned char b0 = sequence[0];
1458  const int length = inlineUTF8SequenceLength(b0);
1459  if (length == 0) {
1460  return -1;
1461  }
1462 
1463  // Handle 1-byte sequences (plain ASCII).
1464  const unsigned char b1 = sequence[1];
1465  if (length == 1) {
1466  if (b1) {
1467  return -1;
1468  }
1469  return b0;
1470  }
1471 
1472  // Handle 2-byte sequences.
1473  if ((b1 & 0xC0) != 0x80) {
1474  return -1;
1475  }
1476  const unsigned char b2 = sequence[2];
1477  if (length == 2) {
1478  if (b2) {
1479  return -1;
1480  }
1481  const int c = ((b0 & 0x1F) << 6) | (b1 & 0x3F);
1482  if (c < 0x80) {
1483  return -1;
1484  }
1485  return c;
1486  }
1487 
1488  // Handle 3-byte sequences.
1489  if ((b2 & 0xC0) != 0x80) {
1490  return -1;
1491  }
1492  const unsigned char b3 = sequence[3];
1493  if (length == 3) {
1494  if (b3) {
1495  return -1;
1496  }
1497  const int c = ((b0 & 0xF) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F);
1498  if (c < 0x800) {
1499  return -1;
1500  }
1501  // UTF-16 surrogates should never appear in UTF-8 data.
1502  if (c >= 0xD800 && c <= 0xDFFF) {
1503  return -1;
1504  }
1505  // Backwards BOM and U+FFFF should never appear in UTF-8 data.
1506  if (c == 0xFFFE || c == 0xFFFF) {
1507  return -1;
1508  }
1509  return c;
1510  }
1511 
1512  // Handle 4-byte sequences.
1513  if ((b3 & 0xC0) != 0x80) {
1514  return -1;
1515  }
1516  const unsigned char b4 = sequence[4];
1517  if (length == 4) {
1518  if (b4) {
1519  return -1;
1520  }
1521  const int c = ((b0 & 0x7) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F);
1522  if (c < 0x10000 || c > 0x10FFFF) {
1523  return -1;
1524  }
1525  return c;
1526  }
1527 
1528  return -1;
1529 }
1530 
1532 {
1533  // Allocate a buffer big enough to hold all the characters.
1534  const int length = size();
1535  Vector<char, 1024> buffer(length * 3);
1536 
1537  // Convert to runs of 8-bit characters.
1538  char *p = buffer.begin();
1539  const unsigned short *d = &data()->uc;
1540  for (int i = 0; i != length; ++i) {
1541  unsigned int c = d[i], sc;
1542  if (c < 0x80) {
1543  *p++ = (char)c;
1544  } else if (c < 0x800) {
1545  *p++ = (char)((c >> 6) | 0xC0); // C0 is the 2-byte flag for UTF-8
1546  *p++ = (char)((c | 0x80) & 0xBF); // next 6 bits, with high bit set
1547  } else if (c >= 0xD800 && c <= 0xDBFF && (i + 1) < length &&
1548  (sc = d[i + 1]) >= 0xDC00 && sc <= 0xDFFF) {
1549  sc = 0x10000 + (((c & 0x3FF) << 10) | (sc & 0x3FF));
1550  *p++ = (char)((sc >> 18) | 0xF0); // F0 is the 4-byte flag for UTF-8
1551  *p++ = (char)(((sc >> 12) | 0x80) & 0xBF); // next 6 bits, with high bit set
1552  *p++ = (char)(((sc >> 6) | 0x80) & 0xBF); // next 6 bits, with high bit set
1553  *p++ = (char)((sc | 0x80) & 0xBF); // next 6 bits, with high bit set
1554  ++i;
1555  } else {
1556  *p++ = (char)((c >> 12) | 0xE0); // E0 is the 3-byte flag for UTF-8
1557  *p++ = (char)(((c >> 6) | 0x80) & 0xBF); // next 6 bits, with high bit set
1558  *p++ = (char)((c | 0x80) & 0xBF); // next 6 bits, with high bit set
1559  }
1560  }
1561 
1562  // Return the result as a C string.
1563  CString result(buffer.data(), p - buffer.data());
1564 
1565  return result;
1566 }
1567 
1568 } // namespace KJS
const UChar operator[](int pos) const
Const character at specified position.
Definition: ustring.cpp:1020
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
Definition: ustring.cpp:934
UString & append(const UString &subStr, int subPos, int subLength=-1)
Append another string.
Definition: ustring.cpp:761
int size() const
Definition: ustring.h:420
uint32_t toStrictUInt32(bool *ok=nullptr) const
Attempts an conversion to a 32-bit integer.
Definition: ustring.cpp:1131
UString substr(int pos=0, int len=-1) const
Definition: ustring.cpp:1276
bool is8Bit() const
Use this if you want to make sure that this string is a plain ASCII string.
Definition: ustring.cpp:1006
QAction * create(StandardAction id, const QObject *recvr, const char *slot, QObject *parent)
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
static const UString & null()
Static instance of a null string.
Definition: ustring.cpp:553
unsigned short unicode() const
Definition: ustring.h:107
UString()
Constructs a null string.
Definition: ustring.h:545
Unicode character.
Definition: ustring.h:70
int find(const UString &f, int pos=0) const
Definition: ustring.cpp:1188
const UChar * data() const
Definition: ustring.h:391
int rfind(const UString &f, int pos) const
Definition: ustring.cpp:1230
static size_t maxUChars()
Maximum permitted string length.
Definition: ustring.cpp:1299
static UString from(int i)
Constructs a string from an int.
Definition: ustring.cpp:559
bool isEmpty() const
Definition: ustring.h:405
CString UTF8String() const
Convert the string to UTF-8, assuming it is UTF-16 encoded.
Definition: ustring.cpp:1531
8 bit char based string class
Definition: ustring.h:124
bool isNaN(double x)
CString cstring() const
Definition: ustring.cpp:929
Unicode string class.
Definition: ustring.h:153
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Dec 2 2023 03:59:16 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.