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; }
static HRESULT String_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) { StringInstance *string = (StringInstance*)jsdisp; jsstr_t *ret; ret = jsstr_substr(string->str, idx, 1); if(!ret) return E_OUTOFMEMORY; TRACE("%p[%u] = %s\n", string, idx, debugstr_jsstr(ret)); *r = jsval_string(ret); return S_OK; }
const char *debugstr_jsval(const jsval_t v) { switch(jsval_type(v)) { case JSV_UNDEFINED: return "undefined"; case JSV_NULL: return "null"; case JSV_OBJECT: return wine_dbg_sprintf("obj(%p)", get_object(v)); case JSV_STRING: return wine_dbg_sprintf("str(%s)", debugstr_jsstr(get_string(v))); case JSV_NUMBER: return wine_dbg_sprintf("%lf", get_number(v)); case JSV_BOOL: return get_bool(v) ? "true" : "false"; case JSV_VARIANT: return debugstr_variant(get_variant(v)); } assert(0); return NULL; }
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; }
const char *debugstr_jsstr(jsstr_t *str) { return jsstr_is_inline(str) ? debugstr_wn(jsstr_as_inline(str)->buf, jsstr_length(str)) : jsstr_is_heap(str) ? debugstr_wn(jsstr_as_heap(str)->buf, jsstr_length(str)) : wine_dbg_sprintf("%s...", debugstr_jsstr(jsstr_as_rope(str)->left)); }
/* 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; }