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 "GlobalEvalFunction.h"
30 #include "JSGlobalObject.h"
31 #include "LiteralParser.h"
33 #include "Interpreter.h"
41 #include <wtf/ASCIICType.h>
42 #include <wtf/Assertions.h>
43 #include <wtf/MathExtras.h>
44 #include <wtf/unicode/UTF8.h>
47 using namespace Unicode
;
51 static JSValue
encode(ExecState
* exec
, const ArgList
& args
, const char* doNotEscape
)
53 UString str
= args
.at(0).toString(exec
);
54 CString cstr
= str
.UTF8String(true);
56 return throwError(exec
, URIError
, "String contained an illegal UTF-16 sequence.");
59 const char* p
= cstr
.c_str();
60 for (size_t k
= 0; k
< cstr
.size(); k
++, p
++) {
62 if (c
&& strchr(doNotEscape
, c
))
66 snprintf(tmp
, sizeof(tmp
), "%%%02X", static_cast<unsigned char>(c
));
70 return jsString(exec
, result
);
73 static JSValue
decode(ExecState
* exec
, const ArgList
& args
, const char* doNotUnescape
, bool strict
)
76 UString str
= args
.at(0).toString(exec
);
79 const UChar
* d
= str
.data();
82 const UChar
* p
= d
+ k
;
86 if (k
<= len
- 3 && isASCIIHexDigit(p
[1]) && isASCIIHexDigit(p
[2])) {
87 const char b0
= Lexer::convertHex(p
[1], p
[2]);
88 const int sequenceLen
= UTF8SequenceLength(b0
);
89 if (sequenceLen
!= 0 && k
<= len
- sequenceLen
* 3) {
90 charLen
= sequenceLen
* 3;
93 for (int i
= 1; i
< sequenceLen
; ++i
) {
94 const UChar
* q
= p
+ i
* 3;
95 if (q
[0] == '%' && isASCIIHexDigit(q
[1]) && isASCIIHexDigit(q
[2]))
96 sequence
[i
] = Lexer::convertHex(q
[1], q
[2]);
103 sequence
[sequenceLen
] = 0;
104 const int character
= decodeUTF8Sequence(sequence
);
105 if (character
< 0 || character
>= 0x110000)
107 else if (character
>= 0x10000) {
108 // Convert to surrogate pair.
109 result
.append(static_cast<UChar
>(0xD800 | ((character
- 0x10000) >> 10)));
110 u
= static_cast<UChar
>(0xDC00 | ((character
- 0x10000) & 0x3FF));
112 u
= static_cast<UChar
>(character
);
118 return throwError(exec
, URIError
);
119 // The only case where we don't use "strict" mode is the "unescape" function.
120 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
121 if (k
<= len
- 6 && p
[1] == 'u'
122 && isASCIIHexDigit(p
[2]) && isASCIIHexDigit(p
[3])
123 && isASCIIHexDigit(p
[4]) && isASCIIHexDigit(p
[5])) {
125 u
= Lexer::convertUnicode(p
[2], p
[3], p
[4], p
[5]);
128 if (charLen
&& (u
== 0 || u
>= 128 || !strchr(doNotUnescape
, u
))) {
136 return jsString(exec
, result
);
139 bool isStrWhiteSpace(UChar c
)
153 return c
> 0xff && isSeparatorSpace(c
);
157 static int parseDigit(unsigned short c
, int radix
)
161 if (c
>= '0' && c
<= '9')
163 else if (c
>= 'A' && c
<= 'Z')
164 digit
= c
- 'A' + 10;
165 else if (c
>= 'a' && c
<= 'z')
166 digit
= c
- 'a' + 10;
173 double parseIntOverflow(const char* s
, int length
, int radix
)
176 double radixMultiplier
= 1.0;
178 for (const char* p
= s
+ length
- 1; p
>= s
; p
--) {
179 if (radixMultiplier
== Inf
) {
185 int digit
= parseDigit(*p
, radix
);
186 number
+= digit
* radixMultiplier
;
189 radixMultiplier
*= radix
;
195 static double parseInt(const UString
& s
, int radix
)
197 int length
= s
.size();
198 const UChar
* data
= s
.data();
201 while (p
< length
&& isStrWhiteSpace(data
[p
]))
208 else if (data
[p
] == '-') {
214 if ((radix
== 0 || radix
== 16) && length
- p
>= 2 && data
[p
] == '0' && (data
[p
+ 1] == 'x' || data
[p
+ 1] == 'X')) {
217 } else if (radix
== 0) {
218 if (p
< length
&& data
[p
] == '0')
224 if (radix
< 2 || radix
> 36)
227 int firstDigitPosition
= p
;
228 bool sawDigit
= false;
231 int digit
= parseDigit(data
[p
], radix
);
240 if (number
>= mantissaOverflowLowerBound
) {
242 number
= WTF::strtod(s
.substr(firstDigitPosition
, p
- firstDigitPosition
).ascii(), 0);
243 else if (radix
== 2 || radix
== 4 || radix
== 8 || radix
== 16 || radix
== 32)
244 number
= parseIntOverflow(s
.substr(firstDigitPosition
, p
- firstDigitPosition
).ascii(), p
- firstDigitPosition
, radix
);
250 return sign
* number
;
253 static double parseFloat(const UString
& s
)
255 // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
256 // Need to skip any whitespace and then one + or - sign.
257 int length
= s
.size();
258 const UChar
* data
= s
.data();
260 while (p
< length
&& isStrWhiteSpace(data
[p
]))
263 if (p
< length
&& (data
[p
] == '+' || data
[p
] == '-'))
266 if (length
- p
>= 2 && data
[p
] == '0' && (data
[p
+ 1] == 'x' || data
[p
+ 1] == 'X'))
269 return s
.toDouble(true /*tolerant*/, false /* NaN for empty string */);
272 JSValue JSC_HOST_CALL
globalFuncEval(ExecState
* exec
, JSObject
* function
, JSValue thisValue
, const ArgList
& args
)
274 JSObject
* thisObject
= thisValue
.toThisObject(exec
);
275 JSObject
* unwrappedObject
= thisObject
->unwrappedObject();
276 if (!unwrappedObject
->isGlobalObject() || static_cast<JSGlobalObject
*>(unwrappedObject
)->evalFunction() != function
)
277 return throwError(exec
, EvalError
, "The \"this\" value passed to eval must be the global object from which eval originated");
279 JSValue x
= args
.at(0);
283 UString s
= x
.toString(exec
);
285 LiteralParser
preparser(exec
, s
, LiteralParser::NonStrictJSON
);
286 if (JSValue parsedObject
= preparser
.tryLiteralParse())
292 SourceCode source
= makeSource(s
);
293 RefPtr
<EvalNode
> evalNode
= exec
->globalData().parser
->parse
<EvalNode
>(exec
, exec
->dynamicGlobalObject()->debugger(), source
, &errLine
, &errMsg
);
296 return throwError(exec
, SyntaxError
, errMsg
, errLine
, source
.provider()->asID(), NULL
);
298 return exec
->interpreter()->execute(evalNode
.get(), exec
, thisObject
, static_cast<JSGlobalObject
*>(unwrappedObject
)->globalScopeChain().node(), exec
->exceptionSlot());
301 JSValue JSC_HOST_CALL
globalFuncParseInt(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
303 JSValue value
= args
.at(0);
304 int32_t radix
= args
.at(1).toInt32(exec
);
306 if (radix
!= 0 && radix
!= 10)
307 return jsNumber(exec
, parseInt(value
.toString(exec
), radix
));
312 if (value
.isDouble()) {
313 double d
= value
.asDouble();
315 return jsNumber(exec
, (d
> 0) ? floor(d
) : ceil(d
));
316 if (isnan(d
) || isinf(d
))
318 return jsNumber(exec
, 0);
321 return jsNumber(exec
, parseInt(value
.toString(exec
), radix
));
324 JSValue JSC_HOST_CALL
globalFuncParseFloat(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
326 return jsNumber(exec
, parseFloat(args
.at(0).toString(exec
)));
329 JSValue JSC_HOST_CALL
globalFuncIsNaN(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
331 return jsBoolean(isnan(args
.at(0).toNumber(exec
)));
334 JSValue JSC_HOST_CALL
globalFuncIsFinite(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
336 double n
= args
.at(0).toNumber(exec
);
337 return jsBoolean(!isnan(n
) && !isinf(n
));
340 JSValue JSC_HOST_CALL
globalFuncDecodeURI(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
342 static const char do_not_unescape_when_decoding_URI
[] =
345 return decode(exec
, args
, do_not_unescape_when_decoding_URI
, true);
348 JSValue JSC_HOST_CALL
globalFuncDecodeURIComponent(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
350 return decode(exec
, args
, "", true);
353 JSValue JSC_HOST_CALL
globalFuncEncodeURI(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
355 static const char do_not_escape_when_encoding_URI
[] =
356 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
357 "abcdefghijklmnopqrstuvwxyz"
359 "!#$&'()*+,-./:;=?@_~";
361 return encode(exec
, args
, do_not_escape_when_encoding_URI
);
364 JSValue JSC_HOST_CALL
globalFuncEncodeURIComponent(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
366 static const char do_not_escape_when_encoding_URI_component
[] =
367 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
368 "abcdefghijklmnopqrstuvwxyz"
372 return encode(exec
, args
, do_not_escape_when_encoding_URI_component
);
375 JSValue JSC_HOST_CALL
globalFuncEscape(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
377 static const char do_not_escape
[] =
378 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
379 "abcdefghijklmnopqrstuvwxyz"
385 UString str
= args
.at(0).toString(exec
);
386 const UChar
* c
= str
.data();
387 for (int k
= 0; k
< str
.size(); k
++, c
++) {
391 snprintf(tmp
, sizeof(tmp
), "%%u%04X", u
);
393 } else if (u
!= 0 && strchr(do_not_escape
, static_cast<char>(u
)))
397 snprintf(tmp
, sizeof(tmp
), "%%%02X", u
);
403 return jsString(exec
, result
);
406 JSValue JSC_HOST_CALL
globalFuncUnescape(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
409 UString str
= args
.at(0).toString(exec
);
411 int len
= str
.size();
413 const UChar
* c
= str
.data() + k
;
415 if (c
[0] == '%' && k
<= len
- 6 && c
[1] == 'u') {
416 if (isASCIIHexDigit(c
[2]) && isASCIIHexDigit(c
[3]) && isASCIIHexDigit(c
[4]) && isASCIIHexDigit(c
[5])) {
417 u
= Lexer::convertUnicode(c
[2], c
[3], c
[4], c
[5]);
421 } else if (c
[0] == '%' && k
<= len
- 3 && isASCIIHexDigit(c
[1]) && isASCIIHexDigit(c
[2])) {
422 u
= UChar(Lexer::convertHex(c
[1], c
[2]));
430 return jsString(exec
, result
);
434 JSValue JSC_HOST_CALL
globalFuncJSCPrint(ExecState
* exec
, JSObject
*, JSValue
, const ArgList
& args
)
436 CStringBuffer string
;
437 args
.at(0).toString(exec
).getCString(string
);
439 return jsUndefined();