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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 726 HRESULT create_object_prototype(script_ctx_t *ctx, jsdisp_t **ret) 727 { 728 return create_dispex(ctx, &Object_info, NULL, ret); 729 } 730 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