XPCVariant.cpp (23028B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* nsIVariant implementation for xpconnect. */ 8 9 #include "mozilla/Range.h" 10 11 #include "xpcprivate.h" 12 13 #include "jsfriendapi.h" 14 #include "js/Array.h" // JS::GetArrayLength, JS::IsArrayObject, JS::NewArrayObject 15 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit 16 #include "js/friend/WindowProxy.h" // js::ToWindowIfWindowProxy 17 #include "js/PropertyAndElement.h" // JS_GetElement 18 #include "js/Wrapper.h" 19 #include "mozilla/HoldDropJSObjects.h" 20 21 using namespace JS; 22 using namespace mozilla; 23 using namespace xpc; 24 25 NS_IMPL_CLASSINFO(XPCVariant, nullptr, 0, XPCVARIANT_CID) 26 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCVariant) 27 NS_INTERFACE_MAP_ENTRY(XPCVariant) 28 NS_INTERFACE_MAP_ENTRY(nsIVariant) 29 NS_INTERFACE_MAP_ENTRY(nsISupports) 30 NS_IMPL_QUERY_CLASSINFO(XPCVariant) 31 NS_INTERFACE_MAP_END 32 NS_IMPL_CI_INTERFACE_GETTER(XPCVariant, XPCVariant, nsIVariant) 33 34 NS_IMPL_CYCLE_COLLECTING_ADDREF(XPCVariant) 35 NS_IMPL_CYCLE_COLLECTING_RELEASE(XPCVariant) 36 37 XPCVariant::XPCVariant(JSContext* cx, const Value& aJSVal) : mJSVal(aJSVal) { 38 if (!mJSVal.isPrimitive()) { 39 // XXXbholley - The innerization here was from bug 638026. Blake says 40 // the basic problem was that we were storing the C++ inner but the JS 41 // outer, which meant that, after navigation, the JS inner could be 42 // collected, which would cause us to try to recreate the JS inner at 43 // some later point after teardown, which would crash. This is shouldn't 44 // be a problem anymore because SetParentToWindow will do the right 45 // thing, but I'm saving the cleanup here for another day. Blake thinks 46 // that we should just not store the WN if we're creating a variant for 47 // an outer window. 48 JSObject* obj = js::ToWindowIfWindowProxy(&mJSVal.toObject()); 49 mJSVal = JS::ObjectValue(*obj); 50 51 JSObject* unwrapped = 52 js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false); 53 mReturnRawObject = !(unwrapped && IsWrappedNativeReflector(unwrapped)); 54 } else { 55 mReturnRawObject = false; 56 } 57 58 if (aJSVal.isGCThing()) { 59 mozilla::HoldJSObjects(this); 60 } 61 } 62 63 XPCVariant::~XPCVariant() { Cleanup(); } 64 65 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant) 66 67 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant) 68 tmp->mData.Traverse(cb); 69 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 70 71 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant) 72 tmp->Cleanup(); 73 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 74 75 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(XPCVariant) 76 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJSVal) 77 NS_IMPL_CYCLE_COLLECTION_TRACE_END 78 79 // static 80 already_AddRefed<XPCVariant> XPCVariant::newVariant(JSContext* cx, 81 const Value& aJSVal) { 82 RefPtr<XPCVariant> variant = new XPCVariant(cx, aJSVal); 83 if (!variant->InitializeData(cx)) { 84 return nullptr; 85 } 86 87 return variant.forget(); 88 } 89 90 void XPCVariant::Cleanup() { 91 mData.Cleanup(); 92 93 if (!GetJSValPreserveColor().isGCThing()) { 94 return; 95 } 96 mJSVal = JS::NullValue(); 97 mozilla::DropJSObjects(this); 98 } 99 100 // Helper class to give us a namespace for the table based code below. 101 class XPCArrayHomogenizer { 102 private: 103 enum Type { 104 tNull = 0, // null value 105 tInt, // Integer 106 tDbl, // Double 107 tBool, // Boolean 108 tStr, // String 109 tID, // ID 110 tArr, // Array 111 tISup, // nsISupports (really just a plain JSObject) 112 tUnk, // Unknown. Used only for initial state. 113 114 tTypeCount, // Just a count for table dimensioning. 115 116 tVar, // nsVariant - last ditch if no other common type found. 117 tErr // No valid state or type has this value. 118 }; 119 120 // Table has tUnk as a state (column) but not as a type (row). 121 static const Type StateTable[tTypeCount][tTypeCount - 1]; 122 123 public: 124 static bool GetTypeForArray(JSContext* cx, HandleObject array, 125 uint32_t length, nsXPTType* resultType, 126 nsID* resultID); 127 }; 128 129 // Current state is the column down the side. 130 // Current type is the row along the top. 131 // New state is in the box at the intersection. 132 133 const XPCArrayHomogenizer::Type 134 XPCArrayHomogenizer::StateTable[tTypeCount][tTypeCount - 1] = { 135 /* tNull,tInt ,tDbl ,tBool,tStr ,tID ,tArr ,tISup */ 136 /* tNull */ {tNull, tVar, tVar, tVar, tStr, tID, tVar, tISup}, 137 /* tInt */ {tVar, tInt, tDbl, tVar, tVar, tVar, tVar, tVar}, 138 /* tDbl */ {tVar, tDbl, tDbl, tVar, tVar, tVar, tVar, tVar}, 139 /* tBool */ {tVar, tVar, tVar, tBool, tVar, tVar, tVar, tVar}, 140 /* tStr */ {tStr, tVar, tVar, tVar, tStr, tVar, tVar, tVar}, 141 /* tID */ {tID, tVar, tVar, tVar, tVar, tID, tVar, tVar}, 142 /* tArr */ {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, 143 /* tISup */ {tISup, tVar, tVar, tVar, tVar, tVar, tVar, tISup}, 144 /* tUnk */ {tNull, tInt, tDbl, tBool, tStr, tID, tVar, tISup}}; 145 146 // static 147 bool XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array, 148 uint32_t length, 149 nsXPTType* resultType, 150 nsID* resultID) { 151 Type state = tUnk; 152 Type type; 153 154 RootedValue val(cx); 155 RootedObject jsobj(cx); 156 for (uint32_t i = 0; i < length; i++) { 157 if (!JS_GetElement(cx, array, i, &val)) { 158 return false; 159 } 160 161 if (val.isInt32()) { 162 type = tInt; 163 } else if (val.isDouble()) { 164 type = tDbl; 165 } else if (val.isBoolean()) { 166 type = tBool; 167 } else if (val.isUndefined() || val.isSymbol() || val.isBigInt()) { 168 state = tVar; 169 break; 170 } else if (val.isNull()) { 171 type = tNull; 172 } else if (val.isString()) { 173 type = tStr; 174 } else { 175 MOZ_RELEASE_ASSERT(val.isObject(), "invalid type of jsval!"); 176 jsobj = &val.toObject(); 177 178 bool isArray; 179 if (!JS::IsArrayObject(cx, jsobj, &isArray)) { 180 return false; 181 } 182 183 if (isArray) { 184 type = tArr; 185 } else if (xpc::JSValue2ID(cx, val)) { 186 type = tID; 187 } else { 188 type = tISup; 189 } 190 } 191 192 MOZ_ASSERT(state != tErr, "bad state table!"); 193 MOZ_ASSERT(type != tErr, "bad type!"); 194 MOZ_ASSERT(type != tVar, "bad type!"); 195 MOZ_ASSERT(type != tUnk, "bad type!"); 196 197 state = StateTable[state][type]; 198 199 MOZ_ASSERT(state != tErr, "bad state table!"); 200 MOZ_ASSERT(state != tUnk, "bad state table!"); 201 202 if (state == tVar) { 203 break; 204 } 205 } 206 207 switch (state) { 208 case tInt: 209 *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INT32); 210 break; 211 case tDbl: 212 *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::DOUBLE); 213 break; 214 case tBool: 215 *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::BOOL); 216 break; 217 case tStr: 218 *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::PWSTRING); 219 break; 220 case tID: 221 *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::NSIDPTR); 222 break; 223 case tISup: 224 *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INTERFACE_IS_TYPE); 225 *resultID = NS_GET_IID(nsISupports); 226 break; 227 case tNull: 228 // FALL THROUGH 229 case tVar: 230 *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INTERFACE_IS_TYPE); 231 *resultID = NS_GET_IID(nsIVariant); 232 break; 233 case tArr: 234 // FALL THROUGH 235 case tUnk: 236 // FALL THROUGH 237 case tErr: 238 // FALL THROUGH 239 default: 240 NS_ERROR("bad state"); 241 return false; 242 } 243 return true; 244 } 245 246 bool XPCVariant::InitializeData(JSContext* cx) { 247 js::AutoCheckRecursionLimit recursion(cx); 248 if (!recursion.check(cx)) { 249 return false; 250 } 251 252 RootedValue val(cx, GetJSVal()); 253 254 if (val.isInt32()) { 255 mData.SetFromInt32(val.toInt32()); 256 return true; 257 } 258 if (val.isDouble()) { 259 mData.SetFromDouble(val.toDouble()); 260 return true; 261 } 262 if (val.isBoolean()) { 263 mData.SetFromBool(val.toBoolean()); 264 return true; 265 } 266 // We can't represent symbol or BigInt on C++ side, so pretend it is void. 267 if (val.isUndefined() || val.isSymbol() || val.isBigInt()) { 268 mData.SetToVoid(); 269 return true; 270 } 271 if (val.isNull()) { 272 mData.SetToEmpty(); 273 return true; 274 } 275 if (val.isString()) { 276 RootedString str(cx, val.toString()); 277 if (!str) { 278 return false; 279 } 280 281 MOZ_ASSERT(mData.GetType() == nsIDataType::VTYPE_EMPTY, 282 "Why do we already have data?"); 283 284 size_t length = JS_GetStringLength(str); 285 mData.AllocateWStringWithSize(length); 286 287 mozilla::Range<char16_t> destChars(mData.u.wstr.mWStringValue, length); 288 if (!JS_CopyStringChars(cx, destChars, str)) { 289 return false; 290 } 291 292 MOZ_ASSERT(mData.u.wstr.mWStringValue[length] == '\0'); 293 return true; 294 } 295 if (Maybe<nsID> id = xpc::JSValue2ID(cx, val)) { 296 mData.SetFromID(id.ref()); 297 return true; 298 } 299 300 // leaving only JSObject... 301 MOZ_RELEASE_ASSERT(val.isObject(), "invalid type of jsval!"); 302 303 RootedObject jsobj(cx, &val.toObject()); 304 305 // Let's see if it is a js array object. 306 307 uint32_t len; 308 309 bool isArray; 310 if (!JS::IsArrayObject(cx, jsobj, &isArray) || 311 (isArray && !JS::GetArrayLength(cx, jsobj, &len))) { 312 return false; 313 } 314 315 if (isArray) { 316 if (!len) { 317 // Zero length array 318 mData.SetToEmptyArray(); 319 return true; 320 } 321 322 nsXPTType type; 323 nsID id; 324 325 if (!XPCArrayHomogenizer::GetTypeForArray(cx, jsobj, len, &type, &id)) { 326 return false; 327 } 328 329 if (!XPCConvert::JSData2Native(cx, &mData.u.array.mArrayValue, val, type, 330 &id, len, nullptr)) 331 return false; 332 333 const nsXPTType& elty = type.ArrayElementType(); 334 mData.mType = nsIDataType::VTYPE_ARRAY; 335 if (elty.IsInterfacePointer()) { 336 mData.u.array.mArrayInterfaceID = id; 337 } 338 mData.u.array.mArrayCount = len; 339 mData.u.array.mArrayType = elty.Tag(); 340 341 return true; 342 } 343 344 // XXX This could be smarter and pick some more interesting iface. 345 346 nsIXPConnect* xpc = nsIXPConnect::XPConnect(); 347 nsCOMPtr<nsISupports> wrapper; 348 const nsIID& iid = NS_GET_IID(nsISupports); 349 350 if (NS_FAILED(xpc->WrapJS(cx, jsobj, iid, getter_AddRefs(wrapper)))) { 351 return false; 352 } 353 354 mData.SetFromInterface(iid, wrapper); 355 return true; 356 } 357 358 NS_IMETHODIMP 359 XPCVariant::GetAsJSVal(MutableHandleValue result) { 360 result.set(GetJSVal()); 361 return NS_OK; 362 } 363 364 // static 365 bool XPCVariant::VariantDataToJS(JSContext* cx, nsIVariant* variant, 366 nsresult* pErr, MutableHandleValue pJSVal) { 367 // Get the type early because we might need to spoof it below. 368 uint16_t type = variant->GetDataType(); 369 370 RootedValue realVal(cx); 371 nsresult rv = variant->GetAsJSVal(&realVal); 372 373 if (NS_SUCCEEDED(rv) && 374 (realVal.isPrimitive() || type == nsIDataType::VTYPE_ARRAY || 375 type == nsIDataType::VTYPE_EMPTY_ARRAY || 376 type == nsIDataType::VTYPE_ID)) { 377 if (!JS_WrapValue(cx, &realVal)) { 378 return false; 379 } 380 pJSVal.set(realVal); 381 return true; 382 } 383 384 nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant); 385 if (xpcvariant && xpcvariant->mReturnRawObject) { 386 MOZ_ASSERT(type == nsIDataType::VTYPE_INTERFACE || 387 type == nsIDataType::VTYPE_INTERFACE_IS, 388 "Weird variant"); 389 390 if (!JS_WrapValue(cx, &realVal)) { 391 return false; 392 } 393 pJSVal.set(realVal); 394 return true; 395 } 396 397 // else, it's an object and we really need to double wrap it if we've 398 // already decided that its 'natural' type is as some sort of interface. 399 400 // We just fall through to the code below and let it do what it does. 401 402 // The nsIVariant is not a XPCVariant (or we act like it isn't). 403 // So we extract the data and do the Right Thing. 404 405 // We ASSUME that the variant implementation can do these conversions... 406 407 nsID iid; 408 409 switch (type) { 410 case nsIDataType::VTYPE_INT8: 411 case nsIDataType::VTYPE_INT16: 412 case nsIDataType::VTYPE_INT32: 413 case nsIDataType::VTYPE_INT64: 414 case nsIDataType::VTYPE_UINT8: 415 case nsIDataType::VTYPE_UINT16: 416 case nsIDataType::VTYPE_UINT32: 417 case nsIDataType::VTYPE_UINT64: 418 case nsIDataType::VTYPE_FLOAT: 419 case nsIDataType::VTYPE_DOUBLE: { 420 double d; 421 if (NS_FAILED(variant->GetAsDouble(&d))) { 422 return false; 423 } 424 pJSVal.set(JS_NumberValue(d)); 425 return true; 426 } 427 case nsIDataType::VTYPE_BOOL: { 428 bool b; 429 if (NS_FAILED(variant->GetAsBool(&b))) { 430 return false; 431 } 432 pJSVal.setBoolean(b); 433 return true; 434 } 435 case nsIDataType::VTYPE_CHAR: { 436 char c; 437 if (NS_FAILED(variant->GetAsChar(&c))) { 438 return false; 439 } 440 return XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&c, {TD_CHAR}, 441 &iid, 0, pErr); 442 } 443 case nsIDataType::VTYPE_WCHAR: { 444 char16_t wc; 445 if (NS_FAILED(variant->GetAsWChar(&wc))) { 446 return false; 447 } 448 return XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&wc, {TD_WCHAR}, 449 &iid, 0, pErr); 450 } 451 case nsIDataType::VTYPE_ID: { 452 if (NS_FAILED(variant->GetAsID(&iid))) { 453 return false; 454 } 455 nsID* v = &iid; 456 return XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&v, 457 {TD_NSIDPTR}, &iid, 0, pErr); 458 } 459 case nsIDataType::VTYPE_ASTRING: { 460 nsAutoString astring; 461 if (NS_FAILED(variant->GetAsAString(astring))) { 462 return false; 463 } 464 return XPCConvert::NativeData2JS(cx, pJSVal, &astring, {TD_ASTRING}, &iid, 465 0, pErr); 466 } 467 case nsIDataType::VTYPE_CSTRING: { 468 nsAutoCString cString; 469 if (NS_FAILED(variant->GetAsACString(cString))) { 470 return false; 471 } 472 return XPCConvert::NativeData2JS(cx, pJSVal, &cString, {TD_CSTRING}, &iid, 473 0, pErr); 474 } 475 case nsIDataType::VTYPE_UTF8STRING: { 476 nsUTF8String utf8String; 477 if (NS_FAILED(variant->GetAsAUTF8String(utf8String))) { 478 return false; 479 } 480 return XPCConvert::NativeData2JS(cx, pJSVal, &utf8String, {TD_UTF8STRING}, 481 &iid, 0, pErr); 482 } 483 case nsIDataType::VTYPE_CHAR_STR: { 484 char* pc; 485 if (NS_FAILED(variant->GetAsString(&pc))) { 486 return false; 487 } 488 bool success = XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&pc, 489 {TD_PSTRING}, &iid, 0, pErr); 490 free(pc); 491 return success; 492 } 493 case nsIDataType::VTYPE_STRING_SIZE_IS: { 494 char* pc; 495 uint32_t size; 496 if (NS_FAILED(variant->GetAsStringWithSize(&size, &pc))) { 497 return false; 498 } 499 bool success = XPCConvert::NativeData2JS( 500 cx, pJSVal, (const void*)&pc, {TD_PSTRING_SIZE_IS}, &iid, size, pErr); 501 free(pc); 502 return success; 503 } 504 case nsIDataType::VTYPE_WCHAR_STR: { 505 char16_t* pwc; 506 if (NS_FAILED(variant->GetAsWString(&pwc))) { 507 return false; 508 } 509 bool success = XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&pwc, 510 {TD_PSTRING}, &iid, 0, pErr); 511 free(pwc); 512 return success; 513 } 514 case nsIDataType::VTYPE_WSTRING_SIZE_IS: { 515 char16_t* pwc; 516 uint32_t size; 517 if (NS_FAILED(variant->GetAsWStringWithSize(&size, &pwc))) { 518 return false; 519 } 520 bool success = 521 XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&pwc, 522 {TD_PWSTRING_SIZE_IS}, &iid, size, pErr); 523 free(pwc); 524 return success; 525 } 526 case nsIDataType::VTYPE_INTERFACE: 527 case nsIDataType::VTYPE_INTERFACE_IS: { 528 nsISupports* pi; 529 nsID* piid; 530 if (NS_FAILED(variant->GetAsInterface(&piid, (void**)&pi))) { 531 return false; 532 } 533 534 iid = *piid; 535 free((char*)piid); 536 537 bool success = XPCConvert::NativeData2JS( 538 cx, pJSVal, (const void*)&pi, {TD_INTERFACE_IS_TYPE}, &iid, 0, pErr); 539 if (pi) { 540 pi->Release(); 541 } 542 return success; 543 } 544 case nsIDataType::VTYPE_ARRAY: { 545 nsDiscriminatedUnion du; 546 nsresult rv; 547 548 rv = variant->GetAsArray( 549 &du.u.array.mArrayType, &du.u.array.mArrayInterfaceID, 550 &du.u.array.mArrayCount, &du.u.array.mArrayValue); 551 if (NS_FAILED(rv)) { 552 return false; 553 } 554 555 // must exit via VARIANT_DONE from here on... 556 du.mType = nsIDataType::VTYPE_ARRAY; 557 558 uint16_t elementType = du.u.array.mArrayType; 559 const nsID* pid = nullptr; 560 561 nsXPTType::Idx xptIndex; 562 switch (elementType) { 563 case nsIDataType::VTYPE_INT8: 564 xptIndex = nsXPTType::Idx::INT8; 565 break; 566 case nsIDataType::VTYPE_INT16: 567 xptIndex = nsXPTType::Idx::INT16; 568 break; 569 case nsIDataType::VTYPE_INT32: 570 xptIndex = nsXPTType::Idx::INT32; 571 break; 572 case nsIDataType::VTYPE_INT64: 573 xptIndex = nsXPTType::Idx::INT64; 574 break; 575 case nsIDataType::VTYPE_UINT8: 576 xptIndex = nsXPTType::Idx::UINT8; 577 break; 578 case nsIDataType::VTYPE_UINT16: 579 xptIndex = nsXPTType::Idx::UINT16; 580 break; 581 case nsIDataType::VTYPE_UINT32: 582 xptIndex = nsXPTType::Idx::UINT32; 583 break; 584 case nsIDataType::VTYPE_UINT64: 585 xptIndex = nsXPTType::Idx::UINT64; 586 break; 587 case nsIDataType::VTYPE_FLOAT: 588 xptIndex = nsXPTType::Idx::FLOAT; 589 break; 590 case nsIDataType::VTYPE_DOUBLE: 591 xptIndex = nsXPTType::Idx::DOUBLE; 592 break; 593 case nsIDataType::VTYPE_BOOL: 594 xptIndex = nsXPTType::Idx::BOOL; 595 break; 596 case nsIDataType::VTYPE_CHAR: 597 xptIndex = nsXPTType::Idx::CHAR; 598 break; 599 case nsIDataType::VTYPE_WCHAR: 600 xptIndex = nsXPTType::Idx::WCHAR; 601 break; 602 case nsIDataType::VTYPE_ID: 603 xptIndex = nsXPTType::Idx::NSIDPTR; 604 break; 605 case nsIDataType::VTYPE_CHAR_STR: 606 xptIndex = nsXPTType::Idx::PSTRING; 607 break; 608 case nsIDataType::VTYPE_WCHAR_STR: 609 xptIndex = nsXPTType::Idx::PWSTRING; 610 break; 611 case nsIDataType::VTYPE_INTERFACE: 612 pid = &NS_GET_IID(nsISupports); 613 xptIndex = nsXPTType::Idx::INTERFACE_IS_TYPE; 614 break; 615 case nsIDataType::VTYPE_INTERFACE_IS: 616 pid = &du.u.array.mArrayInterfaceID; 617 xptIndex = nsXPTType::Idx::INTERFACE_IS_TYPE; 618 break; 619 620 // The rest are illegal. 621 case nsIDataType::VTYPE_VOID: 622 case nsIDataType::VTYPE_ASTRING: 623 case nsIDataType::VTYPE_CSTRING: 624 case nsIDataType::VTYPE_UTF8STRING: 625 case nsIDataType::VTYPE_WSTRING_SIZE_IS: 626 case nsIDataType::VTYPE_STRING_SIZE_IS: 627 case nsIDataType::VTYPE_ARRAY: 628 case nsIDataType::VTYPE_EMPTY_ARRAY: 629 case nsIDataType::VTYPE_EMPTY: 630 default: 631 NS_ERROR("bad type in array!"); 632 return false; 633 } 634 635 bool success = XPCConvert::NativeData2JS( 636 cx, pJSVal, (const void*)&du.u.array.mArrayValue, 637 nsXPTType::MkArrayType(xptIndex), pid, du.u.array.mArrayCount, pErr); 638 639 return success; 640 } 641 case nsIDataType::VTYPE_EMPTY_ARRAY: { 642 JSObject* array = JS::NewArrayObject(cx, 0); 643 if (!array) { 644 return false; 645 } 646 pJSVal.setObject(*array); 647 return true; 648 } 649 case nsIDataType::VTYPE_VOID: 650 pJSVal.setUndefined(); 651 return true; 652 case nsIDataType::VTYPE_EMPTY: 653 pJSVal.setNull(); 654 return true; 655 default: 656 NS_ERROR("bad type in variant!"); 657 return false; 658 } 659 } 660 661 /***************************************************************************/ 662 /***************************************************************************/ 663 // XXX These default implementations need to be improved to allow for 664 // some more interesting conversions. 665 666 uint16_t XPCVariant::GetDataType() { return mData.GetType(); } 667 668 NS_IMETHODIMP XPCVariant::GetAsInt8(uint8_t* _retval) { 669 return mData.ConvertToInt8(_retval); 670 } 671 672 NS_IMETHODIMP XPCVariant::GetAsInt16(int16_t* _retval) { 673 return mData.ConvertToInt16(_retval); 674 } 675 676 NS_IMETHODIMP XPCVariant::GetAsInt32(int32_t* _retval) { 677 return mData.ConvertToInt32(_retval); 678 } 679 680 NS_IMETHODIMP XPCVariant::GetAsInt64(int64_t* _retval) { 681 return mData.ConvertToInt64(_retval); 682 } 683 684 NS_IMETHODIMP XPCVariant::GetAsUint8(uint8_t* _retval) { 685 return mData.ConvertToUint8(_retval); 686 } 687 688 NS_IMETHODIMP XPCVariant::GetAsUint16(uint16_t* _retval) { 689 return mData.ConvertToUint16(_retval); 690 } 691 692 NS_IMETHODIMP XPCVariant::GetAsUint32(uint32_t* _retval) { 693 return mData.ConvertToUint32(_retval); 694 } 695 696 NS_IMETHODIMP XPCVariant::GetAsUint64(uint64_t* _retval) { 697 return mData.ConvertToUint64(_retval); 698 } 699 700 NS_IMETHODIMP XPCVariant::GetAsFloat(float* _retval) { 701 return mData.ConvertToFloat(_retval); 702 } 703 704 NS_IMETHODIMP XPCVariant::GetAsDouble(double* _retval) { 705 return mData.ConvertToDouble(_retval); 706 } 707 708 NS_IMETHODIMP XPCVariant::GetAsBool(bool* _retval) { 709 return mData.ConvertToBool(_retval); 710 } 711 712 NS_IMETHODIMP XPCVariant::GetAsChar(char* _retval) { 713 return mData.ConvertToChar(_retval); 714 } 715 716 NS_IMETHODIMP XPCVariant::GetAsWChar(char16_t* _retval) { 717 return mData.ConvertToWChar(_retval); 718 } 719 720 NS_IMETHODIMP_(nsresult) XPCVariant::GetAsID(nsID* retval) { 721 return mData.ConvertToID(retval); 722 } 723 724 NS_IMETHODIMP XPCVariant::GetAsAString(nsAString& _retval) { 725 return mData.ConvertToAString(_retval); 726 } 727 728 NS_IMETHODIMP XPCVariant::GetAsACString(nsACString& _retval) { 729 return mData.ConvertToACString(_retval); 730 } 731 732 NS_IMETHODIMP XPCVariant::GetAsAUTF8String(nsAUTF8String& _retval) { 733 return mData.ConvertToAUTF8String(_retval); 734 } 735 736 NS_IMETHODIMP XPCVariant::GetAsString(char** _retval) { 737 return mData.ConvertToString(_retval); 738 } 739 740 NS_IMETHODIMP XPCVariant::GetAsWString(char16_t** _retval) { 741 return mData.ConvertToWString(_retval); 742 } 743 744 NS_IMETHODIMP XPCVariant::GetAsISupports(nsISupports** _retval) { 745 return mData.ConvertToISupports(_retval); 746 } 747 748 NS_IMETHODIMP XPCVariant::GetAsInterface(nsIID** iid, void** iface) { 749 return mData.ConvertToInterface(iid, iface); 750 } 751 752 NS_IMETHODIMP_(nsresult) 753 XPCVariant::GetAsArray(uint16_t* type, nsIID* iid, uint32_t* count, 754 void** ptr) { 755 return mData.ConvertToArray(type, iid, count, ptr); 756 } 757 758 NS_IMETHODIMP XPCVariant::GetAsStringWithSize(uint32_t* size, char** str) { 759 return mData.ConvertToStringWithSize(size, str); 760 } 761 762 NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(uint32_t* size, char16_t** str) { 763 return mData.ConvertToWStringWithSize(size, str); 764 }