source: webkit/trunk/JavaScriptCore/kjs/ustring.cpp@ 13311

Last change on this file since 13311 was 13311, checked in by eseidel, 19 years ago

2006-03-15 Eric Seidel <[email protected]>

Reviewed by mjs.

Fix CString copy constructor, fixes Date.parse("") on Win32.

  • kjs/date_object.cpp: (KJS::DateProtoFunc::callAsFunction):
  • kjs/ustring.cpp: (KJS::CString::CString): (KJS::CString::operator=):
  • Property allow-tabs set to x
  • Property svn:eol-style set to native
File size: 31.2 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2000 Harri Porten ([email protected])
5 * Copyright (C) 2004 Apple Computer, Inc.
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 "config.h"
25#include "ustring.h"
26
27#include <assert.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <ctype.h>
31#if HAVE(STRING_H)
32#include <string.h>
33#endif
34#if HAVE(STRINGS_H)
35#include <strings.h>
36#endif
37
38#include "operations.h"
39#include "identifier.h"
40#include <math.h>
41#include "dtoa.h"
42
43#include <kxmlcore/Vector.h>
44
45using std::max;
46
47#include <unicode/uchar.h>
48
49namespace KJS {
50
51extern const double NaN;
52extern const double Inf;
53
54CString::CString(const char *c)
55{
56 length = strlen(c);
57 data = new char[length+1];
58 memcpy(data, c, length + 1);
59}
60
61CString::CString(const char *c, int len)
62{
63 length = len;
64 data = new char[len+1];
65 memcpy(data, c, len);
66 data[len] = 0;
67}
68
69CString::CString(const CString &b)
70{
71 length = b.length;
72 if (b.data) {
73 data = new char[length+1];
74 memcpy(data, b.data, length + 1);
75 }
76 else
77 data = 0;
78}
79
80CString::~CString()
81{
82 delete [] data;
83}
84
85CString &CString::append(const CString &t)
86{
87 char *n;
88 n = new char[length+t.length+1];
89 if (length)
90 memcpy(n, data, length);
91 if (t.length)
92 memcpy(n+length, t.data, t.length);
93 length += t.length;
94 n[length] = 0;
95
96 delete [] data;
97 data = n;
98
99 return *this;
100}
101
102CString &CString::operator=(const char *c)
103{
104 if (data)
105 delete [] data;
106 length = strlen(c);
107 data = new char[length+1];
108 memcpy(data, c, length + 1);
109
110 return *this;
111}
112
113CString &CString::operator=(const CString &str)
114{
115 if (this == &str)
116 return *this;
117
118 if (data)
119 delete [] data;
120 length = str.length;
121 if (str.data) {
122 data = new char[length + 1];
123 memcpy(data, str.data, length + 1);
124 }
125 else
126 data = 0;
127
128 return *this;
129}
130
131bool operator==(const CString& c1, const CString& c2)
132{
133 int len = c1.size();
134 return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0);
135}
136
137// Hack here to avoid a global with a constructor; point to an unsigned short instead of a UChar.
138static unsigned short almostUChar;
139static UChar *const nonNullUCharPointer = reinterpret_cast<UChar *>(&almostUChar);
140UString::Rep UString::Rep::null = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
141UString::Rep UString::Rep::empty = { 0, 0, 1, 0, 0, 0, nonNullUCharPointer, 0, 0, 0, 0 };
142const int normalStatBufferSize = 4096;
143static char *statBuffer = 0;
144static int statBufferSize = 0;
145
146UChar UChar::toLower() const
147{
148 return static_cast<unsigned short>(u_tolower(uc));
149}
150
151UChar UChar::toUpper() const
152{
153 return static_cast<unsigned short>(u_toupper(uc));
154}
155
156UCharReference& UCharReference::operator=(UChar c)
157{
158 str->copyForWriting();
159 if (offset < str->rep()->len)
160 *(str->rep()->data() + offset) = c;
161 /* TODO: lengthen string ? */
162 return *this;
163}
164
165UChar& UCharReference::ref() const
166{
167 if (offset < str->rep()->len)
168 return *(str->rep()->data() + offset);
169 else {
170 static UChar callerBetterNotModifyThis('\0');
171 return callerBetterNotModifyThis;
172 }
173}
174
175PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar *d, int l)
176{
177 int sizeInBytes = l * sizeof(UChar);
178 UChar *copyD = static_cast<UChar *>(fastMalloc(sizeInBytes));
179 memcpy(copyD, d, sizeInBytes);
180
181 return create(copyD, l);
182}
183
184PassRefPtr<UString::Rep> UString::Rep::create(UChar *d, int l)
185{
186 Rep *r = new Rep;
187 r->offset = 0;
188 r->len = l;
189 r->rc = 1;
190 r->_hash = 0;
191 r->isIdentifier = 0;
192 r->baseString = 0;
193 r->buf = d;
194 r->usedCapacity = l;
195 r->capacity = l;
196 r->usedPreCapacity = 0;
197 r->preCapacity = 0;
198
199 // steal the single reference this Rep was created with
200 return adoptRef(r);
201}
202
203PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<Rep> base, int offset, int length)
204{
205 assert(base);
206
207 int baseOffset = base->offset;
208
209 if (base->baseString) {
210 base = base->baseString;
211 }
212
213 assert(-(offset + baseOffset) <= base->usedPreCapacity);
214 assert(offset + baseOffset + length <= base->usedCapacity);
215
216 Rep *r = new Rep;
217 r->offset = baseOffset + offset;
218 r->len = length;
219 r->rc = 1;
220 r->_hash = 0;
221 r->isIdentifier = 0;
222 r->baseString = base.release();
223 r->buf = 0;
224 r->usedCapacity = 0;
225 r->capacity = 0;
226 r->usedPreCapacity = 0;
227 r->preCapacity = 0;
228
229 // steal the single reference this Rep was created with
230 return adoptRef(r);
231}
232
233void UString::Rep::destroy()
234{
235 if (isIdentifier)
236 Identifier::remove(this);
237 if (baseString) {
238 baseString->deref();
239 } else {
240 fastFree(buf);
241 }
242 delete this;
243}
244
245// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
246// or anything like that.
247const unsigned PHI = 0x9e3779b9U;
248
249// Paul Hsieh's SuperFastHash
250// http://www.azillionmonkeys.com/qed/hash.html
251unsigned UString::Rep::computeHash(const UChar *s, int len)
252{
253 unsigned l = len;
254 uint32_t hash = PHI;
255 uint32_t tmp;
256
257 int rem = l & 1;
258 l >>= 1;
259
260 // Main loop
261 for (; l > 0; l--) {
262 hash += s[0].uc;
263 tmp = (s[1].uc << 11) ^ hash;
264 hash = (hash << 16) ^ tmp;
265 s += 2;
266 hash += hash >> 11;
267 }
268
269 // Handle end case
270 if (rem) {
271 hash += s[0].uc;
272 hash ^= hash << 11;
273 hash += hash >> 17;
274 }
275
276 // Force "avalanching" of final 127 bits
277 hash ^= hash << 3;
278 hash += hash >> 5;
279 hash ^= hash << 2;
280 hash += hash >> 15;
281 hash ^= hash << 10;
282
283 // this avoids ever returning a hash code of 0, since that is used to
284 // signal "hash not computed yet", using a value that is likely to be
285 // effectively the same as 0 when the low bits are masked
286 if (hash == 0)
287 hash = 0x80000000;
288
289 return hash;
290}
291
292// Paul Hsieh's SuperFastHash
293// http://www.azillionmonkeys.com/qed/hash.html
294unsigned UString::Rep::computeHash(const char *s)
295{
296 // This hash is designed to work on 16-bit chunks at a time. But since the normal case
297 // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
298 // were 16-bit chunks, which should give matching results
299
300 uint32_t hash = PHI;
301 uint32_t tmp;
302 unsigned l = strlen(s);
303
304 int rem = l & 1;
305 l >>= 1;
306
307 // Main loop
308 for (; l > 0; l--) {
309 hash += (unsigned char)s[0];
310 tmp = ((unsigned char)s[1] << 11) ^ hash;
311 hash = (hash << 16) ^ tmp;
312 s += 2;
313 hash += hash >> 11;
314 }
315
316 // Handle end case
317 if (rem) {
318 hash += (unsigned char)s[0];
319 hash ^= hash << 11;
320 hash += hash >> 17;
321 }
322
323 // Force "avalanching" of final 127 bits
324 hash ^= hash << 3;
325 hash += hash >> 5;
326 hash ^= hash << 2;
327 hash += hash >> 15;
328 hash ^= hash << 10;
329
330 // this avoids ever returning a hash code of 0, since that is used to
331 // signal "hash not computed yet", using a value that is likely to be
332 // effectively the same as 0 when the low bits are masked
333 if (hash == 0)
334 hash = 0x80000000;
335
336 return hash;
337}
338
339// put these early so they can be inlined
340inline int UString::expandedSize(int size, int otherSize) const
341{
342 int s = (size * 11 / 10) + 1 + otherSize;
343 return s;
344}
345
346inline int UString::usedCapacity() const
347{
348 return m_rep->baseString ? m_rep->baseString->usedCapacity : m_rep->usedCapacity;
349}
350
351inline int UString::usedPreCapacity() const
352{
353 return m_rep->baseString ? m_rep->baseString->usedPreCapacity : m_rep->usedPreCapacity;
354}
355
356void UString::expandCapacity(int requiredLength)
357{
358 Rep *r = m_rep->baseString ? m_rep->baseString : rep();
359
360 if (requiredLength > r->capacity) {
361 int newCapacity = expandedSize(requiredLength, r->preCapacity);
362 r->buf = static_cast<UChar *>(fastRealloc(r->buf, newCapacity * sizeof(UChar)));
363 r->capacity = newCapacity - r->preCapacity;
364 }
365 if (requiredLength > r->usedCapacity) {
366 r->usedCapacity = requiredLength;
367 }
368}
369
370void UString::expandPreCapacity(int requiredPreCap)
371{
372 Rep *r = m_rep->baseString ? m_rep->baseString : rep();
373
374 if (requiredPreCap > r->preCapacity) {
375 int newCapacity = expandedSize(requiredPreCap, r->capacity);
376 int delta = newCapacity - r->capacity - r->preCapacity;
377
378 UChar *newBuf = static_cast<UChar *>(fastMalloc(newCapacity * sizeof(UChar)));
379 memcpy(newBuf + delta, r->buf, (r->capacity + r->preCapacity) * sizeof(UChar));
380 fastFree(r->buf);
381 r->buf = newBuf;
382
383 r->preCapacity = newCapacity - r->capacity;
384 }
385 if (requiredPreCap > r->usedPreCapacity) {
386 r->usedPreCapacity = requiredPreCap;
387 }
388}
389
390
391UString::UString(char c)
392{
393 UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar)));
394 d[0] = c;
395 m_rep = Rep::create(d, 1);
396}
397
398UString::UString(const char *c)
399{
400 if (!c) {
401 m_rep = &Rep::null;
402 return;
403 }
404 int length = strlen(c);
405 if (length == 0) {
406 m_rep = &Rep::empty;
407 return;
408 }
409 UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * length));
410 for (int i = 0; i < length; i++)
411 d[i].uc = c[i];
412 m_rep = Rep::create(d, length);
413}
414
415UString::UString(const UChar *c, int length)
416{
417 if (length == 0)
418 m_rep = &Rep::empty;
419 else
420 m_rep = Rep::createCopying(c, length);
421}
422
423UString::UString(UChar *c, int length, bool copy)
424{
425 if (length == 0)
426 m_rep = &Rep::empty;
427 else if (copy)
428 m_rep = Rep::createCopying(c, length);
429 else
430 m_rep = Rep::create(c, length);
431}
432
433UString::UString(const UString &a, const UString &b)
434{
435 int aSize = a.size();
436 int aOffset = a.m_rep->offset;
437 int bSize = b.size();
438 int bOffset = b.m_rep->offset;
439 int length = aSize + bSize;
440
441 // possible cases:
442
443 if (aSize == 0) {
444 // a is empty
445 m_rep = b.m_rep;
446 } else if (bSize == 0) {
447 // b is empty
448 m_rep = a.m_rep;
449 } else if (aOffset + aSize == a.usedCapacity() && 4 * aSize >= bSize &&
450 (-bOffset != b.usedPreCapacity() || aSize >= bSize)) {
451 // - a reaches the end of its buffer so it qualifies for shared append
452 // - also, it's at least a quarter the length of b - appending to a much shorter
453 // string does more harm than good
454 // - however, if b qualifies for prepend and is longer than a, we'd rather prepend
455 UString x(a);
456 x.expandCapacity(aOffset + length);
457 memcpy(const_cast<UChar *>(a.data() + aSize), b.data(), bSize * sizeof(UChar));
458 m_rep = Rep::create(a.m_rep, 0, length);
459 } else if (-bOffset == b.usedPreCapacity() && 4 * bSize >= aSize) {
460 // - b reaches the beginning of its buffer so it qualifies for shared prepend
461 // - also, it's at least a quarter the length of a - prepending to a much shorter
462 // string does more harm than good
463 UString y(b);
464 y.expandPreCapacity(-bOffset + aSize);
465 memcpy(const_cast<UChar *>(b.data() - aSize), a.data(), aSize * sizeof(UChar));
466 m_rep = Rep::create(b.m_rep, -aSize, length);
467 } else {
468 // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
469 int newCapacity = expandedSize(length, 0);
470 UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * newCapacity));
471 memcpy(d, a.data(), aSize * sizeof(UChar));
472 memcpy(d + aSize, b.data(), bSize * sizeof(UChar));
473 m_rep = Rep::create(d, length);
474 m_rep->capacity = newCapacity;
475 }
476}
477
478const UString &UString::null()
479{
480 static UString n;
481 return n;
482}
483
484UString UString::from(int i)
485{
486 UChar buf[1 + sizeof(i) * 3];
487 UChar *end = buf + sizeof(buf) / sizeof(UChar);
488 UChar *p = end;
489
490 if (i == 0) {
491 *--p = '0';
492 } else if (i == INT_MIN) {
493 char minBuf[1 + sizeof(i) * 3];
494 sprintf(minBuf, "%d", INT_MIN);
495 return UString(minBuf);
496 } else {
497 bool negative = false;
498 if (i < 0) {
499 negative = true;
500 i = -i;
501 }
502 while (i) {
503 *--p = (unsigned short)((i % 10) + '0');
504 i /= 10;
505 }
506 if (negative) {
507 *--p = '-';
508 }
509 }
510
511 return UString(p, end - p);
512}
513
514UString UString::from(unsigned int u)
515{
516 UChar buf[sizeof(u) * 3];
517 UChar *end = buf + sizeof(buf) / sizeof(UChar);
518 UChar *p = end;
519
520 if (u == 0) {
521 *--p = '0';
522 } else {
523 while (u) {
524 *--p = (unsigned short)((u % 10) + '0');
525 u /= 10;
526 }
527 }
528
529 return UString(p, end - p);
530}
531
532UString UString::from(long l)
533{
534 UChar buf[1 + sizeof(l) * 3];
535 UChar *end = buf + sizeof(buf) / sizeof(UChar);
536 UChar *p = end;
537
538 if (l == 0) {
539 *--p = '0';
540 } else if (l == LONG_MIN) {
541 char minBuf[1 + sizeof(l) * 3];
542 sprintf(minBuf, "%ld", LONG_MIN);
543 return UString(minBuf);
544 } else {
545 bool negative = false;
546 if (l < 0) {
547 negative = true;
548 l = -l;
549 }
550 while (l) {
551 *--p = (unsigned short)((l % 10) + '0');
552 l /= 10;
553 }
554 if (negative) {
555 *--p = '-';
556 }
557 }
558
559 return UString(p, end - p);
560}
561
562UString UString::from(double d)
563{
564 char buf[80];
565 int decimalPoint;
566 int sign;
567
568 char *result = kjs_dtoa(d, 0, 0, &decimalPoint, &sign, NULL);
569 int length = strlen(result);
570
571 int i = 0;
572 if (sign) {
573 buf[i++] = '-';
574 }
575
576 if (decimalPoint <= 0 && decimalPoint > -6) {
577 buf[i++] = '0';
578 buf[i++] = '.';
579 for (int j = decimalPoint; j < 0; j++) {
580 buf[i++] = '0';
581 }
582 strcpy(buf + i, result);
583 } else if (decimalPoint <= 21 && decimalPoint > 0) {
584 if (length <= decimalPoint) {
585 strcpy(buf + i, result);
586 i += length;
587 for (int j = 0; j < decimalPoint - length; j++) {
588 buf[i++] = '0';
589 }
590 buf[i] = '\0';
591 } else {
592 strncpy(buf + i, result, decimalPoint);
593 i += decimalPoint;
594 buf[i++] = '.';
595 strcpy(buf + i, result + decimalPoint);
596 }
597 } else if (result[0] < '0' || result[0] > '9') {
598 strcpy(buf + i, result);
599 } else {
600 buf[i++] = result[0];
601 if (length > 1) {
602 buf[i++] = '.';
603 strcpy(buf + i, result + 1);
604 i += length - 1;
605 }
606
607 buf[i++] = 'e';
608 buf[i++] = (decimalPoint >= 0) ? '+' : '-';
609 // decimalPoint can't be more than 3 digits decimal given the
610 // nature of float representation
611 int exponential = decimalPoint - 1;
612 if (exponential < 0) {
613 exponential = exponential * -1;
614 }
615 if (exponential >= 100) {
616 buf[i++] = '0' + exponential / 100;
617 }
618 if (exponential >= 10) {
619 buf[i++] = '0' + (exponential % 100) / 10;
620 }
621 buf[i++] = '0' + exponential % 10;
622 buf[i++] = '\0';
623 }
624
625 kjs_freedtoa(result);
626
627 return UString(buf);
628}
629
630UString UString::spliceSubstringsWithSeparators(const Range *substringRanges, int rangeCount, const UString *separators, int separatorCount) const
631{
632 int totalLength = 0;
633
634 for (int i = 0; i < rangeCount; i++) {
635 totalLength += substringRanges[i].length;
636 }
637 for (int i = 0; i < separatorCount; i++) {
638 totalLength += separators[i].size();
639 }
640
641 UChar *buffer = static_cast<UChar *>(fastMalloc(totalLength * sizeof(UChar)));
642
643 int maxCount = max(rangeCount, separatorCount);
644 int bufferPos = 0;
645 for (int i = 0; i < maxCount; i++) {
646 if (i < rangeCount) {
647 memcpy(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length * sizeof(UChar));
648 bufferPos += substringRanges[i].length;
649 }
650 if (i < separatorCount) {
651 memcpy(buffer + bufferPos, separators[i].data(), separators[i].size() * sizeof(UChar));
652 bufferPos += separators[i].size();
653 }
654 }
655
656 return UString(UString::Rep::create(buffer, totalLength));
657}
658
659
660
661UString &UString::append(const UString &t)
662{
663 int thisSize = size();
664 int thisOffset = m_rep->offset;
665 int tSize = t.size();
666 int length = thisSize + tSize;
667
668 // possible cases:
669 if (thisSize == 0) {
670 // this is empty
671 *this = t;
672 } else if (tSize == 0) {
673 // t is empty
674 } else if (!m_rep->baseString && m_rep->rc == 1) {
675 // this is direct and has refcount of 1 (so we can just alter it directly)
676 expandCapacity(thisOffset + length);
677 memcpy(const_cast<UChar *>(data() + thisSize), t.data(), tSize * sizeof(UChar));
678 m_rep->len = length;
679 m_rep->_hash = 0;
680 } else if (thisOffset + thisSize == usedCapacity()) {
681 // this reaches the end of the buffer - extend it
682 expandCapacity(thisOffset + length);
683 memcpy(const_cast<UChar *>(data() + thisSize), t.data(), tSize * sizeof(UChar));
684 m_rep = Rep::create(m_rep, 0, length);
685 } else {
686 // this is shared with someone using more capacity, gotta make a whole new string
687 int newCapacity = expandedSize(length, 0);
688 UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * newCapacity));
689 memcpy(d, data(), thisSize * sizeof(UChar));
690 memcpy(const_cast<UChar *>(d + thisSize), t.data(), tSize * sizeof(UChar));
691 m_rep = Rep::create(d, length);
692 m_rep->capacity = newCapacity;
693 }
694
695 return *this;
696}
697
698UString &UString::append(const char *t)
699{
700 int thisSize = size();
701 int thisOffset = m_rep->offset;
702 int tSize = strlen(t);
703 int length = thisSize + tSize;
704
705 // possible cases:
706 if (thisSize == 0) {
707 // this is empty
708 *this = t;
709 } else if (tSize == 0) {
710 // t is empty, we'll just return *this below.
711 } else if (!m_rep->baseString && m_rep->rc == 1) {
712 // this is direct and has refcount of 1 (so we can just alter it directly)
713 expandCapacity(thisOffset + length);
714 UChar *d = const_cast<UChar *>(data());
715 for (int i = 0; i < tSize; ++i)
716 d[thisSize+i] = t[i];
717 m_rep->len = length;
718 m_rep->_hash = 0;
719 } else if (thisOffset + thisSize == usedCapacity()) {
720 // this string reaches the end of the buffer - extend it
721 expandCapacity(thisOffset + length);
722 UChar *d = const_cast<UChar *>(data());
723 for (int i = 0; i < tSize; ++i)
724 d[thisSize+i] = t[i];
725 m_rep = Rep::create(m_rep, 0, length);
726 } else {
727 // this is shared with someone using more capacity, gotta make a whole new string
728 int newCapacity = expandedSize(length, 0);
729 UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * newCapacity));
730 memcpy(d, data(), thisSize * sizeof(UChar));
731 for (int i = 0; i < tSize; ++i)
732 d[thisSize+i] = t[i];
733 m_rep = Rep::create(d, length);
734 m_rep->capacity = newCapacity;
735 }
736
737 return *this;
738}
739
740UString &UString::append(unsigned short c)
741{
742 int thisOffset = m_rep->offset;
743 int length = size();
744
745 // possible cases:
746 if (length == 0) {
747 // this is empty - must make a new m_rep because we don't want to pollute the shared empty one
748 int newCapacity = expandedSize(1, 0);
749 UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * newCapacity));
750 d[0] = c;
751 m_rep = Rep::create(d, 1);
752 m_rep->capacity = newCapacity;
753 } else if (!m_rep->baseString && m_rep->rc == 1) {
754 // this is direct and has refcount of 1 (so we can just alter it directly)
755 expandCapacity(thisOffset + length + 1);
756 UChar *d = const_cast<UChar *>(data());
757 d[length] = c;
758 m_rep->len = length + 1;
759 m_rep->_hash = 0;
760 } else if (thisOffset + length == usedCapacity()) {
761 // this reaches the end of the string - extend it and share
762 expandCapacity(thisOffset + length + 1);
763 UChar *d = const_cast<UChar *>(data());
764 d[length] = c;
765 m_rep = Rep::create(m_rep, 0, length + 1);
766 } else {
767 // this is shared with someone using more capacity, gotta make a whole new string
768 int newCapacity = expandedSize((length + 1), 0);
769 UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * newCapacity));
770 memcpy(d, data(), length * sizeof(UChar));
771 d[length] = c;
772 m_rep = Rep::create(d, length);
773 m_rep->capacity = newCapacity;
774 }
775
776 return *this;
777}
778
779CString UString::cstring() const
780{
781 return ascii();
782}
783
784char *UString::ascii() const
785{
786 // Never make the buffer smaller than normalStatBufferSize.
787 // Thus we almost never need to reallocate.
788 int length = size();
789 int neededSize = length + 1;
790 if (neededSize < normalStatBufferSize) {
791 neededSize = normalStatBufferSize;
792 }
793 if (neededSize != statBufferSize) {
794 delete [] statBuffer;
795 statBuffer = new char [neededSize];
796 statBufferSize = neededSize;
797 }
798
799 const UChar *p = data();
800 char *q = statBuffer;
801 const UChar *limit = p + length;
802 while (p != limit) {
803 *q = p->uc;
804 ++p;
805 ++q;
806 }
807 *q = '\0';
808
809 return statBuffer;
810}
811
812#ifdef KJS_DEBUG_MEM
813void UString::globalClear()
814{
815 delete [] statBuffer;
816 statBuffer = 0;
817 statBufferSize = 0;
818}
819#endif
820
821UString &UString::operator=(const char *c)
822{
823 int l = c ? strlen(c) : 0;
824 UChar *d;
825 if (m_rep->rc == 1 && l <= m_rep->capacity && !m_rep->baseString && m_rep->offset == 0 && m_rep->preCapacity == 0) {
826 d = m_rep->buf;
827 m_rep->_hash = 0;
828 } else {
829 d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * l));
830 m_rep = Rep::create(d, l);
831 }
832 for (int i = 0; i < l; i++)
833 d[i].uc = c[i];
834
835 return *this;
836}
837
838bool UString::is8Bit() const
839{
840 const UChar *u = data();
841 const UChar *limit = u + size();
842 while (u < limit) {
843 if (u->uc > 0xFF)
844 return false;
845 ++u;
846 }
847
848 return true;
849}
850
851UChar UString::operator[](int pos) const
852{
853 if (pos >= size())
854 return '\0';
855 return data()[pos];
856}
857
858UCharReference UString::operator[](int pos)
859{
860 /* TODO: boundary check */
861 return UCharReference(this, pos);
862}
863
864double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
865{
866 double d;
867
868 // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
869 // after the number, so is8Bit is too strict a check.
870 if (!is8Bit())
871 return NaN;
872
873 const char *c = ascii();
874
875 // skip leading white space
876 while (isspace(*c))
877 c++;
878
879 // empty string ?
880 if (*c == '\0')
881 return tolerateEmptyString ? 0.0 : NaN;
882
883 // hex number ?
884 if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) {
885 c++;
886 d = 0.0;
887 while (*(++c)) {
888 if (*c >= '0' && *c <= '9')
889 d = d * 16.0 + *c - '0';
890 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
891 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
892 else
893 break;
894 }
895 } else {
896 // regular number ?
897 char *end;
898 d = kjs_strtod(c, &end);
899 if ((d != 0.0 || end != c) && d != HUGE_VAL && d != -HUGE_VAL) {
900 c = end;
901 } else {
902 // infinity ?
903 d = 1.0;
904 if (*c == '+')
905 c++;
906 else if (*c == '-') {
907 d = -1.0;
908 c++;
909 }
910 if (strncmp(c, "Infinity", 8) != 0)
911 return NaN;
912 d = d * Inf;
913 c += 8;
914 }
915 }
916
917 // allow trailing white space
918 while (isspace(*c))
919 c++;
920 // don't allow anything after - unless tolerant=true
921 if (!tolerateTrailingJunk && *c != '\0')
922 d = NaN;
923
924 return d;
925}
926
927double UString::toDouble(bool tolerateTrailingJunk) const
928{
929 return toDouble(tolerateTrailingJunk, true);
930}
931
932double UString::toDouble() const
933{
934 return toDouble(false, true);
935}
936
937uint32_t UString::toUInt32(bool *ok) const
938{
939 double d = toDouble();
940 bool b = true;
941
942 if (d != static_cast<uint32_t>(d)) {
943 b = false;
944 d = 0;
945 }
946
947 if (ok)
948 *ok = b;
949
950 return static_cast<uint32_t>(d);
951}
952
953uint32_t UString::toUInt32(bool *ok, bool tolerateEmptyString) const
954{
955 double d = toDouble(false, tolerateEmptyString);
956 bool b = true;
957
958 if (d != static_cast<uint32_t>(d)) {
959 b = false;
960 d = 0;
961 }
962
963 if (ok)
964 *ok = b;
965
966 return static_cast<uint32_t>(d);
967}
968
969uint32_t UString::toStrictUInt32(bool *ok) const
970{
971 if (ok)
972 *ok = false;
973
974 // Empty string is not OK.
975 int len = m_rep->len;
976 if (len == 0)
977 return 0;
978 const UChar *p = m_rep->data();
979 unsigned short c = p->unicode();
980
981 // If the first digit is 0, only 0 itself is OK.
982 if (c == '0') {
983 if (len == 1 && ok)
984 *ok = true;
985 return 0;
986 }
987
988 // Convert to UInt32, checking for overflow.
989 uint32_t i = 0;
990 while (1) {
991 // Process character, turning it into a digit.
992 if (c < '0' || c > '9')
993 return 0;
994 const unsigned d = c - '0';
995
996 // Multiply by 10, checking for overflow out of 32 bits.
997 if (i > 0xFFFFFFFFU / 10)
998 return 0;
999 i *= 10;
1000
1001 // Add in the digit, checking for overflow out of 32 bits.
1002 const unsigned max = 0xFFFFFFFFU - d;
1003 if (i > max)
1004 return 0;
1005 i += d;
1006
1007 // Handle end of string.
1008 if (--len == 0) {
1009 if (ok)
1010 *ok = true;
1011 return i;
1012 }
1013
1014 // Get next character.
1015 c = (++p)->unicode();
1016 }
1017}
1018
1019int UString::find(const UString &f, int pos) const
1020{
1021 int sz = size();
1022 int fsz = f.size();
1023 if (sz < fsz)
1024 return -1;
1025 if (pos < 0)
1026 pos = 0;
1027 if (fsz == 0)
1028 return pos;
1029 const UChar *end = data() + sz - fsz;
1030 int fsizeminusone = (fsz - 1) * sizeof(UChar);
1031 const UChar *fdata = f.data();
1032 unsigned short fchar = fdata->uc;
1033 ++fdata;
1034 for (const UChar *c = data() + pos; c <= end; c++)
1035 if (c->uc == fchar && !memcmp(c + 1, fdata, fsizeminusone))
1036 return (c-data());
1037
1038 return -1;
1039}
1040
1041int UString::find(UChar ch, int pos) const
1042{
1043 if (pos < 0)
1044 pos = 0;
1045 const UChar *end = data() + size();
1046 for (const UChar *c = data() + pos; c < end; c++)
1047 if (*c == ch)
1048 return (c-data());
1049
1050 return -1;
1051}
1052
1053int UString::rfind(const UString &f, int pos) const
1054{
1055 int sz = size();
1056 int fsz = f.size();
1057 if (sz < fsz)
1058 return -1;
1059 if (pos < 0)
1060 pos = 0;
1061 if (pos > sz - fsz)
1062 pos = sz - fsz;
1063 if (fsz == 0)
1064 return pos;
1065 int fsizeminusone = (fsz - 1) * sizeof(UChar);
1066 const UChar *fdata = f.data();
1067 for (const UChar *c = data() + pos; c >= data(); c--) {
1068 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
1069 return (c-data());
1070 }
1071
1072 return -1;
1073}
1074
1075int UString::rfind(UChar ch, int pos) const
1076{
1077 if (isEmpty())
1078 return -1;
1079 if (pos + 1 >= size())
1080 pos = size() - 1;
1081 for (const UChar *c = data() + pos; c >= data(); c--) {
1082 if (*c == ch)
1083 return (c-data());
1084 }
1085
1086 return -1;
1087}
1088
1089UString UString::substr(int pos, int len) const
1090{
1091 int s = size();
1092
1093 if (pos < 0)
1094 pos = 0;
1095 else if (pos >= s)
1096 pos = s;
1097 if (len < 0)
1098 len = s;
1099 if (pos + len >= s)
1100 len = s - pos;
1101
1102 if (pos == 0 && len == s)
1103 return *this;
1104
1105 return UString(Rep::create(m_rep, pos, len));
1106}
1107
1108void UString::copyForWriting()
1109{
1110 if (m_rep->rc > 1 || m_rep->baseString) {
1111 int l = size();
1112 UChar *n = static_cast<UChar *>(fastMalloc(sizeof(UChar) * l));
1113 memcpy(n, data(), l * sizeof(UChar));
1114 m_rep = Rep::create(n, l);
1115 }
1116}
1117
1118bool operator==(const UString& s1, const UString& s2)
1119{
1120 if (s1.m_rep->len != s2.m_rep->len)
1121 return false;
1122
1123 return (memcmp(s1.m_rep->data(), s2.m_rep->data(),
1124 s1.m_rep->len * sizeof(UChar)) == 0);
1125}
1126
1127bool operator==(const UString& s1, const char *s2)
1128{
1129 if (s2 == 0) {
1130 return s1.isEmpty();
1131 }
1132
1133 const UChar *u = s1.data();
1134 const UChar *uend = u + s1.size();
1135 while (u != uend && *s2) {
1136 if (u->uc != (unsigned char)*s2)
1137 return false;
1138 s2++;
1139 u++;
1140 }
1141
1142 return u == uend && *s2 == 0;
1143}
1144
1145bool operator<(const UString& s1, const UString& s2)
1146{
1147 const int l1 = s1.size();
1148 const int l2 = s2.size();
1149 const int lmin = l1 < l2 ? l1 : l2;
1150 const UChar *c1 = s1.data();
1151 const UChar *c2 = s2.data();
1152 int l = 0;
1153 while (l < lmin && *c1 == *c2) {
1154 c1++;
1155 c2++;
1156 l++;
1157 }
1158 if (l < lmin)
1159 return (c1->uc < c2->uc);
1160
1161 return (l1 < l2);
1162}
1163
1164int compare(const UString& s1, const UString& s2)
1165{
1166 const int l1 = s1.size();
1167 const int l2 = s2.size();
1168 const int lmin = l1 < l2 ? l1 : l2;
1169 const UChar *c1 = s1.data();
1170 const UChar *c2 = s2.data();
1171 int l = 0;
1172 while (l < lmin && *c1 == *c2) {
1173 c1++;
1174 c2++;
1175 l++;
1176 }
1177
1178 if (l < lmin)
1179 return (c1->uc > c2->uc) ? 1 : -1;
1180
1181 if (l1 == l2)
1182 return 0;
1183
1184 return (l1 > l2) ? 1 : -1;
1185}
1186
1187inline int inlineUTF8SequenceLengthNonASCII(char b0)
1188{
1189 if ((b0 & 0xC0) != 0xC0)
1190 return 0;
1191 if ((b0 & 0xE0) == 0xC0)
1192 return 2;
1193 if ((b0 & 0xF0) == 0xE0)
1194 return 3;
1195 if ((b0 & 0xF8) == 0xF0)
1196 return 4;
1197 return 0;
1198}
1199
1200int UTF8SequenceLengthNonASCII(char b0)
1201{
1202 return inlineUTF8SequenceLengthNonASCII(b0);
1203}
1204
1205inline int inlineUTF8SequenceLength(char b0)
1206{
1207 return (b0 & 0x80) == 0 ? 1 : UTF8SequenceLengthNonASCII(b0);
1208}
1209
1210// Given a first byte, gives the length of the UTF-8 sequence it begins.
1211// Returns 0 for bytes that are not legal starts of UTF-8 sequences.
1212// Only allows sequences of up to 4 bytes, since that works for all Unicode characters (U-00000000 to U-0010FFFF).
1213int UTF8SequenceLength(char b0)
1214{
1215 return (b0 & 0x80) == 0 ? 1 : inlineUTF8SequenceLengthNonASCII(b0);
1216}
1217
1218// Takes a null-terminated C-style string with a UTF-8 sequence in it and converts it to a character.
1219// Only allows Unicode characters (U-00000000 to U-0010FFFF).
1220// Returns -1 if the sequence is not valid (including presence of extra bytes).
1221int decodeUTF8Sequence(const char *sequence)
1222{
1223 // Handle 0-byte sequences (never valid).
1224 const unsigned char b0 = sequence[0];
1225 const int length = inlineUTF8SequenceLength(b0);
1226 if (length == 0)
1227 return -1;
1228
1229 // Handle 1-byte sequences (plain ASCII).
1230 const unsigned char b1 = sequence[1];
1231 if (length == 1) {
1232 if (b1)
1233 return -1;
1234 return b0;
1235 }
1236
1237 // Handle 2-byte sequences.
1238 if ((b1 & 0xC0) != 0x80)
1239 return -1;
1240 const unsigned char b2 = sequence[2];
1241 if (length == 2) {
1242 if (b2)
1243 return -1;
1244 const int c = ((b0 & 0x1F) << 6) | (b1 & 0x3F);
1245 if (c < 0x80)
1246 return -1;
1247 return c;
1248 }
1249
1250 // Handle 3-byte sequences.
1251 if ((b2 & 0xC0) != 0x80)
1252 return -1;
1253 const unsigned char b3 = sequence[3];
1254 if (length == 3) {
1255 if (b3)
1256 return -1;
1257 const int c = ((b0 & 0xF) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F);
1258 if (c < 0x800)
1259 return -1;
1260 // UTF-16 surrogates should never appear in UTF-8 data.
1261 if (c >= 0xD800 && c <= 0xDFFF)
1262 return -1;
1263 // Backwards BOM and U+FFFF should never appear in UTF-8 data.
1264 if (c == 0xFFFE || c == 0xFFFF)
1265 return -1;
1266 return c;
1267 }
1268
1269 // Handle 4-byte sequences.
1270 if ((b3 & 0xC0) != 0x80)
1271 return -1;
1272 const unsigned char b4 = sequence[4];
1273 if (length == 4) {
1274 if (b4)
1275 return -1;
1276 const int c = ((b0 & 0x7) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F);
1277 if (c < 0x10000 || c > 0x10FFFF)
1278 return -1;
1279 return c;
1280 }
1281
1282 return -1;
1283}
1284
1285CString UString::UTF8String() const
1286{
1287 // Allocate a buffer big enough to hold all the characters.
1288 const int length = size();
1289 Vector<char, 1024> buffer(length * 3);
1290
1291 // Convert to runs of 8-bit characters.
1292 char *p = buffer.begin();
1293 const UChar *d = data();
1294 for (int i = 0; i != length; ++i) {
1295 unsigned short c = d[i].unicode();
1296 if (c < 0x80) {
1297 *p++ = (char)c;
1298 } else if (c < 0x800) {
1299 *p++ = (char)((c >> 6) | 0xC0); // C0 is the 2-byte flag for UTF-8
1300 *p++ = (char)((c | 0x80) & 0xBF); // next 6 bits, with high bit set
1301 } else if (c >= 0xD800 && c <= 0xDBFF && i < length && d[i+1].uc >= 0xDC00 && d[i+1].uc <= 0xDFFF) {
1302 unsigned sc = 0x10000 + (((c & 0x3FF) << 10) | (d[i+1].uc & 0x3FF));
1303 *p++ = (char)((sc >> 18) | 0xF0); // F0 is the 4-byte flag for UTF-8
1304 *p++ = (char)(((sc >> 12) | 0x80) & 0xBF); // next 6 bits, with high bit set
1305 *p++ = (char)(((sc >> 6) | 0x80) & 0xBF); // next 6 bits, with high bit set
1306 *p++ = (char)((sc | 0x80) & 0xBF); // next 6 bits, with high bit set
1307 ++i;
1308 } else {
1309 *p++ = (char)((c >> 12) | 0xE0); // E0 is the 3-byte flag for UTF-8
1310 *p++ = (char)(((c >> 6) | 0x80) & 0xBF); // next 6 bits, with high bit set
1311 *p++ = (char)((c | 0x80) & 0xBF); // next 6 bits, with high bit set
1312 }
1313 }
1314
1315 // Return the result as a C string.
1316 CString result(buffer, p - buffer);
1317
1318 return result;
1319}
1320
1321} // namespace KJS
Note: See TracBrowser for help on using the repository browser.