xref: /reactos/dll/win32/jscript/string.c (revision 3e2d6582)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Copyright 2008 Jacek Caban for CodeWeavers
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
5c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
6c2c66affSColin Finck  * License as published by the Free Software Foundation; either
7c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
8c2c66affSColin Finck  *
9c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
10c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12c2c66affSColin Finck  * Lesser General Public License for more details.
13c2c66affSColin Finck  *
14c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
15c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
16c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17c2c66affSColin Finck  */
18c2c66affSColin Finck 
19*3e2d6582SAmine Khaldi 
20*3e2d6582SAmine Khaldi #include <math.h>
218dba275bSAmine Khaldi 
22c2c66affSColin Finck #include "jscript.h"
238dba275bSAmine Khaldi #include "regexp.h"
248dba275bSAmine Khaldi 
258dba275bSAmine Khaldi #include "wine/debug.h"
268dba275bSAmine Khaldi 
278dba275bSAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(jscript);
28c2c66affSColin Finck 
29c2c66affSColin Finck typedef struct {
30c2c66affSColin Finck     jsdisp_t dispex;
31c2c66affSColin Finck     jsstr_t *str;
32c2c66affSColin Finck } StringInstance;
33c2c66affSColin Finck 
34c2c66affSColin Finck static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
35c2c66affSColin Finck static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
36c2c66affSColin Finck static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
37c2c66affSColin Finck static const WCHAR anchorW[] = {'a','n','c','h','o','r',0};
38c2c66affSColin Finck static const WCHAR bigW[] = {'b','i','g',0};
39c2c66affSColin Finck static const WCHAR blinkW[] = {'b','l','i','n','k',0};
40c2c66affSColin Finck static const WCHAR boldW[] = {'b','o','l','d',0};
41c2c66affSColin Finck static const WCHAR charAtW[] = {'c','h','a','r','A','t',0};
42c2c66affSColin Finck static const WCHAR charCodeAtW[] = {'c','h','a','r','C','o','d','e','A','t',0};
43c2c66affSColin Finck static const WCHAR concatW[] = {'c','o','n','c','a','t',0};
44c2c66affSColin Finck static const WCHAR fixedW[] = {'f','i','x','e','d',0};
45c2c66affSColin Finck static const WCHAR fontcolorW[] = {'f','o','n','t','c','o','l','o','r',0};
46c2c66affSColin Finck static const WCHAR fontsizeW[] = {'f','o','n','t','s','i','z','e',0};
47c2c66affSColin Finck static const WCHAR indexOfW[] = {'i','n','d','e','x','O','f',0};
48c2c66affSColin Finck static const WCHAR italicsW[] = {'i','t','a','l','i','c','s',0};
49c2c66affSColin Finck static const WCHAR lastIndexOfW[] = {'l','a','s','t','I','n','d','e','x','O','f',0};
50c2c66affSColin Finck static const WCHAR linkW[] = {'l','i','n','k',0};
51c2c66affSColin Finck static const WCHAR matchW[] = {'m','a','t','c','h',0};
52c2c66affSColin Finck static const WCHAR replaceW[] = {'r','e','p','l','a','c','e',0};
53c2c66affSColin Finck static const WCHAR searchW[] = {'s','e','a','r','c','h',0};
54c2c66affSColin Finck static const WCHAR sliceW[] = {'s','l','i','c','e',0};
55c2c66affSColin Finck static const WCHAR smallW[] = {'s','m','a','l','l',0};
56c2c66affSColin Finck static const WCHAR splitW[] = {'s','p','l','i','t',0};
57c2c66affSColin Finck static const WCHAR strikeW[] = {'s','t','r','i','k','e',0};
58c2c66affSColin Finck static const WCHAR subW[] = {'s','u','b',0};
59c2c66affSColin Finck static const WCHAR substringW[] = {'s','u','b','s','t','r','i','n','g',0};
60c2c66affSColin Finck static const WCHAR substrW[] = {'s','u','b','s','t','r',0};
61c2c66affSColin Finck static const WCHAR supW[] = {'s','u','p',0};
62c2c66affSColin Finck static const WCHAR toLowerCaseW[] = {'t','o','L','o','w','e','r','C','a','s','e',0};
63c2c66affSColin Finck static const WCHAR toUpperCaseW[] = {'t','o','U','p','p','e','r','C','a','s','e',0};
64c2c66affSColin Finck static const WCHAR toLocaleLowerCaseW[] = {'t','o','L','o','c','a','l','e','L','o','w','e','r','C','a','s','e',0};
65c2c66affSColin Finck static const WCHAR toLocaleUpperCaseW[] = {'t','o','L','o','c','a','l','e','U','p','p','e','r','C','a','s','e',0};
663f071cc5SAmine Khaldi static const WCHAR trimW[] = {'t','r','i','m',0};
67c2c66affSColin Finck static const WCHAR localeCompareW[] = {'l','o','c','a','l','e','C','o','m','p','a','r','e',0};
68c2c66affSColin Finck static const WCHAR fromCharCodeW[] = {'f','r','o','m','C','h','a','r','C','o','d','e',0};
69c2c66affSColin Finck 
string_from_jsdisp(jsdisp_t * jsdisp)70c2c66affSColin Finck static inline StringInstance *string_from_jsdisp(jsdisp_t *jsdisp)
71c2c66affSColin Finck {
72c2c66affSColin Finck     return CONTAINING_RECORD(jsdisp, StringInstance, dispex);
73c2c66affSColin Finck }
74c2c66affSColin Finck 
string_from_vdisp(vdisp_t * vdisp)75c2c66affSColin Finck static inline StringInstance *string_from_vdisp(vdisp_t *vdisp)
76c2c66affSColin Finck {
77c2c66affSColin Finck     return string_from_jsdisp(vdisp->u.jsdisp);
78c2c66affSColin Finck }
79c2c66affSColin Finck 
string_this(vdisp_t * jsthis)80c2c66affSColin Finck static inline StringInstance *string_this(vdisp_t *jsthis)
81c2c66affSColin Finck {
82c2c66affSColin Finck     return is_vclass(jsthis, JSCLASS_STRING) ? string_from_vdisp(jsthis) : NULL;
83c2c66affSColin Finck }
84c2c66affSColin Finck 
get_string_val(script_ctx_t * ctx,vdisp_t * jsthis,jsstr_t ** val)85c2c66affSColin Finck static HRESULT get_string_val(script_ctx_t *ctx, vdisp_t *jsthis, jsstr_t **val)
86c2c66affSColin Finck {
87c2c66affSColin Finck     StringInstance *string;
88c2c66affSColin Finck 
89c2c66affSColin Finck     if((string = string_this(jsthis))) {
90c2c66affSColin Finck         *val = jsstr_addref(string->str);
91c2c66affSColin Finck         return S_OK;
92c2c66affSColin Finck     }
93c2c66affSColin Finck 
94c2c66affSColin Finck     return to_string(ctx, jsval_disp(jsthis->u.disp), val);
95c2c66affSColin Finck }
96c2c66affSColin Finck 
get_string_flat_val(script_ctx_t * ctx,vdisp_t * jsthis,jsstr_t ** jsval,const WCHAR ** val)97c2c66affSColin Finck static HRESULT get_string_flat_val(script_ctx_t *ctx, vdisp_t *jsthis, jsstr_t **jsval, const WCHAR **val)
98c2c66affSColin Finck {
99c2c66affSColin Finck     HRESULT hres;
100c2c66affSColin Finck 
101c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, jsval);
102c2c66affSColin Finck     if(FAILED(hres))
103c2c66affSColin Finck         return hres;
104c2c66affSColin Finck 
105c2c66affSColin Finck     *val = jsstr_flatten(*jsval);
106c2c66affSColin Finck     if(*val)
107c2c66affSColin Finck         return S_OK;
108c2c66affSColin Finck 
109c2c66affSColin Finck     jsstr_release(*jsval);
110c2c66affSColin Finck     return E_OUTOFMEMORY;
111c2c66affSColin Finck }
112c2c66affSColin Finck 
String_get_length(script_ctx_t * ctx,jsdisp_t * jsthis,jsval_t * r)113c2c66affSColin Finck static HRESULT String_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
114c2c66affSColin Finck {
115c2c66affSColin Finck     StringInstance *string = string_from_jsdisp(jsthis);
116c2c66affSColin Finck 
117c2c66affSColin Finck     TRACE("%p\n", jsthis);
118c2c66affSColin Finck 
119c2c66affSColin Finck     *r = jsval_number(jsstr_length(string->str));
120c2c66affSColin Finck     return S_OK;
121c2c66affSColin Finck }
122c2c66affSColin Finck 
stringobj_to_string(vdisp_t * jsthis,jsval_t * r)123c2c66affSColin Finck static HRESULT stringobj_to_string(vdisp_t *jsthis, jsval_t *r)
124c2c66affSColin Finck {
125c2c66affSColin Finck     StringInstance *string;
126c2c66affSColin Finck 
127c2c66affSColin Finck     if(!(string = string_this(jsthis))) {
128c2c66affSColin Finck         WARN("this is not a string object\n");
129c2c66affSColin Finck         return E_FAIL;
130c2c66affSColin Finck     }
131c2c66affSColin Finck 
132c2c66affSColin Finck     if(r)
133c2c66affSColin Finck         *r = jsval_string(jsstr_addref(string->str));
134c2c66affSColin Finck     return S_OK;
135c2c66affSColin Finck }
136c2c66affSColin Finck 
137c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.2 */
String_toString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)138c2c66affSColin Finck static HRESULT String_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
139c2c66affSColin Finck         jsval_t *r)
140c2c66affSColin Finck {
141c2c66affSColin Finck     TRACE("\n");
142c2c66affSColin Finck 
143c2c66affSColin Finck     return stringobj_to_string(jsthis, r);
144c2c66affSColin Finck }
145c2c66affSColin Finck 
146c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.2 */
String_valueOf(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)147c2c66affSColin Finck static HRESULT String_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
148c2c66affSColin Finck         jsval_t *r)
149c2c66affSColin Finck {
150c2c66affSColin Finck     TRACE("\n");
151c2c66affSColin Finck 
152c2c66affSColin Finck     return stringobj_to_string(jsthis, r);
153c2c66affSColin Finck }
154c2c66affSColin Finck 
do_attributeless_tag_format(script_ctx_t * ctx,vdisp_t * jsthis,jsval_t * r,const WCHAR * tagname)155c2c66affSColin Finck static HRESULT do_attributeless_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r, const WCHAR *tagname)
156c2c66affSColin Finck {
157c2c66affSColin Finck     unsigned tagname_len;
158c2c66affSColin Finck     jsstr_t *str, *ret;
159c2c66affSColin Finck     WCHAR *ptr;
160c2c66affSColin Finck     HRESULT hres;
161c2c66affSColin Finck 
162c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
163c2c66affSColin Finck     if(FAILED(hres))
164c2c66affSColin Finck         return hres;
165c2c66affSColin Finck 
166c2c66affSColin Finck     if(!r) {
167c2c66affSColin Finck         jsstr_release(str);
168c2c66affSColin Finck         return S_OK;
169c2c66affSColin Finck     }
170c2c66affSColin Finck 
171*3e2d6582SAmine Khaldi     tagname_len = lstrlenW(tagname);
172c2c66affSColin Finck 
173c2c66affSColin Finck     ret = jsstr_alloc_buf(jsstr_length(str) + 2*tagname_len + 5, &ptr);
174c2c66affSColin Finck     if(!ret) {
175c2c66affSColin Finck         jsstr_release(str);
176c2c66affSColin Finck         return E_OUTOFMEMORY;
177c2c66affSColin Finck     }
178c2c66affSColin Finck 
179c2c66affSColin Finck     *ptr++ = '<';
180c2c66affSColin Finck     memcpy(ptr, tagname, tagname_len*sizeof(WCHAR));
181c2c66affSColin Finck     ptr += tagname_len;
182c2c66affSColin Finck     *ptr++ = '>';
183c2c66affSColin Finck 
184c2c66affSColin Finck     ptr += jsstr_flush(str, ptr);
185c2c66affSColin Finck     jsstr_release(str);
186c2c66affSColin Finck 
187c2c66affSColin Finck     *ptr++ = '<';
188c2c66affSColin Finck     *ptr++ = '/';
189c2c66affSColin Finck     memcpy(ptr, tagname, tagname_len*sizeof(WCHAR));
190c2c66affSColin Finck     ptr += tagname_len;
191c2c66affSColin Finck     *ptr = '>';
192c2c66affSColin Finck 
193c2c66affSColin Finck     *r = jsval_string(ret);
194c2c66affSColin Finck     return S_OK;
195c2c66affSColin Finck }
196c2c66affSColin Finck 
do_attribute_tag_format(script_ctx_t * ctx,vdisp_t * jsthis,unsigned argc,jsval_t * argv,jsval_t * r,const WCHAR * tagname,const WCHAR * attrname)197c2c66affSColin Finck static HRESULT do_attribute_tag_format(script_ctx_t *ctx, vdisp_t *jsthis, unsigned argc, jsval_t *argv, jsval_t *r,
198c2c66affSColin Finck         const WCHAR *tagname, const WCHAR *attrname)
199c2c66affSColin Finck {
200c2c66affSColin Finck     jsstr_t *str, *attr_value = NULL;
201c2c66affSColin Finck     HRESULT hres;
202c2c66affSColin Finck 
203c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
204c2c66affSColin Finck     if(FAILED(hres))
205c2c66affSColin Finck         return hres;
206c2c66affSColin Finck 
207c2c66affSColin Finck     if(argc) {
208c2c66affSColin Finck         hres = to_string(ctx, argv[0], &attr_value);
209c2c66affSColin Finck         if(FAILED(hres)) {
210c2c66affSColin Finck             jsstr_release(str);
211c2c66affSColin Finck             return hres;
212c2c66affSColin Finck         }
213c2c66affSColin Finck     }else {
214c2c66affSColin Finck         attr_value = jsstr_undefined();
215c2c66affSColin Finck     }
216c2c66affSColin Finck 
217c2c66affSColin Finck     if(r) {
218*3e2d6582SAmine Khaldi         unsigned attrname_len = lstrlenW(attrname);
219*3e2d6582SAmine Khaldi         unsigned tagname_len = lstrlenW(tagname);
220c2c66affSColin Finck         jsstr_t *ret;
221c2c66affSColin Finck         WCHAR *ptr;
222c2c66affSColin Finck 
223c2c66affSColin Finck         ret = jsstr_alloc_buf(2*tagname_len + attrname_len + jsstr_length(attr_value) + jsstr_length(str) + 9, &ptr);
224c2c66affSColin Finck         if(ret) {
225c2c66affSColin Finck             *ptr++ = '<';
226c2c66affSColin Finck             memcpy(ptr, tagname, tagname_len*sizeof(WCHAR));
227c2c66affSColin Finck             ptr += tagname_len;
228c2c66affSColin Finck             *ptr++ = ' ';
229c2c66affSColin Finck             memcpy(ptr, attrname, attrname_len*sizeof(WCHAR));
230c2c66affSColin Finck             ptr += attrname_len;
231c2c66affSColin Finck             *ptr++ = '=';
232c2c66affSColin Finck             *ptr++ = '"';
233c2c66affSColin Finck             ptr += jsstr_flush(attr_value, ptr);
234c2c66affSColin Finck             *ptr++ = '"';
235c2c66affSColin Finck             *ptr++ = '>';
236c2c66affSColin Finck             ptr += jsstr_flush(str, ptr);
237c2c66affSColin Finck 
238c2c66affSColin Finck             *ptr++ = '<';
239c2c66affSColin Finck             *ptr++ = '/';
240c2c66affSColin Finck             memcpy(ptr, tagname, tagname_len*sizeof(WCHAR));
241c2c66affSColin Finck             ptr += tagname_len;
242c2c66affSColin Finck             *ptr = '>';
243c2c66affSColin Finck 
244c2c66affSColin Finck             *r = jsval_string(ret);
245c2c66affSColin Finck         }else {
246c2c66affSColin Finck             hres = E_OUTOFMEMORY;
247c2c66affSColin Finck         }
248c2c66affSColin Finck     }
249c2c66affSColin Finck 
250c2c66affSColin Finck     jsstr_release(attr_value);
251c2c66affSColin Finck     jsstr_release(str);
252c2c66affSColin Finck     return hres;
253c2c66affSColin Finck }
254c2c66affSColin Finck 
String_anchor(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)255c2c66affSColin Finck static HRESULT String_anchor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
256c2c66affSColin Finck         jsval_t *r)
257c2c66affSColin Finck {
258c2c66affSColin Finck     static const WCHAR fontW[] = {'A',0};
259c2c66affSColin Finck     static const WCHAR colorW[] = {'N','A','M','E',0};
260c2c66affSColin Finck 
261c2c66affSColin Finck     return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
262c2c66affSColin Finck }
263c2c66affSColin Finck 
String_big(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)264c2c66affSColin Finck static HRESULT String_big(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
265c2c66affSColin Finck         jsval_t *r)
266c2c66affSColin Finck {
267c2c66affSColin Finck     static const WCHAR bigtagW[] = {'B','I','G',0};
268c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, bigtagW);
269c2c66affSColin Finck }
270c2c66affSColin Finck 
String_blink(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)271c2c66affSColin Finck static HRESULT String_blink(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
272c2c66affSColin Finck         jsval_t *r)
273c2c66affSColin Finck {
274c2c66affSColin Finck     static const WCHAR blinktagW[] = {'B','L','I','N','K',0};
275c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, blinktagW);
276c2c66affSColin Finck }
277c2c66affSColin Finck 
String_bold(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)278c2c66affSColin Finck static HRESULT String_bold(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
279c2c66affSColin Finck         jsval_t *r)
280c2c66affSColin Finck {
281c2c66affSColin Finck     static const WCHAR boldtagW[] = {'B',0};
282c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, boldtagW);
283c2c66affSColin Finck }
284c2c66affSColin Finck 
285c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.5 */
String_charAt(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)286c2c66affSColin Finck static HRESULT String_charAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
287c2c66affSColin Finck         jsval_t *r)
288c2c66affSColin Finck {
289c2c66affSColin Finck     jsstr_t *str, *ret;
290c2c66affSColin Finck     INT pos = 0;
291c2c66affSColin Finck     HRESULT hres;
292c2c66affSColin Finck 
293c2c66affSColin Finck     TRACE("\n");
294c2c66affSColin Finck 
295c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
296c2c66affSColin Finck     if(FAILED(hres))
297c2c66affSColin Finck         return hres;
298c2c66affSColin Finck 
299c2c66affSColin Finck     if(argc) {
300c2c66affSColin Finck         double d;
301c2c66affSColin Finck 
302c2c66affSColin Finck         hres = to_integer(ctx, argv[0], &d);
303c2c66affSColin Finck         if(FAILED(hres)) {
304c2c66affSColin Finck             jsstr_release(str);
305c2c66affSColin Finck             return hres;
306c2c66affSColin Finck         }
307c2c66affSColin Finck         pos = is_int32(d) ? d : -1;
308c2c66affSColin Finck     }
309c2c66affSColin Finck 
310c2c66affSColin Finck     if(!r) {
311c2c66affSColin Finck         jsstr_release(str);
312c2c66affSColin Finck         return S_OK;
313c2c66affSColin Finck     }
314c2c66affSColin Finck 
315c2c66affSColin Finck     if(0 <= pos && pos < jsstr_length(str)) {
316c2c66affSColin Finck         ret = jsstr_substr(str, pos, 1);
317c2c66affSColin Finck         if(!ret)
318c2c66affSColin Finck             return E_OUTOFMEMORY;
319c2c66affSColin Finck     }else {
320c2c66affSColin Finck         ret = jsstr_empty();
321c2c66affSColin Finck     }
322c2c66affSColin Finck 
323c2c66affSColin Finck     *r = jsval_string(ret);
324c2c66affSColin Finck     return S_OK;
325c2c66affSColin Finck }
326c2c66affSColin Finck 
327c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.5 */
String_charCodeAt(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)328c2c66affSColin Finck static HRESULT String_charCodeAt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
329c2c66affSColin Finck         jsval_t *r)
330c2c66affSColin Finck {
331c2c66affSColin Finck     jsstr_t *str;
332c2c66affSColin Finck     DWORD idx = 0;
333c2c66affSColin Finck     HRESULT hres;
334c2c66affSColin Finck 
335c2c66affSColin Finck     TRACE("\n");
336c2c66affSColin Finck 
337c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
338c2c66affSColin Finck     if(FAILED(hres))
339c2c66affSColin Finck         return hres;
340c2c66affSColin Finck 
341c2c66affSColin Finck     if(argc > 0) {
342c2c66affSColin Finck         double d;
343c2c66affSColin Finck 
344c2c66affSColin Finck         hres = to_integer(ctx, argv[0], &d);
345c2c66affSColin Finck         if(FAILED(hres)) {
346c2c66affSColin Finck             jsstr_release(str);
347c2c66affSColin Finck             return hres;
348c2c66affSColin Finck         }
349c2c66affSColin Finck 
350c2c66affSColin Finck         if(!is_int32(d) || d < 0 || d >= jsstr_length(str)) {
351c2c66affSColin Finck             jsstr_release(str);
352c2c66affSColin Finck             if(r)
353c2c66affSColin Finck                 *r = jsval_number(NAN);
354c2c66affSColin Finck             return S_OK;
355c2c66affSColin Finck         }
356c2c66affSColin Finck 
357c2c66affSColin Finck         idx = d;
358c2c66affSColin Finck     }
359c2c66affSColin Finck 
360c2c66affSColin Finck     if(r) {
361c2c66affSColin Finck         WCHAR c;
362c2c66affSColin Finck         jsstr_extract(str, idx, 1, &c);
363c2c66affSColin Finck         *r = jsval_number(c);
364c2c66affSColin Finck     }
365c2c66affSColin Finck 
366c2c66affSColin Finck     jsstr_release(str);
367c2c66affSColin Finck     return S_OK;
368c2c66affSColin Finck }
369c2c66affSColin Finck 
370c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.6 */
String_concat(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)371c2c66affSColin Finck static HRESULT String_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
372c2c66affSColin Finck         jsval_t *r)
373c2c66affSColin Finck {
374c2c66affSColin Finck     jsstr_t *ret = NULL, *str;
375c2c66affSColin Finck     HRESULT hres;
376c2c66affSColin Finck 
377c2c66affSColin Finck     TRACE("\n");
378c2c66affSColin Finck 
379c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
380c2c66affSColin Finck     if(FAILED(hres))
381c2c66affSColin Finck         return hres;
382c2c66affSColin Finck 
383c2c66affSColin Finck     switch(argc) {
384c2c66affSColin Finck     case 0:
385c2c66affSColin Finck         ret = str;
386c2c66affSColin Finck         break;
387c2c66affSColin Finck     case 1: {
388c2c66affSColin Finck         jsstr_t *arg_str;
389c2c66affSColin Finck 
390c2c66affSColin Finck         hres = to_string(ctx, argv[0], &arg_str);
391c2c66affSColin Finck         if(FAILED(hres)) {
392c2c66affSColin Finck             jsstr_release(str);
393c2c66affSColin Finck             return hres;
394c2c66affSColin Finck         }
395c2c66affSColin Finck 
396c2c66affSColin Finck         ret = jsstr_concat(str, arg_str);
397c2c66affSColin Finck         jsstr_release(str);
398c2c66affSColin Finck         if(!ret)
399c2c66affSColin Finck             return E_OUTOFMEMORY;
400c2c66affSColin Finck         break;
401c2c66affSColin Finck     }
402c2c66affSColin Finck     default: {
403c2c66affSColin Finck         const unsigned str_cnt = argc+1;
404c2c66affSColin Finck         unsigned len = 0, i;
405c2c66affSColin Finck         jsstr_t **strs;
406c2c66affSColin Finck         WCHAR *ptr;
407c2c66affSColin Finck 
408c2c66affSColin Finck         strs = heap_alloc_zero(str_cnt * sizeof(*strs));
409c2c66affSColin Finck         if(!strs) {
410c2c66affSColin Finck             jsstr_release(str);
411c2c66affSColin Finck             return E_OUTOFMEMORY;
412c2c66affSColin Finck         }
413c2c66affSColin Finck 
414c2c66affSColin Finck         strs[0] = str;
415c2c66affSColin Finck         for(i=0; i < argc; i++) {
416c2c66affSColin Finck             hres = to_string(ctx, argv[i], strs+i+1);
417c2c66affSColin Finck             if(FAILED(hres))
418c2c66affSColin Finck                 break;
419c2c66affSColin Finck         }
420c2c66affSColin Finck 
421c2c66affSColin Finck         if(SUCCEEDED(hres)) {
422c2c66affSColin Finck             for(i=0; i < str_cnt; i++) {
423c2c66affSColin Finck                 len += jsstr_length(strs[i]);
424c2c66affSColin Finck                 if(len > JSSTR_MAX_LENGTH) {
425c2c66affSColin Finck                     hres = E_OUTOFMEMORY;
426c2c66affSColin Finck                     break;
427c2c66affSColin Finck                 }
428c2c66affSColin Finck             }
429c2c66affSColin Finck 
430c2c66affSColin Finck             if(SUCCEEDED(hres)) {
431c2c66affSColin Finck                 ret = jsstr_alloc_buf(len, &ptr);
432c2c66affSColin Finck                 if(ret) {
433c2c66affSColin Finck                     for(i=0; i < str_cnt; i++)
434c2c66affSColin Finck                         ptr += jsstr_flush(strs[i], ptr);
435c2c66affSColin Finck                 }else {
436c2c66affSColin Finck                     hres = E_OUTOFMEMORY;
437c2c66affSColin Finck                 }
438c2c66affSColin Finck             }
439c2c66affSColin Finck         }
440c2c66affSColin Finck 
441c2c66affSColin Finck         while(i--)
442c2c66affSColin Finck             jsstr_release(strs[i]);
443c2c66affSColin Finck         heap_free(strs);
444c2c66affSColin Finck         if(FAILED(hres))
445c2c66affSColin Finck             return hres;
446c2c66affSColin Finck     }
447c2c66affSColin Finck     }
448c2c66affSColin Finck 
449c2c66affSColin Finck     if(r)
450c2c66affSColin Finck         *r = jsval_string(ret);
451c2c66affSColin Finck     else
452c2c66affSColin Finck         jsstr_release(ret);
453c2c66affSColin Finck     return S_OK;
454c2c66affSColin Finck }
455c2c66affSColin Finck 
String_fixed(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)456c2c66affSColin Finck static HRESULT String_fixed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
457c2c66affSColin Finck         jsval_t *r)
458c2c66affSColin Finck {
459c2c66affSColin Finck     static const WCHAR fixedtagW[] = {'T','T',0};
460c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, fixedtagW);
461c2c66affSColin Finck }
462c2c66affSColin Finck 
String_fontcolor(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)463c2c66affSColin Finck static HRESULT String_fontcolor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
464c2c66affSColin Finck         jsval_t *r)
465c2c66affSColin Finck {
466c2c66affSColin Finck     static const WCHAR fontW[] = {'F','O','N','T',0};
467c2c66affSColin Finck     static const WCHAR colorW[] = {'C','O','L','O','R',0};
468c2c66affSColin Finck 
469c2c66affSColin Finck     return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
470c2c66affSColin Finck }
471c2c66affSColin Finck 
String_fontsize(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)472c2c66affSColin Finck static HRESULT String_fontsize(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
473c2c66affSColin Finck         jsval_t *r)
474c2c66affSColin Finck {
475c2c66affSColin Finck     static const WCHAR fontW[] = {'F','O','N','T',0};
476c2c66affSColin Finck     static const WCHAR colorW[] = {'S','I','Z','E',0};
477c2c66affSColin Finck 
478c2c66affSColin Finck     return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
479c2c66affSColin Finck }
480c2c66affSColin Finck 
String_indexOf(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)481c2c66affSColin Finck static HRESULT String_indexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
482c2c66affSColin Finck         jsval_t *r)
483c2c66affSColin Finck {
484c2c66affSColin Finck     unsigned pos = 0, search_len, length;
485c2c66affSColin Finck     jsstr_t *search_jsstr, *jsstr;
486c2c66affSColin Finck     const WCHAR *search_str, *str;
487c2c66affSColin Finck     INT ret = -1;
488c2c66affSColin Finck     HRESULT hres;
489c2c66affSColin Finck 
490c2c66affSColin Finck     TRACE("\n");
491c2c66affSColin Finck 
492c2c66affSColin Finck     hres = get_string_flat_val(ctx, jsthis, &jsstr, &str);
493c2c66affSColin Finck     if(FAILED(hres))
494c2c66affSColin Finck         return hres;
495c2c66affSColin Finck 
496c2c66affSColin Finck     if(!argc) {
497c2c66affSColin Finck         if(r)
498c2c66affSColin Finck             *r = jsval_number(-1);
499c2c66affSColin Finck         jsstr_release(jsstr);
500c2c66affSColin Finck         return S_OK;
501c2c66affSColin Finck     }
502c2c66affSColin Finck 
503c2c66affSColin Finck     hres = to_flat_string(ctx, argv[0], &search_jsstr, &search_str);
504c2c66affSColin Finck     if(FAILED(hres)) {
505c2c66affSColin Finck         jsstr_release(jsstr);
506c2c66affSColin Finck         return hres;
507c2c66affSColin Finck     }
508c2c66affSColin Finck 
509c2c66affSColin Finck     search_len = jsstr_length(search_jsstr);
510c2c66affSColin Finck     length = jsstr_length(jsstr);
511c2c66affSColin Finck 
512c2c66affSColin Finck     if(argc >= 2) {
513c2c66affSColin Finck         double d;
514c2c66affSColin Finck 
515c2c66affSColin Finck         hres = to_integer(ctx, argv[1], &d);
516c2c66affSColin Finck         if(SUCCEEDED(hres) && d > 0.0)
517c2c66affSColin Finck             pos = is_int32(d) ? min(length, d) : length;
518c2c66affSColin Finck     }
519c2c66affSColin Finck 
520c2c66affSColin Finck     if(SUCCEEDED(hres) && length >= search_len) {
521c2c66affSColin Finck         const WCHAR *end = str+length-search_len;
522c2c66affSColin Finck         const WCHAR *ptr;
523c2c66affSColin Finck 
524c2c66affSColin Finck         for(ptr = str+pos; ptr <= end; ptr++) {
525c2c66affSColin Finck             if(!memcmp(ptr, search_str, search_len*sizeof(WCHAR))) {
526c2c66affSColin Finck                 ret = ptr-str;
527c2c66affSColin Finck                 break;
528c2c66affSColin Finck             }
529c2c66affSColin Finck         }
530c2c66affSColin Finck     }
531c2c66affSColin Finck 
532c2c66affSColin Finck     jsstr_release(search_jsstr);
533c2c66affSColin Finck     jsstr_release(jsstr);
534c2c66affSColin Finck     if(FAILED(hres))
535c2c66affSColin Finck         return hres;
536c2c66affSColin Finck 
537c2c66affSColin Finck     if(r)
538c2c66affSColin Finck         *r = jsval_number(ret);
539c2c66affSColin Finck     return S_OK;
540c2c66affSColin Finck }
541c2c66affSColin Finck 
String_italics(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)542c2c66affSColin Finck static HRESULT String_italics(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
543c2c66affSColin Finck         jsval_t *r)
544c2c66affSColin Finck {
545c2c66affSColin Finck     static const WCHAR italicstagW[] = {'I',0};
546c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, italicstagW);
547c2c66affSColin Finck }
548c2c66affSColin Finck 
549c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.8 */
String_lastIndexOf(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)550c2c66affSColin Finck static HRESULT String_lastIndexOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
551c2c66affSColin Finck         jsval_t *r)
552c2c66affSColin Finck {
553c2c66affSColin Finck     unsigned pos = 0, search_len, length;
554c2c66affSColin Finck     jsstr_t *search_jsstr, *jsstr;
555c2c66affSColin Finck     const WCHAR *search_str, *str;
556c2c66affSColin Finck     INT ret = -1;
557c2c66affSColin Finck     HRESULT hres;
558c2c66affSColin Finck 
559c2c66affSColin Finck     TRACE("\n");
560c2c66affSColin Finck 
561c2c66affSColin Finck     hres = get_string_flat_val(ctx, jsthis, &jsstr, &str);
562c2c66affSColin Finck     if(FAILED(hres))
563c2c66affSColin Finck         return hres;
564c2c66affSColin Finck 
565c2c66affSColin Finck     if(!argc) {
566c2c66affSColin Finck         if(r)
567c2c66affSColin Finck             *r = jsval_number(-1);
568c2c66affSColin Finck         jsstr_release(jsstr);
569c2c66affSColin Finck         return S_OK;
570c2c66affSColin Finck     }
571c2c66affSColin Finck 
572c2c66affSColin Finck     hres = to_flat_string(ctx, argv[0], &search_jsstr, &search_str);
573c2c66affSColin Finck     if(FAILED(hres)) {
574c2c66affSColin Finck         jsstr_release(jsstr);
575c2c66affSColin Finck         return hres;
576c2c66affSColin Finck     }
577c2c66affSColin Finck 
578c2c66affSColin Finck     search_len = jsstr_length(search_jsstr);
579c2c66affSColin Finck     length = jsstr_length(jsstr);
580c2c66affSColin Finck 
581c2c66affSColin Finck     if(argc >= 2) {
582c2c66affSColin Finck         double d;
583c2c66affSColin Finck 
584c2c66affSColin Finck         hres = to_integer(ctx, argv[1], &d);
585c2c66affSColin Finck         if(SUCCEEDED(hres) && d > 0)
586c2c66affSColin Finck             pos = is_int32(d) ? min(length, d) : length;
587c2c66affSColin Finck     }else {
588c2c66affSColin Finck         pos = length;
589c2c66affSColin Finck     }
590c2c66affSColin Finck 
591c2c66affSColin Finck     if(SUCCEEDED(hres) && length >= search_len) {
592c2c66affSColin Finck         const WCHAR *ptr;
593c2c66affSColin Finck 
594c2c66affSColin Finck         for(ptr = str+min(pos, length-search_len); ptr >= str; ptr--) {
595c2c66affSColin Finck             if(!memcmp(ptr, search_str, search_len*sizeof(WCHAR))) {
596c2c66affSColin Finck                 ret = ptr-str;
597c2c66affSColin Finck                 break;
598c2c66affSColin Finck             }
599c2c66affSColin Finck         }
600c2c66affSColin Finck     }
601c2c66affSColin Finck 
602c2c66affSColin Finck     jsstr_release(search_jsstr);
603c2c66affSColin Finck     jsstr_release(jsstr);
604c2c66affSColin Finck     if(FAILED(hres))
605c2c66affSColin Finck         return hres;
606c2c66affSColin Finck 
607c2c66affSColin Finck     if(r)
608c2c66affSColin Finck         *r = jsval_number(ret);
609c2c66affSColin Finck     return S_OK;
610c2c66affSColin Finck }
611c2c66affSColin Finck 
String_link(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)612c2c66affSColin Finck static HRESULT String_link(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
613c2c66affSColin Finck         jsval_t *r)
614c2c66affSColin Finck {
615c2c66affSColin Finck     static const WCHAR fontW[] = {'A',0};
616c2c66affSColin Finck     static const WCHAR colorW[] = {'H','R','E','F',0};
617c2c66affSColin Finck 
618c2c66affSColin Finck     return do_attribute_tag_format(ctx, jsthis, argc, argv, r, fontW, colorW);
619c2c66affSColin Finck }
620c2c66affSColin Finck 
621c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.10 */
String_match(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)622c2c66affSColin Finck static HRESULT String_match(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
623c2c66affSColin Finck         jsval_t *r)
624c2c66affSColin Finck {
625c2c66affSColin Finck     jsdisp_t *regexp = NULL;
626c2c66affSColin Finck     jsstr_t *str;
627c2c66affSColin Finck     HRESULT hres;
628c2c66affSColin Finck 
629c2c66affSColin Finck     TRACE("\n");
630c2c66affSColin Finck 
631c2c66affSColin Finck     if(!argc) {
632c2c66affSColin Finck         if(r)
633c2c66affSColin Finck             *r = jsval_null();
634c2c66affSColin Finck         return S_OK;
635c2c66affSColin Finck     }
636c2c66affSColin Finck 
637c2c66affSColin Finck     if(is_object_instance(argv[0])) {
638c2c66affSColin Finck         regexp = iface_to_jsdisp(get_object(argv[0]));
639c2c66affSColin Finck         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
640c2c66affSColin Finck             jsdisp_release(regexp);
641c2c66affSColin Finck             regexp = NULL;
642c2c66affSColin Finck         }
643c2c66affSColin Finck     }
644c2c66affSColin Finck 
645c2c66affSColin Finck     if(!regexp) {
646c2c66affSColin Finck         jsstr_t *match_str;
647c2c66affSColin Finck 
648c2c66affSColin Finck         hres = to_string(ctx, argv[0], &match_str);
649c2c66affSColin Finck         if(FAILED(hres))
650c2c66affSColin Finck             return hres;
651c2c66affSColin Finck 
652c2c66affSColin Finck         hres = create_regexp(ctx, match_str, 0, &regexp);
653c2c66affSColin Finck         jsstr_release(match_str);
654c2c66affSColin Finck         if(FAILED(hres))
655c2c66affSColin Finck             return hres;
656c2c66affSColin Finck     }
657c2c66affSColin Finck 
658c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
659c2c66affSColin Finck     if(SUCCEEDED(hres))
660c2c66affSColin Finck         hres = regexp_string_match(ctx, regexp, str, r);
661c2c66affSColin Finck 
662c2c66affSColin Finck     jsdisp_release(regexp);
663c2c66affSColin Finck     jsstr_release(str);
664c2c66affSColin Finck     return hres;
665c2c66affSColin Finck }
666c2c66affSColin Finck 
667c2c66affSColin Finck typedef struct {
668c2c66affSColin Finck     WCHAR *buf;
669c2c66affSColin Finck     DWORD size;
670c2c66affSColin Finck     DWORD len;
671c2c66affSColin Finck } strbuf_t;
672c2c66affSColin Finck 
strbuf_ensure_size(strbuf_t * buf,unsigned len)673c2c66affSColin Finck static BOOL strbuf_ensure_size(strbuf_t *buf, unsigned len)
674c2c66affSColin Finck {
675c2c66affSColin Finck     WCHAR *new_buf;
676c2c66affSColin Finck     DWORD new_size;
677c2c66affSColin Finck 
678c2c66affSColin Finck     if(len <= buf->size)
679c2c66affSColin Finck         return TRUE;
680c2c66affSColin Finck 
681c2c66affSColin Finck     new_size = buf->size ? buf->size<<1 : 16;
682c2c66affSColin Finck     if(new_size < len)
683c2c66affSColin Finck         new_size = len;
684c2c66affSColin Finck     if(buf->buf)
685c2c66affSColin Finck         new_buf = heap_realloc(buf->buf, new_size*sizeof(WCHAR));
686c2c66affSColin Finck     else
687c2c66affSColin Finck         new_buf = heap_alloc(new_size*sizeof(WCHAR));
688c2c66affSColin Finck     if(!new_buf)
689c2c66affSColin Finck         return FALSE;
690c2c66affSColin Finck 
691c2c66affSColin Finck     buf->buf = new_buf;
692c2c66affSColin Finck     buf->size = new_size;
693c2c66affSColin Finck     return TRUE;
694c2c66affSColin Finck }
695c2c66affSColin Finck 
strbuf_append(strbuf_t * buf,const WCHAR * str,DWORD len)696c2c66affSColin Finck static HRESULT strbuf_append(strbuf_t *buf, const WCHAR *str, DWORD len)
697c2c66affSColin Finck {
698c2c66affSColin Finck     if(!len)
699c2c66affSColin Finck         return S_OK;
700c2c66affSColin Finck 
701c2c66affSColin Finck     if(!strbuf_ensure_size(buf, buf->len+len))
702c2c66affSColin Finck         return E_OUTOFMEMORY;
703c2c66affSColin Finck 
704c2c66affSColin Finck     memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
705c2c66affSColin Finck     buf->len += len;
706c2c66affSColin Finck     return S_OK;
707c2c66affSColin Finck }
708c2c66affSColin Finck 
strbuf_append_jsstr(strbuf_t * buf,jsstr_t * str)709c2c66affSColin Finck static HRESULT strbuf_append_jsstr(strbuf_t *buf, jsstr_t *str)
710c2c66affSColin Finck {
711c2c66affSColin Finck     if(!strbuf_ensure_size(buf, buf->len+jsstr_length(str)))
712c2c66affSColin Finck         return E_OUTOFMEMORY;
713c2c66affSColin Finck 
714c2c66affSColin Finck     jsstr_flush(str, buf->buf+buf->len);
715c2c66affSColin Finck     buf->len += jsstr_length(str);
716c2c66affSColin Finck     return S_OK;
717c2c66affSColin Finck }
718c2c66affSColin Finck 
rep_call(script_ctx_t * ctx,jsdisp_t * func,jsstr_t * jsstr,const WCHAR * str,match_state_t * match,jsstr_t ** ret)719c2c66affSColin Finck static HRESULT rep_call(script_ctx_t *ctx, jsdisp_t *func,
720c2c66affSColin Finck         jsstr_t *jsstr, const WCHAR *str, match_state_t *match, jsstr_t **ret)
721c2c66affSColin Finck {
722c2c66affSColin Finck     jsval_t *argv;
723c2c66affSColin Finck     unsigned argc;
724c2c66affSColin Finck     jsval_t val;
725c2c66affSColin Finck     jsstr_t *tmp_str;
726c2c66affSColin Finck     DWORD i;
727c2c66affSColin Finck     HRESULT hres = S_OK;
728c2c66affSColin Finck 
729c2c66affSColin Finck     argc = match->paren_count+3;
730c2c66affSColin Finck     argv = heap_alloc_zero(sizeof(*argv)*argc);
731c2c66affSColin Finck     if(!argv)
732c2c66affSColin Finck         return E_OUTOFMEMORY;
733c2c66affSColin Finck 
734c2c66affSColin Finck     tmp_str = jsstr_alloc_len(match->cp-match->match_len, match->match_len);
735c2c66affSColin Finck     if(!tmp_str)
736c2c66affSColin Finck         hres = E_OUTOFMEMORY;
737c2c66affSColin Finck     argv[0] = jsval_string(tmp_str);
738c2c66affSColin Finck 
739c2c66affSColin Finck     if(SUCCEEDED(hres)) {
740c2c66affSColin Finck         for(i=0; i < match->paren_count; i++) {
741c2c66affSColin Finck             if(match->parens[i].index != -1)
742c2c66affSColin Finck                 tmp_str = jsstr_substr(jsstr, match->parens[i].index, match->parens[i].length);
743c2c66affSColin Finck             else
744c2c66affSColin Finck                 tmp_str = jsstr_empty();
745c2c66affSColin Finck             if(!tmp_str) {
746c2c66affSColin Finck                hres = E_OUTOFMEMORY;
747c2c66affSColin Finck                break;
748c2c66affSColin Finck             }
749c2c66affSColin Finck             argv[i+1] = jsval_string(tmp_str);
750c2c66affSColin Finck         }
751c2c66affSColin Finck     }
752c2c66affSColin Finck 
753c2c66affSColin Finck     if(SUCCEEDED(hres)) {
754c2c66affSColin Finck         argv[match->paren_count+1] = jsval_number(match->cp-str - match->match_len);
755c2c66affSColin Finck         argv[match->paren_count+2] = jsval_string(jsstr);
756c2c66affSColin Finck     }
757c2c66affSColin Finck 
758c2c66affSColin Finck     if(SUCCEEDED(hres))
759c2c66affSColin Finck         hres = jsdisp_call_value(func, NULL, DISPATCH_METHOD, argc, argv, &val);
760c2c66affSColin Finck 
761c2c66affSColin Finck     for(i=0; i <= match->paren_count; i++)
762c2c66affSColin Finck         jsstr_release(get_string(argv[i]));
763c2c66affSColin Finck     heap_free(argv);
764c2c66affSColin Finck 
765c2c66affSColin Finck     if(FAILED(hres))
766c2c66affSColin Finck         return hres;
767c2c66affSColin Finck 
768c2c66affSColin Finck     hres = to_string(ctx, val, ret);
769c2c66affSColin Finck     jsval_release(val);
770c2c66affSColin Finck     return hres;
771c2c66affSColin Finck }
772c2c66affSColin Finck 
773c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.11 */
String_replace(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)774c2c66affSColin Finck static HRESULT String_replace(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
775c2c66affSColin Finck         jsval_t *r)
776c2c66affSColin Finck {
777c2c66affSColin Finck     const WCHAR *str, *match_str = NULL, *rep_str = NULL;
778c2c66affSColin Finck     jsstr_t *rep_jsstr, *match_jsstr, *jsstr;
779c2c66affSColin Finck     jsdisp_t *rep_func = NULL, *regexp = NULL;
780c2c66affSColin Finck     match_state_t *match = NULL, last_match = {0};
781c2c66affSColin Finck     strbuf_t ret = {NULL,0,0};
782c2c66affSColin Finck     DWORD re_flags = REM_NO_CTX_UPDATE|REM_ALLOC_RESULT;
783c2c66affSColin Finck     DWORD rep_len=0;
784c2c66affSColin Finck     HRESULT hres = S_OK;
785c2c66affSColin Finck 
786c2c66affSColin Finck     TRACE("\n");
787c2c66affSColin Finck 
788c2c66affSColin Finck     hres = get_string_flat_val(ctx, jsthis, &jsstr, &str);
789c2c66affSColin Finck     if(FAILED(hres))
790c2c66affSColin Finck         return hres;
791c2c66affSColin Finck 
792c2c66affSColin Finck     if(!argc) {
793c2c66affSColin Finck         if(r)
794c2c66affSColin Finck             *r = jsval_string(jsstr);
795c2c66affSColin Finck         else
796c2c66affSColin Finck             jsstr_release(jsstr);
797c2c66affSColin Finck         return S_OK;
798c2c66affSColin Finck     }
799c2c66affSColin Finck 
800c2c66affSColin Finck     if(is_object_instance(argv[0])) {
801c2c66affSColin Finck         regexp = iface_to_jsdisp(get_object(argv[0]));
802c2c66affSColin Finck         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
803c2c66affSColin Finck             jsdisp_release(regexp);
804c2c66affSColin Finck             regexp = NULL;
805c2c66affSColin Finck         }
806c2c66affSColin Finck     }
807c2c66affSColin Finck 
808c2c66affSColin Finck     if(!regexp) {
809c2c66affSColin Finck         hres = to_flat_string(ctx, argv[0], &match_jsstr, &match_str);
810c2c66affSColin Finck         if(FAILED(hres)) {
811c2c66affSColin Finck             jsstr_release(jsstr);
812c2c66affSColin Finck             return hres;
813c2c66affSColin Finck         }
814c2c66affSColin Finck     }
815c2c66affSColin Finck 
816c2c66affSColin Finck     if(argc >= 2) {
817c2c66affSColin Finck         if(is_object_instance(argv[1])) {
818c2c66affSColin Finck             rep_func = iface_to_jsdisp(get_object(argv[1]));
819c2c66affSColin Finck             if(rep_func && !is_class(rep_func, JSCLASS_FUNCTION)) {
820c2c66affSColin Finck                 jsdisp_release(rep_func);
821c2c66affSColin Finck                 rep_func = NULL;
822c2c66affSColin Finck             }
823c2c66affSColin Finck         }
824c2c66affSColin Finck 
825c2c66affSColin Finck         if(!rep_func) {
826c2c66affSColin Finck             hres = to_flat_string(ctx, argv[1], &rep_jsstr, &rep_str);
827c2c66affSColin Finck             if(SUCCEEDED(hres))
828c2c66affSColin Finck                 rep_len = jsstr_length(rep_jsstr);
829c2c66affSColin Finck         }
830c2c66affSColin Finck     }
831c2c66affSColin Finck 
832c2c66affSColin Finck     if(SUCCEEDED(hres)) {
833c2c66affSColin Finck         const WCHAR *ecp = str;
834c2c66affSColin Finck 
835c2c66affSColin Finck         while(1) {
836c2c66affSColin Finck             if(regexp) {
837c2c66affSColin Finck                 hres = regexp_match_next(ctx, regexp, re_flags, jsstr, &match);
838c2c66affSColin Finck                 re_flags = (re_flags | REM_CHECK_GLOBAL) & (~REM_ALLOC_RESULT);
839c2c66affSColin Finck 
840c2c66affSColin Finck                 if(hres == S_FALSE) {
841c2c66affSColin Finck                     hres = S_OK;
842c2c66affSColin Finck                     break;
843c2c66affSColin Finck                 }
844c2c66affSColin Finck                 if(FAILED(hres))
845c2c66affSColin Finck                     break;
846c2c66affSColin Finck 
847c2c66affSColin Finck                 last_match.cp = match->cp;
848c2c66affSColin Finck                 last_match.match_len = match->match_len;
849c2c66affSColin Finck             }else {
850c2c66affSColin Finck                 if(re_flags & REM_ALLOC_RESULT) {
851c2c66affSColin Finck                     re_flags &= ~REM_ALLOC_RESULT;
852c2c66affSColin Finck                     match = &last_match;
853c2c66affSColin Finck                     match->cp = str;
854c2c66affSColin Finck                 }
855c2c66affSColin Finck 
856*3e2d6582SAmine Khaldi                 match->cp = wcsstr(match->cp, match_str);
857c2c66affSColin Finck                 if(!match->cp)
858c2c66affSColin Finck                     break;
859c2c66affSColin Finck                 match->match_len = jsstr_length(match_jsstr);
860c2c66affSColin Finck                 match->cp += match->match_len;
861c2c66affSColin Finck             }
862c2c66affSColin Finck 
863c2c66affSColin Finck             hres = strbuf_append(&ret, ecp, match->cp-ecp-match->match_len);
864c2c66affSColin Finck             ecp = match->cp;
865c2c66affSColin Finck             if(FAILED(hres))
866c2c66affSColin Finck                 break;
867c2c66affSColin Finck 
868c2c66affSColin Finck             if(rep_func) {
869c2c66affSColin Finck                 jsstr_t *cstr;
870c2c66affSColin Finck 
871c2c66affSColin Finck                 hres = rep_call(ctx, rep_func, jsstr, str, match, &cstr);
872c2c66affSColin Finck                 if(FAILED(hres))
873c2c66affSColin Finck                     break;
874c2c66affSColin Finck 
875c2c66affSColin Finck                 hres = strbuf_append_jsstr(&ret, cstr);
876c2c66affSColin Finck                 jsstr_release(cstr);
877c2c66affSColin Finck                 if(FAILED(hres))
878c2c66affSColin Finck                     break;
879c2c66affSColin Finck             }else if(rep_str && regexp) {
880c2c66affSColin Finck                 const WCHAR *ptr = rep_str, *ptr2;
881c2c66affSColin Finck 
882*3e2d6582SAmine Khaldi                 while((ptr2 = wcschr(ptr, '$'))) {
883c2c66affSColin Finck                     hres = strbuf_append(&ret, ptr, ptr2-ptr);
884c2c66affSColin Finck                     if(FAILED(hres))
885c2c66affSColin Finck                         break;
886c2c66affSColin Finck 
887c2c66affSColin Finck                     switch(ptr2[1]) {
888c2c66affSColin Finck                     case '$':
889c2c66affSColin Finck                         hres = strbuf_append(&ret, ptr2, 1);
890c2c66affSColin Finck                         ptr = ptr2+2;
891c2c66affSColin Finck                         break;
892c2c66affSColin Finck                     case '&':
893c2c66affSColin Finck                         hres = strbuf_append(&ret, match->cp-match->match_len, match->match_len);
894c2c66affSColin Finck                         ptr = ptr2+2;
895c2c66affSColin Finck                         break;
896c2c66affSColin Finck                     case '`':
897c2c66affSColin Finck                         hres = strbuf_append(&ret, str, match->cp-str-match->match_len);
898c2c66affSColin Finck                         ptr = ptr2+2;
899c2c66affSColin Finck                         break;
900c2c66affSColin Finck                     case '\'':
901c2c66affSColin Finck                         hres = strbuf_append(&ret, ecp, (str+jsstr_length(jsstr))-ecp);
902c2c66affSColin Finck                         ptr = ptr2+2;
903c2c66affSColin Finck                         break;
904c2c66affSColin Finck                     default: {
905c2c66affSColin Finck                         DWORD idx;
906c2c66affSColin Finck 
907*3e2d6582SAmine Khaldi                         if(!iswdigit(ptr2[1])) {
908c2c66affSColin Finck                             hres = strbuf_append(&ret, ptr2, 1);
909c2c66affSColin Finck                             ptr = ptr2+1;
910c2c66affSColin Finck                             break;
911c2c66affSColin Finck                         }
912c2c66affSColin Finck 
913c2c66affSColin Finck                         idx = ptr2[1] - '0';
914*3e2d6582SAmine Khaldi                         if(iswdigit(ptr2[2]) && idx*10 + (ptr2[2]-'0') <= match->paren_count) {
915c2c66affSColin Finck                             idx = idx*10 + (ptr[2]-'0');
916c2c66affSColin Finck                             ptr = ptr2+3;
917c2c66affSColin Finck                         }else if(idx && idx <= match->paren_count) {
918c2c66affSColin Finck                             ptr = ptr2+2;
919c2c66affSColin Finck                         }else {
920c2c66affSColin Finck                             hres = strbuf_append(&ret, ptr2, 1);
921c2c66affSColin Finck                             ptr = ptr2+1;
922c2c66affSColin Finck                             break;
923c2c66affSColin Finck                         }
924c2c66affSColin Finck 
925c2c66affSColin Finck                         if(match->parens[idx-1].index != -1)
926c2c66affSColin Finck                             hres = strbuf_append(&ret, str+match->parens[idx-1].index,
927c2c66affSColin Finck                                     match->parens[idx-1].length);
928c2c66affSColin Finck                     }
929c2c66affSColin Finck                     }
930c2c66affSColin Finck 
931c2c66affSColin Finck                     if(FAILED(hres))
932c2c66affSColin Finck                         break;
933c2c66affSColin Finck                 }
934c2c66affSColin Finck 
935c2c66affSColin Finck                 if(SUCCEEDED(hres))
936c2c66affSColin Finck                     hres = strbuf_append(&ret, ptr, (rep_str+rep_len)-ptr);
937c2c66affSColin Finck                 if(FAILED(hres))
938c2c66affSColin Finck                     break;
939c2c66affSColin Finck             }else if(rep_str) {
940c2c66affSColin Finck                 hres = strbuf_append(&ret, rep_str, rep_len);
941c2c66affSColin Finck                 if(FAILED(hres))
942c2c66affSColin Finck                     break;
943c2c66affSColin Finck             }else {
944c2c66affSColin Finck                 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d'};
945c2c66affSColin Finck 
946660f7b90SAmine Khaldi                 hres = strbuf_append(&ret, undefinedW, ARRAY_SIZE(undefinedW));
947c2c66affSColin Finck                 if(FAILED(hres))
948c2c66affSColin Finck                     break;
949c2c66affSColin Finck             }
950c2c66affSColin Finck 
951c2c66affSColin Finck             if(!regexp)
952c2c66affSColin Finck                 break;
953c2c66affSColin Finck             else if(!match->match_len)
954c2c66affSColin Finck                 match->cp++;
955c2c66affSColin Finck         }
956c2c66affSColin Finck 
957c2c66affSColin Finck         if(SUCCEEDED(hres))
958c2c66affSColin Finck             hres = strbuf_append(&ret, ecp, str+jsstr_length(jsstr)-ecp);
959c2c66affSColin Finck     }
960c2c66affSColin Finck 
961c2c66affSColin Finck     if(rep_func)
962c2c66affSColin Finck         jsdisp_release(rep_func);
963c2c66affSColin Finck     if(rep_str)
964c2c66affSColin Finck         jsstr_release(rep_jsstr);
965c2c66affSColin Finck     if(match_str)
966c2c66affSColin Finck         jsstr_release(match_jsstr);
967c2c66affSColin Finck     if(regexp)
968c2c66affSColin Finck         heap_free(match);
969c2c66affSColin Finck 
970c2c66affSColin Finck     if(SUCCEEDED(hres) && last_match.cp && regexp) {
971c2c66affSColin Finck         jsstr_release(ctx->last_match);
972c2c66affSColin Finck         ctx->last_match = jsstr_addref(jsstr);
973c2c66affSColin Finck         ctx->last_match_index = last_match.cp-str-last_match.match_len;
974c2c66affSColin Finck         ctx->last_match_length = last_match.match_len;
975c2c66affSColin Finck     }
976c2c66affSColin Finck 
977c2c66affSColin Finck     if(regexp)
978c2c66affSColin Finck         jsdisp_release(regexp);
979c2c66affSColin Finck     jsstr_release(jsstr);
980c2c66affSColin Finck 
981c2c66affSColin Finck     if(SUCCEEDED(hres) && r) {
982c2c66affSColin Finck         jsstr_t *ret_str;
983c2c66affSColin Finck 
984c2c66affSColin Finck         ret_str = jsstr_alloc_len(ret.buf, ret.len);
985c2c66affSColin Finck         if(!ret_str)
986c2c66affSColin Finck             return E_OUTOFMEMORY;
987c2c66affSColin Finck 
988c2c66affSColin Finck         TRACE("= %s\n", debugstr_jsstr(ret_str));
989c2c66affSColin Finck         *r = jsval_string(ret_str);
990c2c66affSColin Finck     }
991c2c66affSColin Finck 
992c2c66affSColin Finck     heap_free(ret.buf);
993c2c66affSColin Finck     return hres;
994c2c66affSColin Finck }
995c2c66affSColin Finck 
String_search(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)996c2c66affSColin Finck static HRESULT String_search(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
997c2c66affSColin Finck         jsval_t *r)
998c2c66affSColin Finck {
999c2c66affSColin Finck     jsdisp_t *regexp = NULL;
1000c2c66affSColin Finck     const WCHAR *str;
1001c2c66affSColin Finck     jsstr_t *jsstr;
1002c2c66affSColin Finck     match_state_t match, *match_ptr = &match;
1003c2c66affSColin Finck     HRESULT hres;
1004c2c66affSColin Finck 
1005c2c66affSColin Finck     TRACE("\n");
1006c2c66affSColin Finck 
1007c2c66affSColin Finck     hres = get_string_flat_val(ctx, jsthis, &jsstr, &str);
1008c2c66affSColin Finck     if(FAILED(hres))
1009c2c66affSColin Finck         return hres;
1010c2c66affSColin Finck 
1011c2c66affSColin Finck     if(!argc) {
1012c2c66affSColin Finck         if(r)
1013c2c66affSColin Finck             *r = jsval_null();
1014c2c66affSColin Finck         jsstr_release(jsstr);
1015c2c66affSColin Finck         return S_OK;
1016c2c66affSColin Finck     }
1017c2c66affSColin Finck 
1018c2c66affSColin Finck     if(is_object_instance(argv[0])) {
1019c2c66affSColin Finck         regexp = iface_to_jsdisp(get_object(argv[0]));
1020c2c66affSColin Finck         if(regexp && !is_class(regexp, JSCLASS_REGEXP)) {
1021c2c66affSColin Finck             jsdisp_release(regexp);
1022c2c66affSColin Finck             regexp = NULL;
1023c2c66affSColin Finck         }
1024c2c66affSColin Finck     }
1025c2c66affSColin Finck 
1026c2c66affSColin Finck     if(!regexp) {
1027c2c66affSColin Finck         hres = create_regexp_var(ctx, argv[0], NULL, &regexp);
1028c2c66affSColin Finck         if(FAILED(hres)) {
1029c2c66affSColin Finck             jsstr_release(jsstr);
1030c2c66affSColin Finck             return hres;
1031c2c66affSColin Finck         }
1032c2c66affSColin Finck     }
1033c2c66affSColin Finck 
1034c2c66affSColin Finck     match.cp = str;
1035c2c66affSColin Finck     hres = regexp_match_next(ctx, regexp, REM_RESET_INDEX|REM_NO_PARENS, jsstr, &match_ptr);
1036c2c66affSColin Finck     jsstr_release(jsstr);
1037c2c66affSColin Finck     jsdisp_release(regexp);
1038c2c66affSColin Finck     if(FAILED(hres))
1039c2c66affSColin Finck         return hres;
1040c2c66affSColin Finck 
1041c2c66affSColin Finck     if(r)
1042c2c66affSColin Finck         *r = jsval_number(hres == S_OK ? match.cp-match.match_len-str : -1);
1043c2c66affSColin Finck     return S_OK;
1044c2c66affSColin Finck }
1045c2c66affSColin Finck 
1046c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.13 */
String_slice(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1047c2c66affSColin Finck static HRESULT String_slice(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1048c2c66affSColin Finck         jsval_t *r)
1049c2c66affSColin Finck {
1050c2c66affSColin Finck     int start=0, end, length;
1051c2c66affSColin Finck     jsstr_t *str;
1052c2c66affSColin Finck     double d;
1053c2c66affSColin Finck     HRESULT hres;
1054c2c66affSColin Finck 
1055c2c66affSColin Finck     TRACE("\n");
1056c2c66affSColin Finck 
1057c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
1058c2c66affSColin Finck     if(FAILED(hres))
1059c2c66affSColin Finck         return hres;
1060c2c66affSColin Finck 
1061c2c66affSColin Finck     length = jsstr_length(str);
1062c2c66affSColin Finck     if(argc) {
1063c2c66affSColin Finck         hres = to_integer(ctx, argv[0], &d);
1064c2c66affSColin Finck         if(FAILED(hres)) {
1065c2c66affSColin Finck             jsstr_release(str);
1066c2c66affSColin Finck             return hres;
1067c2c66affSColin Finck         }
1068c2c66affSColin Finck 
1069c2c66affSColin Finck         if(is_int32(d)) {
1070c2c66affSColin Finck             start = d;
1071c2c66affSColin Finck             if(start < 0) {
1072c2c66affSColin Finck                 start = length + start;
1073c2c66affSColin Finck                 if(start < 0)
1074c2c66affSColin Finck                     start = 0;
1075c2c66affSColin Finck             }else if(start > length) {
1076c2c66affSColin Finck                 start = length;
1077c2c66affSColin Finck             }
1078c2c66affSColin Finck         }else if(d > 0) {
1079c2c66affSColin Finck             start = length;
1080c2c66affSColin Finck         }
1081c2c66affSColin Finck     }
1082c2c66affSColin Finck 
1083c2c66affSColin Finck     if(argc >= 2) {
1084c2c66affSColin Finck         hres = to_integer(ctx, argv[1], &d);
1085c2c66affSColin Finck         if(FAILED(hres)) {
1086c2c66affSColin Finck             jsstr_release(str);
1087c2c66affSColin Finck             return hres;
1088c2c66affSColin Finck         }
1089c2c66affSColin Finck 
1090c2c66affSColin Finck         if(is_int32(d)) {
1091c2c66affSColin Finck             end = d;
1092c2c66affSColin Finck             if(end < 0) {
1093c2c66affSColin Finck                 end = length + end;
1094c2c66affSColin Finck                 if(end < 0)
1095c2c66affSColin Finck                     end = 0;
1096c2c66affSColin Finck             }else if(end > length) {
1097c2c66affSColin Finck                 end = length;
1098c2c66affSColin Finck             }
1099c2c66affSColin Finck         }else {
1100c2c66affSColin Finck             end = d < 0.0 ? 0 : length;
1101c2c66affSColin Finck         }
1102c2c66affSColin Finck     }else {
1103c2c66affSColin Finck         end = length;
1104c2c66affSColin Finck     }
1105c2c66affSColin Finck 
1106c2c66affSColin Finck     if(end < start)
1107c2c66affSColin Finck         end = start;
1108c2c66affSColin Finck 
1109c2c66affSColin Finck     if(r) {
1110c2c66affSColin Finck         jsstr_t *retstr = jsstr_substr(str, start, end-start);
1111c2c66affSColin Finck         if(!retstr) {
1112c2c66affSColin Finck             jsstr_release(str);
1113c2c66affSColin Finck             return E_OUTOFMEMORY;
1114c2c66affSColin Finck         }
1115c2c66affSColin Finck 
1116c2c66affSColin Finck         *r = jsval_string(retstr);
1117c2c66affSColin Finck     }
1118c2c66affSColin Finck 
1119c2c66affSColin Finck     jsstr_release(str);
1120c2c66affSColin Finck     return S_OK;
1121c2c66affSColin Finck }
1122c2c66affSColin Finck 
String_small(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1123c2c66affSColin Finck static HRESULT String_small(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1124c2c66affSColin Finck         jsval_t *r)
1125c2c66affSColin Finck {
1126c2c66affSColin Finck     static const WCHAR smalltagW[] = {'S','M','A','L','L',0};
1127c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, smalltagW);
1128c2c66affSColin Finck }
1129c2c66affSColin Finck 
String_split(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1130c2c66affSColin Finck static HRESULT String_split(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1131c2c66affSColin Finck         jsval_t *r)
1132c2c66affSColin Finck {
1133c2c66affSColin Finck     match_state_t match_result, *match_ptr = &match_result;
1134*3e2d6582SAmine Khaldi     size_t length, i = 0, match_len = 0;
1135c2c66affSColin Finck     const WCHAR *ptr, *ptr2, *str, *match_str = NULL;
1136c2c66affSColin Finck     unsigned limit = ~0u;
1137c2c66affSColin Finck     jsdisp_t *array, *regexp = NULL;
1138c2c66affSColin Finck     jsstr_t *jsstr, *match_jsstr, *tmp_str;
1139c2c66affSColin Finck     HRESULT hres;
1140c2c66affSColin Finck 
1141c2c66affSColin Finck     hres = get_string_flat_val(ctx, jsthis, &jsstr, &str);
1142c2c66affSColin Finck     if(FAILED(hres))
1143c2c66affSColin Finck         return hres;
1144c2c66affSColin Finck     length = jsstr_length(jsstr);
1145c2c66affSColin Finck 
1146*3e2d6582SAmine Khaldi     TRACE("%s\n", debugstr_wn(str, length));
1147*3e2d6582SAmine Khaldi 
1148660f7b90SAmine Khaldi     if(!argc || (is_undefined(argv[0]) && ctx->version >= SCRIPTLANGUAGEVERSION_ES5)) {
1149660f7b90SAmine Khaldi         if(!r)
1150660f7b90SAmine Khaldi             return S_OK;
1151660f7b90SAmine Khaldi 
1152660f7b90SAmine Khaldi         hres = create_array(ctx, 0, &array);
1153660f7b90SAmine Khaldi         if(FAILED(hres))
1154660f7b90SAmine Khaldi             return hres;
1155660f7b90SAmine Khaldi 
1156660f7b90SAmine Khaldi         /* NOTE: according to spec, we should respect limit argument here (if provided).
1157660f7b90SAmine Khaldi          * We have a test showing that it's broken in native IE. */
1158660f7b90SAmine Khaldi         hres = jsdisp_propput_idx(array, 0, jsval_string(jsstr));
1159660f7b90SAmine Khaldi         if(FAILED(hres)) {
1160660f7b90SAmine Khaldi             jsdisp_release(array);
1161660f7b90SAmine Khaldi             return hres;
1162660f7b90SAmine Khaldi         }
1163660f7b90SAmine Khaldi 
1164660f7b90SAmine Khaldi         *r = jsval_obj(array);
1165660f7b90SAmine Khaldi         return S_OK;
1166660f7b90SAmine Khaldi     }
1167660f7b90SAmine Khaldi 
1168c2c66affSColin Finck     if(argc > 1 && !is_undefined(argv[1])) {
1169c2c66affSColin Finck         hres = to_uint32(ctx, argv[1], &limit);
1170c2c66affSColin Finck         if(FAILED(hres)) {
1171c2c66affSColin Finck             jsstr_release(jsstr);
1172c2c66affSColin Finck             return hres;
1173c2c66affSColin Finck         }
1174c2c66affSColin Finck     }
1175c2c66affSColin Finck 
1176c2c66affSColin Finck     if(is_object_instance(argv[0])) {
1177c2c66affSColin Finck         regexp = iface_to_jsdisp(get_object(argv[0]));
1178c2c66affSColin Finck         if(regexp) {
1179c2c66affSColin Finck             if(!is_class(regexp, JSCLASS_REGEXP)) {
1180c2c66affSColin Finck                 jsdisp_release(regexp);
1181c2c66affSColin Finck                 regexp = NULL;
1182c2c66affSColin Finck             }
1183c2c66affSColin Finck         }
1184c2c66affSColin Finck     }
1185c2c66affSColin Finck 
1186c2c66affSColin Finck     if(!regexp) {
1187c2c66affSColin Finck         hres = to_flat_string(ctx, argv[0], &match_jsstr, &match_str);
1188c2c66affSColin Finck         if(FAILED(hres)) {
1189c2c66affSColin Finck             jsstr_release(jsstr);
1190c2c66affSColin Finck             return hres;
1191c2c66affSColin Finck         }
1192c2c66affSColin Finck 
1193c2c66affSColin Finck         match_len = jsstr_length(match_jsstr);
1194c2c66affSColin Finck         if(!match_len) {
1195c2c66affSColin Finck             jsstr_release(match_jsstr);
1196c2c66affSColin Finck             match_str = NULL;
1197c2c66affSColin Finck         }
1198c2c66affSColin Finck     }
1199c2c66affSColin Finck 
1200c2c66affSColin Finck     hres = create_array(ctx, 0, &array);
1201c2c66affSColin Finck 
1202c2c66affSColin Finck     if(SUCCEEDED(hres)) {
1203c2c66affSColin Finck         ptr = str;
1204c2c66affSColin Finck         match_result.cp = str;
1205*3e2d6582SAmine Khaldi         while(i < limit) {
1206c2c66affSColin Finck             if(regexp) {
1207c2c66affSColin Finck                 hres = regexp_match_next(ctx, regexp, REM_NO_PARENS, jsstr, &match_ptr);
1208c2c66affSColin Finck                 if(hres != S_OK)
1209c2c66affSColin Finck                     break;
1210*3e2d6582SAmine Khaldi                 TRACE("got match %d %d\n", (int)(match_result.cp - match_result.match_len - str), match_result.match_len);
1211*3e2d6582SAmine Khaldi                 if(!match_result.match_len) {
1212*3e2d6582SAmine Khaldi                     /* If an empty string is matched, prevent including any match in the result */
1213*3e2d6582SAmine Khaldi                     if(!length) {
1214*3e2d6582SAmine Khaldi                         limit = 0;
1215*3e2d6582SAmine Khaldi                         break;
1216*3e2d6582SAmine Khaldi                     }
1217*3e2d6582SAmine Khaldi                     if(match_result.cp == ptr) {
1218*3e2d6582SAmine Khaldi                         match_result.cp++;
1219*3e2d6582SAmine Khaldi                         hres = regexp_match_next(ctx, regexp, REM_NO_PARENS, jsstr, &match_ptr);
1220*3e2d6582SAmine Khaldi                         if(hres != S_OK)
1221*3e2d6582SAmine Khaldi                             break;
1222*3e2d6582SAmine Khaldi                         TRACE("retried, got match %d %d\n", (int)(match_result.cp - match_result.match_len - str),
1223*3e2d6582SAmine Khaldi                               match_result.match_len);
1224*3e2d6582SAmine Khaldi                     }
1225*3e2d6582SAmine Khaldi                     if(!match_result.match_len && match_result.cp == str + length)
1226*3e2d6582SAmine Khaldi                         break;
1227*3e2d6582SAmine Khaldi                 }
1228c2c66affSColin Finck                 ptr2 = match_result.cp - match_result.match_len;
1229c2c66affSColin Finck             }else if(match_str) {
1230*3e2d6582SAmine Khaldi                 ptr2 = wcsstr(ptr, match_str);
1231c2c66affSColin Finck                 if(!ptr2)
1232c2c66affSColin Finck                     break;
1233c2c66affSColin Finck             }else {
1234c2c66affSColin Finck                 if(!*ptr)
1235c2c66affSColin Finck                     break;
1236c2c66affSColin Finck                 ptr2 = ptr+1;
1237c2c66affSColin Finck             }
1238c2c66affSColin Finck 
1239*3e2d6582SAmine Khaldi             if(!regexp || ptr2 > ptr || ctx->version >= SCRIPTLANGUAGEVERSION_ES5) {
1240c2c66affSColin Finck                 tmp_str = jsstr_alloc_len(ptr, ptr2-ptr);
1241c2c66affSColin Finck                 if(!tmp_str) {
1242c2c66affSColin Finck                     hres = E_OUTOFMEMORY;
1243c2c66affSColin Finck                     break;
1244c2c66affSColin Finck                 }
1245c2c66affSColin Finck 
1246*3e2d6582SAmine Khaldi                 hres = jsdisp_propput_idx(array, i++, jsval_string(tmp_str));
1247c2c66affSColin Finck                 jsstr_release(tmp_str);
1248c2c66affSColin Finck                 if(FAILED(hres))
1249c2c66affSColin Finck                     break;
1250*3e2d6582SAmine Khaldi             }
1251c2c66affSColin Finck 
1252c2c66affSColin Finck             if(regexp)
1253c2c66affSColin Finck                 ptr = match_result.cp;
1254c2c66affSColin Finck             else if(match_str)
1255c2c66affSColin Finck                 ptr = ptr2 + match_len;
1256c2c66affSColin Finck             else
1257c2c66affSColin Finck                 ptr++;
1258c2c66affSColin Finck         }
1259c2c66affSColin Finck     }
1260c2c66affSColin Finck 
1261c2c66affSColin Finck     if(SUCCEEDED(hres) && (match_str || regexp) && i<limit) {
1262c2c66affSColin Finck         DWORD len = (str+length) - ptr;
1263c2c66affSColin Finck 
1264*3e2d6582SAmine Khaldi         if(len || match_str || !length || ctx->version >= SCRIPTLANGUAGEVERSION_ES5) {
1265c2c66affSColin Finck             tmp_str = jsstr_alloc_len(ptr, len);
1266c2c66affSColin Finck 
1267c2c66affSColin Finck             if(tmp_str) {
1268c2c66affSColin Finck                 hres = jsdisp_propput_idx(array, i, jsval_string(tmp_str));
1269c2c66affSColin Finck                 jsstr_release(tmp_str);
1270c2c66affSColin Finck             }else {
1271c2c66affSColin Finck                 hres = E_OUTOFMEMORY;
1272c2c66affSColin Finck             }
1273c2c66affSColin Finck         }
1274c2c66affSColin Finck     }
1275c2c66affSColin Finck 
1276c2c66affSColin Finck     if(regexp)
1277c2c66affSColin Finck         jsdisp_release(regexp);
1278c2c66affSColin Finck     if(match_str)
1279c2c66affSColin Finck         jsstr_release(match_jsstr);
1280c2c66affSColin Finck     jsstr_release(jsstr);
1281c2c66affSColin Finck 
1282c2c66affSColin Finck     if(SUCCEEDED(hres) && r)
1283c2c66affSColin Finck         *r = jsval_obj(array);
1284c2c66affSColin Finck     else
1285c2c66affSColin Finck         jsdisp_release(array);
1286c2c66affSColin Finck 
1287c2c66affSColin Finck     return hres;
1288c2c66affSColin Finck }
1289c2c66affSColin Finck 
String_strike(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1290c2c66affSColin Finck static HRESULT String_strike(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1291c2c66affSColin Finck         jsval_t *r)
1292c2c66affSColin Finck {
1293c2c66affSColin Finck     static const WCHAR striketagW[] = {'S','T','R','I','K','E',0};
1294c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, striketagW);
1295c2c66affSColin Finck }
1296c2c66affSColin Finck 
String_sub(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1297c2c66affSColin Finck static HRESULT String_sub(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1298c2c66affSColin Finck         jsval_t *r)
1299c2c66affSColin Finck {
1300c2c66affSColin Finck     static const WCHAR subtagW[] = {'S','U','B',0};
1301c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, subtagW);
1302c2c66affSColin Finck }
1303c2c66affSColin Finck 
1304c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.4.15 */
String_substring(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1305c2c66affSColin Finck static HRESULT String_substring(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1306c2c66affSColin Finck         jsval_t *r)
1307c2c66affSColin Finck {
1308c2c66affSColin Finck     INT start=0, end, length;
1309c2c66affSColin Finck     jsstr_t *str;
1310c2c66affSColin Finck     double d;
1311c2c66affSColin Finck     HRESULT hres;
1312c2c66affSColin Finck 
1313c2c66affSColin Finck     TRACE("\n");
1314c2c66affSColin Finck 
1315c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
1316c2c66affSColin Finck     if(FAILED(hres))
1317c2c66affSColin Finck         return hres;
1318c2c66affSColin Finck 
1319c2c66affSColin Finck     length = jsstr_length(str);
1320c2c66affSColin Finck     if(argc >= 1) {
1321c2c66affSColin Finck         hres = to_integer(ctx, argv[0], &d);
1322c2c66affSColin Finck         if(FAILED(hres)) {
1323c2c66affSColin Finck             jsstr_release(str);
1324c2c66affSColin Finck             return hres;
1325c2c66affSColin Finck         }
1326c2c66affSColin Finck 
1327c2c66affSColin Finck         if(d >= 0)
1328c2c66affSColin Finck             start = is_int32(d) ? min(length, d) : length;
1329c2c66affSColin Finck     }
1330c2c66affSColin Finck 
1331c2c66affSColin Finck     if(argc >= 2) {
1332c2c66affSColin Finck         hres = to_integer(ctx, argv[1], &d);
1333c2c66affSColin Finck         if(FAILED(hres)) {
1334c2c66affSColin Finck             jsstr_release(str);
1335c2c66affSColin Finck             return hres;
1336c2c66affSColin Finck         }
1337c2c66affSColin Finck 
1338c2c66affSColin Finck         if(d >= 0)
1339c2c66affSColin Finck             end = is_int32(d) ? min(length, d) : length;
1340c2c66affSColin Finck         else
1341c2c66affSColin Finck             end = 0;
1342c2c66affSColin Finck     }else {
1343c2c66affSColin Finck         end = length;
1344c2c66affSColin Finck     }
1345c2c66affSColin Finck 
1346c2c66affSColin Finck     if(start > end) {
1347c2c66affSColin Finck         INT tmp = start;
1348c2c66affSColin Finck         start = end;
1349c2c66affSColin Finck         end = tmp;
1350c2c66affSColin Finck     }
1351c2c66affSColin Finck 
1352c2c66affSColin Finck     if(r) {
1353c2c66affSColin Finck         jsstr_t *ret = jsstr_substr(str, start, end-start);
1354c2c66affSColin Finck         if(ret)
1355c2c66affSColin Finck             *r = jsval_string(ret);
1356c2c66affSColin Finck         else
1357c2c66affSColin Finck             hres = E_OUTOFMEMORY;
1358c2c66affSColin Finck     }
1359c2c66affSColin Finck     jsstr_release(str);
1360c2c66affSColin Finck     return hres;
1361c2c66affSColin Finck }
1362c2c66affSColin Finck 
1363c2c66affSColin Finck /* ECMA-262 3rd Edition    B.2.3 */
String_substr(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1364c2c66affSColin Finck static HRESULT String_substr(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1365c2c66affSColin Finck         jsval_t *r)
1366c2c66affSColin Finck {
1367c2c66affSColin Finck     int start=0, len, length;
1368c2c66affSColin Finck     jsstr_t *str;
1369c2c66affSColin Finck     double d;
1370c2c66affSColin Finck     HRESULT hres;
1371c2c66affSColin Finck 
1372c2c66affSColin Finck     TRACE("\n");
1373c2c66affSColin Finck 
1374c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
1375c2c66affSColin Finck     if(FAILED(hres))
1376c2c66affSColin Finck         return hres;
1377c2c66affSColin Finck 
1378c2c66affSColin Finck     length = jsstr_length(str);
1379c2c66affSColin Finck     if(argc >= 1) {
1380c2c66affSColin Finck         hres = to_integer(ctx, argv[0], &d);
1381c2c66affSColin Finck         if(FAILED(hres)) {
1382c2c66affSColin Finck             jsstr_release(str);
1383c2c66affSColin Finck             return hres;
1384c2c66affSColin Finck         }
1385c2c66affSColin Finck 
1386c2c66affSColin Finck         if(d >= 0)
1387c2c66affSColin Finck             start = is_int32(d) ? min(length, d) : length;
1388c2c66affSColin Finck     }
1389c2c66affSColin Finck 
1390c2c66affSColin Finck     if(argc >= 2) {
1391c2c66affSColin Finck         hres = to_integer(ctx, argv[1], &d);
1392c2c66affSColin Finck         if(FAILED(hres)) {
1393c2c66affSColin Finck             jsstr_release(str);
1394c2c66affSColin Finck             return hres;
1395c2c66affSColin Finck         }
1396c2c66affSColin Finck 
1397c2c66affSColin Finck         if(d >= 0.0)
1398c2c66affSColin Finck             len = is_int32(d) ? min(length-start, d) : length-start;
1399c2c66affSColin Finck         else
1400c2c66affSColin Finck             len = 0;
1401c2c66affSColin Finck     }else {
1402c2c66affSColin Finck         len = length-start;
1403c2c66affSColin Finck     }
1404c2c66affSColin Finck 
1405c2c66affSColin Finck     hres = S_OK;
1406c2c66affSColin Finck     if(r) {
1407c2c66affSColin Finck         jsstr_t *ret = jsstr_substr(str, start, len);
1408c2c66affSColin Finck         if(ret)
1409c2c66affSColin Finck             *r = jsval_string(ret);
1410c2c66affSColin Finck         else
1411c2c66affSColin Finck             hres = E_OUTOFMEMORY;
1412c2c66affSColin Finck     }
1413c2c66affSColin Finck 
1414c2c66affSColin Finck     jsstr_release(str);
1415c2c66affSColin Finck     return hres;
1416c2c66affSColin Finck }
1417c2c66affSColin Finck 
String_sup(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1418c2c66affSColin Finck static HRESULT String_sup(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1419c2c66affSColin Finck         jsval_t *r)
1420c2c66affSColin Finck {
1421c2c66affSColin Finck     static const WCHAR suptagW[] = {'S','U','P',0};
1422c2c66affSColin Finck     return do_attributeless_tag_format(ctx, jsthis, r, suptagW);
1423c2c66affSColin Finck }
1424c2c66affSColin Finck 
String_toLowerCase(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1425c2c66affSColin Finck static HRESULT String_toLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1426c2c66affSColin Finck         jsval_t *r)
1427c2c66affSColin Finck {
1428c2c66affSColin Finck     jsstr_t *str;
1429c2c66affSColin Finck     HRESULT  hres;
1430c2c66affSColin Finck 
1431c2c66affSColin Finck     TRACE("\n");
1432c2c66affSColin Finck 
1433c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
1434c2c66affSColin Finck     if(FAILED(hres))
1435c2c66affSColin Finck         return hres;
1436c2c66affSColin Finck 
1437c2c66affSColin Finck     if(r) {
1438c2c66affSColin Finck         unsigned len = jsstr_length(str);
1439c2c66affSColin Finck         jsstr_t *ret;
1440c2c66affSColin Finck         WCHAR *buf;
1441c2c66affSColin Finck 
1442c2c66affSColin Finck         ret = jsstr_alloc_buf(len, &buf);
1443c2c66affSColin Finck         if(!ret) {
1444c2c66affSColin Finck             jsstr_release(str);
1445c2c66affSColin Finck             return E_OUTOFMEMORY;
1446c2c66affSColin Finck         }
1447c2c66affSColin Finck 
1448c2c66affSColin Finck         jsstr_flush(str, buf);
1449*3e2d6582SAmine Khaldi         for (; len--; buf++) *buf = towlower(*buf);
1450c2c66affSColin Finck 
1451c2c66affSColin Finck         *r = jsval_string(ret);
1452c2c66affSColin Finck     }
1453c2c66affSColin Finck     jsstr_release(str);
1454c2c66affSColin Finck     return S_OK;
1455c2c66affSColin Finck }
1456c2c66affSColin Finck 
String_toUpperCase(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1457c2c66affSColin Finck static HRESULT String_toUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1458c2c66affSColin Finck         jsval_t *r)
1459c2c66affSColin Finck {
1460c2c66affSColin Finck     jsstr_t *str;
1461c2c66affSColin Finck     HRESULT hres;
1462c2c66affSColin Finck 
1463c2c66affSColin Finck     TRACE("\n");
1464c2c66affSColin Finck 
1465c2c66affSColin Finck     hres = get_string_val(ctx, jsthis, &str);
1466c2c66affSColin Finck     if(FAILED(hres))
1467c2c66affSColin Finck         return hres;
1468c2c66affSColin Finck 
1469c2c66affSColin Finck     if(r) {
1470c2c66affSColin Finck         unsigned len = jsstr_length(str);
1471c2c66affSColin Finck         jsstr_t *ret;
1472c2c66affSColin Finck         WCHAR *buf;
1473c2c66affSColin Finck 
1474c2c66affSColin Finck         ret = jsstr_alloc_buf(len, &buf);
1475c2c66affSColin Finck         if(!ret) {
1476c2c66affSColin Finck             jsstr_release(str);
1477c2c66affSColin Finck             return E_OUTOFMEMORY;
1478c2c66affSColin Finck         }
1479c2c66affSColin Finck 
1480c2c66affSColin Finck         jsstr_flush(str, buf);
1481*3e2d6582SAmine Khaldi         for (; len--; buf++) *buf = towupper(*buf);
1482c2c66affSColin Finck 
1483c2c66affSColin Finck         *r = jsval_string(ret);
1484c2c66affSColin Finck     }
1485c2c66affSColin Finck     jsstr_release(str);
1486c2c66affSColin Finck     return S_OK;
1487c2c66affSColin Finck }
1488c2c66affSColin Finck 
String_toLocaleLowerCase(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1489c2c66affSColin Finck static HRESULT String_toLocaleLowerCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1490c2c66affSColin Finck         jsval_t *r)
1491c2c66affSColin Finck {
1492c2c66affSColin Finck     FIXME("\n");
1493c2c66affSColin Finck     return E_NOTIMPL;
1494c2c66affSColin Finck }
1495c2c66affSColin Finck 
String_toLocaleUpperCase(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1496c2c66affSColin Finck static HRESULT String_toLocaleUpperCase(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1497c2c66affSColin Finck         jsval_t *r)
1498c2c66affSColin Finck {
1499c2c66affSColin Finck     FIXME("\n");
1500c2c66affSColin Finck     return E_NOTIMPL;
1501c2c66affSColin Finck }
1502c2c66affSColin Finck 
String_trim(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)15033f071cc5SAmine Khaldi static HRESULT String_trim(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc,
15043f071cc5SAmine Khaldi         jsval_t *argv, jsval_t *r)
15053f071cc5SAmine Khaldi {
15063f071cc5SAmine Khaldi     const WCHAR *str, *begin, *end;
15073f071cc5SAmine Khaldi     jsstr_t *jsstr;
15083f071cc5SAmine Khaldi     unsigned len;
15093f071cc5SAmine Khaldi     HRESULT hres;
15103f071cc5SAmine Khaldi 
15113f071cc5SAmine Khaldi     hres = to_flat_string(ctx, jsval_disp(jsthis->u.disp), &jsstr, &str);
15123f071cc5SAmine Khaldi     if(FAILED(hres)) {
15133f071cc5SAmine Khaldi         WARN("to_flat_string failed: %08x\n", hres);
15143f071cc5SAmine Khaldi         return hres;
15153f071cc5SAmine Khaldi     }
15163f071cc5SAmine Khaldi     len = jsstr_length(jsstr);
15173f071cc5SAmine Khaldi     TRACE("%s\n", debugstr_wn(str, len));
15183f071cc5SAmine Khaldi 
1519*3e2d6582SAmine Khaldi     for(begin = str, end = str + len; begin < end && iswspace(*begin); begin++);
1520*3e2d6582SAmine Khaldi     while(end > begin + 1 && iswspace(*(end-1))) end--;
15213f071cc5SAmine Khaldi 
15223f071cc5SAmine Khaldi     if(r) {
15233f071cc5SAmine Khaldi         jsstr_t *ret;
15243f071cc5SAmine Khaldi 
15253f071cc5SAmine Khaldi         if(begin == str && end == str + len)
15263f071cc5SAmine Khaldi             ret = jsstr_addref(jsstr);
15273f071cc5SAmine Khaldi         else
15283f071cc5SAmine Khaldi             ret = jsstr_alloc_len(begin, end - begin);
15293f071cc5SAmine Khaldi         if(ret)
15303f071cc5SAmine Khaldi             *r = jsval_string(ret);
15313f071cc5SAmine Khaldi         else
15323f071cc5SAmine Khaldi             hres = E_OUTOFMEMORY;
15333f071cc5SAmine Khaldi     }
15343f071cc5SAmine Khaldi     jsstr_release(jsstr);
15353f071cc5SAmine Khaldi     return hres;
15363f071cc5SAmine Khaldi }
15373f071cc5SAmine Khaldi 
String_localeCompare(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1538c2c66affSColin Finck static HRESULT String_localeCompare(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1539c2c66affSColin Finck         jsval_t *r)
1540c2c66affSColin Finck {
1541c2c66affSColin Finck     FIXME("\n");
1542c2c66affSColin Finck     return E_NOTIMPL;
1543c2c66affSColin Finck }
1544c2c66affSColin Finck 
String_get_value(script_ctx_t * ctx,jsdisp_t * jsthis,jsval_t * r)1545c2c66affSColin Finck static HRESULT String_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
1546c2c66affSColin Finck {
1547c2c66affSColin Finck     StringInstance *This = string_from_jsdisp(jsthis);
1548c2c66affSColin Finck 
1549c2c66affSColin Finck     TRACE("\n");
1550c2c66affSColin Finck 
1551c2c66affSColin Finck     *r = jsval_string(jsstr_addref(This->str));
1552c2c66affSColin Finck     return S_OK;
1553c2c66affSColin Finck }
1554c2c66affSColin Finck 
String_destructor(jsdisp_t * dispex)1555c2c66affSColin Finck static void String_destructor(jsdisp_t *dispex)
1556c2c66affSColin Finck {
1557c2c66affSColin Finck     StringInstance *This = string_from_jsdisp(dispex);
1558c2c66affSColin Finck 
1559c2c66affSColin Finck     jsstr_release(This->str);
1560c2c66affSColin Finck     heap_free(This);
1561c2c66affSColin Finck }
1562c2c66affSColin Finck 
String_idx_length(jsdisp_t * jsdisp)1563c2c66affSColin Finck static unsigned String_idx_length(jsdisp_t *jsdisp)
1564c2c66affSColin Finck {
1565c2c66affSColin Finck     StringInstance *string = string_from_jsdisp(jsdisp);
1566c2c66affSColin Finck 
1567c2c66affSColin Finck     /*
1568c2c66affSColin Finck      * NOTE: For invoke version < 2, indexed array is not implemented at all.
1569c2c66affSColin Finck      * Newer jscript.dll versions implement it on string type, not class,
1570c2c66affSColin Finck      * which is not how it should work according to spec. IE9 implements it
1571c2c66affSColin Finck      * properly, but it uses its own JavaScript engine inside MSHTML. We
1572c2c66affSColin Finck      * implement it here, but in the way IE9 and spec work.
1573c2c66affSColin Finck      */
1574c2c66affSColin Finck     return string->dispex.ctx->version < 2 ? 0 : jsstr_length(string->str);
1575c2c66affSColin Finck }
1576c2c66affSColin Finck 
String_idx_get(jsdisp_t * jsdisp,unsigned idx,jsval_t * r)1577c2c66affSColin Finck static HRESULT String_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r)
1578c2c66affSColin Finck {
1579c2c66affSColin Finck     StringInstance *string = string_from_jsdisp(jsdisp);
1580c2c66affSColin Finck     jsstr_t *ret;
1581c2c66affSColin Finck 
1582c2c66affSColin Finck     ret = jsstr_substr(string->str, idx, 1);
1583c2c66affSColin Finck     if(!ret)
1584c2c66affSColin Finck         return E_OUTOFMEMORY;
1585c2c66affSColin Finck 
1586c2c66affSColin Finck     TRACE("%p[%u] = %s\n", string, idx, debugstr_jsstr(ret));
1587c2c66affSColin Finck 
1588c2c66affSColin Finck     *r = jsval_string(ret);
1589c2c66affSColin Finck     return S_OK;
1590c2c66affSColin Finck }
1591c2c66affSColin Finck 
1592c2c66affSColin Finck static const builtin_prop_t String_props[] = {
1593c2c66affSColin Finck     {anchorW,                String_anchor,                PROPF_METHOD|1},
1594c2c66affSColin Finck     {bigW,                   String_big,                   PROPF_METHOD},
1595c2c66affSColin Finck     {blinkW,                 String_blink,                 PROPF_METHOD},
1596c2c66affSColin Finck     {boldW,                  String_bold,                  PROPF_METHOD},
1597c2c66affSColin Finck     {charAtW,                String_charAt,                PROPF_METHOD|1},
1598c2c66affSColin Finck     {charCodeAtW,            String_charCodeAt,            PROPF_METHOD|1},
1599c2c66affSColin Finck     {concatW,                String_concat,                PROPF_METHOD|1},
1600c2c66affSColin Finck     {fixedW,                 String_fixed,                 PROPF_METHOD},
1601c2c66affSColin Finck     {fontcolorW,             String_fontcolor,             PROPF_METHOD|1},
1602c2c66affSColin Finck     {fontsizeW,              String_fontsize,              PROPF_METHOD|1},
1603c2c66affSColin Finck     {indexOfW,               String_indexOf,               PROPF_METHOD|2},
1604c2c66affSColin Finck     {italicsW,               String_italics,               PROPF_METHOD},
1605c2c66affSColin Finck     {lastIndexOfW,           String_lastIndexOf,           PROPF_METHOD|2},
16063f071cc5SAmine Khaldi     {lengthW,                NULL,0,                       String_get_length},
1607c2c66affSColin Finck     {linkW,                  String_link,                  PROPF_METHOD|1},
1608c2c66affSColin Finck     {localeCompareW,         String_localeCompare,         PROPF_METHOD|1},
1609c2c66affSColin Finck     {matchW,                 String_match,                 PROPF_METHOD|1},
1610c2c66affSColin Finck     {replaceW,               String_replace,               PROPF_METHOD|1},
1611c2c66affSColin Finck     {searchW,                String_search,                PROPF_METHOD},
1612c2c66affSColin Finck     {sliceW,                 String_slice,                 PROPF_METHOD},
1613c2c66affSColin Finck     {smallW,                 String_small,                 PROPF_METHOD},
1614c2c66affSColin Finck     {splitW,                 String_split,                 PROPF_METHOD|2},
1615c2c66affSColin Finck     {strikeW,                String_strike,                PROPF_METHOD},
1616c2c66affSColin Finck     {subW,                   String_sub,                   PROPF_METHOD},
1617c2c66affSColin Finck     {substrW,                String_substr,                PROPF_METHOD|2},
1618c2c66affSColin Finck     {substringW,             String_substring,             PROPF_METHOD|2},
1619c2c66affSColin Finck     {supW,                   String_sup,                   PROPF_METHOD},
1620c2c66affSColin Finck     {toLocaleLowerCaseW,     String_toLocaleLowerCase,     PROPF_METHOD},
1621c2c66affSColin Finck     {toLocaleUpperCaseW,     String_toLocaleUpperCase,     PROPF_METHOD},
1622c2c66affSColin Finck     {toLowerCaseW,           String_toLowerCase,           PROPF_METHOD},
1623c2c66affSColin Finck     {toStringW,              String_toString,              PROPF_METHOD},
1624c2c66affSColin Finck     {toUpperCaseW,           String_toUpperCase,           PROPF_METHOD},
16253f071cc5SAmine Khaldi     {trimW,                  String_trim,                  PROPF_ES5|PROPF_METHOD},
1626c2c66affSColin Finck     {valueOfW,               String_valueOf,               PROPF_METHOD}
1627c2c66affSColin Finck };
1628c2c66affSColin Finck 
1629c2c66affSColin Finck static const builtin_info_t String_info = {
1630c2c66affSColin Finck     JSCLASS_STRING,
1631c2c66affSColin Finck     {NULL, NULL,0, String_get_value},
1632660f7b90SAmine Khaldi     ARRAY_SIZE(String_props),
1633c2c66affSColin Finck     String_props,
1634c2c66affSColin Finck     String_destructor,
1635c2c66affSColin Finck     NULL
1636c2c66affSColin Finck };
1637c2c66affSColin Finck 
1638c2c66affSColin Finck static const builtin_prop_t StringInst_props[] = {
16393f071cc5SAmine Khaldi     {lengthW,                NULL,0,                       String_get_length}
1640c2c66affSColin Finck };
1641c2c66affSColin Finck 
1642c2c66affSColin Finck static const builtin_info_t StringInst_info = {
1643c2c66affSColin Finck     JSCLASS_STRING,
1644c2c66affSColin Finck     {NULL, NULL,0, String_get_value},
1645660f7b90SAmine Khaldi     ARRAY_SIZE(StringInst_props),
1646c2c66affSColin Finck     StringInst_props,
1647c2c66affSColin Finck     String_destructor,
1648c2c66affSColin Finck     NULL,
1649c2c66affSColin Finck     String_idx_length,
1650c2c66affSColin Finck     String_idx_get
1651c2c66affSColin Finck };
1652c2c66affSColin Finck 
1653c2c66affSColin Finck /* ECMA-262 3rd Edition    15.5.3.2 */
StringConstr_fromCharCode(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1654c2c66affSColin Finck static HRESULT StringConstr_fromCharCode(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
1655c2c66affSColin Finck         unsigned argc, jsval_t *argv, jsval_t *r)
1656c2c66affSColin Finck {
1657c2c66affSColin Finck     WCHAR *ret_str;
1658c2c66affSColin Finck     DWORD i, code;
1659c2c66affSColin Finck     jsstr_t *ret;
1660c2c66affSColin Finck     HRESULT hres;
1661c2c66affSColin Finck 
1662c2c66affSColin Finck     TRACE("\n");
1663c2c66affSColin Finck 
1664c2c66affSColin Finck     ret = jsstr_alloc_buf(argc, &ret_str);
1665c2c66affSColin Finck     if(!ret)
1666c2c66affSColin Finck         return E_OUTOFMEMORY;
1667c2c66affSColin Finck 
1668c2c66affSColin Finck     for(i=0; i<argc; i++) {
1669c2c66affSColin Finck         hres = to_uint32(ctx, argv[i], &code);
1670c2c66affSColin Finck         if(FAILED(hres)) {
1671c2c66affSColin Finck             jsstr_release(ret);
1672c2c66affSColin Finck             return hres;
1673c2c66affSColin Finck         }
1674c2c66affSColin Finck 
1675c2c66affSColin Finck         ret_str[i] = code;
1676c2c66affSColin Finck     }
1677c2c66affSColin Finck 
1678c2c66affSColin Finck     if(r)
1679c2c66affSColin Finck         *r = jsval_string(ret);
1680c2c66affSColin Finck     else
1681c2c66affSColin Finck         jsstr_release(ret);
1682c2c66affSColin Finck     return S_OK;
1683c2c66affSColin Finck }
1684c2c66affSColin Finck 
StringConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1685c2c66affSColin Finck static HRESULT StringConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1686c2c66affSColin Finck         jsval_t *r)
1687c2c66affSColin Finck {
1688c2c66affSColin Finck     HRESULT hres;
1689c2c66affSColin Finck 
1690c2c66affSColin Finck     TRACE("\n");
1691c2c66affSColin Finck 
1692c2c66affSColin Finck     switch(flags) {
1693c2c66affSColin Finck     case INVOKE_FUNC: {
1694c2c66affSColin Finck         jsstr_t *str;
1695c2c66affSColin Finck 
1696c2c66affSColin Finck         if(argc) {
1697c2c66affSColin Finck             hres = to_string(ctx, argv[0], &str);
1698c2c66affSColin Finck             if(FAILED(hres))
1699c2c66affSColin Finck                 return hres;
1700c2c66affSColin Finck         }else {
1701c2c66affSColin Finck             str = jsstr_empty();
1702c2c66affSColin Finck         }
1703c2c66affSColin Finck 
1704c2c66affSColin Finck         *r = jsval_string(str);
1705c2c66affSColin Finck         break;
1706c2c66affSColin Finck     }
1707c2c66affSColin Finck     case DISPATCH_CONSTRUCT: {
1708c2c66affSColin Finck         jsstr_t *str;
1709c2c66affSColin Finck         jsdisp_t *ret;
1710c2c66affSColin Finck 
1711c2c66affSColin Finck         if(argc) {
1712c2c66affSColin Finck             hres = to_string(ctx, argv[0], &str);
1713c2c66affSColin Finck             if(FAILED(hres))
1714c2c66affSColin Finck                 return hres;
1715c2c66affSColin Finck         }else {
1716c2c66affSColin Finck             str = jsstr_empty();
1717c2c66affSColin Finck         }
1718c2c66affSColin Finck 
1719c2c66affSColin Finck         hres = create_string(ctx, str, &ret);
1720c2c66affSColin Finck         if (SUCCEEDED(hres)) *r = jsval_obj(ret);
1721c2c66affSColin Finck         jsstr_release(str);
1722c2c66affSColin Finck         return hres;
1723c2c66affSColin Finck     }
1724c2c66affSColin Finck 
1725c2c66affSColin Finck     default:
1726c2c66affSColin Finck         FIXME("unimplemented flags: %x\n", flags);
1727c2c66affSColin Finck         return E_NOTIMPL;
1728c2c66affSColin Finck     }
1729c2c66affSColin Finck 
1730c2c66affSColin Finck     return S_OK;
1731c2c66affSColin Finck }
1732c2c66affSColin Finck 
string_alloc(script_ctx_t * ctx,jsdisp_t * object_prototype,jsstr_t * str,StringInstance ** ret)1733c2c66affSColin Finck static HRESULT string_alloc(script_ctx_t *ctx, jsdisp_t *object_prototype, jsstr_t *str, StringInstance **ret)
1734c2c66affSColin Finck {
1735c2c66affSColin Finck     StringInstance *string;
1736c2c66affSColin Finck     HRESULT hres;
1737c2c66affSColin Finck 
1738c2c66affSColin Finck     string = heap_alloc_zero(sizeof(StringInstance));
1739c2c66affSColin Finck     if(!string)
1740c2c66affSColin Finck         return E_OUTOFMEMORY;
1741c2c66affSColin Finck 
1742c2c66affSColin Finck     if(object_prototype)
1743c2c66affSColin Finck         hres = init_dispex(&string->dispex, ctx, &String_info, object_prototype);
1744c2c66affSColin Finck     else
1745c2c66affSColin Finck         hres = init_dispex_from_constr(&string->dispex, ctx, &StringInst_info, ctx->string_constr);
1746c2c66affSColin Finck     if(FAILED(hres)) {
1747c2c66affSColin Finck         heap_free(string);
1748c2c66affSColin Finck         return hres;
1749c2c66affSColin Finck     }
1750c2c66affSColin Finck 
1751c2c66affSColin Finck     string->str = jsstr_addref(str);
1752c2c66affSColin Finck     *ret = string;
1753c2c66affSColin Finck     return S_OK;
1754c2c66affSColin Finck }
1755c2c66affSColin Finck 
1756c2c66affSColin Finck static const builtin_prop_t StringConstr_props[] = {
1757c2c66affSColin Finck     {fromCharCodeW,    StringConstr_fromCharCode,    PROPF_METHOD},
1758c2c66affSColin Finck };
1759c2c66affSColin Finck 
1760c2c66affSColin Finck static const builtin_info_t StringConstr_info = {
1761c2c66affSColin Finck     JSCLASS_FUNCTION,
1762c2c66affSColin Finck     DEFAULT_FUNCTION_VALUE,
1763660f7b90SAmine Khaldi     ARRAY_SIZE(StringConstr_props),
1764c2c66affSColin Finck     StringConstr_props,
1765c2c66affSColin Finck     NULL,
1766c2c66affSColin Finck     NULL
1767c2c66affSColin Finck };
1768c2c66affSColin Finck 
create_string_constr(script_ctx_t * ctx,jsdisp_t * object_prototype,jsdisp_t ** ret)1769c2c66affSColin Finck HRESULT create_string_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1770c2c66affSColin Finck {
1771c2c66affSColin Finck     StringInstance *string;
1772c2c66affSColin Finck     HRESULT hres;
1773c2c66affSColin Finck 
1774c2c66affSColin Finck     static const WCHAR StringW[] = {'S','t','r','i','n','g',0};
1775c2c66affSColin Finck 
1776c2c66affSColin Finck     hres = string_alloc(ctx, object_prototype, jsstr_empty(), &string);
1777c2c66affSColin Finck     if(FAILED(hres))
1778c2c66affSColin Finck         return hres;
1779c2c66affSColin Finck 
1780c2c66affSColin Finck     hres = create_builtin_constructor(ctx, StringConstr_value, StringW, &StringConstr_info,
1781c2c66affSColin Finck             PROPF_CONSTR|1, &string->dispex, ret);
1782c2c66affSColin Finck 
1783c2c66affSColin Finck     jsdisp_release(&string->dispex);
1784c2c66affSColin Finck     return hres;
1785c2c66affSColin Finck }
1786c2c66affSColin Finck 
create_string(script_ctx_t * ctx,jsstr_t * str,jsdisp_t ** ret)1787c2c66affSColin Finck HRESULT create_string(script_ctx_t *ctx, jsstr_t *str, jsdisp_t **ret)
1788c2c66affSColin Finck {
1789c2c66affSColin Finck     StringInstance *string;
1790c2c66affSColin Finck     HRESULT hres;
1791c2c66affSColin Finck 
1792c2c66affSColin Finck     hres = string_alloc(ctx, NULL, str, &string);
1793c2c66affSColin Finck     if(FAILED(hres))
1794c2c66affSColin Finck         return hres;
1795c2c66affSColin Finck 
1796c2c66affSColin Finck     *ret = &string->dispex;
1797c2c66affSColin Finck     return S_OK;
1798c2c66affSColin Finck 
1799c2c66affSColin Finck }
1800