jscript: Added String default value 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 static HRESULT String_concat(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
245         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
246 {
247     FIXME("\n");
248     return E_NOTIMPL;
249 }
250
251 static HRESULT String_fixed(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
252         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
253 {
254     FIXME("\n");
255     return E_NOTIMPL;
256 }
257
258 static HRESULT String_fontcolor(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
259         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
260 {
261     FIXME("\n");
262     return E_NOTIMPL;
263 }
264
265 static HRESULT String_fontsize(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
266         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
267 {
268     FIXME("\n");
269     return E_NOTIMPL;
270 }
271
272 static HRESULT String_indexOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
273         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
274 {
275     FIXME("\n");
276     return E_NOTIMPL;
277 }
278
279 static HRESULT String_italics(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
280         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
281 {
282     FIXME("\n");
283     return E_NOTIMPL;
284 }
285
286 static HRESULT String_lastIndexOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
287         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
288 {
289     FIXME("\n");
290     return E_NOTIMPL;
291 }
292
293 static HRESULT String_link(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
294         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
295 {
296     FIXME("\n");
297     return E_NOTIMPL;
298 }
299
300 /* ECMA-262 3rd Edition    15.5.4.10 */
301 static HRESULT String_match(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
302         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
303 {
304     StringInstance *This = (StringInstance*)dispex;
305     match_result_t *match_result;
306     DispatchEx *array;
307     VARIANT var, *arg_var;
308     DWORD match_cnt, i;
309     HRESULT hres = S_OK;
310
311     TRACE("\n");
312
313     if(dp->cArgs - dp->cNamedArgs != 1) {
314         FIXME("unsupported args\n");
315         return E_NOTIMPL;
316     }
317
318     arg_var = get_arg(dp, 0);
319     switch(V_VT(arg_var)) {
320     case VT_DISPATCH: {
321         DispatchEx *regexp;
322
323         regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
324         if(regexp) {
325             if(regexp->builtin_info->class == JSCLASS_REGEXP) {
326                 hres = regexp_match(regexp, This->str, This->length, FALSE, &match_result, &match_cnt);
327                 jsdisp_release(regexp);
328                 if(FAILED(hres))
329                     return hres;
330                 break;
331             }
332             jsdisp_release(regexp);
333         }
334     }
335     default:
336         FIXME("implemented only for regexp args\n");
337         return E_NOTIMPL;
338     }
339
340     if(!match_cnt) {
341         TRACE("no match\n");
342
343         if(retv)
344             V_VT(retv) = VT_NULL;
345         return S_OK;
346     }
347
348     hres = create_array(dispex->ctx, match_cnt, &array);
349     if(FAILED(hres))
350         return hres;
351
352     V_VT(&var) = VT_BSTR;
353
354     for(i=0; i < match_cnt; i++) {
355         V_BSTR(&var) = SysAllocStringLen(match_result[i].str, match_result[i].len);
356         if(!V_BSTR(&var)) {
357             hres = E_OUTOFMEMORY;
358             break;
359         }
360
361         hres = jsdisp_propput_idx(array, i, lcid, &var, ei, NULL/*FIXME*/);
362         SysFreeString(V_BSTR(&var));
363         if(FAILED(hres))
364             break;
365     }
366
367     if(FAILED(hres)) {
368         jsdisp_release(array);
369         return hres;
370     }
371
372     V_VT(retv) = VT_DISPATCH;
373     V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(array);
374     return S_OK;
375 }
376
377 static HRESULT String_replace(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
378         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
379 {
380     FIXME("\n");
381     return E_NOTIMPL;
382 }
383
384 static HRESULT String_search(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
385         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
386 {
387     FIXME("\n");
388     return E_NOTIMPL;
389 }
390
391 /* ECMA-262 3rd Edition    15.5.4.13 */
392 static HRESULT String_slice(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
393         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
394 {
395     const WCHAR *str;
396     DWORD length;
397     INT start=0, end;
398     VARIANT v;
399     HRESULT hres;
400
401     TRACE("\n");
402
403     if(is_class(dispex, JSCLASS_STRING)) {
404         StringInstance *string = (StringInstance*)dispex;
405
406         str = string->str;
407         length = string->length;
408     }else {
409         FIXME("this is not a string class");
410         return E_NOTIMPL;
411     }
412
413     if(arg_cnt(dp)) {
414         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-1, ei, &v);
415         if(FAILED(hres))
416             return hres;
417
418         if(V_VT(&v) == VT_I4) {
419             start = V_I4(&v);
420             if(start < 0) {
421                 start = length + start;
422                 if(start < 0)
423                     start = 0;
424             }else if(start > length) {
425                 start = length;
426             }
427         }else {
428             start = V_R8(&v) < 0.0 ? 0 : length;
429         }
430     }else {
431         start = 0;
432     }
433
434     if(arg_cnt(dp) >= 2) {
435         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-2, ei, &v);
436         if(FAILED(hres))
437             return hres;
438
439         if(V_VT(&v) == VT_I4) {
440             end = V_I4(&v);
441             if(end < 0) {
442                 end = length + end;
443                 if(end < 0)
444                     end = 0;
445             }else if(end > length) {
446                 end = length;
447             }
448         }else {
449             end = V_R8(&v) < 0.0 ? 0 : length;
450         }
451     }else {
452         end = length;
453     }
454
455     if(end < start)
456         end = start;
457
458     if(retv) {
459         BSTR retstr = SysAllocStringLen(str+start, end-start);
460         if(!str)
461             return E_OUTOFMEMORY;
462
463         V_VT(retv) = VT_BSTR;
464         V_BSTR(retv) = retstr;
465     }
466     return S_OK;
467 }
468
469 static HRESULT String_small(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
470         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
471 {
472     FIXME("\n");
473     return E_NOTIMPL;
474 }
475
476 static HRESULT String_split(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
477         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
478 {
479     FIXME("\n");
480     return E_NOTIMPL;
481 }
482
483 static HRESULT String_strike(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
484         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
485 {
486     FIXME("\n");
487     return E_NOTIMPL;
488 }
489
490 static HRESULT String_sub(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
491         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
492 {
493     FIXME("\n");
494     return E_NOTIMPL;
495 }
496
497 /* ECMA-262 3rd Edition    15.5.4.15 */
498 static HRESULT String_substring(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
499         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
500 {
501     const WCHAR *str;
502     INT start=0, end;
503     DWORD length;
504     VARIANT v;
505     HRESULT hres;
506
507     TRACE("\n");
508
509     if(is_class(dispex, JSCLASS_STRING)) {
510         StringInstance *string = (StringInstance*)dispex;
511
512         length = string->length;
513         str = string->str;
514     }else {
515         FIXME("not string this not supported\n");
516         return E_NOTIMPL;
517     }
518
519     if(arg_cnt(dp) >= 1) {
520         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-1, ei, &v);
521         if(FAILED(hres))
522             return hres;
523
524         if(V_VT(&v) == VT_I4) {
525             start = V_I4(&v);
526             if(start < 0)
527                 start = 0;
528             else if(start >= length)
529                 start = length;
530         }else {
531             start = V_R8(&v) < 0.0 ? 0 : length;
532         }
533     }
534
535     if(arg_cnt(dp) >= 2) {
536         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-2, ei, &v);
537         if(FAILED(hres))
538             return hres;
539
540         if(V_VT(&v) == VT_I4) {
541             end = V_I4(&v);
542             if(end < 0)
543                 end = 0;
544             else if(end > length)
545                 end = length;
546         }else {
547             end = V_R8(&v) < 0.0 ? 0 : length;
548         }
549     }else {
550         end = length;
551     }
552
553     if(start > end) {
554         INT tmp = start;
555         start = end;
556         end = tmp;
557     }
558
559     if(retv) {
560         V_VT(retv) = VT_BSTR;
561         V_BSTR(retv) = SysAllocStringLen(str+start, end-start);
562         if(!V_BSTR(retv))
563             return E_OUTOFMEMORY;
564     }
565     return S_OK;
566 }
567
568 static HRESULT String_substr(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
569         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
570 {
571     FIXME("\n");
572     return E_NOTIMPL;
573 }
574
575 static HRESULT String_sup(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
576         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
577 {
578     FIXME("\n");
579     return E_NOTIMPL;
580 }
581
582 static HRESULT String_toLowerCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
583         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
584 {
585     FIXME("\n");
586     return E_NOTIMPL;
587 }
588
589 static HRESULT String_toUpperCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
590         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
591 {
592     FIXME("\n");
593     return E_NOTIMPL;
594 }
595
596 static HRESULT String_toLocaleLowerCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
597         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
598 {
599     FIXME("\n");
600     return E_NOTIMPL;
601 }
602
603 static HRESULT String_toLocaleUpperCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
604         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
605 {
606     FIXME("\n");
607     return E_NOTIMPL;
608 }
609
610 static HRESULT String_localeCompare(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
611         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
612 {
613     FIXME("\n");
614     return E_NOTIMPL;
615 }
616
617 static HRESULT String_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
618         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
619 {
620     FIXME("\n");
621     return E_NOTIMPL;
622 }
623
624 static HRESULT String_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
625         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
626 {
627     FIXME("\n");
628     return E_NOTIMPL;
629 }
630
631 static HRESULT String_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
632         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
633 {
634     FIXME("\n");
635     return E_NOTIMPL;
636 }
637
638 static HRESULT String_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
639         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
640 {
641     StringInstance *This = (StringInstance*)dispex;
642
643     TRACE("\n");
644
645     switch(flags) {
646     case DISPATCH_PROPERTYGET: {
647         BSTR str = SysAllocString(This->str);
648         if(!str)
649             return E_OUTOFMEMORY;
650
651         V_VT(retv) = VT_BSTR;
652         V_BSTR(retv) = str;
653         break;
654     }
655     default:
656         FIXME("flags %x\n", flags);
657         return E_NOTIMPL;
658     }
659
660     return S_OK;
661 }
662
663 static void String_destructor(DispatchEx *dispex)
664 {
665     StringInstance *This = (StringInstance*)dispex;
666
667     heap_free(This->str);
668     heap_free(This);
669 }
670
671 static const builtin_prop_t String_props[] = {
672     {anchorW,                String_anchor,                PROPF_METHOD},
673     {bigW,                   String_big,                   PROPF_METHOD},
674     {blinkW,                 String_blink,                 PROPF_METHOD},
675     {boldW,                  String_bold,                  PROPF_METHOD},
676     {charAtW,                String_charAt,                PROPF_METHOD},
677     {charCodeAtW,            String_charCodeAt,            PROPF_METHOD},
678     {concatW,                String_concat,                PROPF_METHOD},
679     {fixedW,                 String_fixed,                 PROPF_METHOD},
680     {fontcolorW,             String_fontcolor,             PROPF_METHOD},
681     {fontsizeW,              String_fontsize,              PROPF_METHOD},
682     {hasOwnPropertyW,        String_hasOwnProperty,        PROPF_METHOD},
683     {indexOfW,               String_indexOf,               PROPF_METHOD},
684     {isPrototypeOfW,         String_isPrototypeOf,         PROPF_METHOD},
685     {italicsW,               String_italics,               PROPF_METHOD},
686     {lastIndexOfW,           String_lastIndexOf,           PROPF_METHOD},
687     {lengthW,                String_length,                0},
688     {linkW,                  String_link,                  PROPF_METHOD},
689     {localeCompareW,         String_localeCompare,         PROPF_METHOD},
690     {matchW,                 String_match,                 PROPF_METHOD},
691     {propertyIsEnumerableW,  String_propertyIsEnumerable,  PROPF_METHOD},
692     {replaceW,               String_replace,               PROPF_METHOD},
693     {searchW,                String_search,                PROPF_METHOD},
694     {sliceW,                 String_slice,                 PROPF_METHOD},
695     {smallW,                 String_small,                 PROPF_METHOD},
696     {splitW,                 String_split,                 PROPF_METHOD},
697     {strikeW,                String_strike,                PROPF_METHOD},
698     {substringW,             String_substring,             PROPF_METHOD},
699     {substrW,                String_substr,                PROPF_METHOD},
700     {subW,                   String_sub,                   PROPF_METHOD},
701     {supW,                   String_sup,                   PROPF_METHOD},
702     {toLocaleLowerCaseW,     String_toLocaleLowerCase,     PROPF_METHOD},
703     {toLocaleUpperCaseW,     String_toLocaleUpperCase,     PROPF_METHOD},
704     {toLowerCaseW,           String_toLowerCase,           PROPF_METHOD},
705     {toStringW,              String_toString,              PROPF_METHOD},
706     {toUpperCaseW,           String_toUpperCase,           PROPF_METHOD},
707     {valueOfW,               String_valueOf,               PROPF_METHOD}
708 };
709
710 static const builtin_info_t String_info = {
711     JSCLASS_STRING,
712     {NULL, String_value, 0},
713     sizeof(String_props)/sizeof(*String_props),
714     String_props,
715     String_destructor,
716     NULL
717 };
718
719 static HRESULT StringConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
720         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
721 {
722     HRESULT hres;
723
724     switch(flags) {
725     case DISPATCH_CONSTRUCT: {
726         DispatchEx *ret;
727
728         if(arg_cnt(dp)) {
729             BSTR str;
730
731             hres = to_string(dispex->ctx, get_arg(dp, 0), ei, &str);
732             if(FAILED(hres))
733                 return hres;
734
735             hres = create_string(dispex->ctx, str, SysStringLen(str), &ret);
736             SysFreeString(str);
737         }else {
738             hres = create_string(dispex->ctx, NULL, 0, &ret);
739         }
740
741         if(FAILED(hres))
742             return hres;
743
744         V_VT(retv) = VT_DISPATCH;
745         V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(ret);
746         break;
747     }
748
749     default:
750         FIXME("unimplemented flags: %x\n", flags);
751         return E_NOTIMPL;
752     }
753
754     return S_OK;
755 }
756
757 static HRESULT string_alloc(script_ctx_t *ctx, BOOL use_constr, StringInstance **ret)
758 {
759     StringInstance *string;
760     HRESULT hres;
761
762     string = heap_alloc_zero(sizeof(StringInstance));
763     if(!string)
764         return E_OUTOFMEMORY;
765
766     if(use_constr)
767         hres = init_dispex_from_constr(&string->dispex, ctx, &String_info, ctx->string_constr);
768     else
769         hres = init_dispex(&string->dispex, ctx, &String_info, NULL);
770     if(FAILED(hres)) {
771         heap_free(string);
772         return hres;
773     }
774
775     *ret = string;
776     return S_OK;
777 }
778
779 HRESULT create_string_constr(script_ctx_t *ctx, DispatchEx **ret)
780 {
781     StringInstance *string;
782     HRESULT hres;
783
784     hres = string_alloc(ctx, FALSE, &string);
785     if(FAILED(hres))
786         return hres;
787
788     hres = create_builtin_function(ctx, StringConstr_value, PROPF_CONSTR, &string->dispex, ret);
789
790     jsdisp_release(&string->dispex);
791     return hres;
792 }
793
794 HRESULT create_string(script_ctx_t *ctx, const WCHAR *str, DWORD len, DispatchEx **ret)
795 {
796     StringInstance *string;
797     HRESULT hres;
798
799     hres = string_alloc(ctx, TRUE, &string);
800     if(FAILED(hres))
801         return hres;
802
803     if(len == -1)
804         len = strlenW(str);
805
806     string->length = len;
807     string->str = heap_alloc((len+1)*sizeof(WCHAR));
808     if(!string->str) {
809         jsdisp_release(&string->dispex);
810         return E_OUTOFMEMORY;
811     }
812
813     memcpy(string->str, str, len*sizeof(WCHAR));
814     string->str[len] = 0;
815
816     *ret = &string->dispex;
817     return S_OK;
818
819 }