~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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, 2012 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 "JSFunction.h"
 
31
#include "JSGlobalObject.h"
 
32
#include "JSString.h"
 
33
#include "JSStringBuilder.h"
 
34
#include "Lexer.h"
 
35
#include "LiteralParser.h"
 
36
#include "Nodes.h"
 
37
#include "Parser.h"
 
38
#include <wtf/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/text/StringBuilder.h>
 
46
#include <wtf/unicode/UTF8.h>
 
47
 
 
48
using namespace WTF;
 
49
using namespace Unicode;
 
50
 
 
51
namespace JSC {
 
52
 
 
53
static JSValue encode(ExecState* exec, const char* doNotEscape)
 
54
{
 
55
    CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(String::StrictConversion);
 
56
    if (!cstr.data())
 
57
        return throwError(exec, createURIError(exec, ASCIILiteral("String contained an illegal UTF-16 sequence.")));
 
58
 
 
59
    JSStringBuilder builder;
 
60
    const char* p = cstr.data();
 
61
    for (size_t k = 0; k < cstr.length(); k++, p++) {
 
62
        char c = *p;
 
63
        if (c && strchr(doNotEscape, c))
 
64
            builder.append(c);
 
65
        else {
 
66
            char tmp[4];
 
67
            snprintf(tmp, sizeof(tmp), "%%%02X", static_cast<unsigned char>(c));
 
68
            builder.append(tmp);
 
69
        }
 
70
    }
 
71
    return builder.build(exec);
 
72
}
 
73
 
 
74
template <typename CharType>
 
75
ALWAYS_INLINE
 
76
static JSValue decode(ExecState* exec, const CharType* characters, int length, const char* doNotUnescape, bool strict)
 
77
{
 
78
    JSStringBuilder builder;
 
79
    int k = 0;
 
80
    UChar u = 0;
 
81
    while (k < length) {
 
82
        const CharType* p = characters + k;
 
83
        CharType c = *p;
 
84
        if (c == '%') {
 
85
            int charLen = 0;
 
86
            if (k <= length - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {
 
87
                const char b0 = Lexer<CharType>::convertHex(p[1], p[2]);
 
88
                const int sequenceLen = UTF8SequenceLength(b0);
 
89
                if (sequenceLen && k <= length - sequenceLen * 3) {
 
90
                    charLen = sequenceLen * 3;
 
91
                    char sequence[5];
 
92
                    sequence[0] = b0;
 
93
                    for (int i = 1; i < sequenceLen; ++i) {
 
94
                        const CharType* q = p + i * 3;
 
95
                        if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))
 
96
                            sequence[i] = Lexer<CharType>::convertHex(q[1], q[2]);
 
97
                        else {
 
98
                            charLen = 0;
 
99
                            break;
 
100
                        }
 
101
                    }
 
102
                    if (charLen != 0) {
 
103
                        sequence[sequenceLen] = 0;
 
104
                        const int character = decodeUTF8Sequence(sequence);
 
105
                        if (character < 0 || character >= 0x110000)
 
106
                            charLen = 0;
 
107
                        else if (character >= 0x10000) {
 
108
                            // Convert to surrogate pair.
 
109
                            builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
 
110
                            u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
 
111
                        } else
 
112
                            u = static_cast<UChar>(character);
 
113
                    }
 
114
                }
 
115
            }
 
116
            if (charLen == 0) {
 
117
                if (strict)
 
118
                    return throwError(exec, createURIError(exec, ASCIILiteral("URI error")));
 
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 <= length - 6 && p[1] == 'u'
 
122
                        && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])
 
123
                        && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {
 
124
                    charLen = 6;
 
125
                    u = Lexer<UChar>::convertUnicode(p[2], p[3], p[4], p[5]);
 
126
                }
 
127
            }
 
128
            if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) {
 
129
                if (u < 256)
 
130
                    builder.append(static_cast<LChar>(u));
 
131
                else
 
132
                    builder.append(u);
 
133
                k += charLen;
 
134
                continue;
 
135
            }
 
136
        }
 
137
        k++;
 
138
        builder.append(c);
 
139
    }
 
140
    return builder.build(exec);
 
141
}
 
142
 
 
143
static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict)
 
