/* ECMA-262 5.1 Edition 15.12.2 */ static HRESULT JSON_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { json_parse_ctx_t parse_ctx; const WCHAR *buf; jsstr_t *str; jsval_t ret; HRESULT hres; if(argc != 1) { FIXME("Unsupported args\n"); return E_INVALIDARG; } hres = to_flat_string(ctx, argv[0], &str, &buf); if(FAILED(hres)) return hres; TRACE("%s\n", debugstr_w(buf)); parse_ctx.ptr = buf; parse_ctx.end = buf + jsstr_length(str); parse_ctx.ctx = ctx; hres = parse_json_value(&parse_ctx, &ret); jsstr_release(str); if(FAILED(hres)) return hres; if(skip_spaces(&parse_ctx)) { FIXME("syntax error\n"); jsval_release(ret); return E_FAIL; } if(r) *r = ret; else jsval_release(ret); return S_OK; }
static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *function; jsstr_t *str; HRESULT hres; TRACE("\n"); if(!(function = function_this(jsthis))) return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); hres = function_to_string(function, &str); if(FAILED(hres)) return hres; if(r) *r = jsval_string(str); else jsstr_release(str); return S_OK; }
static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { match_state_t *match; jsstr_t *undef_str; heap_pool_t *mark; BOOL b; HRESULT hres; TRACE("\n"); mark = heap_pool_mark(&ctx->tmp_heap); hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b); heap_pool_clear(mark); if(!argc) jsstr_release(undef_str); if(FAILED(hres)) return hres; if(r) *r = jsval_bool(b); return S_OK; }
static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *argv, IDispatch **ret) { WCHAR *str = NULL, *ptr; unsigned len = 0, i = 0; bytecode_t *code; jsdisp_t *function; jsstr_t **params = NULL; int j = 0; HRESULT hres = S_OK; static const WCHAR function_anonymousW[] = {'f','u','n','c','t','i','o','n',' ','a','n','o','n','y','m','o','u','s','('}; static const WCHAR function_beginW[] = {')',' ','{','\n'}; static const WCHAR function_endW[] = {'\n','}',0}; if(argc) { params = heap_alloc(argc*sizeof(*params)); if(!params) return E_OUTOFMEMORY; if(argc > 2) len = (argc-2)*2; /* separating commas */ for(i=0; i < argc; i++) { hres = to_string(ctx, argv[i], params+i); if(FAILED(hres)) break; len += jsstr_length(params[i]); } } if(SUCCEEDED(hres)) { len += (sizeof(function_anonymousW) + sizeof(function_beginW) + sizeof(function_endW)) / sizeof(WCHAR); str = heap_alloc(len*sizeof(WCHAR)); if(str) { memcpy(str, function_anonymousW, sizeof(function_anonymousW)); ptr = str + sizeof(function_anonymousW)/sizeof(WCHAR); if(argc > 1) { while(1) { ptr += jsstr_flush(params[j], ptr); if(++j == argc-1) break; *ptr++ = ','; *ptr++ = ' '; } } memcpy(ptr, function_beginW, sizeof(function_beginW)); ptr += sizeof(function_beginW)/sizeof(WCHAR); if(argc) ptr += jsstr_flush(params[argc-1], ptr); memcpy(ptr, function_endW, sizeof(function_endW)); TRACE("%s\n", debugstr_w(str)); }else { hres = E_OUTOFMEMORY; } } while(i) jsstr_release(params[--i]); heap_free(params); if(FAILED(hres)) return hres; hres = compile_script(ctx, str, NULL, NULL, FALSE, FALSE, &code); heap_free(str); if(FAILED(hres)) return hres; if(code->global_code.func_cnt != 1 || code->global_code.var_cnt) { ERR("Invalid parser result!\n"); release_bytecode(code); return E_UNEXPECTED; } hres = create_source_function(ctx, code, code->global_code.funcs, NULL, &function); release_bytecode(code); if(FAILED(hres)) return hres; *ret = to_disp(function); return S_OK; }
/* 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; }
static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, const WCHAR *sep, jsval_t *r) { jsstr_t **str_tab, *ret; jsval_t val; DWORD i; HRESULT hres = E_FAIL; if(!length) { if(r) *r = jsval_string(jsstr_empty()); return S_OK; } str_tab = heap_alloc_zero(length * sizeof(*str_tab)); if(!str_tab) return E_OUTOFMEMORY; for(i=0; i < length; i++) { hres = jsdisp_get_idx(array, i, &val); if(hres == DISP_E_UNKNOWNNAME) { hres = S_OK; continue; } else if(FAILED(hres)) break; if(!is_undefined(val) && !is_null(val)) { hres = to_string(ctx, val, str_tab+i); jsval_release(val); if(FAILED(hres)) break; } } if(SUCCEEDED(hres)) { DWORD seplen = 0, len = 0; seplen = strlenW(sep); if(str_tab[0]) len = jsstr_length(str_tab[0]); for(i=1; i < length; i++) { len += seplen; if(str_tab[i]) len += jsstr_length(str_tab[i]); if(len > JSSTR_MAX_LENGTH) { hres = E_OUTOFMEMORY; break; } } if(SUCCEEDED(hres)) { WCHAR *ptr = NULL; ptr = jsstr_alloc_buf(len, &ret); if(ptr) { if(str_tab[0]) ptr += jsstr_flush(str_tab[0], ptr); for(i=1; i < length; i++) { if(seplen) { memcpy(ptr, sep, seplen*sizeof(WCHAR)); ptr += seplen; } if(str_tab[i]) ptr += jsstr_flush(str_tab[i], ptr); } }else { hres = E_OUTOFMEMORY; } } } for(i=0; i < length; i++) { if(str_tab[i]) jsstr_release(str_tab[i]); } heap_free(str_tab); if(FAILED(hres)) return hres; TRACE("= %s\n", debugstr_jsstr(ret)); if(r) *r = jsval_string(ret); else jsstr_release(ret); return S_OK; }
/* ECMA-262 3rd Edition 15.7.4.2 */ static HRESULT Number_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { NumberInstance *number; INT radix = 10; DOUBLE val; 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], &radix); if(FAILED(hres)) return hres; if(radix<2 || radix>36) return throw_type_error(ctx, JS_E_INVALIDARG, NULL); } val = number->value; if(radix==10 || isnan(val) || isinf(val)) { hres = to_string(ctx, jsval_number(val), &str); if(FAILED(hres)) return hres; } else { INT idx = 0; DOUBLE integ, frac, log_radix = 0; WCHAR buf[NUMBER_TOSTRING_BUF_SIZE+16]; BOOL exp = FALSE; if(val<0) { val = -val; buf[idx++] = '-'; } while(1) { integ = floor(val); frac = val-integ; if(integ == 0) buf[idx++] = '0'; while(integ>=1 && idx<NUMBER_TOSTRING_BUF_SIZE) { buf[idx] = fmod(integ, radix); if(buf[idx]<10) buf[idx] += '0'; else buf[idx] += 'a'-10; integ /= radix; idx++; } if(idx<NUMBER_TOSTRING_BUF_SIZE) { INT beg = buf[0]=='-'?1:0; INT end = idx-1; WCHAR wch; while(end > beg) { wch = buf[beg]; buf[beg++] = buf[end]; buf[end--] = wch; } } if(idx != NUMBER_TOSTRING_BUF_SIZE) buf[idx++] = '.'; while(frac>0 && idx<NUMBER_TOSTRING_BUF_SIZE) { frac *= radix; buf[idx] = fmod(frac, radix); frac -= buf[idx]; if(buf[idx]<10) buf[idx] += '0'; else buf[idx] += 'a'-10; idx++; } if(idx==NUMBER_TOSTRING_BUF_SIZE && !exp) { exp = TRUE; idx = (buf[0]=='-') ? 1 : 0; log_radix = floor(log(val)/log(radix)); val *= pow(radix, -log_radix); continue; } break; } while(buf[idx-1] == '0') idx--; if(buf[idx-1] == '.') idx--; if(exp) { if(log_radix==0) buf[idx] = 0; else { static const WCHAR formatW[] = {'(','e','%','c','%','d',')',0}; WCHAR ch; if(log_radix<0) { log_radix = -log_radix; ch = '-'; } else ch = '+'; sprintfW(&buf[idx], formatW, ch, (int)log_radix); } } else buf[idx] = '\0'; str = jsstr_alloc(buf); if(!str) return E_OUTOFMEMORY; } if(r) *r = jsval_string(str); else jsstr_release(str); 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 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; }
void free_strings(void) { jsstr_release(empty_str); jsstr_release(nan_str); jsstr_release(undefined_str); }
/* ECMA-262 3rd Edition 15.11.4.4 */ static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; jsstr_t *name = NULL, *msg = NULL, *ret = NULL; jsval_t v; HRESULT hres; static const WCHAR object_errorW[] = {'[','o','b','j','e','c','t',' ','E','r','r','o','r',']',0}; TRACE("\n"); jsthis = get_jsdisp(vthis); if(!jsthis || ctx->version < 2) { if(r) { jsstr_t *str; str = jsstr_alloc(object_errorW); if(!str) return E_OUTOFMEMORY; *r = jsval_string(str); } return S_OK; } hres = jsdisp_propget_name(jsthis, nameW, &v); if(FAILED(hres)) return hres; if(!is_undefined(v)) { hres = to_string(ctx, v, &name); jsval_release(v); if(FAILED(hres)) return hres; } hres = jsdisp_propget_name(jsthis, messageW, &v); if(SUCCEEDED(hres)) { if(!is_undefined(v)) { hres = to_string(ctx, v, &msg); jsval_release(v); } } if(SUCCEEDED(hres)) { unsigned name_len = name ? jsstr_length(name) : 0; unsigned msg_len = msg ? jsstr_length(msg) : 0; if(name_len && msg_len) { ret = jsstr_alloc_buf(name_len + msg_len + 2); if(ret) { jsstr_flush(name, ret->str); ret->str[name_len] = ':'; ret->str[name_len+1] = ' '; jsstr_flush(msg, ret->str+name_len+2); } }else if(name_len) { ret = name; name = NULL; }else if(msg_len) { ret = msg; msg = NULL; }else { ret = jsstr_alloc(object_errorW); } } if(msg) jsstr_release(msg); if(name) jsstr_release(name); if(FAILED(hres)) return hres; if(!ret) return E_OUTOFMEMORY; if(r) *r = jsval_string(ret); else jsstr_release(ret); return S_OK; }
/* 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 15.5.4.8 */ static HRESULT String_lastIndexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { unsigned pos = 0, search_len, length; jsstr_t *search_jsstr, *jsstr; const WCHAR *search_str, *str; INT ret = -1; HRESULT hres; TRACE("\n"); hres = get_string_flat_val(ctx, jsthis, &jsstr, &str); if(FAILED(hres)) return hres; 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; } search_len = jsstr_length(search_jsstr); length = jsstr_length(jsstr); if(argc >= 2) { double d; hres = to_integer(ctx, argv[1], &d); if(SUCCEEDED(hres) && d > 0) pos = is_int32(d) ? min(length, d) : length; } else { pos = length; } if(SUCCEEDED(hres) && length >= search_len) { const WCHAR *ptr; for(ptr = str+min(pos, length-search_len); ptr >= str; ptr--) { if(!memcmp(ptr, search_str, search_len*sizeof(WCHAR))) { ret = ptr-str; break; } } } jsstr_release(search_jsstr); jsstr_release(jsstr); if(FAILED(hres)) return hres; if(r) *r = jsval_number(ret); return S_OK; }
/* ECMA-262 3rd Edition 15.5.4.6 */ static HRESULT String_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t *ret, *str; HRESULT hres; TRACE("\n"); hres = get_string_val(ctx, jsthis, &str); if(FAILED(hres)) return hres; switch(argc) { case 0: ret = str; break; case 1: { jsstr_t *arg_str; hres = to_string(ctx, argv[0], &arg_str); if(FAILED(hres)) { jsstr_release(str); return hres; } ret = jsstr_concat(str, arg_str); jsstr_release(str); if(!ret) return E_OUTOFMEMORY; break; } default: { const unsigned str_cnt = argc+1; unsigned len = 0, i; jsstr_t **strs; WCHAR *ptr; strs = heap_alloc_zero(str_cnt * sizeof(*strs)); if(!strs) { jsstr_release(str); return E_OUTOFMEMORY; } strs[0] = str; for(i=0; i < argc; i++) { hres = to_string(ctx, argv[i], strs+i+1); if(FAILED(hres)) break; } if(SUCCEEDED(hres)) { for(i=0; i < str_cnt; i++) { len += jsstr_length(strs[i]); if(len > JSSTR_MAX_LENGTH) { hres = E_OUTOFMEMORY; break; } } if(SUCCEEDED(hres)) { ptr = jsstr_alloc_buf(len, &ret); if(ptr) { for(i=0; i < str_cnt; i++) ptr += jsstr_flush(strs[i], ptr); } else { hres = E_OUTOFMEMORY; } } } while(i--) jsstr_release(strs[i]); heap_free(strs); if(FAILED(hres)) return hres; } } if(r) *r = jsval_string(ret); else jsstr_release(ret); return S_OK; }
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 3rd Edition 15.5.4.13 */ static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { int start=0, end, length; jsstr_t *str; double d; HRESULT hres; TRACE("\n"); hres = get_string_val(ctx, jsthis, &str); if(FAILED(hres)) return hres; length = jsstr_length(str); if(argc) { hres = to_integer(ctx, argv[0], &d); if(FAILED(hres)) { jsstr_release(str); return hres; } if(is_int32(d)) { start = d; if(start < 0) { start = length + start; if(start < 0) start = 0; } else if(start > length) { start = length; } } else if(d > 0) { start = length; } } if(argc >= 2) { hres = to_integer(ctx, argv[1], &d); if(FAILED(hres)) { jsstr_release(str); return hres; } if(is_int32(d)) { end = d; if(end < 0) { end = length + end; if(end < 0) end = 0; } else if(end > length) { end = length; } } else { end = d < 0.0 ? 0 : length; } } else { end = length; } if(end < start) end = start; if(r) { jsstr_t *retstr = jsstr_substr(str, start, end-start); if(!retstr) { jsstr_release(str); return E_OUTOFMEMORY; } *r = jsval_string(retstr); } jsstr_release(str); return S_OK; }