static HRESULT do_attribute_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, unsigned argc, jsval_t *argv, jsval_t *r, const WCHAR *tagname, const WCHAR *attrname) { jsstr_t *str, *attr_value = NULL; HRESULT hres; hres = get_string_val(ctx, jsthis, &str); if(FAILED(hres)) return hres; if(argc) { hres = to_string(ctx, argv[0], &attr_value); if(FAILED(hres)) { jsstr_release(str); return hres; } } else { attr_value = jsstr_undefined(); } if(r) { unsigned attrname_len = strlenW(attrname); unsigned tagname_len = strlenW(tagname); jsstr_t *ret; WCHAR *ptr; ptr = jsstr_alloc_buf(2*tagname_len + attrname_len + jsstr_length(attr_value) + jsstr_length(str) + 9, &ret); if(ptr) { *ptr++ = '<'; memcpy(ptr, tagname, tagname_len*sizeof(WCHAR)); ptr += tagname_len; *ptr++ = ' '; memcpy(ptr, attrname, attrname_len*sizeof(WCHAR)); ptr += attrname_len; *ptr++ = '='; *ptr++ = '"'; ptr += jsstr_flush(attr_value, ptr); *ptr++ = '"'; *ptr++ = '>'; ptr += jsstr_flush(str, ptr); *ptr++ = '<'; *ptr++ = '/'; memcpy(ptr, tagname, tagname_len*sizeof(WCHAR)); ptr += tagname_len; *ptr = '>'; *r = jsval_string(ret); } else { hres = E_OUTOFMEMORY; } } jsstr_release(attr_value); jsstr_release(str); return hres; }
jsstr_t *jsstr_concat(jsstr_t *str1, jsstr_t *str2) { unsigned len1, len2; jsstr_t *ret; WCHAR *ptr; len1 = jsstr_length(str1); if(!len1) return jsstr_addref(str2); len2 = jsstr_length(str2); if(!len2) return jsstr_addref(str1); if(len1 + len2 >= JSSTR_SHORT_STRING_LENGTH) { unsigned depth, depth2; jsstr_rope_t *rope; depth = jsstr_is_rope(str1) ? jsstr_as_rope(str1)->depth : 0; depth2 = jsstr_is_rope(str2) ? jsstr_as_rope(str2)->depth : 0; if(depth2 > depth) depth = depth2; if(depth++ < JSSTR_MAX_ROPE_DEPTH) { if(len1+len2 > JSSTR_MAX_LENGTH) return NULL; rope = heap_alloc(sizeof(*rope)); if(!rope) return NULL; jsstr_init(&rope->str, len1+len2, JSSTR_ROPE); rope->left = jsstr_addref(str1); rope->right = jsstr_addref(str2); rope->depth = depth; return &rope->str; } } ptr = jsstr_alloc_buf(len1+len2, &ret); if(!ret) return NULL; jsstr_flush(str1, ptr); jsstr_flush(str2, ptr+len1); return ret; }
static HRESULT String_toUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t *str; HRESULT hres; TRACE("\n"); hres = get_string_val(ctx, jsthis, &str); if(FAILED(hres)) return hres; if(r) { jsstr_t *ret; WCHAR *buf; buf = jsstr_alloc_buf(jsstr_length(str), &ret); if(!buf) { jsstr_release(str); return E_OUTOFMEMORY; } jsstr_flush(str, buf); struprW(buf); *r = jsval_string(ret); } jsstr_release(str); return S_OK; }
const WCHAR *jsstr_rope_flatten(jsstr_rope_t *str) { WCHAR *buf; buf = heap_alloc((jsstr_length(&str->str)+1) * sizeof(WCHAR)); if(!buf) return NULL; jsstr_flush(str->left, buf); jsstr_flush(str->right, buf+jsstr_length(str->left)); buf[jsstr_length(&str->str)] = 0; /* Trasform to heap string */ jsstr_release(str->left); jsstr_release(str->right); str->str.length_flags |= JSSTR_FLAG_FLAT; return jsstr_as_heap(&str->str)->buf = buf; }
static HRESULT strbuf_append_jsstr(strbuf_t *buf, jsstr_t *str) { if(!strbuf_ensure_size(buf, buf->len+jsstr_length(str))) return E_OUTOFMEMORY; jsstr_flush(str, buf->buf+buf->len); buf->len += jsstr_length(str); return S_OK; }
HRESULT jsval_to_variant(jsval_t val, VARIANT *retv) { switch(jsval_type(val)) { case JSV_UNDEFINED: V_VT(retv) = VT_EMPTY; return S_OK; case JSV_NULL: V_VT(retv) = VT_NULL; return S_OK; case JSV_OBJECT: V_VT(retv) = VT_DISPATCH; if(get_object(val)) IDispatch_AddRef(get_object(val)); V_DISPATCH(retv) = get_object(val); return S_OK; case JSV_STRING: { jsstr_t *str = get_string(val); V_VT(retv) = VT_BSTR; if(str->length_flags & JSSTR_FLAG_NULLBSTR) { V_BSTR(retv) = NULL; } else { V_BSTR(retv) = SysAllocStringLen(NULL, jsstr_length(str)); if(V_BSTR(retv)) jsstr_flush(str, V_BSTR(retv)); else return E_OUTOFMEMORY; } return S_OK; } case JSV_NUMBER: { double n = get_number(val); if(is_int32(n)) { V_VT(retv) = VT_I4; V_I4(retv) = n; } else { V_VT(retv) = VT_R8; V_R8(retv) = n; } return S_OK; } case JSV_BOOL: V_VT(retv) = VT_BOOL; V_BOOL(retv) = get_bool(val) ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; case JSV_VARIANT: V_VT(retv) = VT_EMPTY; return VariantCopy(retv, get_variant(val)); } assert(0); return E_FAIL; }
jsstr_t *jsstr_concat(jsstr_t *str1, jsstr_t *str2) { unsigned len1, len2; jsstr_t *ret; len1 = jsstr_length(str1); if(!len1) return jsstr_addref(str2); len2 = jsstr_length(str2); if(!len2) return jsstr_addref(str1); ret = jsstr_alloc_buf(len1+len2); if(!ret) return NULL; jsstr_flush(str1, ret->str); jsstr_flush(str2, ret->str+len1); return ret; }
static HRESULT do_attributeless_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r, const WCHAR *tagname) { unsigned tagname_len; jsstr_t *str, *ret; WCHAR *ptr; HRESULT hres; hres = get_string_val(ctx, jsthis, &str); if(FAILED(hres)) return hres; if(!r) { jsstr_release(str); return S_OK; } tagname_len = strlenW(tagname); ptr = jsstr_alloc_buf(jsstr_length(str) + 2*tagname_len + 5, &ret); if(!ret) { jsstr_release(str); return E_OUTOFMEMORY; } *ptr++ = '<'; memcpy(ptr, tagname, tagname_len*sizeof(WCHAR)); ptr += tagname_len; *ptr++ = '>'; ptr += jsstr_flush(str, ptr); jsstr_release(str); *ptr++ = '<'; *ptr++ = '/'; memcpy(ptr, tagname, tagname_len*sizeof(WCHAR)); ptr += tagname_len; *ptr = '>'; *r = jsval_string(ret); 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; }
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.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; }
HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt) { jsval_t val; HRESULT hres; clear_ei(ctx); hres = variant_to_jsval(src, &val); if(FAILED(hres)) return hres; switch(vt) { case VT_I2: case VT_I4: { INT i; hres = to_int32(ctx, val, &i); if(SUCCEEDED(hres)) { if(vt == VT_I4) V_I4(dst) = i; else V_I2(dst) = i; } break; } case VT_R8: { double n; hres = to_number(ctx, val, &n); if(SUCCEEDED(hres)) V_R8(dst) = n; break; } case VT_R4: { double n; hres = to_number(ctx, val, &n); if(SUCCEEDED(hres)) V_R4(dst) = n; break; } case VT_BOOL: { BOOL b; hres = to_boolean(val, &b); if(SUCCEEDED(hres)) V_BOOL(dst) = b ? VARIANT_TRUE : VARIANT_FALSE; break; } case VT_BSTR: { jsstr_t *str; hres = to_string(ctx, val, &str); if(FAILED(hres)) break; if(str->length_flags & JSSTR_FLAG_NULLBSTR) { V_BSTR(dst) = NULL; break; } V_BSTR(dst) = SysAllocStringLen(NULL, jsstr_length(str)); if(V_BSTR(dst)) jsstr_flush(str, V_BSTR(dst)); else hres = E_OUTOFMEMORY; break; } case VT_EMPTY: hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL; break; case VT_NULL: hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL; break; default: FIXME("vt %d not implemented\n", vt); hres = E_NOTIMPL; } jsval_release(val); if(FAILED(hres)) return hres; V_VT(dst) = vt; 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; }