144
{
 
145
    JSStringBuilder builder;
 
146
    String str = exec->argument(0).toString(exec)->value(exec);
 
147
    
 
148
    if (str.is8Bit())
 
149
        return decode(exec, str.characters8(), str.length(), doNotUnescape, strict);
 
150
    return decode(exec, str.characters16(), str.length(), doNotUnescape, strict);
 
151
}
 
152
 
 
153
bool isStrWhiteSpace(UChar c)
 
154
{
 
155
    switch (c) {
 
156
        // ECMA-262-5th 7.2 & 7.3
 
157
        case 0x0009:
 
158
        case 0x000A:
 
159
        case 0x000B:
 
160
        case 0x000C:
 
161
        case 0x000D:
 
162
        case 0x0020:
 
163
        case 0x00A0:
 
164
        case 0x2028:
 
165
        case 0x2029:
 
166
        case 0xFEFF:
 
167
            return true;
 
168
        default:
 
169
            return c > 0xff && isSeparatorSpace(c);
 
170
    }
 
171
}
 
172
 
 
173
static int parseDigit(unsigned short c, int radix)
 
174
{
 
175
    int digit = -1;
 
176
 
 
177
    if (c >= '0' && c <= '9')
 
178
        digit = c - '0';
 
179
    else if (c >= 'A' && c <= 'Z')
 
180
        digit = c - 'A' + 10;
 
181
    else if (c >= 'a' && c <= 'z')
 
182
        digit = c - 'a' + 10;
 
183
 
 
184
    if (digit >= radix)
 
185
        return -1;
 
186
    return digit;
 
187
}
 
188
 
 
189
double parseIntOverflow(const LChar* s, int length, int radix)
 
190
{
 
191
    double number = 0.0;
 
192
    double radixMultiplier = 1.0;
 
193
 
 
194
    for (const LChar* p = s + length - 1; p >= s; p--) {
 
195
        if (radixMultiplier == std::numeric_limits<double>::infinity()) {
 
196
            if (*p != '0') {
 
197
                number = std::numeric_limits<double>::infinity();
 
198
                break;
 
199
            }
 
200
        } else {
 
201
            int digit = parseDigit(*p, radix);
 
202
            number += digit * radixMultiplier;
 
203
        }
 
204
 
 
205
        radixMultiplier *= radix;
 
206
    }
 
207
 
 
208
    return number;
 
209
}
 
210
 
 
211
double parseIntOverflow(const UChar* s, int length, int radix)
 
212
{
 
213
    double number = 0.0;
 
214
    double radixMultiplier = 1.0;
 
215
 
 
216
    for (const UChar* p = s + length - 1; p >= s; p--) {
 
217
        if (radixMultiplier == std::numeric_limits<double>::infinity()) {
 
218
            if (*p != '0') {
 
219
                number = std::numeric_limits<double>::infinity();
 
220
                break;
 
221
            }
 
222
        } else {
 
223
            int digit = parseDigit(*p, radix);
 
224
            number += digit * radixMultiplier;
 
225
        }
 
226
 
 
227
        radixMultiplier *= radix;
 
228
    }
 
229
 
 
230
    return number;
 
231
}
 
232
 
 
233
// ES5.1 15.1.2.2
 
234
template <typename CharType>
 
235
ALWAYS_INLINE
 
236
static double parseInt(const String& s, const CharType* data, int radix)
 
