1 /* 2 * Copyright 2008 Jacek Caban for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #ifdef __REACTOS__ 20 #include <wine/config.h> 21 #include <wine/port.h> 22 #endif 23 24 #include <math.h> 25 #include <limits.h> 26 27 #include "jscript.h" 28 #include "engine.h" 29 30 #include "wine/debug.h" 31 32 WINE_DEFAULT_DEBUG_CHANNEL(jscript); 33 34 static const WCHAR NaNW[] = {'N','a','N',0}; 35 static const WCHAR InfinityW[] = {'I','n','f','i','n','i','t','y',0}; 36 static const WCHAR ArrayW[] = {'A','r','r','a','y',0}; 37 static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0}; 38 static const WCHAR DateW[] = {'D','a','t','e',0}; 39 static const WCHAR ErrorW[] = {'E','r','r','o','r',0}; 40 static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0}; 41 static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0}; 42 static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0}; 43 static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0}; 44 static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0}; 45 static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0}; 46 static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0}; 47 static const WCHAR NumberW[] = {'N','u','m','b','e','r',0}; 48 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0}; 49 static const WCHAR StringW[] = {'S','t','r','i','n','g',0}; 50 static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0}; 51 static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0}; 52 static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0}; 53 static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0}; 54 static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0}; 55 static const WCHAR escapeW[] = {'e','s','c','a','p','e',0}; 56 static const WCHAR evalW[] = {'e','v','a','l',0}; 57 static const WCHAR isNaNW[] = {'i','s','N','a','N',0}; 58 static const WCHAR isFiniteW[] = {'i','s','F','i','n','i','t','e',0}; 59 static const WCHAR parseIntW[] = {'p','a','r','s','e','I','n','t',0}; 60 static const WCHAR parseFloatW[] = {'p','a','r','s','e','F','l','o','a','t',0}; 61 static const WCHAR unescapeW[] = {'u','n','e','s','c','a','p','e',0}; 62 static const WCHAR _GetObjectW[] = {'G','e','t','O','b','j','e','c','t',0}; 63 static const WCHAR ScriptEngineW[] = {'S','c','r','i','p','t','E','n','g','i','n','e',0}; 64 static const WCHAR ScriptEngineMajorVersionW[] = 65 {'S','c','r','i','p','t','E','n','g','i','n','e','M','a','j','o','r','V','e','r','s','i','o','n',0}; 66 static const WCHAR ScriptEngineMinorVersionW[] = 67 {'S','c','r','i','p','t','E','n','g','i','n','e','M','i','n','o','r','V','e','r','s','i','o','n',0}; 68 static const WCHAR ScriptEngineBuildVersionW[] = 69 {'S','c','r','i','p','t','E','n','g','i','n','e','B','u','i','l','d','V','e','r','s','i','o','n',0}; 70 static const WCHAR CollectGarbageW[] = {'C','o','l','l','e','c','t','G','a','r','b','a','g','e',0}; 71 static const WCHAR MathW[] = {'M','a','t','h',0}; 72 static const WCHAR JSONW[] = {'J','S','O','N',0}; 73 static const WCHAR encodeURIW[] = {'e','n','c','o','d','e','U','R','I',0}; 74 static const WCHAR decodeURIW[] = {'d','e','c','o','d','e','U','R','I',0}; 75 static const WCHAR encodeURIComponentW[] = {'e','n','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0}; 76 static const WCHAR decodeURIComponentW[] = {'d','e','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0}; 77 78 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0}; 79 80 static int uri_char_table[] = { 81 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0f */ 82 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1f */ 83 0,2,0,0,1,0,1,2,2,2,2,1,1,2,2,1, /* 20-2f */ 84 2,2,2,2,2,2,2,2,2,2,1,1,0,1,0,1, /* 30-3f */ 85 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 40-4f */ 86 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2, /* 50-5f */ 87 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 60-6f */ 88 2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,0, /* 70-7f */ 89 }; 90 91 /* 1 - reserved */ 92 /* 2 - unescaped */ 93 94 static inline BOOL is_uri_reserved(WCHAR c) 95 { 96 return c < 128 && uri_char_table[c] == 1; 97 } 98 99 static inline BOOL is_uri_unescaped(WCHAR c) 100 { 101 return c < 128 && uri_char_table[c] == 2; 102 } 103 104 /* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */ 105 static inline BOOL is_ecma_nonblank(const WCHAR c) 106 { 107 return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || 108 c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/'); 109 } 110 111 static WCHAR int_to_char(int i) 112 { 113 if(i < 10) 114 return '0'+i; 115 return 'A'+i-10; 116 } 117 118 static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 119 jsval_t *r) 120 { 121 jsstr_t *ret_str, *str; 122 const WCHAR *ptr, *buf; 123 DWORD len = 0; 124 WCHAR *ret; 125 HRESULT hres; 126 127 TRACE("\n"); 128 129 if(!argc) { 130 if(r) 131 *r = jsval_string(jsstr_undefined()); 132 return S_OK; 133 } 134 135 hres = to_flat_string(ctx, argv[0], &str, &buf); 136 if(FAILED(hres)) 137 return hres; 138 139 for(ptr = buf; *ptr; ptr++) { 140 if(*ptr > 0xff) 141 len += 6; 142 else if(is_ecma_nonblank(*ptr)) 143 len++; 144 else 145 len += 3; 146 } 147 148 ret_str = jsstr_alloc_buf(len, &ret); 149 if(!ret_str) { 150 jsstr_release(str); 151 return E_OUTOFMEMORY; 152 } 153 154 len = 0; 155 for(ptr = buf; *ptr; ptr++) { 156 if(*ptr > 0xff) { 157 ret[len++] = '%'; 158 ret[len++] = 'u'; 159 ret[len++] = int_to_char(*ptr >> 12); 160 ret[len++] = int_to_char((*ptr >> 8) & 0xf); 161 ret[len++] = int_to_char((*ptr >> 4) & 0xf); 162 ret[len++] = int_to_char(*ptr & 0xf); 163 } 164 else if(is_ecma_nonblank(*ptr)) 165 ret[len++] = *ptr; 166 else { 167 ret[len++] = '%'; 168 ret[len++] = int_to_char(*ptr >> 4); 169 ret[len++] = int_to_char(*ptr & 0xf); 170 } 171 } 172 173 jsstr_release(str); 174 175 if(r) 176 *r = jsval_string(ret_str); 177 else 178 jsstr_release(ret_str); 179 return S_OK; 180 } 181 182 /* ECMA-262 3rd Edition 15.1.2.1 */ 183 HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 184 jsval_t *r) 185 { 186 call_frame_t *frame = ctx->call_ctx; 187 DWORD exec_flags = EXEC_EVAL; 188 bytecode_t *code; 189 const WCHAR *src; 190 HRESULT hres; 191 192 TRACE("\n"); 193 194 if(!argc) { 195 if(r) 196 *r = jsval_undefined(); 197 return S_OK; 198 } 199 200 if(!is_string(argv[0])) { 201 if(r) 202 return jsval_copy(argv[0], r); 203 return S_OK; 204 } 205 206 src = jsstr_flatten(get_string(argv[0])); 207 if(!src) 208 return E_OUTOFMEMORY; 209 210 TRACE("parsing %s\n", debugstr_jsval(argv[0])); 211 hres = compile_script(ctx, src, NULL, NULL, TRUE, FALSE, &code); 212 if(FAILED(hres)) { 213 WARN("parse (%s) failed: %08x\n", debugstr_jsval(argv[0]), hres); 214 return throw_syntax_error(ctx, hres, NULL); 215 } 216 217 if(!frame || (frame->flags & EXEC_GLOBAL)) 218 exec_flags |= EXEC_GLOBAL; 219 if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) 220 exec_flags |= EXEC_RETURN_TO_INTERP; 221 hres = exec_source(ctx, exec_flags, code, &code->global_code, frame ? frame->scope : NULL, 222 frame ? frame->this_obj : NULL, NULL, frame ? frame->variable_obj : ctx->global, 0, NULL, r); 223 release_bytecode(code); 224 return hres; 225 } 226 227 static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 228 jsval_t *r) 229 { 230 BOOL ret = TRUE; 231 double n; 232 HRESULT hres; 233 234 TRACE("\n"); 235 236 if(argc) { 237 hres = to_number(ctx, argv[0], &n); 238 if(FAILED(hres)) 239 return hres; 240 241 if(!isnan(n)) 242 ret = FALSE; 243 } 244 245 if(r) 246 *r = jsval_bool(ret); 247 return S_OK; 248 } 249 250 static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 251 jsval_t *r) 252 { 253 BOOL ret = FALSE; 254 HRESULT hres; 255 256 TRACE("\n"); 257 258 if(argc) { 259 double n; 260 261 hres = to_number(ctx, argv[0], &n); 262 if(FAILED(hres)) 263 return hres; 264 265 ret = is_finite(n); 266 } 267 268 if(r) 269 *r = jsval_bool(ret); 270 return S_OK; 271 } 272 273 static INT char_to_int(WCHAR c) 274 { 275 if('0' <= c && c <= '9') 276 return c - '0'; 277 if('a' <= c && c <= 'z') 278 return c - 'a' + 10; 279 if('A' <= c && c <= 'Z') 280 return c - 'A' + 10; 281 return 100; 282 } 283 284 static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 285 jsval_t *r) 286 { 287 BOOL neg = FALSE, empty = TRUE; 288 const WCHAR *ptr; 289 DOUBLE ret = 0.0; 290 INT radix=0, i; 291 jsstr_t *str; 292 HRESULT hres; 293 294 if(!argc) { 295 if(r) 296 *r = jsval_number(NAN); 297 return S_OK; 298 } 299 300 if(argc >= 2) { 301 hres = to_int32(ctx, argv[1], &radix); 302 if(FAILED(hres)) 303 return hres; 304 305 if(radix && (radix < 2 || radix > 36)) { 306 WARN("radix %d out of range\n", radix); 307 if(r) 308 *r = jsval_number(NAN); 309 return S_OK; 310 } 311 } 312 313 hres = to_flat_string(ctx, argv[0], &str, &ptr); 314 if(FAILED(hres)) 315 return hres; 316 317 while(iswspace(*ptr)) 318 ptr++; 319 320 switch(*ptr) { 321 case '+': 322 ptr++; 323 break; 324 case '-': 325 neg = TRUE; 326 ptr++; 327 break; 328 } 329 330 if(!radix) { 331 if(*ptr == '0') { 332 if(ptr[1] == 'x' || ptr[1] == 'X') { 333 radix = 16; 334 ptr += 2; 335 }else { 336 radix = 8; 337 ptr++; 338 empty = FALSE; 339 } 340 }else { 341 radix = 10; 342 } 343 }else if(radix == 16 && *ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) { 344 ptr += 2; 345 } 346 347 i = char_to_int(*ptr++); 348 if(i < radix) { 349 do { 350 ret = ret*radix + i; 351 i = char_to_int(*ptr++); 352 }while(i < radix); 353 }else if(empty) { 354 ret = NAN; 355 } 356 357 jsstr_release(str); 358 359 if(neg) 360 ret = -ret; 361 362 if(r) 363 *r = jsval_number(ret); 364 return S_OK; 365 } 366 367 static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 368 jsval_t *r) 369 { 370 LONGLONG d = 0, hlp; 371 jsstr_t *val_str; 372 int exp = 0; 373 const WCHAR *str; 374 BOOL ret_nan = TRUE, positive = TRUE; 375 HRESULT hres; 376 377 if(!argc) { 378 if(r) 379 *r = jsval_number(NAN); 380 return S_OK; 381 } 382 383 hres = to_flat_string(ctx, argv[0], &val_str, &str); 384 if(FAILED(hres)) 385 return hres; 386 387 while(iswspace(*str)) str++; 388 389 if(*str == '+') 390 str++; 391 else if(*str == '-') { 392 positive = FALSE; 393 str++; 394 } 395 396 if(iswdigit(*str)) 397 ret_nan = FALSE; 398 399 while(iswdigit(*str)) { 400 hlp = d*10 + *(str++) - '0'; 401 if(d>MAXLONGLONG/10 || hlp<0) { 402 exp++; 403 break; 404 } 405 else 406 d = hlp; 407 } 408 while(iswdigit(*str)) { 409 exp++; 410 str++; 411 } 412 413 if(*str == '.') str++; 414 415 if(iswdigit(*str)) 416 ret_nan = FALSE; 417 418 while(iswdigit(*str)) { 419 hlp = d*10 + *(str++) - '0'; 420 if(d>MAXLONGLONG/10 || hlp<0) 421 break; 422 423 d = hlp; 424 exp--; 425 } 426 while(iswdigit(*str)) 427 str++; 428 429 if(*str && !ret_nan && (*str=='e' || *str=='E')) { 430 int sign = 1, e = 0; 431 432 str++; 433 if(*str == '+') 434 str++; 435 else if(*str == '-') { 436 sign = -1; 437 str++; 438 } 439 440 while(iswdigit(*str)) { 441 if(e>INT_MAX/10 || (e = e*10 + *str++ - '0')<0) 442 e = INT_MAX; 443 } 444 e *= sign; 445 446 if(exp<0 && e<0 && exp+e>0) exp = INT_MIN; 447 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX; 448 else exp += e; 449 } 450 451 jsstr_release(val_str); 452 453 if(ret_nan) { 454 if(r) 455 *r = jsval_number(NAN); 456 return S_OK; 457 } 458 459 if(!positive) 460 d = -d; 461 if(r) 462 *r = jsval_number(exp>0 ? d*pow(10, exp) : d/pow(10, -exp)); 463 return S_OK; 464 } 465 466 static inline int hex_to_int(const WCHAR wch) { 467 if(towupper(wch)>='A' && towupper(wch)<='F') return towupper(wch)-'A'+10; 468 if(iswdigit(wch)) return wch-'0'; 469 return -1; 470 } 471 472 static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 473 jsval_t *r) 474 { 475 jsstr_t *ret_str, *str; 476 const WCHAR *ptr, *buf; 477 DWORD len = 0; 478 WCHAR *ret; 479 HRESULT hres; 480 481 TRACE("\n"); 482 483 if(!argc) { 484 if(r) 485 *r = jsval_string(jsstr_undefined()); 486 return S_OK; 487 } 488 489 hres = to_flat_string(ctx, argv[0], &str, &buf); 490 if(FAILED(hres)) 491 return hres; 492 493 for(ptr = buf; *ptr; ptr++) { 494 if(*ptr == '%') { 495 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) 496 ptr += 2; 497 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1 498 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1) 499 ptr += 5; 500 } 501 502 len++; 503 } 504 505 ret_str = jsstr_alloc_buf(len, &ret); 506 if(!ret_str) { 507 jsstr_release(str); 508 return E_OUTOFMEMORY; 509 } 510 511 len = 0; 512 for(ptr = buf; *ptr; ptr++) { 513 if(*ptr == '%') { 514 if(hex_to_int(*(ptr+1))!=-1 && hex_to_int(*(ptr+2))!=-1) { 515 ret[len] = (hex_to_int(*(ptr+1))<<4) + hex_to_int(*(ptr+2)); 516 ptr += 2; 517 } 518 else if(*(ptr+1)=='u' && hex_to_int(*(ptr+2))!=-1 && hex_to_int(*(ptr+3))!=-1 519 && hex_to_int(*(ptr+4))!=-1 && hex_to_int(*(ptr+5))!=-1) { 520 ret[len] = (hex_to_int(*(ptr+2))<<12) + (hex_to_int(*(ptr+3))<<8) 521 + (hex_to_int(*(ptr+4))<<4) + hex_to_int(*(ptr+5)); 522 ptr += 5; 523 } 524 else 525 ret[len] = *ptr; 526 } 527 else 528 ret[len] = *ptr; 529 530 len++; 531 } 532 533 jsstr_release(str); 534 535 if(r) 536 *r = jsval_string(ret_str); 537 else 538 jsstr_release(ret_str); 539 return S_OK; 540 } 541 542 static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 543 jsval_t *r) 544 { 545 FIXME("\n"); 546 return E_NOTIMPL; 547 } 548 549 static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 550 jsval_t *r) 551 { 552 static const WCHAR JScriptW[] = {'J','S','c','r','i','p','t',0}; 553 554 TRACE("\n"); 555 556 if(r) { 557 jsstr_t *ret; 558 559 ret = jsstr_alloc(JScriptW); 560 if(!ret) 561 return E_OUTOFMEMORY; 562 563 *r = jsval_string(ret); 564 } 565 566 return S_OK; 567 } 568 569 static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 570 jsval_t *r) 571 { 572 TRACE("\n"); 573 574 if(r) 575 *r = jsval_number(JSCRIPT_MAJOR_VERSION); 576 return S_OK; 577 } 578 579 static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 580 jsval_t *r) 581 { 582 TRACE("\n"); 583 584 if(r) 585 *r = jsval_number(JSCRIPT_MINOR_VERSION); 586 return S_OK; 587 } 588 589 static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 590 jsval_t *r) 591 { 592 TRACE("\n"); 593 594 if(r) 595 *r = jsval_number(JSCRIPT_BUILD_VERSION); 596 return S_OK; 597 } 598 599 static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 600 jsval_t *r) 601 { 602 static int once = 0; 603 if (!once++) 604 FIXME(": stub\n"); 605 return S_OK; 606 } 607 608 static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 609 jsval_t *r) 610 { 611 const WCHAR *ptr, *uri; 612 jsstr_t *str, *ret; 613 DWORD len = 0, i; 614 char buf[4]; 615 WCHAR *rptr; 616 HRESULT hres; 617 618 TRACE("\n"); 619 620 if(!argc) { 621 if(r) 622 *r = jsval_string(jsstr_undefined()); 623 return S_OK; 624 } 625 626 hres = to_flat_string(ctx, argv[0], &str, &uri); 627 if(FAILED(hres)) 628 return hres; 629 630 for(ptr = uri; *ptr; ptr++) { 631 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') { 632 len++; 633 }else { 634 i = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL)*3; 635 if(!i) { 636 jsstr_release(str); 637 return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL); 638 } 639 640 len += i; 641 } 642 } 643 644 ret = jsstr_alloc_buf(len, &rptr); 645 if(!ret) { 646 jsstr_release(str); 647 return E_OUTOFMEMORY; 648 } 649 650 for(ptr = uri; *ptr; ptr++) { 651 if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') { 652 *rptr++ = *ptr; 653 }else { 654 len = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL); 655 for(i=0; i<len; i++) { 656 *rptr++ = '%'; 657 *rptr++ = int_to_char((BYTE)buf[i] >> 4); 658 *rptr++ = int_to_char(buf[i] & 0x0f); 659 } 660 } 661 } 662 663 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret)); 664 jsstr_release(str); 665 666 if(r) 667 *r = jsval_string(ret); 668 else 669 jsstr_release(ret); 670 return S_OK; 671 } 672 673 static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 674 jsval_t *r) 675 { 676 const WCHAR *ptr, *uri; 677 jsstr_t *str, *ret_str; 678 unsigned len = 0; 679 int i, val, res; 680 WCHAR *ret; 681 char buf[4]; 682 WCHAR out; 683 HRESULT hres; 684 685 TRACE("\n"); 686 687 if(!argc) { 688 if(r) 689 *r = jsval_string(jsstr_undefined()); 690 return S_OK; 691 } 692 693 hres = to_flat_string(ctx, argv[0], &str, &uri); 694 if(FAILED(hres)) 695 return hres; 696 697 for(ptr = uri; *ptr; ptr++) { 698 if(*ptr != '%') { 699 len++; 700 }else { 701 res = 0; 702 for(i=0; i<4; i++) { 703 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1) 704 break; 705 val += hex_to_int(ptr[i*3+1])<<4; 706 buf[i] = val; 707 708 res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, &out, 1); 709 if(res) 710 break; 711 } 712 713 if(!res) { 714 jsstr_release(str); 715 return throw_uri_error(ctx, JS_E_INVALID_URI_CODING, NULL); 716 } 717 718 ptr += i*3+2; 719 len++; 720 } 721 } 722 723 ret_str = jsstr_alloc_buf(len, &ret); 724 if(!ret_str) { 725 jsstr_release(str); 726 return E_OUTOFMEMORY; 727 } 728 729 for(ptr = uri; *ptr; ptr++) { 730 if(*ptr != '%') { 731 *ret++ = *ptr; 732 }else { 733 for(i=0; i<4; i++) { 734 if(ptr[i*3]!='%' || hex_to_int(ptr[i*3+1])==-1 || (val=hex_to_int(ptr[i*3+2]))==-1) 735 break; 736 val += hex_to_int(ptr[i*3+1])<<4; 737 buf[i] = val; 738 739 res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, ret, 1); 740 if(res) 741 break; 742 } 743 744 ptr += i*3+2; 745 ret++; 746 } 747 } 748 749 TRACE("%s -> %s\n", debugstr_jsstr(str), debugstr_jsstr(ret_str)); 750 jsstr_release(str); 751 752 if(r) 753 *r = jsval_string(ret_str); 754 else 755 jsstr_release(ret_str); 756 return S_OK; 757 } 758 759 static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 760 jsval_t *r) 761 { 762 jsstr_t *str, *ret_str; 763 char buf[4]; 764 const WCHAR *ptr, *uri; 765 DWORD len = 0, size, i; 766 WCHAR *ret; 767 HRESULT hres; 768 769 TRACE("\n"); 770 771 if(!argc) { 772 if(r) 773 *r = jsval_string(jsstr_undefined()); 774 return S_OK; 775 } 776 777 hres = to_flat_string(ctx, argv[0], &str, &uri); 778 if(FAILED(hres)) 779 return hres; 780 781 for(ptr = uri; *ptr; ptr++) { 782 if(is_uri_unescaped(*ptr)) 783 len++; 784 else { 785 size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL); 786 if(!size) { 787 jsstr_release(str); 788 return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL); 789 } 790 len += size*3; 791 } 792 } 793 794 ret_str = jsstr_alloc_buf(len, &ret); 795 if(!ret_str) { 796 jsstr_release(str); 797 return E_OUTOFMEMORY; 798 } 799 800 for(ptr = uri; *ptr; ptr++) { 801 if(is_uri_unescaped(*ptr)) { 802 *ret++ = *ptr; 803 }else { 804 size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL); 805 for(i=0; i<size; i++) { 806 *ret++ = '%'; 807 *ret++ = int_to_char((BYTE)buf[i] >> 4); 808 *ret++ = int_to_char(buf[i] & 0x0f); 809 } 810 } 811 } 812 813 jsstr_release(str); 814 815 if(r) 816 *r = jsval_string(ret_str); 817 else 818 jsstr_release(ret_str); 819 return S_OK; 820 } 821 822 /* ECMA-262 3rd Edition 15.1.3.2 */ 823 static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 824 jsval_t *r) 825 { 826 const WCHAR *ptr, *uri; 827 jsstr_t *str, *ret; 828 WCHAR *out_ptr; 829 DWORD len = 0; 830 HRESULT hres; 831 832 TRACE("\n"); 833 834 if(!argc) { 835 if(r) 836 *r = jsval_string(jsstr_undefined()); 837 return S_OK; 838 } 839 840 hres = to_flat_string(ctx, argv[0], &str, &uri); 841 if(FAILED(hres)) 842 return hres; 843 844 ptr = uri; 845 while(*ptr) { 846 if(*ptr == '%') { 847 char octets[4]; 848 unsigned char mask = 0x80; 849 int i, size, num_bytes = 0; 850 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) { 851 FIXME("Throw URIError: Invalid hex sequence\n"); 852 jsstr_release(str); 853 return E_FAIL; 854 } 855 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2)); 856 ptr += 3; 857 while(octets[0] & mask) { 858 mask = mask >> 1; 859 ++num_bytes; 860 } 861 if(num_bytes == 1 || num_bytes > 4) { 862 FIXME("Throw URIError: Invalid initial UTF character\n"); 863 jsstr_release(str); 864 return E_FAIL; 865 } 866 for(i = 1; i < num_bytes; ++i) { 867 if(*ptr != '%'){ 868 FIXME("Throw URIError: Incomplete UTF sequence\n"); 869 jsstr_release(str); 870 return E_FAIL; 871 } 872 if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) { 873 FIXME("Throw URIError: Invalid hex sequence\n"); 874 jsstr_release(str); 875 return E_FAIL; 876 } 877 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2)); 878 ptr += 3; 879 } 880 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets, 881 num_bytes ? num_bytes : 1, NULL, 0); 882 if(size == 0) { 883 FIXME("Throw URIError: Invalid UTF sequence\n"); 884 jsstr_release(str); 885 return E_FAIL; 886 } 887 len += size; 888 }else { 889 ++ptr; 890 ++len; 891 } 892 } 893 894 ret = jsstr_alloc_buf(len, &out_ptr); 895 if(!ret) { 896 jsstr_release(str); 897 return E_OUTOFMEMORY; 898 } 899 900 ptr = uri; 901 while(*ptr) { 902 if(*ptr == '%') { 903 char octets[4]; 904 unsigned char mask = 0x80; 905 int i, size, num_bytes = 0; 906 octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2)); 907 ptr += 3; 908 while(octets[0] & mask) { 909 mask = mask >> 1; 910 ++num_bytes; 911 } 912 for(i = 1; i < num_bytes; ++i) { 913 octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2)); 914 ptr += 3; 915 } 916 size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets, 917 num_bytes ? num_bytes : 1, out_ptr, len); 918 len -= size; 919 out_ptr += size; 920 }else { 921 *out_ptr++ = *ptr++; 922 --len; 923 } 924 } 925 926 jsstr_release(str); 927 928 if(r) 929 *r = jsval_string(ret); 930 else 931 jsstr_release(ret); 932 return S_OK; 933 } 934 935 static const builtin_prop_t JSGlobal_props[] = { 936 {CollectGarbageW, JSGlobal_CollectGarbage, PROPF_METHOD}, 937 {_GetObjectW, JSGlobal_GetObject, PROPF_METHOD|2}, 938 {ScriptEngineW, JSGlobal_ScriptEngine, PROPF_METHOD}, 939 {ScriptEngineBuildVersionW, JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD}, 940 {ScriptEngineMajorVersionW, JSGlobal_ScriptEngineMajorVersion, PROPF_METHOD}, 941 {ScriptEngineMinorVersionW, JSGlobal_ScriptEngineMinorVersion, PROPF_METHOD}, 942 {decodeURIW, JSGlobal_decodeURI, PROPF_METHOD|1}, 943 {decodeURIComponentW, JSGlobal_decodeURIComponent, PROPF_METHOD|1}, 944 {encodeURIW, JSGlobal_encodeURI, PROPF_METHOD|1}, 945 {encodeURIComponentW, JSGlobal_encodeURIComponent, PROPF_METHOD|1}, 946 {escapeW, JSGlobal_escape, PROPF_METHOD|1}, 947 {evalW, JSGlobal_eval, PROPF_METHOD|1}, 948 {isFiniteW, JSGlobal_isFinite, PROPF_METHOD|1}, 949 {isNaNW, JSGlobal_isNaN, PROPF_METHOD|1}, 950 {parseFloatW, JSGlobal_parseFloat, PROPF_METHOD|1}, 951 {parseIntW, JSGlobal_parseInt, PROPF_METHOD|2}, 952 {unescapeW, JSGlobal_unescape, PROPF_METHOD|1} 953 }; 954 955 static const builtin_info_t JSGlobal_info = { 956 JSCLASS_GLOBAL, 957 {NULL, NULL, 0}, 958 ARRAY_SIZE(JSGlobal_props), 959 JSGlobal_props, 960 NULL, 961 NULL 962 }; 963 964 static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) 965 { 966 HRESULT hres; 967 968 hres = init_function_constr(ctx, object_prototype); 969 if(FAILED(hres)) 970 return hres; 971 972 hres = jsdisp_define_data_property(ctx->global, FunctionW, PROPF_WRITABLE, 973 jsval_obj(ctx->function_constr)); 974 if(FAILED(hres)) 975 return hres; 976 977 hres = create_object_constr(ctx, object_prototype, &ctx->object_constr); 978 if(FAILED(hres)) 979 return hres; 980 981 hres = jsdisp_define_data_property(ctx->global, ObjectW, PROPF_WRITABLE, 982 jsval_obj(ctx->object_constr)); 983 if(FAILED(hres)) 984 return hres; 985 986 hres = create_array_constr(ctx, object_prototype, &ctx->array_constr); 987 if(FAILED(hres)) 988 return hres; 989 990 hres = jsdisp_define_data_property(ctx->global, ArrayW, PROPF_WRITABLE, 991 jsval_obj(ctx->array_constr)); 992 if(FAILED(hres)) 993 return hres; 994 995 hres = create_bool_constr(ctx, object_prototype, &ctx->bool_constr); 996 if(FAILED(hres)) 997 return hres; 998 999 hres = jsdisp_define_data_property(ctx->global, BooleanW, PROPF_WRITABLE, 1000 jsval_obj(ctx->bool_constr)); 1001 if(FAILED(hres)) 1002 return hres; 1003 1004 hres = create_date_constr(ctx, object_prototype, &ctx->date_constr); 1005 if(FAILED(hres)) 1006 return hres; 1007 1008 hres = jsdisp_define_data_property(ctx->global, DateW, PROPF_WRITABLE, 1009 jsval_obj(ctx->date_constr)); 1010 if(FAILED(hres)) 1011 return hres; 1012 1013 hres = create_enumerator_constr(ctx, object_prototype, &ctx->enumerator_constr); 1014 if(FAILED(hres)) 1015 return hres; 1016 1017 hres = jsdisp_define_data_property(ctx->global, EnumeratorW, PROPF_WRITABLE, 1018 jsval_obj(ctx->enumerator_constr)); 1019 if(FAILED(hres)) 1020 return hres; 1021 1022 hres = init_error_constr(ctx, object_prototype); 1023 if(FAILED(hres)) 1024 return hres; 1025 1026 hres = jsdisp_define_data_property(ctx->global, ErrorW, PROPF_WRITABLE, 1027 jsval_obj(ctx->error_constr)); 1028 if(FAILED(hres)) 1029 return hres; 1030 1031 hres = jsdisp_define_data_property(ctx->global, EvalErrorW, PROPF_WRITABLE, 1032 jsval_obj(ctx->eval_error_constr)); 1033 if(FAILED(hres)) 1034 return hres; 1035 1036 hres = jsdisp_define_data_property(ctx->global, RangeErrorW, PROPF_WRITABLE, 1037 jsval_obj(ctx->range_error_constr)); 1038 if(FAILED(hres)) 1039 return hres; 1040 1041 hres = jsdisp_define_data_property(ctx->global, ReferenceErrorW, PROPF_WRITABLE, 1042 jsval_obj(ctx->reference_error_constr)); 1043 if(FAILED(hres)) 1044 return hres; 1045 1046 hres = jsdisp_define_data_property(ctx->global, RegExpErrorW, PROPF_WRITABLE, 1047 jsval_obj(ctx->regexp_error_constr)); 1048 if(FAILED(hres)) 1049 return hres; 1050 1051 hres = jsdisp_define_data_property(ctx->global, SyntaxErrorW, PROPF_WRITABLE, 1052 jsval_obj(ctx->syntax_error_constr)); 1053 if(FAILED(hres)) 1054 return hres; 1055 1056 hres = jsdisp_define_data_property(ctx->global, TypeErrorW, PROPF_WRITABLE, 1057 jsval_obj(ctx->type_error_constr)); 1058 if(FAILED(hres)) 1059 return hres; 1060 1061 hres = jsdisp_define_data_property(ctx->global, URIErrorW, PROPF_WRITABLE, 1062 jsval_obj(ctx->uri_error_constr)); 1063 if(FAILED(hres)) 1064 return hres; 1065 1066 hres = create_number_constr(ctx, object_prototype, &ctx->number_constr); 1067 if(FAILED(hres)) 1068 return hres; 1069 1070 hres = jsdisp_define_data_property(ctx->global, NumberW, PROPF_WRITABLE, 1071 jsval_obj(ctx->number_constr)); 1072 if(FAILED(hres)) 1073 return hres; 1074 1075 hres = create_regexp_constr(ctx, object_prototype, &ctx->regexp_constr); 1076 if(FAILED(hres)) 1077 return hres; 1078 1079 hres = jsdisp_define_data_property(ctx->global, RegExpW, PROPF_WRITABLE, 1080 jsval_obj(ctx->regexp_constr)); 1081 if(FAILED(hres)) 1082 return hres; 1083 1084 hres = create_string_constr(ctx, object_prototype, &ctx->string_constr); 1085 if(FAILED(hres)) 1086 return hres; 1087 1088 hres = jsdisp_define_data_property(ctx->global, StringW, PROPF_WRITABLE, 1089 jsval_obj(ctx->string_constr)); 1090 if(FAILED(hres)) 1091 return hres; 1092 1093 hres = create_vbarray_constr(ctx, object_prototype, &ctx->vbarray_constr); 1094 if(FAILED(hres)) 1095 return hres; 1096 1097 hres = jsdisp_define_data_property(ctx->global, VBArrayW, PROPF_WRITABLE, 1098 jsval_obj(ctx->vbarray_constr)); 1099 if(FAILED(hres)) 1100 return hres; 1101 1102 return S_OK; 1103 } 1104 1105 HRESULT init_global(script_ctx_t *ctx) 1106 { 1107 unsigned const_flags = ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? 0 : PROPF_WRITABLE; 1108 jsdisp_t *math, *object_prototype, *constr; 1109 HRESULT hres; 1110 1111 if(ctx->global) 1112 return S_OK; 1113 1114 hres = create_dispex(ctx, &JSGlobal_info, NULL, &ctx->global); 1115 if(FAILED(hres)) 1116 return hres; 1117 1118 hres = create_object_prototype(ctx, &object_prototype); 1119 if(FAILED(hres)) 1120 return hres; 1121 1122 hres = init_constructors(ctx, object_prototype); 1123 jsdisp_release(object_prototype); 1124 if(FAILED(hres)) 1125 return hres; 1126 1127 hres = create_math(ctx, &math); 1128 if(FAILED(hres)) 1129 return hres; 1130 1131 hres = jsdisp_define_data_property(ctx->global, MathW, PROPF_WRITABLE, jsval_obj(math)); 1132 jsdisp_release(math); 1133 if(FAILED(hres)) 1134 return hres; 1135 1136 if(ctx->version >= 2) { 1137 jsdisp_t *json; 1138 1139 hres = create_json(ctx, &json); 1140 if(FAILED(hres)) 1141 return hres; 1142 1143 hres = jsdisp_define_data_property(ctx->global, JSONW, PROPF_WRITABLE, jsval_obj(json)); 1144 jsdisp_release(json); 1145 if(FAILED(hres)) 1146 return hres; 1147 } 1148 1149 hres = create_activex_constr(ctx, &constr); 1150 if(FAILED(hres)) 1151 return hres; 1152 1153 hres = jsdisp_define_data_property(ctx->global, ActiveXObjectW, PROPF_WRITABLE, 1154 jsval_obj(constr)); 1155 jsdisp_release(constr); 1156 if(FAILED(hres)) 1157 return hres; 1158 1159 hres = jsdisp_define_data_property(ctx->global, undefinedW, const_flags, jsval_undefined()); 1160 if(FAILED(hres)) 1161 return hres; 1162 1163 hres = jsdisp_define_data_property(ctx->global, NaNW, const_flags, jsval_number(NAN)); 1164 if(FAILED(hres)) 1165 return hres; 1166 1167 hres = jsdisp_define_data_property(ctx->global, InfinityW, const_flags, jsval_number(INFINITY)); 1168 return hres; 1169 } 1170