jscript: Added String.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 static HRESULT String_valueOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
118         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
119 {
120     FIXME("\n");
121     return E_NOTIMPL;
122 }
123
124 static HRESULT String_anchor(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
125         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
126 {
127     FIXME("\n");
128     return E_NOTIMPL;
129 }
130
131 static HRESULT String_big(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
132         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
133 {
134     FIXME("\n");
135     return E_NOTIMPL;
136 }
137
138 static HRESULT String_blink(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
139         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
140 {
141     FIXME("\n");
142     return E_NOTIMPL;
143 }
144
145 static HRESULT String_bold(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
146         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
147 {
148     FIXME("\n");
149     return E_NOTIMPL;
150 }
151
152 /* ECMA-262 3rd Edition    15.5.4.5 */
153 static HRESULT String_charAt(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
154         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
155 {
156     StringInstance *strobj;
157     BSTR str;
158     INT pos = 0;
159     HRESULT hres;
160
161     TRACE("\n");
162
163     if(dispex->builtin_info->class != JSCLASS_STRING) {
164         FIXME("not string this not supported\n");
165         return E_NOTIMPL;
166     }
167
168     strobj = (StringInstance*)dispex;
169
170     if(arg_cnt(dp)) {
171         VARIANT num;
172
173         hres = to_integer(dispex->ctx, get_arg(dp, 0), ei, &num);
174         if(FAILED(hres))
175             return hres;
176
177         if(V_VT(&num) == VT_I4) {
178             pos = V_I4(&num);
179         }else {
180             WARN("pos = %lf\n", V_R8(&num));
181             pos = -1;
182         }
183     }
184
185     if(!retv)
186         return S_OK;
187
188     if(0 <= pos && pos < strobj->length)
189         str = SysAllocStringLen(strobj->str+pos, 1);
190     else
191         str = SysAllocStringLen(NULL, 0);
192     if(!str)
193         return E_OUTOFMEMORY;
194
195     V_VT(retv) = VT_BSTR;
196     V_BSTR(retv) = str;
197     return S_OK;
198 }
199
200 static HRESULT String_charCodeAt(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
201         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
202 {
203     FIXME("\n");
204     return E_NOTIMPL;
205 }
206
207 static HRESULT String_concat(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
208         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
209 {
210     FIXME("\n");
211     return E_NOTIMPL;
212 }
213
214 static HRESULT String_fixed(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
215         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
216 {
217     FIXME("\n");
218     return E_NOTIMPL;
219 }
220
221 static HRESULT String_fontcolor(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
222         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
223 {
224     FIXME("\n");
225     return E_NOTIMPL;
226 }
227
228 static HRESULT String_fontsize(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
229         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
230 {
231     FIXME("\n");
232     return E_NOTIMPL;
233 }
234
235 static HRESULT String_indexOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
236         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
237 {
238     FIXME("\n");
239     return E_NOTIMPL;
240 }
241
242 static HRESULT String_italics(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
243         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
244 {
245     FIXME("\n");
246     return E_NOTIMPL;
247 }
248
249 static HRESULT String_lastIndexOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
250         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
251 {
252     FIXME("\n");
253     return E_NOTIMPL;
254 }
255
256 static HRESULT String_link(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
257         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
258 {
259     FIXME("\n");
260     return E_NOTIMPL;
261 }
262
263 /* ECMA-262 3rd Edition    15.5.4.10 */
264 static HRESULT String_match(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
265         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
266 {
267     StringInstance *This = (StringInstance*)dispex;
268     match_result_t *match_result;
269     DispatchEx *array;
270     VARIANT var, *arg_var;
271     DWORD match_cnt, i;
272     HRESULT hres = S_OK;
273
274     TRACE("\n");
275
276     if(dp->cArgs - dp->cNamedArgs != 1) {
277         FIXME("unsupported args\n");
278         return E_NOTIMPL;
279     }
280
281     arg_var = get_arg(dp, 0);
282     switch(V_VT(arg_var)) {
283     case VT_DISPATCH: {
284         DispatchEx *regexp;
285
286         regexp = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg_var));
287         if(regexp) {
288             if(regexp->builtin_info->class == JSCLASS_REGEXP) {
289                 hres = regexp_match(regexp, This->str, This->length, FALSE, &match_result, &match_cnt);
290                 jsdisp_release(regexp);
291                 if(FAILED(hres))
292                     return hres;
293                 break;
294             }
295             jsdisp_release(regexp);
296         }
297     }
298     default:
299         FIXME("implemented only for regexp args\n");
300         return E_NOTIMPL;
301     }
302
303     if(!match_cnt) {
304         TRACE("no match\n");
305
306         if(retv)
307             V_VT(retv) = VT_NULL;
308         return S_OK;
309     }
310
311     hres = create_array(dispex->ctx, match_cnt, &array);
312     if(FAILED(hres))
313         return hres;
314
315     V_VT(&var) = VT_BSTR;
316
317     for(i=0; i < match_cnt; i++) {
318         V_BSTR(&var) = SysAllocStringLen(match_result[i].str, match_result[i].len);
319         if(!V_BSTR(&var)) {
320             hres = E_OUTOFMEMORY;
321             break;
322         }
323
324         hres = jsdisp_propput_idx(array, i, lcid, &var, ei, NULL/*FIXME*/);
325         SysFreeString(V_BSTR(&var));
326         if(FAILED(hres))
327             break;
328     }
329
330     if(FAILED(hres)) {
331         jsdisp_release(array);
332         return hres;
333     }
334
335     V_VT(retv) = VT_DISPATCH;
336     V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(array);
337     return S_OK;
338 }
339
340 static HRESULT String_replace(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
341         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
342 {
343     FIXME("\n");
344     return E_NOTIMPL;
345 }
346
347 static HRESULT String_search(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
348         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
349 {
350     FIXME("\n");
351     return E_NOTIMPL;
352 }
353
354 static HRESULT String_slice(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
355         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
356 {
357     FIXME("\n");
358     return E_NOTIMPL;
359 }
360
361 static HRESULT String_small(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
362         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
363 {
364     FIXME("\n");
365     return E_NOTIMPL;
366 }
367
368 static HRESULT String_split(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
369         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
370 {
371     FIXME("\n");
372     return E_NOTIMPL;
373 }
374
375 static HRESULT String_strike(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
376         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
377 {
378     FIXME("\n");
379     return E_NOTIMPL;
380 }
381
382 static HRESULT String_sub(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
383         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
384 {
385     FIXME("\n");
386     return E_NOTIMPL;
387 }
388
389 /* ECMA-262 3rd Edition    15.5.4.15 */
390 static HRESULT String_substring(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
391         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
392 {
393     const WCHAR *str;
394     INT start=0, end;
395     DWORD length;
396     VARIANT v;
397     HRESULT hres;
398
399     TRACE("\n");
400
401     if(is_class(dispex, JSCLASS_STRING)) {
402         StringInstance *string = (StringInstance*)dispex;
403
404         length = string->length;
405         str = string->str;
406     }else {
407         FIXME("not string this not supported\n");
408         return E_NOTIMPL;
409     }
410
411     if(arg_cnt(dp) >= 1) {
412         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-1, ei, &v);
413         if(FAILED(hres))
414             return hres;
415
416         if(V_VT(&v) == VT_I4) {
417             start = V_I4(&v);
418             if(start < 0)
419                 start = 0;
420             else if(start >= length)
421                 start = length;
422         }else {
423             start = V_R8(&v) < 0.0 ? 0 : length;
424         }
425     }
426
427     if(arg_cnt(dp) >= 2) {
428         hres = to_integer(dispex->ctx, dp->rgvarg + dp->cArgs-2, ei, &v);
429         if(FAILED(hres))
430             return hres;
431
432         if(V_VT(&v) == VT_I4) {
433             end = V_I4(&v);
434             if(end < 0)
435                 end = 0;
436             else if(end > length)
437                 end = length;
438         }else {
439             end = V_R8(&v) < 0.0 ? 0 : length;
440         }
441     }else {
442         end = length;
443     }
444
445     if(start > end) {
446         INT tmp = start;
447         start = end;
448         end = tmp;
449     }
450
451     if(retv) {
452         V_VT(retv) = VT_BSTR;
453         V_BSTR(retv) = SysAllocStringLen(str+start, end-start);
454         if(!V_BSTR(retv))
455             return E_OUTOFMEMORY;
456     }
457     return S_OK;
458 }
459
460 static HRESULT String_substr(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
461         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
462 {
463     FIXME("\n");
464     return E_NOTIMPL;
465 }
466
467 static HRESULT String_sup(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
468         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
469 {
470     FIXME("\n");
471     return E_NOTIMPL;
472 }
473
474 static HRESULT String_toLowerCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
475         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
476 {
477     FIXME("\n");
478     return E_NOTIMPL;
479 }
480
481 static HRESULT String_toUpperCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
482         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
483 {
484     FIXME("\n");
485     return E_NOTIMPL;
486 }
487
488 static HRESULT String_toLocaleLowerCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
489         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
490 {
491     FIXME("\n");
492     return E_NOTIMPL;
493 }
494
495 static HRESULT String_toLocaleUpperCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
496         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
497 {
498     FIXME("\n");
499     return E_NOTIMPL;
500 }
501
502 static HRESULT String_localeCompare(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
503         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
504 {
505     FIXME("\n");
506     return E_NOTIMPL;
507 }
508
509 static HRESULT String_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
510         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
511 {
512     FIXME("\n");
513     return E_NOTIMPL;
514 }
515
516 static HRESULT String_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
517         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
518 {
519     FIXME("\n");
520     return E_NOTIMPL;
521 }
522
523 static HRESULT String_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
524         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
525 {
526     FIXME("\n");
527     return E_NOTIMPL;
528 }
529
530 static HRESULT String_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
531         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
532 {
533     FIXME("\n");
534     return E_NOTIMPL;
535 }
536
537 static void String_destructor(DispatchEx *dispex)
538 {
539     StringInstance *This = (StringInstance*)dispex;
540
541     heap_free(This->str);
542     heap_free(This);
543 }
544
545 static const builtin_prop_t String_props[] = {
546     {anchorW,                String_anchor,                PROPF_METHOD},
547     {bigW,                   String_big,                   PROPF_METHOD},
548     {blinkW,                 String_blink,                 PROPF_METHOD},
549     {boldW,                  String_bold,                  PROPF_METHOD},
550     {charAtW,                String_charAt,                PROPF_METHOD},
551     {charCodeAtW,            String_charCodeAt,            PROPF_METHOD},
552     {concatW,                String_concat,                PROPF_METHOD},
553     {fixedW,                 String_fixed,                 PROPF_METHOD},
554     {fontcolorW,             String_fontcolor,             PROPF_METHOD},
555     {fontsizeW,              String_fontsize,              PROPF_METHOD},
556     {hasOwnPropertyW,        String_hasOwnProperty,        PROPF_METHOD},
557     {indexOfW,               String_indexOf,               PROPF_METHOD},
558     {isPrototypeOfW,         String_isPrototypeOf,         PROPF_METHOD},
559     {italicsW,               String_italics,               PROPF_METHOD},
560     {lastIndexOfW,           String_lastIndexOf,           PROPF_METHOD},
561     {lengthW,                String_length,                0},
562     {linkW,                  String_link,                  PROPF_METHOD},
563     {localeCompareW,         String_localeCompare,         PROPF_METHOD},
564     {matchW,                 String_match,                 PROPF_METHOD},
565     {propertyIsEnumerableW,  String_propertyIsEnumerable,  PROPF_METHOD},
566     {replaceW,               String_replace,               PROPF_METHOD},
567     {searchW,                String_search,                PROPF_METHOD},
568     {sliceW,                 String_slice,                 PROPF_METHOD},
569     {smallW,                 String_small,                 PROPF_METHOD},
570     {splitW,                 String_split,                 PROPF_METHOD},
571     {strikeW,                String_strike,                PROPF_METHOD},
572     {substringW,             String_substring,             PROPF_METHOD},
573     {substrW,                String_substr,                PROPF_METHOD},
574     {subW,                   String_sub,                   PROPF_METHOD},
575     {supW,                   String_sup,                   PROPF_METHOD},
576     {toLocaleLowerCaseW,     String_toLocaleLowerCase,     PROPF_METHOD},
577     {toLocaleUpperCaseW,     String_toLocaleUpperCase,     PROPF_METHOD},
578     {toLowerCaseW,           String_toLowerCase,           PROPF_METHOD},
579     {toStringW,              String_toString,              PROPF_METHOD},
580     {toUpperCaseW,           String_toUpperCase,           PROPF_METHOD},
581     {valueOfW,               String_valueOf,               PROPF_METHOD}
582 };
583
584 static const builtin_info_t String_info = {
585     JSCLASS_STRING,
586     {NULL, String_value, 0},
587     sizeof(String_props)/sizeof(*String_props),
588     String_props,
589     String_destructor,
590     NULL
591 };
592
593 static HRESULT StringConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
594         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
595 {
596     FIXME("\n");
597     return E_NOTIMPL;
598 }
599
600 static HRESULT string_alloc(script_ctx_t *ctx, BOOL use_constr, StringInstance **ret)
601 {
602     StringInstance *string;
603     HRESULT hres;
604
605     string = heap_alloc_zero(sizeof(StringInstance));
606     if(!string)
607         return E_OUTOFMEMORY;
608
609     if(use_constr)
610         hres = init_dispex_from_constr(&string->dispex, ctx, &String_info, ctx->string_constr);
611     else
612         hres = init_dispex(&string->dispex, ctx, &String_info, NULL);
613     if(FAILED(hres)) {
614         heap_free(string);
615         return hres;
616     }
617
618     *ret = string;
619     return S_OK;
620 }
621
622 HRESULT create_string_constr(script_ctx_t *ctx, DispatchEx **ret)
623 {
624     StringInstance *string;
625     HRESULT hres;
626
627     hres = string_alloc(ctx, FALSE, &string);
628     if(FAILED(hres))
629         return hres;
630
631     hres = create_builtin_function(ctx, StringConstr_value, PROPF_CONSTR, &string->dispex, ret);
632
633     jsdisp_release(&string->dispex);
634     return hres;
635 }
636
637 HRESULT create_string(script_ctx_t *ctx, const WCHAR *str, DWORD len, DispatchEx **ret)
638 {
639     StringInstance *string;
640     HRESULT hres;
641
642     hres = string_alloc(ctx, TRUE, &string);
643     if(FAILED(hres))
644         return hres;
645
646     if(len == -1)
647         len = strlenW(str);
648
649     string->length = len;
650     string->str = heap_alloc((len+1)*sizeof(WCHAR));
651     if(!string->str) {
652         jsdisp_release(&string->dispex);
653         return E_OUTOFMEMORY;
654     }
655
656     memcpy(string->str, str, len*sizeof(WCHAR));
657     string->str[len] = 0;
658
659     *ret = &string->dispex;
660     return S_OK;
661
662 }