1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include <assert.h>
20
21 #include "jscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
26
27 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
28 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
29 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
30 static const WCHAR hasOwnPropertyW[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0};
31 static const WCHAR propertyIsEnumerableW[] =
32 {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
33 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
34
35 static const WCHAR createW[] = {'c','r','e','a','t','e',0};
36 static const WCHAR getOwnPropertyDescriptorW[] =
37 {'g','e','t','O','w','n','P','r','o','p','e','r','t','y','D','e','s','c','r','i','p','t','o','r',0};
38 static const WCHAR getPrototypeOfW[] =
39 {'g','e','t','P','r','o','t','o','t','y','p','e','O','f',0};
40 static const WCHAR definePropertyW[] = {'d','e','f','i','n','e','P','r','o','p','e','r','t','y',0};
41
42 static const WCHAR definePropertiesW[] = {'d','e','f','i','n','e','P','r','o','p','e','r','t','i','e','s',0};
43
44 static const WCHAR default_valueW[] = {'[','o','b','j','e','c','t',' ','O','b','j','e','c','t',']',0};
45
46 static const WCHAR configurableW[] = {'c','o','n','f','i','g','u','r','a','b','l','e',0};
47 static const WCHAR enumerableW[] = {'e','n','u','m','e','r','a','b','l','e',0};
48 static const WCHAR valueW[] = {'v','a','l','u','e',0};
49 static const WCHAR writableW[] = {'w','r','i','t','a','b','l','e',0};
50 static const WCHAR getW[] = {'g','e','t',0};
51 static const WCHAR setW[] = {'s','e','t',0};
52
Object_toString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)53 static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
54 jsval_t *r)
55 {
56 jsdisp_t *jsdisp;
57 const WCHAR *str;
58
59 static const WCHAR formatW[] = {'[','o','b','j','e','c','t',' ','%','s',']',0};
60
61 static const WCHAR arrayW[] = {'A','r','r','a','y',0};
62 static const WCHAR booleanW[] = {'B','o','o','l','e','a','n',0};
63 static const WCHAR dateW[] = {'D','a','t','e',0};
64 static const WCHAR errorW[] = {'E','r','r','o','r',0};
65 static const WCHAR functionW[] = {'F','u','n','c','t','i','o','n',0};
66 static const WCHAR mathW[] = {'M','a','t','h',0};
67 static const WCHAR numberW[] = {'N','u','m','b','e','r',0};
68 static const WCHAR objectW[] = {'O','b','j','e','c','t',0};
69 static const WCHAR regexpW[] = {'R','e','g','E','x','p',0};
70 static const WCHAR stringW[] = {'S','t','r','i','n','g',0};
71 /* Keep in sync with jsclass_t enum */
72 static const WCHAR *names[] = {NULL, arrayW, booleanW, dateW, objectW, errorW,
73 functionW, NULL, mathW, numberW, objectW, regexpW, stringW, objectW, objectW, objectW};
74
75 TRACE("\n");
76
77 jsdisp = get_jsdisp(jsthis);
78 if(!jsdisp) {
79 str = objectW;
80 }else if(names[jsdisp->builtin_info->class]) {
81 str = names[jsdisp->builtin_info->class];
82 }else {
83 assert(jsdisp->builtin_info->class != JSCLASS_NONE);
84 FIXME("jdisp->builtin_info->class = %d\n", jsdisp->builtin_info->class);
85 return E_FAIL;
86 }
87
88 if(r) {
89 jsstr_t *ret;
90 WCHAR *ptr;
91
92 ret = jsstr_alloc_buf(9+lstrlenW(str), &ptr);
93 if(!ret)
94 return E_OUTOFMEMORY;
95
96 swprintf(ptr, formatW, str);
97 *r = jsval_string(ret);
98 }
99
100 return S_OK;
101 }
102
Object_toLocaleString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)103 static HRESULT Object_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
104 jsval_t *r)
105 {
106 TRACE("\n");
107
108 if(!is_jsdisp(jsthis)) {
109 FIXME("Host object this\n");
110 return E_FAIL;
111 }
112
113 return jsdisp_call_name(jsthis->u.jsdisp, toStringW, DISPATCH_METHOD, 0, NULL, r);
114 }
115
Object_valueOf(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)116 static HRESULT Object_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
117 jsval_t *r)
118 {
119 TRACE("\n");
120
121 if(r) {
122 IDispatch_AddRef(jsthis->u.disp);
123 *r = jsval_disp(jsthis->u.disp);
124 }
125 return S_OK;
126 }
127
Object_hasOwnProperty(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)128 static HRESULT Object_hasOwnProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
129 jsval_t *r)
130 {
131 jsstr_t *name;
132 DISPID id;
133 BSTR bstr;
134 HRESULT hres;
135
136 TRACE("\n");
137
138 if(!argc) {
139 if(r)
140 *r = jsval_bool(FALSE);
141 return S_OK;
142 }
143
144 hres = to_string(ctx, argv[0], &name);
145 if(FAILED(hres))
146 return hres;
147
148 if(is_jsdisp(jsthis)) {
149 property_desc_t prop_desc;
150 const WCHAR *name_str;
151
152 name_str = jsstr_flatten(name);
153 if(!name_str) {
154 jsstr_release(name);
155 return E_OUTOFMEMORY;
156 }
157
158 hres = jsdisp_get_own_property(jsthis->u.jsdisp, name_str, TRUE, &prop_desc);
159 jsstr_release(name);
160 if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
161 return hres;
162
163 if(r) *r = jsval_bool(hres == S_OK);
164 return S_OK;
165 }
166
167
168 bstr = SysAllocStringLen(NULL, jsstr_length(name));
169 if(bstr)
170 jsstr_flush(name, bstr);
171 jsstr_release(name);
172 if(!bstr)
173 return E_OUTOFMEMORY;
174
175 if(is_dispex(jsthis))
176 hres = IDispatchEx_GetDispID(jsthis->u.dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive), &id);
177 else
178 hres = IDispatch_GetIDsOfNames(jsthis->u.disp, &IID_NULL, &bstr, 1, ctx->lcid, &id);
179
180 SysFreeString(bstr);
181 if(r)
182 *r = jsval_bool(SUCCEEDED(hres));
183 return S_OK;
184 }
185
Object_propertyIsEnumerable(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)186 static HRESULT Object_propertyIsEnumerable(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
187 jsval_t *r)
188 {
189 property_desc_t prop_desc;
190 const WCHAR *name;
191 jsstr_t *name_str;
192 HRESULT hres;
193
194 TRACE("\n");
195
196 if(argc != 1) {
197 FIXME("argc %d not supported\n", argc);
198 return E_NOTIMPL;
199 }
200
201 if(!is_jsdisp(jsthis)) {
202 FIXME("Host object this\n");
203 return E_FAIL;
204 }
205
206 hres = to_flat_string(ctx, argv[0], &name_str, &name);
207 if(FAILED(hres))
208 return hres;
209
210 hres = jsdisp_get_own_property(jsthis->u.jsdisp, name, TRUE, &prop_desc);
211 jsstr_release(name_str);
212 if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME)
213 return hres;
214
215 if(r)
216 *r = jsval_bool(hres == S_OK && (prop_desc.flags & PROPF_ENUMERABLE) != 0);
217 return S_OK;
218 }
219
Object_isPrototypeOf(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)220 static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
221 jsval_t *r)
222 {
223 FIXME("\n");
224 return E_NOTIMPL;
225 }
226
Object_get_value(script_ctx_t * ctx,jsdisp_t * jsthis,jsval_t * r)227 static HRESULT Object_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
228 {
229 jsstr_t *ret;
230
231 TRACE("\n");
232
233 ret = jsstr_alloc(default_valueW);
234 if(!ret)
235 return E_OUTOFMEMORY;
236
237 *r = jsval_string(ret);
238 return S_OK;
239 }
240
Object_destructor(jsdisp_t * dispex)241 static void Object_destructor(jsdisp_t *dispex)
242 {
243 heap_free(dispex);
244 }
245
246 static const builtin_prop_t Object_props[] = {
247 {hasOwnPropertyW, Object_hasOwnProperty, PROPF_METHOD|1},
248 {isPrototypeOfW, Object_isPrototypeOf, PROPF_METHOD|1},
249 {propertyIsEnumerableW, Object_propertyIsEnumerable, PROPF_METHOD|1},
250 {toLocaleStringW, Object_toLocaleString, PROPF_METHOD},
251 {toStringW, Object_toString, PROPF_METHOD},
252 {valueOfW, Object_valueOf, PROPF_METHOD}
253 };
254
255 static const builtin_info_t Object_info = {
256 JSCLASS_OBJECT,
257 {NULL, NULL,0, Object_get_value},
258 ARRAY_SIZE(Object_props),
259 Object_props,
260 Object_destructor,
261 NULL
262 };
263
264 static const builtin_info_t ObjectInst_info = {
265 JSCLASS_OBJECT,
266 {NULL, NULL,0, Object_get_value},
267 0, NULL,
268 Object_destructor,
269 NULL
270 };
271
release_property_descriptor(property_desc_t * desc)272 static void release_property_descriptor(property_desc_t *desc)
273 {
274 if(desc->explicit_value)
275 jsval_release(desc->value);
276 if(desc->getter)
277 jsdisp_release(desc->getter);
278 if(desc->setter)
279 jsdisp_release(desc->setter);
280 }
281
to_property_descriptor(script_ctx_t * ctx,jsdisp_t * attr_obj,property_desc_t * desc)282 static HRESULT to_property_descriptor(script_ctx_t *ctx, jsdisp_t *attr_obj, property_desc_t *desc)
283 {
284 DISPID id;
285 jsval_t v;
286 BOOL b;
287 HRESULT hres;
288
289 memset(desc, 0, sizeof(*desc));
290 desc->value = jsval_undefined();
291
292 hres = jsdisp_get_id(attr_obj, enumerableW, 0, &id);
293 if(SUCCEEDED(hres)) {
294 desc->mask |= PROPF_ENUMERABLE;
295 hres = jsdisp_propget(attr_obj, id, &v);
296 if(FAILED(hres))
297 return hres;
298 hres = to_boolean(v, &b);
299 jsval_release(v);
300 if(FAILED(hres))
301 return hres;
302 if(b)
303 desc->flags |= PROPF_ENUMERABLE;
304 }else if(hres != DISP_E_UNKNOWNNAME) {
305 return hres;
306 }
307
308 hres = jsdisp_get_id(attr_obj, configurableW, 0, &id);
309 if(SUCCEEDED(hres)) {
310 desc->mask |= PROPF_CONFIGURABLE;
311 hres = jsdisp_propget(attr_obj, id, &v);
312 if(FAILED(hres))
313 return hres;
314 hres = to_boolean(v, &b);
315 jsval_release(v);
316 if(FAILED(hres))
317 return hres;
318 if(b)
319 desc->flags |= PROPF_CONFIGURABLE;
320 }else if(hres != DISP_E_UNKNOWNNAME) {
321 return hres;
322 }
323
324 hres = jsdisp_get_id(attr_obj, valueW, 0, &id);
325 if(SUCCEEDED(hres)) {
326 hres = jsdisp_propget(attr_obj, id, &desc->value);
327 if(FAILED(hres))
328 return hres;
329 desc->explicit_value = TRUE;
330 }else if(hres != DISP_E_UNKNOWNNAME) {
331 return hres;
332 }
333
334 hres = jsdisp_get_id(attr_obj, writableW, 0, &id);
335 if(SUCCEEDED(hres)) {
336 desc->mask |= PROPF_WRITABLE;
337 hres = jsdisp_propget(attr_obj, id, &v);
338 if(SUCCEEDED(hres)) {
339 hres = to_boolean(v, &b);
340 jsval_release(v);
341 if(SUCCEEDED(hres) && b)
342 desc->flags |= PROPF_WRITABLE;
343 }
344 }else if(hres == DISP_E_UNKNOWNNAME) {
345 hres = S_OK;
346 }
347 if(FAILED(hres)) {
348 release_property_descriptor(desc);
349 return hres;
350 }
351
352 hres = jsdisp_get_id(attr_obj, getW, 0, &id);
353 if(SUCCEEDED(hres)) {
354 desc->explicit_getter = TRUE;
355 hres = jsdisp_propget(attr_obj, id, &v);
356 if(SUCCEEDED(hres) && !is_undefined(v)) {
357 if(!is_object_instance(v)) {
358 FIXME("getter is not an object\n");
359 jsval_release(v);
360 hres = E_FAIL;
361 }else {
362 /* FIXME: Check IsCallable */
363 desc->getter = to_jsdisp(get_object(v));
364 if(!desc->getter)
365 FIXME("getter is not JS object\n");
366 }
367 }
368 }else if(hres == DISP_E_UNKNOWNNAME) {
369 hres = S_OK;
370 }
371 if(FAILED(hres)) {
372 release_property_descriptor(desc);
373 return hres;
374 }
375
376 hres = jsdisp_get_id(attr_obj, setW, 0, &id);
377 if(SUCCEEDED(hres)) {
378 desc->explicit_setter = TRUE;
379 hres = jsdisp_propget(attr_obj, id, &v);
380 if(SUCCEEDED(hres) && !is_undefined(v)) {
381 if(!is_object_instance(v)) {
382 FIXME("setter is not an object\n");
383 jsval_release(v);
384 hres = E_FAIL;
385 }else {
386 /* FIXME: Check IsCallable */
387 desc->setter = to_jsdisp(get_object(v));
388 if(!desc->setter)
389 FIXME("setter is not JS object\n");
390 }
391 }
392 }else if(hres == DISP_E_UNKNOWNNAME) {
393 hres = S_OK;
394 }
395 if(FAILED(hres)) {
396 release_property_descriptor(desc);
397 return hres;
398 }
399
400 if(desc->explicit_getter || desc->explicit_setter) {
401 if(desc->explicit_value)
402 hres = throw_type_error(ctx, JS_E_PROP_DESC_MISMATCH, NULL);
403 else if(desc->mask & PROPF_WRITABLE)
404 hres = throw_type_error(ctx, JS_E_INVALID_WRITABLE_PROP_DESC, NULL);
405 }
406
407 if(FAILED(hres))
408 release_property_descriptor(desc);
409 return hres;
410 }
411
jsdisp_define_properties(script_ctx_t * ctx,jsdisp_t * obj,jsval_t list_val)412 static HRESULT jsdisp_define_properties(script_ctx_t *ctx, jsdisp_t *obj, jsval_t list_val)
413 {
414 DISPID id = DISPID_STARTENUM;
415 property_desc_t prop_desc;
416 IDispatch *list_disp;
417 jsdisp_t *list_obj, *desc_obj;
418 jsval_t desc_val;
419 BSTR name;
420 HRESULT hres;
421
422 hres = to_object(ctx, list_val, &list_disp);
423 if(FAILED(hres))
424 return hres;
425
426 if(!(list_obj = to_jsdisp(list_disp))) {
427 FIXME("non-JS list obj\n");
428 IDispatch_Release(list_disp);
429 return E_NOTIMPL;
430 }
431
432 while(1) {
433 hres = jsdisp_next_prop(list_obj, id, TRUE, &id);
434 if(hres != S_OK)
435 break;
436
437 hres = jsdisp_propget(list_obj, id, &desc_val);
438 if(FAILED(hres))
439 break;
440
441 if(!is_object_instance(desc_val) || !get_object(desc_val) || !(desc_obj = to_jsdisp(get_object(desc_val)))) {
442 jsval_release(desc_val);
443 break;
444 }
445
446 hres = to_property_descriptor(ctx, desc_obj, &prop_desc);
447 jsdisp_release(desc_obj);
448 if(FAILED(hres))
449 break;
450
451 hres = IDispatchEx_GetMemberName(&list_obj->IDispatchEx_iface, id, &name);
452 if(SUCCEEDED(hres))
453 hres = jsdisp_define_property(obj, name, &prop_desc);
454 release_property_descriptor(&prop_desc);
455 if(FAILED(hres))
456 break;
457 }
458
459 jsdisp_release(list_obj);
460 return FAILED(hres) ? hres : S_OK;
461 }
462
Object_defineProperty(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)463 static HRESULT Object_defineProperty(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
464 unsigned argc, jsval_t *argv, jsval_t *r)
465 {
466 property_desc_t prop_desc;
467 jsdisp_t *obj, *attr_obj;
468 const WCHAR *name;
469 jsstr_t *name_str;
470 HRESULT hres;
471
472 TRACE("\n");
473
474 if(argc < 1 || !is_object_instance(argv[0]))
475 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
476 obj = to_jsdisp(get_object(argv[0]));
477 if(!obj) {
478 FIXME("not implemented non-JS object\n");
479 return E_NOTIMPL;
480 }
481
482 hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
483 if(FAILED(hres))
484 return hres;
485
486 if(argc >= 3 && is_object_instance(argv[2])) {
487 attr_obj = to_jsdisp(get_object(argv[2]));
488 if(attr_obj) {
489 hres = to_property_descriptor(ctx, attr_obj, &prop_desc);
490 }else {
491 FIXME("not implemented non-JS object\n");
492 hres = E_NOTIMPL;
493 }
494 }else {
495 hres = throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
496 }
497 jsstr_release(name_str);
498 if(FAILED(hres))
499 return hres;
500
501 hres = jsdisp_define_property(obj, name, &prop_desc);
502 release_property_descriptor(&prop_desc);
503 if(SUCCEEDED(hres) && r)
504 *r = jsval_obj(jsdisp_addref(obj));
505 return hres;
506 }
507
Object_defineProperties(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)508 static HRESULT Object_defineProperties(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
509 unsigned argc, jsval_t *argv, jsval_t *r)
510 {
511 jsdisp_t *obj;
512 HRESULT hres;
513
514 if(argc < 1 || !is_object_instance(argv[0]) || !get_object(argv[0]) || !(obj = to_jsdisp(get_object(argv[0])))) {
515 FIXME("not an object\n");
516 return E_NOTIMPL;
517 }
518
519 TRACE("%p\n", obj);
520
521 hres = jsdisp_define_properties(ctx, obj, argc >= 2 ? argv[1] : jsval_undefined());
522 if(SUCCEEDED(hres) && r)
523 *r = jsval_obj(jsdisp_addref(obj));
524 return hres;
525 }
526
Object_getOwnPropertyDescriptor(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)527 static HRESULT Object_getOwnPropertyDescriptor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
528 unsigned argc, jsval_t *argv, jsval_t *r)
529 {
530 property_desc_t prop_desc;
531 jsdisp_t *obj, *desc_obj;
532 const WCHAR *name;
533 jsstr_t *name_str;
534 HRESULT hres;
535
536 TRACE("\n");
537
538 if(argc < 1 || !is_object_instance(argv[0]))
539 return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
540 obj = to_jsdisp(get_object(argv[0]));
541 if(!obj) {
542 FIXME("not implemented non-JS object\n");
543 return E_NOTIMPL;
544 }
545
546 hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
547 if(FAILED(hres))
548 return hres;
549
550 hres = jsdisp_get_own_property(obj, name, FALSE, &prop_desc);
551 jsstr_release(name_str);
552 if(hres == DISP_E_UNKNOWNNAME) {
553 if(r) *r = jsval_undefined();
554 return S_OK;
555 }
556 if(FAILED(hres))
557 return hres;
558
559 hres = create_object(ctx, NULL, &desc_obj);
560 if(FAILED(hres))
561 return hres;
562
563 if(prop_desc.explicit_getter || prop_desc.explicit_setter) {
564 hres = jsdisp_define_data_property(desc_obj, getW, PROPF_ALL,
565 prop_desc.getter ? jsval_obj(prop_desc.getter) : jsval_undefined());
566 if(SUCCEEDED(hres))
567 hres = jsdisp_define_data_property(desc_obj, setW, PROPF_ALL,
568 prop_desc.setter ? jsval_obj(prop_desc.setter) : jsval_undefined());
569 }else {
570 hres = jsdisp_propput_name(desc_obj, valueW, prop_desc.value);
571 if(SUCCEEDED(hres))
572 hres = jsdisp_define_data_property(desc_obj, writableW, PROPF_ALL,
573 jsval_bool(!!(prop_desc.flags & PROPF_WRITABLE)));
574 }
575 if(SUCCEEDED(hres))
576 hres = jsdisp_define_data_property(desc_obj, enumerableW, PROPF_ALL,
577 jsval_bool(!!(prop_desc.flags & PROPF_ENUMERABLE)));
578 if(SUCCEEDED(hres))
579 hres = jsdisp_define_data_property(desc_obj, configurableW, PROPF_ALL,
580 jsval_bool(!!(prop_desc.flags & PROPF_CONFIGURABLE)));
581
582 release_property_descriptor(&prop_desc);
583 if(SUCCEEDED(hres) && r)
584 *r = jsval_obj(desc_obj);
585 else
586 jsdisp_release(desc_obj);
587 return hres;
588 }
589
Object_create(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)590 static HRESULT Object_create(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
591 unsigned argc, jsval_t *argv, jsval_t *r)
592 {
593 jsdisp_t *proto = NULL, *obj;
594 HRESULT hres;
595
596 if(!argc || (!is_object_instance(argv[0]) && !is_null(argv[0]))) {
597 FIXME("Invalid arg\n");
598 return E_INVALIDARG;
599 }
600
601 TRACE("(%s)\n", debugstr_jsval(argv[0]));
602
603 if(argc && is_object_instance(argv[0])) {
604 if(get_object(argv[0]))
605 proto = to_jsdisp(get_object(argv[0]));
606 if(!proto) {
607 FIXME("Non-JS prototype\n");
608 return E_NOTIMPL;
609 }
610 }else if(!is_null(argv[0])) {
611 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
612 return E_INVALIDARG;
613 }
614
615 hres = create_dispex(ctx, NULL, proto, &obj);
616 if(FAILED(hres))
617 return hres;
618
619 if(argc >= 2 && !is_undefined(argv[1]))
620 hres = jsdisp_define_properties(ctx, obj, argv[1]);
621
622 if(SUCCEEDED(hres) && r)
623 *r = jsval_obj(obj);
624 else
625 jsdisp_release(obj);
626 return hres;
627 }
628
Object_getPrototypeOf(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)629 static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
630 unsigned argc, jsval_t *argv, jsval_t *r)
631 {
632 jsdisp_t *obj;
633
634 if(!argc || !is_object_instance(argv[0])) {
635 FIXME("invalid arguments\n");
636 return E_NOTIMPL;
637 }
638
639 TRACE("(%s)\n", debugstr_jsval(argv[1]));
640
641 obj = to_jsdisp(get_object(argv[0]));
642 if(!obj) {
643 FIXME("Non-JS object\n");
644 return E_NOTIMPL;
645 }
646
647 if(r)
648 *r = obj->prototype
649 ? jsval_obj(jsdisp_addref(obj->prototype))
650 : jsval_null();
651 return S_OK;
652 }
653
654 static const builtin_prop_t ObjectConstr_props[] = {
655 {createW, Object_create, PROPF_ES5|PROPF_METHOD|2},
656 {definePropertiesW, Object_defineProperties, PROPF_ES5|PROPF_METHOD|2},
657 {definePropertyW, Object_defineProperty, PROPF_ES5|PROPF_METHOD|2},
658 {getOwnPropertyDescriptorW, Object_getOwnPropertyDescriptor, PROPF_ES5|PROPF_METHOD|2},
659 {getPrototypeOfW, Object_getPrototypeOf, PROPF_ES5|PROPF_METHOD|1}
660 };
661
662 static const builtin_info_t ObjectConstr_info = {
663 JSCLASS_FUNCTION,
664 DEFAULT_FUNCTION_VALUE,
665 ARRAY_SIZE(ObjectConstr_props),
666 ObjectConstr_props,
667 NULL,
668 NULL
669 };
670
ObjectConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)671 static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
672 jsval_t *r)
673 {
674 HRESULT hres;
675
676 TRACE("\n");
677
678 switch(flags) {
679 case DISPATCH_METHOD:
680 case DISPATCH_CONSTRUCT: {
681 jsdisp_t *obj;
682
683 if(argc) {
684 if(!is_undefined(argv[0]) && !is_null(argv[0]) && (!is_object_instance(argv[0]) || get_object(argv[0]))) {
685 IDispatch *disp;
686
687 hres = to_object(ctx, argv[0], &disp);
688 if(FAILED(hres))
689 return hres;
690
691 if(r)
692 *r = jsval_disp(disp);
693 else
694 IDispatch_Release(disp);
695 return S_OK;
696 }
697 }
698
699 hres = create_object(ctx, NULL, &obj);
700 if(FAILED(hres))
701 return hres;
702
703 if(r)
704 *r = jsval_obj(obj);
705 else
706 jsdisp_release(obj);
707 break;
708 }
709
710 default:
711 FIXME("unimplemented flags: %x\n", flags);
712 return E_NOTIMPL;
713 }
714
715 return S_OK;
716 }
717
create_object_constr(script_ctx_t * ctx,jsdisp_t * object_prototype,jsdisp_t ** ret)718 HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
719 {
720 static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
721
722 return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, &ObjectConstr_info, PROPF_CONSTR,
723 object_prototype, ret);
724 }
725
create_object_prototype(script_ctx_t * ctx,jsdisp_t ** ret)726 HRESULT create_object_prototype(script_ctx_t *ctx, jsdisp_t **ret)
727 {
728 return create_dispex(ctx, &Object_info, NULL, ret);
729 }
730
create_object(script_ctx_t * ctx,jsdisp_t * constr,jsdisp_t ** ret)731 HRESULT create_object(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t **ret)
732 {
733 jsdisp_t *object;
734 HRESULT hres;
735
736 object = heap_alloc_zero(sizeof(jsdisp_t));
737 if(!object)
738 return E_OUTOFMEMORY;
739
740 hres = init_dispex_from_constr(object, ctx, &ObjectInst_info, constr ? constr : ctx->object_constr);
741 if(FAILED(hres)) {
742 heap_free(object);
743 return hres;
744 }
745
746 *ret = object;
747 return S_OK;
748 }
749