HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **ret) { RegExpInstance *regexp; const WCHAR *str; HRESULT hres; TRACE("%s %x\n", debugstr_jsstr(src), flags); str = jsstr_flatten(src); if(!str) return E_OUTOFMEMORY; 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, str, jsstr_length(regexp->str), flags, FALSE); if(!regexp->jsregexp) { WARN("regexp_new failed\n"); jsdisp_release(®exp->dispex); return E_FAIL; } *ret = ®exp->dispex; return S_OK; }
HRESULT regexp_match_next(script_ctx_t *ctx, jsdisp_t *dispex, DWORD rem_flags, jsstr_t *jsstr, match_state_t **ret) { RegExpInstance *regexp = (RegExpInstance*)dispex; match_state_t *match; heap_pool_t *mark; const WCHAR *str; HRESULT hres; if((rem_flags & REM_CHECK_GLOBAL) && !(regexp->jsregexp->flags & REG_GLOB)) { if(rem_flags & REM_ALLOC_RESULT) *ret = NULL; return S_FALSE; } str = jsstr_flatten(jsstr); if(!str) return E_OUTOFMEMORY; if(rem_flags & REM_ALLOC_RESULT) { match = alloc_match_state(regexp->jsregexp, NULL, str); if(!match) return E_OUTOFMEMORY; *ret = match; } mark = heap_pool_mark(&ctx->tmp_heap); if(rem_flags & REM_NO_PARENS) { match = alloc_match_state(regexp->jsregexp, &ctx->tmp_heap, NULL); if(!match) { heap_pool_clear(mark); return E_OUTOFMEMORY; } match->cp = (*ret)->cp; match->match_len = (*ret)->match_len; }else { match = *ret; } hres = do_regexp_match_next(ctx, regexp, rem_flags, jsstr, str, match); if(rem_flags & REM_NO_PARENS) { (*ret)->cp = match->cp; (*ret)->match_len = match->match_len; } heap_pool_clear(mark); if(hres != S_OK && (rem_flags & REM_ALLOC_RESULT)) { heap_free(match); *ret = NULL; } return hres; }
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 get_string_flat_val(script_ctx_t *ctx, vdisp_t *jsthis, jsstr_t **jsval, const WCHAR **val) { HRESULT hres; hres = get_string_val(ctx, jsthis, jsval); if(FAILED(hres)) return hres; *val = jsstr_flatten(*jsval); if(*val) return S_OK; jsstr_release(*jsval); return E_OUTOFMEMORY; }
HRESULT to_flat_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str, const WCHAR **ret_str) { HRESULT hres; hres = to_string(ctx, val, str); if(FAILED(hres)) return hres; *ret_str = jsstr_flatten(*str); if(!*ret_str) { jsstr_release(*str); return E_OUTOFMEMORY; } 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; }
HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, 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; const WCHAR *str; jsdisp_t *array; HRESULT hres; str = jsstr_flatten(jsstr); if(!str) return E_OUTOFMEMORY; 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); if(!match) { heap_pool_clear(mark); return E_OUTOFMEMORY; } hres = regexp_match_next(ctx, ®exp->dispex, 0, jsstr, &match); if(FAILED(hres)) { heap_pool_clear(mark); return hres; } if(r) { if(hres == S_OK) { IDispatch *ret; hres = create_match_array(ctx, jsstr, 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, jsstr, 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(jsstr, 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(jsstr)); 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_str, const match_state_t *result, IDispatch **ret) { const WCHAR *input; 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}; input = jsstr_flatten(input_str); if(!input) return E_OUTOFMEMORY; 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_str, 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-result->match_len)); if(FAILED(hres)) break; hres = jsdisp_propput_name(array, lastIndexW, jsval_number(result->cp-input)); if(FAILED(hres)) break; hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr_addref(input_str))); 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; }
static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, BOOL gflag, match_result_t **match_result, DWORD *result_cnt) { RegExpInstance *This = (RegExpInstance*)dispex; match_result_t *ret = NULL; match_state_t *result; DWORD i=0, ret_size = 0; heap_pool_t *mark; const WCHAR *str; HRESULT hres; mark = heap_pool_mark(&ctx->tmp_heap); str = jsstr_flatten(jsstr); if(!str) return E_OUTOFMEMORY; result = alloc_match_state(This->jsregexp, &ctx->tmp_heap, str); if(!result) { heap_pool_clear(mark); return E_OUTOFMEMORY; } while(1) { hres = do_regexp_match_next(ctx, This, 0, jsstr, str, result); if(hres == S_FALSE) { hres = S_OK; break; } if(FAILED(hres)) break; if(ret_size == i) { if(ret) { match_result_t *old_ret = ret; ret = heap_realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t)); if(!ret) heap_free(old_ret); }else { ret = heap_alloc((ret_size=4) * sizeof(match_result_t)); } if(!ret) { hres = E_OUTOFMEMORY; break; } } ret[i].index = result->cp - str - result->match_len; ret[i++].length = result->match_len; if(!gflag && !(This->jsregexp->flags & REG_GLOB)) { hres = S_OK; break; } } heap_pool_clear(mark); if(FAILED(hres)) { heap_free(ret); return hres; } *match_result = ret; *result_cnt = i; return S_OK; }
/* ECMA-262 3rd Edition 9.3.1 */ static HRESULT str_to_number(jsstr_t *str, double *ret) { const WCHAR *ptr; BOOL neg = FALSE; DOUBLE d = 0.0; static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'}; ptr = jsstr_flatten(str); if(!ptr) return E_OUTOFMEMORY; while(isspaceW(*ptr)) ptr++; if(*ptr == '-') { neg = TRUE; ptr++; }else if(*ptr == '+') { ptr++; } if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) { ptr += sizeof(infinityW)/sizeof(WCHAR); while(*ptr && isspaceW(*ptr)) ptr++; if(*ptr) *ret = NAN; else *ret = neg ? -INFINITY : INFINITY; return S_OK; } if(*ptr == '0' && ptr[1] == 'x') { DWORD l = 0; ptr += 2; while((l = hex_to_int(*ptr)) != -1) { d = d*16 + l; ptr++; } *ret = d; return S_OK; } while(isdigitW(*ptr)) d = d*10 + (*ptr++ - '0'); if(*ptr == 'e' || *ptr == 'E') { BOOL eneg = FALSE; LONG l = 0; ptr++; if(*ptr == '-') { ptr++; eneg = TRUE; }else if(*ptr == '+') { ptr++; } while(isdigitW(*ptr)) l = l*10 + (*ptr++ - '0'); if(eneg) l = -l; d *= pow(10, l); }else if(*ptr == '.') { DOUBLE dec = 0.1; ptr++; while(isdigitW(*ptr)) { d += dec * (*ptr++ - '0'); dec *= 0.1; } } while(isspaceW(*ptr)) ptr++; if(*ptr) { *ret = NAN; return S_OK; } if(neg) d = -d; *ret = d; return S_OK; }