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