https://bugs.webkit.org/show_bug.cgi?id=16777
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGlobalObjectFunctions.cpp
1 /*
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
7  *
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.
12  *
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.
17  *
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.
22  *
23  */
24
25 #include "config.h"
26 #include "JSGlobalObjectFunctions.h"
27
28 #include "CallFrame.h"
29 #include "Interpreter.h"
30 #include "JSGlobalObject.h"
31 #include "JSString.h"
32 #include "JSStringBuilder.h"
33 #include "Lexer.h"
34 #include "LiteralParser.h"
35 #include "Nodes.h"
36 #include "Parser.h"
37 #include "UStringBuilder.h"
38 #include "dtoa.h"
39 #include <stdio.h>
40 #include <stdlib.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>
46
47 using namespace WTF;
48 using namespace Unicode;
49
50 namespace JSC {
51
52 #define NaN std::numeric_limits<double>::quiet_NaN()
53 #define Inf std::numeric_limits<double>::infinity()
54
55 static JSValue encode(ExecState* exec, const char* doNotEscape)
56 {
57     UString str = exec->argument(0).toString(exec);
58     CString cstr = str.utf8(true);
59     if (!cstr.data())
60         return throwError(exec, createURIError(exec, "String contained an illegal UTF-16 sequence."));
61
62     JSStringBuilder builder;
63     const char* p = cstr.data();
64     for (size_t k = 0; k < cstr.length(); k++, p++) {
65         char c = *p;
66         if (c && strchr(doNotEscape, c))
67             builder.append(c);
68         else {
69             char tmp[4];
70             snprintf(tmp, sizeof(tmp), "%%%02X", static_cast<unsigned char>(c));
71             builder.append(tmp);
72         }
73     }
74     return builder.build(exec);
75 }
76
77 static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict)
78 {
79     JSStringBuilder builder;
80     UString str = exec->argument(0).toString(exec);
81     int k = 0;
82     int len = str.length();
83     const UChar* d = str.characters();
84     UChar u = 0;
85     while (k < len) {
86         const UChar* p = d + k;
87         UChar c = *p;
88         if (c == '%') {
89             int charLen = 0;
90             if (k <= len - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {
91                 const char b0 = Lexer::convertHex(p[1], p[2]);
92                 const int sequenceLen = UTF8SequenceLength(b0);
93                 if (sequenceLen != 0 && k <= len - sequenceLen * 3) {
94                     charLen = sequenceLen * 3;
95                     char sequence[5];
96                     sequence[0] = b0;
97                     for (int i = 1; i < sequenceLen; ++i) {
98                         const UChar* q = p + i * 3;
99                         if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))
100                             sequence[i] = Lexer::convertHex(q[1], q[2]);
101                         else {
102                             charLen = 0;
103                             break;
104                         }
105                     }
106                     if (charLen != 0) {
107                         sequence[sequenceLen] = 0;
108                         const int character = decodeUTF8Sequence(sequence);
109                         if (character < 0 || character >= 0x110000)
110                             charLen = 0;
111                         else if (character >= 0x10000) {
112                             // Convert to surrogate pair.
113                             builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
114                             u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
115                         } else
116                             u = static_cast<UChar>(character);
117                     }
118                 }
119             }
120             if (charLen == 0) {
121                 if (strict)
122                     return throwError(exec, createURIError(exec, "URI error"));
123                 // The only case where we don't use "strict" mode is the "unescape" function.
124                 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
125                 if (k <= len - 6 && p[1] == 'u'
126                         && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])
127                         && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {
128                     charLen = 6;
129                     u = Lexer::convertUnicode(p[2], p[3], p[4], p[5]);
130                 }
131             }
132             if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) {
133                 c = u;
134                 k += charLen - 1;
135             }
136         }
137         k++;
138         builder.append(c);
139     }
140     return builder.build(exec);
141 }
142
143 bool isStrWhiteSpace(UChar c)
144 {
145     switch (c) {
146         // ECMA-262-5th 7.2 & 7.3
147         case 0x0009:
148         case 0x000A:
149         case 0x000B:
150         case 0x000C:
151         case 0x000D:
152         case 0x0020:
153         case 0x00A0:
154         case 0x2028:
155         case 0x2029:
156         case 0xFEFF:
157             return true;
158         default:
159             return c > 0xff && isSeparatorSpace(c);
160     }
161 }
162
163 static int parseDigit(unsigned short c, int radix)
164 {
165     int digit = -1;
166
167     if (c >= '0' && c <= '9')
168         digit = c - '0';
169     else if (c >= 'A' && c <= 'Z')
170         digit = c - 'A' + 10;
171     else if (c >= 'a' && c <= 'z')
172         digit = c - 'a' + 10;
173
174     if (digit >= radix)
175         return -1;
176     return digit;
177 }
178
179 double parseIntOverflow(const char* s, int length, int radix)
180 {
181     double number = 0.0;
182     double radixMultiplier = 1.0;
183
184     for (const char* p = s + length - 1; p >= s; p--) {
185         if (radixMultiplier == Inf) {
186             if (*p != '0') {
187                 number = Inf;
188                 break;
189             }
190         } else {
191             int digit = parseDigit(*p, radix);
192             number += digit * radixMultiplier;
193         }
194
195         radixMultiplier *= radix;
196     }
197
198     return number;
199 }
200
201 double parseIntOverflow(const UChar* s, int length, int radix)
202 {
203     double number = 0.0;
204     double radixMultiplier = 1.0;
205
206     for (const UChar* p = s + length - 1; p >= s; p--) {
207         if (radixMultiplier == Inf) {
208             if (*p != '0') {
209                 number = Inf;
210                 break;
211             }
212         } else {
213             int digit = parseDigit(*p, radix);
214             number += digit * radixMultiplier;
215         }
216
217         radixMultiplier *= radix;
218     }
219
220     return number;
221 }
222
223 static double parseInt(const UString& s, int radix)
224 {
225     int length = s.length();
226     const UChar* data = s.characters();
227     int p = 0;
228
229     while (p < length && isStrWhiteSpace(data[p]))
230         ++p;
231
232     double sign = 1;
233     if (p < length) {
234         if (data[p] == '+')
235             ++p;
236         else if (data[p] == '-') {
237             sign = -1;
238             ++p;
239         }
240     }
241
242     if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {
243         radix = 16;
244         p += 2;
245     } else if (radix == 0) {
246         if (p < length && data[p] == '0')
247             radix = 8;
248         else
249             radix = 10;
250     }
251
252     if (radix < 2 || radix > 36)
253         return NaN;
254
255     int firstDigitPosition = p;
256     bool sawDigit = false;
257     double number = 0;
258     while (p < length) {
259         int digit = parseDigit(data[p], radix);
260         if (digit == -1)
261             break;
262         sawDigit = true;
263         number *= radix;
264         number += digit;
265         ++p;
266     }
267
268     if (number >= mantissaOverflowLowerBound) {
269         if (radix == 10)
270             number = WTF::strtod(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), 0);
271         else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
272             number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
273     }
274
275     if (!sawDigit)
276         return NaN;
277
278     return sign * number;
279 }
280
281 static const int SizeOfInfinity = 8;
282
283 static bool isInfinity(const UChar* data, const UChar* end)
284 {
285     return (end - data) >= SizeOfInfinity
286         && data[0] == 'I'
287         && data[1] == 'n'
288         && data[2] == 'f'
289         && data[3] == 'i'
290         && data[4] == 'n'
291         && data[5] == 'i'
292         && data[6] == 't'
293         && data[7] == 'y';
294 }
295
296 // See ecma-262 9.3.1
297 static double jsHexIntegerLiteral(const UChar*& data, const UChar* end)
298 {
299     // Hex number.
300     data += 2;
301     const UChar* firstDigitPosition = data;
302     double number = 0;
303     while (true) {
304         number = number * 16 + toASCIIHexValue(*data);
305         ++data;
306         if (data == end)
307             break;
308         if (!isASCIIHexDigit(*data))
309             break;
310     }
311     if (number >= mantissaOverflowLowerBound)
312         number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
313
314     return number;
315 }
316
317 // See ecma-262 9.3.1
318 static double jsStrDecimalLiteral(const UChar*& data, const UChar* end)
319 {
320     ASSERT(data < end);
321
322     // Copy the sting into a null-terminated byte buffer, and call strtod.
323     Vector<char, 32> byteBuffer;
324     for (const UChar* characters = data; characters < end; ++characters) {
325         UChar character = *characters;
326         byteBuffer.append(isASCII(character) ? character : 0);
327     }
328     byteBuffer.append(0);
329     char* endOfNumber;
330     double number = WTF::strtod(byteBuffer.data(), &endOfNumber);
331
332     // Check if strtod found a number; if so return it.
333     ptrdiff_t consumed = endOfNumber - byteBuffer.data();
334     if (consumed) {
335         data += consumed;
336         return number;
337     }
338
339     // Check for [+-]?Infinity
340     switch (*data) {
341     case 'I':
342         if (isInfinity(data, end)) {
343             data += SizeOfInfinity;
344             return Inf;
345         }
346         break;
347
348     case '+':
349         if (isInfinity(data + 1, end)) {
350             data += SizeOfInfinity + 1;
351             return Inf;
352         }
353         break;
354
355     case '-':
356         if (isInfinity(data + 1, end)) {
357             data += SizeOfInfinity + 1;
358             return -Inf;
359         }
360         break;
361     }
362
363     // Not a number.
364     return NaN;
365 }
366
367 // See ecma-262 9.3.1
368 double jsToNumber(const UString& s)
369 {
370     unsigned size = s.length();
371
372     if (size == 1) {
373         UChar c = s.characters()[0];
374         if (isASCIIDigit(c))
375             return c - '0';
376         if (isStrWhiteSpace(c))
377             return 0;
378         return NaN;
379     }
380
381     const UChar* data = s.characters();
382     const UChar* end = data + size;
383
384     // Skip leading white space.
385     for (; data < end; ++data) {
386         if (!isStrWhiteSpace(*data))
387             break;
388     }
389
390     // Empty string.
391     if (data == end)
392         return 0.0;
393
394     double number;
395     if (data[0] == '0' && data + 2 < end && (data[1] | 0x20) == 'x' && isASCIIHexDigit(data[2]))
396         number = jsHexIntegerLiteral(data, end);
397     else
398         number = jsStrDecimalLiteral(data, end);
399
400     // Allow trailing white space.
401     for (; data < end; ++data) {
402         if (!isStrWhiteSpace(*data))
403             break;
404     }
405     if (data != end)
406         return NaN;
407
408     return number;
409 }
410
411 static double parseFloat(const UString& s)
412 {
413     unsigned size = s.length();
414
415     if (size == 1) {
416         UChar c = s.characters()[0];
417         if (isASCIIDigit(c))
418             return c - '0';
419         return NaN;
420     }
421
422     const UChar* data = s.characters();
423     const UChar* end = data + size;
424
425     // Skip leading white space.
426     for (; data < end; ++data) {
427         if (!isStrWhiteSpace(*data))
428             break;
429     }
430
431     // Empty string.
432     if (data == end)
433         return NaN;
434
435     return jsStrDecimalLiteral(data, end);
436 }
437
438 EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
439 {
440     JSObject* thisObject = exec->hostThisValue().toThisObject(exec);
441     JSObject* unwrappedObject = thisObject->unwrappedObject();
442     if (!unwrappedObject->isGlobalObject() || static_cast<JSGlobalObject*>(unwrappedObject)->evalFunction() != exec->callee())
443         return throwVMError(exec, createEvalError(exec, "The \"this\" value passed to eval must be the global object from which eval originated"));
444
445     JSValue x = exec->argument(0);
446     if (!x.isString())
447         return JSValue::encode(x);
448
449     UString s = x.toString(exec);
450
451     LiteralParser preparser(exec, s, LiteralParser::NonStrictJSON);
452     if (JSValue parsedObject = preparser.tryLiteralParse())
453         return JSValue::encode(parsedObject);
454
455     EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
456     JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain());
457     if (error)
458         return throwVMError(exec, error);
459
460     return JSValue::encode(exec->interpreter()->execute(eval, exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain()));
461 }
462
463 EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
464 {
465     JSValue value = exec->argument(0);
466     int32_t radix = exec->argument(1).toInt32(exec);
467
468     if (radix != 0 && radix != 10)
469         return JSValue::encode(jsNumber(parseInt(value.toString(exec), radix)));
470
471     if (value.isInt32())
472         return JSValue::encode(value);
473
474     if (value.isDouble()) {
475         double d = value.asDouble();
476         if (isfinite(d))
477             return JSValue::encode(jsNumber((d > 0) ? floor(d) : ceil(d)));
478         return JSValue::encode(jsNaN());
479     }
480
481     return JSValue::encode(jsNumber(parseInt(value.toString(exec), radix)));
482 }
483
484 EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
485 {
486     return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec))));
487 }
488
489 EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec)
490 {
491     return JSValue::encode(jsBoolean(isnan(exec->argument(0).toNumber(exec))));
492 }
493
494 EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)
495 {
496     double n = exec->argument(0).toNumber(exec);
497     return JSValue::encode(jsBoolean(isfinite(n)));
498 }
499
500 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
501 {
502     static const char do_not_unescape_when_decoding_URI[] =
503         "#$&+,/:;=?@";
504
505     return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true));
506 }
507
508 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
509 {
510     return JSValue::encode(decode(exec, "", true));
511 }
512
513 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
514 {
515     static const char do_not_escape_when_encoding_URI[] =
516         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
517         "abcdefghijklmnopqrstuvwxyz"
518         "0123456789"
519         "!#$&'()*+,-./:;=?@_~";
520
521     return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI));
522 }
523
524 EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
525 {
526     static const char do_not_escape_when_encoding_URI_component[] =
527         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
528         "abcdefghijklmnopqrstuvwxyz"
529         "0123456789"
530         "!'()*-._~";
531
532     return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component));
533 }
534
535 EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
536 {
537     static const char do_not_escape[] =
538         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
539         "abcdefghijklmnopqrstuvwxyz"
540         "0123456789"
541         "*+-./@_";
542
543     JSStringBuilder builder;
544     UString str = exec->argument(0).toString(exec);
545     const UChar* c = str.characters();
546     for (unsigned k = 0; k < str.length(); k++, c++) {
547         int u = c[0];
548         if (u > 255) {
549             char tmp[7];
550             snprintf(tmp, sizeof(tmp), "%%u%04X", u);
551             builder.append(tmp);
552         } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u)))
553             builder.append(c, 1);
554         else {
555             char tmp[4];
556             snprintf(tmp, sizeof(tmp), "%%%02X", u);
557             builder.append(tmp);
558         }
559     }
560
561     return JSValue::encode(builder.build(exec));
562 }
563
564 EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
565 {
566     UStringBuilder builder;
567     UString str = exec->argument(0).toString(exec);
568     int k = 0;
569     int len = str.length();
570     while (k < len) {
571         const UChar* c = str.characters() + k;
572         UChar u;
573         if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
574             if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
575                 u = Lexer::convertUnicode(c[2], c[3], c[4], c[5]);
576                 c = &u;
577                 k += 5;
578             }
579         } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
580             u = UChar(Lexer::convertHex(c[1], c[2]));
581             c = &u;
582             k += 2;
583         }
584         k++;
585         builder.append(*c);
586     }
587
588     return JSValue::encode(jsString(exec, builder.toUString()));
589 }
590
591 } // namespace JSC