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 "config.h" 20 #include "wine/port.h" 21 22 #include <math.h> 23 #include <assert.h> 24 25 #include "jscript.h" 26 #include "engine.h" 27 28 #include "wine/debug.h" 29 30 WINE_DEFAULT_DEBUG_CHANNEL(jscript); 31 WINE_DECLARE_DEBUG_CHANNEL(heap); 32 33 const char *debugstr_jsval(const jsval_t v) 34 { 35 switch(jsval_type(v)) { 36 case JSV_UNDEFINED: 37 return "undefined"; 38 case JSV_NULL: 39 return "null"; 40 case JSV_OBJECT: 41 return wine_dbg_sprintf("obj(%p)", get_object(v)); 42 case JSV_STRING: 43 return wine_dbg_sprintf("str(%s)", debugstr_jsstr(get_string(v))); 44 case JSV_NUMBER: 45 return wine_dbg_sprintf("%lf", get_number(v)); 46 case JSV_BOOL: 47 return get_bool(v) ? "true" : "false"; 48 case JSV_VARIANT: 49 return debugstr_variant(get_variant(v)); 50 } 51 52 assert(0); 53 return NULL; 54 } 55 56 BOOL is_finite(double n) 57 { 58 return !isnan(n) && !isinf(n); 59 } 60 61 #define MIN_BLOCK_SIZE 128 62 #define ARENA_FREE_FILLER 0xaa 63 64 static inline DWORD block_size(DWORD block) 65 { 66 return MIN_BLOCK_SIZE << block; 67 } 68 69 void heap_pool_init(heap_pool_t *heap) 70 { 71 memset(heap, 0, sizeof(*heap)); 72 list_init(&heap->custom_blocks); 73 } 74 75 void *heap_pool_alloc(heap_pool_t *heap, DWORD size) 76 { 77 struct list *list; 78 void *tmp; 79 80 if(!heap->block_cnt) { 81 if(!heap->blocks) { 82 heap->blocks = heap_alloc(sizeof(void*)); 83 if(!heap->blocks) 84 return NULL; 85 } 86 87 tmp = heap_alloc(block_size(0)); 88 if(!tmp) 89 return NULL; 90 91 heap->blocks[0] = tmp; 92 heap->block_cnt = 1; 93 } 94 95 if(heap->offset + size <= block_size(heap->last_block)) { 96 tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset; 97 heap->offset += size; 98 return tmp; 99 } 100 101 if(size <= block_size(heap->last_block+1)) { 102 if(heap->last_block+1 == heap->block_cnt) { 103 tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*)); 104 if(!tmp) 105 return NULL; 106 107 heap->blocks = tmp; 108 heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt)); 109 if(!heap->blocks[heap->block_cnt]) 110 return NULL; 111 112 heap->block_cnt++; 113 } 114 115 heap->last_block++; 116 heap->offset = size; 117 return heap->blocks[heap->last_block]; 118 } 119 120 list = heap_alloc(size + sizeof(struct list)); 121 if(!list) 122 return NULL; 123 124 list_add_head(&heap->custom_blocks, list); 125 return list+1; 126 } 127 128 void *heap_pool_grow(heap_pool_t *heap, void *mem, DWORD size, DWORD inc) 129 { 130 void *ret; 131 132 if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size 133 && heap->offset+inc < block_size(heap->last_block)) { 134 heap->offset += inc; 135 return mem; 136 } 137 138 ret = heap_pool_alloc(heap, size+inc); 139 if(ret) /* FIXME: avoid copying for custom blocks */ 140 memcpy(ret, mem, size); 141 return ret; 142 } 143 144 void heap_pool_clear(heap_pool_t *heap) 145 { 146 struct list *tmp; 147 148 if(!heap) 149 return; 150 151 while((tmp = list_head(&heap->custom_blocks))) { 152 list_remove(tmp); 153 heap_free(tmp); 154 } 155 156 if(WARN_ON(heap)) { 157 DWORD i; 158 159 for(i=0; i < heap->block_cnt; i++) 160 memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i)); 161 } 162 163 heap->last_block = heap->offset = 0; 164 heap->mark = FALSE; 165 } 166 167 void heap_pool_free(heap_pool_t *heap) 168 { 169 DWORD i; 170 171 heap_pool_clear(heap); 172 173 for(i=0; i < heap->block_cnt; i++) 174 heap_free(heap->blocks[i]); 175 heap_free(heap->blocks); 176 177 heap_pool_init(heap); 178 } 179 180 heap_pool_t *heap_pool_mark(heap_pool_t *heap) 181 { 182 if(heap->mark) 183 return NULL; 184 185 heap->mark = TRUE; 186 return heap; 187 } 188 189 void jsval_release(jsval_t val) 190 { 191 switch(jsval_type(val)) { 192 case JSV_OBJECT: 193 if(get_object(val)) 194 IDispatch_Release(get_object(val)); 195 break; 196 case JSV_STRING: 197 jsstr_release(get_string(val)); 198 break; 199 case JSV_VARIANT: 200 VariantClear(get_variant(val)); 201 heap_free(get_variant(val)); 202 break; 203 default: 204 break; 205 } 206 } 207 208 static HRESULT jsval_variant(jsval_t *val, VARIANT *var) 209 { 210 VARIANT *v; 211 HRESULT hres; 212 213 __JSVAL_TYPE(*val) = JSV_VARIANT; 214 __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT)); 215 if(!v) { 216 *val = jsval_undefined(); 217 return E_OUTOFMEMORY; 218 } 219 220 V_VT(v) = VT_EMPTY; 221 hres = VariantCopy(v, var); 222 if(FAILED(hres)) { 223 *val = jsval_undefined(); 224 heap_free(v); 225 } 226 return hres; 227 } 228 229 HRESULT jsval_copy(jsval_t v, jsval_t *r) 230 { 231 switch(jsval_type(v)) { 232 case JSV_UNDEFINED: 233 case JSV_NULL: 234 case JSV_NUMBER: 235 case JSV_BOOL: 236 *r = v; 237 return S_OK; 238 case JSV_OBJECT: 239 if(get_object(v)) 240 IDispatch_AddRef(get_object(v)); 241 *r = v; 242 return S_OK; 243 case JSV_STRING: { 244 jsstr_addref(get_string(v)); 245 *r = v; 246 return S_OK; 247 } 248 case JSV_VARIANT: 249 return jsval_variant(r, get_variant(v)); 250 } 251 252 assert(0); 253 return E_FAIL; 254 } 255 256 HRESULT variant_to_jsval(VARIANT *var, jsval_t *r) 257 { 258 if(V_VT(var) == (VT_VARIANT|VT_BYREF)) 259 var = V_VARIANTREF(var); 260 261 switch(V_VT(var)) { 262 case VT_EMPTY: 263 *r = jsval_undefined(); 264 return S_OK; 265 case VT_NULL: 266 *r = jsval_null(); 267 return S_OK; 268 case VT_BOOL: 269 *r = jsval_bool(V_BOOL(var)); 270 return S_OK; 271 case VT_I4: 272 *r = jsval_number(V_I4(var)); 273 return S_OK; 274 case VT_R8: 275 *r = jsval_number(V_R8(var)); 276 return S_OK; 277 case VT_BSTR: { 278 jsstr_t *str; 279 280 if(V_BSTR(var)) { 281 str = jsstr_alloc_len(V_BSTR(var), SysStringLen(V_BSTR(var))); 282 if(!str) 283 return E_OUTOFMEMORY; 284 }else { 285 str = jsstr_null_bstr(); 286 } 287 288 *r = jsval_string(str); 289 return S_OK; 290 } 291 case VT_DISPATCH: { 292 if(V_DISPATCH(var)) 293 IDispatch_AddRef(V_DISPATCH(var)); 294 *r = jsval_disp(V_DISPATCH(var)); 295 return S_OK; 296 } 297 case VT_I2: 298 *r = jsval_number(V_I2(var)); 299 return S_OK; 300 case VT_UI2: 301 *r = jsval_number(V_UI2(var)); 302 return S_OK; 303 case VT_INT: 304 *r = jsval_number(V_INT(var)); 305 return S_OK; 306 case VT_UI4: 307 *r = jsval_number(V_UI4(var)); 308 return S_OK; 309 case VT_UI8: 310 /* 311 * Native doesn't support VT_UI8 here, but it's needed for IE9+ APIs 312 * (native IE9 doesn't use jscript.dll for JavaScript). 313 */ 314 *r = jsval_number(V_UI8(var)); 315 return S_OK; 316 case VT_R4: 317 *r = jsval_number(V_R4(var)); 318 return S_OK; 319 case VT_UNKNOWN: 320 if(V_UNKNOWN(var)) { 321 IDispatch *disp; 322 HRESULT hres; 323 324 hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp); 325 if(SUCCEEDED(hres)) { 326 *r = jsval_disp(disp); 327 return S_OK; 328 } 329 }else { 330 *r = jsval_disp(NULL); 331 return S_OK; 332 } 333 /* fall through */ 334 default: 335 return jsval_variant(r, var); 336 } 337 } 338 339 HRESULT jsval_to_variant(jsval_t val, VARIANT *retv) 340 { 341 switch(jsval_type(val)) { 342 case JSV_UNDEFINED: 343 V_VT(retv) = VT_EMPTY; 344 return S_OK; 345 case JSV_NULL: 346 V_VT(retv) = VT_NULL; 347 return S_OK; 348 case JSV_OBJECT: 349 V_VT(retv) = VT_DISPATCH; 350 if(get_object(val)) 351 IDispatch_AddRef(get_object(val)); 352 V_DISPATCH(retv) = get_object(val); 353 return S_OK; 354 case JSV_STRING: { 355 jsstr_t *str = get_string(val); 356 357 V_VT(retv) = VT_BSTR; 358 if(is_null_bstr(str)) { 359 V_BSTR(retv) = NULL; 360 }else { 361 V_BSTR(retv) = SysAllocStringLen(NULL, jsstr_length(str)); 362 if(V_BSTR(retv)) 363 jsstr_flush(str, V_BSTR(retv)); 364 else 365 return E_OUTOFMEMORY; 366 } 367 return S_OK; 368 } 369 case JSV_NUMBER: { 370 double n = get_number(val); 371 372 if(is_int32(n)) { 373 V_VT(retv) = VT_I4; 374 V_I4(retv) = n; 375 }else { 376 V_VT(retv) = VT_R8; 377 V_R8(retv) = n; 378 } 379 380 return S_OK; 381 } 382 case JSV_BOOL: 383 V_VT(retv) = VT_BOOL; 384 V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE; 385 return S_OK; 386 case JSV_VARIANT: 387 V_VT(retv) = VT_EMPTY; 388 return VariantCopy(retv, get_variant(val)); 389 } 390 391 assert(0); 392 return E_FAIL; 393 } 394 395 /* ECMA-262 3rd Edition 9.1 */ 396 HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) 397 { 398 if(is_object_instance(val)) { 399 jsdisp_t *jsdisp; 400 jsval_t prim; 401 DISPID id; 402 HRESULT hres; 403 404 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; 405 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0}; 406 407 if(!get_object(val)) { 408 *ret = jsval_null(); 409 return S_OK; 410 } 411 412 jsdisp = iface_to_jsdisp(get_object(val)); 413 if(!jsdisp) 414 return disp_propget(ctx, get_object(val), DISPID_VALUE, ret); 415 416 if(hint == NO_HINT) 417 hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER; 418 419 /* Native implementation doesn't throw TypeErrors, returns strange values */ 420 421 hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id); 422 if(SUCCEEDED(hres)) { 423 hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim); 424 if(FAILED(hres)) { 425 WARN("call error - forwarding exception\n"); 426 jsdisp_release(jsdisp); 427 return hres; 428 }else if(!is_object_instance(prim)) { 429 jsdisp_release(jsdisp); 430 *ret = prim; 431 return S_OK; 432 }else { 433 IDispatch_Release(get_object(prim)); 434 } 435 } 436 437 hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id); 438 if(SUCCEEDED(hres)) { 439 hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim); 440 if(FAILED(hres)) { 441 WARN("call error - forwarding exception\n"); 442 jsdisp_release(jsdisp); 443 return hres; 444 }else if(!is_object_instance(prim)) { 445 jsdisp_release(jsdisp); 446 *ret = prim; 447 return S_OK; 448 }else { 449 IDispatch_Release(get_object(prim)); 450 } 451 } 452 453 jsdisp_release(jsdisp); 454 455 WARN("failed\n"); 456 return throw_type_error(ctx, JS_E_TO_PRIMITIVE, NULL); 457 } 458 459 return jsval_copy(val, ret); 460 461 } 462 463 /* ECMA-262 3rd Edition 9.2 */ 464 HRESULT to_boolean(jsval_t val, BOOL *ret) 465 { 466 switch(jsval_type(val)) { 467 case JSV_UNDEFINED: 468 case JSV_NULL: 469 *ret = FALSE; 470 return S_OK; 471 case JSV_OBJECT: 472 *ret = get_object(val) != NULL; 473 return S_OK; 474 case JSV_STRING: 475 *ret = jsstr_length(get_string(val)) != 0; 476 return S_OK; 477 case JSV_NUMBER: 478 *ret = !isnan(get_number(val)) && get_number(val); 479 return S_OK; 480 case JSV_BOOL: 481 *ret = get_bool(val); 482 return S_OK; 483 case JSV_VARIANT: 484 FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val))); 485 return E_NOTIMPL; 486 } 487 488 assert(0); 489 return E_FAIL; 490 } 491 492 static int hex_to_int(WCHAR c) 493 { 494 if('0' <= c && c <= '9') 495 return c-'0'; 496 497 if('a' <= c && c <= 'f') 498 return c-'a'+10; 499 500 if('A' <= c && c <= 'F') 501 return c-'A'+10; 502 503 return -1; 504 } 505 506 /* ECMA-262 3rd Edition 9.3.1 */ 507 static HRESULT str_to_number(jsstr_t *str, double *ret) 508 { 509 const WCHAR *ptr; 510 BOOL neg = FALSE; 511 DOUBLE d = 0.0; 512 513 static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'}; 514 515 ptr = jsstr_flatten(str); 516 if(!ptr) 517 return E_OUTOFMEMORY; 518 519 while(isspaceW(*ptr)) 520 ptr++; 521 522 if(*ptr == '-') { 523 neg = TRUE; 524 ptr++; 525 }else if(*ptr == '+') { 526 ptr++; 527 } 528 529 if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) { 530 ptr += sizeof(infinityW)/sizeof(WCHAR); 531 while(*ptr && isspaceW(*ptr)) 532 ptr++; 533 534 if(*ptr) 535 *ret = NAN; 536 else 537 *ret = neg ? -INFINITY : INFINITY; 538 return S_OK; 539 } 540 541 if(*ptr == '0' && ptr[1] == 'x') { 542 DWORD l = 0; 543 544 ptr += 2; 545 while((l = hex_to_int(*ptr)) != -1) { 546 d = d*16 + l; 547 ptr++; 548 } 549 550 *ret = d; 551 return S_OK; 552 } 553 554 while(isdigitW(*ptr)) 555 d = d*10 + (*ptr++ - '0'); 556 557 if(*ptr == 'e' || *ptr == 'E') { 558 BOOL eneg = FALSE; 559 LONG l = 0; 560 561 ptr++; 562 if(*ptr == '-') { 563 ptr++; 564 eneg = TRUE; 565 }else if(*ptr == '+') { 566 ptr++; 567 } 568 569 while(isdigitW(*ptr)) 570 l = l*10 + (*ptr++ - '0'); 571 if(eneg) 572 l = -l; 573 574 d *= pow(10, l); 575 }else if(*ptr == '.') { 576 DOUBLE dec = 0.1; 577 578 ptr++; 579 while(isdigitW(*ptr)) { 580 d += dec * (*ptr++ - '0'); 581 dec *= 0.1; 582 } 583 } 584 585 while(isspaceW(*ptr)) 586 ptr++; 587 588 if(*ptr) { 589 *ret = NAN; 590 return S_OK; 591 } 592 593 if(neg) 594 d = -d; 595 596 *ret = d; 597 return S_OK; 598 } 599 600 /* ECMA-262 3rd Edition 9.3 */ 601 HRESULT to_number(script_ctx_t *ctx, jsval_t val, double *ret) 602 { 603 switch(jsval_type(val)) { 604 case JSV_UNDEFINED: 605 *ret = NAN; 606 return S_OK; 607 case JSV_NULL: 608 *ret = 0; 609 return S_OK; 610 case JSV_NUMBER: 611 *ret = get_number(val); 612 return S_OK; 613 case JSV_STRING: 614 return str_to_number(get_string(val), ret); 615 case JSV_OBJECT: { 616 jsval_t prim; 617 HRESULT hres; 618 619 hres = to_primitive(ctx, val, &prim, HINT_NUMBER); 620 if(FAILED(hres)) 621 return hres; 622 623 hres = to_number(ctx, prim, ret); 624 jsval_release(prim); 625 return hres; 626 } 627 case JSV_BOOL: 628 *ret = get_bool(val) ? 1 : 0; 629 return S_OK; 630 case JSV_VARIANT: 631 FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val))); 632 return E_NOTIMPL; 633 }; 634 635 assert(0); 636 return E_FAIL; 637 } 638 639 /* ECMA-262 3rd Edition 9.4 */ 640 HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret) 641 { 642 double n; 643 HRESULT hres; 644 645 hres = to_number(ctx, v, &n); 646 if(FAILED(hres)) 647 return hres; 648 649 if(isnan(n)) 650 *ret = 0; 651 else 652 *ret = n >= 0.0 ? floor(n) : -floor(-n); 653 return S_OK; 654 } 655 656 /* ECMA-262 3rd Edition 9.5 */ 657 HRESULT to_int32(script_ctx_t *ctx, jsval_t v, INT *ret) 658 { 659 double n; 660 HRESULT hres; 661 662 hres = to_number(ctx, v, &n); 663 if(FAILED(hres)) 664 return hres; 665 666 *ret = is_finite(n) ? n : 0; 667 return S_OK; 668 } 669 670 /* ECMA-262 3rd Edition 9.6 */ 671 HRESULT to_uint32(script_ctx_t *ctx, jsval_t val, DWORD *ret) 672 { 673 INT32 n; 674 HRESULT hres; 675 676 hres = to_int32(ctx, val, &n); 677 if(SUCCEEDED(hres)) 678 *ret = n; 679 return hres; 680 } 681 682 static jsstr_t *int_to_string(int i) 683 { 684 WCHAR buf[12], *p; 685 BOOL neg = FALSE; 686 687 if(!i) { 688 static const WCHAR zeroW[] = {'0',0}; 689 return jsstr_alloc(zeroW); 690 } 691 692 if(i < 0) { 693 neg = TRUE; 694 i = -i; 695 } 696 697 p = buf + sizeof(buf)/sizeof(*buf)-1; 698 *p-- = 0; 699 while(i) { 700 *p-- = i%10 + '0'; 701 i /= 10; 702 } 703 704 if(neg) 705 *p = '-'; 706 else 707 p++; 708 709 return jsstr_alloc(p); 710 } 711 712 HRESULT double_to_string(double n, jsstr_t **str) 713 { 714 const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0}; 715 716 if(isnan(n)) { 717 *str = jsstr_nan(); 718 }else if(isinf(n)) { 719 *str = jsstr_alloc(n<0 ? InfinityW : InfinityW+1); 720 }else if(is_int32(n)) { 721 *str = int_to_string(n); 722 }else { 723 VARIANT strv, v; 724 HRESULT hres; 725 726 /* FIXME: Don't use VariantChangeTypeEx */ 727 V_VT(&v) = VT_R8; 728 V_R8(&v) = n; 729 V_VT(&strv) = VT_EMPTY; 730 hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR); 731 if(FAILED(hres)) 732 return hres; 733 734 *str = jsstr_alloc(V_BSTR(&strv)); 735 SysFreeString(V_BSTR(&strv)); 736 } 737 738 return *str ? S_OK : E_OUTOFMEMORY; 739 } 740 741 /* ECMA-262 3rd Edition 9.8 */ 742 HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str) 743 { 744 const WCHAR nullW[] = {'n','u','l','l',0}; 745 const WCHAR trueW[] = {'t','r','u','e',0}; 746 const WCHAR falseW[] = {'f','a','l','s','e',0}; 747 748 switch(jsval_type(val)) { 749 case JSV_UNDEFINED: 750 *str = jsstr_undefined(); 751 return S_OK; 752 case JSV_NULL: 753 *str = jsstr_alloc(nullW); 754 break; 755 case JSV_NUMBER: 756 return double_to_string(get_number(val), str); 757 case JSV_STRING: 758 *str = jsstr_addref(get_string(val)); 759 break; 760 case JSV_OBJECT: { 761 jsval_t prim; 762 HRESULT hres; 763 764 hres = to_primitive(ctx, val, &prim, HINT_STRING); 765 if(FAILED(hres)) 766 return hres; 767 768 hres = to_string(ctx, prim, str); 769 jsval_release(prim); 770 return hres; 771 } 772 case JSV_BOOL: 773 *str = jsstr_alloc(get_bool(val) ? trueW : falseW); 774 break; 775 default: 776 FIXME("unsupported %s\n", debugstr_jsval(val)); 777 return E_NOTIMPL; 778 } 779 780 return *str ? S_OK : E_OUTOFMEMORY; 781 } 782 783 HRESULT to_flat_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str, const WCHAR **ret_str) 784 { 785 HRESULT hres; 786 787 hres = to_string(ctx, val, str); 788 if(FAILED(hres)) 789 return hres; 790 791 *ret_str = jsstr_flatten(*str); 792 if(!*ret_str) { 793 jsstr_release(*str); 794 return E_OUTOFMEMORY; 795 } 796 797 return S_OK; 798 } 799 800 /* ECMA-262 3rd Edition 9.9 */ 801 HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp) 802 { 803 jsdisp_t *dispex; 804 HRESULT hres; 805 806 switch(jsval_type(val)) { 807 case JSV_STRING: 808 hres = create_string(ctx, get_string(val), &dispex); 809 if(FAILED(hres)) 810 return hres; 811 812 *disp = to_disp(dispex); 813 break; 814 case JSV_NUMBER: 815 hres = create_number(ctx, get_number(val), &dispex); 816 if(FAILED(hres)) 817 return hres; 818 819 *disp = to_disp(dispex); 820 break; 821 case JSV_OBJECT: 822 if(get_object(val)) { 823 *disp = get_object(val); 824 IDispatch_AddRef(*disp); 825 }else { 826 jsdisp_t *obj; 827 828 hres = create_object(ctx, NULL, &obj); 829 if(FAILED(hres)) 830 return hres; 831 832 *disp = to_disp(obj); 833 } 834 break; 835 case JSV_BOOL: 836 hres = create_bool(ctx, get_bool(val), &dispex); 837 if(FAILED(hres)) 838 return hres; 839 840 *disp = to_disp(dispex); 841 break; 842 case JSV_UNDEFINED: 843 case JSV_NULL: 844 WARN("object expected\n"); 845 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL); 846 case JSV_VARIANT: 847 switch(V_VT(get_variant(val))) { 848 case VT_ARRAY|VT_VARIANT: 849 hres = create_vbarray(ctx, V_ARRAY(get_variant(val)), &dispex); 850 if(FAILED(hres)) 851 return hres; 852 853 *disp = to_disp(dispex); 854 break; 855 856 default: 857 FIXME("Unsupported %s\n", debugstr_variant(get_variant(val))); 858 return E_NOTIMPL; 859 } 860 break; 861 } 862 863 return S_OK; 864 } 865 866 HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt) 867 { 868 jsval_t val; 869 HRESULT hres; 870 871 clear_ei(ctx); 872 hres = variant_to_jsval(src, &val); 873 if(FAILED(hres)) 874 return hres; 875 876 switch(vt) { 877 case VT_I2: 878 case VT_I4: { 879 INT i; 880 881 hres = to_int32(ctx, val, &i); 882 if(SUCCEEDED(hres)) { 883 if(vt == VT_I4) 884 V_I4(dst) = i; 885 else 886 V_I2(dst) = i; 887 } 888 break; 889 } 890 case VT_R8: { 891 double n; 892 hres = to_number(ctx, val, &n); 893 if(SUCCEEDED(hres)) 894 V_R8(dst) = n; 895 break; 896 } 897 case VT_R4: { 898 double n; 899 900 hres = to_number(ctx, val, &n); 901 if(SUCCEEDED(hres)) 902 V_R4(dst) = n; 903 break; 904 } 905 case VT_BOOL: { 906 BOOL b; 907 908 hres = to_boolean(val, &b); 909 if(SUCCEEDED(hres)) 910 V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE; 911 break; 912 } 913 case VT_BSTR: { 914 jsstr_t *str; 915 916 hres = to_string(ctx, val, &str); 917 if(FAILED(hres)) 918 break; 919 920 if(is_null_bstr(str)) { 921 V_BSTR(dst) = NULL; 922 break; 923 } 924 925 V_BSTR(dst) = SysAllocStringLen(NULL, jsstr_length(str)); 926 if(V_BSTR(dst)) 927 jsstr_flush(str, V_BSTR(dst)); 928 else 929 hres = E_OUTOFMEMORY; 930 break; 931 } 932 case VT_EMPTY: 933 hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL; 934 break; 935 case VT_NULL: 936 hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL; 937 break; 938 default: 939 FIXME("vt %d not implemented\n", vt); 940 hres = E_NOTIMPL; 941 } 942 943 jsval_release(val); 944 if(FAILED(hres)) 945 return hres; 946 947 V_VT(dst) = vt; 948 return S_OK; 949 } 950 951 static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface) 952 { 953 return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface); 954 } 955 956 static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) 957 { 958 JSCaller *This = impl_from_IServiceProvider(iface); 959 960 if(IsEqualGUID(&IID_IUnknown, riid)) { 961 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 962 *ppv = &This->IServiceProvider_iface; 963 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { 964 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv); 965 *ppv = &This->IServiceProvider_iface; 966 }else { 967 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 968 *ppv = NULL; 969 return E_NOINTERFACE; 970 } 971 972 IUnknown_AddRef((IUnknown*)*ppv); 973 return S_OK; 974 } 975 976 static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface) 977 { 978 JSCaller *This = impl_from_IServiceProvider(iface); 979 LONG ref = InterlockedIncrement(&This->ref); 980 981 TRACE("(%p) ref=%d\n", This, ref); 982 983 return ref; 984 } 985 986 static ULONG WINAPI JSCaller_Release(IServiceProvider *iface) 987 { 988 JSCaller *This = impl_from_IServiceProvider(iface); 989 LONG ref = InterlockedIncrement(&This->ref); 990 991 TRACE("(%p) ref=%d\n", This, ref); 992 993 if(!ref) { 994 assert(!This->ctx); 995 heap_free(This); 996 } 997 998 return ref; 999 } 1000 1001 static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService, 1002 REFIID riid, void **ppv) 1003 { 1004 JSCaller *This = impl_from_IServiceProvider(iface); 1005 1006 if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) { 1007 TRACE("(%p)->(SID_VariantConversion)\n", This); 1008 return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv); 1009 } 1010 1011 FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); 1012 1013 *ppv = NULL; 1014 return E_NOINTERFACE; 1015 } 1016 1017 static const IServiceProviderVtbl ServiceProviderVtbl = { 1018 JSCaller_QueryInterface, 1019 JSCaller_AddRef, 1020 JSCaller_Release, 1021 JSCaller_QueryService 1022 }; 1023 1024 HRESULT create_jscaller(script_ctx_t *ctx) 1025 { 1026 JSCaller *ret; 1027 1028 ret = heap_alloc(sizeof(*ret)); 1029 if(!ret) 1030 return E_OUTOFMEMORY; 1031 1032 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; 1033 ret->ref = 1; 1034 ret->ctx = ctx; 1035 1036 ctx->jscaller = ret; 1037 return S_OK; 1038 } 1039