/* ECMA-262 3rd Edition 15.8.2.13 */ static HRESULT Math_pow(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { double x, y; HRESULT hres; TRACE("\n"); if(argc < 2) { if(r) *r = jsval_number(NAN); return S_OK; } hres = to_number(ctx, argv[0], &x); if(FAILED(hres)) return hres; hres = to_number(ctx, argv[1], &y); if(FAILED(hres)) return hres; if(r) *r = jsval_number(pow(x, y)); return S_OK; }
/* ECMA-262 3rd Edition 15.8.2.12 */ static HRESULT Math_min(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DOUBLE min, d; DWORD i; HRESULT hres; TRACE("\n"); if(!argc) { if(r) *r = jsval_number(INFINITY); return S_OK; } hres = to_number(ctx, argv[0], &min); if(FAILED(hres)) return hres; for(i=1; i < argc; i++) { hres = to_number(ctx, argv[i], &d); if(FAILED(hres)) return hres; if(d < min || isnan(d)) min = d; } if(r) *r = jsval_number(min); return S_OK; }
HRESULT variant_to_jsval(VARIANT *var, jsval_t *r) { switch(V_VT(var)) { case VT_EMPTY: *r = jsval_undefined(); return S_OK; case VT_NULL: *r = jsval_null(); return S_OK; case VT_BOOL: *r = jsval_bool(V_BOOL(var)); return S_OK; case VT_I4: *r = jsval_number(V_I4(var)); return S_OK; case VT_R8: *r = jsval_number(V_R8(var)); return S_OK; case VT_BSTR: { jsstr_t *str; str = jsstr_alloc_len(V_BSTR(var), SysStringLen(V_BSTR(var))); if(!str) return E_OUTOFMEMORY; if(!V_BSTR(var)) str->length_flags |= JSSTR_FLAG_NULLBSTR; *r = jsval_string(str); return S_OK; } case VT_DISPATCH: { if(V_DISPATCH(var)) IDispatch_AddRef(V_DISPATCH(var)); *r = jsval_disp(V_DISPATCH(var)); return S_OK; } case VT_I2: *r = jsval_number(V_I2(var)); return S_OK; case VT_INT: *r = jsval_number(V_INT(var)); return S_OK; case VT_UNKNOWN: if(V_UNKNOWN(var)) { IDispatch *disp; HRESULT hres; hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp); if(SUCCEEDED(hres)) { *r = jsval_disp(disp); return S_OK; } } /* fall through */ default: return jsval_variant(r, var); } }
static HRESULT String_indexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t *search_jsstr, *jsstr; const WCHAR *search_str, *str; int length, pos = 0; INT ret = -1; HRESULT hres; TRACE("\n"); hres = get_string_flat_val(ctx, jsthis, &jsstr, &str); if(FAILED(hres)) return hres; length = jsstr_length(jsstr); if(!argc) { if(r) *r = jsval_number(-1); jsstr_release(jsstr); return S_OK; } hres = to_flat_string(ctx, argv[0], &search_jsstr, &search_str); if(FAILED(hres)) { jsstr_release(jsstr); return hres; } if(argc >= 2) { double d; hres = to_integer(ctx, argv[1], &d); if(SUCCEEDED(hres) && d > 0.0) pos = is_int32(d) ? min(length, d) : length; } if(SUCCEEDED(hres)) { const WCHAR *ptr; ptr = strstrW(str+pos, search_str); if(ptr) ret = ptr - str; else ret = -1; } jsstr_release(search_jsstr); jsstr_release(jsstr); if(FAILED(hres)) return hres; if(r) *r = jsval_number(ret); return S_OK; }
static HRESULT Array_indexOf(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; unsigned length, i, from = 0; jsval_t search, value; BOOL eq; HRESULT hres; TRACE("\n"); hres = get_length(ctx, vthis, &jsthis, &length); if(FAILED(hres)) return hres; if(!length) { if(r) *r = jsval_number(-1); return S_OK; } search = argc ? argv[0] : jsval_undefined(); if(argc > 1) { double from_arg; hres = to_integer(ctx, argv[1], &from_arg); if(FAILED(hres)) return hres; if(from_arg >= 0) from = min(from_arg, length); else from = max(from_arg + length, 0); } for(i = from; i < length; i++) { hres = jsdisp_get_idx(jsthis, i, &value); if(hres == DISP_E_UNKNOWNNAME) continue; if(FAILED(hres)) return hres; hres = jsval_strict_equal(value, search, &eq); jsval_release(value); if(FAILED(hres)) return hres; if(eq) { if(r) *r = jsval_number(i); return S_OK; } } if(r) *r = jsval_number(-1); return S_OK; }
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; }
HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **ret) { RegExpInstance *regexp; HRESULT hres; TRACE("%s %x\n", debugstr_jsstr(src), flags); hres = alloc_regexp(ctx, NULL, ®exp); if(FAILED(hres)) return hres; regexp->str = jsstr_addref(src); regexp->last_index_val = jsval_number(0); regexp->jsregexp = regexp_new(ctx, &ctx->tmp_heap, regexp->str->str, jsstr_length(regexp->str), flags, FALSE); if(FAILED(hres)) { WARN("regexp_new failed\n"); jsdisp_release(®exp->dispex); return E_FAIL; } *ret = ®exp->dispex; return S_OK; }
HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name, const builtin_info_t *builtin_info, DWORD flags, jsdisp_t *prototype, jsdisp_t **ret) { FunctionInstance *function; HRESULT hres; hres = create_function(ctx, builtin_info, flags, FALSE, NULL, &function); if(FAILED(hres)) return hres; if(builtin_info) hres = jsdisp_propput_const(&function->dispex, lengthW, jsval_number(function->length)); if(SUCCEEDED(hres)) hres = set_prototype(ctx, &function->dispex, prototype); if(FAILED(hres)) { jsdisp_release(&function->dispex); return hres; } function->value_proc = value_proc; function->name = name; *ret = &function->dispex; return S_OK; }
static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { TRACE("%p\n", jsthis); *r = jsval_number(function_from_jsdisp(jsthis)->length); return S_OK; }
/* ECMA-262 3rd Edition 15.4.4.7 */ static HRESULT Array_push(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; DWORD length = 0; unsigned i; HRESULT hres; TRACE("\n"); hres = get_length(ctx, vthis, &jsthis, &length); if(FAILED(hres)) return hres; for(i=0; i < argc; i++) { hres = jsdisp_propput_idx(jsthis, length+i, argv[i]); if(FAILED(hres)) return hres; } hres = set_length(jsthis, length+argc); if(FAILED(hres)) return hres; if(r) *r = jsval_number(length+argc); 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 VBArray_ubound(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { VBArrayInstance *vbarray; int dim; HRESULT hres; TRACE("\n"); vbarray = vbarray_this(vthis); if(!vbarray) return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL); if(argc) { hres = to_int32(ctx, argv[0], &dim); if(FAILED(hres)) return hres; } else dim = 1; hres = SafeArrayGetUBound(vbarray->safearray, dim, &dim); if(hres == DISP_E_BADINDEX) return throw_range_error(ctx, JS_E_SUBSCRIPT_OUT_OF_RANGE, NULL); else if(FAILED(hres)) return hres; if(r) *r = jsval_number(dim); return S_OK; }
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; }
/* ECMA-262 3rd Edition 15.4.4.13 */ static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; WCHAR buf[14], *buf_end, *str; DWORD i, length; jsval_t val; DISPID id; HRESULT hres; TRACE("\n"); hres = get_length(ctx, vthis, &jsthis, &length); if(FAILED(hres)) return hres; if(argc) { buf_end = buf + sizeof(buf)/sizeof(WCHAR)-1; *buf_end-- = 0; i = length; while(i--) { str = idx_to_str(i, buf_end); hres = jsdisp_get_id(jsthis, str, 0, &id); if(SUCCEEDED(hres)) { hres = jsdisp_propget(jsthis, id, &val); if(FAILED(hres)) return hres; hres = jsdisp_propput_idx(jsthis, i+argc, val); jsval_release(val); }else if(hres == DISP_E_UNKNOWNNAME) { hres = IDispatchEx_DeleteMemberByDispID(vthis->u.dispex, id); } } if(FAILED(hres)) return hres; } for(i=0; i<argc; i++) { hres = jsdisp_propput_idx(jsthis, i, argv[i]); if(FAILED(hres)) return hres; } if(argc) { length += argc; hres = set_length(jsthis, length); if(FAILED(hres)) return hres; } if(r) *r = ctx->version < 2 ? jsval_undefined() : jsval_number(length); return S_OK; }
static HRESULT Number_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { NumberInstance *number = number_from_jsdisp(jsthis); TRACE("(%p)\n", number); *r = jsval_number(number->value); 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)); }
static HRESULT String_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { StringInstance *string = (StringInstance*)jsthis; TRACE("%p\n", jsthis); *r = jsval_number(jsstr_length(string->str)); return S_OK; }
/* ECMA-262 3rd Edition 15.5.4.5 */ static HRESULT String_charCodeAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t *str; DWORD idx = 0; HRESULT hres; TRACE("\n"); hres = get_string_val(ctx, jsthis, &str); if(FAILED(hres)) return hres; if(argc > 0) { double d; hres = to_integer(ctx, argv[0], &d); if(FAILED(hres)) { jsstr_release(str); return hres; } if(!is_int32(d) || d < 0 || d >= jsstr_length(str)) { jsstr_release(str); if(r) *r = jsval_number(NAN); return S_OK; } idx = d; } if(r) { WCHAR c; jsstr_extract(str, idx, 1, &c); *r = jsval_number(c); } jsstr_release(str); return S_OK; }
static HRESULT rep_call(script_ctx_t *ctx, jsdisp_t *func, jsstr_t *jsstr, const WCHAR *str, match_state_t *match, jsstr_t **ret) { jsval_t *argv; unsigned argc; jsval_t val; jsstr_t *tmp_str; DWORD i; HRESULT hres = S_OK; argc = match->paren_count+3; argv = heap_alloc_zero(sizeof(*argv)*argc); if(!argv) return E_OUTOFMEMORY; tmp_str = jsstr_alloc_len(match->cp-match->match_len, match->match_len); if(!tmp_str) hres = E_OUTOFMEMORY; argv[0] = jsval_string(tmp_str); if(SUCCEEDED(hres)) { for(i=0; i < match->paren_count; i++) { if(match->parens[i].index != -1) tmp_str = jsstr_substr(jsstr, match->parens[i].index, match->parens[i].length); else tmp_str = jsstr_empty(); if(!tmp_str) { hres = E_OUTOFMEMORY; break; } argv[i+1] = jsval_string(tmp_str); } } if(SUCCEEDED(hres)) { argv[match->paren_count+1] = jsval_number(match->cp-str - match->match_len); argv[match->paren_count+2] = jsval_string(jsstr); } if(SUCCEEDED(hres)) hres = jsdisp_call_value(func, NULL, DISPATCH_METHOD, argc, argv, &val); for(i=0; i <= match->paren_count; i++) jsstr_release(get_string(argv[i])); heap_free(argv); if(FAILED(hres)) return hres; hres = to_string(ctx, val, ret); jsval_release(val); return hres; }
/* ECMA-262 3rd Edition 15.8.2.12 */ static HRESULT Math_abs(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { double d; HRESULT hres; TRACE("\n"); if(!argc) { if(r) *r = jsval_number(NAN); return S_OK; } hres = to_number(ctx, argv[0], &d); if(FAILED(hres)) return hres; if(r) *r = jsval_number(d < 0.0 ? -d : d); return S_OK; }
static HRESULT Math_acos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { double x; HRESULT hres; TRACE("\n"); if(!argc) { if(r) *r = jsval_number(NAN); return S_OK; } hres = to_number(ctx, argv[0], &x); if(FAILED(hres)) return hres; if(r) *r = jsval_number(x < -1.0 || x > 1.0 ? NAN : acos(x)); return S_OK; }
static HRESULT Number_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { NumberInstance *number; TRACE("\n"); if(!(number = number_this(jsthis))) return throw_type_error(ctx, JS_E_NUMBER_EXPECTED, NULL); if(r) *r = jsval_number(number->value); return S_OK; }
/* ECMA-262 3rd Edition 15.8.2.14 */ static HRESULT Math_random(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { UINT x; TRACE("\n"); if(!RtlGenRandom(&x, sizeof(x))) return E_UNEXPECTED; if(r) *r = jsval_number((double)x/(double)UINT_MAX); return S_OK; }
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; }
static HRESULT VBArray_dimensions(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { VBArrayInstance *vbarray; TRACE("\n"); vbarray = vbarray_this(vthis); if(!vbarray) return throw_type_error(ctx, JS_E_VBARRAY_EXPECTED, NULL); if(r) *r = jsval_number(SafeArrayGetDim(vbarray->safearray)); return S_OK; }
static HRESULT create_arguments(script_ctx_t *ctx, FunctionInstance *calee, jsdisp_t *var_obj, unsigned argc, jsval_t *argv, jsdisp_t **ret) { ArgumentsInstance *args; unsigned i; HRESULT hres; static const WCHAR caleeW[] = {'c','a','l','l','e','e',0}; args = heap_alloc_zero(sizeof(*args)); if(!args) return E_OUTOFMEMORY; hres = init_dispex_from_constr(&args->jsdisp, ctx, &Arguments_info, ctx->object_constr); if(FAILED(hres)) { heap_free(args); return hres; } jsdisp_addref(&calee->dispex); args->function = calee; args->var_obj = jsdisp_addref(var_obj); /* Store unnamed arguments directly in arguments object */ for(i = calee->length; i < argc; i++) { WCHAR buf[12]; static const WCHAR formatW[] = {'%','d',0}; sprintfW(buf, formatW, i); hres = jsdisp_propput_dontenum(&args->jsdisp, buf, argv[i]); if(FAILED(hres)) break; } if(SUCCEEDED(hres)) { hres = jsdisp_propput_dontenum(&args->jsdisp, lengthW, jsval_number(argc)); if(SUCCEEDED(hres)) hres = jsdisp_propput_dontenum(&args->jsdisp, caleeW, jsval_disp(to_disp(&calee->dispex))); } if(FAILED(hres)) { jsdisp_release(&args->jsdisp); return hres; } *ret = &args->jsdisp; return S_OK; }
static HRESULT Number_toPrecision(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { NumberInstance *number; INT prec = 0, size; jsstr_t *str; DOUBLE val; HRESULT hres; if(!(number = number_this(jsthis))) return throw_type_error(ctx, JS_E_NUMBER_EXPECTED, NULL); if(argc) { hres = to_int32(ctx, argv[0], &prec); if(FAILED(hres)) return hres; if(prec<1 || prec>21) return throw_range_error(ctx, JS_E_PRECISION_OUT_OF_RANGE, NULL); } val = number->value; if(isinf(val) || isnan(val) || !prec) { hres = to_string(ctx, jsval_number(val), &str); if(FAILED(hres)) return hres; } else { if(val != 0) size = floor(log10(val>0 ? val : -val)) + 1; else size = 1; if(size > prec) str = number_to_exponential(val, prec-1); else str = number_to_fixed(val, prec-size); if(!str) return E_OUTOFMEMORY; } if(r) *r = jsval_string(str); else jsstr_release(str); return S_OK; }
static HRESULT Function_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *This = function_from_vdisp(jsthis); TRACE("%p %d\n", This, This->length); switch(flags) { case DISPATCH_PROPERTYGET: *r = jsval_number(This->length); break; default: FIXME("unimplemented flags %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT Number_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { NumberInstance *number = number_from_vdisp(jsthis); switch(flags) { case INVOKE_FUNC: return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); case DISPATCH_PROPERTYGET: *r = jsval_number(number->value); break; default: FIXME("flags %x\n", flags); return E_NOTIMPL; } return S_OK; }
static HRESULT Number_toExponential(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { NumberInstance *number; DOUBLE val; INT prec = 0; jsstr_t *str; HRESULT hres; TRACE("\n"); if(!(number = number_this(jsthis))) return throw_type_error(ctx, JS_E_NUMBER_EXPECTED, NULL); if(argc) { hres = to_int32(ctx, argv[0], &prec); if(FAILED(hres)) return hres; if(prec<0 || prec>20) return throw_range_error(ctx, JS_E_FRACTION_DIGITS_OUT_OF_RANGE, NULL); } val = number->value; if(isinf(val) || isnan(val)) { hres = to_string(ctx, jsval_number(val), &str); if(FAILED(hres)) return hres; } else { if(!prec) prec--; str = number_to_exponential(val, prec); if(!str) return E_OUTOFMEMORY; } if(r) *r = jsval_string(str); else jsstr_release(str); return S_OK; }