comctl32/tests: Use CRT allocation functions.
[wine.git] / dlls / jscript / object.c
blob65b25cab2396d91663745a822e6e7ce758135626
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
19 #include <assert.h>
21 #include "jscript.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
27 static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
28 jsval_t *r)
30 jsdisp_t *jsdisp;
31 const WCHAR *str;
32 IDispatch *disp;
33 HRESULT hres;
35 /* Keep in sync with jsclass_t enum */
36 static const WCHAR *names[] = {
37 NULL,
38 L"[object Array]",
39 L"[object Boolean]",
40 L"[object Date]",
41 L"[object Object]",
42 L"[object Error]",
43 L"[object Function]",
44 NULL,
45 L"[object Math]",
46 L"[object Number]",
47 L"[object Object]",
48 L"[object RegExp]",
49 L"[object String]",
50 L"[object Object]",
51 L"[object Object]",
52 L"[object Object]",
53 L"[object Object]",
54 L"[object Object]",
55 L"[object Object]"
58 TRACE("\n");
60 if(is_undefined(vthis) || is_null(vthis)) {
61 if(ctx->version < SCRIPTLANGUAGEVERSION_ES5)
62 str = L"[object Object]";
63 else
64 str = is_null(vthis) ? L"[object Null]" : L"[object Undefined]";
65 goto set_output;
68 hres = to_object(ctx, vthis, &disp);
69 if(FAILED(hres))
70 return hres;
72 jsdisp = to_jsdisp(disp);
73 if(!jsdisp) {
74 str = L"[object Object]";
75 }else if(names[jsdisp->builtin_info->class]) {
76 str = names[jsdisp->builtin_info->class];
77 }else {
78 assert(jsdisp->builtin_info->class != JSCLASS_NONE);
79 FIXME("jsdisp->builtin_info->class = %d\n", jsdisp->builtin_info->class);
80 hres = E_FAIL;
82 IDispatch_Release(disp);
83 if(FAILED(hres))
84 return hres;
86 set_output:
87 if(r) {
88 jsstr_t *ret;
89 ret = jsstr_alloc(str);
90 if(!ret)
91 return E_OUTOFMEMORY;
92 *r = jsval_string(ret);
95 return S_OK;
98 static HRESULT Object_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
99 jsval_t *r)
101 jsdisp_t *jsdisp;
102 IDispatch *disp;
103 HRESULT hres;
105 TRACE("\n");
107 hres = to_object(ctx, vthis, &disp);
108 if(FAILED(hres))
109 return hres;
111 if(!(jsdisp = to_jsdisp(disp))) {
112 FIXME("Host object this\n");
113 hres = E_FAIL;
114 goto done;
117 hres = jsdisp_call_name(jsdisp, L"toString", DISPATCH_METHOD, 0, NULL, r);
118 done:
119 IDispatch_Release(disp);
120 return hres;
123 static HRESULT Object_valueOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
124 jsval_t *r)
126 IDispatch *disp;
127 HRESULT hres;
129 TRACE("\n");
131 if(is_null_disp(vthis)) {
132 if(r) *r = jsval_null_disp();
133 return S_OK;
136 hres = to_object(ctx, vthis, &disp);
137 if(FAILED(hres))
138 return hres;
140 if(r)
141 *r = jsval_disp(disp);
142 else
143 IDispatch_Release(disp);
144 return S_OK;
147 static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
148 jsval_t *r)
150 IDispatchEx *dispex;
151 jsdisp_t *jsdisp;
152 IDispatch *disp;
153 jsstr_t *name;
154 DISPID id;
155 BSTR bstr;
156 HRESULT hres;
158 TRACE("\n");
160 hres = to_object(ctx, vthis, &disp);
161 if(FAILED(hres))
162 return hres;
164 if(!argc) {
165 if(r)
166 *r = jsval_bool(FALSE);
167 goto done;
170 hres = to_string(ctx, argv[0], &name);
171 if(FAILED(hres))
172 goto done;
174 if((jsdisp = to_jsdisp(disp))) {
175 property_desc_t prop_desc;
176 const WCHAR *name_str;
178 name_str = jsstr_flatten(name);
179 if(!name_str) {
180 jsstr_release(name);
181 hres = E_OUTOFMEMORY;
182 goto done;
185 hres = jsdisp_get_own_property(jsdisp, name_str, TRUE, &prop_desc);
186 jsstr_release(name);
187 if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
188 goto done;
190 if(r) *r = jsval_bool(hres == S_OK);
191 hres = S_OK;
192 goto done;
196 bstr = SysAllocStringLen(NULL, jsstr_length(name));
197 if(bstr)
198 jsstr_flush(name, bstr);
199 jsstr_release(name);
200 if(!bstr) {
201 hres = E_OUTOFMEMORY;
202 goto done;
205 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
206 if(SUCCEEDED(hres)) {
207 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive), &id);
208 IDispatchEx_Release(dispex);
209 }else {
210 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, ctx->lcid, &id);
212 SysFreeString(bstr);
213 if(r)
214 *r = jsval_bool(SUCCEEDED(hres));
215 hres = S_OK;
216 done:
217 IDispatch_Release(disp);
218 return hres;
221 static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
222 jsval_t *r)
224 property_desc_t prop_desc;
225 const WCHAR *name;
226 jsstr_t *name_str;
227 jsdisp_t *jsdisp;
228 IDispatch *disp;
229 HRESULT hres;
231 TRACE("\n");
233 hres = to_object(ctx, vthis, &disp);
234 if(FAILED(hres))
235 return hres;
237 if(argc != 1) {
238 FIXME("argc %d not supported\n", argc);
239 hres = E_NOTIMPL;
240 goto done;
243 if(!(jsdisp = to_jsdisp(disp))) {
244 FIXME("Host object this\n");
245 hres = E_FAIL;
246 goto done;
249 hres = to_flat_string(ctx, argv[0], &name_str, &name);
250 if(FAILED(hres))
251 goto done;
253 hres = jsdisp_get_own_property(jsdisp, name, TRUE, &prop_desc);
254 jsstr_release(name_str);
255 if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
256 goto done;
258 if(r)
259 *r = jsval_bool(hres == S_OK && (prop_desc.flags & PROPF_ENUMERABLE) != 0);
260 hres = S_OK;
261 done:
262 IDispatch_Release(disp);
263 return hres;
266 static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
267 jsval_t *r)
269 jsdisp_t *jsthis, *jsdisp;
270 IDispatch *disp;
271 BOOL ret = FALSE;
272 HRESULT hres;
274 hres = to_object(ctx, vthis, &disp);
275 if(FAILED(hres))
276 return hres;
278 if(!r)
279 goto done;
281 if(argc && (jsthis = to_jsdisp(disp)) && is_object_instance(argv[0]) &&
282 (jsdisp = to_jsdisp(get_object(argv[0])))) {
283 while(jsdisp->prototype) {
284 if(jsdisp->prototype == jsthis) {
285 ret = TRUE;
286 break;
288 jsdisp = jsdisp->prototype;
292 *r = jsval_bool(ret);
293 done:
294 IDispatch_Release(disp);
295 return hres;
298 static HRESULT Object_defineGetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
300 property_desc_t desc;
301 const WCHAR *name;
302 jsstr_t *name_str;
303 jsdisp_t *jsthis;
304 HRESULT hres;
306 TRACE("\n");
308 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
309 goto done;
311 if(argc < 2 || !is_object_instance(argv[1]))
312 return JS_E_FUNCTION_EXPECTED;
314 desc.getter = to_jsdisp(get_object(argv[1]));
315 if(!desc.getter) {
316 FIXME("getter is not JS object\n");
317 return E_NOTIMPL;
319 /* FIXME: Check IsCallable */
321 hres = to_flat_string(ctx, argv[0], &name_str, &name);
322 if(FAILED(hres))
323 return hres;
325 desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
326 desc.explicit_getter = TRUE;
327 desc.explicit_setter = FALSE;
328 desc.explicit_value = FALSE;
329 desc.setter = NULL;
330 hres = jsdisp_define_property(jsthis, name, &desc);
332 jsstr_release(name_str);
333 if(FAILED(hres))
334 return hres;
335 done:
336 if(r)
337 *r = jsval_undefined();
338 return S_OK;
341 static HRESULT Object_defineSetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
343 property_desc_t desc;
344 const WCHAR *name;
345 jsstr_t *name_str;
346 jsdisp_t *jsthis;
347 HRESULT hres;
349 TRACE("\n");
351 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
352 goto done;
354 if(argc < 2 || !is_object_instance(argv[1]))
355 return JS_E_FUNCTION_EXPECTED;
357 desc.setter = to_jsdisp(get_object(argv[1]));
358 if(!desc.setter) {
359 FIXME("setter is not JS object\n");
360 return E_NOTIMPL;
362 /* FIXME: Check IsCallable */
364 hres = to_flat_string(ctx, argv[0], &name_str, &name);
365 if(FAILED(hres))
366 return hres;
368 desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
369 desc.explicit_getter = FALSE;
370 desc.explicit_setter = TRUE;
371 desc.explicit_value = FALSE;
372 desc.getter = NULL;
373 hres = jsdisp_define_property(jsthis, name, &desc);
375 jsstr_release(name_str);
376 if(FAILED(hres))
377 return hres;
378 done:
379 if(r)
380 *r = jsval_undefined();
381 return S_OK;
384 HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
386 jsdisp_t *jsthis;
387 IDispatch *disp;
388 HRESULT hres;
390 TRACE("%s\n", debugstr_jsval(vthis));
392 hres = to_object(ctx, vthis, &disp);
393 if(FAILED(hres))
394 return hres;
396 if(!r)
397 goto done;
399 if(!(jsthis = to_jsdisp(disp))) {
400 FIXME("Host object this\n");
401 hres = E_FAIL;
402 goto done;
405 *r = jsthis->prototype
406 ? jsval_obj(jsdisp_addref(jsthis->prototype))
407 : jsval_null();
408 done:
409 IDispatch_Release(disp);
410 return hres;
413 HRESULT Object_set_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
415 jsdisp_t *jsthis, *proto;
416 HRESULT hres;
418 TRACE("%s\n", debugstr_jsval(vthis));
420 if(is_undefined(vthis) || is_null(vthis))
421 return JS_E_OBJECT_EXPECTED;
422 if(!argc) {
423 if(r)
424 *r = jsval_undefined();
425 return S_OK;
427 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
428 goto done;
430 if(is_null(argv[0])) {
431 proto = NULL;
432 }else if(is_object_instance(argv[0])) {
433 proto = to_jsdisp(get_object(argv[0]));
434 if(!proto) {
435 FIXME("Host object value\n");
436 return E_FAIL;
438 }else
439 goto done;
441 hres = jsdisp_change_prototype(jsthis, proto);
442 if(FAILED(hres))
443 return hres;
445 done:
446 return r ? jsval_copy(argv[0], r) : S_OK;
449 static void Object_destructor(jsdisp_t *dispex)
451 free(dispex);
454 static const builtin_prop_t Object_props[] = {
455 {L"__defineGetter__", Object_defineGetter, PROPF_METHOD|PROPF_ES6|2},
456 {L"__defineSetter__", Object_defineSetter, PROPF_METHOD|PROPF_ES6|2},
457 {L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1},
458 {L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1},
459 {L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1},
460 {L"toLocaleString", Object_toLocaleString, PROPF_METHOD},
461 {L"toString", Object_toString, PROPF_METHOD},
462 {L"valueOf", Object_valueOf, PROPF_METHOD}
465 static const builtin_info_t Object_info = {
466 JSCLASS_OBJECT,
467 NULL,
468 ARRAY_SIZE(Object_props),
469 Object_props,
470 Object_destructor,
471 NULL
474 static const builtin_info_t ObjectInst_info = {
475 JSCLASS_OBJECT,
476 NULL,
477 0, NULL,
478 Object_destructor,
479 NULL
482 static void release_property_descriptor(property_desc_t *desc)
484 if(desc->explicit_value)
485 jsval_release(desc->value);
486 if(desc->getter)
487 jsdisp_release(desc->getter);
488 if(desc->setter)
489 jsdisp_release(desc->setter);
492 static HRESULT to_property_descriptor(script_ctx_t *ctx, jsdisp_t *attr_obj, property_desc_t *desc)
494 DISPID id;
495 jsval_t v;
496 BOOL b;
497 HRESULT hres;
499 memset(desc, 0, sizeof(*desc));
500 desc->value = jsval_undefined();
502 hres = jsdisp_get_id(attr_obj, L"enumerable", 0, &id);
503 if(SUCCEEDED(hres)) {
504 desc->mask |= PROPF_ENUMERABLE;
505 hres = jsdisp_propget(attr_obj, id, &v);
506 if(FAILED(hres))
507 return hres;
508 hres = to_boolean(v, &b);
509 jsval_release(v);
510 if(FAILED(hres))
511 return hres;
512 if(b)
513 desc->flags |= PROPF_ENUMERABLE;
514 }else if(hres != DISP_E_UNKNOWNNAME) {
515 return hres;
518 hres = jsdisp_get_id(attr_obj, L"configurable", 0, &id);
519 if(SUCCEEDED(hres)) {
520 desc->mask |= PROPF_CONFIGURABLE;
521 hres = jsdisp_propget(attr_obj, id, &v);
522 if(FAILED(hres))
523 return hres;
524 hres = to_boolean(v, &b);
525 jsval_release(v);
526 if(FAILED(hres))
527 return hres;
528 if(b)
529 desc->flags |= PROPF_CONFIGURABLE;
530 }else if(hres != DISP_E_UNKNOWNNAME) {
531 return hres;
534 hres = jsdisp_get_id(attr_obj, L"value", 0, &id);
535 if(SUCCEEDED(hres)) {
536 hres = jsdisp_propget(attr_obj, id, &desc->value);
537 if(FAILED(hres))
538 return hres;
539 desc->explicit_value = TRUE;
540 }else if(hres != DISP_E_UNKNOWNNAME) {
541 return hres;
544 hres = jsdisp_get_id(attr_obj, L"writable", 0, &id);
545 if(SUCCEEDED(hres)) {
546 desc->mask |= PROPF_WRITABLE;
547 hres = jsdisp_propget(attr_obj, id, &v);
548 if(SUCCEEDED(hres)) {
549 hres = to_boolean(v, &b);
550 jsval_release(v);
551 if(SUCCEEDED(hres) && b)
552 desc->flags |= PROPF_WRITABLE;
554 }else if(hres == DISP_E_UNKNOWNNAME) {
555 hres = S_OK;
557 if(FAILED(hres)) {
558 release_property_descriptor(desc);
559 return hres;
562 hres = jsdisp_get_id(attr_obj, L"get", 0, &id);
563 if(SUCCEEDED(hres)) {
564 desc->explicit_getter = TRUE;
565 hres = jsdisp_propget(attr_obj, id, &v);
566 if(SUCCEEDED(hres) && !is_undefined(v)) {
567 if(!is_object_instance(v)) {
568 FIXME("getter is not an object\n");
569 jsval_release(v);
570 hres = E_FAIL;
571 }else {
572 /* FIXME: Check IsCallable */
573 desc->getter = to_jsdisp(get_object(v));
574 if(!desc->getter)
575 FIXME("getter is not JS object\n");
578 }else if(hres == DISP_E_UNKNOWNNAME) {
579 hres = S_OK;
581 if(FAILED(hres)) {
582 release_property_descriptor(desc);
583 return hres;
586 hres = jsdisp_get_id(attr_obj, L"set", 0, &id);
587 if(SUCCEEDED(hres)) {
588 desc->explicit_setter = TRUE;
589 hres = jsdisp_propget(attr_obj, id, &v);
590 if(SUCCEEDED(hres) && !is_undefined(v)) {
591 if(!is_object_instance(v)) {
592 FIXME("setter is not an object\n");
593 jsval_release(v);
594 hres = E_FAIL;
595 }else {
596 /* FIXME: Check IsCallable */
597 desc->setter = to_jsdisp(get_object(v));
598 if(!desc->setter)
599 FIXME("setter is not JS object\n");
602 }else if(hres == DISP_E_UNKNOWNNAME) {
603 hres = S_OK;
605 if(FAILED(hres)) {
606 release_property_descriptor(desc);
607 return hres;
610 if(desc->explicit_getter || desc->explicit_setter) {
611 if(desc->explicit_value)
612 hres = JS_E_PROP_DESC_MISMATCH;
613 else if(desc->mask & PROPF_WRITABLE)
614 hres = JS_E_INVALID_WRITABLE_PROP_DESC;
617 if(FAILED(hres))
618 release_property_descriptor(desc);
619 return hres;
622 static HRESULT jsdisp_define_properties(script_ctx_t *ctx, jsdisp_t *obj, jsval_t list_val)
624 DISPID id = DISPID_STARTENUM;
625 property_desc_t prop_desc;
626 IDispatch *list_disp;
627 jsdisp_t *list_obj, *desc_obj;
628 jsval_t desc_val;
629 BSTR name;
630 HRESULT hres;
632 hres = to_object(ctx, list_val, &list_disp);
633 if(FAILED(hres))
634 return hres;
636 if(!(list_obj = to_jsdisp(list_disp))) {
637 FIXME("non-JS list obj\n");
638 IDispatch_Release(list_disp);
639 return E_NOTIMPL;
642 while(1) {
643 hres = jsdisp_next_prop(list_obj, id, JSDISP_ENUM_OWN_ENUMERABLE, &id);
644 if(hres != S_OK)
645 break;
647 hres = jsdisp_propget(list_obj, id, &desc_val);
648 if(FAILED(hres))
649 break;
651 if(!is_object_instance(desc_val) || !(desc_obj = to_jsdisp(get_object(desc_val)))) {
652 jsval_release(desc_val);
653 break;
656 hres = to_property_descriptor(ctx, desc_obj, &prop_desc);
657 jsdisp_release(desc_obj);
658 if(FAILED(hres))
659 break;
661 hres = IDispatchEx_GetMemberName(&list_obj->IDispatchEx_iface, id, &name);
662 if(SUCCEEDED(hres))
663 hres = jsdisp_define_property(obj, name, &prop_desc);
664 release_property_descriptor(&prop_desc);
665 if(FAILED(hres))
666 break;
669 jsdisp_release(list_obj);
670 return FAILED(hres) ? hres : S_OK;
673 static HRESULT Object_defineProperty(script_ctx_t *ctx, jsval_t vthis, WORD flags,
674 unsigned argc, jsval_t *argv, jsval_t *r)
676 property_desc_t prop_desc;
677 jsdisp_t *obj, *attr_obj;
678 const WCHAR *name;
679 jsstr_t *name_str;
680 HRESULT hres;
682 TRACE("\n");
684 if(argc < 1 || !is_object_instance(argv[0]))
685 return JS_E_OBJECT_EXPECTED;
686 obj = to_jsdisp(get_object(argv[0]));
687 if(!obj) {
688 FIXME("not implemented non-JS object\n");
689 return E_NOTIMPL;
692 hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
693 if(FAILED(hres))
694 return hres;
696 if(argc >= 3 && is_object_instance(argv[2])) {
697 attr_obj = to_jsdisp(get_object(argv[2]));
698 if(attr_obj) {
699 hres = to_property_descriptor(ctx, attr_obj, &prop_desc);
700 }else {
701 FIXME("not implemented non-JS object\n");
702 hres = E_NOTIMPL;
704 }else {
705 hres = JS_E_OBJECT_EXPECTED;
708 if(FAILED(hres))
710 jsstr_release(name_str);
711 return hres;
714 hres = jsdisp_define_property(obj, name, &prop_desc);
715 jsstr_release(name_str);
716 release_property_descriptor(&prop_desc);
717 if(SUCCEEDED(hres) && r)
718 *r = jsval_obj(jsdisp_addref(obj));
719 return hres;
722 static HRESULT Object_defineProperties(script_ctx_t *ctx, jsval_t vthis, WORD flags,
723 unsigned argc, jsval_t *argv, jsval_t *r)
725 jsdisp_t *obj;
726 HRESULT hres;
728 if(argc < 1 || !is_object_instance(argv[0]) || !(obj = to_jsdisp(get_object(argv[0])))) {
729 FIXME("not an object\n");
730 return E_NOTIMPL;
733 TRACE("%p\n", obj);
735 hres = jsdisp_define_properties(ctx, obj, argc >= 2 ? argv[1] : jsval_undefined());
736 if(SUCCEEDED(hres) && r)
737 *r = jsval_obj(jsdisp_addref(obj));
738 return hres;
741 static HRESULT Object_getOwnPropertyDescriptor(script_ctx_t *ctx, jsval_t vthis, WORD flags,
742 unsigned argc, jsval_t *argv, jsval_t *r)
744 property_desc_t prop_desc;
745 jsdisp_t *obj, *desc_obj;
746 const WCHAR *name;
747 jsstr_t *name_str;
748 HRESULT hres;
750 TRACE("\n");
752 if(argc < 1 || !is_object_instance(argv[0]))
753 return JS_E_OBJECT_EXPECTED;
754 obj = to_jsdisp(get_object(argv[0]));
755 if(!obj) {
756 FIXME("not implemented non-JS object\n");
757 return E_NOTIMPL;
760 hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
761 if(FAILED(hres))
762 return hres;
764 hres = jsdisp_get_own_property(obj, name, FALSE, &prop_desc);
765 jsstr_release(name_str);
766 if(hres == DISP_E_UNKNOWNNAME) {
767 if(r) *r = jsval_undefined();
768 return S_OK;
770 if(FAILED(hres))
771 return hres;
773 hres = create_object(ctx, NULL, &desc_obj);
774 if(FAILED(hres))
775 return hres;
777 if(prop_desc.explicit_getter || prop_desc.explicit_setter) {
778 hres = jsdisp_define_data_property(desc_obj, L"get", PROPF_ALL,
779 prop_desc.getter ? jsval_obj(prop_desc.getter) : jsval_undefined());
780 if(SUCCEEDED(hres))
781 hres = jsdisp_define_data_property(desc_obj, L"set", PROPF_ALL,
782 prop_desc.setter ? jsval_obj(prop_desc.setter) : jsval_undefined());
783 }else {
784 hres = jsdisp_propput_name(desc_obj, L"value", prop_desc.value);
785 if(SUCCEEDED(hres))
786 hres = jsdisp_define_data_property(desc_obj, L"writable", PROPF_ALL,
787 jsval_bool(!!(prop_desc.flags & PROPF_WRITABLE)));
789 if(SUCCEEDED(hres))
790 hres = jsdisp_define_data_property(desc_obj, L"enumerable", PROPF_ALL,
791 jsval_bool(!!(prop_desc.flags & PROPF_ENUMERABLE)));
792 if(SUCCEEDED(hres))
793 hres = jsdisp_define_data_property(desc_obj, L"configurable", PROPF_ALL,
794 jsval_bool(!!(prop_desc.flags & PROPF_CONFIGURABLE)));
796 release_property_descriptor(&prop_desc);
797 if(SUCCEEDED(hres) && r)
798 *r = jsval_obj(desc_obj);
799 else
800 jsdisp_release(desc_obj);
801 return hres;
804 static HRESULT Object_create(script_ctx_t *ctx, jsval_t vthis, WORD flags,
805 unsigned argc, jsval_t *argv, jsval_t *r)
807 jsdisp_t *proto = NULL, *obj;
808 HRESULT hres;
810 if(!argc || (!is_object_instance(argv[0]) && !is_null(argv[0]))) {
811 FIXME("Invalid arg\n");
812 return E_INVALIDARG;
815 TRACE("(%s)\n", debugstr_jsval(argv[0]));
817 if(argc && is_object_instance(argv[0])) {
818 if(get_object(argv[0]))
819 proto = to_jsdisp(get_object(argv[0]));
820 if(!proto) {
821 FIXME("Non-JS prototype\n");
822 return E_NOTIMPL;
824 }else if(!is_null(argv[0])) {
825 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
826 return E_INVALIDARG;
829 hres = create_dispex(ctx, &ObjectInst_info, proto, &obj);
830 if(FAILED(hres))
831 return hres;
833 if(argc >= 2 && !is_undefined(argv[1]))
834 hres = jsdisp_define_properties(ctx, obj, argv[1]);
836 if(SUCCEEDED(hres) && r)
837 *r = jsval_obj(obj);
838 else
839 jsdisp_release(obj);
840 return hres;
843 static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flags,
844 unsigned argc, jsval_t *argv, jsval_t *r)
846 jsdisp_t *obj;
848 if(!argc || !is_object_instance(argv[0]))
849 return JS_E_OBJECT_EXPECTED;
851 TRACE("(%s)\n", debugstr_jsval(argv[0]));
853 obj = to_jsdisp(get_object(argv[0]));
854 if(r)
855 *r = obj && obj->prototype
856 ? jsval_obj(jsdisp_addref(obj->prototype))
857 : jsval_null();
858 return S_OK;
861 static HRESULT object_keys(script_ctx_t *ctx, jsval_t arg, enum jsdisp_enum_type enum_type, jsval_t *r)
863 DISPID id = DISPID_STARTENUM;
864 jsdisp_t *obj, *array;
865 unsigned i = 0;
866 jsstr_t *key;
867 HRESULT hres;
869 if(!is_object_instance(arg))
870 return JS_E_OBJECT_EXPECTED;
872 obj = to_jsdisp(get_object(arg));
873 if(!obj) {
874 FIXME("Non-JS object\n");
875 return E_NOTIMPL;
878 hres = create_array(ctx, 0, &array);
879 if(FAILED(hres))
880 return hres;
882 do {
883 hres = jsdisp_next_prop(obj, id, enum_type, &id);
884 if(hres != S_OK)
885 break;
887 hres = jsdisp_get_prop_name(obj, id, &key);
888 if(FAILED(hres))
889 break;
891 hres = jsdisp_propput_idx(array, i++, jsval_string(key));
892 jsstr_release(key);
893 } while(hres == S_OK);
895 if(SUCCEEDED(hres) && r)
896 *r = jsval_obj(array);
897 else
898 jsdisp_release(array);
899 return hres;
902 static HRESULT Object_keys(script_ctx_t *ctx, jsval_t vthis, WORD flags,
903 unsigned argc, jsval_t *argv, jsval_t *r)
905 jsval_t arg = argc ? argv[0] : jsval_undefined();
907 TRACE("(%s)\n", debugstr_jsval(arg));
909 return object_keys(ctx, arg, JSDISP_ENUM_OWN_ENUMERABLE, r);
912 static HRESULT Object_getOwnPropertyNames(script_ctx_t *ctx, jsval_t vthis, WORD flags,
913 unsigned argc, jsval_t *argv, jsval_t *r)
915 jsval_t arg = argc ? argv[0] : jsval_undefined();
917 TRACE("(%s)\n", debugstr_jsval(arg));
919 return object_keys(ctx, arg, JSDISP_ENUM_OWN, r);
922 static HRESULT Object_preventExtensions(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
924 jsdisp_t *obj;
926 if(!argc || !is_object_instance(argv[0]))
927 return JS_E_OBJECT_EXPECTED;
929 TRACE("(%s)\n", debugstr_jsval(argv[0]));
931 obj = to_jsdisp(get_object(argv[0]));
932 if(!obj) {
933 FIXME("Non-JS object\n");
934 return E_NOTIMPL;
937 obj->extensible = FALSE;
938 if(r) *r = jsval_obj(jsdisp_addref(obj));
939 return S_OK;
942 static HRESULT Object_freeze(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
943 jsval_t *argv, jsval_t *r)
945 jsdisp_t *obj;
947 if(!argc || !is_object_instance(argv[0])) {
948 WARN("argument is not an object\n");
949 return JS_E_OBJECT_EXPECTED;
952 TRACE("(%s)\n", debugstr_jsval(argv[0]));
954 obj = to_jsdisp(get_object(argv[0]));
955 if(!obj) {
956 FIXME("Non-JS object\n");
957 return E_NOTIMPL;
960 jsdisp_freeze(obj, FALSE);
961 if(r) *r = jsval_obj(jsdisp_addref(obj));
962 return S_OK;
965 static HRESULT Object_seal(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
966 jsval_t *argv, jsval_t *r)
968 jsdisp_t *obj;
970 if(!argc || !is_object_instance(argv[0])) {
971 WARN("argument is not an object\n");
972 return JS_E_OBJECT_EXPECTED;
975 TRACE("(%s)\n", debugstr_jsval(argv[0]));
977 obj = to_jsdisp(get_object(argv[0]));
978 if(!obj) {
979 FIXME("Non-JS object\n");
980 return E_NOTIMPL;
983 jsdisp_freeze(obj, TRUE);
984 if(r) *r = jsval_obj(jsdisp_addref(obj));
985 return S_OK;
988 static HRESULT Object_isExtensible(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
990 jsdisp_t *obj;
992 if(!argc || !is_object_instance(argv[0])) {
993 WARN("argument is not an object\n");
994 return JS_E_OBJECT_EXPECTED;
997 TRACE("(%s)\n", debugstr_jsval(argv[0]));
999 obj = to_jsdisp(get_object(argv[0]));
1000 if(!obj) {
1001 FIXME("Non-JS object\n");
1002 return E_NOTIMPL;
1005 if(r) *r = jsval_bool(obj->extensible);
1006 return S_OK;
1009 static HRESULT Object_isFrozen(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
1010 jsval_t *argv, jsval_t *r)
1012 jsdisp_t *obj;
1014 if(!argc || !is_object_instance(argv[0])) {
1015 WARN("argument is not an object\n");
1016 return JS_E_OBJECT_EXPECTED;
1019 TRACE("(%s)\n", debugstr_jsval(argv[0]));
1021 obj = to_jsdisp(get_object(argv[0]));
1022 if(!obj) {
1023 FIXME("Non-JS object\n");
1024 return E_NOTIMPL;
1027 if(r) *r = jsval_bool(jsdisp_is_frozen(obj, FALSE));
1028 return S_OK;
1031 static HRESULT Object_isSealed(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
1032 jsval_t *argv, jsval_t *r)
1034 jsdisp_t *obj;
1036 if(!argc || !is_object_instance(argv[0])) {
1037 WARN("argument is not an object\n");
1038 return JS_E_OBJECT_EXPECTED;
1041 TRACE("(%s)\n", debugstr_jsval(argv[0]));
1043 obj = to_jsdisp(get_object(argv[0]));
1044 if(!obj) {
1045 FIXME("Non-JS object\n");
1046 return E_NOTIMPL;
1049 if(r) *r = jsval_bool(jsdisp_is_frozen(obj, TRUE));
1050 return S_OK;
1053 static const builtin_prop_t ObjectConstr_props[] = {
1054 {L"create", Object_create, PROPF_ES5|PROPF_METHOD|2},
1055 {L"defineProperties", Object_defineProperties, PROPF_ES5|PROPF_METHOD|2},
1056 {L"defineProperty", Object_defineProperty, PROPF_ES5|PROPF_METHOD|2},
1057 {L"freeze", Object_freeze, PROPF_ES5|PROPF_METHOD|1},
1058 {L"getOwnPropertyDescriptor", Object_getOwnPropertyDescriptor, PROPF_ES5|PROPF_METHOD|2},
1059 {L"getOwnPropertyNames", Object_getOwnPropertyNames, PROPF_ES5|PROPF_METHOD|1},
1060 {L"getPrototypeOf", Object_getPrototypeOf, PROPF_ES5|PROPF_METHOD|1},
1061 {L"isExtensible", Object_isExtensible, PROPF_ES5|PROPF_METHOD|1},
1062 {L"isFrozen", Object_isFrozen, PROPF_ES5|PROPF_METHOD|1},
1063 {L"isSealed", Object_isSealed, PROPF_ES5|PROPF_METHOD|1},
1064 {L"keys", Object_keys, PROPF_ES5|PROPF_METHOD|1},
1065 {L"preventExtensions", Object_preventExtensions, PROPF_ES5|PROPF_METHOD|1},
1066 {L"seal", Object_seal, PROPF_ES5|PROPF_METHOD|1},
1069 static const builtin_info_t ObjectConstr_info = {
1070 JSCLASS_FUNCTION,
1071 Function_value,
1072 ARRAY_SIZE(ObjectConstr_props),
1073 ObjectConstr_props,
1074 NULL,
1075 NULL
1078 static HRESULT ObjectConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1079 jsval_t *r)
1081 HRESULT hres;
1083 TRACE("\n");
1085 switch(flags) {
1086 case DISPATCH_METHOD:
1087 case DISPATCH_CONSTRUCT: {
1088 jsdisp_t *obj;
1090 if(argc) {
1091 if(!is_undefined(argv[0]) && !is_null(argv[0])) {
1092 IDispatch *disp;
1094 hres = to_object(ctx, argv[0], &disp);
1095 if(FAILED(hres))
1096 return hres;
1098 if(r)
1099 *r = jsval_disp(disp);
1100 else
1101 IDispatch_Release(disp);
1102 return S_OK;
1106 hres = create_object(ctx, NULL, &obj);
1107 if(FAILED(hres))
1108 return hres;
1110 if(r)
1111 *r = jsval_obj(obj);
1112 else
1113 jsdisp_release(obj);
1114 break;
1117 default:
1118 FIXME("unimplemented flags: %x\n", flags);
1119 return E_NOTIMPL;
1122 return S_OK;
1125 HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1127 return create_builtin_constructor(ctx, ObjectConstr_value, L"Object", &ObjectConstr_info, PROPF_CONSTR,
1128 object_prototype, ret);
1131 HRESULT create_object_prototype(script_ctx_t *ctx, jsdisp_t **ret)
1133 return create_dispex(ctx, &Object_info, NULL, ret);
1136 HRESULT create_object(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t **ret)
1138 jsdisp_t *object;
1139 HRESULT hres;
1141 object = calloc(1, sizeof(jsdisp_t));
1142 if(!object)
1143 return E_OUTOFMEMORY;
1145 hres = init_dispex_from_constr(object, ctx, &ObjectInst_info, constr ? constr : ctx->object_constr);
1146 if(FAILED(hres)) {
1147 free(object);
1148 return hres;
1151 *ret = object;
1152 return S_OK;