2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
5 * Copyright (C) 2009 Google Inc. All rights reserved.
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.
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.
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.
27 #include "JSGlobalObjectFunctions.h"
28 #include "Collector.h"
30 #include "Identifier.h"
31 #include "Operations.h"
39 #include <wtf/ASCIICType.h>
40 #include <wtf/Assertions.h>
41 #include <wtf/MathExtras.h>
42 #include <wtf/StringExtras.h>
43 #include <wtf/Vector.h>
44 #include <wtf/unicode/UTF8.h>
45 #include <wtf/StringExtras.h>
52 using namespace WTF::Unicode
;
57 extern const double NaN
;
58 extern const double Inf
;
60 CString::CString(const char* c
)
62 , m_data(new char[m_length
+ 1])
64 memcpy(m_data
, c
, m_length
+ 1);
67 CString::CString(const char* c
, size_t length
)
69 , m_data(new char[length
+ 1])
71 memcpy(m_data
, c
, m_length
);
75 CString::CString(const CString
& b
)
77 m_length
= b
.m_length
;
79 m_data
= new char[m_length
+ 1];
80 memcpy(m_data
, b
.m_data
, m_length
+ 1);
90 CString
CString::adopt(char* c
, size_t length
)
98 CString
& CString::append(const CString
& t
)
101 n
= new char[m_length
+ t
.m_length
+ 1];
103 memcpy(n
, m_data
, m_length
);
105 memcpy(n
+ m_length
, t
.m_data
, t
.m_length
);
106 m_length
+= t
.m_length
;
115 CString
& CString::operator=(const char* c
)
119 m_length
= strlen(c
);
120 m_data
= new char[m_length
+ 1];
121 memcpy(m_data
, c
, m_length
+ 1);
126 CString
& CString::operator=(const CString
& str
)
133 m_length
= str
.m_length
;
135 m_data
= new char[m_length
+ 1];
136 memcpy(m_data
, str
.m_data
, m_length
+ 1);
143 bool operator==(const CString
& c1
, const CString
& c2
)
145 size_t len
= c1
.size();
146 return len
== c2
.size() && (len
== 0 || memcmp(c1
.c_str(), c2
.c_str(), len
) == 0);
149 // These static strings are immutable, except for rc, whose initial value is chosen to
150 // reduce the possibility of it becoming zero due to ref/deref not being thread-safe.
151 static UChar sharedEmptyChar
;
152 UStringImpl
* UStringImpl::s_null
;
153 UStringImpl
* UStringImpl::s_empty
;
154 UString
* UString::nullUString
;
156 void initializeUString()
158 UStringImpl::s_null
= new UStringImpl(0, 0, UStringImpl::ConstructStaticString
);
159 UStringImpl::s_empty
= new UStringImpl(&sharedEmptyChar
, 0, UStringImpl::ConstructStaticString
);
160 UString::nullUString
= new UString
;
163 static PassRefPtr
<UString::Rep
> createRep(const char* c
)
166 return &UString::Rep::null();
169 return &UString::Rep::empty();
171 size_t length
= strlen(c
);
173 PassRefPtr
<UStringImpl
> result
= UStringImpl::tryCreateUninitialized(length
, d
);
175 return &UString::Rep::null();
177 for (size_t i
= 0; i
< length
; i
++)
178 d
[i
] = static_cast<unsigned char>(c
[i
]); // use unsigned char to zero-extend instead of sign-extend
182 static inline PassRefPtr
<UString::Rep
> createRep(const char* c
, int length
)
185 return &UString::Rep::null();
188 return &UString::Rep::empty();
191 PassRefPtr
<UStringImpl
> result
= UStringImpl::tryCreateUninitialized(length
, d
);
193 return &UString::Rep::null();
195 for (int i
= 0; i
< length
; i
++)
196 d
[i
] = static_cast<unsigned char>(c
[i
]); // use unsigned char to zero-extend instead of sign-extend
200 UString::UString(const char* c
)
201 : m_rep(createRep(c
))
205 UString::UString(const char* c
, int length
)
206 : m_rep(createRep(c
, length
))
210 UString::UString(const UChar
* c
, int length
)
213 m_rep
= &Rep::empty();
215 m_rep
= Rep::create(c
, length
);
218 UString
UString::createFromUTF8(const char* string
)
223 size_t length
= strlen(string
);
224 Vector
<UChar
, 1024> buffer(length
);
225 UChar
* p
= buffer
.data();
226 if (conversionOK
!= convertUTF8ToUTF16(&string
, string
+ length
, &p
, p
+ length
))
229 return UString(buffer
.data(), p
- buffer
.data());
232 UString
UString::from(int i
)
234 UChar buf
[1 + sizeof(i
) * 3];
235 UChar
* end
= buf
+ sizeof(buf
) / sizeof(UChar
);
240 else if (i
== INT_MIN
) {
241 char minBuf
[1 + sizeof(i
) * 3];
242 snprintf(minBuf
, sizeof(minBuf
), "%d", INT_MIN
);
243 return UString(minBuf
);
245 bool negative
= false;
251 *--p
= static_cast<unsigned short>((i
% 10) + '0');
258 return UString(p
, static_cast<int>(end
- p
));
261 UString
UString::from(long long i
)
263 UChar buf
[1 + sizeof(i
) * 3];
264 UChar
* end
= buf
+ sizeof(buf
) / sizeof(UChar
);
269 else if (i
== std::numeric_limits
<long long>::min()) {
270 char minBuf
[1 + sizeof(i
) * 3];
272 snprintf(minBuf
, sizeof(minBuf
) - 1, "%I64d", std::numeric_limits
<long long>::min());
273 #elif PLATFORM(IPHONE)
274 snprintf(minBuf
, sizeof(minBuf
), "%lld", std::numeric_limits
<long long>::min());
276 snprintf(minBuf
, sizeof(minBuf
) - 1, "%lld", std::numeric_limits
<long long>::min());
278 return UString(minBuf
);
280 bool negative
= false;
286 *--p
= static_cast<unsigned short>((i
% 10) + '0');
293 return UString(p
, static_cast<int>(end
- p
));
296 UString
UString::from(unsigned int u
)
298 UChar buf
[sizeof(u
) * 3];
299 UChar
* end
= buf
+ sizeof(buf
) / sizeof(UChar
);
306 *--p
= static_cast<unsigned short>((u
% 10) + '0');
311 return UString(p
, static_cast<int>(end
- p
));
314 UString
UString::from(long l
)
316 UChar buf
[1 + sizeof(l
) * 3];
317 UChar
* end
= buf
+ sizeof(buf
) / sizeof(UChar
);
322 else if (l
== LONG_MIN
) {
323 char minBuf
[1 + sizeof(l
) * 3];
324 snprintf(minBuf
, sizeof(minBuf
), "%ld", LONG_MIN
);
325 return UString(minBuf
);
327 bool negative
= false;
333 *--p
= static_cast<unsigned short>((l
% 10) + '0');
340 return UString(p
, static_cast<int>(end
- p
));
343 UString
UString::from(double d
)
347 doubleToStringInJavaScriptFormat(d
, buffer
, &length
);
348 return UString(buffer
, length
);
351 UString
UString::spliceSubstringsWithSeparators(const Range
* substringRanges
, int rangeCount
, const UString
* separators
, int separatorCount
) const
353 m_rep
->checkConsistency();
355 if (rangeCount
== 1 && separatorCount
== 0) {
356 int thisSize
= size();
357 int position
= substringRanges
[0].position
;
358 int length
= substringRanges
[0].length
;
359 if (position
<= 0 && length
>= thisSize
)
361 return UString::Rep::create(m_rep
, max(0, position
), min(thisSize
, length
));
365 for (int i
= 0; i
< rangeCount
; i
++)
366 totalLength
+= substringRanges
[i
].length
;
367 for (int i
= 0; i
< separatorCount
; i
++)
368 totalLength
+= separators
[i
].size();
370 if (totalLength
== 0)
374 PassRefPtr
<Rep
> rep
= Rep::tryCreateUninitialized(totalLength
, buffer
);
378 int maxCount
= max(rangeCount
, separatorCount
);
380 for (int i
= 0; i
< maxCount
; i
++) {
381 if (i
< rangeCount
) {
382 UStringImpl::copyChars(buffer
+ bufferPos
, data() + substringRanges
[i
].position
, substringRanges
[i
].length
);
383 bufferPos
+= substringRanges
[i
].length
;
385 if (i
< separatorCount
) {
386 UStringImpl::copyChars(buffer
+ bufferPos
, separators
[i
].data(), separators
[i
].size());
387 bufferPos
+= separators
[i
].size();
394 UString
UString::replaceRange(int rangeStart
, int rangeLength
, const UString
& replacement
) const
396 m_rep
->checkConsistency();
398 int replacementLength
= replacement
.size();
399 int totalLength
= size() - rangeLength
+ replacementLength
;
400 if (totalLength
== 0)
404 PassRefPtr
<Rep
> rep
= Rep::tryCreateUninitialized(totalLength
, buffer
);
408 UStringImpl::copyChars(buffer
, data(), rangeStart
);
409 UStringImpl::copyChars(buffer
+ rangeStart
, replacement
.data(), replacementLength
);
410 int rangeEnd
= rangeStart
+ rangeLength
;
411 UStringImpl::copyChars(buffer
+ rangeStart
+ replacementLength
, data() + rangeEnd
, size() - rangeEnd
);
416 bool UString::getCString(CStringBuffer
& buffer
) const
419 int neededSize
= length
+ 1;
420 buffer
.resize(neededSize
);
421 char* buf
= buffer
.data();
424 const UChar
* p
= data();
426 const UChar
* limit
= p
+ length
;
430 *q
= static_cast<char>(c
);
436 return !(ored
& 0xFF00);
439 char* UString::ascii() const
441 static char* asciiBuffer
= 0;
444 int neededSize
= length
+ 1;
445 delete[] asciiBuffer
;
446 asciiBuffer
= new char[neededSize
];
448 const UChar
* p
= data();
449 char* q
= asciiBuffer
;
450 const UChar
* limit
= p
+ length
;
452 *q
= static_cast<char>(p
[0]);
461 UString
& UString::operator=(const char* c
)
464 m_rep
= &Rep::null();
469 m_rep
= &Rep::empty();
473 int l
= static_cast<int>(strlen(c
));
475 m_rep
= Rep::tryCreateUninitialized(l
, d
);
477 for (int i
= 0; i
< l
; i
++)
478 d
[i
] = static_cast<unsigned char>(c
[i
]); // use unsigned char to zero-extend instead of sign-extend
485 bool UString::is8Bit() const
487 const UChar
* u
= data();
488 const UChar
* limit
= u
+ size();
498 UChar
UString::operator[](int pos
) const
505 double UString::toDouble(bool tolerateTrailingJunk
, bool tolerateEmptyString
) const
511 if (isASCIISpace(c
) && tolerateEmptyString
)
516 // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
517 // after the number, so this is too strict a check.
521 const char* c
= s
.data();
523 // skip leading white space
524 while (isASCIISpace(*c
))
529 return tolerateEmptyString
? 0.0 : NaN
;
534 if (*c
== '0' && (*(c
+ 1) == 'x' || *(c
+ 1) == 'X')) {
535 const char* firstDigitPosition
= c
+ 2;
539 if (*c
>= '0' && *c
<= '9')
540 d
= d
* 16.0 + *c
- '0';
541 else if ((*c
>= 'A' && *c
<= 'F') || (*c
>= 'a' && *c
<= 'f'))
542 d
= d
* 16.0 + (*c
& 0xdf) - 'A' + 10.0;
547 if (d
>= mantissaOverflowLowerBound
)
548 d
= parseIntOverflow(firstDigitPosition
, c
- firstDigitPosition
, 16);
552 d
= WTF::strtod(c
, &end
);
553 if ((d
!= 0.0 || end
!= c
) && d
!= Inf
&& d
!= -Inf
) {
560 else if (*c
== '-') {
565 // We used strtod() to do the conversion. However, strtod() handles
566 // infinite values slightly differently than JavaScript in that it
567 // converts the string "inf" with any capitalization to infinity,
568 // whereas the ECMA spec requires that it be converted to NaN.
570 if (c
[0] == 'I' && c
[1] == 'n' && c
[2] == 'f' && c
[3] == 'i' && c
[4] == 'n' && c
[5] == 'i' && c
[6] == 't' && c
[7] == 'y') {
573 } else if ((d
== Inf
|| d
== -Inf
) && *c
!= 'I' && *c
!= 'i')
580 // allow trailing white space
581 while (isASCIISpace(*c
))
583 // don't allow anything after - unless tolerant=true
584 if (!tolerateTrailingJunk
&& *c
!= '\0')
590 double UString::toDouble(bool tolerateTrailingJunk
) const
592 return toDouble(tolerateTrailingJunk
, true);
595 double UString::toDouble() const
597 return toDouble(false, true);
600 uint32_t UString::toUInt32(bool* ok
) const
602 double d
= toDouble();
605 if (d
!= static_cast<uint32_t>(d
)) {
613 return static_cast<uint32_t>(d
);
616 uint32_t UString::toUInt32(bool* ok
, bool tolerateEmptyString
) const
618 double d
= toDouble(false, tolerateEmptyString
);
621 if (d
!= static_cast<uint32_t>(d
)) {
629 return static_cast<uint32_t>(d
);
632 uint32_t UString::toStrictUInt32(bool* ok
) const
637 // Empty string is not OK.
638 int len
= m_rep
->size();
641 const UChar
* p
= m_rep
->data();
642 unsigned short c
= p
[0];
644 // If the first digit is 0, only 0 itself is OK.
651 // Convert to UInt32, checking for overflow.
654 // Process character, turning it into a digit.
655 if (c
< '0' || c
> '9')
657 const unsigned d
= c
- '0';
659 // Multiply by 10, checking for overflow out of 32 bits.
660 if (i
> 0xFFFFFFFFU
/ 10)
664 // Add in the digit, checking for overflow out of 32 bits.
665 const unsigned max
= 0xFFFFFFFFU
- d
;
670 // Handle end of string.
677 // Get next character.
682 int UString::find(const UString
& f
, int pos
) const
691 const UChar
* end
= data() + size();
692 for (const UChar
* c
= data() + pos
; c
< end
; c
++) {
694 return static_cast<int>(c
- data());
704 const UChar
* end
= data() + sz
- fsz
;
705 int fsizeminusone
= (fsz
- 1) * sizeof(UChar
);
706 const UChar
* fdata
= f
.data();
707 unsigned short fchar
= fdata
[0];
709 for (const UChar
* c
= data() + pos
; c
<= end
; c
++) {
710 if (c
[0] == fchar
&& !memcmp(c
+ 1, fdata
, fsizeminusone
))
711 return static_cast<int>(c
- data());
717 int UString::find(UChar ch
, int pos
) const
721 const UChar
* end
= data() + size();
722 for (const UChar
* c
= data() + pos
; c
< end
; c
++) {
724 return static_cast<int>(c
- data());
730 int UString::rfind(const UString
& f
, int pos
) const
742 int fsizeminusone
= (fsz
- 1) * sizeof(UChar
);
743 const UChar
* fdata
= f
.data();
744 for (const UChar
* c
= data() + pos
; c
>= data(); c
--) {
745 if (*c
== *fdata
&& !memcmp(c
+ 1, fdata
+ 1, fsizeminusone
))
746 return static_cast<int>(c
- data());
752 int UString::rfind(UChar ch
, int pos
) const
756 if (pos
+ 1 >= size())
758 for (const UChar
* c
= data() + pos
; c
>= data(); c
--) {
760 return static_cast<int>(c
- data());
766 UString
UString::substr(int pos
, int len
) const
779 if (pos
== 0 && len
== s
)
782 return UString(Rep::create(m_rep
, pos
, len
));
785 bool operator==(const UString
& s1
, const char *s2
)
790 const UChar
* u
= s1
.data();
791 const UChar
* uend
= u
+ s1
.size();
792 while (u
!= uend
&& *s2
) {
793 if (u
[0] != (unsigned char)*s2
)
799 return u
== uend
&& *s2
== 0;
802 bool operator<(const UString
& s1
, const UString
& s2
)
804 const int l1
= s1
.size();
805 const int l2
= s2
.size();
806 const int lmin
= l1
< l2
? l1
: l2
;
807 const UChar
* c1
= s1
.data();
808 const UChar
* c2
= s2
.data();
810 while (l
< lmin
&& *c1
== *c2
) {
816 return (c1
[0] < c2
[0]);
821 bool operator>(const UString
& s1
, const UString
& s2
)
823 const int l1
= s1
.size();
824 const int l2
= s2
.size();
825 const int lmin
= l1
< l2
? l1
: l2
;
826 const UChar
* c1
= s1
.data();
827 const UChar
* c2
= s2
.data();
829 while (l
< lmin
&& *c1
== *c2
) {
835 return (c1
[0] > c2
[0]);
840 int compare(const UString
& s1
, const UString
& s2
)
842 const int l1
= s1
.size();
843 const int l2
= s2
.size();
844 const int lmin
= l1
< l2
? l1
: l2
;
845 const UChar
* c1
= s1
.data();
846 const UChar
* c2
= s2
.data();
848 while (l
< lmin
&& *c1
== *c2
) {
855 return (c1
[0] > c2
[0]) ? 1 : -1;
860 return (l1
> l2
) ? 1 : -1;
863 bool equal(const UString::Rep
* r
, const UString::Rep
* b
)
865 int length
= r
->size();
866 if (length
!= b
->size())
868 const UChar
* d
= r
->data();
869 const UChar
* s
= b
->data();
870 for (int i
= 0; i
!= length
; ++i
) {
877 CString
UString::UTF8String(bool strict
) const
879 // Allocate a buffer big enough to hold all the characters.
880 const int length
= size();
881 Vector
<char, 1024> buffer(length
* 3);
883 // Convert to runs of 8-bit characters.
884 char* p
= buffer
.data();
885 const UChar
* d
= reinterpret_cast<const UChar
*>(&data()[0]);
886 ConversionResult result
= convertUTF16ToUTF8(&d
, d
+ length
, &p
, p
+ buffer
.size(), strict
);
887 if (result
!= conversionOK
)
890 return CString(buffer
.data(), p
- buffer
.data());
893 // For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X.
894 NEVER_INLINE
void UString::makeNull()
896 m_rep
= &Rep::null();
899 // For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X.
900 NEVER_INLINE
UString::Rep
* UString::nullRep()