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