windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / jscript / object.c
blob16ecc3dea3cce2a73b0052fee06cdbad5bd08f67
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 ArrayBuffer]",
54 L"[object Object]",
55 L"[object Object]",
56 L"[object Object]",
57 L"[object Object]"
60 TRACE("\n");
62 if(is_undefined(vthis) || is_null(vthis)) {
63 if(ctx->version < SCRIPTLANGUAGEVERSION_ES5)
64 str = L"[object Object]";
65 else
66 str = is_null(vthis) ? L"[object Null]" : L"[object Undefined]";
67 goto set_output;
70 hres = to_object(ctx, vthis, &disp);
71 if(FAILED(hres))
72 return hres;
74 jsdisp = to_jsdisp(disp);
75 if(!jsdisp) {
76 str = L"[object Object]";
77 }else if(names[jsdisp->builtin_info->class]) {
78 str = names[jsdisp->builtin_info->class];
79 }else {
80 assert(jsdisp->builtin_info->class != JSCLASS_NONE);
81 FIXME("jsdisp->builtin_info->class = %d\n", jsdisp->builtin_info->class);
82 hres = E_FAIL;
84 IDispatch_Release(disp);
85 if(FAILED(hres))
86 return hres;
88 set_output:
89 if(r) {
90 jsstr_t *ret;
91 ret = jsstr_alloc(str);
92 if(!ret)
93 return E_OUTOFMEMORY;
94 *r = jsval_string(ret);
97 return S_OK;
100 static HRESULT Object_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
101 jsval_t *r)
103 jsdisp_t *jsdisp;
104 IDispatch *disp;
105 HRESULT hres;
107 TRACE("\n");
109 hres = to_object(ctx, vthis, &disp);
110 if(FAILED(hres))
111 return hres;
113 if(!(jsdisp = to_jsdisp(disp))) {
114 FIXME("Host object this\n");
115 hres = E_FAIL;
116 goto done;
119 hres = jsdisp_call_name(jsdisp, L"toString", DISPATCH_METHOD, 0, NULL, r);
120 done:
121 IDispatch_Release(disp);
122 return hres;
125 static HRESULT Object_valueOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
126 jsval_t *r)
128 IDispatch *disp;
129 HRESULT hres;
131 TRACE("\n");
133 if(is_null_disp(vthis)) {
134 if(r) *r = jsval_null_disp();
135 return S_OK;
138 hres = to_object(ctx, vthis, &disp);
139 if(FAILED(hres))
140 return hres;
142 if(r)
143 *r = jsval_disp(disp);
144 else
145 IDispatch_Release(disp);
146 return S_OK;
149 static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
150 jsval_t *r)
152 IDispatchEx *dispex;
153 jsdisp_t *jsdisp;
154 IDispatch *disp;
155 jsstr_t *name;
156 DISPID id;
157 BSTR bstr;
158 HRESULT hres;
160 TRACE("\n");
162 hres = to_object(ctx, vthis, &disp);
163 if(FAILED(hres))
164 return hres;
166 if(!argc) {
167 if(r)
168 *r = jsval_bool(FALSE);
169 goto done;
172 hres = to_string(ctx, argv[0], &name);
173 if(FAILED(hres))
174 goto done;
176 if((jsdisp = to_jsdisp(disp))) {
177 property_desc_t prop_desc;
178 const WCHAR *name_str;
180 name_str = jsstr_flatten(name);
181 if(!name_str) {
182 jsstr_release(name);
183 hres = E_OUTOFMEMORY;
184 goto done;
187 hres = jsdisp_get_own_property(jsdisp, name_str, TRUE, &prop_desc);
188 jsstr_release(name);
189 if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
190 goto done;
192 if(r) *r = jsval_bool(hres == S_OK);
193 hres = S_OK;
194 goto done;
198 bstr = SysAllocStringLen(NULL, jsstr_length(name));
199 if(bstr)
200 jsstr_flush(name, bstr);
201 jsstr_release(name);
202 if(!bstr) {
203 hres = E_OUTOFMEMORY;
204 goto done;
207 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
208 if(SUCCEEDED(hres)) {
209 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive), &id);
210 IDispatchEx_Release(dispex);
211 }else {
212 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, ctx->lcid, &id);
214 SysFreeString(bstr);
215 if(r)
216 *r = jsval_bool(SUCCEEDED(hres));
217 hres = S_OK;
218 done:
219 IDispatch_Release(disp);
220 return hres;
223 static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
224 jsval_t *r)
226 property_desc_t prop_desc;
227 const WCHAR *name;
228 jsstr_t *name_str;
229 jsdisp_t *jsdisp;
230 IDispatch *disp;
231 HRESULT hres;
233 TRACE("\n");
235 hres = to_object(ctx, vthis, &disp);
236 if(FAILED(hres))
237 return hres;
239 if(argc != 1) {
240 FIXME("argc %d not supported\n", argc);
241 hres = E_NOTIMPL;
242 goto done;
245 if(!(jsdisp = to_jsdisp(disp))) {
246 FIXME("Host object this\n");
247 hres = E_FAIL;
248 goto done;
251 hres = to_flat_string(ctx, argv[0], &name_str, &name);
252 if(FAILED(hres))
253 goto done;
255 hres = jsdisp_get_own_property(jsdisp, name, TRUE, &prop_desc);
256 jsstr_release(name_str);
257 if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
258 goto done;
260 if(r)
261 *r = jsval_bool(hres == S_OK && (prop_desc.flags & PROPF_ENUMERABLE) != 0);
262 hres = S_OK;
263 done:
264 IDispatch_Release(disp);
265 return hres;
268 static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
269 jsval_t *r)
271 jsdisp_t *jsthis, *jsdisp;
272 IDispatch *disp;
273 BOOL ret = FALSE;
274 HRESULT hres;
276 hres = to_object(ctx, vthis, &disp);
277 if(FAILED(hres))
278 return hres;
280 if(!r)
281 goto done;
283 if(argc && (jsthis = to_jsdisp(disp)) && is_object_instance(argv[0]) &&
284 (jsdisp = to_jsdisp(get_object(argv[0])))) {
285 while(jsdisp->prototype) {
286 if(jsdisp->prototype == jsthis) {
287 ret = TRUE;
288 break;
290 jsdisp = jsdisp->prototype;
294 *r = jsval_bool(ret);
295 done:
296 IDispatch_Release(disp);
297 return hres;
300 static HRESULT Object_defineGetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
302 property_desc_t desc;
303 const WCHAR *name;
304 jsstr_t *name_str;
305 jsdisp_t *jsthis;
306 HRESULT hres;
308 TRACE("\n");
310 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
311 goto done;
313 if(argc < 2 || !is_object_instance(argv[1]))
314 return JS_E_FUNCTION_EXPECTED;
316 desc.getter = to_jsdisp(get_object(argv[1]));
317 if(!desc.getter) {
318 FIXME("getter is not JS object\n");
319 return E_NOTIMPL;
321 /* FIXME: Check IsCallable */
323 hres = to_flat_string(ctx, argv[0], &name_str, &name);
324 if(FAILED(hres))
325 return hres;
327 desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
328 desc.explicit_getter = TRUE;
329 desc.explicit_setter = FALSE;
330 desc.explicit_value = FALSE;
331 desc.setter = NULL;
332 hres = jsdisp_define_property(jsthis, name, &desc);
334 jsstr_release(name_str);
335 if(FAILED(hres))
336 return hres;
337 done:
338 if(r)
339 *r = jsval_undefined();
340 return S_OK;
343 static HRESULT Object_defineSetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
345 property_desc_t desc;
346 const WCHAR *name;
347 jsstr_t *name_str;
348 jsdisp_t *jsthis;
349 HRESULT hres;
351 TRACE("\n");
353 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
354 goto done;
356 if(argc < 2 || !is_object_instance(argv[1]))
357 return JS_E_FUNCTION_EXPECTED;
359 desc.setter = to_jsdisp(get_object(argv[1]));
360 if(!desc.setter) {
361 FIXME("setter is not JS object\n");
362 return E_NOTIMPL;
364 /* FIXME: Check IsCallable */
366 hres = to_flat_string(ctx, argv[0], &name_str, &name);
367 if(FAILED(hres))
368 return hres;
370 desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
371 desc.explicit_getter = FALSE;
372 desc.explicit_setter = TRUE;
373 desc.explicit_value = FALSE;
374 desc.getter = NULL;
375 hres = jsdisp_define_property(jsthis, name, &desc);
377 jsstr_release(name_str);
378 if(FAILED(hres))
379 return hres;
380 done:
381 if(r)
382 *r = jsval_undefined();
383 return S_OK;
386 HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
388 jsdisp_t *jsthis;
389 IDispatch *disp;
390 HRESULT hres;
392 TRACE("%s\n", debugstr_jsval(vthis));
394 hres = to_object(ctx, vthis, &disp);
395 if(FAILED(hres))
396 return hres;
398 if(!r)
399 goto done;
401 if(!(jsthis = to_jsdisp(disp))) {
402 FIXME("Host object this\n");
403 hres = E_FAIL;
404 goto done;
407 *r = jsthis->prototype
408 ? jsval_obj(jsdisp_addref(jsthis->prototype))
409 : jsval_null();
410 done:
411 IDispatch_Release(disp);
412 return hres;
415 HRESULT Object_set_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
417 jsdisp_t *jsthis, *proto;
418 HRESULT hres;
420 TRACE("%s\n", debugstr_jsval(vthis));
422 if(is_undefined(vthis) || is_null(vthis))
423 return JS_E_OBJECT_EXPECTED;
424 if(!argc) {
425 if(r)
426 *r = jsval_undefined();
427 return S_OK;
429 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
430 goto done;
432 if(is_null(argv[0])) {
433 proto = NULL;
434 }else if(is_object_instance(argv[0])) {
435 proto = to_jsdisp(get_object(argv[0]));
436 if(!proto) {
437 FIXME("Host object value\n");
438 return E_FAIL;
440 }else
441 goto done;
443 hres = jsdisp_change_prototype(jsthis, proto);
444 if(FAILED(hres))
445 return hres;
447 done:
448 return r ? jsval_copy(argv[0], r) : S_OK;
451 static void Object_destructor(jsdisp_t *dispex)
453 free(dispex);
456 static const builtin_prop_t Object_props[] = {
457 {L"__defineGetter__", Object_defineGetter, PROPF_METHOD|PROPF_ES6|2},
458 {L"__defineSetter__", Object_defineSetter, PROPF_METHOD|PROPF_ES6|2},
459 {L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1},
460 {L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1},
461 {L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1},
462 {L"toLocaleString", Object_toLocaleString, PROPF_METHOD},
463 {L"toString", Object_toString, PROPF_METHOD},
464 {L"valueOf", Object_valueOf, PROPF_METHOD}
467 static const builtin_info_t Object_info = {
468 JSCLASS_OBJECT,
469 NULL,
470 ARRAY_SIZE(Object_props),
471 Object_props,
472 Object_destructor,
473 NULL
476 static const builtin_info_t ObjectInst_info = {
477 JSCLASS_OBJECT,
478 NULL,
479 0, NULL,
480 Object_destructor,
481 NULL
484 static void release_property_descriptor(property_desc_t *desc)
486 if(desc->explicit_value)
487 jsval_release(desc->value);
488 if(desc->getter)
489 jsdisp_release(desc->getter);
490 if(desc->setter)
491 jsdisp_release(desc->setter);
494 static HRESULT to_property_descriptor(script_ctx_t *ctx, jsdisp_t *attr_obj, property_desc_t *desc)
496 DISPID id;
497 jsval_t v;
498 BOOL b;
499 HRESULT hres;
501 memset(desc, 0, sizeof(*desc));
502 desc->value = jsval_undefined();
504 hres = jsdisp_get_id(attr_obj, L"enumerable", 0, &id);
505 if(SUCCEEDED(hres)) {
506 desc->mask |= PROPF_ENUMERABLE;
507 hres = jsdisp_propget(attr_obj, id, &v);
508 if(FAILED(hres))
509 return hres;
510 hres = to_boolean(v, &b);
511 jsval_release(v);
512 if(FAILED(hres))
513 return hres;
514 if(b)
515 desc->flags |= PROPF_ENUMERABLE;
516 }else if(hres != DISP_E_UNKNOWNNAME) {
517 return hres;
520 hres = jsdisp_get_id(attr_obj, L"configurable", 0, &id);
521 if(SUCCEEDED(hres)) {
522 desc->mask |= PROPF_CONFIGURABLE;
523 hres = jsdisp_propget(attr_obj, id, &v);
524 if(FAILED(hres))
525 return hres;
526 hres = to_boolean(v, &b);
527 jsval_release(v);
528 if(FAILED(hres))
529 return hres;
530 if(b)
531 desc->flags |= PROPF_CONFIGURABLE;
532 }else if(hres != DISP_E_UNKNOWNNAME) {
533 return hres;
536 hres = jsdisp_get_id(attr_obj, L"value", 0, &id);
537 if(SUCCEEDED(hres)) {
538 hres = jsdisp_propget(attr_obj, id, &desc->value);
539 if(FAILED(hres))
540 return hres;
541 desc->explicit_value = TRUE;
542 }else if(hres != DISP_E_UNKNOWNNAME) {
543 return hres;
546 hres = jsdisp_get_id(attr_obj, L"writable", 0, &id);
547 if(SUCCEEDED(hres)) {
548 desc->mask |= PROPF_WRITABLE;
549 hres = jsdisp_propget(attr_obj, id, &v);
550 if(SUCCEEDED(hres)) {
551 hres = to_boolean(v, &b);
552 jsval_release(v);
553 if(SUCCEEDED(hres) && b)
554 desc->flags |= PROPF_WRITABLE;
556 }else if(hres == DISP_E_UNKNOWNNAME) {
557 hres = S_OK;
559 if(FAILED(hres)) {
560 release_property_descriptor(desc);
561 return hres;
564 hres = jsdisp_get_id(attr_obj, L"get", 0, &id);
565 if(SUCCEEDED(hres)) {
566 desc->explicit_getter = TRUE;
567 hres = jsdisp_propget(attr_obj, id, &v);
568 if(SUCCEEDED(hres) && !is_undefined(v)) {
569 if(!is_object_instance(v)) {
570 FIXME("getter is not an object\n");
571 jsval_release(v);
572 hres = E_FAIL;
573 }else {
574 /* FIXME: Check IsCallable */
575 desc->getter = to_jsdisp(get_object(v));
576 if(!desc->getter)
577 FIXME("getter is not JS object\n");
580 }else if(hres == DISP_E_UNKNOWNNAME) {
581 hres = S_OK;
583 if(FAILED(hres)) {
584 release_property_descriptor(desc);
585 return hres;
588 hres = jsdisp_get_id(attr_obj, L"set", 0, &id);
589 if(SUCCEEDED(hres)) {
590 desc->explicit_setter = TRUE;
591 hres = jsdisp_propget(attr_obj, id, &v);
592 if(SUCCEEDED(hres) && !is_undefined(v)) {
593 if(!is_object_instance(v)) {
594 FIXME("setter is not an object\n");
595 jsval_release(v);
596 hres = E_FAIL;
597 }else {
598 /* FIXME: Check IsCallable */
599 desc->setter = to_jsdisp(get_object(v));
600 if(!desc->setter)
601 FIXME("setter is not JS object\n");
604 }else if(hres == DISP_E_UNKNOWNNAME) {
605 hres = S_OK;
607 if(FAILED(hres)) {
608 release_property_descriptor(desc);
609 return hres;
612 if(desc->explicit_getter || desc->explicit_setter) {
613 if(desc->explicit_value)
614 hres = JS_E_PROP_DESC_MISMATCH;
615 else if(desc->mask & PROPF_WRITABLE)
616 hres = JS_E_INVALID_WRITABLE_PROP_DESC;
619 if(FAILED(hres))
620 release_property_descriptor(desc);
621 return hres;
624 static HRESULT jsdisp_define_properties(script_ctx_t *ctx, jsdisp_t *obj, jsval_t list_val)
626 DISPID id = DISPID_STARTENUM;
627 property_desc_t prop_desc;
628 IDispatch *list_disp;
629 jsdisp_t *list_obj, *desc_obj;
630 jsval_t desc_val;
631 BSTR name;
632 HRESULT hres;
634 hres = to_object(ctx, list_val, &list_disp);
635 if(FAILED(hres))
636 return hres;
638 if(!(list_obj = to_jsdisp(list_disp))) {
639 FIXME("non-JS list obj\n");
640 IDispatch_Release(list_disp);
641 return E_NOTIMPL;
644 while(1) {
645 hres = jsdisp_next_prop(list_obj, id, JSDISP_ENUM_OWN_ENUMERABLE, &id);
646 if(hres != S_OK)
647 break;
649 hres = jsdisp_propget(list_obj, id, &desc_val);
650 if(FAILED(hres))
651 break;
653 if(!is_object_instance(desc_val) || !(desc_obj = to_jsdisp(get_object(desc_val)))) {
654 jsval_release(desc_val);
655 break;
658 hres = to_property_descriptor(ctx, desc_obj, &prop_desc);
659 jsdisp_release(desc_obj);
660 if(FAILED(hres))
661 break;
663 hres = IDispatchEx_GetMemberName(&list_obj->IDispatchEx_iface, id, &name);
664 if(SUCCEEDED(hres))
665 hres = jsdisp_define_property(obj, name, &prop_desc);
666 release_property_descriptor(&prop_desc);
667 if(FAILED(hres))
668 break;
671 jsdisp_release(list_obj);
672 return FAILED(hres) ? hres : S_OK;
675 static HRESULT Object_defineProperty(script_ctx_t *ctx, jsval_t vthis, WORD flags,
676 unsigned argc, jsval_t *argv, jsval_t *r)
678 property_desc_t prop_desc;
679 jsdisp_t *obj, *attr_obj;
680 const WCHAR *name;
681 jsstr_t *name_str;
682 HRESULT hres;
684 TRACE("\n");
686 if(argc < 1 || !is_object_instance(argv[0]))
687 return JS_E_OBJECT_EXPECTED;
688 obj = to_jsdisp(get_object(argv[0]));
689 if(!obj) {
690 FIXME("not implemented non-JS object\n");
691 return E_NOTIMPL;
694 hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
695 if(FAILED(hres))
696 return hres;
698 if(argc >= 3 && is_object_instance(argv[2])) {
699 attr_obj = to_jsdisp(get_object(argv[2]));
700 if(attr_obj) {
701 hres = to_property_descriptor(ctx, attr_obj, &prop_desc);
702 }else {
703 FIXME("not implemented non-JS object\n");
704 hres = E_NOTIMPL;
706 }else {
707 hres = JS_E_OBJECT_EXPECTED;
710 if(FAILED(hres))
712 jsstr_release(name_str);
713 return hres;
716 hres = jsdisp_define_property(obj, name, &prop_desc);
717 jsstr_release(name_str);
718 release_property_descriptor(&prop_desc);
719 if(SUCCEEDED(hres) && r)
720 *r = jsval_obj(jsdisp_addref(obj));
721 return hres;
724 static HRESULT Object_defineProperties(script_ctx_t *ctx, jsval_t vthis, WORD flags,
725 unsigned argc, jsval_t *argv, jsval_t *r)
727 jsdisp_t *obj;
728 HRESULT hres;
730 if(argc < 1 || !is_object_instance(argv[0]) || !(obj = to_jsdisp(get_object(argv[0])))) {
731 FIXME("not an object\n");
732 return E_NOTIMPL;
735 TRACE("%p\n", obj);
737 hres = jsdisp_define_properties(ctx, obj, argc >= 2 ? argv[1] : jsval_undefined());
738 if(SUCCEEDED(hres) && r)
739 *r = jsval_obj(jsdisp_addref(obj));
740 return hres;
743 static HRESULT Object_getOwnPropertyDescriptor(script_ctx_t *ctx, jsval_t vthis, WORD flags,
744 unsigned argc, jsval_t *argv, jsval_t *r)
746 property_desc_t prop_desc;
747 jsdisp_t *obj, *desc_obj;
748 const WCHAR *name;
749 jsstr_t *name_str;
750 HRESULT hres;
752 TRACE("\n");
754 if(argc < 1 || !is_object_instance(argv[0]))
755 return JS_E_OBJECT_EXPECTED;
756 obj = to_jsdisp(get_object(argv[0]));
757 if(!obj) {
758 FIXME("not implemented non-JS object\n");
759 return E_NOTIMPL;
762 hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
763 if(FAILED(hres))
764 return hres;
766 hres = jsdisp_get_own_property(obj, name, FALSE, &prop_desc);
767 jsstr_release(name_str);
768 if(hres == DISP_E_UNKNOWNNAME) {
769 if(r) *r = jsval_undefined();
770 return S_OK;
772 if(FAILED(hres))
773 return hres;
775 hres = create_object(ctx, NULL, &desc_obj);
776 if(FAILED(hres))
777 return hres;
779 if(prop_desc.explicit_getter || prop_desc.explicit_setter) {
780 hres = jsdisp_define_data_property(desc_obj, L"get", PROPF_ALL,
781 prop_desc.getter ? jsval_obj(prop_desc.getter) : jsval_undefined());
782 if(SUCCEEDED(hres))
783 hres = jsdisp_define_data_property(desc_obj, L"set", PROPF_ALL,
784 prop_desc.setter ? jsval_obj(prop_desc.setter) : jsval_undefined());
785 }else {
786 hres = jsdisp_propput_name(desc_obj, L"value", prop_desc.value);
787 if(SUCCEEDED(hres))
788 hres = jsdisp_define_data_property(desc_obj, L"writable", PROPF_ALL,
789 jsval_bool(!!(prop_desc.flags & PROPF_WRITABLE)));
791 if(SUCCEEDED(hres))
792 hres = jsdisp_define_data_property(desc_obj, L"enumerable", PROPF_ALL,
793 jsval_bool(!!(prop_desc.flags & PROPF_ENUMERABLE)));
794 if(SUCCEEDED(hres))
795 hres = jsdisp_define_data_property(desc_obj, L"configurable", PROPF_ALL,
796 jsval_bool(!!(prop_desc.flags & PROPF_CONFIGURABLE)));
798 release_property_descriptor(&prop_desc);
799 if(SUCCEEDED(hres) && r)
800 *r = jsval_obj(desc_obj);
801 else
802 jsdisp_release(desc_obj);
803 return hres;
806 static HRESULT Object_create(script_ctx_t *ctx, jsval_t vthis, WORD flags,
807 unsigned argc, jsval_t *argv, jsval_t *r)
809 jsdisp_t *proto = NULL, *obj;
810 HRESULT hres;
812 if(!argc || (!is_object_instance(argv[0]) && !is_null(argv[0]))) {
813 FIXME("Invalid arg\n");
814 return E_INVALIDARG;
817 TRACE("(%s)\n", debugstr_jsval(argv[0]));
819 if(argc && is_object_instance(argv[0])) {
820 if(get_object(argv[0]))
821 proto = to_jsdisp(get_object(argv[0]));
822 if(!proto) {
823 FIXME("Non-JS prototype\n");
824 return E_NOTIMPL;
826 }else if(!is_null(argv[0])) {
827 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
828 return E_INVALIDARG;
831 hres = create_dispex(ctx, &ObjectInst_info, proto, &obj);
832 if(FAILED(hres))
833 return hres;
835 if(argc >= 2 && !is_undefined(argv[1]))
836 hres = jsdisp_define_properties(ctx, obj, argv[1]);
838 if(SUCCEEDED(hres) && r)
839 *r = jsval_obj(obj);
840 else
841 jsdisp_release(obj);
842 return hres;
845 static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flags,
846 unsigned argc, jsval_t *argv, jsval_t *r)
848 jsdisp_t *obj;
850 if(!argc || !is_object_instance(argv[0]))
851 return JS_E_OBJECT_EXPECTED;
853 TRACE("(%s)\n", debugstr_jsval(argv[0]));
855 obj = to_jsdisp(get_object(argv[0]));
856 if(r)
857 *r = obj && obj->prototype
858 ? jsval_obj(jsdisp_addref(obj->prototype))
859 : jsval_null();
860 return S_OK;
863 static HRESULT object_keys(script_ctx_t *ctx, jsval_t arg, enum jsdisp_enum_type enum_type, jsval_t *r)
865 DISPID id = DISPID_STARTENUM;
866 jsdisp_t *obj, *array;
867 unsigned i = 0;
868 jsstr_t *key;
869 HRESULT hres;
871 if(!is_object_instance(arg))
872 return JS_E_OBJECT_EXPECTED;
874 obj = to_jsdisp(get_object(arg));
875 if(!obj) {
876 FIXME("Non-JS object\n");
877 return E_NOTIMPL;
880 hres = create_array(ctx, 0, &array);
881 if(FAILED(hres))
882 return hres;
884 do {
885 hres = jsdisp_next_prop(obj, id, enum_type, &id);
886 if(hres != S_OK)
887 break;
889 hres = jsdisp_get_prop_name(obj, id, &key);
890 if(FAILED(hres))
891 break;
893 hres = jsdisp_propput_idx(array, i++, jsval_string(key));
894 jsstr_release(key);
895 } while(hres == S_OK);
897 if(SUCCEEDED(hres) && r)
898 *r = jsval_obj(array);
899 else
900 jsdisp_release(array);
901 return hres;
904 static HRESULT Object_keys(script_ctx_t *ctx, jsval_t vthis, WORD flags,
905 unsigned argc, jsval_t *argv, jsval_t *r)
907 jsval_t arg = argc ? argv[0] : jsval_undefined();
909 TRACE("(%s)\n", debugstr_jsval(arg));
911 return object_keys(ctx, arg, JSDISP_ENUM_OWN_ENUMERABLE, r);
914 static HRESULT Object_getOwnPropertyNames(script_ctx_t *ctx, jsval_t vthis, WORD flags,
915 unsigned argc, jsval_t *argv, jsval_t *r)
917 jsval_t arg = argc ? argv[0] : jsval_undefined();
919 TRACE("(%s)\n", debugstr_jsval(arg));
921 return object_keys(ctx, arg, JSDISP_ENUM_OWN, r);
924 static HRESULT Object_preventExtensions(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
926 jsdisp_t *obj;
928 if(!argc || !is_object_instance(argv[0]))
929 return JS_E_OBJECT_EXPECTED;
931 TRACE("(%s)\n", debugstr_jsval(argv[0]));
933 obj = to_jsdisp(get_object(argv[0]));
934 if(!obj) {
935 FIXME("Non-JS object\n");
936 return E_NOTIMPL;
939 obj->extensible = FALSE;
940 if(r) *r = jsval_obj(jsdisp_addref(obj));
941 return S_OK;
944 static HRESULT Object_freeze(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
945 jsval_t *argv, jsval_t *r)
947 jsdisp_t *obj;
949 if(!argc || !is_object_instance(argv[0])) {
950 WARN("argument is not an object\n");
951 return JS_E_OBJECT_EXPECTED;
954 TRACE("(%s)\n", debugstr_jsval(argv[0]));
956 obj = to_jsdisp(get_object(argv[0]));
957 if(!obj) {
958 FIXME("Non-JS object\n");
959 return E_NOTIMPL;
962 jsdisp_freeze(obj, FALSE);
963 if(r) *r = jsval_obj(jsdisp_addref(obj));
964 return S_OK;
967 static HRESULT Object_seal(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
968 jsval_t *argv, jsval_t *r)
970 jsdisp_t *obj;
972 if(!argc || !is_object_instance(argv[0])) {
973 WARN("argument is not an object\n");
974 return JS_E_OBJECT_EXPECTED;
977 TRACE("(%s)\n", debugstr_jsval(argv[0]));
979 obj = to_jsdisp(get_object(argv[0]));
980 if(!obj) {
981 FIXME("Non-JS object\n");
982 return E_NOTIMPL;
985 jsdisp_freeze(obj, TRUE);
986 if(r) *r = jsval_obj(jsdisp_addref(obj));
987 return S_OK;
990 static HRESULT Object_isExtensible(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
992 jsdisp_t *obj;
994 if(!argc || !is_object_instance(argv[0])) {
995 WARN("argument is not an object\n");
996 return JS_E_OBJECT_EXPECTED;
999 TRACE("(%s)\n", debugstr_jsval(argv[0]));
1001 obj = to_jsdisp(get_object(argv[0]));
1002 if(!obj) {
1003 FIXME("Non-JS object\n");
1004 return E_NOTIMPL;
1007 if(r) *r = jsval_bool(obj->extensible);
1008 return S_OK;
1011 static HRESULT Object_isFrozen(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
1012 jsval_t *argv, jsval_t *r)
1014 jsdisp_t *obj;
1016 if(!argc || !is_object_instance(argv[0])) {
1017 WARN("argument is not an object\n");
1018 return JS_E_OBJECT_EXPECTED;
1021 TRACE("(%s)\n", debugstr_jsval(argv[0]));
1023 obj = to_jsdisp(get_object(argv[0]));
1024 if(!obj) {
1025 FIXME("Non-JS object\n");
1026 return E_NOTIMPL;
1029 if(r) *r = jsval_bool(jsdisp_is_frozen(obj, FALSE));
1030 return S_OK;
1033 static HRESULT Object_isSealed(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
1034 jsval_t *argv, jsval_t *r)
1036 jsdisp_t *obj;
1038 if(!argc || !is_object_instance(argv[0])) {
1039 WARN("argument is not an object\n");
1040 return JS_E_OBJECT_EXPECTED;
1043 TRACE("(%s)\n", debugstr_jsval(argv[0]));
1045 obj = to_jsdisp(get_object(argv[0]));
1046 if(!obj) {
1047 FIXME("Non-JS object\n");
1048 return E_NOTIMPL;
1051 if(r) *r = jsval_bool(jsdisp_is_frozen(obj, TRUE));
1052 return S_OK;
1055 static const builtin_prop_t ObjectConstr_props[] = {
1056 {L"create", Object_create, PROPF_ES5|PROPF_METHOD|2},
1057 {L"defineProperties", Object_defineProperties, PROPF_ES5|PROPF_METHOD|2},
1058 {L"defineProperty", Object_defineProperty, PROPF_ES5|PROPF_METHOD|2},
1059 {L"freeze", Object_freeze, PROPF_ES5|PROPF_METHOD|1},
1060 {L"getOwnPropertyDescriptor", Object_getOwnPropertyDescriptor, PROPF_ES5|PROPF_METHOD|2},
1061 {L"getOwnPropertyNames", Object_getOwnPropertyNames, PROPF_ES5|PROPF_METHOD|1},
1062 {L"getPrototypeOf", Object_getPrototypeOf, PROPF_ES5|PROPF_METHOD|1},
1063 {L"isExtensible", Object_isExtensible, PROPF_ES5|PROPF_METHOD|1},
1064 {L"isFrozen", Object_isFrozen, PROPF_ES5|PROPF_METHOD|1},
1065 {L"isSealed", Object_isSealed, PROPF_ES5|PROPF_METHOD|1},
1066 {L"keys", Object_keys, PROPF_ES5|PROPF_METHOD|1},
1067 {L"preventExtensions", Object_preventExtensions, PROPF_ES5|PROPF_METHOD|1},
1068 {L"seal", Object_seal, PROPF_ES5|PROPF_METHOD|1},
1071 static const builtin_info_t ObjectConstr_info = {
1072 JSCLASS_FUNCTION,
1073 Function_value,
1074 ARRAY_SIZE(ObjectConstr_props),
1075 ObjectConstr_props,
1076 NULL,
1077 NULL
1080 static HRESULT ObjectConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1081 jsval_t *r)
1083 HRESULT hres;
1085 TRACE("\n");
1087 switch(flags) {
1088 case DISPATCH_METHOD:
1089 case DISPATCH_CONSTRUCT: {
1090 jsdisp_t *obj;
1092 if(argc) {
1093 if(!is_undefined(argv[0]) && !is_null(argv[0])) {
1094 IDispatch *disp;
1096 hres = to_object(ctx, argv[0], &disp);
1097 if(FAILED(hres))
1098 return hres;
1100 if(r)
1101 *r = jsval_disp(disp);
1102 else
1103 IDispatch_Release(disp);
1104 return S_OK;
1108 hres = create_object(ctx, NULL, &obj);
1109 if(FAILED(hres))
1110 return hres;
1112 if(r)
1113 *r = jsval_obj(obj);
1114 else
1115 jsdisp_release(obj);
1116 break;
1119 default:
1120 FIXME("unimplemented flags: %x\n", flags);
1121 return E_NOTIMPL;
1124 return S_OK;
1127 HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1129 return create_builtin_constructor(ctx, ObjectConstr_value, L"Object", &ObjectConstr_info, PROPF_CONSTR,
1130 object_prototype, ret);
1133 HRESULT create_object_prototype(script_ctx_t *ctx, jsdisp_t **ret)
1135 return create_dispex(ctx, &Object_info, NULL, ret);
1138 HRESULT create_object(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t **ret)
1140 jsdisp_t *object;
1141 HRESULT hres;
1143 object = calloc(1, sizeof(jsdisp_t));
1144 if(!object)
1145 return E_OUTOFMEMORY;
1147 hres = init_dispex_from_constr(object, ctx, &ObjectInst_info, constr ? constr : ctx->object_constr);
1148 if(FAILED(hres)) {
1149 free(object);
1150 return hres;
1153 *ret = object;
1154 return S_OK;