237
{
 
238
    // 1. Let inputString be ToString(string).
 
239
    // 2. Let S be a newly created substring of inputString consisting of the first character that is not a
 
240
    //    StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
 
241
    //    space.) If inputString does not contain any such characters, let S be the empty string.
 
242
    int length = s.length();
 
243
    int p = 0;
 
244
    while (p < length && isStrWhiteSpace(data[p]))
 
245
        ++p;
 
246
 
 
247
    // 3. Let sign be 1.
 
248
    // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.
 
249
    // 5. If S is not empty and the first character of S is a plus sign + or a minus sign -, then remove the first character from S.
 
250
    double sign = 1;
 
251
    if (p < length) {
 
252
        if (data[p] == '+')
 
253
            ++p;
 
254
        else if (data[p] == '-') {
 
255
            sign = -1;
 
256
            ++p;
 
257
        }
 
258
    }
 
259
 
 
260
    // 6. Let R = ToInt32(radix).
 
261
    // 7. Let stripPrefix be true.
 
262
    // 8. If R != 0,then
 
263
    //   b. If R != 16, let stripPrefix be false.
 
264
    // 9. Else, R == 0
 
265
    //   a. LetR = 10.
 
266
    // 10. If stripPrefix is true, then
 
267
    //   a. If the length of S is at least 2 and the first two characters of S are either ā€•0x or ā€•0X,
 
268
    //      then remove the first two characters from S and let R = 16.
 
269
    // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S
 
270
    //     consisting of all characters before the first such character; otherwise, let Z be S.
 
271
    if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {
 
272
        radix = 16;
 
273
        p += 2;
 
274
    } else if (radix == 0)
 
275
        radix = 10;
 
276
 
 
277
    // 8.a If R < 2 or R > 36, then return NaN.
 
278
    if (radix < 2 || radix > 36)
 
279
        return QNaN;
 
280
 
 
281
    // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
 
282
    //     A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
 
283
    //     digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;
 
284
    //     and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the
 
285
    //     mathematical integer value that is represented by Z in radix-R notation.)
 
286
    // 14. Let number be the Number value for mathInt.
 
287
    int firstDigitPosition = p;
 
288
    bool sawDigit = false;
 
289
    double number = 0;
 
290
    while (p < length) {
 
291
        int digit = parseDigit(data[p], radix);
 
292
        if (digit == -1)
 
293
            break;
 
294
        sawDigit = true;
 
295
        number *= radix;
 
296
        number += digit;
 
297
        ++p;
 
298
    }
 
299
 
 
300
    // 12. If Z is empty, return NaN.
 
301
    if (!sawDigit)
 
302
        return QNaN;
 
303
 
 
304
    // Alternate code path for certain large numbers.
 
305
    if (number >= mantissaOverflowLowerBound) {
 
306
        if (radix == 10) {
 
307
            size_t parsedLength;
 
308
            number = parseDouble(s.characters() + firstDigitPosition, p - firstDigitPosition, parsedLength);
 
309
        } else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
 
310
            number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
 
311
    }
 
312
 
 
313
    // 15. Return sign x number.
 
314
    return sign * number;
 
315
}
 
316
 
 
317
static double parseInt(const String& s, int radix)
 
318
{
 
319
    if (s.is8Bit())
 
320
        return parseInt(s, s.characters8(), radix);
 
321
    return parseInt(s, s.characters16(), radix);
 
322
}
 
323
 
 
324
static const int SizeOfInfinity = 8;
 
325
 
 
326
template <typename CharType>
 
327
static bool isInfinity(const CharType* data, const CharType* end)
 
328
{
 
329
    return (end - data) >= SizeOfInfinity
 
330
        && data[0] == 'I'
 
331
        && data[1] == 'n'
 
332
        && data[2] == 'f'
 
333
        && data[3] == 'i'
 
334
        && data[4] == 'n'
 
335
        && data[5] == 'i'
 
336
        && data[6] == 't'
 
337
        && data[7] == 'y';
 
338
}
 
339
 
 
340
// See ecma-262 9.3.1
 
341
template <typename CharType>
 
342
static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
 
343
{
 
344
    // Hex number.
 
345
    data += 2;
 
346
    const CharType* firstDigitPosition = data;
 
347
    double number = 0;
 
348
    while (true) {
 
349
        number = number * 16 + toASCIIHexValue(*data);
 
350
        ++data;
 
351
        if (data == end)
 
352
            break;
 
353
        if (!isASCIIHexDigit(*data))
 
354
            break;
 
355
    }
 
356
    if (number >= mantissaOverflowLowerBound)
 
357
        number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
 
358
 
 
359
    return number;
 
360
}
 
361
 
 
362
// See ecma-262 9.3.1
 
363
template <typename CharType>
 
364
static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
 
365
{
 
366
    ASSERT(data < end);
 
367
 
 
368
    size_t parsedLength;
 
369
    double number = parseDouble(data, end - data, parsedLength);
 
370
    if (parsedLength) {
 
371
        data += parsedLength;
 
372
        return number;
 
373
    }
 
374
 
 
375
    // Check for [+-]?Infinity
 
376
    switch (*data) {
 
377
    case 'I':
 
378
        if (isInfinity(data, end)) {
 
379
            data += SizeOfInfinity;
 
380
            return std::numeric_limits<double>::infinity();
 
381
        }
 
382
        break;
 
383
 
 
384
    case '+':
 
385
        if (isInfinity(data + 1, end)) {
 
386
            data += SizeOfInfinity + 1;
 
387
            return std::numeric_limits<double>::infinity();
 
388
        }
 
389
        break;
 
390
 
 
391
    case '-':
 
392
        if (isInfinity(data + 1, end)) {
 
393
            data += SizeOfInfinity + 1;
 
394
            return -std::numeric_limits<double>::infinity();
 
395
        }
 
396
        break;
 
397
    }
 
398
 
 
399
    // Not a number.
 
400
    return QNaN;
 
401
}
 
