static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); switch(flags) { case DISPATCH_METHOD: if(argc) { if(is_object_instance(argv[0])) { jsdisp_t *jsdisp = iface_to_jsdisp((IUnknown*)get_object(argv[0])); if(jsdisp) { if(is_class(jsdisp, JSCLASS_REGEXP)) { if(argc > 1 && !is_undefined(argv[1])) { jsdisp_release(jsdisp); return throw_regexp_error(ctx, JS_E_REGEXP_SYNTAX, NULL); } if(r) *r = jsval_obj(jsdisp); else jsdisp_release(jsdisp); return S_OK; } jsdisp_release(jsdisp); } } } /* fall through */ case DISPATCH_CONSTRUCT: { jsdisp_t *ret; HRESULT hres; if(!argc) { FIXME("no args\n"); return E_NOTIMPL; } hres = create_regexp_var(ctx, argv[0], argc > 1 ? argv+1 : NULL, &ret); if(FAILED(hres)) return hres; if(r) *r = jsval_obj(ret); else jsdisp_release(ret); return S_OK; } default: FIXME("unimplemented flags: %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *obj; DWORD i; HRESULT hres; TRACE("\n"); switch(flags) { case DISPATCH_METHOD: case DISPATCH_CONSTRUCT: { if(argc == 1 && is_number(argv[0])) { double n = get_number(argv[0]); if(n < 0 || !is_int32(n)) return throw_range_error(ctx, JS_E_INVALID_LENGTH, NULL); hres = create_array(ctx, n, &obj); if(FAILED(hres)) return hres; *r = jsval_obj(obj); return S_OK; } hres = create_array(ctx, argc, &obj); if(FAILED(hres)) return hres; for(i=0; i < argc; i++) { hres = jsdisp_propput_idx(obj, i, argv[i]); if(FAILED(hres)) break; } if(FAILED(hres)) { jsdisp_release(obj); return hres; } *r = jsval_obj(obj); break; } default: FIXME("unimplemented flags: %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT maybe_to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *r) { jsdisp_t *obj; HRESULT hres; if(!is_object_instance(val) || !get_object(val) || !(obj = iface_to_jsdisp((IUnknown*)get_object(val)))) return jsval_copy(val, r); if(is_class(obj, JSCLASS_NUMBER)) { double n; hres = to_number(ctx, val, &n); jsdisp_release(obj); if(SUCCEEDED(hres)) *r = jsval_number(n); return hres; } if(is_class(obj, JSCLASS_STRING)) { jsstr_t *str; hres = to_string(ctx, val, &str); jsdisp_release(obj); if(SUCCEEDED(hres)) *r = jsval_string(str); return hres; } if(is_class(obj, JSCLASS_BOOLEAN)) { *r = jsval_bool(bool_obj_value(obj)); jsdisp_release(obj); return S_OK; } *r = jsval_obj(obj); 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 throw_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str, jsdisp_t *constr) { WCHAR buf[1024], *pos = NULL; jsdisp_t *err; jsstr_t *msg; HRESULT hres; if(!is_jscript_error(error)) return error; buf[0] = '\0'; LoadStringW(jscript_hinstance, HRESULT_CODE(error), buf, sizeof(buf)/sizeof(WCHAR)); if(str) pos = strchrW(buf, '|'); if(pos) { int len = strlenW(str); memmove(pos+len, pos+1, (strlenW(pos+1)+1)*sizeof(WCHAR)); memcpy(pos, str, len*sizeof(WCHAR)); } WARN("%s\n", debugstr_w(buf)); msg = jsstr_alloc(buf); if(!msg) return E_OUTOFMEMORY; hres = create_error(ctx, constr, error, msg, &err); jsstr_release(msg); if(FAILED(hres)) return hres; jsval_release(ctx->ei.val); ctx->ei.val = jsval_obj(err); return error; }
static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *obj; HRESULT hres; TRACE("\n"); switch(flags) { case DISPATCH_CONSTRUCT: { if (argc > 1) return throw_syntax_error(ctx, JS_E_INVALIDARG, NULL); hres = create_enumerator(ctx, (argc == 1) ? &argv[0] : 0, &obj); if(FAILED(hres)) return hres; *r = jsval_obj(obj); break; } default: FIXME("unimplemented flags: %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT invoke_constructor(script_ctx_t *ctx, FunctionInstance *function, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *this_obj; jsval_t 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), argc, argv, &var); if(FAILED(hres)) { jsdisp_release(this_obj); return hres; } if(is_object_instance(var)) { jsdisp_release(this_obj); *r = var; }else { jsval_release(var); *r = jsval_obj(this_obj); } return S_OK; }
static HRESULT constructor_call(jsdisp_t *constr, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { if(flags != DISPATCH_PROPERTYGET) return jsdisp_call_value(constr, NULL, flags, argc, argv, r); *r = jsval_obj(jsdisp_addref(constr)); return S_OK; }
static HRESULT Function_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { FunctionInstance *function = function_from_jsdisp(jsthis); TRACE("\n"); *r = function->arguments ? jsval_obj(jsdisp_addref(function->arguments)) : jsval_null(); return S_OK; }
static HRESULT VBArray_toArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { VBArrayInstance *vbarray; jsdisp_t *array; jsval_t val; VARIANT *v; int i, size = 1, ubound, lbound; HRESULT hres; TRACE("\n"); vbarray = vbarray_this(vthis); if(!vbarray) return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL); for(i=1; i<=SafeArrayGetDim(vbarray->safearray); i++) { SafeArrayGetLBound(vbarray->safearray, i, &lbound); SafeArrayGetUBound(vbarray->safearray, i, &ubound); size *= ubound-lbound+1; } hres = SafeArrayAccessData(vbarray->safearray, (void**)&v); if(FAILED(hres)) return hres; hres = create_array(ctx, 0, &array); if(FAILED(hres)) { SafeArrayUnaccessData(vbarray->safearray); return hres; } for(i=0; i<size; i++) { hres = variant_to_jsval(v, &val); if(SUCCEEDED(hres)) { hres = jsdisp_propput_idx(array, i, val); jsval_release(val); } if(FAILED(hres)) { SafeArrayUnaccessData(vbarray->safearray); jsdisp_release(array); return hres; } v++; } SafeArrayUnaccessData(vbarray->safearray); if(r) *r = jsval_obj(array); else jsdisp_release(array); return S_OK; }
static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; DWORD length, k, l; jsval_t v1, v2; HRESULT hres1, hres2; TRACE("\n"); hres1 = get_length(ctx, vthis, &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); if(FAILED(hres1) && hres1!=DISP_E_UNKNOWNNAME) return hres1; hres2 = jsdisp_get_idx(jsthis, l, &v2); if(FAILED(hres2) && hres2!=DISP_E_UNKNOWNNAME) { jsval_release(v1); return hres2; } if(hres1 == DISP_E_UNKNOWNNAME) hres1 = jsdisp_delete_idx(jsthis, l); else hres1 = jsdisp_propput_idx(jsthis, l, v1); if(FAILED(hres1)) { jsval_release(v1); jsval_release(v2); return hres1; } if(hres2 == DISP_E_UNKNOWNNAME) hres2 = jsdisp_delete_idx(jsthis, k); else hres2 = jsdisp_propput_idx(jsthis, k, v2); if(FAILED(hres2)) { jsval_release(v2); return hres2; } } if(r) *r = jsval_obj(jsdisp_addref(jsthis)); return S_OK; }
static HRESULT invoke_source(script_ctx_t *ctx, FunctionInstance *function, IDispatch *this_obj, unsigned argc, jsval_t *argv, BOOL is_constructor, BOOL caller_execs_source, jsval_t *r) { jsdisp_t *var_disp, *arg_disp; 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)) { DWORD exec_flags = 0; if(caller_execs_source) exec_flags |= EXEC_RETURN_TO_INTERP; if(is_constructor) exec_flags |= EXEC_CONSTRUCTOR; hres = exec_source(ctx, exec_flags, function->code, function->func_code, scope, this_obj, &function->dispex, var_disp, arg_disp, r); scope_release(scope); } jsdisp_release(arg_disp); jsdisp_release(var_disp); return hres; }
static HRESULT error_constr(script_ctx_t *ctx, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, jsdisp_t *constr) { jsdisp_t *err; UINT num = 0; jsstr_t *msg = NULL; HRESULT hres; if(argc) { double n; hres = to_number(ctx, argv[0], &n); if(FAILED(hres)) /* FIXME: really? */ n = NAN; if(isnan(n)) hres = to_string(ctx, argv[0], &msg); if(FAILED(hres)) return hres; num = n; } if(!msg) { if(argc > 1) { hres = to_string(ctx, argv[1], &msg); if(FAILED(hres)) return hres; }else { msg = jsstr_empty(); } } switch(flags) { case INVOKE_FUNC: case DISPATCH_CONSTRUCT: hres = create_error(ctx, constr, num, msg, &err); jsstr_release(msg); if(FAILED(hres)) return hres; if(r) *r = jsval_obj(err); else jsdisp_release(err); return S_OK; default: if(msg) jsstr_release(msg); FIXME("unimplemented flags %x\n", flags); return E_NOTIMPL; } }
static HRESULT NumberConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { double n; HRESULT hres; TRACE("\n"); switch(flags) { case INVOKE_FUNC: if(!argc) { if(r) *r = jsval_number(0); return S_OK; } hres = to_number(ctx, argv[0], &n); if(FAILED(hres)) return hres; if(r) *r = jsval_number(n); break; case DISPATCH_CONSTRUCT: { jsdisp_t *obj; if(argc) { hres = to_number(ctx, argv[0], &n); if(FAILED(hres)) return hres; } else { n = 0; } hres = create_number(ctx, n, &obj); if(FAILED(hres)) return hres; *r = jsval_obj(obj); break; } default: FIXME("unimplemented flags %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT StringConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { HRESULT hres; TRACE("\n"); switch(flags) { case INVOKE_FUNC: { jsstr_t *str; if(argc) { hres = to_string(ctx, argv[0], &str); if(FAILED(hres)) return hres; } else { str = jsstr_empty(); } *r = jsval_string(str); break; } case DISPATCH_CONSTRUCT: { jsstr_t *str; jsdisp_t *ret; if(argc) { hres = to_string(ctx, argv[0], &str); if(FAILED(hres)) return hres; } else { str = jsstr_empty(); } hres = create_string(ctx, str, &ret); if (SUCCEEDED(hres)) *r = jsval_obj(ret); jsstr_release(str); return hres; } default: FIXME("unimplemented flags: %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT Function_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { FunctionInstance *function = function_from_jsdisp(jsthis); call_frame_t *frame; TRACE("\n"); for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) { if(frame->function_instance == &function->dispex) { *r = jsval_obj(jsdisp_addref(frame->arguments_obj)); return S_OK; } } *r = jsval_null(); 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 Array_forEach(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsval_t value, args[3], res; jsdisp_t *jsthis; unsigned length, i; HRESULT hres; TRACE("\n"); /* FIXME: Check IsCallable */ if(argc != 1 || !is_object_instance(argv[0])) { FIXME("Unsupported arguments\n"); return E_NOTIMPL; } hres = get_length(ctx, vthis, &jsthis, &length); if(FAILED(hres)) return hres; for(i = 0; i < length; i++) { hres = jsdisp_get_idx(jsthis, i, &value); if(hres == DISP_E_UNKNOWNNAME) continue; if(FAILED(hres)) return hres; args[0] = value; args[1] = jsval_number(i); args[2] = jsval_obj(jsthis); hres = disp_call_value(ctx, get_object(argv[0]), NULL, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); jsval_release(value); if(FAILED(hres)) return hres; jsval_release(res); } if(r) *r = jsval_undefined(); return S_OK; }
static HRESULT VBArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { VBArrayInstance *vbarray; HRESULT hres; TRACE("\n"); switch(flags) { case DISPATCH_METHOD: if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT)) return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL); return jsval_copy(argv[0], r); case DISPATCH_CONSTRUCT: if(argc<1 || !is_variant(argv[0]) || V_VT(get_variant(argv[0])) != (VT_ARRAY|VT_VARIANT)) return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL); hres = alloc_vbarray(ctx, NULL, &vbarray); if(FAILED(hres)) return hres; hres = SafeArrayCopy(V_ARRAY(get_variant(argv[0])), &vbarray->safearray); if(FAILED(hres)) { jsdisp_release(&vbarray->dispex); return hres; } *r = jsval_obj(&vbarray->dispex); 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, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *function = (FunctionInstance*)jsthis->u.jsdisp; HRESULT hres = S_OK; TRACE("\n"); switch(flags) { case DISPATCH_PROPERTYGET: { *r = function->arguments ? jsval_obj(jsdisp_addref(function->arguments)) : jsval_null(); break; } case DISPATCH_PROPERTYPUT: break; default: FIXME("unimplemented flags %x\n", flags); hres = E_NOTIMPL; } return hres; }
static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { 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); if(SUCCEEDED(hres)) { DWORD i; for(i=0; i < argc; i++) { if(is_object_instance(argv[i])) hres = concat_obj(ret, get_object(argv[i]), &len); else hres = jsdisp_propput_idx(ret, len++, argv[i]); if(FAILED(hres)) break; } } if(FAILED(hres)) return hres; if(r) *r = jsval_obj(ret); else jsdisp_release(ret); return S_OK; }
/* 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, 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; }
/* ECMA-262 3rd Edition 15.4.4.11 */ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis, *cmp_func = NULL; jsval_t *vtab, **sorttab = NULL; DWORD length; DWORD i; HRESULT hres = S_OK; TRACE("\n"); hres = get_length(ctx, vthis, &jsthis, &length); if(FAILED(hres)) return hres; if(argc > 1) { WARN("invalid arg_cnt %d\n", argc); return E_FAIL; } if(argc == 1) { if(!is_object_instance(argv[0])) { WARN("arg is not dispatch\n"); return E_FAIL; } cmp_func = iface_to_jsdisp((IUnknown*)get_object(argv[0])); 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(r) *r = jsval_obj(jsdisp_addref(jsthis)); return S_OK; } vtab = heap_alloc_zero(length * sizeof(*vtab)); if(vtab) { for(i=0; i<length; i++) { hres = jsdisp_get_idx(jsthis, i, vtab+i); if(hres == DISP_E_UNKNOWNNAME) { vtab[i] = jsval_undefined(); 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(*sorttab)); if(!sorttab) hres = E_OUTOFMEMORY; } /* merge-sort */ if(SUCCEEDED(hres)) { jsval_t *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], &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(jsval_t*)); while(a < k && b < bend) { hres = sort_cmp(ctx, cmp_func, *tmpbuf[a], *sorttab[i+k+b], &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(jsval_t*)); } if(FAILED(hres)) break; } } for(i=0; SUCCEEDED(hres) && i < length; i++) hres = jsdisp_propput_idx(jsthis, i, *sorttab[i]); } if(vtab) { for(i=0; i < length; i++) jsval_release(vtab[i]); heap_free(vtab); } heap_free(sorttab); if(cmp_func) jsdisp_release(cmp_func); if(FAILED(hres)) return hres; if(r) *r = jsval_obj(jsdisp_addref(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, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *arr, *jsthis; DOUBLE range; DWORD length, start, end, idx; HRESULT hres; TRACE("\n"); hres = get_length(ctx, vthis, &jsthis, &length); if(FAILED(hres)) return hres; if(argc) { hres = to_number(ctx, argv[0], &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(argc > 1) { hres = to_number(ctx, argv[1], &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++) { jsval_t v; hres = jsdisp_get_idx(jsthis, idx, &v); if(hres == DISP_E_UNKNOWNNAME) continue; if(SUCCEEDED(hres)) { hres = jsdisp_propput_idx(arr, idx-start, v); jsval_release(v); } if(FAILED(hres)) { jsdisp_release(arr); return hres; } } if(r) *r = jsval_obj(arr); else jsdisp_release(arr); 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; }
static inline HRESULT set_prototype(script_ctx_t *ctx, jsdisp_t *dispex, jsdisp_t *prototype) { return jsdisp_propput_dontenum(dispex, prototypeW, jsval_obj(prototype)); }
static HRESULT set_constructor_prop(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t *prot) { static const WCHAR constructorW[] = {'c','o','n','s','t','r','u','c','t','o','r',0}; return jsdisp_propput_dontenum(prot, constructorW, jsval_obj(constr)); }
static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { match_state_t match_result, *match_ptr = &match_result; DWORD length, i, match_len = 0; const WCHAR *ptr, *ptr2, *str, *match_str = NULL; unsigned limit = ~0u; jsdisp_t *array, *regexp = NULL; jsstr_t *jsstr, *match_jsstr, *tmp_str; HRESULT hres; TRACE("\n"); if(argc != 1 && argc != 2) { FIXME("unsupported argc %u\n", argc); return E_NOTIMPL; } hres = get_string_flat_val(ctx, jsthis, &jsstr, &str); if(FAILED(hres)) return hres; length = jsstr_length(jsstr); if(argc > 1 && !is_undefined(argv[1])) { hres = to_uint32(ctx, argv[1], &limit); if(FAILED(hres)) { jsstr_release(jsstr); return hres; } } if(is_object_instance(argv[0])) { regexp = iface_to_jsdisp(get_object(argv[0])); if(regexp) { if(!is_class(regexp, JSCLASS_REGEXP)) { jsdisp_release(regexp); regexp = NULL; } } } if(!regexp) { hres = to_flat_string(ctx, argv[0], &match_jsstr, &match_str); if(FAILED(hres)) { jsstr_release(jsstr); return hres; } match_len = jsstr_length(match_jsstr); if(!match_len) { jsstr_release(match_jsstr); match_str = NULL; } } hres = create_array(ctx, 0, &array); if(SUCCEEDED(hres)) { ptr = str; match_result.cp = str; for(i=0; i<limit; i++) { if(regexp) { hres = regexp_match_next(ctx, regexp, REM_NO_PARENS, jsstr, &match_ptr); if(hres != S_OK) break; ptr2 = match_result.cp - match_result.match_len; } else if(match_str) { ptr2 = strstrW(ptr, match_str); if(!ptr2) break; } else { if(!*ptr) break; ptr2 = ptr+1; } tmp_str = jsstr_alloc_len(ptr, ptr2-ptr); 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; if(regexp) ptr = match_result.cp; else if(match_str) ptr = ptr2 + match_len; else ptr++; } } if(SUCCEEDED(hres) && (match_str || regexp) && i<limit) { DWORD len = (str+length) - ptr; if(len || match_str) { tmp_str = jsstr_alloc_len(ptr, len); if(tmp_str) { hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str)); jsstr_release(tmp_str); } else { hres = E_OUTOFMEMORY; } } } if(regexp) jsdisp_release(regexp); if(match_str) jsstr_release(match_jsstr); jsstr_release(jsstr); if(SUCCEEDED(hres) && r) *r = jsval_obj(array); else jsdisp_release(array); return hres; }