BOOL init_strings(void) { static const WCHAR NaNW[] = { 'N','a','N',0 }; static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0}; if(!jsstr_alloc_buf(0, &empty_str)) return FALSE; if(!(nan_str = jsstr_alloc(NaNW))) return FALSE; if(!(undefined_str = jsstr_alloc(undefinedW))) return FALSE; if(!jsstr_alloc_buf(0, &null_bstr_str)) return FALSE; return TRUE; }
/* ECMA-262 3rd Edition 15.5.3.2 */ static HRESULT StringConstr_fromCharCode(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { WCHAR *ret_str; DWORD i, code; jsstr_t *ret; HRESULT hres; TRACE("\n"); ret_str = jsstr_alloc_buf(argc, &ret); if(!ret_str) return E_OUTOFMEMORY; for(i=0; i<argc; i++) { hres = to_uint32(ctx, argv[i], &code); if(FAILED(hres)) { jsstr_release(ret); return hres; } ret_str[i] = code; } if(r) *r = jsval_string(ret); else jsstr_release(ret); return S_OK; }
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; }
static HRESULT function_to_string(FunctionInstance *function, jsstr_t **ret) { jsstr_t *str; static const WCHAR native_prefixW[] = {'\n','f','u','n','c','t','i','o','n',' '}; static const WCHAR native_suffixW[] = {'(',')',' ','{','\n',' ',' ',' ',' ','[','n','a','t','i','v','e',' ','c','o','d','e',']','\n','}','\n'}; if(function->value_proc) { DWORD name_len; WCHAR *ptr; name_len = strlenW(function->name); ptr = jsstr_alloc_buf((sizeof(native_prefixW)+sizeof(native_suffixW))/sizeof(WCHAR) + name_len, &str); if(!ptr) return E_OUTOFMEMORY; memcpy(ptr, native_prefixW, sizeof(native_prefixW)); memcpy(ptr += sizeof(native_prefixW)/sizeof(WCHAR), function->name, name_len*sizeof(WCHAR)); memcpy(ptr + name_len, native_suffixW, sizeof(native_suffixW)); }else { str = jsstr_alloc_len(function->func_code->source, function->func_code->source_len); if(!str) return E_OUTOFMEMORY; } *ret = str; return S_OK; }
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_alloc_len(const WCHAR *buf, unsigned len) { jsstr_t *ret; ret = jsstr_alloc_buf(len); if(ret) memcpy(ret->str, buf, len*sizeof(WCHAR)); return ret; }
BOOL init_strings(void) { static const WCHAR NaNW[] = { 'N','a','N',0 }; if(!(empty_str = jsstr_alloc_buf(0))) return FALSE; if(!(nan_str = jsstr_alloc(NaNW))) return FALSE; return TRUE; }
jsstr_t *jsstr_alloc_len(const WCHAR *buf, unsigned len) { jsstr_t *ret; WCHAR *ptr; ptr = jsstr_alloc_buf(len, &ret); if(ptr) memcpy(ptr, buf, len*sizeof(WCHAR)); return ret; }
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 JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t *ret_str, *str; const WCHAR *ptr; DWORD len = 0; WCHAR *ret; HRESULT hres; TRACE("\n"); if(!argc) { if(r) *r = jsval_string(jsstr_undefined()); return S_OK; } hres = to_string(ctx, argv[0], &str); if(FAILED(hres)) return hres; for(ptr = str->str; *ptr; ptr++) { if(*ptr > 0xff) len += 6; else if(is_ecma_nonblank(*ptr)) len++; else len += 3; } ret_str = jsstr_alloc_buf(len); if(!ret_str) { jsstr_release(str); return E_OUTOFMEMORY; } len = 0; ret = ret_str->str; for(ptr = str->str; *ptr; ptr++) { if(*ptr > 0xff) { ret[len++] = '%'; ret[len++] = 'u'; ret[len++] = int_to_char(*ptr >> 12); ret[len++] = int_to_char((*ptr >> 8) & 0xf); ret[len++] = int_to_char((*ptr >> 4) & 0xf); ret[len++] = int_to_char(*ptr & 0xf); } else if(is_ecma_nonblank(*ptr))
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; }
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; }
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; memcpy(ret->str, str1->str, len1*sizeof(WCHAR)); memcpy(ret->str+len1, str2->str, len2*sizeof(WCHAR)); return ret; }
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; }
static inline jsstr_t *number_to_fixed(double val, int prec) { WCHAR buf[NUMBER_DTOA_SIZE]; int dec_point, size, buf_size, buf_pos; BOOL neg = FALSE; jsstr_t *ret; WCHAR *str; TRACE("%lf %d\n", val, prec); if(val < 0) { neg = TRUE; val = -val; } if(val >= 1) buf_size = log10(val)+prec+2; else buf_size = prec ? prec+1 : 2; if(buf_size > NUMBER_DTOA_SIZE) buf_size = NUMBER_DTOA_SIZE; number_to_str(val, buf, buf_size, &dec_point); dec_point++; size = 0; if(neg) size++; if(dec_point > 0) size += dec_point; else size++; if(prec) size += prec+1; str = jsstr_alloc_buf(size, &ret); if(!ret) return NULL; size = buf_pos = 0; if(neg) str[size++] = '-'; if(dec_point > 0) { for(; buf_pos<buf_size-1 && dec_point; dec_point--) str[size++] = buf[buf_pos++]; } else { str[size++] = '0'; } for(; dec_point>0; dec_point--) str[size++] = '0'; if(prec) { str[size++] = '.'; for(; dec_point<0 && prec; dec_point++, prec--) str[size++] = '0'; for(; buf_pos<buf_size-1 && prec; prec--) str[size++] = buf[buf_pos++]; for(; prec; prec--) { str[size++] = '0'; } } str[size++] = 0; return ret; }
static inline jsstr_t *number_to_exponential(double val, int prec) { WCHAR buf[NUMBER_DTOA_SIZE], *pbuf; int dec_point, size, buf_size, exp_size = 1; BOOL neg = FALSE; jsstr_t *ret; WCHAR *str; if(val < 0) { neg = TRUE; val = -val; } buf_size = prec+2; if(buf_size<2 || buf_size>NUMBER_DTOA_SIZE) buf_size = NUMBER_DTOA_SIZE; number_to_str(val, buf, buf_size, &dec_point); buf_size--; if(prec == -1) for(; buf_size>1 && buf[buf_size-1]=='0'; buf_size--) buf[buf_size-1] = 0; size = 10; while(dec_point>=size || dec_point<=-size) { size *= 10; exp_size++; } if(buf_size == 1) size = buf_size+2+exp_size; /* 2 = strlen(e+) */ else if(prec == -1) size = buf_size+3+exp_size; /* 3 = strlen(.e+) */ else size = prec+4+exp_size; /* 4 = strlen(0.e+) */ if(neg) size++; str = jsstr_alloc_buf(size, &ret); if(!ret) return NULL; size = 0; pbuf = buf; if(neg) str[size++] = '-'; str[size++] = *pbuf++; if(buf_size != 1) { str[size++] = '.'; while(*pbuf) str[size++] = *pbuf++; for(; prec>buf_size-1; prec--) str[size++] = '0'; } str[size++] = 'e'; if(dec_point >= 0) { str[size++] = '+'; } else { str[size++] = '-'; dec_point = -dec_point; } size += exp_size; do { str[--size] = '0'+dec_point%10; dec_point /= 10; } while(dec_point>0); size += exp_size; str[size] = 0; return ret; }
/* 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.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; }