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_UI2: 291 *r = jsval_number(V_UI2(var)); 292 return S_OK; 293 case VT_INT: 294 *r = jsval_number(V_INT(var)); 295 return S_OK; 296 case VT_UI4: 297 *r = jsval_number(V_UI4(var)); 298 return S_OK; 299 case VT_UI8: 300 /* 301 * Native doesn't support VT_UI8 here, but it's needed for IE9+ APIs 302 * (native IE9 doesn't use jscript.dll for JavaScript). 303 */ 304 *r = jsval_number(V_UI8(var)); 305 return S_OK; 306 case VT_R4: 307 *r = jsval_number(V_R4(var)); 308 return S_OK; 309 case VT_UNKNOWN: 310 if(V_UNKNOWN(var)) { 311 IDispatch *disp; 312 HRESULT hres; 313 314 hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp); 315 if(SUCCEEDED(hres)) { 316 *r = jsval_disp(disp); 317 return S_OK; 318 } 319 }else { 320 *r = jsval_disp(NULL); 321 return S_OK; 322 } 323 /* fall through */ 324 default: 325 return jsval_variant(r, var); 326 } 327 } 328 329 HRESULT jsval_to_variant(jsval_t val, VARIANT *retv) 330 { 331 switch(jsval_type(val)) { 332 case JSV_UNDEFINED: 333 V_VT(retv) = VT_EMPTY; 334 return S_OK; 335 case JSV_NULL: 336 V_VT(retv) = VT_NULL; 337 return S_OK; 338 case JSV_OBJECT: 339 V_VT(retv) = VT_DISPATCH; 340 if(get_object(val)) 341 IDispatch_AddRef(get_object(val)); 342 V_DISPATCH(retv) = get_object(val); 343 return S_OK; 344 case JSV_STRING: { 345 jsstr_t *str = get_string(val); 346 347 V_VT(retv) = VT_BSTR; 348 if(is_null_bstr(str)) { 349 V_BSTR(retv) = NULL; 350 }else { 351 V_BSTR(retv) = SysAllocStringLen(NULL, jsstr_length(str)); 352 if(V_BSTR(retv)) 353 jsstr_flush(str, V_BSTR(retv)); 354 else 355 return E_OUTOFMEMORY; 356 } 357 return S_OK; 358 } 359 case JSV_NUMBER: { 360 double n = get_number(val); 361 362 if(is_int32(n)) { 363 V_VT(retv) = VT_I4; 364 V_I4(retv) = n; 365 }else { 366 V_VT(retv) = VT_R8; 367 V_R8(retv) = n; 368 } 369 370 return S_OK; 371 } 372 case JSV_BOOL: 373 V_VT(retv) = VT_BOOL; 374 V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE; 375 return S_OK; 376 case JSV_VARIANT: 377 V_VT(retv) = VT_EMPTY; 378 return VariantCopy(retv, get_variant(val)); 379 } 380 381 assert(0); 382 return E_FAIL; 383 } 384 385 /* ECMA-262 3rd Edition 9.1 */ 386 HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) 387 { 388 if(is_object_instance(val)) { 389 jsdisp_t *jsdisp; 390 jsval_t prim; 391 DISPID id; 392 HRESULT hres; 393 394 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; 395 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0}; 396 397 if(!get_object(val)) { 398 *ret = jsval_null(); 399 return S_OK; 400 } 401 402 jsdisp = iface_to_jsdisp(get_object(val)); 403 if(!jsdisp) 404 return disp_propget(ctx, get_object(val), DISPID_VALUE, ret); 405 406 if(hint == NO_HINT) 407 hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER; 408 409 /* Native implementation doesn't throw TypeErrors, returns strange values */ 410 411 hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id); 412 if(SUCCEEDED(hres)) { 413 hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim); 414 if(FAILED(hres)) { 415 WARN("call error - forwarding exception\n"); 416 jsdisp_release(jsdisp); 417 return hres; 418 }else if(!is_object_instance(prim)) { 419 jsdisp_release(jsdisp); 420 *ret = prim; 421 return S_OK; 422 }else { 423 IDispatch_Release(get_object(prim)); 424 } 425 } 426 427 hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id); 428 if(SUCCEEDED(hres)) { 429 hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim); 430 if(FAILED(hres)) { 431 WARN("call error - forwarding exception\n"); 432 jsdisp_release(jsdisp); 433 return hres; 434 }else if(!is_object_instance(prim)) { 435 jsdisp_release(jsdisp); 436 *ret = prim; 437 return S_OK; 438 }else { 439 IDispatch_Release(get_object(prim)); 440 } 441 } 442 443 jsdisp_release(jsdisp); 444 445 WARN("failed\n"); 446 return throw_type_error(ctx, JS_E_TO_PRIMITIVE, NULL); 447 } 448 449 return jsval_copy(val, ret); 450 451 } 452 453 /* ECMA-262 3rd Edition 9.2 */ 454 HRESULT to_boolean(jsval_t val, BOOL *ret) 455 { 456 switch(jsval_type(val)) { 457 case JSV_UNDEFINED: 458 case JSV_NULL: 459 *ret = FALSE; 460 return S_OK; 461 case JSV_OBJECT: 462 *ret = get_object(val) != NULL; 463 return S_OK; 464 case JSV_STRING: 465 *ret = jsstr_length(get_string(val)) != 0; 466 return S_OK; 467 case JSV_NUMBER: 468 *ret = !isnan(get_number(val)) && get_number(val); 469 return S_OK; 470 case JSV_BOOL: 471 *ret = get_bool(val); 472 return S_OK; 473 case JSV_VARIANT: 474 FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val))); 475 return E_NOTIMPL; 476 } 477 478 assert(0); 479 return E_FAIL; 480 } 481 482 static int hex_to_int(WCHAR c) 483 { 484 if('0' <= c && c <= '9') 485 return c-'0'; 486 487 if('a' <= c && c <= 'f') 488 return c-'a'+10; 489 490 if('A' <= c && c <= 'F') 491 return c-'A'+10; 492 493 return -1; 494 } 495 496 /* ECMA-262 3rd Edition 9.3.1 */ 497 static HRESULT str_to_number(jsstr_t *str, double *ret) 498 { 499 const WCHAR *ptr; 500 BOOL neg = FALSE; 501 DOUBLE d = 0.0; 502 503 static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'}; 504 505 ptr = jsstr_flatten(str); 506 if(!ptr) 507 return E_OUTOFMEMORY; 508 509 while(isspaceW(*ptr)) 510 ptr++; 511 512 if(*ptr == '-') { 513 neg = TRUE; 514 ptr++; 515 }else if(*ptr == '+') { 516 ptr++; 517 } 518 519 if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) { 520 ptr += sizeof(infinityW)/sizeof(WCHAR); 521 while(*ptr && isspaceW(*ptr)) 522 ptr++; 523 524 if(*ptr) 525 *ret = NAN; 526 else 527 *ret = neg ? -INFINITY : INFINITY; 528 return S_OK; 529 } 530 531 if(*ptr == '0' && ptr[1] == 'x') { 532 DWORD l = 0; 533 534 ptr += 2; 535 while((l = hex_to_int(*ptr)) != -1) { 536 d = d*16 + l; 537 ptr++; 538 } 539 540 *ret = d; 541 return S_OK; 542 } 543 544 while(isdigitW(*ptr)) 545 d = d*10 + (*ptr++ - '0'); 546 547 if(*ptr == 'e' || *ptr == 'E') { 548 BOOL eneg = FALSE; 549 LONG l = 0; 550 551 ptr++; 552 if(*ptr == '-') { 553 ptr++; 554 eneg = TRUE; 555 }else if(*ptr == '+') { 556 ptr++; 557 } 558 559 while(isdigitW(*ptr)) 560 l = l*10 + (*ptr++ - '0'); 561 if(eneg) 562 l = -l; 563 564 d *= pow(10, l); 565 }else if(*ptr == '.') { 566 DOUBLE dec = 0.1; 567 568 ptr++; 569 while(isdigitW(*ptr)) { 570 d += dec * (*ptr++ - '0'); 571 dec *= 0.1; 572 } 573 } 574 575 while(isspaceW(*ptr)) 576 ptr++; 577 578 if(*ptr) { 579 *ret = NAN; 580 return S_OK; 581 } 582 583 if(neg) 584 d = -d; 585 586 *ret = d; 587 return S_OK; 588 } 589 590 /* ECMA-262 3rd Edition 9.3 */ 591 HRESULT to_number(script_ctx_t *ctx, jsval_t val, double *ret) 592 { 593 switch(jsval_type(val)) { 594 case JSV_UNDEFINED: 595 *ret = NAN; 596 return S_OK; 597 case JSV_NULL: 598 *ret = 0; 599 return S_OK; 600 case JSV_NUMBER: 601 *ret = get_number(val); 602 return S_OK; 603 case JSV_STRING: 604 return str_to_number(get_string(val), ret); 605 case JSV_OBJECT: { 606 jsval_t prim; 607 HRESULT hres; 608 609 hres = to_primitive(ctx, val, &prim, HINT_NUMBER); 610 if(FAILED(hres)) 611 return hres; 612 613 hres = to_number(ctx, prim, ret); 614 jsval_release(prim); 615 return hres; 616 } 617 case JSV_BOOL: 618 *ret = get_bool(val) ? 1 : 0; 619 return S_OK; 620 case JSV_VARIANT: 621 FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val))); 622 return E_NOTIMPL; 623 }; 624 625 assert(0); 626 return E_FAIL; 627 } 628 629 /* ECMA-262 3rd Edition 9.4 */ 630 HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret) 631 { 632 double n; 633 HRESULT hres; 634 635 hres = to_number(ctx, v, &n); 636 if(FAILED(hres)) 637 return hres; 638 639 if(isnan(n)) 640 *ret = 0; 641 else 642 *ret = n >= 0.0 ? floor(n) : -floor(-n); 643 return S_OK; 644 } 645 646 /* ECMA-262 3rd Edition 9.5 */ 647 HRESULT to_int32(script_ctx_t *ctx, jsval_t v, INT *ret) 648 { 649 double n; 650 HRESULT hres; 651 652 hres = to_number(ctx, v, &n); 653 if(FAILED(hres)) 654 return hres; 655 656 *ret = is_finite(n) ? n : 0; 657 return S_OK; 658 } 659 660 /* ECMA-262 3rd Edition 9.6 */ 661 HRESULT to_uint32(script_ctx_t *ctx, jsval_t val, DWORD *ret) 662 { 663 INT32 n; 664 HRESULT hres; 665 666 hres = to_int32(ctx, val, &n); 667 if(SUCCEEDED(hres)) 668 *ret = n; 669 return hres; 670 } 671 672 static jsstr_t *int_to_string(int i) 673 { 674 WCHAR buf[12], *p; 675 BOOL neg = FALSE; 676 677 if(!i) { 678 static const WCHAR zeroW[] = {'0',0}; 679 return jsstr_alloc(zeroW); 680 } 681 682 if(i < 0) { 683 neg = TRUE; 684 i = -i; 685 } 686 687 p = buf + sizeof(buf)/sizeof(*buf)-1; 688 *p-- = 0; 689 while(i) { 690 *p-- = i%10 + '0'; 691 i /= 10; 692 } 693 694 if(neg) 695 *p = '-'; 696 else 697 p++; 698 699 return jsstr_alloc(p); 700 } 701 702 HRESULT double_to_string(double n, jsstr_t **str) 703 { 704 const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0}; 705 706 if(isnan(n)) { 707 *str = jsstr_nan(); 708 }else if(isinf(n)) { 709 *str = jsstr_alloc(n<0 ? InfinityW : InfinityW+1); 710 }else if(is_int32(n)) { 711 *str = int_to_string(n); 712 }else { 713 VARIANT strv, v; 714 HRESULT hres; 715 716 /* FIXME: Don't use VariantChangeTypeEx */ 717 V_VT(&v) = VT_R8; 718 V_R8(&v) = n; 719 V_VT(&strv) = VT_EMPTY; 720 hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR); 721 if(FAILED(hres)) 722 return hres; 723 724 *str = jsstr_alloc(V_BSTR(&strv)); 725 SysFreeString(V_BSTR(&strv)); 726 } 727 728 return *str ? S_OK : E_OUTOFMEMORY; 729 } 730 731 /* ECMA-262 3rd Edition 9.8 */ 732 HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str) 733 { 734 const WCHAR nullW[] = {'n','u','l','l',0}; 735 const WCHAR trueW[] = {'t','r','u','e',0}; 736 const WCHAR falseW[] = {'f','a','l','s','e',0}; 737 738 switch(jsval_type(val)) { 739 case JSV_UNDEFINED: 740 *str = jsstr_undefined(); 741 return S_OK; 742 case JSV_NULL: 743 *str = jsstr_alloc(nullW); 744 break; 745 case JSV_NUMBER: 746 return double_to_string(get_number(val), str); 747 case JSV_STRING: 748 *str = jsstr_addref(get_string(val)); 749 break; 750 case JSV_OBJECT: { 751 jsval_t prim; 752 HRESULT hres; 753 754 hres = to_primitive(ctx, val, &prim, HINT_STRING); 755 if(FAILED(hres)) 756 return hres; 757 758 hres = to_string(ctx, prim, str); 759 jsval_release(prim); 760 return hres; 761 } 762 case JSV_BOOL: 763 *str = jsstr_alloc(get_bool(val) ? trueW : falseW); 764 break; 765 default: 766 FIXME("unsupported %s\n", debugstr_jsval(val)); 767 return E_NOTIMPL; 768 } 769 770 return *str ? S_OK : E_OUTOFMEMORY; 771 } 772 773 HRESULT to_flat_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str, const WCHAR **ret_str) 774 { 775 HRESULT hres; 776 777 hres = to_string(ctx, val, str); 778 if(FAILED(hres)) 779 return hres; 780 781 *ret_str = jsstr_flatten(*str); 782 if(!*ret_str) { 783 jsstr_release(*str); 784 return E_OUTOFMEMORY; 785 } 786 787 return S_OK; 788 } 789 790 /* ECMA-262 3rd Edition 9.9 */ 791 HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp) 792 { 793 jsdisp_t *dispex; 794 HRESULT hres; 795 796 switch(jsval_type(val)) { 797 case JSV_STRING: 798 hres = create_string(ctx, get_string(val), &dispex); 799 if(FAILED(hres)) 800 return hres; 801 802 *disp = to_disp(dispex); 803 break; 804 case JSV_NUMBER: 805 hres = create_number(ctx, get_number(val), &dispex); 806 if(FAILED(hres)) 807 return hres; 808 809 *disp = to_disp(dispex); 810 break; 811 case JSV_OBJECT: 812 if(get_object(val)) { 813 *disp = get_object(val); 814 IDispatch_AddRef(*disp); 815 }else { 816 jsdisp_t *obj; 817 818 hres = create_object(ctx, NULL, &obj); 819 if(FAILED(hres)) 820 return hres; 821 822 *disp = to_disp(obj); 823 } 824 break; 825 case JSV_BOOL: 826 hres = create_bool(ctx, get_bool(val), &dispex); 827 if(FAILED(hres)) 828 return hres; 829 830 *disp = to_disp(dispex); 831 break; 832 case JSV_UNDEFINED: 833 case JSV_NULL: 834 WARN("object expected\n"); 835 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL); 836 case JSV_VARIANT: 837 switch(V_VT(get_variant(val))) { 838 case VT_ARRAY|VT_VARIANT: 839 hres = create_vbarray(ctx, V_ARRAY(get_variant(val)), &dispex); 840 if(FAILED(hres)) 841 return hres; 842 843 *disp = to_disp(dispex); 844 break; 845 846 default: 847 FIXME("Unsupported %s\n", debugstr_variant(get_variant(val))); 848 return E_NOTIMPL; 849 } 850 break; 851 } 852 853 return S_OK; 854 } 855 856 HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt) 857 { 858 jsval_t val; 859 HRESULT hres; 860 861 clear_ei(ctx); 862 hres = variant_to_jsval(src, &val); 863 if(FAILED(hres)) 864 return hres; 865 866 switch(vt) { 867 case VT_I2: 868 case VT_I4: { 869 INT i; 870 871 hres = to_int32(ctx, val, &i); 872 if(SUCCEEDED(hres)) { 873 if(vt == VT_I4) 874 V_I4(dst) = i; 875 else 876 V_I2(dst) = i; 877 } 878 break; 879 } 880 case VT_R8: { 881 double n; 882 hres = to_number(ctx, val, &n); 883 if(SUCCEEDED(hres)) 884 V_R8(dst) = n; 885 break; 886 } 887 case VT_R4: { 888 double n; 889 890 hres = to_number(ctx, val, &n); 891 if(SUCCEEDED(hres)) 892 V_R4(dst) = n; 893 break; 894 } 895 case VT_BOOL: { 896 BOOL b; 897 898 hres = to_boolean(val, &b); 899 if(SUCCEEDED(hres)) 900 V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE; 901 break; 902 } 903 case VT_BSTR: { 904 jsstr_t *str; 905 906 hres = to_string(ctx, val, &str); 907 if(FAILED(hres)) 908 break; 909 910 if(is_null_bstr(str)) { 911 V_BSTR(dst) = NULL; 912 break; 913 } 914 915 V_BSTR(dst) = SysAllocStringLen(NULL, jsstr_length(str)); 916 if(V_BSTR(dst)) 917 jsstr_flush(str, V_BSTR(dst)); 918 else 919 hres = E_OUTOFMEMORY; 920 break; 921 } 922 case VT_EMPTY: 923 hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL; 924 break; 925 case VT_NULL: 926 hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL; 927 break; 928 default: 929 FIXME("vt %d not implemented\n", vt); 930 hres = E_NOTIMPL; 931 } 932 933 jsval_release(val); 934 if(FAILED(hres)) 935 return hres; 936 937 V_VT(dst) = vt; 938 return S_OK; 939 } 940 941 static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface) 942 { 943 return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface); 944 } 945 946 static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) 947 { 948 JSCaller *This = impl_from_IServiceProvider(iface); 949 950 if(IsEqualGUID(&IID_IUnknown, riid)) { 951 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 952 *ppv = &This->IServiceProvider_iface; 953 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { 954 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv); 955 *ppv = &This->IServiceProvider_iface; 956 }else { 957 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 958 *ppv = NULL; 959 return E_NOINTERFACE; 960 } 961 962 IUnknown_AddRef((IUnknown*)*ppv); 963 return S_OK; 964 } 965 966 static ULONG WINAPI JSCaller_AddRef(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 return ref; 974 } 975 976 static ULONG WINAPI JSCaller_Release(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 if(!ref) { 984 assert(!This->ctx); 985 heap_free(This); 986 } 987 988 return ref; 989 } 990 991 static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService, 992 REFIID riid, void **ppv) 993 { 994 JSCaller *This = impl_from_IServiceProvider(iface); 995 996 if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) { 997 TRACE("(%p)->(SID_VariantConversion)\n", This); 998 return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv); 999 } 1000 1001 FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); 1002 1003 *ppv = NULL; 1004 return E_NOINTERFACE; 1005 } 1006 1007 static const IServiceProviderVtbl ServiceProviderVtbl = { 1008 JSCaller_QueryInterface, 1009 JSCaller_AddRef, 1010 JSCaller_Release, 1011 JSCaller_QueryService 1012 }; 1013 1014 HRESULT create_jscaller(script_ctx_t *ctx) 1015 { 1016 JSCaller *ret; 1017 1018 ret = heap_alloc(sizeof(*ret)); 1019 if(!ret) 1020 return E_OUTOFMEMORY; 1021 1022 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; 1023 ret->ref = 1; 1024 ret->ctx = ctx; 1025 1026 ctx->jscaller = ret; 1027 return S_OK; 1028 } 1029