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

KDE's Doxygen guidelines are available online.