jscript: Added Function.toString implementation.
[wine] / dlls / jscript / string.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "jscript.h"
20
21 #include "wine/debug.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
24
25 typedef struct {
26     DispatchEx dispex;
27
28     WCHAR *str;
29     DWORD length;
30 } StringInstance;
31
32 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
33 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
34 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
35 static const WCHAR anchorW[] = {'a','n','c','h','o','r',0};
36 static const WCHAR bigW[] = {'b','i','g',0};
37 static const WCHAR blinkW[] = {'b','l','i','n','k',0};
38 static const WCHAR boldW[] = {'b','o','l','d',0};
39 static const WCHAR charAtW[] = {'c','h','a','r','A','t',0};
40 static const WCHAR charCodeAtW[] = {'c','h','a','r','C','o','d','e','A','t',0};
41 static const WCHAR concatW[] = {'c','o','n','c','a','t',0};
42 static const WCHAR fixedW[] = {'f','i','x','e','d',0};
43 static const WCHAR fontcolorW[] = {'f','o','n','t','c','o','l','o','r',0};
44 static const WCHAR fontsizeW[] = {'f','o','n','t','s','i','z','e',0};
45 static const WCHAR indexOfW[] = {'i','n','d','e','x','O','f',0};
46 static const WCHAR italicsW[] = {'i','t','a','l','i','c','s',0};
47 static const WCHAR lastIndexOfW[] = {'l','a','s','t','I','n','d','e','x','O','f',0};
48 static const WCHAR linkW[] = {'l','i','n','k',0};
49 static const WCHAR matchW[] = {'m','a','t','c','h',0};
50 static const WCHAR replaceW[] = {'r','e','p','l','a','c','e',0};
51 static const WCHAR searchW[] = {'s','e','a','r','c','h',0};
52 static const WCHAR sliceW[] = {'s','l','i','c','e',0};
53 static const WCHAR smallW[] = {'s','m','a','l','l',0};
54 static const WCHAR splitW[] = {'s','p','l','i','t',0};
55 static const WCHAR strikeW[] = {'s','t','r','i','k','e',0};
56 static const WCHAR subW[] = {'s','u','b',0};
57 static const WCHAR substringW[] = {'s','u','b','s','t','r','i','n','g',0};
58 static const WCHAR substrW[] = {'s','u','b','s','t','r',0};
59 static const WCHAR supW[] = {'s','u','p',0};
60 static const WCHAR toLowerCaseW[] = {'t','o','L','o','w','e','r','C','a','s','e',0};
61 static const WCHAR toUpperCaseW[] = {'t','o','U','p','p','e','r','C','a','s','e',0};
62 static const WCHAR toLocaleLowerCaseW[] = {'t','o','L','o','c','a','l','e','L','o','w','e','r','C','a','s','e',0};
63 static const WCHAR toLocaleUpperCaseW[] = {'t','o','L','o','c','a','l','e','U','p','p','e','r','C','a','s','e',0};
64 static const WCHAR localeCompareW[] = {'l','o','c','a','l','e','C','o','m','p','a','r','e',0};
65 static const WCHAR hasOwnPropertyW[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0};
66 static const WCHAR propertyIsEnumerableW[] =
67     {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
68 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
69
70 static HRESULT String_length(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
71         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
72 {
73     TRACE("%p\n", dispex);
74
75     switch(flags) {
76     case DISPATCH_PROPERTYGET: {
77         StringInstance *jsthis = (StringInstance*)dispex;
78
79         V_VT(retv) = VT_I4;
80         V_I4(retv) = jsthis->length;
81         break;
82     }
83     default:
84         FIXME("unimplemented flags %x\n", flags);
85         return E_NOTIMPL;
86     }
87
88     return S_OK;
89 }
90
91 /* ECMA-262 3rd Edition    15.5.4.2 */
92 static HRESULT String_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
93         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
94 {
95     StringInstance *string;
96
97     TRACE("\n");
98
99     if(!is_class(dispex, JSCLASS_STRING)) {
100         WARN("this is not a string object\n");
101         return E_FAIL;
102     }
103
104     string = (StringInstance*)dispex;
105
106     if(retv) {
107         BSTR str = SysAllocString(string->str);
108         if(!str)
109             return E_OUTOFMEMORY;
110
111         V_VT(retv) = VT_BSTR;
112         V_BSTR(retv) = str;
113     }
114     return S_OK;
115 }
116
117 /* ECMA-262 3rd Edition    15.5.4.2 */
118 static HRESULT String_valueOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
119         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
120 {
121     TRACE("\n");
122
123     return String_toString(dispex, lcid, flags, dp, retv, ei, sp);
124 }
125
126 static HRESULT String_anchor(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
127         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
128 {
129     FIXME("\n");
130     return E_NOTIMPL;
131 }
132
133 static HRESULT String_big(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
134         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
135 {
136     FIXME("\n");
137     return E_NOTIMPL;
138 }
139
140 static HRESULT String_blink(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
141         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
142 {
143     FIXME("\n");
144     return E_NOTIMPL;
145 }
146
147 static HRESULT String_bold(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
148         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
149 {
150     FIXME("\n");
151     return E_NOTIMPL;
152 }
153
154 /* ECMA-262 3rd Edition    15.5.4.5 */
155 static HRESULT String_charAt(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
156         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
157 {
158     StringInstance *strobj;
159     BSTR str;
160     INT pos = 0;
161     HRESULT hres;
162
163     TRACE("\n");
164
165     if(dispex->builtin_info->class != JSCLASS_STRING) {
166         FIXME("not string this not supported\n");
167         return E_NOTIMPL;
168     }
169
170     strobj = (StringInstance*)dispex;
171
172     if(arg_cnt(dp)) {
173         VARIANT num;
174
175         hres = to_integer(dispex->ctx, get_arg(dp, 0), ei, &num);
176         if(FAILED(hres))
177             return hres;
178
179         if(V_VT(&num) == VT_I4) {
180             pos = V_I4(&num);
181         }else {
182             WARN("pos = %lf\n", V_R8(&num));
183             pos = -1;
184         }
185     }
186
187     if(!retv)
188         return S_OK;
189
190     if(0 <= pos && pos < strobj->length)
191         str = SysAllocStringLen(strobj->str+pos, 1);
192     else
193         str = SysAllocStringLen(NULL, 0);
194     if(!str)
195         return E_OUTOFMEMORY;
196
197     V_VT(retv) = VT_BSTR;
198     V_BSTR(retv) = str;
199     return S_OK;
200 }
201
202 /* ECMA-262 3rd Edition    15.5.4.5 */
203 static HRESULT String_charCodeAt(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
204         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
205 {
206     const WCHAR *str;
207     DWORD length, idx = 0;
208     HRESULT hres;
209
210     TRACE("\n");
211
212     if(dispex->builtin_info->class == JSCLASS_STRING) {
213         StringInstance *string = (StringInstance*)dispex;
214
215         str = string->str;
216         length = string->length;
217     }else {
218         FIXME("not string this not supported\n");
219         return E_NOTIMPL;
220     }
221
222     if(arg_cnt(dp) > 0) {
223         VARIANT v;
224
225         hres = to_integer(dispex->ctx, get_arg(dp, 0), ei, &v);
226         if(FAILED(hres))
227             return hres;
228
229         if(V_VT(&v) != VT_I4 || V_I4(&v) < 0 || V_I4(&v) >= length) {
230             FIXME("NAN\n");
231             return E_FAIL;
232         }
233
234         idx = V_I4(&v);
235     }
236
237     if(retv) {
238         V_VT(retv) = VT_I4;
239         V_I4(retv) = str[idx];
240     }
241     return S_OK;
242 }
243
244 /* ECMA-262 3rd Edition    15.5.4.6 */
245 static HRESULT String_concat(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
246         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
247 {
248     BSTR *strs = NULL, ret = NULL;
249     DWORD len = 0, i, l, str_cnt;
250     VARIANT var;
251     WCHAR *ptr;
252     HRESULT hres;
253
254     TRACE("\n");
255
256     str_cnt = arg_cnt(dp)+1;
257     strs = heap_alloc_zero(str_cnt * sizeof(BSTR));
258     if(!strs)
259         return E_OUTOFMEMORY;
260
261     V_VT(&var) = VT_DISPATCH;
262     V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(dispex);
263
264     hres = to_string(dispex->ctx, &var, ei, strs);
265     if(SUCCEEDED(hres)) {
266         for(i=0; i < arg_cnt(dp); i++) {
267             hres = to_string(dispex->ctx, get_arg(dp, i), ei, strs+i+1);
268             if(FAILED(hres))
269                 break;
270         }
271     }
272
273     if(SUCCEEDED(hres)) {
274         for(i=0; i < str_cnt; i++)
275             len += SysStringLen(strs[i]);
276
277         ptr = ret = SysAllocStringLen(NULL, len);
278
279         for(i=0; i < str_cnt; i++) {
280             l = SysStringLen(strs[i]);
281             memcpy(ptr, strs[i], l*sizeof(WCHAR));
282             ptr += l;
283         }
284     }
285
286     for(i=0; i < str_cnt; i++)
287         SysFreeString(strs[i]);
288     heap_free(strs);
289
290     if(FAILED(hres))
291         return hres;
292
293     if(retv) {
294         V_VT(retv) = VT_BSTR;
295         V_BSTR(retv) = ret;
296     }else {
297         SysFreeString(ret);
298     }
299     return S_OK;
300 }
301
302 static HRESULT String_fixed(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
303         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
304 {
305     FIXME("\n");
306     return E_NOTIMPL;
307 }
308
309 static HRESULT String_fontcolor(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
310         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
311 {
312     FIXME("\n");
313     return E_NOTIMPL;
314 }
315
316 static HRESULT String_fontsize(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
317         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
318 {
319     FIXME("\n");
320     return E_NOTIMPL;
321 }
322
323 static HRESULT String_indexOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
324         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
325 {
326     FIXME("\n");
327     return E_NOTIMPL;
328 }
329
330 static HRESULT String_italics(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
331         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
332 {
333     FIXME("\n");
334     return E_NOTIMPL;
335 }
336
337 static HRESULT String_lastIndexOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
338         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
339 {
340     FIXME("\n");
341     return E_NOTIMPL;
342 }
343
344 static HRESULT String_link(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
345         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
346 {
347     FIXME("\n");
348     return E_NOTIMPL;
349 }
350
351 /* ECMA-262 3rd Edition    15.5.4.10 */
352 static HRESULT String_match(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
353         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
354 {
355     StringInstance *This = (StringInstance*)dispex;
356     match_result_t *match_result;
357     DispatchEx *array;
358     VARIANT var, *arg_var;
359     DWORD match_cnt, i;
360     HRESULT hres = S_OK;
361
362     TRACE("\n");
363
364     if(dp->cArgs - dp->cNamedArgs != 1) {
365         FIXME("unsupported args\n");
366         return E_NOTIMPL;
367     }
368
369     arg_var = get_arg(dp, 0);
370     switch(V_VT(arg_var)) {
371     case VT_DISPATCH: {
372         DispatchEx *regexp;
373
374         regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
375         if(regexp) {
376             if(regexp->builtin_info->class == JSCLASS_REGEXP) {
377                 hres = regexp_match(regexp, This->str, This->length, FALSE, &match_result, &match_cnt);
378                 jsdisp_release(regexp);
379                 if(FAILED(hres))
380                     return hres;
381                 break;
382             }
383             jsdisp_release(regexp);
384         }
385     }
386     default:
387         FIXME("implemented only for regexp args\n");
388         return E_NOTIMPL;
389     }
390
391     if(!match_cnt) {
392         TRACE("no match\n");
393
394         if(retv)
395             V_VT(retv) = VT_NULL;
396         return S_OK;
397     }
398
399     hres = create_array(dispex->ctx, match_cnt, &array);
400     if(FAILED(hres))
401         return hres;
402
403     V_VT(&var) = VT_BSTR;
404
405     for(i=0; i < match_cnt; i++) {
406         V_BSTR(&var) = SysAllocStringLen(match_result[i].str, match_result[i].len);
407         if(!V_BSTR(&var)) {
408             hres = E_OUTOFMEMORY;
409             break;
410         }
411
412         hres = jsdisp_propput_idx(array, i, lcid, &var, ei, NULL/*FIXME*/);
413         SysFreeString(V_BSTR(&var));
414         if(FAILED(hres))
415             break;
416     }
417
418     if(FAILED(hres)) {
419         jsdisp_release(array);
420         return hres;
421     }
422
423     V_VT(retv) = VT_DISPATCH;
424     V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(array);
425     return S_OK;
426 }
427
428 static HRESULT String_replace(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
429         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
430 {
431     FIXME("\n");
432     return E_NOTIMPL;
433 }
434
435 static HRESULT String_search(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
436         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
437 {
438     FIXME("\n");
439     return E_NOTIMPL;
440 }
441
442 /* ECMA-262 3rd Edition    15.5.4.13 */
443 static HRESULT String_slice(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
444         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
445 {
446     const WCHAR *str;
447     DWORD length;
448     INT start=0, end;
449     VARIANT v;
450     HRESULT hres;
451
452     TRACE("\n");
453
454     if(is_class(dispex, JSCLASS_STRING)) {
455         StringInstance *string = (StringInstance*)dispex;
456
457         str = string->str;
458         length = string->length;
459     }else {
460         FIXME("this is not a string class");
461         return E_NOTIMPL;
462     }
463
464     if(arg_cnt(dp)) {
465         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-1, ei, &v);
466         if(FAILED(hres))
467             return hres;
468
469         if(V_VT(&v) == VT_I4) {
470             start = V_I4(&v);
471             if(start < 0) {
472                 start = length + start;
473                 if(start < 0)
474                     start = 0;
475             }else if(start > length) {
476                 start = length;
477             }
478         }else {
479             start = V_R8(&v) < 0.0 ? 0 : length;
480         }
481     }else {
482         start = 0;
483     }
484
485     if(arg_cnt(dp) >= 2) {
486         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-2, ei, &v);
487         if(FAILED(hres))
488             return hres;
489
490         if(V_VT(&v) == VT_I4) {
491             end = V_I4(&v);
492             if(end < 0) {
493                 end = length + end;
494                 if(end < 0)
495                     end = 0;
496             }else if(end > length) {
497                 end = length;
498             }
499         }else {
500             end = V_R8(&v) < 0.0 ? 0 : length;
501         }
502     }else {
503         end = length;
504     }
505
506     if(end < start)
507         end = start;
508
509     if(retv) {
510         BSTR retstr = SysAllocStringLen(str+start, end-start);
511         if(!str)
512             return E_OUTOFMEMORY;
513
514         V_VT(retv) = VT_BSTR;
515         V_BSTR(retv) = retstr;
516     }
517     return S_OK;
518 }
519
520 static HRESULT String_small(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
521         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
522 {
523     FIXME("\n");
524     return E_NOTIMPL;
525 }
526
527 static HRESULT String_split(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
528         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
529 {
530     FIXME("\n");
531     return E_NOTIMPL;
532 }
533
534 static HRESULT String_strike(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
535         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
536 {
537     FIXME("\n");
538     return E_NOTIMPL;
539 }
540
541 static HRESULT String_sub(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
542         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
543 {
544     FIXME("\n");
545     return E_NOTIMPL;
546 }
547
548 /* ECMA-262 3rd Edition    15.5.4.15 */
549 static HRESULT String_substring(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
550         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
551 {
552     const WCHAR *str;
553     INT start=0, end;
554     DWORD length;
555     VARIANT v;
556     HRESULT hres;
557
558     TRACE("\n");
559
560     if(is_class(dispex, JSCLASS_STRING)) {
561         StringInstance *string = (StringInstance*)dispex;
562
563         length = string->length;
564         str = string->str;
565     }else {
566         FIXME("not string this not supported\n");
567         return E_NOTIMPL;
568     }
569
570     if(arg_cnt(dp) >= 1) {
571         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-1, ei, &v);
572         if(FAILED(hres))
573             return hres;
574
575         if(V_VT(&v) == VT_I4) {
576             start = V_I4(&v);
577             if(start < 0)
578                 start = 0;
579             else if(start >= length)
580                 start = length;
581         }else {
582             start = V_R8(&v) < 0.0 ? 0 : length;
583         }
584     }
585
586     if(arg_cnt(dp) >= 2) {
587         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-2, ei, &v);
588         if(FAILED(hres))
589             return hres;
590
591         if(V_VT(&v) == VT_I4) {
592             end = V_I4(&v);
593             if(end < 0)
594                 end = 0;
595             else if(end > length)
596                 end = length;
597         }else {
598             end = V_R8(&v) < 0.0 ? 0 : length;
599         }
600     }else {
601         end = length;
602     }
603
604     if(start > end) {
605         INT tmp = start;
606         start = end;
607         end = tmp;
608     }
609
610     if(retv) {
611         V_VT(retv) = VT_BSTR;
612         V_BSTR(retv) = SysAllocStringLen(str+start, end-start);
613         if(!V_BSTR(retv))
614             return E_OUTOFMEMORY;
615     }
616     return S_OK;
617 }
618
619 static HRESULT String_substr(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
620         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
621 {
622     FIXME("\n");
623     return E_NOTIMPL;
624 }
625
626 static HRESULT String_sup(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
627         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
628 {
629     FIXME("\n");
630     return E_NOTIMPL;
631 }
632
633 static HRESULT String_toLowerCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
634         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
635 {
636     FIXME("\n");
637     return E_NOTIMPL;
638 }
639
640 static HRESULT String_toUpperCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
641         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
642 {
643     FIXME("\n");
644     return E_NOTIMPL;
645 }
646
647 static HRESULT String_toLocaleLowerCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
648         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
649 {
650     FIXME("\n");
651     return E_NOTIMPL;
652 }
653
654 static HRESULT String_toLocaleUpperCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
655         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
656 {
657     FIXME("\n");
658     return E_NOTIMPL;
659 }
660
661 static HRESULT String_localeCompare(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
662         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
663 {
664     FIXME("\n");
665     return E_NOTIMPL;
666 }
667
668 static HRESULT String_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
669         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
670 {
671     FIXME("\n");
672     return E_NOTIMPL;
673 }
674
675 static HRESULT String_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
676         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
677 {
678     FIXME("\n");
679     return E_NOTIMPL;
680 }
681
682 static HRESULT String_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
683         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
684 {
685     FIXME("\n");
686     return E_NOTIMPL;
687 }
688
689 static HRESULT String_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
690         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
691 {
692     StringInstance *This = (StringInstance*)dispex;
693
694     TRACE("\n");
695
696     switch(flags) {
697     case DISPATCH_PROPERTYGET: {
698         BSTR str = SysAllocString(This->str);
699         if(!str)
700             return E_OUTOFMEMORY;
701
702         V_VT(retv) = VT_BSTR;
703         V_BSTR(retv) = str;
704         break;
705     }
706     default:
707         FIXME("flags %x\n", flags);
708         return E_NOTIMPL;
709     }
710
711     return S_OK;
712 }
713
714 static void String_destructor(DispatchEx *dispex)
715 {
716     StringInstance *This = (StringInstance*)dispex;
717
718     heap_free(This->str);
719     heap_free(This);
720 }
721
722 static const builtin_prop_t String_props[] = {
723     {anchorW,                String_anchor,                PROPF_METHOD},
724     {bigW,                   String_big,                   PROPF_METHOD},
725     {blinkW,                 String_blink,                 PROPF_METHOD},
726     {boldW,                  String_bold,                  PROPF_METHOD},
727     {charAtW,                String_charAt,                PROPF_METHOD},
728     {charCodeAtW,            String_charCodeAt,            PROPF_METHOD},
729     {concatW,                String_concat,                PROPF_METHOD},
730     {fixedW,                 String_fixed,                 PROPF_METHOD},
731     {fontcolorW,             String_fontcolor,             PROPF_METHOD},
732     {fontsizeW,              String_fontsize,              PROPF_METHOD},
733     {hasOwnPropertyW,        String_hasOwnProperty,        PROPF_METHOD},
734     {indexOfW,               String_indexOf,               PROPF_METHOD},
735     {isPrototypeOfW,         String_isPrototypeOf,         PROPF_METHOD},
736     {italicsW,               String_italics,               PROPF_METHOD},
737     {lastIndexOfW,           String_lastIndexOf,           PROPF_METHOD},
738     {lengthW,                String_length,                0},
739     {linkW,                  String_link,                  PROPF_METHOD},
740     {localeCompareW,         String_localeCompare,         PROPF_METHOD},
741     {matchW,                 String_match,                 PROPF_METHOD},
742     {propertyIsEnumerableW,  String_propertyIsEnumerable,  PROPF_METHOD},
743     {replaceW,               String_replace,               PROPF_METHOD},
744     {searchW,                String_search,                PROPF_METHOD},
745     {sliceW,                 String_slice,                 PROPF_METHOD},
746     {smallW,                 String_small,                 PROPF_METHOD},
747     {splitW,                 String_split,                 PROPF_METHOD},
748     {strikeW,                String_strike,                PROPF_METHOD},
749     {substringW,             String_substring,             PROPF_METHOD},
750     {substrW,                String_substr,                PROPF_METHOD},
751     {subW,                   String_sub,                   PROPF_METHOD},
752     {supW,                   String_sup,                   PROPF_METHOD},
753     {toLocaleLowerCaseW,     String_toLocaleLowerCase,     PROPF_METHOD},
754     {toLocaleUpperCaseW,     String_toLocaleUpperCase,     PROPF_METHOD},
755     {toLowerCaseW,           String_toLowerCase,           PROPF_METHOD},
756     {toStringW,              String_toString,              PROPF_METHOD},
757     {toUpperCaseW,           String_toUpperCase,           PROPF_METHOD},
758     {valueOfW,               String_valueOf,               PROPF_METHOD}
759 };
760
761 static const builtin_info_t String_info = {
762     JSCLASS_STRING,
763     {NULL, String_value, 0},
764     sizeof(String_props)/sizeof(*String_props),
765     String_props,
766     String_destructor,
767     NULL
768 };
769
770 static HRESULT StringConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
771         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
772 {
773     HRESULT hres;
774
775     TRACE("\n");
776
777     switch(flags) {
778     case INVOKE_FUNC: {
779         BSTR str;
780
781         if(arg_cnt(dp)) {
782             hres = to_string(dispex->ctx, get_arg(dp, 0), ei, &str);
783             if(FAILED(hres))
784                 return hres;
785         }else {
786             str = SysAllocStringLen(NULL, 0);
787             if(!str)
788                 return E_OUTOFMEMORY;
789         }
790
791         V_VT(retv) = VT_BSTR;
792         V_BSTR(retv) = str;
793         break;
794     }
795     case DISPATCH_CONSTRUCT: {
796         DispatchEx *ret;
797
798         if(arg_cnt(dp)) {
799             BSTR str;
800
801             hres = to_string(dispex->ctx, get_arg(dp, 0), ei, &str);
802             if(FAILED(hres))
803                 return hres;
804
805             hres = create_string(dispex->ctx, str, SysStringLen(str), &ret);
806             SysFreeString(str);
807         }else {
808             hres = create_string(dispex->ctx, NULL, 0, &ret);
809         }
810
811         if(FAILED(hres))
812             return hres;
813
814         V_VT(retv) = VT_DISPATCH;
815         V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(ret);
816         break;
817     }
818
819     default:
820         FIXME("unimplemented flags: %x\n", flags);
821         return E_NOTIMPL;
822     }
823
824     return S_OK;
825 }
826
827 static HRESULT string_alloc(script_ctx_t *ctx, BOOL use_constr, StringInstance **ret)
828 {
829     StringInstance *string;
830     HRESULT hres;
831
832     string = heap_alloc_zero(sizeof(StringInstance));
833     if(!string)
834         return E_OUTOFMEMORY;
835
836     if(use_constr)
837         hres = init_dispex_from_constr(&string->dispex, ctx, &String_info, ctx->string_constr);
838     else
839         hres = init_dispex(&string->dispex, ctx, &String_info, NULL);
840     if(FAILED(hres)) {
841         heap_free(string);
842         return hres;
843     }
844
845     *ret = string;
846     return S_OK;
847 }
848
849 HRESULT create_string_constr(script_ctx_t *ctx, DispatchEx **ret)
850 {
851     StringInstance *string;
852     HRESULT hres;
853
854     hres = string_alloc(ctx, FALSE, &string);
855     if(FAILED(hres))
856         return hres;
857
858     hres = create_builtin_function(ctx, StringConstr_value, PROPF_CONSTR, &string->dispex, ret);
859
860     jsdisp_release(&string->dispex);
861     return hres;
862 }
863
864 HRESULT create_string(script_ctx_t *ctx, const WCHAR *str, DWORD len, DispatchEx **ret)
865 {
866     StringInstance *string;
867     HRESULT hres;
868
869     hres = string_alloc(ctx, TRUE, &string);
870     if(FAILED(hres))
871         return hres;
872
873     if(len == -1)
874         len = strlenW(str);
875
876     string->length = len;
877     string->str = heap_alloc((len+1)*sizeof(WCHAR));
878     if(!string->str) {
879         jsdisp_release(&string->dispex);
880         return E_OUTOFMEMORY;
881     }
882
883     memcpy(string->str, str, len*sizeof(WCHAR));
884     string->str[len] = 0;
885
886     *ret = &string->dispex;
887     return S_OK;
888
889 }