xref: /reactos/dll/win32/jscript/array.c (revision 3e2d6582)
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #ifdef __REACTOS__
20 #include <wine/config.h>
21 #include <wine/port.h>
22 #endif
23 
24 #include <math.h>
25 #include <assert.h>
26 
27 #include "jscript.h"
28 
29 #include "wine/debug.h"
30 
31 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
32 
33 typedef struct {
34     jsdisp_t dispex;
35 
36     DWORD length;
37 } ArrayInstance;
38 
39 static const WCHAR lengthW[] = {'l','e','n','g','t','h',0};
40 static const WCHAR concatW[] = {'c','o','n','c','a','t',0};
41 static const WCHAR forEachW[] = {'f','o','r','E','a','c','h',0};
42 static const WCHAR joinW[] = {'j','o','i','n',0};
43 static const WCHAR popW[] = {'p','o','p',0};
44 static const WCHAR pushW[] = {'p','u','s','h',0};
45 static const WCHAR reverseW[] = {'r','e','v','e','r','s','e',0};
46 static const WCHAR shiftW[] = {'s','h','i','f','t',0};
47 static const WCHAR sliceW[] = {'s','l','i','c','e',0};
48 static const WCHAR sortW[] = {'s','o','r','t',0};
49 static const WCHAR spliceW[] = {'s','p','l','i','c','e',0};
50 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
51 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
52 static const WCHAR unshiftW[] = {'u','n','s','h','i','f','t',0};
53 static const WCHAR indexOfW[] = {'i','n','d','e','x','O','f',0};
54 static const WCHAR mapW[] = {'m','a','p',0};
55 
56 static const WCHAR default_separatorW[] = {',',0};
57 
array_from_jsdisp(jsdisp_t * jsdisp)58 static inline ArrayInstance *array_from_jsdisp(jsdisp_t *jsdisp)
59 {
60     return CONTAINING_RECORD(jsdisp, ArrayInstance, dispex);
61 }
62 
array_from_vdisp(vdisp_t * vdisp)63 static inline ArrayInstance *array_from_vdisp(vdisp_t *vdisp)
64 {
65     return array_from_jsdisp(vdisp->u.jsdisp);
66 }
67 
array_this(vdisp_t * jsthis)68 static inline ArrayInstance *array_this(vdisp_t *jsthis)
69 {
70     return is_vclass(jsthis, JSCLASS_ARRAY) ? array_from_vdisp(jsthis) : NULL;
71 }
72 
array_get_length(jsdisp_t * array)73 unsigned array_get_length(jsdisp_t *array)
74 {
75     assert(is_class(array, JSCLASS_ARRAY));
76     return array_from_jsdisp(array)->length;
77 }
78 
get_length(script_ctx_t * ctx,vdisp_t * vdisp,jsdisp_t ** jsthis,DWORD * ret)79 static HRESULT get_length(script_ctx_t *ctx, vdisp_t *vdisp, jsdisp_t **jsthis, DWORD *ret)
80 {
81     ArrayInstance *array;
82     jsval_t val;
83     HRESULT hres;
84 
85     array = array_this(vdisp);
86     if(array) {
87         *jsthis = &array->dispex;
88         *ret = array->length;
89         return S_OK;
90     }
91 
92     if(!is_jsdisp(vdisp))
93         return throw_type_error(ctx, JS_E_JSCRIPT_EXPECTED, NULL);
94 
95     hres = jsdisp_propget_name(vdisp->u.jsdisp, lengthW, &val);
96     if(FAILED(hres))
97         return hres;
98 
99     hres = to_uint32(ctx, val, ret);
100     jsval_release(val);
101     if(FAILED(hres))
102         return hres;
103 
104     *jsthis = vdisp->u.jsdisp;
105     return S_OK;
106 }
107 
set_length(jsdisp_t * obj,DWORD length)108 static HRESULT set_length(jsdisp_t *obj, DWORD length)
109 {
110     if(is_class(obj, JSCLASS_ARRAY)) {
111         array_from_jsdisp(obj)->length = length;
112         return S_OK;
113     }
114 
115     return jsdisp_propput_name(obj, lengthW, jsval_number(length));
116 }
117 
idx_to_str(DWORD idx,WCHAR * ptr)118 static WCHAR *idx_to_str(DWORD idx, WCHAR *ptr)
119 {
120     if(!idx) {
121         *ptr = '0';
122         return ptr;
123     }
124 
125     while(idx) {
126         *ptr-- = '0' + (idx%10);
127         idx /= 10;
128     }
129 
130     return ptr+1;
131 }
132 
Array_get_length(script_ctx_t * ctx,jsdisp_t * jsthis,jsval_t * r)133 static HRESULT Array_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
134 {
135     TRACE("%p\n", jsthis);
136 
137     *r = jsval_number(array_from_jsdisp(jsthis)->length);
138     return S_OK;
139 }
140 
Array_set_length(script_ctx_t * ctx,jsdisp_t * jsthis,jsval_t value)141 static HRESULT Array_set_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
142 {
143     ArrayInstance *This = array_from_jsdisp(jsthis);
144     DOUBLE len = -1;
145     DWORD i;
146     HRESULT hres;
147 
148     TRACE("%p %d\n", This, This->length);
149 
150     hres = to_number(ctx, value, &len);
151     if(FAILED(hres))
152         return hres;
153 
154     len = floor(len);
155     if(len!=(DWORD)len)
156         return throw_range_error(ctx, JS_E_INVALID_LENGTH, NULL);
157 
158     for(i=len; i < This->length; i++) {
159         hres = jsdisp_delete_idx(&This->dispex, i);
160         if(FAILED(hres))
161             return hres;
162     }
163 
164     This->length = len;
165     return S_OK;
166 }
167 
concat_array(jsdisp_t * array,ArrayInstance * obj,DWORD * len)168 static HRESULT concat_array(jsdisp_t *array, ArrayInstance *obj, DWORD *len)
169 {
170     jsval_t val;
171     DWORD i;
172     HRESULT hres;
173 
174     for(i=0; i < obj->length; i++) {
175         hres = jsdisp_get_idx(&obj->dispex, i, &val);
176         if(hres == DISP_E_UNKNOWNNAME)
177             continue;
178         if(FAILED(hres))
179             return hres;
180 
181         hres = jsdisp_propput_idx(array, *len+i, val);
182         jsval_release(val);
183         if(FAILED(hres))
184             return hres;
185     }
186 
187     *len += obj->length;
188     return S_OK;
189 }
190 
concat_obj(jsdisp_t * array,IDispatch * obj,DWORD * len)191 static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len)
192 {
193     jsdisp_t *jsobj;
194     HRESULT hres;
195 
196     jsobj = iface_to_jsdisp(obj);
197     if(jsobj) {
198         if(is_class(jsobj, JSCLASS_ARRAY)) {
199             hres = concat_array(array, array_from_jsdisp(jsobj), len);
200             jsdisp_release(jsobj);
201             return hres;
202         }
203         jsdisp_release(jsobj);
204     }
205 
206     return jsdisp_propput_idx(array, (*len)++, jsval_disp(obj));
207 }
208 
Array_concat(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)209 static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
210         jsval_t *r)
211 {
212     jsdisp_t *ret;
213     DWORD len = 0;
214     HRESULT hres;
215 
216     TRACE("\n");
217 
218     hres = create_array(ctx, 0, &ret);
219     if(FAILED(hres))
220         return hres;
221 
222     hres = concat_obj(ret, jsthis->u.disp, &len);
223     if(SUCCEEDED(hres)) {
224         DWORD i;
225 
226         for(i=0; i < argc; i++) {
227             if(is_object_instance(argv[i]))
228                 hres = concat_obj(ret, get_object(argv[i]), &len);
229             else
230                 hres = jsdisp_propput_idx(ret, len++, argv[i]);
231             if(FAILED(hres))
232                 break;
233         }
234     }
235 
236     if(FAILED(hres))
237         return hres;
238 
239     if(r)
240         *r = jsval_obj(ret);
241     else
242         jsdisp_release(ret);
243     return S_OK;
244 }
245 
array_join(script_ctx_t * ctx,jsdisp_t * array,DWORD length,const WCHAR * sep,unsigned seplen,jsval_t * r)246 static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, const WCHAR *sep,
247         unsigned seplen, jsval_t *r)
248 {
249     jsstr_t **str_tab, *ret = NULL;
250     jsval_t val;
251     DWORD i;
252     HRESULT hres = E_FAIL;
253 
254     if(!length) {
255         if(r)
256             *r = jsval_string(jsstr_empty());
257         return S_OK;
258     }
259 
260     str_tab = heap_alloc_zero(length * sizeof(*str_tab));
261     if(!str_tab)
262         return E_OUTOFMEMORY;
263 
264     for(i=0; i < length; i++) {
265         hres = jsdisp_get_idx(array, i, &val);
266         if(hres == DISP_E_UNKNOWNNAME) {
267             hres = S_OK;
268             continue;
269         } else if(FAILED(hres))
270             break;
271 
272         if(!is_undefined(val) && !is_null(val)) {
273             hres = to_string(ctx, val, str_tab+i);
274             jsval_release(val);
275             if(FAILED(hres))
276                 break;
277         }
278     }
279 
280     if(SUCCEEDED(hres)) {
281         DWORD len = 0;
282 
283         if(str_tab[0])
284             len = jsstr_length(str_tab[0]);
285         for(i=1; i < length; i++) {
286             len += seplen;
287             if(str_tab[i])
288                 len += jsstr_length(str_tab[i]);
289             if(len > JSSTR_MAX_LENGTH) {
290                 hres = E_OUTOFMEMORY;
291                 break;
292             }
293         }
294 
295         if(SUCCEEDED(hres)) {
296             WCHAR *ptr = NULL;
297 
298             ret = jsstr_alloc_buf(len, &ptr);
299             if(ret) {
300                 if(str_tab[0])
301                     ptr += jsstr_flush(str_tab[0], ptr);
302 
303                 for(i=1; i < length; i++) {
304                     if(seplen) {
305                         memcpy(ptr, sep, seplen*sizeof(WCHAR));
306                         ptr += seplen;
307                     }
308 
309                     if(str_tab[i])
310                         ptr += jsstr_flush(str_tab[i], ptr);
311                 }
312             }else {
313                 hres = E_OUTOFMEMORY;
314             }
315         }
316     }
317 
318     for(i=0; i < length; i++) {
319         if(str_tab[i])
320             jsstr_release(str_tab[i]);
321     }
322     heap_free(str_tab);
323     if(FAILED(hres))
324         return hres;
325 
326     TRACE("= %s\n", debugstr_jsstr(ret));
327 
328     if(r)
329         *r = jsval_string(ret);
330     else
331         jsstr_release(ret);
332     return S_OK;
333 }
334 
335 /* ECMA-262 3rd Edition    15.4.4.5 */
Array_join(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)336 static HRESULT Array_join(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
337         jsval_t *r)
338 {
339     jsdisp_t *jsthis;
340     DWORD length;
341     HRESULT hres;
342 
343     TRACE("\n");
344 
345     hres = get_length(ctx, vthis, &jsthis, &length);
346     if(FAILED(hres))
347         return hres;
348 
349     if(argc) {
350         const WCHAR *sep;
351         jsstr_t *sep_str;
352 
353         hres = to_flat_string(ctx, argv[0], &sep_str, &sep);
354         if(FAILED(hres))
355             return hres;
356 
357         hres = array_join(ctx, jsthis, length, sep, jsstr_length(sep_str), r);
358 
359         jsstr_release(sep_str);
360     }else {
361         hres = array_join(ctx, jsthis, length, default_separatorW, lstrlenW(default_separatorW), r);
362     }
363 
364     return hres;
365 }
366 
Array_pop(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)367 static HRESULT Array_pop(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
368         jsval_t *r)
369 {
370     jsdisp_t *jsthis;
371     jsval_t val;
372     DWORD length;
373     HRESULT hres;
374 
375     TRACE("\n");
376 
377     hres = get_length(ctx, vthis, &jsthis, &length);
378     if(FAILED(hres))
379         return hres;
380 
381     if(!length) {
382         hres = set_length(jsthis, 0);
383         if(FAILED(hres))
384             return hres;
385 
386         if(r)
387             *r = jsval_undefined();
388         return S_OK;
389     }
390 
391     length--;
392     hres = jsdisp_get_idx(jsthis, length, &val);
393     if(SUCCEEDED(hres))
394         hres = jsdisp_delete_idx(jsthis, length);
395     else if(hres == DISP_E_UNKNOWNNAME) {
396         val = jsval_undefined();
397         hres = S_OK;
398     }else
399         return hres;
400 
401     if(SUCCEEDED(hres))
402         hres = set_length(jsthis, length);
403 
404     if(FAILED(hres)) {
405         jsval_release(val);
406         return hres;
407     }
408 
409     if(r)
410         *r = val;
411     else
412         jsval_release(val);
413     return hres;
414 }
415 
416 /* ECMA-262 3rd Edition    15.4.4.7 */
Array_push(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)417 static HRESULT Array_push(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
418         jsval_t *r)
419 {
420     jsdisp_t *jsthis;
421     DWORD length = 0;
422     unsigned i;
423     HRESULT hres;
424 
425     TRACE("\n");
426 
427     hres = get_length(ctx, vthis, &jsthis, &length);
428     if(FAILED(hres))
429         return hres;
430 
431     for(i=0; i < argc; i++) {
432         hres = jsdisp_propput_idx(jsthis, length+i, argv[i]);
433         if(FAILED(hres))
434             return hres;
435     }
436 
437     hres = set_length(jsthis, length+argc);
438     if(FAILED(hres))
439         return hres;
440 
441     if(r)
442         *r = jsval_number(length+argc);
443     return S_OK;
444 }
445 
Array_reverse(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)446 static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
447         jsval_t *r)
448 {
449     jsdisp_t *jsthis;
450     DWORD length, k, l;
451     jsval_t v1, v2;
452     HRESULT hres1, hres2;
453 
454     TRACE("\n");
455 
456     hres1 = get_length(ctx, vthis, &jsthis, &length);
457     if(FAILED(hres1))
458         return hres1;
459 
460     for(k=0; k<length/2; k++) {
461         l = length-k-1;
462 
463         hres1 = jsdisp_get_idx(jsthis, k, &v1);
464         if(FAILED(hres1) && hres1!=DISP_E_UNKNOWNNAME)
465             return hres1;
466 
467         hres2 = jsdisp_get_idx(jsthis, l, &v2);
468         if(FAILED(hres2) && hres2!=DISP_E_UNKNOWNNAME) {
469             jsval_release(v1);
470             return hres2;
471         }
472 
473         if(hres1 == DISP_E_UNKNOWNNAME)
474             hres1 = jsdisp_delete_idx(jsthis, l);
475         else
476             hres1 = jsdisp_propput_idx(jsthis, l, v1);
477 
478         if(FAILED(hres1)) {
479             jsval_release(v1);
480             jsval_release(v2);
481             return hres1;
482         }
483 
484         if(hres2 == DISP_E_UNKNOWNNAME)
485             hres2 = jsdisp_delete_idx(jsthis, k);
486         else
487             hres2 = jsdisp_propput_idx(jsthis, k, v2);
488 
489         if(FAILED(hres2)) {
490             jsval_release(v2);
491             return hres2;
492         }
493     }
494 
495     if(r)
496         *r = jsval_obj(jsdisp_addref(jsthis));
497     return S_OK;
498 }
499 
500 /* ECMA-262 3rd Edition    15.4.4.9 */
Array_shift(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)501 static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
502         jsval_t *r)
503 {
504     jsdisp_t *jsthis;
505     DWORD length = 0, i;
506     jsval_t v, ret;
507     HRESULT hres;
508 
509     TRACE("\n");
510 
511     hres = get_length(ctx, vthis, &jsthis, &length);
512     if(FAILED(hres))
513         return hres;
514 
515     if(!length) {
516         hres = set_length(jsthis, 0);
517         if(FAILED(hres))
518             return hres;
519 
520         if(r)
521             *r = jsval_undefined();
522         return S_OK;
523     }
524 
525     hres = jsdisp_get_idx(jsthis, 0, &ret);
526     if(hres == DISP_E_UNKNOWNNAME) {
527         ret = jsval_undefined();
528         hres = S_OK;
529     }
530 
531     for(i=1; SUCCEEDED(hres) && i<length; i++) {
532         hres = jsdisp_get_idx(jsthis, i, &v);
533         if(hres == DISP_E_UNKNOWNNAME)
534             hres = jsdisp_delete_idx(jsthis, i-1);
535         else if(SUCCEEDED(hres))
536             hres = jsdisp_propput_idx(jsthis, i-1, v);
537     }
538 
539     if(SUCCEEDED(hres)) {
540         hres = jsdisp_delete_idx(jsthis, length-1);
541         if(SUCCEEDED(hres))
542             hres = set_length(jsthis, length-1);
543     }
544 
545     if(FAILED(hres))
546         return hres;
547 
548     if(r)
549         *r = ret;
550     else
551         jsval_release(ret);
552     return hres;
553 }
554 
555 /* ECMA-262 3rd Edition    15.4.4.10 */
Array_slice(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)556 static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
557 {
558     jsdisp_t *arr, *jsthis;
559     DOUBLE range;
560     DWORD length, start, end, idx;
561     HRESULT hres;
562 
563     TRACE("\n");
564 
565     hres = get_length(ctx, vthis, &jsthis, &length);
566     if(FAILED(hres))
567         return hres;
568 
569     if(argc) {
570         hres = to_number(ctx, argv[0], &range);
571         if(FAILED(hres))
572             return hres;
573 
574         range = floor(range);
575         if(-range>length || isnan(range)) start = 0;
576         else if(range < 0) start = range+length;
577         else if(range <= length) start = range;
578         else start = length;
579     }
580     else start = 0;
581 
582     if(argc > 1) {
583         hres = to_number(ctx, argv[1], &range);
584         if(FAILED(hres))
585             return hres;
586 
587         range = floor(range);
588         if(-range>length) end = 0;
589         else if(range < 0) end = range+length;
590         else if(range <= length) end = range;
591         else end = length;
592     }
593     else end = length;
594 
595     hres = create_array(ctx, (end>start)?end-start:0, &arr);
596     if(FAILED(hres))
597         return hres;
598 
599     for(idx=start; idx<end; idx++) {
600         jsval_t v;
601 
602         hres = jsdisp_get_idx(jsthis, idx, &v);
603         if(hres == DISP_E_UNKNOWNNAME)
604             continue;
605 
606         if(SUCCEEDED(hres)) {
607             hres = jsdisp_propput_idx(arr, idx-start, v);
608             jsval_release(v);
609         }
610 
611         if(FAILED(hres)) {
612             jsdisp_release(arr);
613             return hres;
614         }
615     }
616 
617     if(r)
618         *r = jsval_obj(arr);
619     else
620         jsdisp_release(arr);
621 
622     return S_OK;
623 }
624 
sort_cmp(script_ctx_t * ctx,jsdisp_t * cmp_func,jsval_t v1,jsval_t v2,INT * cmp)625 static HRESULT sort_cmp(script_ctx_t *ctx, jsdisp_t *cmp_func, jsval_t v1, jsval_t v2, INT *cmp)
626 {
627     HRESULT hres;
628 
629     if(cmp_func) {
630         jsval_t args[2];
631         jsval_t res;
632         double n;
633 
634         args[0] = v1;
635         args[1] = v2;
636 
637         hres = jsdisp_call_value(cmp_func, NULL, DISPATCH_METHOD, 2, args, &res);
638         if(FAILED(hres))
639             return hres;
640 
641         hres = to_number(ctx, res, &n);
642         jsval_release(res);
643         if(FAILED(hres))
644             return hres;
645 
646         if(n == 0)
647             *cmp = 0;
648         *cmp = n > 0.0 ? 1 : -1;
649     }else if(is_undefined(v1)) {
650         *cmp = is_undefined(v2) ? 0 : 1;
651     }else if(is_undefined(v2)) {
652         *cmp = -1;
653     }else if(is_number(v1) && is_number(v2)) {
654         double d = get_number(v1)-get_number(v2);
655         if(d > 0.0)
656             *cmp = 1;
657         else
658             *cmp = d < -0.0 ? -1 : 0;
659     }else {
660         jsstr_t *x, *y;
661 
662         hres = to_string(ctx, v1, &x);
663         if(FAILED(hres))
664             return hres;
665 
666         hres = to_string(ctx, v2, &y);
667         if(SUCCEEDED(hres)) {
668             *cmp = jsstr_cmp(x, y);
669             jsstr_release(y);
670         }
671         jsstr_release(x);
672         if(FAILED(hres))
673             return hres;
674     }
675 
676     return S_OK;
677 }
678 
679 /* ECMA-262 3rd Edition    15.4.4.11 */
Array_sort(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)680 static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
681         jsval_t *r)
682 {
683     jsdisp_t *jsthis, *cmp_func = NULL;
684     jsval_t *vtab, **sorttab = NULL;
685     DWORD length;
686     DWORD i;
687     HRESULT hres = S_OK;
688 
689     TRACE("\n");
690 
691     hres = get_length(ctx, vthis, &jsthis, &length);
692     if(FAILED(hres))
693         return hres;
694 
695     if(argc > 1) {
696         WARN("invalid arg_cnt %d\n", argc);
697         return E_FAIL;
698     }
699 
700     if(argc == 1) {
701         if(!is_object_instance(argv[0])) {
702             WARN("arg is not dispatch\n");
703             return E_FAIL;
704         }
705 
706         cmp_func = iface_to_jsdisp(get_object(argv[0]));
707         if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) {
708             WARN("cmp_func is not a function\n");
709             if(cmp_func)
710                 jsdisp_release(cmp_func);
711             return E_FAIL;
712         }
713     }
714 
715     if(!length) {
716         if(cmp_func)
717             jsdisp_release(cmp_func);
718         if(r)
719             *r = jsval_obj(jsdisp_addref(jsthis));
720         return S_OK;
721     }
722 
723     vtab = heap_alloc_zero(length * sizeof(*vtab));
724     if(vtab) {
725         for(i=0; i<length; i++) {
726             hres = jsdisp_get_idx(jsthis, i, vtab+i);
727             if(hres == DISP_E_UNKNOWNNAME) {
728                 vtab[i] = jsval_undefined();
729                 hres = S_OK;
730             } else if(FAILED(hres)) {
731                 WARN("Could not get elem %d: %08x\n", i, hres);
732                 break;
733             }
734         }
735     }else {
736         hres = E_OUTOFMEMORY;
737     }
738 
739     if(SUCCEEDED(hres)) {
740         sorttab = heap_alloc(length*2*sizeof(*sorttab));
741         if(!sorttab)
742             hres = E_OUTOFMEMORY;
743     }
744 
745     /* merge-sort */
746     if(SUCCEEDED(hres)) {
747         jsval_t *tmpv, **tmpbuf;
748         INT cmp;
749 
750         tmpbuf = sorttab + length;
751         for(i=0; i < length; i++)
752             sorttab[i] = vtab+i;
753 
754         for(i=0; i < length/2; i++) {
755             hres = sort_cmp(ctx, cmp_func, *sorttab[2*i+1], *sorttab[2*i], &cmp);
756             if(FAILED(hres))
757                 break;
758 
759             if(cmp < 0) {
760                 tmpv = sorttab[2*i];
761                 sorttab[2*i] = sorttab[2*i+1];
762                 sorttab[2*i+1] = tmpv;
763             }
764         }
765 
766         if(SUCCEEDED(hres)) {
767             DWORD k, a, b, bend;
768 
769             for(k=2; k < length; k *= 2) {
770                 for(i=0; i+k < length; i += 2*k) {
771                     a = b = 0;
772                     if(i+2*k <= length)
773                         bend = k;
774                     else
775                         bend = length - (i+k);
776 
777                     memcpy(tmpbuf, sorttab+i, k*sizeof(jsval_t*));
778 
779                     while(a < k && b < bend) {
780                         hres = sort_cmp(ctx, cmp_func, *tmpbuf[a], *sorttab[i+k+b], &cmp);
781                         if(FAILED(hres))
782                             break;
783 
784                         if(cmp < 0) {
785                             sorttab[i+a+b] = tmpbuf[a];
786                             a++;
787                         }else {
788                             sorttab[i+a+b] = sorttab[i+k+b];
789                             b++;
790                         }
791                     }
792 
793                     if(FAILED(hres))
794                         break;
795 
796                     if(a < k)
797                         memcpy(sorttab+i+a+b, tmpbuf+a, (k-a)*sizeof(jsval_t*));
798                 }
799 
800                 if(FAILED(hres))
801                     break;
802             }
803         }
804 
805         for(i=0; SUCCEEDED(hres) && i < length; i++)
806             hres = jsdisp_propput_idx(jsthis, i, *sorttab[i]);
807     }
808 
809     if(vtab) {
810         for(i=0; i < length; i++)
811             jsval_release(vtab[i]);
812         heap_free(vtab);
813     }
814     heap_free(sorttab);
815     if(cmp_func)
816         jsdisp_release(cmp_func);
817 
818     if(FAILED(hres))
819         return hres;
820 
821     if(r)
822         *r = jsval_obj(jsdisp_addref(jsthis));
823     return S_OK;
824 }
825 
826 /* ECMA-262 3rd Edition    15.4.4.12 */
Array_splice(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)827 static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
828         jsval_t *r)
829 {
830     DWORD length, start=0, delete_cnt=0, i, add_args = 0;
831     jsdisp_t *ret_array = NULL, *jsthis;
832     jsval_t val;
833     double d;
834     int n;
835     HRESULT hres = S_OK;
836 
837     TRACE("\n");
838 
839     hres = get_length(ctx, vthis, &jsthis, &length);
840     if(FAILED(hres))
841         return hres;
842 
843     if(argc) {
844         hres = to_integer(ctx, argv[0], &d);
845         if(FAILED(hres))
846             return hres;
847 
848         if(is_int32(d)) {
849             if((n = d) >= 0)
850                 start = min(n, length);
851             else
852                 start = -n > length ? 0 : length + n;
853         }else {
854             start = d < 0.0 ? 0 : length;
855         }
856     }
857 
858     if(argc >= 2) {
859         hres = to_integer(ctx, argv[1], &d);
860         if(FAILED(hres))
861             return hres;
862 
863         if(is_int32(d)) {
864             if((n = d) > 0)
865                 delete_cnt = min(n, length-start);
866         }else if(d > 0.0) {
867             delete_cnt = length-start;
868         }
869 
870         add_args = argc-2;
871     }
872 
873     if(r) {
874         hres = create_array(ctx, 0, &ret_array);
875         if(FAILED(hres))
876             return hres;
877 
878         for(i=0; SUCCEEDED(hres) && i < delete_cnt; i++) {
879             hres = jsdisp_get_idx(jsthis, start+i, &val);
880             if(hres == DISP_E_UNKNOWNNAME) {
881                 hres = S_OK;
882             }else if(SUCCEEDED(hres)) {
883                 hres = jsdisp_propput_idx(ret_array, i, val);
884                 jsval_release(val);
885             }
886         }
887 
888         if(SUCCEEDED(hres))
889             hres = jsdisp_propput_name(ret_array, lengthW, jsval_number(delete_cnt));
890     }
891 
892     if(add_args < delete_cnt) {
893         for(i = start; SUCCEEDED(hres) && i < length-delete_cnt; i++) {
894             hres = jsdisp_get_idx(jsthis, i+delete_cnt, &val);
895             if(hres == DISP_E_UNKNOWNNAME) {
896                 hres = jsdisp_delete_idx(jsthis, i+add_args);
897             }else if(SUCCEEDED(hres)) {
898                 hres = jsdisp_propput_idx(jsthis, i+add_args, val);
899                 jsval_release(val);
900             }
901         }
902 
903         for(i=length; SUCCEEDED(hres) && i != length-delete_cnt+add_args; i--)
904             hres = jsdisp_delete_idx(jsthis, i-1);
905     }else if(add_args > delete_cnt) {
906         for(i=length-delete_cnt; SUCCEEDED(hres) && i != start; i--) {
907             hres = jsdisp_get_idx(jsthis, i+delete_cnt-1, &val);
908             if(hres == DISP_E_UNKNOWNNAME) {
909                 hres = jsdisp_delete_idx(jsthis, i+add_args-1);
910             }else if(SUCCEEDED(hres)) {
911                 hres = jsdisp_propput_idx(jsthis, i+add_args-1, val);
912                 jsval_release(val);
913             }
914         }
915     }
916 
917     for(i=0; SUCCEEDED(hres) && i < add_args; i++)
918         hres = jsdisp_propput_idx(jsthis, start+i, argv[i+2]);
919 
920     if(SUCCEEDED(hres))
921         hres = jsdisp_propput_name(jsthis, lengthW, jsval_number(length-delete_cnt+add_args));
922 
923     if(FAILED(hres)) {
924         if(ret_array)
925             jsdisp_release(ret_array);
926         return hres;
927     }
928 
929     if(r)
930         *r = jsval_obj(ret_array);
931     return S_OK;
932 }
933 
934 /* ECMA-262 3rd Edition    15.4.4.2 */
Array_toString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)935 static HRESULT Array_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
936         jsval_t *r)
937 {
938     ArrayInstance *array;
939 
940     TRACE("\n");
941 
942     array = array_this(jsthis);
943     if(!array)
944         return throw_type_error(ctx, JS_E_ARRAY_EXPECTED, NULL);
945 
946     return array_join(ctx, &array->dispex, array->length, default_separatorW,
947                       lstrlenW(default_separatorW), r);
948 }
949 
Array_toLocaleString(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)950 static HRESULT Array_toLocaleString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
951         jsval_t *r)
952 {
953     FIXME("\n");
954     return E_NOTIMPL;
955 }
956 
Array_forEach(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)957 static HRESULT Array_forEach(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
958         jsval_t *r)
959 {
960     jsval_t value, args[3], res;
961     jsdisp_t *jsthis;
962     unsigned length, i;
963     HRESULT hres;
964 
965     TRACE("\n");
966 
967     hres = get_length(ctx, vthis, &jsthis, &length);
968     if(FAILED(hres))
969         return hres;
970 
971     /* Fixme check IsCallable */
972     if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
973         FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
974         return E_INVALIDARG;
975     }
976 
977     if(argc > 1 && !is_undefined(argv[1])) {
978         FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
979         return E_NOTIMPL;
980     }
981 
982     for(i = 0; i < length; i++) {
983         hres = jsdisp_get_idx(jsthis, i, &value);
984         if(hres == DISP_E_UNKNOWNNAME)
985             continue;
986         if(FAILED(hres))
987             return hres;
988 
989         args[0] = value;
990         args[1] = jsval_number(i);
991         args[2] = jsval_obj(jsthis);
992         hres = disp_call_value(ctx, get_object(argv[0]), NULL, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
993         jsval_release(value);
994         if(FAILED(hres))
995             return hres;
996         jsval_release(res);
997     }
998 
999     if(r) *r = jsval_undefined();
1000     return S_OK;
1001 }
1002 
Array_indexOf(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1003 static HRESULT Array_indexOf(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
1004         jsval_t *r)
1005 {
1006     jsdisp_t *jsthis;
1007     unsigned length, i, from = 0;
1008     jsval_t search, value;
1009     BOOL eq;
1010     HRESULT hres;
1011 
1012     TRACE("\n");
1013 
1014     hres = get_length(ctx, vthis, &jsthis, &length);
1015     if(FAILED(hres))
1016         return hres;
1017     if(!length) {
1018         if(r) *r = jsval_number(-1);
1019         return S_OK;
1020     }
1021 
1022     search = argc ? argv[0] : jsval_undefined();
1023 
1024     if(argc > 1) {
1025         double from_arg;
1026 
1027         hres = to_integer(ctx, argv[1], &from_arg);
1028         if(FAILED(hres))
1029             return hres;
1030 
1031         if(from_arg >= 0)
1032             from = min(from_arg, length);
1033         else
1034             from = max(from_arg + length, 0);
1035     }
1036 
1037     for(i = from; i < length; i++) {
1038         hres = jsdisp_get_idx(jsthis, i, &value);
1039         if(hres == DISP_E_UNKNOWNNAME)
1040             continue;
1041         if(FAILED(hres))
1042             return hres;
1043 
1044         hres = jsval_strict_equal(value, search, &eq);
1045         jsval_release(value);
1046         if(FAILED(hres))
1047             return hres;
1048         if(eq) {
1049             if(r) *r = jsval_number(i);
1050             return S_OK;
1051         }
1052     }
1053 
1054     if(r) *r = jsval_number(-1);
1055     return S_OK;
1056 }
1057 
Array_map(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1058 static HRESULT Array_map(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1059 {
1060     IDispatch *context_this = NULL, *callback;
1061     jsval_t callback_args[3], mapped_value;
1062     jsdisp_t *jsthis, *array;
1063     DWORD length, k;
1064     HRESULT hres;
1065 
1066     TRACE("\n");
1067 
1068     hres = get_length(ctx, vthis, &jsthis, &length);
1069     if(FAILED(hres)) {
1070         FIXME("Could not get length\n");
1071         return hres;
1072     }
1073 
1074     /* Fixme check IsCallable */
1075     if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
1076         FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1077         return E_INVALIDARG;
1078     }
1079     callback = get_object(argv[0]);
1080 
1081     if(argc > 1) {
1082         if(is_object_instance(argv[1]) && get_object(argv[1])) {
1083             context_this = get_object(argv[1]);
1084         }else if(!is_undefined(argv[1])) {
1085             FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
1086             return E_NOTIMPL;
1087         }
1088     }
1089 
1090     hres = create_array(ctx, length, &array);
1091     if(FAILED(hres))
1092         return hres;
1093 
1094     for(k = 0; k < length; k++) {
1095         hres = jsdisp_get_idx(jsthis, k, &callback_args[0]);
1096         if(hres == DISP_E_UNKNOWNNAME)
1097             continue;
1098         if(FAILED(hres))
1099             break;
1100 
1101         callback_args[1] = jsval_number(k);
1102         callback_args[2] = jsval_obj(jsthis);
1103         hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, 3, callback_args, &mapped_value);
1104         jsval_release(callback_args[0]);
1105         if(FAILED(hres))
1106             break;
1107 
1108         hres = jsdisp_propput_idx(array, k, mapped_value);
1109         if(FAILED(hres))
1110             break;
1111     }
1112 
1113     if(SUCCEEDED(hres) && r)
1114         *r = jsval_obj(array);
1115     else
1116         jsdisp_release(array);
1117     return hres;
1118 }
1119 
1120 /* ECMA-262 3rd Edition    15.4.4.13 */
Array_unshift(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1121 static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
1122         jsval_t *r)
1123 {
1124     jsdisp_t *jsthis;
1125     WCHAR buf[14], *buf_end, *str;
1126     DWORD i, length;
1127     jsval_t val;
1128     DISPID id;
1129     HRESULT hres;
1130 
1131     TRACE("\n");
1132 
1133     hres = get_length(ctx, vthis, &jsthis, &length);
1134     if(FAILED(hres))
1135         return hres;
1136 
1137     if(argc) {
1138         buf_end = buf + ARRAY_SIZE(buf)-1;
1139         *buf_end-- = 0;
1140         i = length;
1141 
1142         while(i--) {
1143             str = idx_to_str(i, buf_end);
1144 
1145             hres = jsdisp_get_id(jsthis, str, 0, &id);
1146             if(SUCCEEDED(hres)) {
1147                 hres = jsdisp_propget(jsthis, id, &val);
1148                 if(FAILED(hres))
1149                     return hres;
1150 
1151                 hres = jsdisp_propput_idx(jsthis, i+argc, val);
1152                 jsval_release(val);
1153             }else if(hres == DISP_E_UNKNOWNNAME) {
1154                 hres = IDispatchEx_DeleteMemberByDispID(vthis->u.dispex, id);
1155             }
1156         }
1157 
1158         if(FAILED(hres))
1159             return hres;
1160     }
1161 
1162     for(i=0; i<argc; i++) {
1163         hres = jsdisp_propput_idx(jsthis, i, argv[i]);
1164         if(FAILED(hres))
1165             return hres;
1166     }
1167 
1168     if(argc) {
1169         length += argc;
1170         hres = set_length(jsthis, length);
1171         if(FAILED(hres))
1172             return hres;
1173     }
1174 
1175     if(r)
1176         *r = ctx->version < 2 ? jsval_undefined() : jsval_number(length);
1177     return S_OK;
1178 }
1179 
Array_get_value(script_ctx_t * ctx,jsdisp_t * jsthis,jsval_t * r)1180 static HRESULT Array_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
1181 {
1182     ArrayInstance *array = array_from_jsdisp(jsthis);
1183 
1184     TRACE("\n");
1185 
1186     return array_join(ctx, &array->dispex, array->length, default_separatorW,
1187                       lstrlenW(default_separatorW), r);
1188 }
1189 
Array_destructor(jsdisp_t * dispex)1190 static void Array_destructor(jsdisp_t *dispex)
1191 {
1192     heap_free(dispex);
1193 }
1194 
Array_on_put(jsdisp_t * dispex,const WCHAR * name)1195 static void Array_on_put(jsdisp_t *dispex, const WCHAR *name)
1196 {
1197     ArrayInstance *array = array_from_jsdisp(dispex);
1198     const WCHAR *ptr = name;
1199     DWORD id = 0;
1200 
1201     if(!iswdigit(*ptr))
1202         return;
1203 
1204     while(*ptr && iswdigit(*ptr)) {
1205         id = id*10 + (*ptr-'0');
1206         ptr++;
1207     }
1208 
1209     if(*ptr)
1210         return;
1211 
1212     if(id >= array->length)
1213         array->length = id+1;
1214 }
1215 
1216 static const builtin_prop_t Array_props[] = {
1217     {concatW,                Array_concat,               PROPF_METHOD|1},
1218     {forEachW,               Array_forEach,              PROPF_METHOD|PROPF_ES5|1},
1219     {indexOfW,               Array_indexOf,              PROPF_METHOD|PROPF_ES5|1},
1220     {joinW,                  Array_join,                 PROPF_METHOD|1},
1221     {lengthW,                NULL,0,                     Array_get_length, Array_set_length},
1222     {mapW,                   Array_map,                  PROPF_METHOD|PROPF_ES5|1},
1223     {popW,                   Array_pop,                  PROPF_METHOD},
1224     {pushW,                  Array_push,                 PROPF_METHOD|1},
1225     {reverseW,               Array_reverse,              PROPF_METHOD},
1226     {shiftW,                 Array_shift,                PROPF_METHOD},
1227     {sliceW,                 Array_slice,                PROPF_METHOD|2},
1228     {sortW,                  Array_sort,                 PROPF_METHOD|1},
1229     {spliceW,                Array_splice,               PROPF_METHOD|2},
1230     {toLocaleStringW,        Array_toLocaleString,       PROPF_METHOD},
1231     {toStringW,              Array_toString,             PROPF_METHOD},
1232     {unshiftW,               Array_unshift,              PROPF_METHOD|1},
1233 };
1234 
1235 static const builtin_info_t Array_info = {
1236     JSCLASS_ARRAY,
1237     {NULL, NULL,0, Array_get_value},
1238     ARRAY_SIZE(Array_props),
1239     Array_props,
1240     Array_destructor,
1241     Array_on_put
1242 };
1243 
1244 static const builtin_prop_t ArrayInst_props[] = {
1245     {lengthW,                NULL,0,                     Array_get_length, Array_set_length}
1246 };
1247 
1248 static const builtin_info_t ArrayInst_info = {
1249     JSCLASS_ARRAY,
1250     {NULL, NULL,0, Array_get_value},
1251     ARRAY_SIZE(ArrayInst_props),
1252     ArrayInst_props,
1253     Array_destructor,
1254     Array_on_put
1255 };
1256 
1257 /* ECMA-262 5.1 Edition    15.4.3.2 */
ArrayConstr_isArray(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1258 static HRESULT ArrayConstr_isArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1259 {
1260     jsdisp_t *obj;
1261 
1262     TRACE("\n");
1263 
1264     if(!argc || !is_object_instance(argv[0])) {
1265         if(r) *r = jsval_bool(FALSE);
1266         return S_OK;
1267     }
1268 
1269     obj = iface_to_jsdisp(get_object(argv[0]));
1270     if(r) *r = jsval_bool(obj && is_class(obj, JSCLASS_ARRAY));
1271     if(obj) jsdisp_release(obj);
1272     return S_OK;
1273 }
1274 
ArrayConstr_value(script_ctx_t * ctx,vdisp_t * vthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1275 static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
1276         jsval_t *r)
1277 {
1278     jsdisp_t *obj;
1279     DWORD i;
1280     HRESULT hres;
1281 
1282     TRACE("\n");
1283 
1284     switch(flags) {
1285     case DISPATCH_METHOD:
1286     case DISPATCH_CONSTRUCT: {
1287         if(argc == 1 && is_number(argv[0])) {
1288             double n = get_number(argv[0]);
1289 
1290             if(n < 0 || !is_int32(n))
1291                 return throw_range_error(ctx, JS_E_INVALID_LENGTH, NULL);
1292 
1293             hres = create_array(ctx, n, &obj);
1294             if(FAILED(hres))
1295                 return hres;
1296 
1297             *r = jsval_obj(obj);
1298             return S_OK;
1299         }
1300 
1301         hres = create_array(ctx, argc, &obj);
1302         if(FAILED(hres))
1303             return hres;
1304 
1305         for(i=0; i < argc; i++) {
1306             hres = jsdisp_propput_idx(obj, i, argv[i]);
1307             if(FAILED(hres))
1308                 break;
1309         }
1310         if(FAILED(hres)) {
1311             jsdisp_release(obj);
1312             return hres;
1313         }
1314 
1315         *r = jsval_obj(obj);
1316         break;
1317     }
1318     default:
1319         FIXME("unimplemented flags: %x\n", flags);
1320         return E_NOTIMPL;
1321     }
1322 
1323     return S_OK;
1324 }
1325 
alloc_array(script_ctx_t * ctx,jsdisp_t * object_prototype,ArrayInstance ** ret)1326 static HRESULT alloc_array(script_ctx_t *ctx, jsdisp_t *object_prototype, ArrayInstance **ret)
1327 {
1328     ArrayInstance *array;
1329     HRESULT hres;
1330 
1331     array = heap_alloc_zero(sizeof(ArrayInstance));
1332     if(!array)
1333         return E_OUTOFMEMORY;
1334 
1335     if(object_prototype)
1336         hres = init_dispex(&array->dispex, ctx, &Array_info, object_prototype);
1337     else
1338         hres = init_dispex_from_constr(&array->dispex, ctx, &ArrayInst_info, ctx->array_constr);
1339 
1340     if(FAILED(hres)) {
1341         heap_free(array);
1342         return hres;
1343     }
1344 
1345     *ret = array;
1346     return S_OK;
1347 }
1348 
1349 static const WCHAR isArrayW[] = {'i','s','A','r','r','a','y',0};
1350 
1351 static const builtin_prop_t ArrayConstr_props[] = {
1352     {isArrayW,    ArrayConstr_isArray,    PROPF_ES5|PROPF_METHOD|1}
1353 };
1354 
1355 static const builtin_info_t ArrayConstr_info = {
1356     JSCLASS_FUNCTION,
1357     DEFAULT_FUNCTION_VALUE,
1358     ARRAY_SIZE(ArrayConstr_props),
1359     ArrayConstr_props,
1360     NULL,
1361     NULL
1362 };
1363 
create_array_constr(script_ctx_t * ctx,jsdisp_t * object_prototype,jsdisp_t ** ret)1364 HRESULT create_array_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1365 {
1366     ArrayInstance *array;
1367     HRESULT hres;
1368 
1369     static const WCHAR ArrayW[] = {'A','r','r','a','y',0};
1370 
1371     hres = alloc_array(ctx, object_prototype, &array);
1372     if(FAILED(hres))
1373         return hres;
1374 
1375     hres = create_builtin_constructor(ctx, ArrayConstr_value, ArrayW, &ArrayConstr_info, PROPF_CONSTR|1, &array->dispex, ret);
1376 
1377     jsdisp_release(&array->dispex);
1378     return hres;
1379 }
1380 
create_array(script_ctx_t * ctx,DWORD length,jsdisp_t ** ret)1381 HRESULT create_array(script_ctx_t *ctx, DWORD length, jsdisp_t **ret)
1382 {
1383     ArrayInstance *array;
1384     HRESULT hres;
1385 
1386     hres = alloc_array(ctx, NULL, &array);
1387     if(FAILED(hres))
1388         return hres;
1389 
1390     array->length = length;
1391 
1392     *ret = &array->dispex;
1393     return S_OK;
1394 }
1395