2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6 * Copyright (C) 2007 Maks Orlovich
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "JSGlobalObjectFunctions.h"
28 #include "CallFrame.h"
29 #include "Interpreter.h"
30 #include "JSGlobalObject.h"
32 #include "JSStringBuilder.h"
34 #include "LiteralParser.h"
37 #include "UStringBuilder.h"
41 #include <wtf/ASCIICType.h>
42 #include <wtf/Assertions.h>
43 #include <wtf/MathExtras.h>
44 #include <wtf/StringExtras.h>
45 #include <wtf/unicode/UTF8.h>
48 using namespace Unicode;
52 static JSValue encode(ExecState* exec, const char* doNotEscape)
54 UString str = exec->argument(0).toString(exec);
55 CString cstr = str.utf8(true);
57 return throwError(exec, createURIError(exec, "String contained an illegal UTF-16 sequence."));
59 JSStringBuilder builder;
60 const char* p = cstr.data();
61 for (size_t k = 0; k < cstr.length(); k++, p++) {
63 if (c && strchr(doNotEscape, c))
67 snprintf(tmp, sizeof(tmp), "%%%02X", static_cast<unsigned char>(c));
71 return builder.build(exec);
74 static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict)
76 JSStringBuilder builder;
77 UString str = exec->argument(0).toString(exec);
79 int len = str.length();
80 const UChar* d = str.characters();
83 const UChar* p = d + k;
87 if (k <= len - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {
88 const char b0 = Lexer::convertHex(p[1], p[2]);
89 const int sequenceLen = UTF8SequenceLength(b0);
90 if (sequenceLen != 0 && k <= len - sequenceLen * 3) {
91 charLen = sequenceLen * 3;
94 for (int i = 1; i < sequenceLen; ++i) {
95 const UChar* q = p + i * 3;
96 if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))
97 sequence[i] = Lexer::convertHex(q[1], q[2]);
104 sequence[sequenceLen] = 0;
105 const int character = decodeUTF8Sequence(sequence);
106 if (character < 0 || character >= 0x110000)
108 else if (character >= 0x10000) {
109 // Convert to surrogate pair.
110 builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
111 u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
113 u = static_cast<UChar>(character);
119 return throwError(exec, createURIError(exec, "URI error"));
120 // The only case where we don't use "strict" mode is the "unescape" function.
121 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
122 if (k <= len - 6 && p[1] == 'u'
123 && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])
124 && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {
126 u = Lexer::convertUnicode(p[2], p[3], p[4], p[5]);
129 if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) {
137 return builder.build(exec);
140 bool isStrWhiteSpace(UChar c)
143 // ECMA-262-5th 7.2 & 7.3
156 return c > 0xff && isSeparatorSpace(c);
160 static int parseDigit(unsigned short c, int radix)
164 if (c >= '0' && c <= '9')
166 else if (c >= 'A' && c <= 'Z')
167 digit = c - 'A' + 10;
168 else if (c >= 'a' && c <= 'z')
169 digit = c - 'a' + 10;
176 double parseIntOverflow(const char* s, int length, int radix)
179 double radixMultiplier = 1.0;
181 for (const char* p = s + length - 1; p >= s; p--) {
182 if (radixMultiplier == std::numeric_limits<double>::infinity()) {
184 number = std::numeric_limits<double>::infinity();
188 int digit = parseDigit(*p, radix);
189 number += digit * radixMultiplier;
192 radixMultiplier *= radix;
198 double parseIntOverflow(const UChar* s, int length, int radix)
201 double radixMultiplier = 1.0;
203 for (const UChar* p = s + length - 1; p >= s; p--) {
204 if (radixMultiplier == std::numeric_limits<double>::infinity()) {
206 number = std::numeric_limits<double>::infinity();
210 int digit = parseDigit(*p, radix);
211 number += digit * radixMultiplier;
214 radixMultiplier *= radix;
220 static double parseInt(const UString& s, int radix)
222 int length = s.length();
223 const UChar* data = s.characters();
226 while (p < length && isStrWhiteSpace(data[p]))
233 else if (data[p] == '-') {
239 if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {
242 } else if (radix == 0) {
243 if (p < length && data[p] == '0')
249 if (radix < 2 || radix > 36)
250 return std::numeric_limits<double>::quiet_NaN();
252 int firstDigitPosition = p;
253 bool sawDigit = false;
256 int digit = parseDigit(data[p], radix);
265 if (number >= mantissaOverflowLowerBound) {
267 number = WTF::strtod(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), 0);
268 else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
269 number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
273 return std::numeric_limits<double>::quiet_NaN();
275 return sign * number;
278 static const int SizeOfInfinity = 8;
280 static bool isInfinity(const UChar* data, const UChar* end)
282 return (end - data) >= SizeOfInfinity
293 // See ecma-262 9.3.1
294 static double jsHexIntegerLiteral(const UChar*& data, const UChar* end)
298 const UChar* firstDigitPosition = data;
301 number = number * 16 + toASCIIHexValue(*data);
305 if (!isASCIIHexDigit(*data))
308 if (number >= mantissaOverflowLowerBound)
309 number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
314 // See ecma-262 9.3.1
315 static double jsStrDecimalLiteral(const UChar*& data, const UChar* end)
319 // Copy the sting into a null-terminated byte buffer, and call strtod.
320 Vector<char, 32> byteBuffer;
321 for (const UChar* characters = data; characters < end; ++characters) {
322 UChar character = *characters;
323 byteBuffer.append(isASCII(character) ? character : 0);
325 byteBuffer.append(0);
327 double number = WTF::strtod(byteBuffer.data(), &endOfNumber);
329 // Check if strtod found a number; if so return it.
330 ptrdiff_t consumed = endOfNumber - byteBuffer.data();
336 // Check for [+-]?Infinity
339 if (isInfinity(data, end)) {
340 data += SizeOfInfinity;
341 return std::numeric_limits<double>::infinity();
346 if (isInfinity(data + 1, end)) {
347 data += SizeOfInfinity + 1;
348 return std::numeric_limits<double>::infinity();
353 if (isInfinity(data + 1, end)) {
354 data += SizeOfInfinity + 1;
355 return -std::numeric_limits<double>::infinity();
361 return std::numeric_limits<double>::quiet_NaN();
364 // See ecma-262 9.3.1
365 double jsToNumber(const UString& s)
367 unsigned size = s.length();
373 if (isStrWhiteSpace(c))
375 return std::numeric_limits<double>::quiet_NaN();
378 const UChar* data = s.characters();
379 const UChar* end = data + size;
381 // Skip leading white space.
382 for (; data < end; ++data) {
383 if (!isStrWhiteSpace(*data))
392 if (data[0] == '0' && data + 2 < end && (data[1] | 0x20) == 'x' && isASCIIHexDigit(data[2]))
393 number = jsHexIntegerLiteral(data, end);
395 number = jsStrDecimalLiteral(data, end);
397 // Allow trailing white space.
398 for (; data < end; ++data) {
399 if (!isStrWhiteSpace(*data))
403 return std::numeric_limits<double>::quiet_NaN();
408 static double parseFloat(const UString& s)
410 unsigned size = s.length();
416 return std::numeric_limits<double>::quiet_NaN();
419 const UChar* data = s.characters();
420 const UChar* end = data + size;
422 // Skip leading white space.
423 for (; data < end; ++data) {
424 if (!isStrWhiteSpace(*data))
430 return std::numeric_limits<double>::quiet_NaN();
432 return jsStrDecimalLiteral(data, end);
435 EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
437 JSObject* thisObject = exec->hostThisValue().toThisObject(exec);
438 JSObject* unwrappedObject = thisObject->unwrappedObject();
439 if (!unwrappedObject->isGlobalObject() || static_cast<JSGlobalObject*>(unwrappedObject)->evalFunction() != exec->callee())
440 return throwVMError(exec, createEvalError(exec, "The \"this\" value passed to eval must be the global object from which eval originated"));
442 JSValue x = exec->argument(0);
444 return JSValue::encode(x);
446 UString s = x.toString(exec);
448 LiteralParser preparser(exec, s.characters(), s.length(), LiteralParser::NonStrictJSON);
449 if (JSValue parsedObject = preparser.tryLiteralParse())
450 return JSValue::encode(parsedObject);
452 EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
453 JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain());
455 return throwVMError(exec, error);
457 return JSValue::encode(exec->interpreter()->execute(eval, exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain()));
460 EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
462 JSValue value = exec->argument(0);
463 JSValue radixValue = exec->argument(1);
465 // Optimized handling for numbers:
466 // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
467 // results in a truncation to integer. In the case of -0, this is converted to 0.
469 // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
470 // however these values cannot be trivially truncated to int since 10^21 exceeds
471 // even the int64_t range. Negative numbers are a little trickier, the case for
472 // values in the range -10^21 < n <= -1 are similar to those for integer, but
473 // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
474 static const double tenToTheMinus6 = 0.000001;
475 static const double intMaxPlusOne = 2147483648.0;
477 if (value.getNumber(n) && ((n < intMaxPlusOne && n >= tenToTheMinus6) || !n) && radixValue.isUndefinedOrNull())
478 return JSValue::encode(jsNumber(static_cast<int32_t>(n)));
480 // If ToString throws, we shouldn't call ToInt32.
481 UString s = value.toString(exec);
482 if (exec->hadException())
483 return JSValue::encode(jsUndefined());
485 return JSValue::encode(jsNumber(parseInt(s, radixValue.toInt32(exec))));
488 EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
490 return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec))));
493 EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec)
495 return JSValue::encode(jsBoolean(isnan(exec->argument(0).toNumber(exec))));
498 EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)
500 double n = exec->argument(0).toNumber(exec);
501 return JSValue::encode(jsBoolean(isfinite(n)));
504 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
506 static const char do_not_unescape_when_decoding_URI[] =
509 return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true));
512 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
514 return JSValue::encode(decode(exec, "", true));
517 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
519 static const char do_not_escape_when_encoding_URI[] =
520 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
521 "abcdefghijklmnopqrstuvwxyz"
523 "!#$&'()*+,-./:;=?@_~";
525 return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI));
528 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
530 static const char do_not_escape_when_encoding_URI_component[] =
531 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
532 "abcdefghijklmnopqrstuvwxyz"
536 return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component));
539 EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
541 static const char do_not_escape[] =
542 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
543 "abcdefghijklmnopqrstuvwxyz"
547 JSStringBuilder builder;
548 UString str = exec->argument(0).toString(exec);
549 const UChar* c = str.characters();
550 for (unsigned k = 0; k < str.length(); k++, c++) {
554 snprintf(tmp, sizeof(tmp), "%%u%04X", u);
556 } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u)))
557 builder.append(c, 1);
560 snprintf(tmp, sizeof(tmp), "%%%02X", u);
565 return JSValue::encode(builder.build(exec));
568 EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
570 UStringBuilder builder;
571 UString str = exec->argument(0).toString(exec);
573 int len = str.length();
575 const UChar* c = str.characters() + k;
577 if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
578 if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
579 u = Lexer::convertUnicode(c[2], c[3], c[4], c[5]);
583 } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
584 u = UChar(Lexer::convertHex(c[1], c[2]));
592 return JSValue::encode(jsString(exec, builder.toUString()));