402
 
 
403
template <typename CharType>
 
404
static double toDouble(const CharType* characters, unsigned size)
 
405
{
 
406
    const CharType* endCharacters = characters + size;
 
407
 
 
408
    // Skip leading white space.
 
409
    for (; characters < endCharacters; ++characters) {
 
410
        if (!isStrWhiteSpace(*characters))
 
411
            break;
 
412
    }
 
413
    
 
414
    // Empty string.
 
415
    if (characters == endCharacters)
 
416
        return 0.0;
 
417
    
 
418
    double number;
 
419
    if (characters[0] == '0' && characters + 2 < endCharacters && (characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
 
420
        number = jsHexIntegerLiteral(characters, endCharacters);
 
421
    else
 
422
        number = jsStrDecimalLiteral(characters, endCharacters);
 
423
    
 
424
    // Allow trailing white space.
 
425
    for (; characters < endCharacters; ++characters) {
 
426
        if (!isStrWhiteSpace(*characters))
 
427
            break;
 
428
    }
 
429
    if (characters != endCharacters)
 
430
        return QNaN;
 
431
    
 
432
    return number;
 
433
}
 
434
 
 
435
// See ecma-262 9.3.1
 
436
double jsToNumber(const String& s)
 
437
{
 
438
    unsigned size = s.length();
 
439
 
 
440
    if (size == 1) {
 
441
        UChar c = s[0];
 
442
        if (isASCIIDigit(c))
 
443
            return c - '0';
 
444
        if (isStrWhiteSpace(c))
 
445
            return 0;
 
446
        return QNaN;
 
447
    }
 
448
 
 
449
    if (s.is8Bit())
 
450
        return toDouble(s.characters8(), size);
 
451
    return toDouble(s.characters16(), size);
 
452
}
 
453
 
 
454
static double parseFloat(const String& s)
 
455
{
 
456
    unsigned size = s.length();
 
457
 
 
458
    if (size == 1) {
 
459
        UChar c = s[0];
 
460
        if (isASCIIDigit(c))
 
461
            return c - '0';
 
462
        return QNaN;
 
463
    }
 
464
 
 
465
    if (s.is8Bit()) {
 
466
        const LChar* data = s.characters8();
 
467
        const LChar* end = data + size;
 
468
 
 
469
        // Skip leading white space.
 
470
        for (; data < end; ++data) {
 
471
            if (!isStrWhiteSpace(*data))
 
472
                break;
 
473
        }
 
474
 
 
475
        // Empty string.
 
476
        if (data == end)
 
477
            return QNaN;
 
478
 
 
479
        return jsStrDecimalLiteral(data, end);
 
480
    }
 
481
 
 
482
    const UChar* data = s.characters16();
 
483
    const UChar* end = data + size;
 
484
 
 
485
    // Skip leading white space.
 
486
    for (; data < end; ++data) {
 
487
        if (!isStrWhiteSpace(*data))
 
488
            break;
 
489
    }
 
490
 
 
491
    // Empty string.
 
492
    if (data == end)
 
493
        return QNaN;
 
494
 
 
495
    return jsStrDecimalLiteral(data, end);
 
496
}
 
497
 
 
498
EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
 
499
{
 
500
    JSValue x = exec->argument(0);
 
501
    if (!x.isString())
 
502
        return JSValue::encode(x);
 
503
 
 
504
    String s = x.toString(exec)->value(exec);
 
505
 
 
506
    if (s.is8Bit()) {
 
507
        LiteralParser<LChar> preparser(exec, s.characters8(), s.length(), NonStrictJSON);
 
508
        if (JSValue parsedObject = preparser.tryLiteralParse())
 
509
            return JSValue::encode(parsedObject);
 
510
    } else {
 
511
        LiteralParser<UChar> preparser(exec, s.characters16(), s.length(), NonStrictJSON);
 
512
        if (JSValue parsedObject = preparser.tryLiteralParse())
 
513
            return JSValue::encode(parsedObject);        
 
514
    }
 
515
 
 
516
    JSGlobalObject* calleeGlobalObject = exec->callee()->globalObject();
 
517
    EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
 
518
    JSObject* error = eval->compile(exec, calleeGlobalObject);
 
519
    if (error)
 
520
        return throwVMError(exec, error);
 
521
 
 
522
    return JSValue::encode(exec->interpreter()->execute(eval, exec, calleeGlobalObject->globalThis(), calleeGlobalObject));
 
523
}
 
524
 
 
525
EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
 
526
{
 
527
    JSValue value = exec->argument(0);
 
528
    JSValue radixValue = exec->argument(1);
 
529
 
 
530
    // Optimized handling for numbers:
 
531
    // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
 
532
    // results in a truncation to integer. In the case of -0, this is converted to 0.
 
533
    //
 
534
    // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
 
535
    // however these values cannot be trivially truncated to int since 10^21 exceeds
 
536
    // even the int64_t range. Negative numbers are a little trickier, the case for
 
537
    // values in the range -10^21 < n <= -1 are similar to those for integer, but
 
538
    // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
 
539
    static const double tenToTheMinus6 = 0.000001;
 
540
    static const double intMaxPlusOne = 2147483648.0;
 
541
    if (value.isNumber()) {
 
542
        double n = value.asNumber();
 
543
        if (((n < intMaxPlusOne && n >= tenToTheMinus6) || !n) && radixValue.isUndefinedOrNull())
 
544
            return JSValue::encode(jsNumber(static_cast<int32_t>(n)));
 
545
    }
 
546
 
 
547
    // If ToString throws, we shouldn't call ToInt32.
 
548
    String s = value.toString(exec)->value(exec);
 
549
    if (exec->hadException())
 
550
        return JSValue::encode(jsUndefined());
 
551
 
 
552
    return JSValue::encode(jsNumber(parseInt(s, radixValue.toInt32(exec))));
 
553
}
 
554
 
 
555
EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
 
556
{
 
557
    return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)->value(exec))));
 
