netstat: Fix compilation on systems that don't support nameless unions.
[wine.git] / dlls / jscript / string.c
blobce5d7022362f966fe535d9f4838f401a8f260a3e
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
22 #include "jscript.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
28 #define UINT32_MAX 0xffffffff
30 typedef struct {
31 jsdisp_t dispex;
32 jsstr_t *str;
33 } StringInstance;
35 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
36 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
37 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
38 static const WCHAR anchorW[] = {'a','n','c','h','o','r',0};
39 static const WCHAR bigW[] = {'b','i','g',0};
40 static const WCHAR blinkW[] = {'b','l','i','n','k',0};
41 static const WCHAR boldW[] = {'b','o','l','d',0};
42 static const WCHAR charAtW[] = {'c','h','a','r','A','t',0};
43 static const WCHAR charCodeAtW[] = {'c','h','a','r','C','o','d','e','A','t',0};
44 static const WCHAR concatW[] = {'c','o','n','c','a','t',0};
45 static const WCHAR fixedW[] = {'f','i','x','e','d',0};
46 static const WCHAR fontcolorW[] = {'f','o','n','t','c','o','l','o','r',0};
47 static const WCHAR fontsizeW[] = {'f','o','n','t','s','i','z','e',0};
48 static const WCHAR indexOfW[] = {'i','n','d','e','x','O','f',0};
49 static const WCHAR italicsW[] = {'i','t','a','l','i','c','s',0};
50 static const WCHAR lastIndexOfW[] = {'l','a','s','t','I','n','d','e','x','O','f',0};
51 static const WCHAR linkW[] = {'l','i','n','k',0};
52 static const WCHAR matchW[] = {'m','a','t','c','h',0};
53 static const WCHAR replaceW[] = {'r','e','p','l','a','c','e',0};
54 static const WCHAR searchW[] = {'s','e','a','r','c','h',0};
55 static const WCHAR sliceW[] = {'s','l','i','c','e',0};
56 static const WCHAR smallW[] = {'s','m','a','l','l',0};
57 static const WCHAR splitW[] = {'s','p','l','i','t',0};
58 static const WCHAR strikeW[] = {'s','t','r','i','k','e',0};
59 static const WCHAR subW[] = {'s','u','b',0};
60 static const WCHAR substringW[] = {'s','u','b','s','t','r','i','n','g',0};
61 static const WCHAR substrW[] = {'s','u','b','s','t','r',0};
62 static const WCHAR supW[] = {'s','u','p',0};
63 static const WCHAR toLowerCaseW[] = {'t','o','L','o','w','e','r','C','a','s','e',0};
64 static const WCHAR toUpperCaseW[] = {'t','o','U','p','p','e','r','C','a','s','e',0};
65 static const WCHAR toLocaleLowerCaseW[] = {'t','o','L','o','c','a','l','e','L','o','w','e','r','C','a','s','e',0};
66 static const WCHAR toLocaleUpperCaseW[] = {'t','o','L','o','c','a','l','e','U','p','p','e','r','C','a','s','e',0};
67 static const WCHAR localeCompareW[] = {'l','o','c','a','l','e','C','o','m','p','a','r','e',0};
68 static const WCHAR fromCharCodeW[] = {'f','r','o','m','C','h','a','r','C','o','d','e',0};
70 static inline StringInstance *string_from_vdisp(vdisp_t *vdisp)
72 return (StringInstance*)vdisp->u.jsdisp;
75 static inline StringInstance *string_this(vdisp_t *jsthis)
77 return is_vclass(jsthis, JSCLASS_STRING) ? string_from_vdisp(jsthis) : NULL;
80 static HRESULT get_string_val(script_ctx_t *ctx, vdisp_t *jsthis, jsstr_t **val)
82 StringInstance *string;
84 if((string = string_this(jsthis))) {
85 *val = jsstr_addref(string->str);
86 return S_OK;
89 return to_string(ctx, jsval_disp(jsthis->u.disp), val);
92 static HRESULT String_length(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
93 jsval_t *r)
95 TRACE("%p\n", jsthis);
97 switch(flags) {
98 case DISPATCH_PROPERTYGET: {
99 StringInstance *string = string_from_vdisp(jsthis);
101 *r = jsval_number(jsstr_length(string->str));
102 break;
104 default:
105 FIXME("unimplemented flags %x\n", flags);
106 return E_NOTIMPL;
109 return S_OK;
112 static HRESULT stringobj_to_string(vdisp_t *jsthis, jsval_t *r)
114 StringInstance *string;
116 if(!(string = string_this(jsthis))) {
117 WARN("this is not a string object\n");
118 return E_FAIL;
121 if(r)
122 *r = jsval_string(jsstr_addref(string->str));
123 return S_OK;
126 /* ECMA-262 3rd Edition 15.5.4.2 */
127 static HRESULT String_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
128 jsval_t *r)
130 TRACE("\n");
132 return stringobj_to_string(jsthis, r);
135 /* ECMA-262 3rd Edition 15.5.4.2 */
136 static HRESULT String_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
137 jsval_t *r)
139 TRACE("\n");
141 return stringobj_to_string(jsthis, r);
144 static HRESULT do_attributeless_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r, const WCHAR *tagname)
146 jsstr_t *str;
147 HRESULT hres;
149 static const WCHAR tagfmt[] = {'<','%','s','>','%','s','<','/','%','s','>',0};
151 hres = get_string_val(ctx, jsthis, &str);
152 if(FAILED(hres))
153 return hres;
155 if(r) {
156 jsstr_t *ret = jsstr_alloc_buf(jsstr_length(str) + 2*strlenW(tagname) + 5);
157 if(!ret) {
158 jsstr_release(str);
159 return E_OUTOFMEMORY;
162 sprintfW(ret->str, tagfmt, tagname, str->str, tagname);
163 *r = jsval_string(ret);
166 jsstr_release(str);
167 return S_OK;
170 static HRESULT do_attribute_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, unsigned argc, jsval_t *argv, jsval_t *r,
171 const WCHAR *tagname, const WCHAR *attr)
173 static const WCHAR tagfmtW[]
174 = {'<','%','s',' ','%','s','=','\"','%','s','\"','>','%','s','<','/','%','s','>',0};
175 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
177 jsstr_t *str, *attr_value = NULL;
178 const WCHAR *attr_str;
179 unsigned attr_len;
180 HRESULT hres;
182 hres = get_string_val(ctx, jsthis, &str);
183 if(FAILED(hres))
184 return hres;
186 if(argc) {
187 hres = to_string(ctx, argv[0], &attr_value);
188 if(FAILED(hres)) {
189 jsstr_release(str);
190 return hres;
192 attr_str = attr_value->str;
193 attr_len = jsstr_length(attr_value);
194 }else {
195 attr_str = undefinedW;
196 attr_len = sizeof(undefinedW)/sizeof(WCHAR)-1;
199 if(r) {
200 jsstr_t *ret;
202 ret = jsstr_alloc_buf(2*strlenW(tagname) + strlenW(attr) + attr_len + jsstr_length(str) + 9);
203 if(ret) {
204 sprintfW(ret->str, tagfmtW, tagname, attr, attr_str, str->str, tagname);
205 *r = jsval_string(ret);
206 }else {
207 hres = E_OUTOFMEMORY;
211 if(attr_value)
212 jsstr_release(attr_value);
213 jsstr_release(str);
214 return hres;
217 static HRESULT String_anchor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
218 jsval_t *r)
220 static const WCHAR fontW[] = {'A',0};
221 static const WCHAR colorW[] = {'N','A','M','E',0};
223 return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
226 static HRESULT String_big(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
227 jsval_t *r)
229 static const WCHAR bigtagW[] = {'B','I','G',0};
230 return do_attributeless_tag_format(ctx, jsthis, r, bigtagW);
233 static HRESULT String_blink(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
234 jsval_t *r)
236 static const WCHAR blinktagW[] = {'B','L','I','N','K',0};
237 return do_attributeless_tag_format(ctx, jsthis, r, blinktagW);
240 static HRESULT String_bold(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
241 jsval_t *r)
243 static const WCHAR boldtagW[] = {'B',0};
244 return do_attributeless_tag_format(ctx, jsthis, r, boldtagW);
247 /* ECMA-262 3rd Edition 15.5.4.5 */
248 static HRESULT String_charAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
249 jsval_t *r)
251 jsstr_t *str, *ret;
252 INT pos = 0;
253 HRESULT hres;
255 TRACE("\n");
257 hres = get_string_val(ctx, jsthis, &str);
258 if(FAILED(hres))
259 return hres;
261 if(argc) {
262 double d;
264 hres = to_integer(ctx, argv[0], &d);
265 if(FAILED(hres)) {
266 jsstr_release(str);
267 return hres;
269 pos = is_int32(d) ? d : -1;
272 if(!r) {
273 jsstr_release(str);
274 return S_OK;
277 if(0 <= pos && pos < jsstr_length(str)) {
278 ret = jsstr_alloc_len(str->str+pos, 1);
279 if(!ret)
280 return E_OUTOFMEMORY;
281 }else {
282 ret = jsstr_empty();
285 *r = jsval_string(ret);
286 return S_OK;
289 /* ECMA-262 3rd Edition 15.5.4.5 */
290 static HRESULT String_charCodeAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
291 jsval_t *r)
293 jsstr_t *str;
294 DWORD idx = 0;
295 HRESULT hres;
297 TRACE("\n");
299 hres = get_string_val(ctx, jsthis, &str);
300 if(FAILED(hres))
301 return hres;
303 if(argc > 0) {
304 double d;
306 hres = to_integer(ctx, argv[0], &d);
307 if(FAILED(hres)) {
308 jsstr_release(str);
309 return hres;
312 if(!is_int32(d) || d < 0 || d >= jsstr_length(str)) {
313 jsstr_release(str);
314 if(r)
315 *r = jsval_number(NAN);
316 return S_OK;
319 idx = d;
322 if(r)
323 *r = jsval_number(str->str[idx]);
325 jsstr_release(str);
326 return S_OK;
329 /* ECMA-262 3rd Edition 15.5.4.6 */
330 static HRESULT String_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
331 jsval_t *r)
333 jsstr_t **strs, *ret = NULL;
334 DWORD len = 0, i, l, str_cnt;
335 WCHAR *ptr;
336 HRESULT hres;
338 TRACE("\n");
340 str_cnt = argc+1;
341 strs = heap_alloc_zero(str_cnt * sizeof(*strs));
342 if(!strs)
343 return E_OUTOFMEMORY;
345 hres = to_string(ctx, jsval_disp(jsthis->u.disp), strs);
346 if(SUCCEEDED(hres)) {
347 for(i=0; i < argc; i++) {
348 hres = to_string(ctx, argv[i], strs+i+1);
349 if(FAILED(hres))
350 break;
354 if(SUCCEEDED(hres)) {
355 for(i=0; i < str_cnt; i++) {
356 len += jsstr_length(strs[i]);
357 if(len > JSSTR_MAX_LENGTH) {
358 hres = E_OUTOFMEMORY;
359 break;
363 ret = jsstr_alloc_buf(len);
364 if(ret) {
365 ptr = ret->str;
366 for(i=0; i < str_cnt; i++) {
367 l = jsstr_length(strs[i]);
368 memcpy(ptr, strs[i]->str, l*sizeof(WCHAR));
369 ptr += l;
371 }else {
372 hres = E_OUTOFMEMORY;
376 for(i=0; i < str_cnt; i++)
377 jsstr_release(strs[i]);
378 heap_free(strs);
380 if(FAILED(hres))
381 return hres;
383 if(r)
384 *r = jsval_string(ret);
385 else
386 jsstr_release(ret);
387 return S_OK;
390 static HRESULT String_fixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
391 jsval_t *r)
393 static const WCHAR fixedtagW[] = {'T','T',0};
394 return do_attributeless_tag_format(ctx, jsthis, r, fixedtagW);
397 static HRESULT String_fontcolor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
398 jsval_t *r)
400 static const WCHAR fontW[] = {'F','O','N','T',0};
401 static const WCHAR colorW[] = {'C','O','L','O','R',0};
403 return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
406 static HRESULT String_fontsize(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
407 jsval_t *r)
409 static const WCHAR fontW[] = {'F','O','N','T',0};
410 static const WCHAR colorW[] = {'S','I','Z','E',0};
412 return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
415 static HRESULT String_indexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
416 jsval_t *r)
418 jsstr_t *search_str, *str;
419 int length, pos = 0;
420 INT ret = -1;
421 HRESULT hres;
423 TRACE("\n");
425 hres = get_string_val(ctx, jsthis, &str);
426 if(FAILED(hres))
427 return hres;
429 length = jsstr_length(str);
430 if(!argc) {
431 if(r)
432 *r = jsval_number(-1);
433 jsstr_release(str);
434 return S_OK;
437 hres = to_string(ctx, argv[0], &search_str);
438 if(FAILED(hres)) {
439 jsstr_release(str);
440 return hres;
443 if(argc >= 2) {
444 double d;
446 hres = to_integer(ctx, argv[1], &d);
447 if(SUCCEEDED(hres) && d > 0.0)
448 pos = is_int32(d) ? min(length, d) : length;
451 if(SUCCEEDED(hres)) {
452 const WCHAR *ptr;
454 ptr = strstrW(str->str+pos, search_str->str);
455 if(ptr)
456 ret = ptr - str->str;
457 else
458 ret = -1;
461 jsstr_release(search_str);
462 jsstr_release(str);
463 if(FAILED(hres))
464 return hres;
466 if(r)
467 *r = jsval_number(ret);
468 return S_OK;
471 static HRESULT String_italics(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
472 jsval_t *r)
474 static const WCHAR italicstagW[] = {'I',0};
475 return do_attributeless_tag_format(ctx, jsthis, r, italicstagW);
478 /* ECMA-262 3rd Edition 15.5.4.8 */
479 static HRESULT String_lastIndexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
480 jsval_t *r)
482 unsigned pos = 0, search_len, length;
483 jsstr_t *search_str, *str;
484 INT ret = -1;
485 HRESULT hres;
487 TRACE("\n");
489 hres = get_string_val(ctx, jsthis, &str);
490 if(FAILED(hres))
491 return hres;
493 if(!argc) {
494 if(r)
495 *r = jsval_number(-1);
496 jsstr_release(str);
497 return S_OK;
500 hres = to_string(ctx, argv[0], &search_str);
501 if(FAILED(hres)) {
502 jsstr_release(str);
503 return hres;
506 search_len = jsstr_length(search_str);
507 length = jsstr_length(str);
509 if(argc >= 2) {
510 double d;
512 hres = to_integer(ctx, argv[1], &d);
513 if(SUCCEEDED(hres) && d > 0)
514 pos = is_int32(d) ? min(length, d) : length;
515 }else {
516 pos = length;
519 if(SUCCEEDED(hres) && length >= search_len) {
520 const WCHAR *ptr;
522 for(ptr = str->str+min(pos, length-search_len); ptr >= str->str; ptr--) {
523 if(!memcmp(ptr, search_str->str, search_len*sizeof(WCHAR))) {
524 ret = ptr-str->str;
525 break;
530 jsstr_release(search_str);
531 jsstr_release(str);
532 if(FAILED(hres))
533 return hres;
535 if(r)
536 *r = jsval_number(ret);
537 return S_OK;
540 static HRESULT String_link(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
541 jsval_t *r)
543 static const WCHAR fontW[] = {'A',0};
544 static const WCHAR colorW[] = {'H','R','E','F',0};
546 return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
549 /* ECMA-262 3rd Edition 15.5.4.10 */
550 static HRESULT String_match(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
551 jsval_t *r)
553 jsdisp_t *regexp = NULL;
554 jsstr_t *str;
555 HRESULT hres;
557 TRACE("\n");
559 if(!argc) {
560 if(r)
561 *r = jsval_null();
562 return S_OK;
565 if(is_object_instance(argv[0])) {
566 regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
567 if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
568 jsdisp_release(regexp);
569 regexp = NULL;
573 if(!regexp) {
574 jsstr_t *match_str;
576 hres = to_string(ctx, argv[0], &match_str);
577 if(FAILED(hres))
578 return hres;
580 hres = create_regexp(ctx, match_str, 0, &regexp);
581 jsstr_release(match_str);
582 if(FAILED(hres))
583 return hres;
586 hres = get_string_val(ctx, jsthis, &str);
587 if(SUCCEEDED(hres))
588 hres = regexp_string_match(ctx, regexp, str, r);
590 jsdisp_release(regexp);
591 jsstr_release(str);
592 return hres;
595 typedef struct {
596 WCHAR *buf;
597 DWORD size;
598 DWORD len;
599 } strbuf_t;
601 static HRESULT strbuf_append(strbuf_t *buf, const WCHAR *str, DWORD len)
603 if(!len)
604 return S_OK;
606 if(len + buf->len > buf->size) {
607 WCHAR *new_buf;
608 DWORD new_size;
610 new_size = buf->size ? buf->size<<1 : 16;
611 if(new_size < buf->len+len)
612 new_size = buf->len+len;
613 if(buf->buf)
614 new_buf = heap_realloc(buf->buf, new_size*sizeof(WCHAR));
615 else
616 new_buf = heap_alloc(new_size*sizeof(WCHAR));
617 if(!new_buf)
618 return E_OUTOFMEMORY;
620 buf->buf = new_buf;
621 buf->size = new_size;
624 memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
625 buf->len += len;
626 return S_OK;
629 static HRESULT rep_call(script_ctx_t *ctx, jsdisp_t *func, jsstr_t *str, match_result_t *match,
630 match_result_t *parens, DWORD parens_cnt, jsstr_t **ret)
632 jsval_t *argv;
633 unsigned argc;
634 jsval_t val;
635 jsstr_t *tmp_str;
636 DWORD i;
637 HRESULT hres = S_OK;
639 argc = parens_cnt+3;
640 argv = heap_alloc_zero(sizeof(*argv)*argc);
641 if(!argv)
642 return E_OUTOFMEMORY;
644 tmp_str = jsstr_alloc_len(match->str, match->len);
645 if(!tmp_str)
646 hres = E_OUTOFMEMORY;
647 argv[0] = jsval_string(tmp_str);
649 if(SUCCEEDED(hres)) {
650 for(i=0; i < parens_cnt; i++) {
651 tmp_str = jsstr_alloc_len(parens[i].str, parens[i].len);
652 if(!tmp_str) {
653 hres = E_OUTOFMEMORY;
654 break;
656 argv[i+1] = jsval_string(tmp_str);
660 if(SUCCEEDED(hres)) {
661 argv[parens_cnt+1] = jsval_number(match->str - str->str);
662 argv[parens_cnt+2] = jsval_string(str);
665 if(SUCCEEDED(hres))
666 hres = jsdisp_call_value(func, NULL, DISPATCH_METHOD, argc, argv, &val);
668 for(i=0; i <= parens_cnt; i++)
669 jsstr_release(get_string(argv[i]));
670 heap_free(argv);
672 if(FAILED(hres))
673 return hres;
675 hres = to_string(ctx, val, ret);
676 jsval_release(val);
677 return hres;
680 /* ECMA-262 3rd Edition 15.5.4.11 */
681 static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
682 jsval_t *r)
684 DWORD parens_cnt = 0, parens_size=0, rep_len=0;
685 jsstr_t *rep_str = NULL, *match_str = NULL, *str;
686 jsdisp_t *rep_func = NULL, *regexp = NULL;
687 match_result_t *parens = NULL, match = {NULL,0}, **parens_ptr = &parens;
688 strbuf_t ret = {NULL,0,0};
689 DWORD re_flags = REM_NO_CTX_UPDATE;
690 HRESULT hres = S_OK;
692 TRACE("\n");
694 hres = get_string_val(ctx, jsthis, &str);
695 if(FAILED(hres))
696 return hres;
698 if(!argc) {
699 if(r)
700 *r = jsval_string(str);
701 else
702 jsstr_release(str);
703 return S_OK;
706 if(is_object_instance(argv[0])) {
707 regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
708 if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
709 jsdisp_release(regexp);
710 regexp = NULL;
714 if(!regexp) {
715 hres = to_string(ctx, argv[0], &match_str);
716 if(FAILED(hres)) {
717 jsstr_release(str);
718 return hres;
722 if(argc >= 2) {
723 if(is_object_instance(argv[1])) {
724 rep_func = iface_to_jsdisp((IUnknown*)get_object(argv[1]));
725 if(rep_func && !is_class(rep_func, JSCLASS_FUNCTION)) {
726 jsdisp_release(rep_func);
727 rep_func = NULL;
731 if(!rep_func) {
732 hres = to_string(ctx, argv[1], &rep_str);
733 if(SUCCEEDED(hres)) {
734 rep_len = jsstr_length(rep_str);
735 if(!strchrW(rep_str->str, '$'))
736 parens_ptr = NULL;
741 if(SUCCEEDED(hres)) {
742 const WCHAR *cp, *ecp;
744 cp = ecp = str->str;
746 while(1) {
747 if(regexp) {
748 hres = regexp_match_next(ctx, regexp, re_flags, str, &cp, parens_ptr,
749 &parens_size, &parens_cnt, &match);
750 re_flags |= REM_CHECK_GLOBAL;
752 if(hres == S_FALSE) {
753 hres = S_OK;
754 break;
756 if(FAILED(hres))
757 break;
759 if(!match.len)
760 cp++;
761 }else {
762 match.str = strstrW(cp, match_str->str);
763 if(!match.str)
764 break;
765 match.len = jsstr_length(match_str);
766 cp = match.str+match.len;
769 hres = strbuf_append(&ret, ecp, match.str-ecp);
770 ecp = match.str+match.len;
771 if(FAILED(hres))
772 break;
774 if(rep_func) {
775 jsstr_t *cstr;
777 hres = rep_call(ctx, rep_func, str, &match, parens, parens_cnt, &cstr);
778 if(FAILED(hres))
779 break;
781 hres = strbuf_append(&ret, cstr->str, jsstr_length(cstr));
782 jsstr_release(cstr);
783 if(FAILED(hres))
784 break;
785 }else if(rep_str && regexp) {
786 const WCHAR *ptr = rep_str->str, *ptr2;
788 while((ptr2 = strchrW(ptr, '$'))) {
789 hres = strbuf_append(&ret, ptr, ptr2-ptr);
790 if(FAILED(hres))
791 break;
793 switch(ptr2[1]) {
794 case '$':
795 hres = strbuf_append(&ret, ptr2, 1);
796 ptr = ptr2+2;
797 break;
798 case '&':
799 hres = strbuf_append(&ret, match.str, match.len);
800 ptr = ptr2+2;
801 break;
802 case '`':
803 hres = strbuf_append(&ret, str->str, match.str-str->str);
804 ptr = ptr2+2;
805 break;
806 case '\'':
807 hres = strbuf_append(&ret, ecp, (str->str+jsstr_length(str))-ecp);
808 ptr = ptr2+2;
809 break;
810 default: {
811 DWORD idx;
813 if(!isdigitW(ptr2[1])) {
814 hres = strbuf_append(&ret, ptr2, 1);
815 ptr = ptr2+1;
816 break;
819 idx = ptr2[1] - '0';
820 if(isdigitW(ptr2[2]) && idx*10 + (ptr2[2]-'0') <= parens_cnt) {
821 idx = idx*10 + (ptr[2]-'0');
822 ptr = ptr2+3;
823 }else if(idx && idx <= parens_cnt) {
824 ptr = ptr2+2;
825 }else {
826 hres = strbuf_append(&ret, ptr2, 1);
827 ptr = ptr2+1;
828 break;
831 hres = strbuf_append(&ret, parens[idx-1].str, parens[idx-1].len);
835 if(FAILED(hres))
836 break;
839 if(SUCCEEDED(hres))
840 hres = strbuf_append(&ret, ptr, (rep_str->str+rep_len)-ptr);
841 if(FAILED(hres))
842 break;
843 }else if(rep_str) {
844 hres = strbuf_append(&ret, rep_str->str, rep_len);
845 if(FAILED(hres))
846 break;
847 }else {
848 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d'};
850 hres = strbuf_append(&ret, undefinedW, sizeof(undefinedW)/sizeof(WCHAR));
851 if(FAILED(hres))
852 break;
855 if(!regexp)
856 break;
859 if(SUCCEEDED(hres))
860 hres = strbuf_append(&ret, ecp, str->str+jsstr_length(str)-ecp);
863 if(rep_func)
864 jsdisp_release(rep_func);
865 if(rep_str)
866 jsstr_release(rep_str);
867 if(match_str)
868 jsstr_release(match_str);
869 heap_free(parens);
871 if(SUCCEEDED(hres) && match.str && regexp) {
872 jsstr_release(ctx->last_match);
873 ctx->last_match = jsstr_addref(str);
874 ctx->last_match_index = match.str-str->str;
875 ctx->last_match_length = match.len;
878 if(regexp)
879 jsdisp_release(regexp);
880 jsstr_release(str);
882 if(SUCCEEDED(hres) && r) {
883 jsstr_t *ret_str;
885 ret_str = jsstr_alloc_len(ret.buf, ret.len);
886 if(!ret_str)
887 return E_OUTOFMEMORY;
889 TRACE("= %s\n", debugstr_jsstr(ret_str));
890 *r = jsval_string(ret_str);
893 heap_free(ret.buf);
894 return hres;
897 static HRESULT String_search(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
898 jsval_t *r)
900 jsdisp_t *regexp = NULL;
901 const WCHAR *cp;
902 match_result_t match;
903 jsstr_t *str;
904 HRESULT hres;
906 TRACE("\n");
908 hres = get_string_val(ctx, jsthis, &str);
909 if(FAILED(hres))
910 return hres;
912 if(!argc) {
913 if(r)
914 *r = jsval_null();
915 jsstr_release(str);
916 return S_OK;
919 if(is_object_instance(argv[0])) {
920 regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
921 if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
922 jsdisp_release(regexp);
923 regexp = NULL;
927 if(!regexp) {
928 hres = create_regexp_var(ctx, argv[0], NULL, &regexp);
929 if(FAILED(hres)) {
930 jsstr_release(str);
931 return hres;
935 cp = str->str;
936 hres = regexp_match_next(ctx, regexp, REM_RESET_INDEX, str, &cp, NULL, NULL, NULL, &match);
937 jsstr_release(str);
938 jsdisp_release(regexp);
939 if(FAILED(hres))
940 return hres;
942 if(r)
943 *r = jsval_number(hres == S_OK ? match.str-str->str : -1);
944 return S_OK;
947 /* ECMA-262 3rd Edition 15.5.4.13 */
948 static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
949 jsval_t *r)
951 int start=0, end, length;
952 jsstr_t *str;
953 double d;
954 HRESULT hres;
956 TRACE("\n");
958 hres = get_string_val(ctx, jsthis, &str);
959 if(FAILED(hres))
960 return hres;
962 length = jsstr_length(str);
963 if(argc) {
964 hres = to_integer(ctx, argv[0], &d);
965 if(FAILED(hres)) {
966 jsstr_release(str);
967 return hres;
970 if(is_int32(d)) {
971 start = d;
972 if(start < 0) {
973 start = length + start;
974 if(start < 0)
975 start = 0;
976 }else if(start > length) {
977 start = length;
979 }else if(d > 0) {
980 start = length;
984 if(argc >= 2) {
985 hres = to_integer(ctx, argv[1], &d);
986 if(FAILED(hres)) {
987 jsstr_release(str);
988 return hres;
991 if(is_int32(d)) {
992 end = d;
993 if(end < 0) {
994 end = length + end;
995 if(end < 0)
996 end = 0;
997 }else if(end > length) {
998 end = length;
1000 }else {
1001 end = d < 0.0 ? 0 : length;
1003 }else {
1004 end = length;
1007 if(end < start)
1008 end = start;
1010 if(r) {
1011 jsstr_t *retstr = jsstr_alloc_len(str->str+start, end-start);
1012 if(!retstr) {
1013 jsstr_release(str);
1014 return E_OUTOFMEMORY;
1017 *r = jsval_string(retstr);
1020 jsstr_release(str);
1021 return S_OK;
1024 static HRESULT String_small(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1025 jsval_t *r)
1027 static const WCHAR smalltagW[] = {'S','M','A','L','L',0};
1028 return do_attributeless_tag_format(ctx, jsthis, r, smalltagW);
1031 static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1032 jsval_t *r)
1034 match_result_t match_result;
1035 DWORD length, i, match_len = 0;
1036 const WCHAR *ptr, *ptr2, *cp;
1037 unsigned limit = UINT32_MAX;
1038 jsdisp_t *array, *regexp = NULL;
1039 jsstr_t *str, *match_str = NULL, *tmp_str;
1040 HRESULT hres;
1042 TRACE("\n");
1044 if(argc != 1 && argc != 2) {
1045 FIXME("unsupported argc %u\n", argc);
1046 return E_NOTIMPL;
1049 hres = get_string_val(ctx, jsthis, &str);
1050 if(FAILED(hres))
1051 return hres;
1053 length = jsstr_length(str);
1055 if(argc > 1 && !is_undefined(argv[1])) {
1056 hres = to_uint32(ctx, argv[1], &limit);
1057 if(FAILED(hres)) {
1058 jsstr_release(str);
1059 return hres;
1063 if(is_object_instance(argv[0])) {
1064 regexp = iface_to_jsdisp((IUnknown*)get_object(argv[0]));
1065 if(regexp) {
1066 if(!is_class(regexp, JSCLASS_REGEXP)) {
1067 jsdisp_release(regexp);
1068 regexp = NULL;
1073 if(!regexp) {
1074 hres = to_string(ctx, argv[0], &match_str);
1075 if(FAILED(hres)) {
1076 jsstr_release(str);
1077 return hres;
1080 match_len = jsstr_length(match_str);
1081 if(!match_len) {
1082 jsstr_release(match_str);
1083 match_str = NULL;
1087 hres = create_array(ctx, 0, &array);
1089 if(SUCCEEDED(hres)) {
1090 ptr = cp = str->str;
1091 for(i=0; i<limit; i++) {
1092 if(regexp) {
1093 hres = regexp_match_next(ctx, regexp, 0, str, &cp, NULL, NULL, NULL, &match_result);
1094 if(hres != S_OK)
1095 break;
1096 ptr2 = match_result.str;
1097 }else if(match_str) {
1098 ptr2 = strstrW(ptr, match_str->str);
1099 if(!ptr2)
1100 break;
1101 }else {
1102 if(!*ptr)
1103 break;
1104 ptr2 = ptr+1;
1107 tmp_str = jsstr_alloc_len(ptr, ptr2-ptr);
1108 if(!tmp_str) {
1109 hres = E_OUTOFMEMORY;
1110 break;
1113 hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
1114 jsstr_release(tmp_str);
1115 if(FAILED(hres))
1116 break;
1118 if(regexp)
1119 ptr = cp;
1120 else if(match_str)
1121 ptr = ptr2 + match_len;
1122 else
1123 ptr++;
1127 if(SUCCEEDED(hres) && (match_str || regexp) && i<limit) {
1128 DWORD len = (str->str+length) - ptr;
1130 if(len || match_str) {
1131 tmp_str = jsstr_alloc_len(ptr, len);
1133 if(tmp_str) {
1134 hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
1135 jsstr_release(tmp_str);
1136 }else {
1137 hres = E_OUTOFMEMORY;
1142 if(regexp)
1143 jsdisp_release(regexp);
1144 if(match_str)
1145 jsstr_release(match_str);
1146 jsstr_release(str);
1148 if(SUCCEEDED(hres) && r)
1149 *r = jsval_obj(array);
1150 else
1151 jsdisp_release(array);
1153 return hres;
1156 static HRESULT String_strike(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1157 jsval_t *r)
1159 static const WCHAR striketagW[] = {'S','T','R','I','K','E',0};
1160 return do_attributeless_tag_format(ctx, jsthis, r, striketagW);
1163 static HRESULT String_sub(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1164 jsval_t *r)
1166 static const WCHAR subtagW[] = {'S','U','B',0};
1167 return do_attributeless_tag_format(ctx, jsthis, r, subtagW);
1170 /* ECMA-262 3rd Edition 15.5.4.15 */
1171 static HRESULT String_substring(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1172 jsval_t *r)
1174 INT start=0, end, length;
1175 jsstr_t *str;
1176 double d;
1177 HRESULT hres;
1179 TRACE("\n");
1181 hres = get_string_val(ctx, jsthis, &str);
1182 if(FAILED(hres))
1183 return hres;
1185 length = jsstr_length(str);
1186 if(argc >= 1) {
1187 hres = to_integer(ctx, argv[0], &d);
1188 if(FAILED(hres)) {
1189 jsstr_release(str);
1190 return hres;
1193 if(d >= 0)
1194 start = is_int32(d) ? min(length, d) : length;
1197 if(argc >= 2) {
1198 hres = to_integer(ctx, argv[1], &d);
1199 if(FAILED(hres)) {
1200 jsstr_release(str);
1201 return hres;
1204 if(d >= 0)
1205 end = is_int32(d) ? min(length, d) : length;
1206 else
1207 end = 0;
1208 }else {
1209 end = length;
1212 if(start > end) {
1213 INT tmp = start;
1214 start = end;
1215 end = tmp;
1218 if(r) {
1219 jsstr_t *ret = jsstr_alloc_len(str->str+start, end-start);
1220 if(!ret) {
1221 jsstr_release(str);
1222 return E_OUTOFMEMORY;
1224 *r = jsval_string(ret);
1226 jsstr_release(str);
1227 return S_OK;
1230 /* ECMA-262 3rd Edition B.2.3 */
1231 static HRESULT String_substr(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1232 jsval_t *r)
1234 int start=0, len, length;
1235 jsstr_t *str;
1236 double d;
1237 HRESULT hres;
1239 TRACE("\n");
1241 hres = get_string_val(ctx, jsthis, &str);
1242 if(FAILED(hres))
1243 return hres;
1245 length = jsstr_length(str);
1246 if(argc >= 1) {
1247 hres = to_integer(ctx, argv[0], &d);
1248 if(FAILED(hres)) {
1249 jsstr_release(str);
1250 return hres;
1253 if(d >= 0)
1254 start = is_int32(d) ? min(length, d) : length;
1257 if(argc >= 2) {
1258 hres = to_integer(ctx, argv[1], &d);
1259 if(FAILED(hres)) {
1260 jsstr_release(str);
1261 return hres;
1264 if(d >= 0.0)
1265 len = is_int32(d) ? min(length-start, d) : length-start;
1266 else
1267 len = 0;
1268 }else {
1269 len = length-start;
1272 hres = S_OK;
1273 if(r) {
1274 jsstr_t *ret = jsstr_alloc_len(str->str+start, len);
1275 if(ret)
1276 *r = jsval_string(ret);
1277 else
1278 hres = E_OUTOFMEMORY;
1281 jsstr_release(str);
1282 return hres;
1285 static HRESULT String_sup(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1286 jsval_t *r)
1288 static const WCHAR suptagW[] = {'S','U','P',0};
1289 return do_attributeless_tag_format(ctx, jsthis, r, suptagW);
1292 static HRESULT String_toLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1293 jsval_t *r)
1295 jsstr_t *str;
1296 HRESULT hres;
1298 TRACE("\n");
1300 hres = get_string_val(ctx, jsthis, &str);
1301 if(FAILED(hres))
1302 return hres;
1304 if(r) {
1305 jsstr_t *ret;
1307 ret = jsstr_alloc_len(str->str, jsstr_length(str));
1308 if(!ret) {
1309 jsstr_release(str);
1310 return E_OUTOFMEMORY;
1313 strlwrW(ret->str);
1314 *r = jsval_string(ret);
1316 jsstr_release(str);
1317 return S_OK;
1320 static HRESULT String_toUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1321 jsval_t *r)
1323 jsstr_t *str;
1324 HRESULT hres;
1326 TRACE("\n");
1328 hres = get_string_val(ctx, jsthis, &str);
1329 if(FAILED(hres))
1330 return hres;
1332 if(r) {
1333 jsstr_t *ret;
1335 ret = jsstr_alloc_len(str->str, jsstr_length(str));
1336 if(!ret) {
1337 jsstr_release(str);
1338 return E_OUTOFMEMORY;
1341 struprW(ret->str);
1342 *r = jsval_string(ret);
1344 jsstr_release(str);
1345 return S_OK;
1348 static HRESULT String_toLocaleLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1349 jsval_t *r)
1351 FIXME("\n");
1352 return E_NOTIMPL;
1355 static HRESULT String_toLocaleUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1356 jsval_t *r)
1358 FIXME("\n");
1359 return E_NOTIMPL;
1362 static HRESULT String_localeCompare(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1363 jsval_t *r)
1365 FIXME("\n");
1366 return E_NOTIMPL;
1369 static HRESULT String_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1370 jsval_t *r)
1372 StringInstance *This = string_from_vdisp(jsthis);
1374 TRACE("\n");
1376 switch(flags) {
1377 case INVOKE_FUNC:
1378 return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
1379 case DISPATCH_PROPERTYGET: {
1380 *r = jsval_string(jsstr_addref(This->str));
1381 break;
1383 default:
1384 FIXME("flags %x\n", flags);
1385 return E_NOTIMPL;
1388 return S_OK;
1391 static void String_destructor(jsdisp_t *dispex)
1393 StringInstance *This = (StringInstance*)dispex;
1395 jsstr_release(This->str);
1396 heap_free(This);
1399 static unsigned String_idx_length(jsdisp_t *jsdisp)
1401 StringInstance *string = (StringInstance*)jsdisp;
1404 * NOTE: For invoke version < 2, indexed array is not implemented at all.
1405 * Newer jscript.dll versions implement it on string type, not class,
1406 * which is not how it should work according to spec. IE9 implements it
1407 * properly, but it uses its own JavaScript engine inside MSHTML. We
1408 * implement it here, but in the way IE9 and spec work.
1410 return string->dispex.ctx->version < 2 ? 0 : jsstr_length(string->str);
1413 static HRESULT String_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r)
1415 StringInstance *string = (StringInstance*)jsdisp;
1416 jsstr_t *ret;
1418 TRACE("%p[%u] = %s\n", string, idx, debugstr_wn(string->str->str+idx, 1));
1420 ret = jsstr_alloc_len(string->str->str+idx, 1);
1421 if(!ret)
1422 return E_OUTOFMEMORY;
1424 *r = jsval_string(ret);
1425 return S_OK;
1428 static const builtin_prop_t String_props[] = {
1429 {anchorW, String_anchor, PROPF_METHOD|1},
1430 {bigW, String_big, PROPF_METHOD},
1431 {blinkW, String_blink, PROPF_METHOD},
1432 {boldW, String_bold, PROPF_METHOD},
1433 {charAtW, String_charAt, PROPF_METHOD|1},
1434 {charCodeAtW, String_charCodeAt, PROPF_METHOD|1},
1435 {concatW, String_concat, PROPF_METHOD|1},
1436 {fixedW, String_fixed, PROPF_METHOD},
1437 {fontcolorW, String_fontcolor, PROPF_METHOD|1},
1438 {fontsizeW, String_fontsize, PROPF_METHOD|1},
1439 {indexOfW, String_indexOf, PROPF_METHOD|2},
1440 {italicsW, String_italics, PROPF_METHOD},
1441 {lastIndexOfW, String_lastIndexOf, PROPF_METHOD|2},
1442 {lengthW, String_length, 0},
1443 {linkW, String_link, PROPF_METHOD|1},
1444 {localeCompareW, String_localeCompare, PROPF_METHOD|1},
1445 {matchW, String_match, PROPF_METHOD|1},
1446 {replaceW, String_replace, PROPF_METHOD|1},
1447 {searchW, String_search, PROPF_METHOD},
1448 {sliceW, String_slice, PROPF_METHOD},
1449 {smallW, String_small, PROPF_METHOD},
1450 {splitW, String_split, PROPF_METHOD|2},
1451 {strikeW, String_strike, PROPF_METHOD},
1452 {subW, String_sub, PROPF_METHOD},
1453 {substrW, String_substr, PROPF_METHOD|2},
1454 {substringW, String_substring, PROPF_METHOD|2},
1455 {supW, String_sup, PROPF_METHOD},
1456 {toLocaleLowerCaseW, String_toLocaleLowerCase, PROPF_METHOD},
1457 {toLocaleUpperCaseW, String_toLocaleUpperCase, PROPF_METHOD},
1458 {toLowerCaseW, String_toLowerCase, PROPF_METHOD},
1459 {toStringW, String_toString, PROPF_METHOD},
1460 {toUpperCaseW, String_toUpperCase, PROPF_METHOD},
1461 {valueOfW, String_valueOf, PROPF_METHOD}
1464 static const builtin_info_t String_info = {
1465 JSCLASS_STRING,
1466 {NULL, String_value, 0},
1467 sizeof(String_props)/sizeof(*String_props),
1468 String_props,
1469 String_destructor,
1470 NULL
1473 static const builtin_prop_t StringInst_props[] = {
1474 {lengthW, String_length, 0}
1477 static const builtin_info_t StringInst_info = {
1478 JSCLASS_STRING,
1479 {NULL, String_value, 0},
1480 sizeof(StringInst_props)/sizeof(*StringInst_props),
1481 StringInst_props,
1482 String_destructor,
1483 NULL,
1484 String_idx_length,
1485 String_idx_get
1488 /* ECMA-262 3rd Edition 15.5.3.2 */
1489 static HRESULT StringConstr_fromCharCode(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
1490 unsigned argc, jsval_t *argv, jsval_t *r)
1492 DWORD i, code;
1493 jsstr_t *ret;
1494 HRESULT hres;
1496 TRACE("\n");
1498 ret = jsstr_alloc_buf(argc);
1499 if(!ret)
1500 return E_OUTOFMEMORY;
1502 for(i=0; i<argc; i++) {
1503 hres = to_uint32(ctx, argv[i], &code);
1504 if(FAILED(hres)) {
1505 jsstr_release(ret);
1506 return hres;
1509 ret->str[i] = code;
1512 if(r)
1513 *r = jsval_string(ret);
1514 else
1515 jsstr_release(ret);
1516 return S_OK;
1519 static HRESULT StringConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1520 jsval_t *r)
1522 HRESULT hres;
1524 TRACE("\n");
1526 switch(flags) {
1527 case INVOKE_FUNC: {
1528 jsstr_t *str;
1530 if(argc) {
1531 hres = to_string(ctx, argv[0], &str);
1532 if(FAILED(hres))
1533 return hres;
1534 }else {
1535 str = jsstr_empty();
1538 *r = jsval_string(str);
1539 break;
1541 case DISPATCH_CONSTRUCT: {
1542 jsdisp_t *ret;
1544 if(argc) {
1545 jsstr_t *str;
1547 hres = to_string(ctx, argv[0], &str);
1548 if(FAILED(hres))
1549 return hres;
1551 hres = create_string(ctx, str, &ret);
1552 jsstr_release(str);
1553 }else {
1554 hres = create_string(ctx, jsstr_empty(), &ret);
1557 if(FAILED(hres))
1558 return hres;
1560 *r = jsval_obj(ret);
1561 break;
1564 default:
1565 FIXME("unimplemented flags: %x\n", flags);
1566 return E_NOTIMPL;
1569 return S_OK;
1572 static HRESULT string_alloc(script_ctx_t *ctx, jsdisp_t *object_prototype, jsstr_t *str, StringInstance **ret)
1574 StringInstance *string;
1575 HRESULT hres;
1577 string = heap_alloc_zero(sizeof(StringInstance));
1578 if(!string)
1579 return E_OUTOFMEMORY;
1581 if(object_prototype)
1582 hres = init_dispex(&string->dispex, ctx, &String_info, object_prototype);
1583 else
1584 hres = init_dispex_from_constr(&string->dispex, ctx, &StringInst_info, ctx->string_constr);
1585 if(FAILED(hres)) {
1586 heap_free(string);
1587 return hres;
1590 string->str = jsstr_addref(str);
1591 *ret = string;
1592 return S_OK;
1595 static const builtin_prop_t StringConstr_props[] = {
1596 {fromCharCodeW, StringConstr_fromCharCode, PROPF_METHOD},
1599 static const builtin_info_t StringConstr_info = {
1600 JSCLASS_FUNCTION,
1601 {NULL, Function_value, 0},
1602 sizeof(StringConstr_props)/sizeof(*StringConstr_props),
1603 StringConstr_props,
1604 NULL,
1605 NULL
1608 HRESULT create_string_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1610 StringInstance *string;
1611 HRESULT hres;
1613 static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
1615 hres = string_alloc(ctx, object_prototype, jsstr_empty(), &string);
1616 if(FAILED(hres))
1617 return hres;
1619 hres = create_builtin_constructor(ctx, StringConstr_value, StringW, &StringConstr_info,
1620 PROPF_CONSTR|1, &string->dispex, ret);
1622 jsdisp_release(&string->dispex);
1623 return hres;
1626 HRESULT create_string(script_ctx_t *ctx, jsstr_t *str, jsdisp_t **ret)
1628 StringInstance *string;
1629 HRESULT hres;
1631 hres = string_alloc(ctx, NULL, str, &string);
1632 if(FAILED(hres))
1633 return hres;
1635 *ret = &string->dispex;
1636 return S_OK;