static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) { jsdisp_t *obj; VARIANT *arg_var; DWORD i; HRESULT hres; TRACE("\n"); switch(flags) { case DISPATCH_METHOD: case DISPATCH_CONSTRUCT: { if(arg_cnt(dp) == 1 && V_VT((arg_var = get_arg(dp, 0))) == VT_I4) { if(V_I4(arg_var) < 0) return throw_range_error(ctx, ei, JS_E_INVALID_LENGTH, NULL); hres = create_array(ctx, V_I4(arg_var), &obj); if(FAILED(hres)) return hres; var_set_jsdisp(retv, obj); return S_OK; } hres = create_array(ctx, arg_cnt(dp), &obj); if(FAILED(hres)) return hres; for(i=0; i < arg_cnt(dp); i++) { hres = jsdisp_propput_idx(obj, i, get_arg(dp, i), ei); if(FAILED(hres)) break; } if(FAILED(hres)) { jsdisp_release(obj); return hres; } var_set_jsdisp(retv, obj); break; } default: FIXME("unimplemented flags: %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT Function_arguments(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) { FunctionInstance *function = (FunctionInstance*)jsthis->u.jsdisp; HRESULT hres = S_OK; TRACE("\n"); switch(flags) { case DISPATCH_PROPERTYGET: { if(function->arguments) { jsdisp_addref(function->arguments); var_set_jsdisp(retv, function->arguments); }else { V_VT(retv) = VT_NULL; } break; } case DISPATCH_PROPERTYPUT: break; default: FIXME("unimplemented flags %x\n", flags); hres = E_NOTIMPL; } return hres; }
static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) { jsdisp_t *this_obj; VARIANT var; HRESULT hres; hres = create_object(ctx, &function->dispex, &this_obj); if(FAILED(hres)) return hres; hres = invoke_source(ctx, function, to_disp(this_obj), dp, &var, ei, caller); if(FAILED(hres)) { jsdisp_release(this_obj); return hres; } if(V_VT(&var) == VT_DISPATCH) { jsdisp_release(this_obj); V_VT(retv) = VT_DISPATCH; V_DISPATCH(retv) = V_DISPATCH(&var); }else { VariantClear(&var); var_set_jsdisp(retv, this_obj); } return S_OK; }
static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) { jsdisp_t *jsthis; DWORD length, k, l; VARIANT v1, v2; HRESULT hres1, hres2; TRACE("\n"); hres1 = get_length(ctx, vthis, ei, &jsthis, &length); if(FAILED(hres1)) return hres1; for(k=0; k<length/2; k++) { l = length-k-1; hres1 = jsdisp_get_idx(jsthis, k, &v1, ei); if(FAILED(hres1) && hres1!=DISP_E_UNKNOWNNAME) return hres1; hres2 = jsdisp_get_idx(jsthis, l, &v2, ei); if(FAILED(hres2) && hres2!=DISP_E_UNKNOWNNAME) { VariantClear(&v1); return hres2; } if(hres1 == DISP_E_UNKNOWNNAME) hres1 = jsdisp_delete_idx(jsthis, l); else hres1 = jsdisp_propput_idx(jsthis, l, &v1, ei); if(FAILED(hres1)) { VariantClear(&v1); VariantClear(&v2); return hres1; } if(hres2 == DISP_E_UNKNOWNNAME) hres2 = jsdisp_delete_idx(jsthis, k); else hres2 = jsdisp_propput_idx(jsthis, k, &v2, ei); if(FAILED(hres2)) { VariantClear(&v2); return hres2; } } if(retv) { jsdisp_addref(jsthis); var_set_jsdisp(retv, jsthis); } return S_OK; }
static HRESULT constructor_call(jsdisp_t *constr, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) { if(flags != DISPATCH_PROPERTYGET) return jsdisp_call_value(constr, flags, dp, retv, ei); jsdisp_addref(constr); var_set_jsdisp(retv, constr); return S_OK; }
static HRESULT set_prototype(script_ctx_t *ctx, jsdisp_t *dispex, jsdisp_t *prototype) { jsexcept_t jsexcept; VARIANT var; var_set_jsdisp(&var, prototype); memset(&jsexcept, 0, sizeof(jsexcept)); return jsdisp_propput_name(dispex, prototypeW, &var, &jsexcept, NULL/*FIXME*/); }
static HRESULT NumberConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) { VARIANT num; HRESULT hres; TRACE("\n"); switch(flags) { case INVOKE_FUNC: if(!arg_cnt(dp)) { if(retv) { V_VT(retv) = VT_I4; V_I4(retv) = 0; } return S_OK; } hres = to_number(ctx, get_arg(dp, 0), ei, &num); if(FAILED(hres)) return hres; if(retv) *retv = num; break; case DISPATCH_CONSTRUCT: { jsdisp_t *obj; if(arg_cnt(dp)) { hres = to_number(ctx, get_arg(dp, 0), ei, &num); if(FAILED(hres)) return hres; }else { V_VT(&num) = VT_I4; V_I4(&num) = 0; } hres = create_number(ctx, &num, &obj); if(FAILED(hres)) return hres; var_set_jsdisp(retv, obj); break; } default: FIXME("unimplemented flags %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) { jsdisp_t *ret; DWORD len = 0; HRESULT hres; TRACE("\n"); hres = create_array(ctx, 0, &ret); if(FAILED(hres)) return hres; hres = concat_obj(ret, jsthis->u.disp, &len, ei); if(SUCCEEDED(hres)) { VARIANT *arg; DWORD i; for(i=0; i < arg_cnt(dp); i++) { arg = get_arg(dp, i); if(V_VT(arg) == VT_DISPATCH) hres = concat_obj(ret, V_DISPATCH(arg), &len, ei); else hres = jsdisp_propput_idx(ret, len++, arg, ei); if(FAILED(hres)) break; } } if(FAILED(hres)) return hres; if(retv) var_set_jsdisp(retv, ret); else jsdisp_release(ret); return S_OK; }
static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, jsdisp_t *arg_disp, DISPPARAMS *dp, jsexcept_t *ei, IServiceProvider *caller, jsdisp_t **ret) { jsdisp_t *var_disp; VARIANT var; HRESULT hres; hres = create_dispex(ctx, NULL, NULL, &var_disp); if(FAILED(hres)) return hres; var_set_jsdisp(&var, arg_disp); hres = jsdisp_propput_name(var_disp, argumentsW, &var, ei, caller); if(SUCCEEDED(hres)) hres = init_parameters(var_disp, function, dp, ei, caller); if(FAILED(hres)) { jsdisp_release(var_disp); return hres; } *ret = var_disp; return S_OK; }
/* ECMA-262 3rd Edition 15.4.4.12 */ static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) { DWORD length, start=0, delete_cnt=0, argc, i, add_args = 0; jsdisp_t *ret_array = NULL, *jsthis; VARIANT v; double d; int n; HRESULT hres = S_OK; TRACE("\n"); hres = get_length(ctx, vthis, ei, &jsthis, &length); if(FAILED(hres)) return hres; argc = arg_cnt(dp); if(argc >= 1) { hres = to_integer(ctx, get_arg(dp,0), ei, &d); if(FAILED(hres)) return hres; if(is_int32(d)) { if((n = d) >= 0) start = min(n, length); else start = -n > length ? 0 : length + n; }else { start = d < 0.0 ? 0 : length; } } if(argc >= 2) { hres = to_integer(ctx, get_arg(dp,1), ei, &d); if(FAILED(hres)) return hres; if(is_int32(d)) { if((n = d) > 0) delete_cnt = min(n, length-start); }else if(d > 0.0) { delete_cnt = length-start; } add_args = argc-2; } if(retv) { hres = create_array(ctx, 0, &ret_array); if(FAILED(hres)) return hres; for(i=0; SUCCEEDED(hres) && i < delete_cnt; i++) { hres = jsdisp_get_idx(jsthis, start+i, &v, ei); if(hres == DISP_E_UNKNOWNNAME) hres = S_OK; else if(SUCCEEDED(hres)) hres = jsdisp_propput_idx(ret_array, i, &v, ei); } if(SUCCEEDED(hres)) { V_VT(&v) = VT_I4; V_I4(&v) = delete_cnt; hres = jsdisp_propput_name(ret_array, lengthW, &v, ei); } } if(add_args < delete_cnt) { for(i = start; SUCCEEDED(hres) && i < length-delete_cnt; i++) { hres = jsdisp_get_idx(jsthis, i+delete_cnt, &v, ei); if(hres == DISP_E_UNKNOWNNAME) hres = jsdisp_delete_idx(jsthis, i+add_args); else if(SUCCEEDED(hres)) hres = jsdisp_propput_idx(jsthis, i+add_args, &v, ei); } for(i=length; SUCCEEDED(hres) && i != length-delete_cnt+add_args; i--) hres = jsdisp_delete_idx(jsthis, i-1); }else if(add_args > delete_cnt) { for(i=length-delete_cnt; SUCCEEDED(hres) && i != start; i--) { hres = jsdisp_get_idx(jsthis, i+delete_cnt-1, &v, ei); if(hres == DISP_E_UNKNOWNNAME) hres = jsdisp_delete_idx(jsthis, i+add_args-1); else if(SUCCEEDED(hres)) hres = jsdisp_propput_idx(jsthis, i+add_args-1, &v, ei); } } for(i=0; SUCCEEDED(hres) && i < add_args; i++) hres = jsdisp_propput_idx(jsthis, start+i, get_arg(dp,i+2), ei); if(SUCCEEDED(hres)) { V_VT(&v) = VT_I4; V_I4(&v) = length-delete_cnt+add_args; hres = jsdisp_propput_name(jsthis, lengthW, &v, ei); } if(FAILED(hres)) { if(ret_array) jsdisp_release(ret_array); return hres; } if(retv) var_set_jsdisp(retv, ret_array); return S_OK; }
/* ECMA-262 3rd Edition 15.4.4.11 */ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) { jsdisp_t *jsthis, *cmp_func = NULL; VARIANT *vtab, **sorttab = NULL; DWORD length; DWORD i; HRESULT hres = S_OK; TRACE("\n"); hres = get_length(ctx, vthis, ei, &jsthis, &length); if(FAILED(hres)) return hres; if(arg_cnt(dp) > 1) { WARN("invalid arg_cnt %d\n", arg_cnt(dp)); return E_FAIL; } if(arg_cnt(dp) == 1) { VARIANT *arg = get_arg(dp, 0); if(V_VT(arg) != VT_DISPATCH) { WARN("arg is not dispatch\n"); return E_FAIL; } cmp_func = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg)); if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) { WARN("cmp_func is not a function\n"); if(cmp_func) jsdisp_release(cmp_func); return E_FAIL; } } if(!length) { if(cmp_func) jsdisp_release(cmp_func); if(retv) { jsdisp_addref(jsthis); var_set_jsdisp(retv, jsthis); } return S_OK; } vtab = heap_alloc_zero(length * sizeof(VARIANT)); if(vtab) { for(i=0; i<length; i++) { hres = jsdisp_get_idx(jsthis, i, vtab+i, ei); if(hres == DISP_E_UNKNOWNNAME) { V_VT(vtab+i) = VT_EMPTY; hres = S_OK; } else if(FAILED(hres)) { WARN("Could not get elem %d: %08x\n", i, hres); break; } } }else { hres = E_OUTOFMEMORY; } if(SUCCEEDED(hres)) { sorttab = heap_alloc(length*2*sizeof(VARIANT*)); if(!sorttab) hres = E_OUTOFMEMORY; } /* merge-sort */ if(SUCCEEDED(hres)) { VARIANT *tmpv, **tmpbuf; INT cmp; tmpbuf = sorttab + length; for(i=0; i < length; i++) sorttab[i] = vtab+i; for(i=0; i < length/2; i++) { hres = sort_cmp(ctx, cmp_func, sorttab[2*i+1], sorttab[2*i], ei, &cmp); if(FAILED(hres)) break; if(cmp < 0) { tmpv = sorttab[2*i]; sorttab[2*i] = sorttab[2*i+1]; sorttab[2*i+1] = tmpv; } } if(SUCCEEDED(hres)) { DWORD k, a, b, bend; for(k=2; k < length; k *= 2) { for(i=0; i+k < length; i += 2*k) { a = b = 0; if(i+2*k <= length) bend = k; else bend = length - (i+k); memcpy(tmpbuf, sorttab+i, k*sizeof(VARIANT*)); while(a < k && b < bend) { hres = sort_cmp(ctx, cmp_func, tmpbuf[a], sorttab[i+k+b], ei, &cmp); if(FAILED(hres)) break; if(cmp < 0) { sorttab[i+a+b] = tmpbuf[a]; a++; }else { sorttab[i+a+b] = sorttab[i+k+b]; b++; } } if(FAILED(hres)) break; if(a < k) memcpy(sorttab+i+a+b, tmpbuf+a, (k-a)*sizeof(VARIANT*)); } if(FAILED(hres)) break; } } for(i=0; SUCCEEDED(hres) && i < length; i++) hres = jsdisp_propput_idx(jsthis, i, sorttab[i], ei); } if(vtab) { for(i=0; i < length; i++) VariantClear(vtab+i); heap_free(vtab); } heap_free(sorttab); if(cmp_func) jsdisp_release(cmp_func); if(FAILED(hres)) return hres; if(retv) { jsdisp_addref(jsthis); var_set_jsdisp(retv, jsthis); } return S_OK; }
/* ECMA-262 3rd Edition 15.4.4.10 */ static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei) { jsdisp_t *arr, *jsthis; DOUBLE range; DWORD length, start, end, idx; HRESULT hres; TRACE("\n"); hres = get_length(ctx, vthis, ei, &jsthis, &length); if(FAILED(hres)) return hres; if(arg_cnt(dp)) { hres = to_number(ctx, get_arg(dp, 0), ei, &range); if(FAILED(hres)) return hres; range = floor(range); if(-range>length || isnan(range)) start = 0; else if(range < 0) start = range+length; else if(range <= length) start = range; else start = length; } else start = 0; if(arg_cnt(dp)>1) { hres = to_number(ctx, get_arg(dp, 1), ei, &range); if(FAILED(hres)) return hres; range = floor(range); if(-range>length) end = 0; else if(range < 0) end = range+length; else if(range <= length) end = range; else end = length; } else end = length; hres = create_array(ctx, (end>start)?end-start:0, &arr); if(FAILED(hres)) return hres; for(idx=start; idx<end; idx++) { VARIANT v; hres = jsdisp_get_idx(jsthis, idx, &v, ei); if(hres == DISP_E_UNKNOWNNAME) continue; if(SUCCEEDED(hres)) { hres = jsdisp_propput_idx(arr, idx-start, &v, ei); VariantClear(&v); } if(FAILED(hres)) { jsdisp_release(arr); return hres; } } if(retv) var_set_jsdisp(retv, arr); else jsdisp_release(arr); return S_OK; }