winegstreamer: Register stub ColorConvertDMO transform.
[wine.git] / dlls / jscript / array.c
blob5a8131f092c2690195400e44afb2ea465bfd439e
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
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.
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.
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
20 #include <math.h>
21 #include <assert.h>
23 #include "jscript.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
29 typedef struct {
30 jsdisp_t dispex;
32 DWORD length;
33 } ArrayInstance;
35 static inline ArrayInstance *array_from_jsdisp(jsdisp_t *jsdisp)
37 return CONTAINING_RECORD(jsdisp, ArrayInstance, dispex);
40 static inline ArrayInstance *array_this(jsval_t vthis)
42 jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL;
43 return (jsdisp && is_class(jsdisp, JSCLASS_ARRAY)) ? array_from_jsdisp(jsdisp) : NULL;
46 unsigned array_get_length(jsdisp_t *array)
48 assert(is_class(array, JSCLASS_ARRAY));
49 return array_from_jsdisp(array)->length;
52 static HRESULT get_length(script_ctx_t *ctx, jsval_t vthis, jsdisp_t **jsthis, UINT32 *ret)
54 jsdisp_t *jsdisp;
55 IDispatch *disp;
56 jsval_t val;
57 HRESULT hres;
59 hres = to_object(ctx, vthis, &disp);
60 if(FAILED(hres))
61 return hres;
63 jsdisp = iface_to_jsdisp(disp);
64 IDispatch_Release(disp);
65 if(!jsdisp)
66 return JS_E_JSCRIPT_EXPECTED;
67 *jsthis = jsdisp;
69 if(is_class(jsdisp, JSCLASS_ARRAY)) {
70 *ret = array_from_jsdisp(jsdisp)->length;
71 return S_OK;
74 hres = jsdisp_propget_name(jsdisp, L"length", &val);
75 if(SUCCEEDED(hres)) {
76 hres = to_uint32(ctx, val, ret);
77 jsval_release(val);
78 if(SUCCEEDED(hres))
79 return hres;
82 jsdisp_release(jsdisp);
83 return hres;
86 static HRESULT set_length(jsdisp_t *obj, DWORD length)
88 if(is_class(obj, JSCLASS_ARRAY)) {
89 array_from_jsdisp(obj)->length = length;
90 return S_OK;
93 return jsdisp_propput_name(obj, L"length", jsval_number(length));
96 static WCHAR *idx_to_str(DWORD idx, WCHAR *ptr)
98 if(!idx) {
99 *ptr = '0';
100 return ptr;
103 while(idx) {
104 *ptr-- = '0' + (idx%10);
105 idx /= 10;
108 return ptr+1;
111 static HRESULT Array_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
113 TRACE("%p\n", jsthis);
115 *r = jsval_number(array_from_jsdisp(jsthis)->length);
116 return S_OK;
119 static HRESULT Array_set_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
121 ArrayInstance *This = array_from_jsdisp(jsthis);
122 DOUBLE len = -1;
123 DWORD i;
124 HRESULT hres;
126 TRACE("%p %ld\n", This, This->length);
128 hres = to_number(ctx, value, &len);
129 if(FAILED(hres))
130 return hres;
132 len = floor(len);
133 if(len!=(DWORD)len)
134 return JS_E_INVALID_LENGTH;
136 for(i=len; i < This->length; i++) {
137 hres = jsdisp_delete_idx(&This->dispex, i);
138 if(FAILED(hres))
139 return hres;
142 This->length = len;
143 return S_OK;
146 static HRESULT concat_array(jsdisp_t *array, ArrayInstance *obj, DWORD *len)
148 jsval_t val;
149 DWORD i;
150 HRESULT hres;
152 for(i=0; i < obj->length; i++) {
153 hres = jsdisp_get_idx(&obj->dispex, i, &val);
154 if(hres == DISP_E_UNKNOWNNAME)
155 continue;
156 if(FAILED(hres))
157 return hres;
159 hres = jsdisp_propput_idx(array, *len+i, val);
160 jsval_release(val);
161 if(FAILED(hres))
162 return hres;
165 *len += obj->length;
166 return S_OK;
169 static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len)
171 jsdisp_t *jsobj;
172 HRESULT hres;
174 jsobj = iface_to_jsdisp(obj);
175 if(jsobj) {
176 if(is_class(jsobj, JSCLASS_ARRAY)) {
177 hres = concat_array(array, array_from_jsdisp(jsobj), len);
178 jsdisp_release(jsobj);
179 return hres;
181 jsdisp_release(jsobj);
184 return jsdisp_propput_idx(array, (*len)++, jsval_disp(obj));
187 static HRESULT Array_concat(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
188 jsval_t *r)
190 IDispatch *jsthis;
191 jsdisp_t *ret;
192 DWORD len = 0;
193 HRESULT hres;
195 TRACE("\n");
197 hres = to_object(ctx, vthis, &jsthis);
198 if(FAILED(hres))
199 return hres;
201 hres = create_array(ctx, 0, &ret);
202 if(FAILED(hres))
203 goto done;
205 hres = concat_obj(ret, jsthis, &len);
206 if(SUCCEEDED(hres)) {
207 DWORD i;
209 for(i=0; i < argc; i++) {
210 if(is_object_instance(argv[i]))
211 hres = concat_obj(ret, get_object(argv[i]), &len);
212 else
213 hres = jsdisp_propput_idx(ret, len++, argv[i]);
214 if(FAILED(hres))
215 break;
219 if(FAILED(hres))
220 goto done;
222 if(r)
223 *r = jsval_obj(ret);
224 else
225 jsdisp_release(ret);
226 done:
227 IDispatch_Release(jsthis);
228 return S_OK;
231 static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, const WCHAR *sep,
232 unsigned seplen, HRESULT (*to_string)(script_ctx_t*,jsval_t,jsstr_t**), jsval_t *r)
234 jsstr_t **str_tab, *ret = NULL;
235 jsval_t val;
236 DWORD i;
237 HRESULT hres = E_FAIL;
239 if(!length) {
240 if(r)
241 *r = jsval_string(jsstr_empty());
242 return S_OK;
245 str_tab = heap_alloc_zero(length * sizeof(*str_tab));
246 if(!str_tab)
247 return E_OUTOFMEMORY;
249 for(i=0; i < length; i++) {
250 hres = jsdisp_get_idx(array, i, &val);
251 if(hres == DISP_E_UNKNOWNNAME) {
252 hres = S_OK;
253 continue;
254 } else if(FAILED(hres))
255 break;
257 if(!is_undefined(val) && !is_null(val)) {
258 hres = to_string(ctx, val, str_tab+i);
259 jsval_release(val);
260 if(FAILED(hres))
261 break;
265 if(SUCCEEDED(hres)) {
266 DWORD len = 0;
268 if(str_tab[0])
269 len = jsstr_length(str_tab[0]);
270 for(i=1; i < length; i++) {
271 len += seplen;
272 if(str_tab[i])
273 len += jsstr_length(str_tab[i]);
274 if(len > JSSTR_MAX_LENGTH) {
275 hres = E_OUTOFMEMORY;
276 break;
280 if(SUCCEEDED(hres)) {
281 WCHAR *ptr = NULL;
283 ret = jsstr_alloc_buf(len, &ptr);
284 if(ret) {
285 if(str_tab[0])
286 ptr += jsstr_flush(str_tab[0], ptr);
288 for(i=1; i < length; i++) {
289 if(seplen) {
290 memcpy(ptr, sep, seplen*sizeof(WCHAR));
291 ptr += seplen;
294 if(str_tab[i])
295 ptr += jsstr_flush(str_tab[i], ptr);
297 }else {
298 hres = E_OUTOFMEMORY;
303 for(i=0; i < length; i++) {
304 if(str_tab[i])
305 jsstr_release(str_tab[i]);
307 heap_free(str_tab);
308 if(FAILED(hres))
309 return hres;
311 TRACE("= %s\n", debugstr_jsstr(ret));
313 if(r)
314 *r = jsval_string(ret);
315 else
316 jsstr_release(ret);
317 return S_OK;
320 /* ECMA-262 3rd Edition 15.4.4.5 */
321 static HRESULT Array_join(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
322 jsval_t *r)
324 jsdisp_t *jsthis;
325 UINT32 length;
326 HRESULT hres;
328 TRACE("\n");
330 hres = get_length(ctx, vthis, &jsthis, &length);
331 if(FAILED(hres))
332 return hres;
334 if(argc) {
335 const WCHAR *sep;
336 jsstr_t *sep_str;
338 hres = to_flat_string(ctx, argv[0], &sep_str, &sep);
339 if(FAILED(hres))
340 goto done;
342 hres = array_join(ctx, jsthis, length, sep, jsstr_length(sep_str), to_string, r);
344 jsstr_release(sep_str);
345 }else {
346 hres = array_join(ctx, jsthis, length, L",", 1, to_string, r);
349 done:
350 jsdisp_release(jsthis);
351 return hres;
354 static HRESULT Array_pop(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
355 jsval_t *r)
357 jsdisp_t *jsthis;
358 jsval_t val;
359 UINT32 length;
360 HRESULT hres;
362 TRACE("\n");
364 hres = get_length(ctx, vthis, &jsthis, &length);
365 if(FAILED(hres))
366 return hres;
368 if(!length) {
369 hres = set_length(jsthis, 0);
370 if(FAILED(hres))
371 goto done;
373 if(r)
374 *r = jsval_undefined();
375 goto done;
378 length--;
379 hres = jsdisp_get_idx(jsthis, length, &val);
380 if(SUCCEEDED(hres))
381 hres = jsdisp_delete_idx(jsthis, length);
382 else if(hres == DISP_E_UNKNOWNNAME) {
383 val = jsval_undefined();
384 hres = S_OK;
385 }else
386 goto done;
388 if(SUCCEEDED(hres))
389 hres = set_length(jsthis, length);
391 if(FAILED(hres)) {
392 jsval_release(val);
393 goto done;
396 if(r)
397 *r = val;
398 else
399 jsval_release(val);
400 done:
401 jsdisp_release(jsthis);
402 return hres;
405 /* ECMA-262 3rd Edition 15.4.4.7 */
406 static HRESULT Array_push(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
407 jsval_t *r)
409 jsdisp_t *jsthis;
410 UINT32 length = 0;
411 unsigned i;
412 HRESULT hres;
414 TRACE("\n");
416 hres = get_length(ctx, vthis, &jsthis, &length);
417 if(FAILED(hres))
418 return hres;
420 for(i=0; i < argc; i++) {
421 hres = jsdisp_propput_idx(jsthis, length+i, argv[i]);
422 if(FAILED(hres))
423 goto done;
426 hres = set_length(jsthis, length+argc);
427 if(FAILED(hres))
428 goto done;
430 if(r)
431 *r = jsval_number(length+argc);
432 done:
433 jsdisp_release(jsthis);
434 return hres;
437 static HRESULT Array_reverse(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
438 jsval_t *r)
440 jsdisp_t *jsthis;
441 UINT32 length, k, l;
442 jsval_t v1, v2;
443 HRESULT hres1, hres2;
445 TRACE("\n");
447 hres1 = get_length(ctx, vthis, &jsthis, &length);
448 if(FAILED(hres1))
449 return hres1;
451 for(k=0; k<length/2; k++) {
452 l = length-k-1;
454 hres1 = jsdisp_get_idx(jsthis, k, &v1);
455 if(FAILED(hres1) && hres1!=DISP_E_UNKNOWNNAME)
456 goto done;
458 hres2 = jsdisp_get_idx(jsthis, l, &v2);
459 if(FAILED(hres2) && hres2!=DISP_E_UNKNOWNNAME) {
460 jsval_release(v1);
461 hres1 = hres2;
462 goto done;
465 if(hres1 == DISP_E_UNKNOWNNAME)
466 hres1 = jsdisp_delete_idx(jsthis, l);
467 else
468 hres1 = jsdisp_propput_idx(jsthis, l, v1);
470 if(FAILED(hres1)) {
471 jsval_release(v1);
472 jsval_release(v2);
473 goto done;
476 if(hres2 == DISP_E_UNKNOWNNAME)
477 hres2 = jsdisp_delete_idx(jsthis, k);
478 else
479 hres2 = jsdisp_propput_idx(jsthis, k, v2);
481 if(FAILED(hres2)) {
482 jsval_release(v2);
483 hres1 = hres2;
484 goto done;
488 if(r)
489 *r = jsval_obj(jsdisp_addref(jsthis));
490 done:
491 jsdisp_release(jsthis);
492 return hres1;
495 /* ECMA-262 3rd Edition 15.4.4.9 */
496 static HRESULT Array_shift(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
497 jsval_t *r)
499 jsdisp_t *jsthis;
500 UINT32 length = 0, i;
501 jsval_t v, ret;
502 HRESULT hres;
504 TRACE("\n");
506 hres = get_length(ctx, vthis, &jsthis, &length);
507 if(FAILED(hres))
508 return hres;
510 if(!length) {
511 hres = set_length(jsthis, 0);
512 if(FAILED(hres))
513 goto done;
515 if(r)
516 *r = jsval_undefined();
517 goto done;
520 hres = jsdisp_get_idx(jsthis, 0, &ret);
521 if(hres == DISP_E_UNKNOWNNAME) {
522 ret = jsval_undefined();
523 hres = S_OK;
526 for(i=1; SUCCEEDED(hres) && i<length; i++) {
527 hres = jsdisp_get_idx(jsthis, i, &v);
528 if(hres == DISP_E_UNKNOWNNAME)
529 hres = jsdisp_delete_idx(jsthis, i-1);
530 else if(SUCCEEDED(hres))
531 hres = jsdisp_propput_idx(jsthis, i-1, v);
534 if(SUCCEEDED(hres)) {
535 hres = jsdisp_delete_idx(jsthis, length-1);
536 if(SUCCEEDED(hres))
537 hres = set_length(jsthis, length-1);
540 if(FAILED(hres))
541 goto done;
543 if(r)
544 *r = ret;
545 else
546 jsval_release(ret);
547 done:
548 jsdisp_release(jsthis);
549 return hres;
552 /* ECMA-262 3rd Edition 15.4.4.10 */
553 static HRESULT Array_slice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
555 jsdisp_t *arr, *jsthis;
556 DOUBLE range;
557 UINT32 length, start, end, idx;
558 HRESULT hres;
560 TRACE("\n");
562 hres = get_length(ctx, vthis, &jsthis, &length);
563 if(FAILED(hres))
564 return hres;
566 if(argc) {
567 hres = to_number(ctx, argv[0], &range);
568 if(FAILED(hres))
569 goto done;
571 range = floor(range);
572 if(-range>length || isnan(range)) start = 0;
573 else if(range < 0) start = range+length;
574 else if(range <= length) start = range;
575 else start = length;
577 else start = 0;
579 if(argc > 1) {
580 hres = to_number(ctx, argv[1], &range);
581 if(FAILED(hres))
582 goto done;
584 range = floor(range);
585 if(-range>length) end = 0;
586 else if(range < 0) end = range+length;
587 else if(range <= length) end = range;
588 else end = length;
590 else end = length;
592 hres = create_array(ctx, (end>start)?end-start:0, &arr);
593 if(FAILED(hres))
594 goto done;
596 for(idx=start; idx<end; idx++) {
597 jsval_t v;
599 hres = jsdisp_get_idx(jsthis, idx, &v);
600 if(hres == DISP_E_UNKNOWNNAME)
601 continue;
603 if(SUCCEEDED(hres)) {
604 hres = jsdisp_propput_idx(arr, idx-start, v);
605 jsval_release(v);
608 if(FAILED(hres)) {
609 jsdisp_release(arr);
610 goto done;
614 if(r)
615 *r = jsval_obj(arr);
616 else
617 jsdisp_release(arr);
618 hres = S_OK;
620 done:
621 jsdisp_release(jsthis);
622 return hres;
625 static HRESULT sort_cmp(script_ctx_t *ctx, jsdisp_t *cmp_func, jsval_t v1, jsval_t v2, INT *cmp)
627 HRESULT hres;
629 if(cmp_func) {
630 jsval_t args[2] = {v1, v2};
631 jsval_t res;
632 double n;
634 hres = jsdisp_call_value(cmp_func, NULL, DISPATCH_METHOD, 2, args, &res);
635 if(FAILED(hres))
636 return hres;
638 hres = to_number(ctx, res, &n);
639 jsval_release(res);
640 if(FAILED(hres))
641 return hres;
643 if(n == 0)
644 *cmp = 0;
645 *cmp = n > 0.0 ? 1 : -1;
646 }else if(is_undefined(v1)) {
647 *cmp = is_undefined(v2) ? 0 : 1;
648 }else if(is_undefined(v2)) {
649 *cmp = -1;
650 }else if(is_number(v1) && is_number(v2)) {
651 double d = get_number(v1)-get_number(v2);
652 if(d > 0.0)
653 *cmp = 1;
654 else
655 *cmp = d < -0.0 ? -1 : 0;
656 }else {
657 jsstr_t *x, *y;
659 hres = to_string(ctx, v1, &x);
660 if(FAILED(hres))
661 return hres;
663 hres = to_string(ctx, v2, &y);
664 if(SUCCEEDED(hres)) {
665 *cmp = jsstr_cmp(x, y);
666 jsstr_release(y);
668 jsstr_release(x);
669 if(FAILED(hres))
670 return hres;
673 return S_OK;
676 /* ECMA-262 3rd Edition 15.4.4.11 */
677 static HRESULT Array_sort(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
678 jsval_t *r)
680 jsdisp_t *jsthis, *cmp_func = NULL;
681 jsval_t *vtab, **sorttab = NULL;
682 UINT32 length;
683 DWORD i;
684 HRESULT hres = S_OK;
686 TRACE("\n");
688 hres = get_length(ctx, vthis, &jsthis, &length);
689 if(FAILED(hres))
690 return hres;
692 if(argc >= 1) {
693 if(is_object_instance(argv[0])) {
694 if(argc > 1 && ctx->version < SCRIPTLANGUAGEVERSION_ES5) {
695 WARN("invalid arg_cnt %d\n", argc);
696 hres = JS_E_JSCRIPT_EXPECTED;
697 goto done;
699 cmp_func = iface_to_jsdisp(get_object(argv[0]));
700 if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) {
701 WARN("cmp_func is not a function\n");
702 if(cmp_func)
703 jsdisp_release(cmp_func);
704 hres = JS_E_JSCRIPT_EXPECTED;
705 goto done;
707 }else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? !is_undefined(argv[0]) :
708 (!is_null(argv[0]) || is_null_disp(argv[0]))) {
709 WARN("invalid arg %s\n", debugstr_jsval(argv[0]));
710 hres = JS_E_JSCRIPT_EXPECTED;
711 goto done;
715 if(!length) {
716 if(cmp_func)
717 jsdisp_release(cmp_func);
718 if(r)
719 *r = jsval_obj(jsdisp_addref(jsthis));
720 goto done;
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 %ld: %08lx\n", i, hres);
732 break;
735 }else {
736 hres = E_OUTOFMEMORY;
739 if(SUCCEEDED(hres)) {
740 sorttab = heap_alloc(length*2*sizeof(*sorttab));
741 if(!sorttab)
742 hres = E_OUTOFMEMORY;
745 /* merge-sort */
746 if(SUCCEEDED(hres)) {
747 jsval_t *tmpv, **tmpbuf;
748 INT cmp;
750 tmpbuf = sorttab + length;
751 for(i=0; i < length; i++)
752 sorttab[i] = vtab+i;
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;
759 if(cmp < 0) {
760 tmpv = sorttab[2*i];
761 sorttab[2*i] = sorttab[2*i+1];
762 sorttab[2*i+1] = tmpv;
766 if(SUCCEEDED(hres)) {
767 DWORD k, a, b, bend;
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);
777 memcpy(tmpbuf, sorttab+i, k*sizeof(jsval_t*));
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;
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++;
793 if(FAILED(hres))
794 break;
796 if(a < k)
797 memcpy(sorttab+i+a+b, tmpbuf+a, (k-a)*sizeof(jsval_t*));
800 if(FAILED(hres))
801 break;
805 for(i=0; SUCCEEDED(hres) && i < length; i++)
806 hres = jsdisp_propput_idx(jsthis, i, *sorttab[i]);
809 if(vtab) {
810 for(i=0; i < length; i++)
811 jsval_release(vtab[i]);
812 heap_free(vtab);
814 heap_free(sorttab);
815 if(cmp_func)
816 jsdisp_release(cmp_func);
818 if(FAILED(hres))
819 goto done;
821 if(r)
822 *r = jsval_obj(jsdisp_addref(jsthis));
823 done:
824 jsdisp_release(jsthis);
825 return hres;
828 /* ECMA-262 3rd Edition 15.4.4.12 */
829 static HRESULT Array_splice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
830 jsval_t *r)
832 UINT32 length, start=0, delete_cnt=0, i, add_args = 0;
833 jsdisp_t *ret_array = NULL, *jsthis;
834 jsval_t val;
835 double d;
836 int n;
837 HRESULT hres = S_OK;
839 TRACE("\n");
841 hres = get_length(ctx, vthis, &jsthis, &length);
842 if(FAILED(hres))
843 return hres;
845 if(argc) {
846 hres = to_integer(ctx, argv[0], &d);
847 if(FAILED(hres))
848 goto done;
850 if(is_int32(d)) {
851 if((n = d) >= 0)
852 start = min(n, length);
853 else
854 start = -n > length ? 0 : length + n;
855 }else {
856 start = d < 0.0 ? 0 : length;
860 if(argc >= 2) {
861 hres = to_integer(ctx, argv[1], &d);
862 if(FAILED(hres))
863 goto done;
865 if(is_int32(d)) {
866 if((n = d) > 0)
867 delete_cnt = min(n, length-start);
868 }else if(d > 0.0) {
869 delete_cnt = length-start;
872 add_args = argc-2;
875 if(r) {
876 hres = create_array(ctx, 0, &ret_array);
877 if(FAILED(hres))
878 goto done;
880 for(i=0; SUCCEEDED(hres) && i < delete_cnt; i++) {
881 hres = jsdisp_get_idx(jsthis, start+i, &val);
882 if(hres == DISP_E_UNKNOWNNAME) {
883 hres = S_OK;
884 }else if(SUCCEEDED(hres)) {
885 hres = jsdisp_propput_idx(ret_array, i, val);
886 jsval_release(val);
890 if(SUCCEEDED(hres))
891 hres = jsdisp_propput_name(ret_array, L"length", jsval_number(delete_cnt));
894 if(add_args < delete_cnt) {
895 for(i = start; SUCCEEDED(hres) && i < length-delete_cnt; i++) {
896 hres = jsdisp_get_idx(jsthis, i+delete_cnt, &val);
897 if(hres == DISP_E_UNKNOWNNAME) {
898 hres = jsdisp_delete_idx(jsthis, i+add_args);
899 }else if(SUCCEEDED(hres)) {
900 hres = jsdisp_propput_idx(jsthis, i+add_args, val);
901 jsval_release(val);
905 for(i=length; SUCCEEDED(hres) && i != length-delete_cnt+add_args; i--)
906 hres = jsdisp_delete_idx(jsthis, i-1);
907 }else if(add_args > delete_cnt) {
908 for(i=length-delete_cnt; SUCCEEDED(hres) && i != start; i--) {
909 hres = jsdisp_get_idx(jsthis, i+delete_cnt-1, &val);
910 if(hres == DISP_E_UNKNOWNNAME) {
911 hres = jsdisp_delete_idx(jsthis, i+add_args-1);
912 }else if(SUCCEEDED(hres)) {
913 hres = jsdisp_propput_idx(jsthis, i+add_args-1, val);
914 jsval_release(val);
919 for(i=0; SUCCEEDED(hres) && i < add_args; i++)
920 hres = jsdisp_propput_idx(jsthis, start+i, argv[i+2]);
922 if(SUCCEEDED(hres))
923 hres = jsdisp_propput_name(jsthis, L"length", jsval_number(length-delete_cnt+add_args));
925 if(FAILED(hres)) {
926 if(ret_array)
927 jsdisp_release(ret_array);
928 goto done;
931 if(r)
932 *r = jsval_obj(ret_array);
933 done:
934 jsdisp_release(jsthis);
935 return hres;
938 /* ECMA-262 3rd Edition 15.4.4.2 */
939 static HRESULT Array_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
940 jsval_t *r)
942 ArrayInstance *array;
944 TRACE("\n");
946 array = array_this(vthis);
947 if(!array)
948 return JS_E_ARRAY_EXPECTED;
950 return array_join(ctx, &array->dispex, array->length, L",", 1, to_string, r);
953 static HRESULT to_locale_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str)
955 jsdisp_t *jsdisp;
956 IDispatch *obj;
957 HRESULT hres;
959 switch(jsval_type(val)) {
960 case JSV_OBJECT:
961 hres = disp_call_name(ctx, get_object(val), L"toLocaleString", DISPATCH_METHOD, 0, NULL, &val);
962 if(FAILED(hres)) {
963 if(hres == JS_E_INVALID_PROPERTY && ctx->version >= SCRIPTLANGUAGEVERSION_ES5)
964 hres = JS_E_FUNCTION_EXPECTED;
965 return hres;
967 break;
968 case JSV_NUMBER:
969 if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5)
970 return localize_number(ctx, get_number(val), FALSE, str);
971 /* fall through */
972 default:
973 if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5)
974 break;
976 hres = to_object(ctx, val, &obj);
977 if(FAILED(hres))
978 return hres;
980 jsdisp = as_jsdisp(obj);
981 hres = jsdisp_call_name(jsdisp, L"toLocaleString", DISPATCH_METHOD, 0, NULL, &val);
982 jsdisp_release(jsdisp);
983 if(FAILED(hres))
984 return hres;
985 break;
988 return to_string(ctx, val, str);
991 static HRESULT Array_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
992 jsval_t *r)
994 jsdisp_t *jsthis;
995 UINT32 length;
996 HRESULT hres;
997 WCHAR buf[5];
998 int len;
1000 TRACE("\n");
1002 if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) {
1003 ArrayInstance *array = array_this(vthis);
1004 if(!array)
1005 return JS_E_ARRAY_EXPECTED;
1006 jsthis = jsdisp_addref(&array->dispex);
1007 length = array->length;
1008 }else {
1009 hres = get_length(ctx, vthis, &jsthis, &length);
1010 if(FAILED(hres))
1011 return hres;
1014 if(!(len = GetLocaleInfoW(ctx->lcid, LOCALE_SLIST, buf, ARRAY_SIZE(buf) - 1))) {
1015 buf[len++] = ',';
1016 len++;
1018 buf[len - 1] = ' ';
1019 buf[len] = '\0';
1021 hres = array_join(ctx, jsthis, length, buf, len, to_locale_string, r);
1022 jsdisp_release(jsthis);
1023 return hres;
1026 static HRESULT Array_every(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1027 jsval_t *r)
1029 IDispatch *context_obj = NULL, *callback;
1030 jsval_t value, args[3], res;
1031 BOOL boolval, ret = TRUE;
1032 unsigned length, i;
1033 jsdisp_t *jsthis;
1034 HRESULT hres;
1036 TRACE("\n");
1038 hres = get_length(ctx, vthis, &jsthis, &length);
1039 if(FAILED(hres))
1040 return hres;
1042 /* FIXME: check IsCallable */
1043 if(!argc || !is_object_instance(argv[0])) {
1044 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1045 hres = E_INVALIDARG;
1046 goto done;
1048 callback = get_object(argv[0]);
1050 if(argc > 1 && !is_undefined(argv[1])) {
1051 if(!is_object_instance(argv[1])) {
1052 FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
1053 hres = E_NOTIMPL;
1054 goto done;
1056 context_obj = get_object(argv[1]);
1059 for(i = 0; i < length; i++) {
1060 hres = jsdisp_get_idx(jsthis, i, &value);
1061 if(FAILED(hres)) {
1062 if(hres == DISP_E_UNKNOWNNAME)
1063 continue;
1064 goto done;
1066 args[0] = value;
1067 args[1] = jsval_number(i);
1068 args[2] = jsval_obj(jsthis);
1069 hres = disp_call_value(ctx, callback, context_obj, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
1070 jsval_release(value);
1071 if(FAILED(hres))
1072 goto done;
1074 hres = to_boolean(res, &boolval);
1075 jsval_release(res);
1076 if(FAILED(hres))
1077 goto done;
1078 if(!boolval) {
1079 ret = FALSE;
1080 break;
1084 if(r)
1085 *r = jsval_bool(ret);
1086 hres = S_OK;
1087 done:
1088 jsdisp_release(jsthis);
1089 return hres;
1092 static HRESULT Array_filter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1093 jsval_t *r)
1095 IDispatch *context_obj = NULL, *callback;
1096 jsval_t value, args[3], res;
1097 unsigned length, i, j = 0;
1098 jsdisp_t *jsthis, *arr;
1099 HRESULT hres;
1100 BOOL boolval;
1102 TRACE("\n");
1104 hres = get_length(ctx, vthis, &jsthis, &length);
1105 if(FAILED(hres))
1106 return hres;
1108 /* FIXME: check IsCallable */
1109 if(!argc || !is_object_instance(argv[0])) {
1110 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1111 hres = E_INVALIDARG;
1112 goto done;
1114 callback = get_object(argv[0]);
1116 if(argc > 1 && !is_undefined(argv[1])) {
1117 if(!is_object_instance(argv[1])) {
1118 FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
1119 hres = E_NOTIMPL;
1120 goto done;
1122 context_obj = get_object(argv[1]);
1125 hres = create_array(ctx, 0, &arr);
1126 if(FAILED(hres))
1127 goto done;
1129 for(i = 0; i < length; i++) {
1130 hres = jsdisp_get_idx(jsthis, i, &value);
1131 if(FAILED(hres)) {
1132 if(hres == DISP_E_UNKNOWNNAME) {
1133 hres = S_OK;
1134 continue;
1136 break;
1138 args[0] = value;
1139 args[1] = jsval_number(i);
1140 args[2] = jsval_obj(jsthis);
1141 hres = disp_call_value(ctx, callback, context_obj, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
1142 if(SUCCEEDED(hres)) {
1143 hres = to_boolean(res, &boolval);
1144 jsval_release(res);
1145 if(SUCCEEDED(hres) && boolval)
1146 hres = jsdisp_propput_idx(arr, j++, value);
1148 jsval_release(value);
1149 if(FAILED(hres))
1150 break;
1153 if(FAILED(hres)) {
1154 jsdisp_release(arr);
1155 goto done;
1157 set_length(arr, j);
1159 if(r)
1160 *r = jsval_obj(arr);
1161 done:
1162 jsdisp_release(jsthis);
1163 return hres;
1166 static HRESULT Array_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1167 jsval_t *r)
1169 IDispatch *context_obj = NULL, *callback;
1170 jsval_t value, args[3], res;
1171 jsdisp_t *jsthis;
1172 unsigned length, i;
1173 HRESULT hres;
1175 TRACE("\n");
1177 hres = get_length(ctx, vthis, &jsthis, &length);
1178 if(FAILED(hres))
1179 return hres;
1181 /* Fixme check IsCallable */
1182 if(!argc || !is_object_instance(argv[0])) {
1183 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1184 hres = E_INVALIDARG;
1185 goto done;
1187 callback = get_object(argv[0]);
1189 if(argc > 1 && !is_undefined(argv[1])) {
1190 if(!is_object_instance(argv[1])) {
1191 FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
1192 hres = E_NOTIMPL;
1193 goto done;
1195 context_obj = get_object(argv[1]);
1198 for(i = 0; i < length; i++) {
1199 hres = jsdisp_get_idx(jsthis, i, &value);
1200 if(hres == DISP_E_UNKNOWNNAME)
1201 continue;
1202 if(FAILED(hres))
1203 goto done;
1205 args[0] = value;
1206 args[1] = jsval_number(i);
1207 args[2] = jsval_obj(jsthis);
1208 hres = disp_call_value(ctx, callback, context_obj, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
1209 jsval_release(value);
1210 if(FAILED(hres))
1211 goto done;
1212 jsval_release(res);
1215 if(r) *r = jsval_undefined();
1216 hres = S_OK;
1217 done:
1218 jsdisp_release(jsthis);
1219 return hres;
1222 static HRESULT Array_indexOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1223 jsval_t *r)
1225 jsdisp_t *jsthis;
1226 unsigned length, i, from = 0;
1227 jsval_t search, value;
1228 BOOL eq;
1229 HRESULT hres;
1231 TRACE("\n");
1233 hres = get_length(ctx, vthis, &jsthis, &length);
1234 if(FAILED(hres))
1235 return hres;
1236 if(!length) {
1237 if(r) *r = jsval_number(-1);
1238 goto done;
1241 search = argc ? argv[0] : jsval_undefined();
1243 if(argc > 1) {
1244 double from_arg;
1246 hres = to_integer(ctx, argv[1], &from_arg);
1247 if(FAILED(hres))
1248 goto done;
1250 if(from_arg >= 0)
1251 from = min(from_arg, length);
1252 else
1253 from = max(from_arg + length, 0);
1256 for(i = from; i < length; i++) {
1257 hres = jsdisp_get_idx(jsthis, i, &value);
1258 if(hres == DISP_E_UNKNOWNNAME)
1259 continue;
1260 if(FAILED(hres))
1261 goto done;
1263 hres = jsval_strict_equal(value, search, &eq);
1264 jsval_release(value);
1265 if(FAILED(hres))
1266 goto done;
1267 if(eq) {
1268 if(r) *r = jsval_number(i);
1269 goto done;
1273 if(r) *r = jsval_number(-1);
1274 hres = S_OK;
1275 done:
1276 jsdisp_release(jsthis);
1277 return hres;
1280 static HRESULT Array_lastIndexOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1281 jsval_t *r)
1283 jsval_t search, value;
1284 unsigned i, length;
1285 jsdisp_t *jsthis;
1286 HRESULT hres;
1287 BOOL eq;
1289 TRACE("\n");
1291 hres = get_length(ctx, vthis, &jsthis, &length);
1292 if(FAILED(hres))
1293 return hres;
1294 if(!length)
1295 goto notfound;
1297 search = argc ? argv[0] : jsval_undefined();
1299 i = length - 1;
1300 if(argc > 1) {
1301 double from_arg;
1303 hres = to_integer(ctx, argv[1], &from_arg);
1304 if(FAILED(hres))
1305 goto done;
1307 if(from_arg >= 0.0)
1308 i = min(from_arg, i);
1309 else {
1310 from_arg += length;
1311 if(from_arg < 0.0)
1312 goto notfound;
1313 i = from_arg;
1317 do {
1318 hres = jsdisp_get_idx(jsthis, i, &value);
1319 if(hres == DISP_E_UNKNOWNNAME)
1320 continue;
1321 if(FAILED(hres))
1322 goto done;
1324 hres = jsval_strict_equal(value, search, &eq);
1325 jsval_release(value);
1326 if(FAILED(hres))
1327 goto done;
1328 if(eq) {
1329 if(r) *r = jsval_number(i);
1330 goto done;
1332 } while(i--);
1334 notfound:
1335 if(r) *r = jsval_number(-1);
1336 hres = S_OK;
1337 done:
1338 jsdisp_release(jsthis);
1339 return hres;
1342 static HRESULT Array_map(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1344 IDispatch *context_this = NULL, *callback;
1345 jsval_t callback_args[3], mapped_value;
1346 jsdisp_t *jsthis, *array;
1347 UINT32 length, k;
1348 HRESULT hres;
1350 TRACE("\n");
1352 hres = get_length(ctx, vthis, &jsthis, &length);
1353 if(FAILED(hres)) {
1354 FIXME("Could not get length\n");
1355 return hres;
1358 /* FIXME: check IsCallable */
1359 if(!argc || !is_object_instance(argv[0])) {
1360 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1361 hres = E_INVALIDARG;
1362 goto done;
1364 callback = get_object(argv[0]);
1366 if(argc > 1) {
1367 if(is_object_instance(argv[1])) {
1368 context_this = get_object(argv[1]);
1369 }else if(!is_undefined(argv[1])) {
1370 FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
1371 hres = E_NOTIMPL;
1372 goto done;
1376 hres = create_array(ctx, length, &array);
1377 if(FAILED(hres))
1378 goto done;
1380 for(k = 0; k < length; k++) {
1381 hres = jsdisp_get_idx(jsthis, k, &callback_args[0]);
1382 if(hres == DISP_E_UNKNOWNNAME)
1383 continue;
1384 if(FAILED(hres))
1385 break;
1387 callback_args[1] = jsval_number(k);
1388 callback_args[2] = jsval_obj(jsthis);
1389 hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, 3, callback_args, &mapped_value);
1390 jsval_release(callback_args[0]);
1391 if(FAILED(hres))
1392 break;
1394 hres = jsdisp_propput_idx(array, k, mapped_value);
1395 if(FAILED(hres))
1396 break;
1399 if(SUCCEEDED(hres) && r)
1400 *r = jsval_obj(array);
1401 else
1402 jsdisp_release(array);
1403 done:
1404 jsdisp_release(jsthis);
1405 return hres;
1408 static HRESULT Array_reduce(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1410 IDispatch *context_this = NULL, *callback;
1411 jsval_t callback_args[4], acc, new_acc;
1412 BOOL have_value = FALSE;
1413 jsdisp_t *jsthis;
1414 UINT32 length, k;
1415 HRESULT hres;
1417 TRACE("\n");
1419 hres = get_length(ctx, vthis, &jsthis, &length);
1420 if(FAILED(hres)) {
1421 FIXME("Could not get length\n");
1422 return hres;
1425 /* Fixme check IsCallable */
1426 if(!argc || !is_object_instance(argv[0])) {
1427 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1428 hres = E_INVALIDARG;
1429 goto done;
1431 callback = get_object(argv[0]);
1433 if(argc > 1) {
1434 have_value = TRUE;
1435 hres = jsval_copy(argv[1], &acc);
1436 if(FAILED(hres))
1437 goto done;
1440 for(k = 0; k < length; k++) {
1441 hres = jsdisp_get_idx(jsthis, k, &callback_args[1]);
1442 if(hres == DISP_E_UNKNOWNNAME)
1443 continue;
1444 if(FAILED(hres))
1445 break;
1447 if(!have_value) {
1448 have_value = TRUE;
1449 acc = callback_args[1];
1450 continue;
1453 callback_args[0] = acc;
1454 callback_args[2] = jsval_number(k);
1455 callback_args[3] = jsval_obj(jsthis);
1456 hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(callback_args), callback_args, &new_acc);
1457 jsval_release(callback_args[1]);
1458 if(FAILED(hres))
1459 break;
1461 jsval_release(acc);
1462 acc = new_acc;
1465 if(SUCCEEDED(hres) && !have_value) {
1466 WARN("No array element\n");
1467 hres = JS_E_INVALID_ACTION;
1470 if(SUCCEEDED(hres) && r)
1471 *r = acc;
1472 else if(have_value)
1473 jsval_release(acc);
1474 done:
1475 jsdisp_release(jsthis);
1476 return hres;
1479 static HRESULT Array_some(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1480 jsval_t *r)
1482 IDispatch *context_obj = NULL, *callback;
1483 jsval_t value, args[3], res;
1484 BOOL boolval, ret = FALSE;
1485 unsigned length, i;
1486 jsdisp_t *jsthis;
1487 HRESULT hres;
1489 TRACE("\n");
1491 hres = get_length(ctx, vthis, &jsthis, &length);
1492 if(FAILED(hres))
1493 return hres;
1495 /* FIXME: check IsCallable */
1496 if(!argc || !is_object_instance(argv[0])) {
1497 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1498 hres = E_INVALIDARG;
1499 goto done;
1501 callback = get_object(argv[0]);
1503 if(argc > 1 && !is_undefined(argv[1])) {
1504 if(!is_object_instance(argv[1])) {
1505 FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
1506 hres = E_NOTIMPL;
1507 goto done;
1509 context_obj = get_object(argv[1]);
1512 for(i = 0; i < length; i++) {
1513 hres = jsdisp_get_idx(jsthis, i, &value);
1514 if(FAILED(hres)) {
1515 if(hres == DISP_E_UNKNOWNNAME)
1516 continue;
1517 goto done;
1519 args[0] = value;
1520 args[1] = jsval_number(i);
1521 args[2] = jsval_obj(jsthis);
1522 hres = disp_call_value(ctx, callback, context_obj, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
1523 jsval_release(value);
1524 if(FAILED(hres))
1525 goto done;
1527 hres = to_boolean(res, &boolval);
1528 jsval_release(res);
1529 if(FAILED(hres))
1530 goto done;
1531 if(boolval) {
1532 ret = TRUE;
1533 break;
1537 if(r)
1538 *r = jsval_bool(ret);
1539 hres = S_OK;
1540 done:
1541 jsdisp_release(jsthis);
1542 return hres;
1545 /* ECMA-262 3rd Edition 15.4.4.13 */
1546 static HRESULT Array_unshift(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1547 jsval_t *r)
1549 jsdisp_t *jsthis;
1550 WCHAR buf[14], *buf_end, *str;
1551 UINT32 i, length;
1552 jsval_t val;
1553 DISPID id;
1554 HRESULT hres;
1556 TRACE("\n");
1558 hres = get_length(ctx, vthis, &jsthis, &length);
1559 if(FAILED(hres))
1560 return hres;
1562 if(argc) {
1563 buf_end = buf + ARRAY_SIZE(buf)-1;
1564 *buf_end-- = 0;
1565 i = length;
1567 while(i--) {
1568 str = idx_to_str(i, buf_end);
1570 hres = jsdisp_get_id(jsthis, str, 0, &id);
1571 if(SUCCEEDED(hres)) {
1572 hres = jsdisp_propget(jsthis, id, &val);
1573 if(FAILED(hres))
1574 goto done;
1576 hres = jsdisp_propput_idx(jsthis, i+argc, val);
1577 jsval_release(val);
1578 }else if(hres == DISP_E_UNKNOWNNAME) {
1579 hres = IDispatchEx_DeleteMemberByDispID(&jsthis->IDispatchEx_iface, id);
1583 if(FAILED(hres))
1584 goto done;
1587 for(i=0; i<argc; i++) {
1588 hres = jsdisp_propput_idx(jsthis, i, argv[i]);
1589 if(FAILED(hres))
1590 goto done;
1593 if(argc) {
1594 length += argc;
1595 hres = set_length(jsthis, length);
1596 if(FAILED(hres))
1597 goto done;
1600 if(r)
1601 *r = ctx->version < 2 ? jsval_undefined() : jsval_number(length);
1602 hres = S_OK;
1603 done:
1604 jsdisp_release(jsthis);
1605 return hres;
1608 static void Array_destructor(jsdisp_t *dispex)
1610 heap_free(dispex);
1613 static void Array_on_put(jsdisp_t *dispex, const WCHAR *name)
1615 ArrayInstance *array = array_from_jsdisp(dispex);
1616 const WCHAR *ptr = name;
1617 DWORD id = 0;
1619 if(!is_digit(*ptr))
1620 return;
1622 while(*ptr && is_digit(*ptr)) {
1623 id = id*10 + (*ptr-'0');
1624 ptr++;
1627 if(*ptr)
1628 return;
1630 if(id >= array->length)
1631 array->length = id+1;
1634 static const builtin_prop_t Array_props[] = {
1635 {L"concat", Array_concat, PROPF_METHOD|1},
1636 {L"every", Array_every, PROPF_METHOD|PROPF_ES5|1},
1637 {L"filter", Array_filter, PROPF_METHOD|PROPF_ES5|1},
1638 {L"forEach", Array_forEach, PROPF_METHOD|PROPF_ES5|1},
1639 {L"indexOf", Array_indexOf, PROPF_METHOD|PROPF_ES5|1},
1640 {L"join", Array_join, PROPF_METHOD|1},
1641 {L"lastIndexOf", Array_lastIndexOf, PROPF_METHOD|PROPF_ES5|1},
1642 {L"length", NULL,0, Array_get_length, Array_set_length},
1643 {L"map", Array_map, PROPF_METHOD|PROPF_ES5|1},
1644 {L"pop", Array_pop, PROPF_METHOD},
1645 {L"push", Array_push, PROPF_METHOD|1},
1646 {L"reduce", Array_reduce, PROPF_METHOD|PROPF_ES5|1},
1647 {L"reverse", Array_reverse, PROPF_METHOD},
1648 {L"shift", Array_shift, PROPF_METHOD},
1649 {L"slice", Array_slice, PROPF_METHOD|2},
1650 {L"some", Array_some, PROPF_METHOD|PROPF_ES5|1},
1651 {L"sort", Array_sort, PROPF_METHOD|1},
1652 {L"splice", Array_splice, PROPF_METHOD|2},
1653 {L"toLocaleString", Array_toLocaleString, PROPF_METHOD},
1654 {L"toString", Array_toString, PROPF_METHOD},
1655 {L"unshift", Array_unshift, PROPF_METHOD|1},
1658 static const builtin_info_t Array_info = {
1659 JSCLASS_ARRAY,
1660 NULL,
1661 ARRAY_SIZE(Array_props),
1662 Array_props,
1663 Array_destructor,
1664 Array_on_put
1667 static const builtin_prop_t ArrayInst_props[] = {
1668 {L"length", NULL,0, Array_get_length, Array_set_length}
1671 static const builtin_info_t ArrayInst_info = {
1672 JSCLASS_ARRAY,
1673 NULL,
1674 ARRAY_SIZE(ArrayInst_props),
1675 ArrayInst_props,
1676 Array_destructor,
1677 Array_on_put
1680 /* ECMA-262 5.1 Edition 15.4.3.2 */
1681 static HRESULT ArrayConstr_isArray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1683 jsdisp_t *obj;
1685 TRACE("\n");
1687 if(!argc || !is_object_instance(argv[0])) {
1688 if(r) *r = jsval_bool(FALSE);
1689 return S_OK;
1692 obj = iface_to_jsdisp(get_object(argv[0]));
1693 if(r) *r = jsval_bool(obj && is_class(obj, JSCLASS_ARRAY));
1694 if(obj) jsdisp_release(obj);
1695 return S_OK;
1698 static HRESULT ArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1699 jsval_t *r)
1701 jsdisp_t *obj;
1702 DWORD i;
1703 HRESULT hres;
1705 TRACE("\n");
1707 switch(flags) {
1708 case DISPATCH_METHOD:
1709 case DISPATCH_CONSTRUCT: {
1710 if(argc == 1 && is_number(argv[0])) {
1711 double n = get_number(argv[0]);
1713 if(n < 0 || !is_int32(n))
1714 return JS_E_INVALID_LENGTH;
1715 if(!r)
1716 return S_OK;
1718 hres = create_array(ctx, n, &obj);
1719 if(FAILED(hres))
1720 return hres;
1722 *r = jsval_obj(obj);
1723 return S_OK;
1726 if(!r)
1727 return S_OK;
1728 hres = create_array(ctx, argc, &obj);
1729 if(FAILED(hres))
1730 return hres;
1732 for(i=0; i < argc; i++) {
1733 hres = jsdisp_propput_idx(obj, i, argv[i]);
1734 if(FAILED(hres))
1735 break;
1737 if(FAILED(hres)) {
1738 jsdisp_release(obj);
1739 return hres;
1742 *r = jsval_obj(obj);
1743 break;
1745 default:
1746 FIXME("unimplemented flags: %x\n", flags);
1747 return E_NOTIMPL;
1750 return S_OK;
1753 static HRESULT alloc_array(script_ctx_t *ctx, jsdisp_t *object_prototype, ArrayInstance **ret)
1755 ArrayInstance *array;
1756 HRESULT hres;
1758 array = heap_alloc_zero(sizeof(ArrayInstance));
1759 if(!array)
1760 return E_OUTOFMEMORY;
1762 if(object_prototype)
1763 hres = init_dispex(&array->dispex, ctx, &Array_info, object_prototype);
1764 else
1765 hres = init_dispex_from_constr(&array->dispex, ctx, &ArrayInst_info, ctx->array_constr);
1767 if(FAILED(hres)) {
1768 heap_free(array);
1769 return hres;
1772 *ret = array;
1773 return S_OK;
1776 static const builtin_prop_t ArrayConstr_props[] = {
1777 {L"isArray", ArrayConstr_isArray, PROPF_ES5|PROPF_METHOD|1}
1780 static const builtin_info_t ArrayConstr_info = {
1781 JSCLASS_FUNCTION,
1782 Function_value,
1783 ARRAY_SIZE(ArrayConstr_props),
1784 ArrayConstr_props,
1785 NULL,
1786 NULL
1789 HRESULT create_array_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1791 ArrayInstance *array;
1792 HRESULT hres;
1794 hres = alloc_array(ctx, object_prototype, &array);
1795 if(FAILED(hres))
1796 return hres;
1798 hres = create_builtin_constructor(ctx, ArrayConstr_value, L"Array", &ArrayConstr_info, PROPF_CONSTR|1, &array->dispex, ret);
1800 jsdisp_release(&array->dispex);
1801 return hres;
1804 HRESULT create_array(script_ctx_t *ctx, DWORD length, jsdisp_t **ret)
1806 ArrayInstance *array;
1807 HRESULT hres;
1809 hres = alloc_array(ctx, NULL, &array);
1810 if(FAILED(hres))
1811 return hres;
1813 array->length = length;
1815 *ret = &array->dispex;
1816 return S_OK;