static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, DISPPARAMS *dp, jsexcept_t *ei, IServiceProvider *caller, DispatchEx **ret) { DispatchEx *var_disp, *arg_disp; HRESULT hres; static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0}; hres = create_dispex(ctx, NULL, NULL, &var_disp); if(FAILED(hres)) return hres; hres = create_arguments(ctx, (IDispatch*)_IDispatchEx_(&function->dispex), dp, ei, caller, &arg_disp); if(SUCCEEDED(hres)) { VARIANT var; V_VT(&var) = VT_DISPATCH; V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(arg_disp); hres = jsdisp_propput_name(var_disp, argumentsW, &var, ei, caller); jsdisp_release(arg_disp); } 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; }
static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *var_disp, *arg_disp; exec_ctx_t *exec_ctx; scope_chain_t *scope; HRESULT hres; if(ctx->state == SCRIPTSTATE_UNINITIALIZED || ctx->state == SCRIPTSTATE_CLOSED) { WARN("Script engine state does not allow running code.\n"); return E_UNEXPECTED; } if(!function->func_code) { FIXME("no source\n"); return E_FAIL; } hres = create_var_disp(ctx, function, argc, argv, &var_disp); if(FAILED(hres)) return hres; hres = create_arguments(ctx, function, var_disp, argc, argv, &arg_disp); if(FAILED(hres)) { jsdisp_release(var_disp); return hres; } hres = jsdisp_propput(var_disp, argumentsW, PROPF_DONTDELETE, jsval_obj(arg_disp)); if(FAILED(hres)) { jsdisp_release(arg_disp); jsdisp_release(var_disp); return hres; } hres = scope_push(function->scope_chain, var_disp, to_disp(var_disp), &scope); if(SUCCEEDED(hres)) { hres = create_exec_ctx(ctx, this_obj, var_disp, scope, FALSE, &exec_ctx); scope_release(scope); if(SUCCEEDED(hres)) { jsdisp_t *prev_args; prev_args = function->arguments; function->arguments = arg_disp; hres = exec_source(exec_ctx, function->code, function->func_code, FALSE, r); function->arguments = prev_args; exec_release(exec_ctx); } } /* Reset arguments value to cut the reference cycle. Note that since all activation contexts have * their own arguments property, it's impossible to use prototype's one during name lookup */ jsdisp_propput_name(var_disp, argumentsW, jsval_undefined()); jsdisp_release(arg_disp); jsdisp_release(var_disp); return hres; }
static HRESULT create_error(script_ctx_t *ctx, jsdisp_t *constr, UINT number, jsstr_t *msg, jsdisp_t **ret) { jsdisp_t *err; HRESULT hres; hres = alloc_error(ctx, NULL, constr, &err); if(FAILED(hres)) return hres; hres = jsdisp_propput_dontenum(err, numberW, jsval_number((INT)number)); if(FAILED(hres)) { jsdisp_release(err); return hres; } hres = jsdisp_propput_name(err, messageW, jsval_string(msg)); if(SUCCEEDED(hres)) hres = jsdisp_propput_dontenum(err, descriptionW, jsval_string(msg)); if(FAILED(hres)) { jsdisp_release(err); return hres; } *ret = err; return S_OK; }
static HRESULT create_arguments(script_ctx_t *ctx, IDispatch *calee, DISPPARAMS *dp, jsexcept_t *ei, IServiceProvider *caller, DispatchEx **ret) { DispatchEx *args; VARIANT var; DWORD i; HRESULT hres; static const WCHAR caleeW[] = {'c','a','l','l','e','e',0}; args = heap_alloc_zero(sizeof(DispatchEx)); if(!args) return E_OUTOFMEMORY; hres = init_dispex_from_constr(args, ctx, &Arguments_info, ctx->object_constr); if(FAILED(hres)) { heap_free(args); return hres; } for(i=0; i < arg_cnt(dp); i++) { hres = jsdisp_propput_idx(args, i, get_arg(dp,i), ei, caller); if(FAILED(hres)) break; } if(SUCCEEDED(hres)) { V_VT(&var) = VT_I4; V_I4(&var) = arg_cnt(dp); hres = jsdisp_propput_name(args, lengthW, &var, ei, caller); if(SUCCEEDED(hres)) { V_VT(&var) = VT_DISPATCH; V_DISPATCH(&var) = calee; hres = jsdisp_propput_name(args, caleeW, &var, ei, caller); } } if(FAILED(hres)) { jsdisp_release(args); return hres; } *ret = args; return S_OK; }
static HRESULT set_length(jsdisp_t *obj, DWORD length) { if(is_class(obj, JSCLASS_ARRAY)) { ((ArrayInstance*)obj)->length = length; return S_OK; } return jsdisp_propput_name(obj, lengthW, jsval_number(length)); }
HRESULT jsdisp_propput_idx(DispatchEx *obj, DWORD idx, LCID lcid, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller) { WCHAR buf[12]; static const WCHAR formatW[] = {'%','d',0}; sprintfW(buf, formatW, idx); return jsdisp_propput_name(obj, buf, lcid, val, ei, caller); }
static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) { ArgumentsInstance *arguments = (ArgumentsInstance*)jsdisp; TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); /* FIXME: Accessing by name won't work for duplicated argument names */ return jsdisp_propput_name(arguments->var_obj, arguments->function->func_code->params[idx], val); }
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 set_prototype(script_ctx_t *ctx, DispatchEx *dispex, DispatchEx *prototype) { jsexcept_t jsexcept; VARIANT var; V_VT(&var) = VT_DISPATCH; V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(prototype); memset(&jsexcept, 0, sizeof(jsexcept)); return jsdisp_propput_name(dispex, prototypeW, &var, &jsexcept, NULL/*FIXME*/); }
static HRESULT set_length(jsdisp_t *obj, jsexcept_t *ei, DWORD length) { VARIANT var; if(is_class(obj, JSCLASS_ARRAY)) { ((ArrayInstance*)obj)->length = length; return S_OK; } V_VT(&var) = VT_I4; V_I4(&var) = length; return jsdisp_propput_name(obj, lengthW, &var, ei); }
static HRESULT create_arguments(script_ctx_t *ctx, IDispatch *calee, unsigned argc, jsval_t *argv, jsdisp_t **ret) { jsdisp_t *args; DWORD i; HRESULT hres; static const WCHAR caleeW[] = {'c','a','l','l','e','e',0}; args = heap_alloc_zero(sizeof(jsdisp_t)); if(!args) return E_OUTOFMEMORY; hres = init_dispex_from_constr(args, ctx, &Arguments_info, ctx->object_constr); if(FAILED(hres)) { heap_free(args); return hres; } for(i=0; i < argc; i++) { hres = jsdisp_propput_idx(args, i, argv[i]); if(FAILED(hres)) break; } if(SUCCEEDED(hres)) { hres = jsdisp_propput_name(args, lengthW, jsval_number(argc)); if(SUCCEEDED(hres)) hres = jsdisp_propput_name(args, caleeW, jsval_disp(calee)); } if(FAILED(hres)) { jsdisp_release(args); return hres; } *ret = args; return S_OK; }
HRESULT init_error_constr(script_ctx_t *ctx, DispatchEx *object_prototype) { static const WCHAR ErrorW[] = {'E','r','r','o','r',0}; static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0}; static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0}; static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0}; static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0}; static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0}; static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0}; static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0}; static const WCHAR *names[] = {ErrorW, EvalErrorW, RangeErrorW, ReferenceErrorW, RegExpErrorW, SyntaxErrorW, TypeErrorW, URIErrorW}; DispatchEx **constr_addr[] = {&ctx->error_constr, &ctx->eval_error_constr, &ctx->range_error_constr, &ctx->reference_error_constr, &ctx->regexp_error_constr, &ctx->syntax_error_constr, &ctx->type_error_constr, &ctx->uri_error_constr}; static builtin_invoke_t constr_val[] = {ErrorConstr_value, EvalErrorConstr_value, RangeErrorConstr_value, ReferenceErrorConstr_value, RegExpErrorConstr_value, SyntaxErrorConstr_value, TypeErrorConstr_value, URIErrorConstr_value}; ErrorInstance *err; INT i; VARIANT v; HRESULT hres; for(i=0; i < sizeof(names)/sizeof(names[0]); i++) { hres = alloc_error(ctx, i==0 ? object_prototype : NULL, NULL, &err); if(FAILED(hres)) return hres; V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(names[i]); if(!V_BSTR(&v)) { jsdisp_release(&err->dispex); return E_OUTOFMEMORY; } hres = jsdisp_propput_name(&err->dispex, nameW, &v, NULL/*FIXME*/, NULL/*FIXME*/); if(SUCCEEDED(hres)) hres = create_builtin_function(ctx, constr_val[i], names[i], NULL, PROPF_CONSTR|1, &err->dispex, constr_addr[i]); jsdisp_release(&err->dispex); VariantClear(&v); if(FAILED(hres)) return hres; } return S_OK; }
static HRESULT init_parameters(jsdisp_t *var_disp, FunctionInstance *function, unsigned argc, jsval_t *argv) { DWORD i=0; HRESULT hres; for(i=0; i < function->func_code->param_cnt; i++) { hres = jsdisp_propput_name(var_disp, function->func_code->params[i], i < argc ? argv[i] : jsval_undefined()); if(FAILED(hres)) return hres; } return S_OK; }
static HRESULT init_arguments(DispatchEx *arg_disp, FunctionInstance *function, LCID lcid, DISPPARAMS *dp, jsexcept_t *ei, IServiceProvider *caller) { VARIANT var; DWORD i; HRESULT hres; for(i=0; i < dp->cArgs-dp->cNamedArgs; i++) { hres = jsdisp_propput_idx(arg_disp, i, lcid, dp->rgvarg+dp->cArgs-1-i, ei, caller); if(FAILED(hres)) return hres; } V_VT(&var) = VT_I4; V_I4(&var) = dp->cArgs - dp->cNamedArgs; return jsdisp_propput_name(arg_disp, lengthW, lcid, &var, ei, caller); }
static HRESULT init_parameters(jsdisp_t *var_disp, FunctionInstance *function, DISPPARAMS *dp, jsexcept_t *ei) { VARIANT var_empty; DWORD cargs, i=0; HRESULT hres; V_VT(&var_empty) = VT_EMPTY; cargs = arg_cnt(dp); for(i=0; i < function->func_code->param_cnt; i++) { hres = jsdisp_propput_name(var_disp, function->func_code->params[i], i < cargs ? get_arg(dp,i) : &var_empty, ei); if(FAILED(hres)) return hres; } return S_OK; }
static HRESULT create_var_disp(script_ctx_t *ctx, FunctionInstance *function, jsdisp_t *arg_disp, unsigned argc, jsval_t *argv, jsdisp_t **ret) { jsdisp_t *var_disp; HRESULT hres; hres = create_dispex(ctx, NULL, NULL, &var_disp); if(FAILED(hres)) return hres; hres = jsdisp_propput_name(var_disp, argumentsW, jsval_obj(arg_disp)); if(SUCCEEDED(hres)) hres = init_parameters(var_disp, function, argc, argv); if(FAILED(hres)) { jsdisp_release(var_disp); return hres; } *ret = var_disp; return S_OK; }
static HRESULT init_parameters(DispatchEx *var_disp, FunctionInstance *function, DISPPARAMS *dp, jsexcept_t *ei, IServiceProvider *caller) { parameter_t *param; VARIANT var_empty; DWORD cargs, i=0; HRESULT hres; V_VT(&var_empty) = VT_EMPTY; cargs = arg_cnt(dp); for(param = function->parameters; param; param = param->next) { hres = jsdisp_propput_name(var_disp, param->identifier, i < cargs ? get_arg(dp,i) : &var_empty, ei, caller); if(FAILED(hres)) return hres; i++; } 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; }
static HRESULT create_function(script_ctx_t *ctx, DWORD flags, BOOL funcprot, DispatchEx *prototype, FunctionInstance **ret) { FunctionInstance *function; HRESULT hres; function = heap_alloc_zero(sizeof(FunctionInstance)); if(!function) return E_OUTOFMEMORY; if(funcprot) hres = init_dispex(&function->dispex, ctx, &Function_info, prototype); else hres = init_dispex_from_constr(&function->dispex, ctx, &Function_info, ctx->function_constr); if(FAILED(hres)) return hres; function->flags = flags; function->length = flags & PROPF_ARGMASK; if(prototype) { jsexcept_t jsexcept; VARIANT var; V_VT(&var) = VT_DISPATCH; V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(prototype); memset(&jsexcept, 0, sizeof(jsexcept)); hres = jsdisp_propput_name(&function->dispex, prototypeW, ctx->lcid, &var, &jsexcept, NULL/*FIXME*/); if(FAILED(hres)) { IDispatchEx_Release(_IDispatchEx_(&function->dispex)); return hres; } } *ret = function; return S_OK; }
static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input, const match_state_t *result, IDispatch **ret) { jsdisp_t *array; jsstr_t *str; DWORD i; HRESULT hres = S_OK; static const WCHAR indexW[] = {'i','n','d','e','x',0}; static const WCHAR inputW[] = {'i','n','p','u','t',0}; static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0}; static const WCHAR zeroW[] = {'0',0}; hres = create_array(ctx, result->paren_count+1, &array); if(FAILED(hres)) return hres; for(i=0; i < result->paren_count; i++) { if(result->parens[i].index != -1) str = jsstr_substr(input, result->parens[i].index, result->parens[i].length); else str = jsstr_empty(); if(!str) { hres = E_OUTOFMEMORY; break; } hres = jsdisp_propput_idx(array, i+1, jsval_string(str)); jsstr_release(str); if(FAILED(hres)) break; } while(SUCCEEDED(hres)) { hres = jsdisp_propput_name(array, indexW, jsval_number(result->cp-input->str-result->match_len)); if(FAILED(hres)) break; hres = jsdisp_propput_name(array, lastIndexW, jsval_number(result->cp-input->str)); if(FAILED(hres)) break; hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr_addref(input))); if(FAILED(hres)) break; str = jsstr_alloc_len(result->cp-result->match_len, result->match_len); if(!str) { hres = E_OUTOFMEMORY; break; } hres = jsdisp_propput_name(array, zeroW, jsval_string(str)); jsstr_release(str); break; } if(FAILED(hres)) { jsdisp_release(array); return hres; } *ret = to_disp(array); return S_OK; }
HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *str, jsval_t *r) { static const WCHAR indexW[] = {'i','n','d','e','x',0}; static const WCHAR inputW[] = {'i','n','p','u','t',0}; static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0}; RegExpInstance *regexp = (RegExpInstance*)re; match_result_t *match_result; unsigned match_cnt, i; jsdisp_t *array; HRESULT hres; if(!(regexp->jsregexp->flags & REG_GLOB)) { match_state_t *match; heap_pool_t *mark; mark = heap_pool_mark(&ctx->tmp_heap); match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, str->str); if(!match) { heap_pool_clear(mark); return E_OUTOFMEMORY; } hres = regexp_match_next(ctx, ®exp->dispex, 0, str, &match); if(FAILED(hres)) { heap_pool_clear(mark); return hres; } if(r) { if(hres == S_OK) { IDispatch *ret; hres = create_match_array(ctx, str, match, &ret); if(SUCCEEDED(hres)) *r = jsval_disp(ret); }else { *r = jsval_null(); } } heap_pool_clear(mark); return S_OK; } hres = regexp_match(ctx, ®exp->dispex, str, FALSE, &match_result, &match_cnt); if(FAILED(hres)) return hres; if(!match_cnt) { TRACE("no match\n"); if(r) *r = jsval_null(); return S_OK; } hres = create_array(ctx, match_cnt, &array); if(FAILED(hres)) return hres; for(i=0; i < match_cnt; i++) { jsstr_t *tmp_str; tmp_str = jsstr_substr(str, match_result[i].index, match_result[i].length); if(!tmp_str) { hres = E_OUTOFMEMORY; break; } hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str)); jsstr_release(tmp_str); if(FAILED(hres)) break; } while(SUCCEEDED(hres)) { hres = jsdisp_propput_name(array, indexW, jsval_number(match_result[match_cnt-1].index)); if(FAILED(hres)) break; hres = jsdisp_propput_name(array, lastIndexW, jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length)); if(FAILED(hres)) break; hres = jsdisp_propput_name(array, inputW, jsval_string(str)); break; } heap_free(match_result); if(SUCCEEDED(hres) && r) *r = jsval_obj(array); else jsdisp_release(array); return hres; }
/* ECMA-262 5.1 Edition 15.12.1.2 */ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r) { HRESULT hres; switch(skip_spaces(ctx)) { /* JSONNullLiteral */ case 'n': if(!is_keyword(ctx, nullW)) break; *r = jsval_null(); return S_OK; /* JSONBooleanLiteral */ case 't': if(!is_keyword(ctx, trueW)) break; *r = jsval_bool(TRUE); return S_OK; case 'f': if(!is_keyword(ctx, falseW)) break; *r = jsval_bool(FALSE); return S_OK; /* JSONObject */ case '{': { WCHAR *prop_name; jsdisp_t *obj; jsval_t val; hres = create_object(ctx->ctx, NULL, &obj); if(FAILED(hres)) return hres; ctx->ptr++; if(skip_spaces(ctx) == '}') { ctx->ptr++; *r = jsval_obj(obj); return S_OK; } while(1) { if(*ctx->ptr != '"') break; hres = parse_json_string(ctx, &prop_name); if(FAILED(hres)) break; if(skip_spaces(ctx) != ':') { FIXME("missing ':'\n"); heap_free(prop_name); break; } ctx->ptr++; hres = parse_json_value(ctx, &val); if(SUCCEEDED(hres)) { hres = jsdisp_propput_name(obj, prop_name, val); jsval_release(val); } heap_free(prop_name); if(FAILED(hres)) break; if(skip_spaces(ctx) == '}') { ctx->ptr++; *r = jsval_obj(obj); return S_OK; } if(*ctx->ptr++ != ',') { FIXME("expected ','\n"); break; } skip_spaces(ctx); } jsdisp_release(obj); break; } /* JSONString */ case '"': { WCHAR *string; jsstr_t *str; hres = parse_json_string(ctx, &string); if(FAILED(hres)) return hres; /* FIXME: avoid reallocation */ str = jsstr_alloc(string); heap_free(string); if(!str) return E_OUTOFMEMORY; *r = jsval_string(str); return S_OK; } /* JSONArray */ case '[': { jsdisp_t *array; unsigned i = 0; jsval_t val; hres = create_array(ctx->ctx, 0, &array); if(FAILED(hres)) return hres; ctx->ptr++; if(skip_spaces(ctx) == ']') { ctx->ptr++; *r = jsval_obj(array); return S_OK; } while(1) { hres = parse_json_value(ctx, &val); if(FAILED(hres)) break; hres = jsdisp_propput_idx(array, i, val); jsval_release(val); if(FAILED(hres)) break; if(skip_spaces(ctx) == ']') { ctx->ptr++; *r = jsval_obj(array); return S_OK; } if(*ctx->ptr != ',') { FIXME("expected ','\n"); break; } ctx->ptr++; i++; } jsdisp_release(array); break; } /* JSONNumber */ default: { int sign = 1; double n; if(*ctx->ptr == '-') { sign = -1; ctx->ptr++; skip_spaces(ctx); } if(!isdigitW(*ctx->ptr)) break; if(*ctx->ptr == '0') { ctx->ptr++; n = 0; if(is_identifier_char(*ctx->ptr)) break; }else { hres = parse_decimal(&ctx->ptr, ctx->end, &n); if(FAILED(hres)) return hres; } *r = jsval_number(sign*n); return S_OK; } } FIXME("Syntax error at %s\n", debugstr_w(ctx->ptr)); return E_FAIL; }
/* 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.12 */ static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DWORD length, start=0, delete_cnt=0, i, add_args = 0; jsdisp_t *ret_array = NULL, *jsthis; jsval_t val; double d; int n; HRESULT hres = S_OK; TRACE("\n"); hres = get_length(ctx, vthis, &jsthis, &length); if(FAILED(hres)) return hres; if(argc) { hres = to_integer(ctx, argv[0], &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, argv[1], &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(r) { 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, &val); if(hres == DISP_E_UNKNOWNNAME) { hres = S_OK; }else if(SUCCEEDED(hres)) { hres = jsdisp_propput_idx(ret_array, i, val); jsval_release(val); } } if(SUCCEEDED(hres)) hres = jsdisp_propput_name(ret_array, lengthW, jsval_number(delete_cnt)); } if(add_args < delete_cnt) { for(i = start; SUCCEEDED(hres) && i < length-delete_cnt; i++) { hres = jsdisp_get_idx(jsthis, i+delete_cnt, &val); 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, val); jsval_release(val); } } 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, &val); 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, val); jsval_release(val); } } } for(i=0; SUCCEEDED(hres) && i < add_args; i++) hres = jsdisp_propput_idx(jsthis, start+i, argv[i+2]); if(SUCCEEDED(hres)) hres = jsdisp_propput_name(jsthis, lengthW, jsval_number(length-delete_cnt+add_args)); if(FAILED(hres)) { if(ret_array) jsdisp_release(ret_array); return hres; } if(r) *r = jsval_obj(ret_array); return S_OK; }
static inline HRESULT set_prototype(script_ctx_t *ctx, jsdisp_t *dispex, jsdisp_t *prototype) { return jsdisp_propput_name(dispex, prototypeW, jsval_obj(prototype)); }