558
}
 
559
 
 
560
EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec)
 
561
{
 
562
    return JSValue::encode(jsBoolean(isnan(exec->argument(0).toNumber(exec))));
 
563
}
 
564
 
 
565
EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)
 
566
{
 
567
    double n = exec->argument(0).toNumber(exec);
 
568
    return JSValue::encode(jsBoolean(isfinite(n)));
 
569
}
 
570
 
 
571
EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
 
572
{
 
573
    static const char do_not_unescape_when_decoding_URI[] =
 
574
        "#$&+,/:;=?@";
 
575
 
 
576
    return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true));
 
577
}
 
578
 
 
579
EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
 
580
{
 
581
    return JSValue::encode(decode(exec, "", true));
 
582
}
 
583
 
 
584
EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
 
585
{
 
586
    static const char do_not_escape_when_encoding_URI[] =
 
587
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
588
        "abcdefghijklmnopqrstuvwxyz"
 
589
        "0123456789"
 
590
        "!#$&'()*+,-./:;=?@_~";
 
591
 
 
592
    return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI));
 
593
}
 
594
 
 
595
EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
 
596
{
 
597
    static const char do_not_escape_when_encoding_URI_component[] =
 
598
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
599
        "abcdefghijklmnopqrstuvwxyz"
 
600
        "0123456789"
 
601
        "!'()*-._~";
 
602
 
 
603
    return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component));
 
604
}
 
605
 
 
606
EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
 
607
{
 
608
    static const char do_not_escape[] =
 
609
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
610
        "abcdefghijklmnopqrstuvwxyz"
 
611
        "0123456789"
 
612
        "*+-./@_";
 
613
 
 
614
    JSStringBuilder builder;
 
615
    String str = exec->argument(0).toString(exec)->value(exec);
 
616
    if (str.is8Bit()) {
 
617
        const LChar* c = str.characters8();
 
618
        for (unsigned k = 0; k < str.length(); k++, c++) {
 
619
            int u = c[0];
 
620
            if (u && strchr(do_not_escape, static_cast<char>(u)))
 
621
                builder.append(c, 1);
 
622
            else {
 
623
                char tmp[4];
 
624
                snprintf(tmp, sizeof(tmp), "%%%02X", u);
 
625
                builder.append(tmp);
 
626
            }
 
627
        }
 
628
 
 
629
        return JSValue::encode(builder.build(exec));        
 
630
    }
 
631
 
 
632
    const UChar* c = str.characters16();
 
633
    for (unsigned k = 0; k < str.length(); k++, c++) {
 
634
        int u = c[0];
 
635
        if (u > 255) {
 
636
            char tmp[7];
 
637
            snprintf(tmp, sizeof(tmp), "%%u%04X", u);
 
638
            builder.append(tmp);
 
639
        } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u)))
 
