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