HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *str, jsval_t *r) { static const WCHAR indexW[] = {'i','n','d','e','x',0}; static const WCHAR inputW[] = {'i','n','p','u','t',0}; static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0}; RegExpInstance *regexp = (RegExpInstance*)re; match_result_t *match_result; unsigned match_cnt, i; jsdisp_t *array; HRESULT hres; if(!(regexp->jsregexp->flags & REG_GLOB)) { match_state_t *match; heap_pool_t *mark; mark = heap_pool_mark(&ctx->tmp_heap); match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, str->str); if(!match) { heap_pool_clear(mark); return E_OUTOFMEMORY; } hres = regexp_match_next(ctx, ®exp->dispex, 0, str, &match); if(FAILED(hres)) { heap_pool_clear(mark); return hres; } if(r) { if(hres == S_OK) { IDispatch *ret; hres = create_match_array(ctx, str, match, &ret); if(SUCCEEDED(hres)) *r = jsval_disp(ret); }else { *r = jsval_null(); } } heap_pool_clear(mark); return S_OK; } hres = regexp_match(ctx, ®exp->dispex, str, FALSE, &match_result, &match_cnt); if(FAILED(hres)) return hres; if(!match_cnt) { TRACE("no match\n"); if(r) *r = jsval_null(); return S_OK; } hres = create_array(ctx, match_cnt, &array); if(FAILED(hres)) return hres; for(i=0; i < match_cnt; i++) { jsstr_t *tmp_str; tmp_str = jsstr_substr(str, match_result[i].index, match_result[i].length); if(!tmp_str) { hres = E_OUTOFMEMORY; break; } hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str)); jsstr_release(tmp_str); if(FAILED(hres)) break; } while(SUCCEEDED(hres)) { hres = jsdisp_propput_name(array, indexW, jsval_number(match_result[match_cnt-1].index)); if(FAILED(hres)) break; hres = jsdisp_propput_name(array, lastIndexW, jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length)); if(FAILED(hres)) break; hres = jsdisp_propput_name(array, inputW, jsval_string(str)); break; } heap_free(match_result); if(SUCCEEDED(hres) && r) *r = jsval_obj(array); else jsdisp_release(array); return hres; }
/* ECMA-262 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; }
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; }
/* 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(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 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; }
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; }