640
            builder.append(c, 1);
 
641
        else {
 
642
            char tmp[4];
 
643
            snprintf(tmp, sizeof(tmp), "%%%02X", u);
 
644
            builder.append(tmp);
 
645
        }
 
646
    }
 
647
 
 
648
    return JSValue::encode(builder.build(exec));
 
649
}
 
650
 
 
651
EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
 
652
{
 
653
    StringBuilder builder;
 
654
    String str = exec->argument(0).toString(exec)->value(exec);
 
655
    int k = 0;
 
656
    int len = str.length();
 
657
    
 
658
    if (str.is8Bit()) {
 
659
        const LChar* characters = str.characters8();
 
660
        LChar convertedLChar;
 
661
        while (k < len) {
 
662
            const LChar* c = characters + k;
 
663
            if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
 
664
                if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
 
665
                    builder.append(Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]));
 
666
                    k += 6;
 
667
                    continue;
 
668
                }
 
669
            } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
 
670
                convertedLChar = LChar(Lexer<LChar>::convertHex(c[1], c[2]));
 
671
                c = &convertedLChar;
 
672
                k += 2;
 
673
            }
 
674
            builder.append(*c);
 
675
            k++;
 
676
        }        
 
677
    } else {
 
678
        const UChar* characters = str.characters16();
 
679
 
 
680
        while (k < len) {
 
681
            const UChar* c = characters + k;
 
682
            UChar convertedUChar;
 
683
            if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
 
684
                if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
 
685
                    convertedUChar = Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]);
 
686
                    c = &convertedUChar;
 
687
                    k += 5;
 
688
                }
 
689
            } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
 
690
                convertedUChar = UChar(Lexer<UChar>::convertHex(c[1], c[2]));
 
691
                c = &convertedUChar;
 
692
                k += 2;
 
693
            }
 
694
            k++;
 
695
            builder.append(*c);
 
696
        }
 
697
    }
 
698
 
 
699
    return JSValue::encode(jsString(exec, builder.toString()));
 
700
}
 
701
 
 
702
EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState* exec)
 
703
{
 
704
    return throwVMTypeError(exec);
 
705
}
 
706
 
 
707
EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec)
 
708
{
 
709
    if (!exec->thisValue().isObject())
 
710
        return JSValue::encode(exec->thisValue().synthesizePrototype(exec));
 
711
 
 
712
    JSObject* thisObject = asObject(exec->thisValue());
 
713
    if (!thisObject->allowsAccessFrom(exec->trueCallerFrame()))
 
714
        return JSValue::encode(jsUndefined());
 
715
 
 
716
    return JSValue::encode(thisObject->prototype());
 
717
}
 
718
 
 
719
EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
 
720
{
 
721
    JSValue value = exec->argument(0);
 
722
 
 
723
    // Setting __proto__ of a primitive should have no effect.
 
724
    if (!exec->thisValue().isObject())
 
725
        return JSValue::encode(jsUndefined());
 
726
 
 
727
    JSObject* thisObject = asObject(exec->thisValue());
 
728
    if (!thisObject->allowsAccessFrom(exec->trueCallerFrame()))
 
729
        return JSValue::encode(jsUndefined());
 
730
 
 
731
    // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
 
732
    if (!value.isObject() && !value.isNull())
 
733
        return JSValue::encode(jsUndefined());
 
734
 
 
735
    if (!thisObject->isExtensible())
 
736
        return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
 
737
 
 
738
    if (!thisObject->setPrototypeWithCycleCheck(exec->globalData(), value))
 
739
        throwError(exec, createError(exec, "cyclic __proto__ value"));
 
740
    return JSValue::encode(jsUndefined());
 
741
}
 
742
 
 
743
} // namespace JSC