1 /* 2 * Copyright 2011 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 "vbscript.h" 20 21 static DISPID propput_dispid = DISPID_PROPERTYPUT; 22 23 typedef struct { 24 vbscode_t *code; 25 instr_t *instr; 26 script_ctx_t *script; 27 function_t *func; 28 IDispatch *this_obj; 29 vbdisp_t *vbthis; 30 31 VARIANT *args; 32 VARIANT *vars; 33 SAFEARRAY **arrays; 34 35 dynamic_var_t *dynamic_vars; 36 heap_pool_t heap; 37 38 BOOL resume_next; 39 40 unsigned stack_size; 41 unsigned top; 42 VARIANT *stack; 43 44 VARIANT ret_val; 45 } exec_ctx_t; 46 47 typedef HRESULT (*instr_func_t)(exec_ctx_t*); 48 49 typedef enum { 50 REF_NONE, 51 REF_DISP, 52 REF_VAR, 53 REF_OBJ, 54 REF_CONST, 55 REF_FUNC 56 } ref_type_t; 57 58 typedef struct { 59 ref_type_t type; 60 union { 61 struct { 62 IDispatch *disp; 63 DISPID id; 64 } d; 65 VARIANT *v; 66 function_t *f; 67 IDispatch *obj; 68 } u; 69 } ref_t; 70 71 typedef struct { 72 VARIANT *v; 73 VARIANT store; 74 BOOL owned; 75 } variant_val_t; 76 77 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref) 78 { 79 while(var) { 80 if(!strcmpiW(var->name, name)) { 81 ref->type = var->is_const ? REF_CONST : REF_VAR; 82 ref->u.v = &var->v; 83 return TRUE; 84 } 85 86 var = var->next; 87 } 88 89 return FALSE; 90 } 91 92 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref) 93 { 94 named_item_t *item; 95 function_t *func; 96 unsigned i; 97 DISPID id; 98 HRESULT hres; 99 100 static const WCHAR errW[] = {'e','r','r',0}; 101 102 if(invoke_type == VBDISP_LET 103 && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET || ctx->func->type == FUNC_DEFGET) 104 && !strcmpiW(name, ctx->func->name)) { 105 ref->type = REF_VAR; 106 ref->u.v = &ctx->ret_val; 107 return S_OK; 108 } 109 110 for(i=0; i < ctx->func->var_cnt; i++) { 111 if(!strcmpiW(ctx->func->vars[i].name, name)) { 112 ref->type = REF_VAR; 113 ref->u.v = ctx->vars+i; 114 return TRUE; 115 } 116 } 117 118 for(i=0; i < ctx->func->arg_cnt; i++) { 119 if(!strcmpiW(ctx->func->args[i].name, name)) { 120 ref->type = REF_VAR; 121 ref->u.v = ctx->args+i; 122 return S_OK; 123 } 124 } 125 126 if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref)) 127 return S_OK; 128 129 if(ctx->func->type != FUNC_GLOBAL) { 130 if(ctx->vbthis) { 131 /* FIXME: Bind such identifier while generating bytecode. */ 132 for(i=0; i < ctx->vbthis->desc->prop_cnt; i++) { 133 if(!strcmpiW(ctx->vbthis->desc->props[i].name, name)) { 134 ref->type = REF_VAR; 135 ref->u.v = ctx->vbthis->props+i; 136 return S_OK; 137 } 138 } 139 } 140 141 hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id); 142 if(SUCCEEDED(hres)) { 143 ref->type = REF_DISP; 144 ref->u.d.disp = ctx->this_obj; 145 ref->u.d.id = id; 146 return S_OK; 147 } 148 } 149 150 if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref)) 151 return S_OK; 152 153 for(func = ctx->script->global_funcs; func; func = func->next) { 154 if(!strcmpiW(func->name, name)) { 155 ref->type = REF_FUNC; 156 ref->u.f = func; 157 return S_OK; 158 } 159 } 160 161 if(!strcmpiW(name, errW)) { 162 ref->type = REF_OBJ; 163 ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface; 164 return S_OK; 165 } 166 167 hres = vbdisp_get_id(ctx->script->global_obj, name, invoke_type, TRUE, &id); 168 if(SUCCEEDED(hres)) { 169 ref->type = REF_DISP; 170 ref->u.d.disp = (IDispatch*)&ctx->script->global_obj->IDispatchEx_iface; 171 ref->u.d.id = id; 172 return S_OK; 173 } 174 175 LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) { 176 if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpiW(item->name, name)) { 177 if(!item->disp) { 178 IUnknown *unk; 179 180 hres = IActiveScriptSite_GetItemInfo(ctx->script->site, item->name, SCRIPTINFO_IUNKNOWN, &unk, NULL); 181 if(FAILED(hres)) { 182 WARN("GetItemInfo failed: %08x\n", hres); 183 continue; 184 } 185 186 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp); 187 IUnknown_Release(unk); 188 if(FAILED(hres)) { 189 WARN("object does not implement IDispatch\n"); 190 continue; 191 } 192 } 193 194 ref->type = REF_OBJ; 195 ref->u.obj = item->disp; 196 return S_OK; 197 } 198 } 199 200 LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) { 201 if((item->flags & SCRIPTITEM_GLOBALMEMBERS)) { 202 hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id); 203 if(SUCCEEDED(hres)) { 204 ref->type = REF_DISP; 205 ref->u.d.disp = item->disp; 206 ref->u.d.id = id; 207 return S_OK; 208 } 209 } 210 } 211 212 ref->type = REF_NONE; 213 return S_OK; 214 } 215 216 static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, 217 BOOL is_const, VARIANT **out_var) 218 { 219 dynamic_var_t *new_var; 220 heap_pool_t *heap; 221 WCHAR *str; 222 unsigned size; 223 224 heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap; 225 226 new_var = heap_pool_alloc(heap, sizeof(*new_var)); 227 if(!new_var) 228 return E_OUTOFMEMORY; 229 230 size = (strlenW(name)+1)*sizeof(WCHAR); 231 str = heap_pool_alloc(heap, size); 232 if(!str) 233 return E_OUTOFMEMORY; 234 memcpy(str, name, size); 235 new_var->name = str; 236 new_var->is_const = is_const; 237 V_VT(&new_var->v) = VT_EMPTY; 238 239 if(ctx->func->type == FUNC_GLOBAL) { 240 new_var->next = ctx->script->global_vars; 241 ctx->script->global_vars = new_var; 242 }else { 243 new_var->next = ctx->dynamic_vars; 244 ctx->dynamic_vars = new_var; 245 } 246 247 *out_var = &new_var->v; 248 return S_OK; 249 } 250 251 static inline VARIANT *stack_pop(exec_ctx_t *ctx) 252 { 253 assert(ctx->top); 254 return ctx->stack + --ctx->top; 255 } 256 257 static inline VARIANT *stack_top(exec_ctx_t *ctx, unsigned n) 258 { 259 assert(ctx->top >= n); 260 return ctx->stack + (ctx->top-n-1); 261 } 262 263 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v) 264 { 265 if(ctx->stack_size == ctx->top) { 266 VARIANT *new_stack; 267 268 new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack)); 269 if(!new_stack) { 270 VariantClear(v); 271 return E_OUTOFMEMORY; 272 } 273 274 ctx->stack = new_stack; 275 ctx->stack_size *= 2; 276 } 277 278 ctx->stack[ctx->top++] = *v; 279 return S_OK; 280 } 281 282 static inline HRESULT stack_push_null(exec_ctx_t *ctx) 283 { 284 VARIANT v; 285 V_VT(&v) = VT_NULL; 286 return stack_push(ctx, &v); 287 } 288 289 static void stack_popn(exec_ctx_t *ctx, unsigned n) 290 { 291 while(n--) 292 VariantClear(stack_pop(ctx)); 293 } 294 295 static void stack_pop_deref(exec_ctx_t *ctx, variant_val_t *r) 296 { 297 VARIANT *v; 298 299 v = stack_pop(ctx); 300 if(V_VT(v) == (VT_BYREF|VT_VARIANT)) { 301 r->owned = FALSE; 302 r->v = V_VARIANTREF(v); 303 }else { 304 r->owned = TRUE; 305 r->v = v; 306 } 307 } 308 309 static inline void release_val(variant_val_t *v) 310 { 311 if(v->owned) 312 VariantClear(v->v); 313 } 314 315 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *r) 316 { 317 stack_pop_deref(ctx, r); 318 319 if(V_VT(r->v) == VT_DISPATCH) { 320 HRESULT hres; 321 322 hres = get_disp_value(ctx->script, V_DISPATCH(r->v), &r->store); 323 if(r->owned) 324 IDispatch_Release(V_DISPATCH(r->v)); 325 if(FAILED(hres)) 326 return hres; 327 328 r->owned = TRUE; 329 r->v = &r->store; 330 } 331 332 return S_OK; 333 } 334 335 static HRESULT stack_assume_val(exec_ctx_t *ctx, unsigned n) 336 { 337 VARIANT *v = stack_top(ctx, n); 338 HRESULT hres; 339 340 if(V_VT(v) == (VT_BYREF|VT_VARIANT)) { 341 VARIANT *ref = V_VARIANTREF(v); 342 343 V_VT(v) = VT_EMPTY; 344 hres = VariantCopy(v, ref); 345 if(FAILED(hres)) 346 return hres; 347 } 348 349 if(V_VT(v) == VT_DISPATCH) { 350 IDispatch *disp; 351 352 disp = V_DISPATCH(v); 353 hres = get_disp_value(ctx->script, disp, v); 354 IDispatch_Release(disp); 355 if(FAILED(hres)) 356 return hres; 357 } 358 359 return S_OK; 360 } 361 362 static int stack_pop_bool(exec_ctx_t *ctx, BOOL *b) 363 { 364 variant_val_t val; 365 HRESULT hres; 366 367 hres = stack_pop_val(ctx, &val); 368 if(FAILED(hres)) 369 return hres; 370 371 switch (V_VT(val.v)) 372 { 373 case VT_BOOL: 374 *b = V_BOOL(val.v); 375 break; 376 case VT_NULL: 377 *b = FALSE; 378 break; 379 case VT_I2: 380 *b = V_I2(val.v); 381 break; 382 case VT_I4: 383 *b = V_I4(val.v); 384 break; 385 default: 386 FIXME("unsupported for %s\n", debugstr_variant(val.v)); 387 release_val(&val); 388 return E_NOTIMPL; 389 } 390 return S_OK; 391 } 392 393 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret) 394 { 395 VARIANT *v = stack_pop(ctx); 396 397 if(V_VT(v) == VT_DISPATCH) { 398 *ret = V_DISPATCH(v); 399 return S_OK; 400 } 401 402 if(V_VT(v) != (VT_VARIANT|VT_BYREF)) { 403 FIXME("not supported type: %s\n", debugstr_variant(v)); 404 VariantClear(v); 405 return E_FAIL; 406 } 407 408 v = V_BYREF(v); 409 if(V_VT(v) != VT_DISPATCH) { 410 FIXME("not disp %s\n", debugstr_variant(v)); 411 return E_FAIL; 412 } 413 414 if(V_DISPATCH(v)) 415 IDispatch_AddRef(V_DISPATCH(v)); 416 *ret = V_DISPATCH(v); 417 return S_OK; 418 } 419 420 static HRESULT stack_assume_disp(exec_ctx_t *ctx, unsigned n, IDispatch **disp) 421 { 422 VARIANT *v = stack_top(ctx, n), *ref; 423 424 if(V_VT(v) != VT_DISPATCH) { 425 if(V_VT(v) != (VT_VARIANT|VT_BYREF)) { 426 FIXME("not supported type: %s\n", debugstr_variant(v)); 427 return E_FAIL; 428 } 429 430 ref = V_VARIANTREF(v); 431 if(V_VT(ref) != VT_DISPATCH) { 432 FIXME("not disp %s\n", debugstr_variant(ref)); 433 return E_FAIL; 434 } 435 436 V_VT(v) = VT_DISPATCH; 437 V_DISPATCH(v) = V_DISPATCH(ref); 438 if(V_DISPATCH(v)) 439 IDispatch_AddRef(V_DISPATCH(v)); 440 } 441 442 if(disp) 443 *disp = V_DISPATCH(v); 444 return S_OK; 445 } 446 447 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr) 448 { 449 ctx->instr = ctx->code->instrs + addr; 450 } 451 452 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, BOOL is_propput, DISPPARAMS *dp) 453 { 454 dp->cNamedArgs = is_propput ? 1 : 0; 455 dp->cArgs = arg_cnt + dp->cNamedArgs; 456 dp->rgdispidNamedArgs = is_propput ? &propput_dispid : NULL; 457 458 if(arg_cnt) { 459 VARIANT tmp; 460 unsigned i; 461 462 assert(ctx->top >= arg_cnt); 463 464 for(i=1; i*2 <= arg_cnt; i++) { 465 tmp = ctx->stack[ctx->top-i]; 466 ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1]; 467 ctx->stack[ctx->top-arg_cnt+i-1] = tmp; 468 } 469 470 dp->rgvarg = ctx->stack + ctx->top-dp->cArgs; 471 }else { 472 dp->rgvarg = is_propput ? ctx->stack+ctx->top-1 : NULL; 473 } 474 } 475 476 static HRESULT array_access(exec_ctx_t *ctx, SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret) 477 { 478 unsigned i, argc = arg_cnt(dp); 479 LONG *indices; 480 HRESULT hres; 481 482 if(!array) { 483 FIXME("NULL array\n"); 484 return E_FAIL; 485 } 486 487 hres = SafeArrayLock(array); 488 if(FAILED(hres)) 489 return hres; 490 491 if(array->cDims != argc) { 492 FIXME("argc %d does not match cDims %d\n", dp->cArgs, array->cDims); 493 SafeArrayUnlock(array); 494 return E_FAIL; 495 } 496 497 indices = heap_alloc(sizeof(*indices) * argc); 498 if(!indices) { 499 SafeArrayUnlock(array); 500 return E_OUTOFMEMORY; 501 } 502 503 for(i=0; i<argc; i++) { 504 hres = to_int(get_arg(dp, i), indices+i); 505 if(FAILED(hres)) { 506 heap_free(indices); 507 SafeArrayUnlock(array); 508 return hres; 509 } 510 } 511 512 hres = SafeArrayPtrOfIndex(array, indices, (void**)ret); 513 SafeArrayUnlock(array); 514 heap_free(indices); 515 return hres; 516 } 517 518 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res) 519 { 520 BSTR identifier = ctx->instr->arg1.bstr; 521 const unsigned arg_cnt = ctx->instr->arg2.uint; 522 DISPPARAMS dp; 523 ref_t ref; 524 HRESULT hres; 525 526 hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref); 527 if(FAILED(hres)) 528 return hres; 529 530 switch(ref.type) { 531 case REF_VAR: 532 case REF_CONST: { 533 VARIANT *v; 534 535 if(!res) { 536 FIXME("REF_VAR no res\n"); 537 return E_NOTIMPL; 538 } 539 540 v = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v; 541 542 if(arg_cnt) { 543 SAFEARRAY *array = NULL; 544 545 switch(V_VT(v)) { 546 case VT_ARRAY|VT_BYREF|VT_VARIANT: 547 array = *V_ARRAYREF(ref.u.v); 548 break; 549 case VT_ARRAY|VT_VARIANT: 550 array = V_ARRAY(ref.u.v); 551 break; 552 case VT_DISPATCH: 553 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); 554 hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_VALUE, &dp, res); 555 if(FAILED(hres)) 556 return hres; 557 break; 558 default: 559 FIXME("arguments not implemented\n"); 560 return E_NOTIMPL; 561 } 562 563 if(!array) 564 break; 565 566 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); 567 hres = array_access(ctx, array, &dp, &v); 568 if(FAILED(hres)) 569 return hres; 570 } 571 572 V_VT(res) = VT_BYREF|VT_VARIANT; 573 V_BYREF(res) = v; 574 break; 575 } 576 case REF_DISP: 577 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); 578 hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res); 579 if(FAILED(hres)) 580 return hres; 581 break; 582 case REF_FUNC: 583 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); 584 hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res); 585 if(FAILED(hres)) 586 return hres; 587 break; 588 case REF_OBJ: 589 if(arg_cnt) { 590 FIXME("arguments on object\n"); 591 return E_NOTIMPL; 592 } 593 594 if(res) { 595 IDispatch_AddRef(ref.u.obj); 596 V_VT(res) = VT_DISPATCH; 597 V_DISPATCH(res) = ref.u.obj; 598 } 599 break; 600 case REF_NONE: 601 if(res && !ctx->func->code_ctx->option_explicit && arg_cnt == 0) { 602 VARIANT *new; 603 hres = add_dynamic_var(ctx, identifier, FALSE, &new); 604 if(FAILED(hres)) 605 return hres; 606 V_VT(res) = VT_BYREF|VT_VARIANT; 607 V_BYREF(res) = new; 608 break; 609 } 610 FIXME("%s not found\n", debugstr_w(identifier)); 611 return DISP_E_UNKNOWNNAME; 612 } 613 614 stack_popn(ctx, arg_cnt); 615 return S_OK; 616 } 617 618 static HRESULT interp_icall(exec_ctx_t *ctx) 619 { 620 VARIANT v; 621 HRESULT hres; 622 623 TRACE("\n"); 624 625 hres = do_icall(ctx, &v); 626 if(FAILED(hres)) 627 return hres; 628 629 return stack_push(ctx, &v); 630 } 631 632 static HRESULT interp_icallv(exec_ctx_t *ctx) 633 { 634 TRACE("\n"); 635 return do_icall(ctx, NULL); 636 } 637 638 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res) 639 { 640 const BSTR identifier = ctx->instr->arg1.bstr; 641 const unsigned arg_cnt = ctx->instr->arg2.uint; 642 IDispatch *obj; 643 DISPPARAMS dp; 644 DISPID id; 645 HRESULT hres; 646 647 hres = stack_pop_disp(ctx, &obj); 648 if(FAILED(hres)) 649 return hres; 650 651 if(!obj) { 652 FIXME("NULL obj\n"); 653 return E_FAIL; 654 } 655 656 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp); 657 658 hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id); 659 if(SUCCEEDED(hres)) 660 hres = disp_call(ctx->script, obj, id, &dp, res); 661 IDispatch_Release(obj); 662 if(FAILED(hres)) 663 return hres; 664 665 stack_popn(ctx, arg_cnt); 666 return S_OK; 667 } 668 669 static HRESULT interp_mcall(exec_ctx_t *ctx) 670 { 671 VARIANT res; 672 HRESULT hres; 673 674 TRACE("\n"); 675 676 hres = do_mcall(ctx, &res); 677 if(FAILED(hres)) 678 return hres; 679 680 return stack_push(ctx, &res); 681 } 682 683 static HRESULT interp_mcallv(exec_ctx_t *ctx) 684 { 685 TRACE("\n"); 686 687 return do_mcall(ctx, NULL); 688 } 689 690 static HRESULT assign_value(exec_ctx_t *ctx, VARIANT *dst, VARIANT *src, WORD flags) 691 { 692 HRESULT hres; 693 694 hres = VariantCopyInd(dst, src); 695 if(FAILED(hres)) 696 return hres; 697 698 if(V_VT(dst) == VT_DISPATCH && !(flags & DISPATCH_PROPERTYPUTREF)) { 699 VARIANT value; 700 701 hres = get_disp_value(ctx->script, V_DISPATCH(dst), &value); 702 IDispatch_Release(V_DISPATCH(dst)); 703 if(FAILED(hres)) 704 return hres; 705 706 *dst = value; 707 } 708 709 return S_OK; 710 } 711 712 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, WORD flags, DISPPARAMS *dp) 713 { 714 ref_t ref; 715 HRESULT hres; 716 717 hres = lookup_identifier(ctx, name, VBDISP_LET, &ref); 718 if(FAILED(hres)) 719 return hres; 720 721 switch(ref.type) { 722 case REF_VAR: { 723 VARIANT *v = ref.u.v; 724 725 if(V_VT(v) == (VT_VARIANT|VT_BYREF)) 726 v = V_VARIANTREF(v); 727 728 if(arg_cnt(dp)) { 729 SAFEARRAY *array; 730 731 if(!(V_VT(v) & VT_ARRAY)) { 732 FIXME("array assign on type %d\n", V_VT(v)); 733 return E_FAIL; 734 } 735 736 switch(V_VT(v)) { 737 case VT_ARRAY|VT_BYREF|VT_VARIANT: 738 array = *V_ARRAYREF(v); 739 break; 740 case VT_ARRAY|VT_VARIANT: 741 array = V_ARRAY(v); 742 break; 743 default: 744 FIXME("Unsupported array type %x\n", V_VT(v)); 745 return E_NOTIMPL; 746 } 747 748 if(!array) { 749 FIXME("null array\n"); 750 return E_FAIL; 751 } 752 753 hres = array_access(ctx, array, dp, &v); 754 if(FAILED(hres)) 755 return hres; 756 }else if(V_VT(v) == (VT_ARRAY|VT_BYREF|VT_VARIANT)) { 757 FIXME("non-array assign\n"); 758 return E_NOTIMPL; 759 } 760 761 hres = assign_value(ctx, v, dp->rgvarg, flags); 762 break; 763 } 764 case REF_DISP: 765 hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, flags, dp); 766 break; 767 case REF_FUNC: 768 FIXME("functions not implemented\n"); 769 return E_NOTIMPL; 770 case REF_OBJ: 771 FIXME("REF_OBJ\n"); 772 return E_NOTIMPL; 773 case REF_CONST: 774 FIXME("REF_CONST\n"); 775 return E_NOTIMPL; 776 case REF_NONE: 777 if(ctx->func->code_ctx->option_explicit) { 778 FIXME("throw exception\n"); 779 hres = E_FAIL; 780 }else { 781 VARIANT *new_var; 782 783 if(arg_cnt(dp)) { 784 FIXME("arg_cnt %d not supported\n", arg_cnt(dp)); 785 return E_NOTIMPL; 786 } 787 788 TRACE("creating variable %s\n", debugstr_w(name)); 789 hres = add_dynamic_var(ctx, name, FALSE, &new_var); 790 if(SUCCEEDED(hres)) 791 hres = assign_value(ctx, new_var, dp->rgvarg, flags); 792 } 793 } 794 795 return hres; 796 } 797 798 static HRESULT interp_assign_ident(exec_ctx_t *ctx) 799 { 800 const BSTR arg = ctx->instr->arg1.bstr; 801 const unsigned arg_cnt = ctx->instr->arg2.uint; 802 DISPPARAMS dp; 803 HRESULT hres; 804 805 TRACE("%s\n", debugstr_w(arg)); 806 807 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp); 808 hres = assign_ident(ctx, arg, DISPATCH_PROPERTYPUT, &dp); 809 if(FAILED(hres)) 810 return hres; 811 812 stack_popn(ctx, arg_cnt+1); 813 return S_OK; 814 } 815 816 static HRESULT interp_set_ident(exec_ctx_t *ctx) 817 { 818 const BSTR arg = ctx->instr->arg1.bstr; 819 const unsigned arg_cnt = ctx->instr->arg2.uint; 820 DISPPARAMS dp; 821 HRESULT hres; 822 823 TRACE("%s\n", debugstr_w(arg)); 824 825 if(arg_cnt) { 826 FIXME("arguments not supported\n"); 827 return E_NOTIMPL; 828 } 829 830 hres = stack_assume_disp(ctx, 0, NULL); 831 if(FAILED(hres)) 832 return hres; 833 834 vbstack_to_dp(ctx, 0, TRUE, &dp); 835 hres = assign_ident(ctx, ctx->instr->arg1.bstr, DISPATCH_PROPERTYPUTREF, &dp); 836 if(FAILED(hres)) 837 return hres; 838 839 stack_popn(ctx, 1); 840 return S_OK; 841 } 842 843 static HRESULT interp_assign_member(exec_ctx_t *ctx) 844 { 845 BSTR identifier = ctx->instr->arg1.bstr; 846 const unsigned arg_cnt = ctx->instr->arg2.uint; 847 IDispatch *obj; 848 DISPPARAMS dp; 849 DISPID id; 850 HRESULT hres; 851 852 TRACE("%s\n", debugstr_w(identifier)); 853 854 hres = stack_assume_disp(ctx, arg_cnt+1, &obj); 855 if(FAILED(hres)) 856 return hres; 857 858 if(!obj) { 859 FIXME("NULL obj\n"); 860 return E_FAIL; 861 } 862 863 hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id); 864 if(SUCCEEDED(hres)) { 865 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp); 866 hres = disp_propput(ctx->script, obj, id, DISPATCH_PROPERTYPUT, &dp); 867 } 868 if(FAILED(hres)) 869 return hres; 870 871 stack_popn(ctx, arg_cnt+2); 872 return S_OK; 873 } 874 875 static HRESULT interp_set_member(exec_ctx_t *ctx) 876 { 877 BSTR identifier = ctx->instr->arg1.bstr; 878 const unsigned arg_cnt = ctx->instr->arg2.uint; 879 IDispatch *obj; 880 DISPPARAMS dp; 881 DISPID id; 882 HRESULT hres; 883 884 TRACE("%s\n", debugstr_w(identifier)); 885 886 if(arg_cnt) { 887 FIXME("arguments not supported\n"); 888 return E_NOTIMPL; 889 } 890 891 hres = stack_assume_disp(ctx, 1, &obj); 892 if(FAILED(hres)) 893 return hres; 894 895 if(!obj) { 896 FIXME("NULL obj\n"); 897 return E_FAIL; 898 } 899 900 hres = stack_assume_disp(ctx, 0, NULL); 901 if(FAILED(hres)) 902 return hres; 903 904 hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id); 905 if(SUCCEEDED(hres)) { 906 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp); 907 hres = disp_propput(ctx->script, obj, id, DISPATCH_PROPERTYPUTREF, &dp); 908 } 909 if(FAILED(hres)) 910 return hres; 911 912 stack_popn(ctx, 2); 913 return S_OK; 914 } 915 916 static HRESULT interp_const(exec_ctx_t *ctx) 917 { 918 BSTR arg = ctx->instr->arg1.bstr; 919 VARIANT *v; 920 ref_t ref; 921 HRESULT hres; 922 923 TRACE("%s\n", debugstr_w(arg)); 924 925 assert(ctx->func->type == FUNC_GLOBAL); 926 927 hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref); 928 if(FAILED(hres)) 929 return hres; 930 931 if(ref.type != REF_NONE) { 932 FIXME("%s already defined\n", debugstr_w(arg)); 933 return E_FAIL; 934 } 935 936 hres = stack_assume_val(ctx, 0); 937 if(FAILED(hres)) 938 return hres; 939 940 hres = add_dynamic_var(ctx, arg, TRUE, &v); 941 if(FAILED(hres)) 942 return hres; 943 944 *v = *stack_pop(ctx); 945 return S_OK; 946 } 947 948 static HRESULT interp_val(exec_ctx_t *ctx) 949 { 950 variant_val_t val; 951 VARIANT v; 952 HRESULT hres; 953 954 TRACE("\n"); 955 956 hres = stack_pop_val(ctx, &val); 957 if(FAILED(hres)) 958 return hres; 959 960 if(!val.owned) { 961 V_VT(&v) = VT_EMPTY; 962 hres = VariantCopy(&v, val.v); 963 if(FAILED(hres)) 964 return hres; 965 } 966 967 return stack_push(ctx, val.owned ? val.v : &v); 968 } 969 970 static HRESULT interp_pop(exec_ctx_t *ctx) 971 { 972 const unsigned n = ctx->instr->arg1.uint; 973 974 TRACE("%u\n", n); 975 976 stack_popn(ctx, n); 977 return S_OK; 978 } 979 980 static HRESULT interp_new(exec_ctx_t *ctx) 981 { 982 const WCHAR *arg = ctx->instr->arg1.bstr; 983 class_desc_t *class_desc; 984 vbdisp_t *obj; 985 VARIANT v; 986 HRESULT hres; 987 988 static const WCHAR regexpW[] = {'r','e','g','e','x','p',0}; 989 990 TRACE("%s\n", debugstr_w(arg)); 991 992 if(!strcmpiW(arg, regexpW)) { 993 V_VT(&v) = VT_DISPATCH; 994 hres = create_regexp(&V_DISPATCH(&v)); 995 if(FAILED(hres)) 996 return hres; 997 998 return stack_push(ctx, &v); 999 } 1000 1001 for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) { 1002 if(!strcmpiW(class_desc->name, arg)) 1003 break; 1004 } 1005 if(!class_desc) { 1006 FIXME("Class %s not found\n", debugstr_w(arg)); 1007 return E_FAIL; 1008 } 1009 1010 hres = create_vbdisp(class_desc, &obj); 1011 if(FAILED(hres)) 1012 return hres; 1013 1014 V_VT(&v) = VT_DISPATCH; 1015 V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface; 1016 return stack_push(ctx, &v); 1017 } 1018 1019 static HRESULT interp_dim(exec_ctx_t *ctx) 1020 { 1021 const BSTR ident = ctx->instr->arg1.bstr; 1022 const unsigned array_id = ctx->instr->arg2.uint; 1023 const array_desc_t *array_desc; 1024 ref_t ref; 1025 HRESULT hres; 1026 1027 TRACE("%s\n", debugstr_w(ident)); 1028 1029 assert(array_id < ctx->func->array_cnt); 1030 if(!ctx->arrays) { 1031 ctx->arrays = heap_alloc_zero(ctx->func->array_cnt * sizeof(SAFEARRAY*)); 1032 if(!ctx->arrays) 1033 return E_OUTOFMEMORY; 1034 } 1035 1036 hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref); 1037 if(FAILED(hres)) { 1038 FIXME("lookup %s failed: %08x\n", debugstr_w(ident), hres); 1039 return hres; 1040 } 1041 1042 if(ref.type != REF_VAR) { 1043 FIXME("got ref.type = %d\n", ref.type); 1044 return E_FAIL; 1045 } 1046 1047 if(ctx->arrays[array_id]) { 1048 FIXME("Array already initialized\n"); 1049 return E_FAIL; 1050 } 1051 1052 array_desc = ctx->func->array_descs + array_id; 1053 if(array_desc->dim_cnt) { 1054 ctx->arrays[array_id] = SafeArrayCreate(VT_VARIANT, array_desc->dim_cnt, array_desc->bounds); 1055 if(!ctx->arrays[array_id]) 1056 return E_OUTOFMEMORY; 1057 } 1058 1059 V_VT(ref.u.v) = VT_ARRAY|VT_BYREF|VT_VARIANT; 1060 V_ARRAYREF(ref.u.v) = ctx->arrays+array_id; 1061 return S_OK; 1062 } 1063 1064 static HRESULT interp_step(exec_ctx_t *ctx) 1065 { 1066 const BSTR ident = ctx->instr->arg2.bstr; 1067 BOOL gteq_zero; 1068 VARIANT zero; 1069 ref_t ref; 1070 HRESULT hres; 1071 1072 TRACE("%s\n", debugstr_w(ident)); 1073 1074 V_VT(&zero) = VT_I2; 1075 V_I2(&zero) = 0; 1076 hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0); 1077 if(FAILED(hres)) 1078 return hres; 1079 1080 gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ; 1081 1082 hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref); 1083 if(FAILED(hres)) 1084 return hres; 1085 1086 if(ref.type != REF_VAR) { 1087 FIXME("%s is not REF_VAR\n", debugstr_w(ident)); 1088 return E_FAIL; 1089 } 1090 1091 hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0); 1092 if(FAILED(hres)) 1093 return hres; 1094 1095 if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT)) { 1096 ctx->instr++; 1097 }else { 1098 stack_popn(ctx, 2); 1099 instr_jmp(ctx, ctx->instr->arg1.uint); 1100 } 1101 return S_OK; 1102 } 1103 1104 static HRESULT interp_newenum(exec_ctx_t *ctx) 1105 { 1106 variant_val_t v; 1107 VARIANT *r; 1108 HRESULT hres; 1109 1110 TRACE("\n"); 1111 1112 stack_pop_deref(ctx, &v); 1113 assert(V_VT(stack_top(ctx, 0)) == VT_EMPTY); 1114 r = stack_top(ctx, 0); 1115 1116 switch(V_VT(v.v)) { 1117 case VT_DISPATCH|VT_BYREF: 1118 case VT_DISPATCH: { 1119 IEnumVARIANT *iter; 1120 DISPPARAMS dp = {0}; 1121 VARIANT iterv; 1122 1123 hres = disp_call(ctx->script, V_ISBYREF(v.v) ? *V_DISPATCHREF(v.v) : V_DISPATCH(v.v), DISPID_NEWENUM, &dp, &iterv); 1124 release_val(&v); 1125 if(FAILED(hres)) 1126 return hres; 1127 1128 if(V_VT(&iterv) != VT_UNKNOWN && V_VT(&iterv) != VT_DISPATCH) { 1129 FIXME("Unsupported iterv %s\n", debugstr_variant(&iterv)); 1130 VariantClear(&iterv); 1131 return hres; 1132 } 1133 1134 hres = IUnknown_QueryInterface(V_UNKNOWN(&iterv), &IID_IEnumVARIANT, (void**)&iter); 1135 IUnknown_Release(V_UNKNOWN(&iterv)); 1136 if(FAILED(hres)) { 1137 FIXME("Could not get IEnumVARIANT iface: %08x\n", hres); 1138 return hres; 1139 } 1140 1141 V_VT(r) = VT_UNKNOWN; 1142 V_UNKNOWN(r) = (IUnknown*)iter; 1143 break; 1144 } 1145 case VT_VARIANT|VT_ARRAY: 1146 case VT_VARIANT|VT_ARRAY|VT_BYREF: { 1147 IEnumVARIANT *iter; 1148 1149 hres = create_safearray_iter(V_ISBYREF(v.v) ? *V_ARRAYREF(v.v) : V_ARRAY(v.v), &iter); 1150 if(FAILED(hres)) 1151 return hres; 1152 1153 V_VT(r) = VT_UNKNOWN; 1154 V_UNKNOWN(r) = (IUnknown*)iter; 1155 break; 1156 } 1157 default: 1158 FIXME("Unsupported for %s\n", debugstr_variant(v.v)); 1159 release_val(&v); 1160 return E_NOTIMPL; 1161 } 1162 1163 return S_OK; 1164 } 1165 1166 static HRESULT interp_enumnext(exec_ctx_t *ctx) 1167 { 1168 const unsigned loop_end = ctx->instr->arg1.uint; 1169 const BSTR ident = ctx->instr->arg2.bstr; 1170 VARIANT v; 1171 DISPPARAMS dp = {&v, &propput_dispid, 1, 1}; 1172 IEnumVARIANT *iter; 1173 BOOL do_continue; 1174 HRESULT hres; 1175 1176 TRACE("\n"); 1177 1178 if(V_VT(stack_top(ctx, 0)) == VT_EMPTY) { 1179 FIXME("uninitialized\n"); 1180 return E_FAIL; 1181 } 1182 1183 assert(V_VT(stack_top(ctx, 0)) == VT_UNKNOWN); 1184 iter = (IEnumVARIANT*)V_UNKNOWN(stack_top(ctx, 0)); 1185 1186 V_VT(&v) = VT_EMPTY; 1187 hres = IEnumVARIANT_Next(iter, 1, &v, NULL); 1188 if(FAILED(hres)) 1189 return hres; 1190 1191 do_continue = hres == S_OK; 1192 hres = assign_ident(ctx, ident, DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &dp); 1193 VariantClear(&v); 1194 if(FAILED(hres)) 1195 return hres; 1196 1197 if(do_continue) { 1198 ctx->instr++; 1199 }else { 1200 stack_popn(ctx, 1); 1201 instr_jmp(ctx, loop_end); 1202 } 1203 return S_OK; 1204 } 1205 1206 static HRESULT interp_jmp(exec_ctx_t *ctx) 1207 { 1208 const unsigned arg = ctx->instr->arg1.uint; 1209 1210 TRACE("%u\n", arg); 1211 1212 instr_jmp(ctx, arg); 1213 return S_OK; 1214 } 1215 1216 static HRESULT interp_jmp_false(exec_ctx_t *ctx) 1217 { 1218 const unsigned arg = ctx->instr->arg1.uint; 1219 HRESULT hres; 1220 BOOL b; 1221 1222 TRACE("%u\n", arg); 1223 1224 hres = stack_pop_bool(ctx, &b); 1225 if(FAILED(hres)) 1226 return hres; 1227 1228 if(b) 1229 ctx->instr++; 1230 else 1231 instr_jmp(ctx, ctx->instr->arg1.uint); 1232 return S_OK; 1233 } 1234 1235 static HRESULT interp_jmp_true(exec_ctx_t *ctx) 1236 { 1237 const unsigned arg = ctx->instr->arg1.uint; 1238 HRESULT hres; 1239 BOOL b; 1240 1241 TRACE("%u\n", arg); 1242 1243 hres = stack_pop_bool(ctx, &b); 1244 if(FAILED(hres)) 1245 return hres; 1246 1247 if(b) 1248 instr_jmp(ctx, ctx->instr->arg1.uint); 1249 else 1250 ctx->instr++; 1251 return S_OK; 1252 } 1253 1254 static HRESULT interp_ret(exec_ctx_t *ctx) 1255 { 1256 TRACE("\n"); 1257 1258 ctx->instr = NULL; 1259 return S_OK; 1260 } 1261 1262 static HRESULT interp_stop(exec_ctx_t *ctx) 1263 { 1264 WARN("\n"); 1265 1266 /* NOTE: this should have effect in debugging mode (that we don't support yet) */ 1267 return S_OK; 1268 } 1269 1270 static HRESULT interp_me(exec_ctx_t *ctx) 1271 { 1272 VARIANT v; 1273 1274 TRACE("\n"); 1275 1276 IDispatch_AddRef(ctx->this_obj); 1277 V_VT(&v) = VT_DISPATCH; 1278 V_DISPATCH(&v) = ctx->this_obj; 1279 return stack_push(ctx, &v); 1280 } 1281 1282 static HRESULT interp_bool(exec_ctx_t *ctx) 1283 { 1284 const VARIANT_BOOL arg = ctx->instr->arg1.lng; 1285 VARIANT v; 1286 1287 TRACE("%s\n", arg ? "true" : "false"); 1288 1289 V_VT(&v) = VT_BOOL; 1290 V_BOOL(&v) = arg; 1291 return stack_push(ctx, &v); 1292 } 1293 1294 static HRESULT interp_errmode(exec_ctx_t *ctx) 1295 { 1296 const int err_mode = ctx->instr->arg1.uint; 1297 1298 TRACE("%d\n", err_mode); 1299 1300 ctx->resume_next = err_mode; 1301 ctx->script->err_number = S_OK; 1302 return S_OK; 1303 } 1304 1305 static HRESULT interp_string(exec_ctx_t *ctx) 1306 { 1307 VARIANT v; 1308 1309 TRACE("\n"); 1310 1311 V_VT(&v) = VT_BSTR; 1312 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str); 1313 if(!V_BSTR(&v)) 1314 return E_OUTOFMEMORY; 1315 1316 return stack_push(ctx, &v); 1317 } 1318 1319 static HRESULT interp_long(exec_ctx_t *ctx) 1320 { 1321 const LONG arg = ctx->instr->arg1.lng; 1322 VARIANT v; 1323 1324 TRACE("%d\n", arg); 1325 1326 V_VT(&v) = VT_I4; 1327 V_I4(&v) = arg; 1328 return stack_push(ctx, &v); 1329 } 1330 1331 static HRESULT interp_short(exec_ctx_t *ctx) 1332 { 1333 const LONG arg = ctx->instr->arg1.lng; 1334 VARIANT v; 1335 1336 TRACE("%d\n", arg); 1337 1338 V_VT(&v) = VT_I2; 1339 V_I2(&v) = arg; 1340 return stack_push(ctx, &v); 1341 } 1342 1343 static HRESULT interp_double(exec_ctx_t *ctx) 1344 { 1345 const DOUBLE *arg = ctx->instr->arg1.dbl; 1346 VARIANT v; 1347 1348 TRACE("%lf\n", *arg); 1349 1350 V_VT(&v) = VT_R8; 1351 V_R8(&v) = *arg; 1352 return stack_push(ctx, &v); 1353 } 1354 1355 static HRESULT interp_empty(exec_ctx_t *ctx) 1356 { 1357 VARIANT v; 1358 1359 TRACE("\n"); 1360 1361 V_VT(&v) = VT_EMPTY; 1362 return stack_push(ctx, &v); 1363 } 1364 1365 static HRESULT interp_null(exec_ctx_t *ctx) 1366 { 1367 TRACE("\n"); 1368 return stack_push_null(ctx); 1369 } 1370 1371 static HRESULT interp_nothing(exec_ctx_t *ctx) 1372 { 1373 VARIANT v; 1374 1375 TRACE("\n"); 1376 1377 V_VT(&v) = VT_DISPATCH; 1378 V_DISPATCH(&v) = NULL; 1379 return stack_push(ctx, &v); 1380 } 1381 1382 static HRESULT interp_hres(exec_ctx_t *ctx) 1383 { 1384 const unsigned arg = ctx->instr->arg1.uint; 1385 VARIANT v; 1386 1387 TRACE("%d\n", arg); 1388 1389 V_VT(&v) = VT_ERROR; 1390 V_ERROR(&v) = arg; 1391 return stack_push(ctx, &v); 1392 } 1393 1394 static HRESULT interp_not(exec_ctx_t *ctx) 1395 { 1396 variant_val_t val; 1397 VARIANT v; 1398 HRESULT hres; 1399 1400 TRACE("\n"); 1401 1402 hres = stack_pop_val(ctx, &val); 1403 if(FAILED(hres)) 1404 return hres; 1405 1406 hres = VarNot(val.v, &v); 1407 release_val(&val); 1408 if(FAILED(hres)) 1409 return hres; 1410 1411 return stack_push(ctx, &v); 1412 } 1413 1414 static HRESULT interp_and(exec_ctx_t *ctx) 1415 { 1416 variant_val_t r, l; 1417 VARIANT v; 1418 HRESULT hres; 1419 1420 TRACE("\n"); 1421 1422 hres = stack_pop_val(ctx, &r); 1423 if(FAILED(hres)) 1424 return hres; 1425 1426 hres = stack_pop_val(ctx, &l); 1427 if(SUCCEEDED(hres)) { 1428 hres = VarAnd(l.v, r.v, &v); 1429 release_val(&l); 1430 } 1431 release_val(&r); 1432 if(FAILED(hres)) 1433 return hres; 1434 1435 return stack_push(ctx, &v); 1436 } 1437 1438 static HRESULT interp_or(exec_ctx_t *ctx) 1439 { 1440 variant_val_t r, l; 1441 VARIANT v; 1442 HRESULT hres; 1443 1444 TRACE("\n"); 1445 1446 hres = stack_pop_val(ctx, &r); 1447 if(FAILED(hres)) 1448 return hres; 1449 1450 hres = stack_pop_val(ctx, &l); 1451 if(SUCCEEDED(hres)) { 1452 hres = VarOr(l.v, r.v, &v); 1453 release_val(&l); 1454 } 1455 release_val(&r); 1456 if(FAILED(hres)) 1457 return hres; 1458 1459 return stack_push(ctx, &v); 1460 } 1461 1462 static HRESULT interp_xor(exec_ctx_t *ctx) 1463 { 1464 variant_val_t r, l; 1465 VARIANT v; 1466 HRESULT hres; 1467 1468 TRACE("\n"); 1469 1470 hres = stack_pop_val(ctx, &r); 1471 if(FAILED(hres)) 1472 return hres; 1473 1474 hres = stack_pop_val(ctx, &l); 1475 if(SUCCEEDED(hres)) { 1476 hres = VarXor(l.v, r.v, &v); 1477 release_val(&l); 1478 } 1479 release_val(&r); 1480 if(FAILED(hres)) 1481 return hres; 1482 1483 return stack_push(ctx, &v); 1484 } 1485 1486 static HRESULT interp_eqv(exec_ctx_t *ctx) 1487 { 1488 variant_val_t r, l; 1489 VARIANT v; 1490 HRESULT hres; 1491 1492 TRACE("\n"); 1493 1494 hres = stack_pop_val(ctx, &r); 1495 if(FAILED(hres)) 1496 return hres; 1497 1498 hres = stack_pop_val(ctx, &l); 1499 if(SUCCEEDED(hres)) { 1500 hres = VarEqv(l.v, r.v, &v); 1501 release_val(&l); 1502 } 1503 release_val(&r); 1504 if(FAILED(hres)) 1505 return hres; 1506 1507 return stack_push(ctx, &v); 1508 } 1509 1510 static HRESULT interp_imp(exec_ctx_t *ctx) 1511 { 1512 variant_val_t r, l; 1513 VARIANT v; 1514 HRESULT hres; 1515 1516 TRACE("\n"); 1517 1518 hres = stack_pop_val(ctx, &r); 1519 if(FAILED(hres)) 1520 return hres; 1521 1522 hres = stack_pop_val(ctx, &l); 1523 if(SUCCEEDED(hres)) { 1524 hres = VarImp(l.v, r.v, &v); 1525 release_val(&l); 1526 } 1527 release_val(&r); 1528 if(FAILED(hres)) 1529 return hres; 1530 1531 return stack_push(ctx, &v); 1532 } 1533 1534 static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r) 1535 { 1536 TRACE("%s %s\n", debugstr_variant(l), debugstr_variant(r)); 1537 1538 /* FIXME: Fix comparing string to number */ 1539 1540 return VarCmp(l, r, ctx->script->lcid, 0); 1541 } 1542 1543 static HRESULT cmp_oper(exec_ctx_t *ctx) 1544 { 1545 variant_val_t l, r; 1546 HRESULT hres; 1547 1548 hres = stack_pop_val(ctx, &r); 1549 if(FAILED(hres)) 1550 return hres; 1551 1552 hres = stack_pop_val(ctx, &l); 1553 if(SUCCEEDED(hres)) { 1554 hres = var_cmp(ctx, l.v, r.v); 1555 release_val(&l); 1556 } 1557 1558 release_val(&r); 1559 return hres; 1560 } 1561 1562 static HRESULT interp_equal(exec_ctx_t *ctx) 1563 { 1564 VARIANT v; 1565 HRESULT hres; 1566 1567 TRACE("\n"); 1568 1569 hres = cmp_oper(ctx); 1570 if(FAILED(hres)) 1571 return hres; 1572 if(hres == VARCMP_NULL) 1573 return stack_push_null(ctx); 1574 1575 V_VT(&v) = VT_BOOL; 1576 V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE; 1577 return stack_push(ctx, &v); 1578 } 1579 1580 static HRESULT interp_nequal(exec_ctx_t *ctx) 1581 { 1582 VARIANT v; 1583 HRESULT hres; 1584 1585 TRACE("\n"); 1586 1587 hres = cmp_oper(ctx); 1588 if(FAILED(hres)) 1589 return hres; 1590 if(hres == VARCMP_NULL) 1591 return stack_push_null(ctx); 1592 1593 V_VT(&v) = VT_BOOL; 1594 V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE; 1595 return stack_push(ctx, &v); 1596 } 1597 1598 static HRESULT interp_gt(exec_ctx_t *ctx) 1599 { 1600 VARIANT v; 1601 HRESULT hres; 1602 1603 TRACE("\n"); 1604 1605 hres = cmp_oper(ctx); 1606 if(FAILED(hres)) 1607 return hres; 1608 if(hres == VARCMP_NULL) 1609 return stack_push_null(ctx); 1610 1611 V_VT(&v) = VT_BOOL; 1612 V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE; 1613 return stack_push(ctx, &v); 1614 } 1615 1616 static HRESULT interp_gteq(exec_ctx_t *ctx) 1617 { 1618 VARIANT v; 1619 HRESULT hres; 1620 1621 TRACE("\n"); 1622 1623 hres = cmp_oper(ctx); 1624 if(FAILED(hres)) 1625 return hres; 1626 if(hres == VARCMP_NULL) 1627 return stack_push_null(ctx); 1628 1629 V_VT(&v) = VT_BOOL; 1630 V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE; 1631 return stack_push(ctx, &v); 1632 } 1633 1634 static HRESULT interp_lt(exec_ctx_t *ctx) 1635 { 1636 VARIANT v; 1637 HRESULT hres; 1638 1639 TRACE("\n"); 1640 1641 hres = cmp_oper(ctx); 1642 if(FAILED(hres)) 1643 return hres; 1644 if(hres == VARCMP_NULL) 1645 return stack_push_null(ctx); 1646 1647 V_VT(&v) = VT_BOOL; 1648 V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE; 1649 return stack_push(ctx, &v); 1650 } 1651 1652 static HRESULT interp_lteq(exec_ctx_t *ctx) 1653 { 1654 VARIANT v; 1655 HRESULT hres; 1656 1657 TRACE("\n"); 1658 1659 hres = cmp_oper(ctx); 1660 if(FAILED(hres)) 1661 return hres; 1662 if(hres == VARCMP_NULL) 1663 return stack_push_null(ctx); 1664 1665 V_VT(&v) = VT_BOOL; 1666 V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE; 1667 return stack_push(ctx, &v); 1668 } 1669 1670 static HRESULT interp_case(exec_ctx_t *ctx) 1671 { 1672 const unsigned arg = ctx->instr->arg1.uint; 1673 variant_val_t v; 1674 HRESULT hres; 1675 1676 TRACE("%d\n", arg); 1677 1678 hres = stack_pop_val(ctx, &v); 1679 if(FAILED(hres)) 1680 return hres; 1681 1682 hres = var_cmp(ctx, stack_top(ctx, 0), v.v); 1683 release_val(&v); 1684 if(FAILED(hres)) 1685 return hres; 1686 1687 if(hres == VARCMP_EQ) { 1688 stack_popn(ctx, 1); 1689 instr_jmp(ctx, arg); 1690 }else { 1691 ctx->instr++; 1692 } 1693 1694 return S_OK; 1695 } 1696 1697 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret) 1698 { 1699 IObjectIdentity *identity; 1700 IUnknown *unk1, *unk2; 1701 HRESULT hres; 1702 1703 if(disp1 == disp2) { 1704 *ret = VARIANT_TRUE; 1705 return S_OK; 1706 } 1707 1708 if(!disp1 || !disp2) { 1709 *ret = VARIANT_FALSE; 1710 return S_OK; 1711 } 1712 1713 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1); 1714 if(FAILED(hres)) 1715 return hres; 1716 1717 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2); 1718 if(FAILED(hres)) { 1719 IUnknown_Release(unk1); 1720 return hres; 1721 } 1722 1723 if(unk1 == unk2) { 1724 *ret = VARIANT_TRUE; 1725 }else { 1726 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity); 1727 if(SUCCEEDED(hres)) { 1728 hres = IObjectIdentity_IsEqualObject(identity, unk2); 1729 IObjectIdentity_Release(identity); 1730 *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE; 1731 }else { 1732 *ret = VARIANT_FALSE; 1733 } 1734 } 1735 1736 IUnknown_Release(unk1); 1737 IUnknown_Release(unk2); 1738 return S_OK; 1739 } 1740 1741 static HRESULT interp_is(exec_ctx_t *ctx) 1742 { 1743 IDispatch *l, *r; 1744 VARIANT v; 1745 HRESULT hres; 1746 1747 TRACE("\n"); 1748 1749 hres = stack_pop_disp(ctx, &r); 1750 if(FAILED(hres)) 1751 return hres; 1752 1753 hres = stack_pop_disp(ctx, &l); 1754 if(SUCCEEDED(hres)) { 1755 V_VT(&v) = VT_BOOL; 1756 hres = disp_cmp(l, r, &V_BOOL(&v)); 1757 if(l) 1758 IDispatch_Release(l); 1759 } 1760 if(r) 1761 IDispatch_Release(r); 1762 if(FAILED(hres)) 1763 return hres; 1764 1765 return stack_push(ctx, &v); 1766 } 1767 1768 static HRESULT interp_concat(exec_ctx_t *ctx) 1769 { 1770 variant_val_t r, l; 1771 VARIANT v; 1772 HRESULT hres; 1773 1774 TRACE("\n"); 1775 1776 hres = stack_pop_val(ctx, &r); 1777 if(FAILED(hres)) 1778 return hres; 1779 1780 hres = stack_pop_val(ctx, &l); 1781 if(SUCCEEDED(hres)) { 1782 hres = VarCat(l.v, r.v, &v); 1783 release_val(&l); 1784 } 1785 release_val(&r); 1786 if(FAILED(hres)) 1787 return hres; 1788 1789 return stack_push(ctx, &v); 1790 } 1791 1792 static HRESULT interp_add(exec_ctx_t *ctx) 1793 { 1794 variant_val_t r, l; 1795 VARIANT v; 1796 HRESULT hres; 1797 1798 TRACE("\n"); 1799 1800 hres = stack_pop_val(ctx, &r); 1801 if(FAILED(hres)) 1802 return hres; 1803 1804 hres = stack_pop_val(ctx, &l); 1805 if(SUCCEEDED(hres)) { 1806 hres = VarAdd(l.v, r.v, &v); 1807 release_val(&l); 1808 } 1809 release_val(&r); 1810 if(FAILED(hres)) 1811 return hres; 1812 1813 return stack_push(ctx, &v); 1814 } 1815 1816 static HRESULT interp_sub(exec_ctx_t *ctx) 1817 { 1818 variant_val_t r, l; 1819 VARIANT v; 1820 HRESULT hres; 1821 1822 TRACE("\n"); 1823 1824 hres = stack_pop_val(ctx, &r); 1825 if(FAILED(hres)) 1826 return hres; 1827 1828 hres = stack_pop_val(ctx, &l); 1829 if(SUCCEEDED(hres)) { 1830 hres = VarSub(l.v, r.v, &v); 1831 release_val(&l); 1832 } 1833 release_val(&r); 1834 if(FAILED(hres)) 1835 return hres; 1836 1837 return stack_push(ctx, &v); 1838 } 1839 1840 static HRESULT interp_mod(exec_ctx_t *ctx) 1841 { 1842 variant_val_t r, l; 1843 VARIANT v; 1844 HRESULT hres; 1845 1846 TRACE("\n"); 1847 1848 hres = stack_pop_val(ctx, &r); 1849 if(FAILED(hres)) 1850 return hres; 1851 1852 hres = stack_pop_val(ctx, &l); 1853 if(SUCCEEDED(hres)) { 1854 hres = VarMod(l.v, r.v, &v); 1855 release_val(&l); 1856 } 1857 release_val(&r); 1858 if(FAILED(hres)) 1859 return hres; 1860 1861 return stack_push(ctx, &v); 1862 } 1863 1864 static HRESULT interp_idiv(exec_ctx_t *ctx) 1865 { 1866 variant_val_t r, l; 1867 VARIANT v; 1868 HRESULT hres; 1869 1870 TRACE("\n"); 1871 1872 hres = stack_pop_val(ctx, &r); 1873 if(FAILED(hres)) 1874 return hres; 1875 1876 hres = stack_pop_val(ctx, &l); 1877 if(SUCCEEDED(hres)) { 1878 hres = VarIdiv(l.v, r.v, &v); 1879 release_val(&l); 1880 } 1881 release_val(&r); 1882 if(FAILED(hres)) 1883 return hres; 1884 1885 return stack_push(ctx, &v); 1886 } 1887 1888 static HRESULT interp_div(exec_ctx_t *ctx) 1889 { 1890 variant_val_t r, l; 1891 VARIANT v; 1892 HRESULT hres; 1893 1894 TRACE("\n"); 1895 1896 hres = stack_pop_val(ctx, &r); 1897 if(FAILED(hres)) 1898 return hres; 1899 1900 hres = stack_pop_val(ctx, &l); 1901 if(SUCCEEDED(hres)) { 1902 hres = VarDiv(l.v, r.v, &v); 1903 release_val(&l); 1904 } 1905 release_val(&r); 1906 if(FAILED(hres)) 1907 return hres; 1908 1909 return stack_push(ctx, &v); 1910 } 1911 1912 static HRESULT interp_mul(exec_ctx_t *ctx) 1913 { 1914 variant_val_t r, l; 1915 VARIANT v; 1916 HRESULT hres; 1917 1918 TRACE("\n"); 1919 1920 hres = stack_pop_val(ctx, &r); 1921 if(FAILED(hres)) 1922 return hres; 1923 1924 hres = stack_pop_val(ctx, &l); 1925 if(SUCCEEDED(hres)) { 1926 hres = VarMul(l.v, r.v, &v); 1927 release_val(&l); 1928 } 1929 release_val(&r); 1930 if(FAILED(hres)) 1931 return hres; 1932 1933 return stack_push(ctx, &v); 1934 } 1935 1936 static HRESULT interp_exp(exec_ctx_t *ctx) 1937 { 1938 variant_val_t r, l; 1939 VARIANT v; 1940 HRESULT hres; 1941 1942 TRACE("\n"); 1943 1944 hres = stack_pop_val(ctx, &r); 1945 if(FAILED(hres)) 1946 return hres; 1947 1948 hres = stack_pop_val(ctx, &l); 1949 if(SUCCEEDED(hres)) { 1950 hres = VarPow(l.v, r.v, &v); 1951 release_val(&l); 1952 } 1953 release_val(&r); 1954 if(FAILED(hres)) 1955 return hres; 1956 1957 return stack_push(ctx, &v); 1958 } 1959 1960 static HRESULT interp_neg(exec_ctx_t *ctx) 1961 { 1962 variant_val_t val; 1963 VARIANT v; 1964 HRESULT hres; 1965 1966 hres = stack_pop_val(ctx, &val); 1967 if(FAILED(hres)) 1968 return hres; 1969 1970 hres = VarNeg(val.v, &v); 1971 release_val(&val); 1972 if(FAILED(hres)) 1973 return hres; 1974 1975 return stack_push(ctx, &v); 1976 } 1977 1978 static HRESULT interp_incc(exec_ctx_t *ctx) 1979 { 1980 const BSTR ident = ctx->instr->arg1.bstr; 1981 VARIANT v; 1982 ref_t ref; 1983 HRESULT hres; 1984 1985 TRACE("\n"); 1986 1987 hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref); 1988 if(FAILED(hres)) 1989 return hres; 1990 1991 if(ref.type != REF_VAR) { 1992 FIXME("ref.type is not REF_VAR\n"); 1993 return E_FAIL; 1994 } 1995 1996 hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v); 1997 if(FAILED(hres)) 1998 return hres; 1999 2000 VariantClear(ref.u.v); 2001 *ref.u.v = v; 2002 return S_OK; 2003 } 2004 2005 static HRESULT interp_catch(exec_ctx_t *ctx) 2006 { 2007 /* Nothing to do here, the OP is for unwinding only. */ 2008 return S_OK; 2009 } 2010 2011 static const instr_func_t op_funcs[] = { 2012 #define X(x,n,a,b) interp_ ## x, 2013 OP_LIST 2014 #undef X 2015 }; 2016 2017 static const unsigned op_move[] = { 2018 #define X(x,n,a,b) n, 2019 OP_LIST 2020 #undef X 2021 }; 2022 2023 void release_dynamic_vars(dynamic_var_t *var) 2024 { 2025 while(var) { 2026 VariantClear(&var->v); 2027 var = var->next; 2028 } 2029 } 2030 2031 static void release_exec(exec_ctx_t *ctx) 2032 { 2033 unsigned i; 2034 2035 VariantClear(&ctx->ret_val); 2036 release_dynamic_vars(ctx->dynamic_vars); 2037 2038 if(ctx->this_obj) 2039 IDispatch_Release(ctx->this_obj); 2040 2041 if(ctx->args) { 2042 for(i=0; i < ctx->func->arg_cnt; i++) 2043 VariantClear(ctx->args+i); 2044 } 2045 2046 if(ctx->vars) { 2047 for(i=0; i < ctx->func->var_cnt; i++) 2048 VariantClear(ctx->vars+i); 2049 } 2050 2051 if(ctx->arrays) { 2052 for(i=0; i < ctx->func->var_cnt; i++) { 2053 if(ctx->arrays[i]) 2054 SafeArrayDestroy(ctx->arrays[i]); 2055 } 2056 heap_free(ctx->arrays); 2057 } 2058 2059 heap_pool_free(&ctx->heap); 2060 heap_free(ctx->args); 2061 heap_free(ctx->vars); 2062 heap_free(ctx->stack); 2063 } 2064 2065 HRESULT exec_script(script_ctx_t *ctx, function_t *func, vbdisp_t *vbthis, DISPPARAMS *dp, VARIANT *res) 2066 { 2067 exec_ctx_t exec = {func->code_ctx}; 2068 vbsop_t op; 2069 HRESULT hres = S_OK; 2070 2071 exec.code = func->code_ctx; 2072 2073 if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) { 2074 FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt); 2075 return E_FAIL; 2076 } 2077 2078 heap_pool_init(&exec.heap); 2079 2080 if(func->arg_cnt) { 2081 VARIANT *v; 2082 unsigned i; 2083 2084 exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT)); 2085 if(!exec.args) { 2086 release_exec(&exec); 2087 return E_OUTOFMEMORY; 2088 } 2089 2090 for(i=0; i < func->arg_cnt; i++) { 2091 v = get_arg(dp, i); 2092 if(V_VT(v) == (VT_VARIANT|VT_BYREF)) { 2093 if(func->args[i].by_ref) 2094 exec.args[i] = *v; 2095 else 2096 hres = VariantCopyInd(exec.args+i, V_VARIANTREF(v)); 2097 }else { 2098 hres = VariantCopyInd(exec.args+i, v); 2099 } 2100 if(FAILED(hres)) { 2101 release_exec(&exec); 2102 return hres; 2103 } 2104 } 2105 }else { 2106 exec.args = NULL; 2107 } 2108 2109 if(func->var_cnt) { 2110 exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT)); 2111 if(!exec.vars) { 2112 release_exec(&exec); 2113 return E_OUTOFMEMORY; 2114 } 2115 }else { 2116 exec.vars = NULL; 2117 } 2118 2119 exec.stack_size = 16; 2120 exec.top = 0; 2121 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT)); 2122 if(!exec.stack) { 2123 release_exec(&exec); 2124 return E_OUTOFMEMORY; 2125 } 2126 2127 if(vbthis) { 2128 exec.this_obj = (IDispatch*)&vbthis->IDispatchEx_iface; 2129 exec.vbthis = vbthis; 2130 }else if (ctx->host_global) { 2131 exec.this_obj = ctx->host_global; 2132 }else { 2133 exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface; 2134 } 2135 IDispatch_AddRef(exec.this_obj); 2136 2137 exec.instr = exec.code->instrs + func->code_off; 2138 exec.script = ctx; 2139 exec.func = func; 2140 2141 while(exec.instr) { 2142 op = exec.instr->op; 2143 hres = op_funcs[op](&exec); 2144 if(FAILED(hres)) { 2145 ctx->err_number = hres = map_hres(hres); 2146 2147 if(exec.resume_next) { 2148 unsigned stack_off; 2149 2150 WARN("Failed %08x in resume next mode\n", hres); 2151 2152 /* 2153 * Unwinding here is simple. We need to find the next OP_catch, which contains 2154 * information about expected stack size and jump offset on error. Generated 2155 * bytecode needs to guarantee, that simple jump and stack adjustment will 2156 * guarantee proper execution continuation. 2157 */ 2158 while((++exec.instr)->op != OP_catch); 2159 2160 TRACE("unwind jmp %d stack_off %d\n", exec.instr->arg1.uint, exec.instr->arg2.uint); 2161 2162 stack_off = exec.instr->arg2.uint; 2163 instr_jmp(&exec, exec.instr->arg1.uint); 2164 2165 if(exec.top > stack_off) { 2166 stack_popn(&exec, exec.top-stack_off); 2167 }else if(exec.top < stack_off) { 2168 VARIANT v; 2169 2170 V_VT(&v) = VT_EMPTY; 2171 while(exec.top < stack_off) { 2172 hres = stack_push(&exec, &v); 2173 if(FAILED(hres)) 2174 break; 2175 } 2176 } 2177 2178 continue; 2179 }else { 2180 WARN("Failed %08x\n", hres); 2181 stack_popn(&exec, exec.top); 2182 break; 2183 } 2184 } 2185 2186 exec.instr += op_move[op]; 2187 } 2188 2189 assert(!exec.top); 2190 if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET) 2191 assert(V_VT(&exec.ret_val) == VT_EMPTY); 2192 2193 if(SUCCEEDED(hres) && res) { 2194 *res = exec.ret_val; 2195 V_VT(&exec.ret_val) = VT_EMPTY; 2196 } 2197 2198 release_exec(&exec); 2199 return hres; 2200 } 2201