ntdll: Rename local variables in heap_reallocate.
[wine.git] / dlls / jscript / object.c
bloba675e45c4a07afb76f0076654e1573d13723e58e
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]"
57 TRACE("\n");
59 if(is_undefined(vthis) || is_null(vthis)) {
60 if(ctx->version < SCRIPTLANGUAGEVERSION_ES5)
61 str = L"[object Object]";
62 else
63 str = is_null(vthis) ? L"[object Null]" : L"[object Undefined]";
64 goto set_output;
67 hres = to_object(ctx, vthis, &disp);
68 if(FAILED(hres))
69 return hres;
71 jsdisp = to_jsdisp(disp);
72 if(!jsdisp) {
73 str = L"[object Object]";
74 }else if(names[jsdisp->builtin_info->class]) {
75 str = names[jsdisp->builtin_info->class];
76 }else {
77 assert(jsdisp->builtin_info->class != JSCLASS_NONE);
78 FIXME("jsdisp->builtin_info->class = %d\n", jsdisp->builtin_info->class);
79 hres = E_FAIL;
81 IDispatch_Release(disp);
82 if(FAILED(hres))
83 return hres;
85 set_output:
86 if(r) {
87 jsstr_t *ret;
88 ret = jsstr_alloc(str);
89 if(!ret)
90 return E_OUTOFMEMORY;
91 *r = jsval_string(ret);
94 return S_OK;
97 static HRESULT Object_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
98 jsval_t *r)
100 jsdisp_t *jsdisp;
101 IDispatch *disp;
102 HRESULT hres;
104 TRACE("\n");
106 hres = to_object(ctx, vthis, &disp);
107 if(FAILED(hres))
108 return hres;
110 if(!(jsdisp = to_jsdisp(disp))) {
111 FIXME("Host object this\n");
112 hres = E_FAIL;
113 goto done;
116 hres = jsdisp_call_name(jsdisp, L"toString", DISPATCH_METHOD, 0, NULL, r);
117 done:
118 IDispatch_Release(disp);
119 return hres;
122 static HRESULT Object_valueOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
123 jsval_t *r)
125 IDispatch *disp;
126 HRESULT hres;
128 TRACE("\n");
130 if(is_null_disp(vthis)) {
131 if(r) *r = jsval_null_disp();
132 return S_OK;
135 hres = to_object(ctx, vthis, &disp);
136 if(FAILED(hres))
137 return hres;
139 if(r)
140 *r = jsval_disp(disp);
141 else
142 IDispatch_Release(disp);
143 return S_OK;
146 static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
147 jsval_t *r)
149 IDispatchEx *dispex;
150 jsdisp_t *jsdisp;
151 IDispatch *disp;
152 jsstr_t *name;
153 DISPID id;
154 BSTR bstr;
155 HRESULT hres;
157 TRACE("\n");
159 hres = to_object(ctx, vthis, &disp);
160 if(FAILED(hres))
161 return hres;
163 if(!argc) {
164 if(r)
165 *r = jsval_bool(FALSE);
166 goto done;
169 hres = to_string(ctx, argv[0], &name);
170 if(FAILED(hres))
171 goto done;
173 if((jsdisp = to_jsdisp(disp))) {
174 property_desc_t prop_desc;
175 const WCHAR *name_str;
177 name_str = jsstr_flatten(name);
178 if(!name_str) {
179 jsstr_release(name);
180 hres = E_OUTOFMEMORY;
181 goto done;
184 hres = jsdisp_get_own_property(jsdisp, name_str, TRUE, &prop_desc);
185 jsstr_release(name);
186 if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
187 goto done;
189 if(r) *r = jsval_bool(hres == S_OK);
190 hres = S_OK;
191 goto done;
195 bstr = SysAllocStringLen(NULL, jsstr_length(name));
196 if(bstr)
197 jsstr_flush(name, bstr);
198 jsstr_release(name);
199 if(!bstr) {
200 hres = E_OUTOFMEMORY;
201 goto done;
204 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
205 if(SUCCEEDED(hres)) {
206 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive), &id);
207 IDispatchEx_Release(dispex);
208 }else {
209 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, ctx->lcid, &id);
211 SysFreeString(bstr);
212 if(r)
213 *r = jsval_bool(SUCCEEDED(hres));
214 hres = S_OK;
215 done:
216 IDispatch_Release(disp);
217 return hres;
220 static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
221 jsval_t *r)
223 property_desc_t prop_desc;
224 const WCHAR *name;
225 jsstr_t *name_str;
226 jsdisp_t *jsdisp;
227 IDispatch *disp;
228 HRESULT hres;
230 TRACE("\n");
232 hres = to_object(ctx, vthis, &disp);
233 if(FAILED(hres))
234 return hres;
236 if(argc != 1) {
237 FIXME("argc %d not supported\n", argc);
238 hres = E_NOTIMPL;
239 goto done;
242 if(!(jsdisp = to_jsdisp(disp))) {
243 FIXME("Host object this\n");
244 hres = E_FAIL;
245 goto done;
248 hres = to_flat_string(ctx, argv[0], &name_str, &name);
249 if(FAILED(hres))
250 goto done;
252 hres = jsdisp_get_own_property(jsdisp, name, TRUE, &prop_desc);
253 jsstr_release(name_str);
254 if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
255 goto done;
257 if(r)
258 *r = jsval_bool(hres == S_OK && (prop_desc.flags & PROPF_ENUMERABLE) != 0);
259 hres = S_OK;
260 done:
261 IDispatch_Release(disp);
262 return hres;
265 static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
266 jsval_t *r)
268 jsdisp_t *jsthis, *jsdisp;
269 IDispatch *disp;
270 BOOL ret = FALSE;
271 HRESULT hres;
273 hres = to_object(ctx, vthis, &disp);
274 if(FAILED(hres))
275 return hres;
277 if(!r)
278 goto done;
280 if(argc && (jsthis = to_jsdisp(disp)) && is_object_instance(argv[0]) &&
281 (jsdisp = to_jsdisp(get_object(argv[0])))) {
282 while(jsdisp->prototype) {
283 if(jsdisp->prototype == jsthis) {
284 ret = TRUE;
285 break;
287 jsdisp = jsdisp->prototype;
291 *r = jsval_bool(ret);
292 done:
293 IDispatch_Release(disp);
294 return hres;
297 static HRESULT Object_defineGetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
299 property_desc_t desc;
300 const WCHAR *name;
301 jsstr_t *name_str;
302 jsdisp_t *jsthis;
303 HRESULT hres;
305 TRACE("\n");
307 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
308 goto done;
310 if(argc < 2 || !is_object_instance(argv[1]))
311 return JS_E_FUNCTION_EXPECTED;
313 desc.getter = to_jsdisp(get_object(argv[1]));
314 if(!desc.getter) {
315 FIXME("getter is not JS object\n");
316 return E_NOTIMPL;
318 /* FIXME: Check IsCallable */
320 hres = to_flat_string(ctx, argv[0], &name_str, &name);
321 if(FAILED(hres))
322 return hres;
324 desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
325 desc.explicit_getter = TRUE;
326 desc.explicit_setter = FALSE;
327 desc.explicit_value = FALSE;
328 desc.setter = NULL;
329 hres = jsdisp_define_property(jsthis, name, &desc);
331 jsstr_release(name_str);
332 if(FAILED(hres))
333 return hres;
334 done:
335 if(r)
336 *r = jsval_undefined();
337 return S_OK;
340 static HRESULT Object_defineSetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
342 property_desc_t desc;
343 const WCHAR *name;
344 jsstr_t *name_str;
345 jsdisp_t *jsthis;
346 HRESULT hres;
348 TRACE("\n");
350 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
351 goto done;
353 if(argc < 2 || !is_object_instance(argv[1]))
354 return JS_E_FUNCTION_EXPECTED;
356 desc.setter = to_jsdisp(get_object(argv[1]));
357 if(!desc.setter) {
358 FIXME("setter is not JS object\n");
359 return E_NOTIMPL;
361 /* FIXME: Check IsCallable */
363 hres = to_flat_string(ctx, argv[0], &name_str, &name);
364 if(FAILED(hres))
365 return hres;
367 desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
368 desc.explicit_getter = FALSE;
369 desc.explicit_setter = TRUE;
370 desc.explicit_value = FALSE;
371 desc.getter = NULL;
372 hres = jsdisp_define_property(jsthis, name, &desc);
374 jsstr_release(name_str);
375 if(FAILED(hres))
376 return hres;
377 done:
378 if(r)
379 *r = jsval_undefined();
380 return S_OK;
383 HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
385 jsdisp_t *jsthis;
386 IDispatch *disp;
387 HRESULT hres;
389 TRACE("%s\n", debugstr_jsval(vthis));
391 hres = to_object(ctx, vthis, &disp);
392 if(FAILED(hres))
393 return hres;
395 if(!r)
396 goto done;
398 if(!(jsthis = to_jsdisp(disp))) {
399 FIXME("Host object this\n");
400 hres = E_FAIL;
401 goto done;
404 *r = jsthis->prototype
405 ? jsval_obj(jsdisp_addref(jsthis->prototype))
406 : jsval_null();
407 done:
408 IDispatch_Release(disp);
409 return hres;
412 HRESULT Object_set_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
414 jsdisp_t *jsthis, *proto;
415 HRESULT hres;
417 TRACE("%s\n", debugstr_jsval(vthis));
419 if(is_undefined(vthis) || is_null(vthis))
420 return JS_E_OBJECT_EXPECTED;
421 if(!argc) {
422 if(r)
423 *r = jsval_undefined();
424 return S_OK;
426 if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
427 goto done;
429 if(is_null(argv[0])) {
430 proto = NULL;
431 }else if(is_object_instance(argv[0])) {
432 proto = to_jsdisp(get_object(argv[0]));
433 if(!proto) {
434 FIXME("Host object value\n");
435 return E_FAIL;
437 }else
438 goto done;
440 hres = jsdisp_change_prototype(jsthis, proto);
441 if(FAILED(hres))
442 return hres;
444 done:
445 return r ? jsval_copy(argv[0], r) : S_OK;
448 static void Object_destructor(jsdisp_t *dispex)
450 heap_free(dispex);
453 static const builtin_prop_t Object_props[] = {
454 {L"__defineGetter__", Object_defineGetter, PROPF_METHOD|PROPF_ES6|2},
455 {L"__defineSetter__", Object_defineSetter, PROPF_METHOD|PROPF_ES6|2},
456 {L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1},
457 {L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1},
458 {L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1},
459 {L"toLocaleString", Object_toLocaleString, PROPF_METHOD},
460 {L"toString", Object_toString, PROPF_METHOD},
461 {L"valueOf", Object_valueOf, PROPF_METHOD}
464 static const builtin_info_t Object_info = {
465 JSCLASS_OBJECT,
466 NULL,
467 ARRAY_SIZE(Object_props),
468 Object_props,
469 Object_destructor,
470 NULL
473 static const builtin_info_t ObjectInst_info = {
474 JSCLASS_OBJECT,
475 NULL,
476 0, NULL,
477 Object_destructor,
478 NULL
481 static void release_property_descriptor(property_desc_t *desc)
483 if(desc->explicit_value)
484 jsval_release(desc->value);
485 if(desc->getter)
486 jsdisp_release(desc->getter);
487 if(desc->setter)
488 jsdisp_release(desc->setter);
491 static HRESULT to_property_descriptor(script_ctx_t *ctx, jsdisp_t *attr_obj, property_desc_t *desc)
493 DISPID id;
494 jsval_t v;
495 BOOL b;
496 HRESULT hres;
498 memset(desc, 0, sizeof(*desc));
499 desc->value = jsval_undefined();
501 hres = jsdisp_get_id(attr_obj, L"enumerable", 0, &id);
502 if(SUCCEEDED(hres)) {
503 desc->mask |= PROPF_ENUMERABLE;
504 hres = jsdisp_propget(attr_obj, id, &v);
505 if(FAILED(hres))
506 return hres;
507 hres = to_boolean(v, &b);
508 jsval_release(v);
509 if(FAILED(hres))
510 return hres;
511 if(b)
512 desc->flags |= PROPF_ENUMERABLE;
513 }else if(hres != DISP_E_UNKNOWNNAME) {
514 return hres;
517 hres = jsdisp_get_id(attr_obj, L"configurable", 0, &id);
518 if(SUCCEEDED(hres)) {
519 desc->mask |= PROPF_CONFIGURABLE;
520 hres = jsdisp_propget(attr_obj, id, &v);
521 if(FAILED(hres))
522 return hres;
523 hres = to_boolean(v, &b);
524 jsval_release(v);
525 if(FAILED(hres))
526 return hres;
527 if(b)
528 desc->flags |= PROPF_CONFIGURABLE;
529 }else if(hres != DISP_E_UNKNOWNNAME) {
530 return hres;
533 hres = jsdisp_get_id(attr_obj, L"value", 0, &id);
534 if(SUCCEEDED(hres)) {
535 hres = jsdisp_propget(attr_obj, id, &desc->value);
536 if(FAILED(hres))
537 return hres;
538 desc->explicit_value = TRUE;
539 }else if(hres != DISP_E_UNKNOWNNAME) {
540 return hres;
543 hres = jsdisp_get_id(attr_obj, L"writable", 0, &id);
544 if(SUCCEEDED(hres)) {
545 desc->mask |= PROPF_WRITABLE;
546 hres = jsdisp_propget(attr_obj, id, &v);
547 if(SUCCEEDED(hres)) {
548 hres = to_boolean(v, &b);
549 jsval_release(v);
550 if(SUCCEEDED(hres) && b)
551 desc->flags |= PROPF_WRITABLE;
553 }else if(hres == DISP_E_UNKNOWNNAME) {
554 hres = S_OK;
556 if(FAILED(hres)) {
557 release_property_descriptor(desc);
558 return hres;
561 hres = jsdisp_get_id(attr_obj, L"get", 0, &id);
562 if(SUCCEEDED(hres)) {
563 desc->explicit_getter = TRUE;
564 hres = jsdisp_propget(attr_obj, id, &v);
565 if(SUCCEEDED(hres) && !is_undefined(v)) {
566 if(!is_object_instance(v)) {
567 FIXME("getter is not an object\n");
568 jsval_release(v);
569 hres = E_FAIL;
570 }else {
571 /* FIXME: Check IsCallable */
572 desc->getter = to_jsdisp(get_object(v));
573 if(!desc->getter)
574 FIXME("getter is not JS object\n");
577 }else if(hres == DISP_E_UNKNOWNNAME) {
578 hres = S_OK;
580 if(FAILED(hres)) {
581 release_property_descriptor(desc);
582 return hres;
585 hres = jsdisp_get_id(attr_obj, L"set", 0, &id);
586 if(SUCCEEDED(hres)) {
587 desc->explicit_setter = TRUE;
588 hres = jsdisp_propget(attr_obj, id, &v);
589 if(SUCCEEDED(hres) && !is_undefined(v)) {
590 if(!is_object_instance(v)) {
591 FIXME("setter is not an object\n");
592 jsval_release(v);
593 hres = E_FAIL;
594 }else {
595 /* FIXME: Check IsCallable */
596 desc->setter = to_jsdisp(get_object(v));
597 if(!desc->setter)
598 FIXME("setter is not JS object\n");
601 }else if(hres == DISP_E_UNKNOWNNAME) {
602 hres = S_OK;
604 if(FAILED(hres)) {
605 release_property_descriptor(desc);
606 return hres;
609 if(desc->explicit_getter || desc->explicit_setter) {
610 if(desc->explicit_value)
611 hres = JS_E_PROP_DESC_MISMATCH;
612 else if(desc->mask & PROPF_WRITABLE)
613 hres = JS_E_INVALID_WRITABLE_PROP_DESC;
616 if(FAILED(hres))
617 release_property_descriptor(desc);
618 return hres;
621 static HRESULT jsdisp_define_properties(script_ctx_t *ctx, jsdisp_t *obj, jsval_t list_val)
623 DISPID id = DISPID_STARTENUM;
624 property_desc_t prop_desc;
625 IDispatch *list_disp;
626 jsdisp_t *list_obj, *desc_obj;
627 jsval_t desc_val;
628 BSTR name;
629 HRESULT hres;
631 hres = to_object(ctx, list_val, &list_disp);
632 if(FAILED(hres))
633 return hres;
635 if(!(list_obj = to_jsdisp(list_disp))) {
636 FIXME("non-JS list obj\n");
637 IDispatch_Release(list_disp);
638 return E_NOTIMPL;
641 while(1) {
642 hres = jsdisp_next_prop(list_obj, id, JSDISP_ENUM_OWN_ENUMERABLE, &id);
643 if(hres != S_OK)
644 break;
646 hres = jsdisp_propget(list_obj, id, &desc_val);
647 if(FAILED(hres))
648 break;
650 if(!is_object_instance(desc_val) || !(desc_obj = to_jsdisp(get_object(desc_val)))) {
651 jsval_release(desc_val);
652 break;
655 hres = to_property_descriptor(ctx, desc_obj, &prop_desc);
656 jsdisp_release(desc_obj);
657 if(FAILED(hres))
658 break;
660 hres = IDispatchEx_GetMemberName(&list_obj->IDispatchEx_iface, id, &name);
661 if(SUCCEEDED(hres))
662 hres = jsdisp_define_property(obj, name, &prop_desc);
663 release_property_descriptor(&prop_desc);
664 if(FAILED(hres))
665 break;
668 jsdisp_release(list_obj);
669 return FAILED(hres) ? hres : S_OK;
672 static HRESULT Object_defineProperty(script_ctx_t *ctx, jsval_t vthis, WORD flags,
673 unsigned argc, jsval_t *argv, jsval_t *r)
675 property_desc_t prop_desc;
676 jsdisp_t *obj, *attr_obj;
677 const WCHAR *name;
678 jsstr_t *name_str;
679 HRESULT hres;
681 TRACE("\n");
683 if(argc < 1 || !is_object_instance(argv[0]))
684 return JS_E_OBJECT_EXPECTED;
685 obj = to_jsdisp(get_object(argv[0]));
686 if(!obj) {
687 FIXME("not implemented non-JS object\n");
688 return E_NOTIMPL;
691 hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
692 if(FAILED(hres))
693 return hres;
695 if(argc >= 3 && is_object_instance(argv[2])) {
696 attr_obj = to_jsdisp(get_object(argv[2]));
697 if(attr_obj) {
698 hres = to_property_descriptor(ctx, attr_obj, &prop_desc);
699 }else {
700 FIXME("not implemented non-JS object\n");
701 hres = E_NOTIMPL;
703 }else {
704 hres = JS_E_OBJECT_EXPECTED;
707 if(FAILED(hres))
709 jsstr_release(name_str);
710 return hres;
713 hres = jsdisp_define_property(obj, name, &prop_desc);
714 jsstr_release(name_str);
715 release_property_descriptor(&prop_desc);
716 if(SUCCEEDED(hres) && r)
717 *r = jsval_obj(jsdisp_addref(obj));
718 return hres;
721 static HRESULT Object_defineProperties(script_ctx_t *ctx, jsval_t vthis, WORD flags,
722 unsigned argc, jsval_t *argv, jsval_t *r)
724 jsdisp_t *obj;
725 HRESULT hres;
727 if(argc < 1 || !is_object_instance(argv[0]) || !(obj = to_jsdisp(get_object(argv[0])))) {
728 FIXME("not an object\n");
729 return E_NOTIMPL;
732 TRACE("%p\n", obj);
734 hres = jsdisp_define_properties(ctx, obj, argc >= 2 ? argv[1] : jsval_undefined());
735 if(SUCCEEDED(hres) && r)
736 *r = jsval_obj(jsdisp_addref(obj));
737 return hres;
740 static HRESULT Object_getOwnPropertyDescriptor(script_ctx_t *ctx, jsval_t vthis, WORD flags,
741 unsigned argc, jsval_t *argv, jsval_t *r)
743 property_desc_t prop_desc;
744 jsdisp_t *obj, *desc_obj;
745 const WCHAR *name;
746 jsstr_t *name_str;
747 HRESULT hres;
749 TRACE("\n");
751 if(argc < 1 || !is_object_instance(argv[0]))
752 return JS_E_OBJECT_EXPECTED;
753 obj = to_jsdisp(get_object(argv[0]));
754 if(!obj) {
755 FIXME("not implemented non-JS object\n");
756 return E_NOTIMPL;
759 hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
760 if(FAILED(hres))
761 return hres;
763 hres = jsdisp_get_own_property(obj, name, FALSE, &prop_desc);
764 jsstr_release(name_str);
765 if(hres == DISP_E_UNKNOWNNAME) {
766 if(r) *r = jsval_undefined();
767 return S_OK;
769 if(FAILED(hres))
770 return hres;
772 hres = create_object(ctx, NULL, &desc_obj);
773 if(FAILED(hres))
774 return hres;
776 if(prop_desc.explicit_getter || prop_desc.explicit_setter) {
777 hres = jsdisp_define_data_property(desc_obj, L"get", PROPF_ALL,
778 prop_desc.getter ? jsval_obj(prop_desc.getter) : jsval_undefined());
779 if(SUCCEEDED(hres))
780 hres = jsdisp_define_data_property(desc_obj, L"set", PROPF_ALL,
781 prop_desc.setter ? jsval_obj(prop_desc.setter) : jsval_undefined());
782 }else {
783 hres = jsdisp_propput_name(desc_obj, L"value", prop_desc.value);
784 if(SUCCEEDED(hres))
785 hres = jsdisp_define_data_property(desc_obj, L"writable", PROPF_ALL,
786 jsval_bool(!!(prop_desc.flags & PROPF_WRITABLE)));
788 if(SUCCEEDED(hres))
789 hres = jsdisp_define_data_property(desc_obj, L"enumerable", PROPF_ALL,
790 jsval_bool(!!(prop_desc.flags & PROPF_ENUMERABLE)));
791 if(SUCCEEDED(hres))
792 hres = jsdisp_define_data_property(desc_obj, L"configurable", PROPF_ALL,
793 jsval_bool(!!(prop_desc.flags & PROPF_CONFIGURABLE)));
795 release_property_descriptor(&prop_desc);
796 if(SUCCEEDED(hres) && r)
797 *r = jsval_obj(desc_obj);
798 else
799 jsdisp_release(desc_obj);
800 return hres;
803 static HRESULT Object_create(script_ctx_t *ctx, jsval_t vthis, WORD flags,
804 unsigned argc, jsval_t *argv, jsval_t *r)
806 jsdisp_t *proto = NULL, *obj;
807 HRESULT hres;
809 if(!argc || (!is_object_instance(argv[0]) && !is_null(argv[0]))) {
810 FIXME("Invalid arg\n");
811 return E_INVALIDARG;
814 TRACE("(%s)\n", debugstr_jsval(argv[0]));
816 if(argc && is_object_instance(argv[0])) {
817 if(get_object(argv[0]))
818 proto = to_jsdisp(get_object(argv[0]));
819 if(!proto) {
820 FIXME("Non-JS prototype\n");
821 return E_NOTIMPL;
823 }else if(!is_null(argv[0])) {
824 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
825 return E_INVALIDARG;
828 hres = create_dispex(ctx, &ObjectInst_info, proto, &obj);
829 if(FAILED(hres))
830 return hres;
832 if(argc >= 2 && !is_undefined(argv[1]))
833 hres = jsdisp_define_properties(ctx, obj, argv[1]);
835 if(SUCCEEDED(hres) && r)
836 *r = jsval_obj(obj);
837 else
838 jsdisp_release(obj);
839 return hres;
842 static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flags,
843 unsigned argc, jsval_t *argv, jsval_t *r)
845 jsdisp_t *obj;
847 if(!argc || !is_object_instance(argv[0]))
848 return JS_E_OBJECT_EXPECTED;
850 TRACE("(%s)\n", debugstr_jsval(argv[0]));
852 obj = to_jsdisp(get_object(argv[0]));
853 if(r)
854 *r = obj && obj->prototype
855 ? jsval_obj(jsdisp_addref(obj->prototype))
856 : jsval_null();
857 return S_OK;
860 static HRESULT object_keys(script_ctx_t *ctx, jsval_t arg, enum jsdisp_enum_type enum_type, jsval_t *r)
862 DISPID id = DISPID_STARTENUM;
863 jsdisp_t *obj, *array;
864 unsigned i = 0;
865 jsstr_t *key;
866 HRESULT hres;
868 if(!is_object_instance(arg))
869 return JS_E_OBJECT_EXPECTED;
871 obj = to_jsdisp(get_object(arg));
872 if(!obj) {
873 FIXME("Non-JS object\n");
874 return E_NOTIMPL;
877 hres = create_array(ctx, 0, &array);
878 if(FAILED(hres))
879 return hres;
881 do {
882 hres = jsdisp_next_prop(obj, id, enum_type, &id);
883 if(hres != S_OK)
884 break;
886 hres = jsdisp_get_prop_name(obj, id, &key);
887 if(FAILED(hres))
888 break;
890 hres = jsdisp_propput_idx(array, i++, jsval_string(key));
891 jsstr_release(key);
892 } while(hres == S_OK);
894 if(SUCCEEDED(hres) && r)
895 *r = jsval_obj(array);
896 else
897 jsdisp_release(array);
898 return hres;
901 static HRESULT Object_keys(script_ctx_t *ctx, jsval_t vthis, WORD flags,
902 unsigned argc, jsval_t *argv, jsval_t *r)
904 jsval_t arg = argc ? argv[0] : jsval_undefined();
906 TRACE("(%s)\n", debugstr_jsval(arg));
908 return object_keys(ctx, arg, JSDISP_ENUM_OWN_ENUMERABLE, r);
911 static HRESULT Object_getOwnPropertyNames(script_ctx_t *ctx, jsval_t vthis, WORD flags,
912 unsigned argc, jsval_t *argv, jsval_t *r)
914 jsval_t arg = argc ? argv[0] : jsval_undefined();
916 TRACE("(%s)\n", debugstr_jsval(arg));
918 return object_keys(ctx, arg, JSDISP_ENUM_OWN, r);
921 static HRESULT Object_preventExtensions(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
923 jsdisp_t *obj;
925 if(!argc || !is_object_instance(argv[0]))
926 return JS_E_OBJECT_EXPECTED;
928 TRACE("(%s)\n", debugstr_jsval(argv[0]));
930 obj = to_jsdisp(get_object(argv[0]));
931 if(!obj) {
932 FIXME("Non-JS object\n");
933 return E_NOTIMPL;
936 obj->extensible = FALSE;
937 if(r) *r = jsval_obj(jsdisp_addref(obj));
938 return S_OK;
941 static HRESULT Object_freeze(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
942 jsval_t *argv, jsval_t *r)
944 jsdisp_t *obj;
946 if(!argc || !is_object_instance(argv[0])) {
947 WARN("argument is not an object\n");
948 return JS_E_OBJECT_EXPECTED;
951 TRACE("(%s)\n", debugstr_jsval(argv[0]));
953 obj = to_jsdisp(get_object(argv[0]));
954 if(!obj) {
955 FIXME("Non-JS object\n");
956 return E_NOTIMPL;
959 jsdisp_freeze(obj, FALSE);
960 if(r) *r = jsval_obj(jsdisp_addref(obj));
961 return S_OK;
964 static HRESULT Object_seal(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
965 jsval_t *argv, jsval_t *r)
967 jsdisp_t *obj;
969 if(!argc || !is_object_instance(argv[0])) {
970 WARN("argument is not an object\n");
971 return JS_E_OBJECT_EXPECTED;
974 TRACE("(%s)\n", debugstr_jsval(argv[0]));
976 obj = to_jsdisp(get_object(argv[0]));
977 if(!obj) {
978 FIXME("Non-JS object\n");
979 return E_NOTIMPL;
982 jsdisp_freeze(obj, TRUE);
983 if(r) *r = jsval_obj(jsdisp_addref(obj));
984 return S_OK;
987 static HRESULT Object_isExtensible(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
989 jsdisp_t *obj;
991 if(!argc || !is_object_instance(argv[0])) {
992 WARN("argument is not an object\n");
993 return JS_E_OBJECT_EXPECTED;
996 TRACE("(%s)\n", debugstr_jsval(argv[0]));
998 obj = to_jsdisp(get_object(argv[0]));
999 if(!obj) {
1000 FIXME("Non-JS object\n");
1001 return E_NOTIMPL;
1004 if(r) *r = jsval_bool(obj->extensible);
1005 return S_OK;
1008 static HRESULT Object_isFrozen(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
1009 jsval_t *argv, jsval_t *r)
1011 jsdisp_t *obj;
1013 if(!argc || !is_object_instance(argv[0])) {
1014 WARN("argument is not an object\n");
1015 return JS_E_OBJECT_EXPECTED;
1018 TRACE("(%s)\n", debugstr_jsval(argv[0]));
1020 obj = to_jsdisp(get_object(argv[0]));
1021 if(!obj) {
1022 FIXME("Non-JS object\n");
1023 return E_NOTIMPL;
1026 if(r) *r = jsval_bool(jsdisp_is_frozen(obj, FALSE));
1027 return S_OK;
1030 static HRESULT Object_isSealed(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc,
1031 jsval_t *argv, jsval_t *r)
1033 jsdisp_t *obj;
1035 if(!argc || !is_object_instance(argv[0])) {
1036 WARN("argument is not an object\n");
1037 return JS_E_OBJECT_EXPECTED;
1040 TRACE("(%s)\n", debugstr_jsval(argv[0]));
1042 obj = to_jsdisp(get_object(argv[0]));
1043 if(!obj) {
1044 FIXME("Non-JS object\n");
1045 return E_NOTIMPL;
1048 if(r) *r = jsval_bool(jsdisp_is_frozen(obj, TRUE));
1049 return S_OK;
1052 static const builtin_prop_t ObjectConstr_props[] = {
1053 {L"create", Object_create, PROPF_ES5|PROPF_METHOD|2},
1054 {L"defineProperties", Object_defineProperties, PROPF_ES5|PROPF_METHOD|2},
1055 {L"defineProperty", Object_defineProperty, PROPF_ES5|PROPF_METHOD|2},
1056 {L"freeze", Object_freeze, PROPF_ES5|PROPF_METHOD|1},
1057 {L"getOwnPropertyDescriptor", Object_getOwnPropertyDescriptor, PROPF_ES5|PROPF_METHOD|2},
1058 {L"getOwnPropertyNames", Object_getOwnPropertyNames, PROPF_ES5|PROPF_METHOD|1},
1059 {L"getPrototypeOf", Object_getPrototypeOf, PROPF_ES5|PROPF_METHOD|1},
1060 {L"isExtensible", Object_isExtensible, PROPF_ES5|PROPF_METHOD|1},
1061 {L"isFrozen", Object_isFrozen, PROPF_ES5|PROPF_METHOD|1},
1062 {L"isSealed", Object_isSealed, PROPF_ES5|PROPF_METHOD|1},
1063 {L"keys", Object_keys, PROPF_ES5|PROPF_METHOD|1},
1064 {L"preventExtensions", Object_preventExtensions, PROPF_ES5|PROPF_METHOD|1},
1065 {L"seal", Object_seal, PROPF_ES5|PROPF_METHOD|1},
1068 static const builtin_info_t ObjectConstr_info = {
1069 JSCLASS_FUNCTION,
1070 Function_value,
1071 ARRAY_SIZE(ObjectConstr_props),
1072 ObjectConstr_props,
1073 NULL,
1074 NULL
1077 static HRESULT ObjectConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1078 jsval_t *r)
1080 HRESULT hres;
1082 TRACE("\n");
1084 switch(flags) {
1085 case DISPATCH_METHOD:
1086 case DISPATCH_CONSTRUCT: {
1087 jsdisp_t *obj;
1089 if(argc) {
1090 if(!is_undefined(argv[0]) && !is_null(argv[0])) {
1091 IDispatch *disp;
1093 hres = to_object(ctx, argv[0], &disp);
1094 if(FAILED(hres))
1095 return hres;
1097 if(r)
1098 *r = jsval_disp(disp);
1099 else
1100 IDispatch_Release(disp);
1101 return S_OK;
1105 hres = create_object(ctx, NULL, &obj);
1106 if(FAILED(hres))
1107 return hres;
1109 if(r)
1110 *r = jsval_obj(obj);
1111 else
1112 jsdisp_release(obj);
1113 break;
1116 default:
1117 FIXME("unimplemented flags: %x\n", flags);
1118 return E_NOTIMPL;
1121 return S_OK;
1124 HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1126 return create_builtin_constructor(ctx, ObjectConstr_value, L"Object", &ObjectConstr_info, PROPF_CONSTR,
1127 object_prototype, ret);
1130 HRESULT create_object_prototype(script_ctx_t *ctx, jsdisp_t **ret)
1132 return create_dispex(ctx, &Object_info, NULL, ret);
1135 HRESULT create_object(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t **ret)
1137 jsdisp_t *object;
1138 HRESULT hres;
1140 object = heap_alloc_zero(sizeof(jsdisp_t));
1141 if(!object)
1142 return E_OUTOFMEMORY;
1144 hres = init_dispex_from_constr(object, ctx, &ObjectInst_info, constr ? constr : ctx->object_constr);
1145 if(FAILED(hres)) {
1146 heap_free(object);
1147 return hres;
1150 *ret = object;
1151 return S_OK;