HRESULT disp_propput(IDispatch *disp, DISPID id, LCID lcid, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller) { DISPID dispid = DISPID_PROPERTYPUT; DISPPARAMS dp = {val, &dispid, 1, 1}; IDispatchEx *dispex; DispatchEx *jsdisp; HRESULT hres; jsdisp = iface_to_jsdisp((IUnknown*)disp); if(jsdisp) { dispex_prop_t *prop; prop = get_prop(jsdisp, id); if(prop) hres = prop_put(jsdisp, prop, lcid, &dp, ei, caller); else hres = DISP_E_MEMBERNOTFOUND; IDispatchEx_Release(_IDispatchEx_(jsdisp)); return hres; } hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(FAILED(hres)) { ULONG err = 0; TRACE("using IDispatch\n"); return IDispatch_Invoke(disp, id, &IID_NULL, DISPATCH_PROPERTYPUT, lcid, &dp, NULL, &ei->ei, &err); } hres = IDispatchEx_InvokeEx(dispex, id, lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ei->ei, caller); IDispatchEx_Release(dispex); return hres; }
HRESULT disp_propget(IDispatch *disp, DISPID id, LCID lcid, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller) { DISPPARAMS dp = {NULL,NULL,0,0}; IDispatchEx *dispex; DispatchEx *jsdisp; HRESULT hres; jsdisp = iface_to_jsdisp((IUnknown*)disp); if(jsdisp) { hres = jsdisp_propget(jsdisp, id, lcid, val, ei, caller); IDispatchEx_Release(_IDispatchEx_(jsdisp)); return hres; } hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(FAILED(hres)) { ULONG err = 0; TRACE("using IDispatch\n"); return IDispatch_Invoke(disp, id, &IID_NULL, lcid, INVOKE_PROPERTYGET, &dp, val, &ei->ei, &err); } hres = IDispatchEx_InvokeEx(dispex, id, lcid, INVOKE_PROPERTYGET, &dp, val, &ei->ei, caller); IDispatchEx_Release(dispex); return hres; }
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; }
HRESULT init_dispex_from_constr(DispatchEx *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *constr) { DispatchEx *prot = NULL; dispex_prop_t *prop; HRESULT hres; static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0}; hres = find_prop_name_prot(constr, prototypeW, FALSE, &prop); if(SUCCEEDED(hres) && prop) { jsexcept_t jsexcept; VARIANT var; V_VT(&var) = VT_EMPTY; memset(&jsexcept, 0, sizeof(jsexcept)); hres = prop_get(constr, prop, ctx->lcid, NULL, &var, &jsexcept, NULL/*FIXME*/); if(FAILED(hres)) { ERR("Could not get prototype\n"); return hres; } if(V_VT(&var) == VT_DISPATCH) prot = iface_to_jsdisp((IUnknown*)V_DISPATCH(&var)); VariantClear(&var); } hres = init_dispex(dispex, ctx, builtin_info, prot); if(prot) IDispatchEx_Release(_IDispatchEx_(prot)); return hres; }
static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) { FunctionInstance *function; DISPPARAMS args = {NULL,NULL,0,0}; DWORD argc, i; IDispatch *this_obj = NULL; HRESULT hres = S_OK; TRACE("\n"); if(!(function = function_this(jsthis))) return throw_type_error(ctx, ei, JS_E_FUNCTION_EXPECTED, NULL); argc = arg_cnt(dp); if(argc) { VARIANT *v = get_arg(dp,0); if(V_VT(v) != VT_EMPTY && V_VT(v) != VT_NULL) { hres = to_object(ctx, v, &this_obj); if(FAILED(hres)) return hres; } } if(argc >= 2) { jsdisp_t *arg_array = NULL; if(V_VT(get_arg(dp,1)) == VT_DISPATCH) { arg_array = iface_to_jsdisp((IUnknown*)V_DISPATCH(get_arg(dp,1))); if(arg_array && (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) { jsdisp_release(arg_array); arg_array = NULL; } } if(arg_array) { hres = array_to_args(ctx, arg_array, ei, caller, &args); jsdisp_release(arg_array); }else { FIXME("throw TypeError\n"); hres = E_FAIL; } } if(SUCCEEDED(hres)) hres = call_function(ctx, function, this_obj, &args, retv, ei, caller); if(this_obj) IDispatch_Release(this_obj); for(i=0; i<args.cArgs; i++) VariantClear(args.rgvarg+i); heap_free(args.rgvarg); return hres; }
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; }
HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg, jsdisp_t **ret) { unsigned flags, opt_len = 0; const WCHAR *opt = NULL; jsstr_t *src; HRESULT hres; if(is_object_instance(src_arg)) { jsdisp_t *obj; obj = iface_to_jsdisp((IUnknown*)get_object(src_arg)); if(obj) { if(is_class(obj, JSCLASS_REGEXP)) { RegExpInstance *regexp = (RegExpInstance*)obj; hres = create_regexp(ctx, regexp->str, regexp->jsregexp->flags, ret); jsdisp_release(obj); return hres; } jsdisp_release(obj); } } if(!is_string(src_arg)) { FIXME("src_arg = %s\n", debugstr_jsval(src_arg)); return E_NOTIMPL; } src = get_string(src_arg); if(flags_arg) { jsstr_t *opt_str; if(!is_string(*flags_arg)) { FIXME("unimplemented for %s\n", debugstr_jsval(*flags_arg)); return E_NOTIMPL; } opt_str = get_string(*flags_arg); opt = jsstr_flatten(opt_str); if(!opt) return E_OUTOFMEMORY; opt_len = jsstr_length(opt_str); } hres = parse_regexp_flags(opt, opt_len, &flags); if(FAILED(hres)) return hres; return create_regexp(ctx, src, flags, ret); }
static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *function; jsval_t *args = NULL; unsigned i, cnt = 0; IDispatch *this_obj = NULL; HRESULT hres = S_OK; TRACE("\n"); if(!(function = function_this(jsthis))) return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); if(argc) { if(!is_undefined(argv[0]) && !is_null(argv[0])) { hres = to_object(ctx, argv[0], &this_obj); if(FAILED(hres)) return hres; } } if(argc >= 2) { jsdisp_t *arg_array = NULL; if(is_object_instance(argv[1])) { arg_array = iface_to_jsdisp((IUnknown*)get_object(argv[1])); if(arg_array && (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) { jsdisp_release(arg_array); arg_array = NULL; } } if(arg_array) { hres = array_to_args(ctx, arg_array, &cnt, &args); jsdisp_release(arg_array); }else { FIXME("throw TypeError\n"); hres = E_FAIL; } } if(SUCCEEDED(hres)) hres = call_function(ctx, function, this_obj, cnt, args, r); if(this_obj) IDispatch_Release(this_obj); for(i=0; i < cnt; i++) jsval_release(args[i]); heap_free(args); return hres; }
static HRESULT String_search(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *regexp = NULL; const WCHAR *str; jsstr_t *jsstr; match_state_t match, *match_ptr = &match; HRESULT hres; TRACE("\n"); hres = get_string_flat_val(ctx, jsthis, &jsstr, &str); if(FAILED(hres)) return hres; if(!argc) { if(r) *r = jsval_null(); jsstr_release(jsstr); return S_OK; } if(is_object_instance(argv[0])) { regexp = iface_to_jsdisp(get_object(argv[0])); if(regexp && !is_class(regexp, JSCLASS_REGEXP)) { jsdisp_release(regexp); regexp = NULL; } } if(!regexp) { hres = create_regexp_var(ctx, argv[0], NULL, ®exp); if(FAILED(hres)) { jsstr_release(jsstr); return hres; } } match.cp = str; hres = regexp_match_next(ctx, regexp, REM_RESET_INDEX|REM_NO_PARENS, jsstr, &match_ptr); jsstr_release(jsstr); jsdisp_release(regexp); if(FAILED(hres)) return hres; if(r) *r = jsval_number(hres == S_OK ? match.cp-match.match_len-str : -1); return S_OK; }
/* ECMA-262 5.1 Edition 15.4.3.2 */ static HRESULT ArrayConstr_isArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *obj; TRACE("\n"); if(!argc || !is_object_instance(argv[0])) { if(r) *r = jsval_bool(FALSE); return S_OK; } obj = iface_to_jsdisp(get_object(argv[0])); if(r) *r = jsval_bool(obj && is_class(obj, JSCLASS_ARRAY)); if(obj) jsdisp_release(obj); return S_OK; }
static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len) { jsdisp_t *jsobj; HRESULT hres; jsobj = iface_to_jsdisp((IUnknown*)obj); if(jsobj) { if(is_class(jsobj, JSCLASS_ARRAY)) { hres = concat_array(array, (ArrayInstance*)jsobj, len); jsdisp_release(jsobj); return hres; } jsdisp_release(jsobj); } return jsdisp_propput_idx(array, (*len)++, jsval_disp(obj)); }
static HRESULT invoke_value_proc(FunctionInstance *function, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) { DispatchEx *this_obj = NULL; IDispatch *this_disp; HRESULT hres; this_disp = get_this(dp); if(this_disp) this_obj = iface_to_jsdisp((IUnknown*)this_disp); hres = function->value_proc(this_obj ? this_obj : function->dispex.ctx->script_disp, lcid, flags, dp, retv, ei, caller); if(this_obj) jsdisp_release(this_obj); return hres; }
/* ECMA-262 3rd Edition 15.5.4.10 */ static HRESULT String_match(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *regexp = NULL; jsstr_t *str; HRESULT hres; TRACE("\n"); if(!argc) { if(r) *r = jsval_null(); return S_OK; } if(is_object_instance(argv[0])) { regexp = iface_to_jsdisp(get_object(argv[0])); if(regexp && !is_class(regexp, JSCLASS_REGEXP)) { jsdisp_release(regexp); regexp = NULL; } } if(!regexp) { jsstr_t *match_str; hres = to_string(ctx, argv[0], &match_str); if(FAILED(hres)) return hres; hres = create_regexp(ctx, match_str, 0, ®exp); jsstr_release(match_str); if(FAILED(hres)) return hres; } hres = get_string_val(ctx, jsthis, &str); if(SUCCEEDED(hres)) hres = regexp_string_match(ctx, regexp, str, r); jsdisp_release(regexp); jsstr_release(str); return hres; }
static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len, jsexcept_t *ei) { jsdisp_t *jsobj; VARIANT var; HRESULT hres; jsobj = iface_to_jsdisp((IUnknown*)obj); if(jsobj) { if(is_class(jsobj, JSCLASS_ARRAY)) { hres = concat_array(array, (ArrayInstance*)jsobj, len, ei); jsdisp_release(jsobj); return hres; } jsdisp_release(jsobj); } V_VT(&var) = VT_DISPATCH; V_DISPATCH(&var) = obj; return jsdisp_propput_idx(array, (*len)++, &var, ei); }
HRESULT disp_call(IDispatch *disp, DISPID id, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller) { DispatchEx *jsdisp; IDispatchEx *dispex; HRESULT hres; jsdisp = iface_to_jsdisp((IUnknown*)disp); if(jsdisp) { hres = jsdisp_call(jsdisp, id, lcid, flags, dp, retv, ei, caller); IDispatchEx_Release(_IDispatchEx_(jsdisp)); return hres; } memset(ei, 0, sizeof(*ei)); if(retv) V_VT(retv) = VT_EMPTY; hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(FAILED(hres)) { UINT err = 0; if(flags == DISPATCH_CONSTRUCT) { WARN("IDispatch cannot be constructor\n"); return DISP_E_MEMBERNOTFOUND; } TRACE("using IDispatch\n"); return IDispatch_Invoke(disp, id, &IID_NULL, lcid, flags, dp, retv, &ei->ei, &err); } hres = IDispatchEx_InvokeEx(dispex, id, lcid, flags, dp, retv, &ei->ei, caller); IDispatchEx_Release(dispex); return hres; }
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; }
/* ECMA-262 5.1 Edition 15.12.3 (abstract operation Str) */ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val) { jsval_t value; HRESULT hres; if(is_object_instance(val) && get_object(val)) { jsdisp_t *obj; DISPID id; obj = iface_to_jsdisp((IUnknown*)get_object(val)); if(!obj) return S_FALSE; hres = jsdisp_get_id(obj, toJSONW, 0, &id); jsdisp_release(obj); if(hres == S_OK) FIXME("Use toJSON.\n"); } /* FIXME: Support replacer replacer. */ hres = maybe_to_primitive(ctx->ctx, val, &value); if(FAILED(hres)) return hres; switch(jsval_type(value)) { case JSV_NULL: if(!append_string(ctx, nullW)) hres = E_OUTOFMEMORY; break; case JSV_BOOL: if(!append_string(ctx, get_bool(value) ? trueW : falseW)) hres = E_OUTOFMEMORY; break; case JSV_STRING: { jsstr_t *str = get_string(value); const WCHAR *ptr = jsstr_flatten(str); if(ptr) hres = json_quote(ctx, ptr, jsstr_length(str)); else hres = E_OUTOFMEMORY; break; } case JSV_NUMBER: { double n = get_number(value); if(is_finite(n)) { const WCHAR *ptr; jsstr_t *str; /* FIXME: Optimize. There is no need for jsstr_t here. */ hres = double_to_string(n, &str); if(FAILED(hres)) break; ptr = jsstr_flatten(str); assert(ptr != NULL); hres = ptr && !append_string_len(ctx, ptr, jsstr_length(str)) ? E_OUTOFMEMORY : S_OK; jsstr_release(str); }else { if(!append_string(ctx, nullW)) hres = E_OUTOFMEMORY; } break; } case JSV_OBJECT: { jsdisp_t *obj; obj = iface_to_jsdisp((IUnknown*)get_object(value)); if(!obj) { hres = S_FALSE; break; } if(!is_callable(obj)) hres = is_class(obj, JSCLASS_ARRAY) ? stringify_array(ctx, obj) : stringify_object(ctx, obj); else hres = S_FALSE; jsdisp_release(obj); break; } case JSV_UNDEFINED: hres = S_FALSE; break; case JSV_VARIANT: FIXME("VARIANT\n"); hres = E_NOTIMPL; break; } jsval_release(value); return hres; }
/* ECMA-262 3rd Edition 15.5.4.11 */ static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { const WCHAR *str, *match_str = NULL, *rep_str = NULL; jsstr_t *rep_jsstr, *match_jsstr, *jsstr; jsdisp_t *rep_func = NULL, *regexp = NULL; match_state_t *match = NULL, last_match = {0}; strbuf_t ret = {NULL,0,0}; DWORD re_flags = REM_NO_CTX_UPDATE|REM_ALLOC_RESULT; DWORD rep_len=0; HRESULT hres = S_OK; TRACE("\n"); hres = get_string_flat_val(ctx, jsthis, &jsstr, &str); if(FAILED(hres)) return hres; if(!argc) { if(r) *r = jsval_string(jsstr); else jsstr_release(jsstr); return S_OK; } if(is_object_instance(argv[0])) { regexp = iface_to_jsdisp(get_object(argv[0])); if(regexp && !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; } } if(argc >= 2) { if(is_object_instance(argv[1])) { rep_func = iface_to_jsdisp(get_object(argv[1])); if(rep_func && !is_class(rep_func, JSCLASS_FUNCTION)) { jsdisp_release(rep_func); rep_func = NULL; } } if(!rep_func) { hres = to_flat_string(ctx, argv[1], &rep_jsstr, &rep_str); if(SUCCEEDED(hres)) rep_len = jsstr_length(rep_jsstr); } } if(SUCCEEDED(hres)) { const WCHAR *ecp = str; while(1) { if(regexp) { hres = regexp_match_next(ctx, regexp, re_flags, jsstr, &match); re_flags = (re_flags | REM_CHECK_GLOBAL) & (~REM_ALLOC_RESULT); if(hres == S_FALSE) { hres = S_OK; break; } if(FAILED(hres)) break; last_match.cp = match->cp; last_match.match_len = match->match_len; } else { if(re_flags & REM_ALLOC_RESULT) { re_flags &= ~REM_ALLOC_RESULT; match = &last_match; match->cp = str; } match->cp = strstrW(match->cp, match_str); if(!match->cp) break; match->match_len = jsstr_length(match_jsstr); match->cp += match->match_len; } hres = strbuf_append(&ret, ecp, match->cp-ecp-match->match_len); ecp = match->cp; if(FAILED(hres)) break; if(rep_func) { jsstr_t *cstr; hres = rep_call(ctx, rep_func, jsstr, str, match, &cstr); if(FAILED(hres)) break; hres = strbuf_append_jsstr(&ret, cstr); jsstr_release(cstr); if(FAILED(hres)) break; } else if(rep_str && regexp) { const WCHAR *ptr = rep_str, *ptr2; while((ptr2 = strchrW(ptr, '$'))) { hres = strbuf_append(&ret, ptr, ptr2-ptr); if(FAILED(hres)) break; switch(ptr2[1]) { case '$': hres = strbuf_append(&ret, ptr2, 1); ptr = ptr2+2; break; case '&': hres = strbuf_append(&ret, match->cp-match->match_len, match->match_len); ptr = ptr2+2; break; case '`': hres = strbuf_append(&ret, str, match->cp-str-match->match_len); ptr = ptr2+2; break; case '\'': hres = strbuf_append(&ret, ecp, (str+jsstr_length(jsstr))-ecp); ptr = ptr2+2; break; default: { DWORD idx; if(!isdigitW(ptr2[1])) { hres = strbuf_append(&ret, ptr2, 1); ptr = ptr2+1; break; } idx = ptr2[1] - '0'; if(isdigitW(ptr2[2]) && idx*10 + (ptr2[2]-'0') <= match->paren_count) { idx = idx*10 + (ptr[2]-'0'); ptr = ptr2+3; } else if(idx && idx <= match->paren_count) { ptr = ptr2+2; } else { hres = strbuf_append(&ret, ptr2, 1); ptr = ptr2+1; break; } if(match->parens[idx-1].index != -1) hres = strbuf_append(&ret, str+match->parens[idx-1].index, match->parens[idx-1].length); } } if(FAILED(hres)) break; } if(SUCCEEDED(hres)) hres = strbuf_append(&ret, ptr, (rep_str+rep_len)-ptr); if(FAILED(hres)) break; } else if(rep_str) { hres = strbuf_append(&ret, rep_str, rep_len); if(FAILED(hres)) break; } else { static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d'}; hres = strbuf_append(&ret, undefinedW, sizeof(undefinedW)/sizeof(WCHAR)); if(FAILED(hres)) break; } if(!regexp) break; else if(!match->match_len) match->cp++; } if(SUCCEEDED(hres)) hres = strbuf_append(&ret, ecp, str+jsstr_length(jsstr)-ecp); } if(rep_func) jsdisp_release(rep_func); if(rep_str) jsstr_release(rep_jsstr); if(match_str) jsstr_release(match_jsstr); if(regexp) heap_free(match); if(SUCCEEDED(hres) && last_match.cp && regexp) { jsstr_release(ctx->last_match); ctx->last_match = jsstr_addref(jsstr); ctx->last_match_index = last_match.cp-str-last_match.match_len; ctx->last_match_length = last_match.match_len; } if(regexp) jsdisp_release(regexp); jsstr_release(jsstr); if(SUCCEEDED(hres) && r) { jsstr_t *ret_str; ret_str = jsstr_alloc_len(ret.buf, ret.len); if(!ret_str) return E_OUTOFMEMORY; TRACE("= %s\n", debugstr_jsstr(ret_str)); *r = jsval_string(ret_str); } heap_free(ret.buf); return hres; }
/* ECMA-262 3rd Edition 9.1 */ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) { if(is_object_instance(val)) { jsdisp_t *jsdisp; jsval_t prim; DISPID id; HRESULT hres; static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0}; if(!get_object(val)) { *ret = jsval_null(); return S_OK; } jsdisp = iface_to_jsdisp((IUnknown*)get_object(val)); if(!jsdisp) return disp_propget(ctx, get_object(val), DISPID_VALUE, ret); if(hint == NO_HINT) hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER; /* Native implementation doesn't throw TypeErrors, returns strange values */ hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id); if(SUCCEEDED(hres)) { hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim); if(FAILED(hres)) { WARN("call error - forwarding exception\n"); jsdisp_release(jsdisp); return hres; }else if(!is_object_instance(prim)) { jsdisp_release(jsdisp); *ret = prim; return S_OK; }else { IDispatch_Release(get_object(prim)); } } hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id); if(SUCCEEDED(hres)) { hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim); if(FAILED(hres)) { WARN("call error - forwarding exception\n"); jsdisp_release(jsdisp); return hres; }else if(!is_object_instance(prim)) { jsdisp_release(jsdisp); *ret = prim; return S_OK; }else { IDispatch_Release(get_object(prim)); } } jsdisp_release(jsdisp); WARN("failed\n"); return throw_type_error(ctx, JS_E_TO_PRIMITIVE, NULL); } return jsval_copy(val, ret); }
/* 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.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; }