JSGlobalObjectFunctions.cpp 25 KB

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