js/xpconnect/src/XPCJSID.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* An xpcom implementation of the JavaScript nsIID and nsCID objects. */
michael@0 8
michael@0 9 #include "xpcprivate.h"
michael@0 10 #include "mozilla/dom/BindingUtils.h"
michael@0 11 #include "mozilla/Attributes.h"
michael@0 12 #include "JavaScriptParent.h"
michael@0 13 #include "mozilla/StaticPtr.h"
michael@0 14
michael@0 15 using namespace mozilla::dom;
michael@0 16 using namespace JS;
michael@0 17
michael@0 18 /***************************************************************************/
michael@0 19 // nsJSID
michael@0 20
michael@0 21 NS_IMPL_CLASSINFO(nsJSID, nullptr, 0, NS_JS_ID_CID)
michael@0 22 NS_IMPL_ISUPPORTS_CI(nsJSID, nsIJSID)
michael@0 23
michael@0 24 char nsJSID::gNoString[] = "";
michael@0 25
michael@0 26 nsJSID::nsJSID()
michael@0 27 : mID(GetInvalidIID()), mNumber(gNoString), mName(gNoString)
michael@0 28 {
michael@0 29 }
michael@0 30
michael@0 31 nsJSID::~nsJSID()
michael@0 32 {
michael@0 33 if (mNumber && mNumber != gNoString)
michael@0 34 NS_Free(mNumber);
michael@0 35 if (mName && mName != gNoString)
michael@0 36 NS_Free(mName);
michael@0 37 }
michael@0 38
michael@0 39 void nsJSID::Reset()
michael@0 40 {
michael@0 41 mID = GetInvalidIID();
michael@0 42
michael@0 43 if (mNumber && mNumber != gNoString)
michael@0 44 NS_Free(mNumber);
michael@0 45 if (mName && mName != gNoString)
michael@0 46 NS_Free(mName);
michael@0 47
michael@0 48 mNumber = mName = nullptr;
michael@0 49 }
michael@0 50
michael@0 51 bool
michael@0 52 nsJSID::SetName(const char* name)
michael@0 53 {
michael@0 54 MOZ_ASSERT(!mName || mName == gNoString ,"name already set");
michael@0 55 MOZ_ASSERT(name,"null name");
michael@0 56 mName = NS_strdup(name);
michael@0 57 return mName ? true : false;
michael@0 58 }
michael@0 59
michael@0 60 NS_IMETHODIMP
michael@0 61 nsJSID::GetName(char * *aName)
michael@0 62 {
michael@0 63 if (!aName)
michael@0 64 return NS_ERROR_NULL_POINTER;
michael@0 65
michael@0 66 if (!NameIsSet())
michael@0 67 SetNameToNoString();
michael@0 68 MOZ_ASSERT(mName, "name not set");
michael@0 69 *aName = NS_strdup(mName);
michael@0 70 return *aName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
michael@0 71 }
michael@0 72
michael@0 73 NS_IMETHODIMP
michael@0 74 nsJSID::GetNumber(char * *aNumber)
michael@0 75 {
michael@0 76 if (!aNumber)
michael@0 77 return NS_ERROR_NULL_POINTER;
michael@0 78
michael@0 79 if (!mNumber) {
michael@0 80 if (!(mNumber = mID.ToString()))
michael@0 81 mNumber = gNoString;
michael@0 82 }
michael@0 83
michael@0 84 *aNumber = NS_strdup(mNumber);
michael@0 85 return *aNumber ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
michael@0 86 }
michael@0 87
michael@0 88 NS_IMETHODIMP_(const nsID*)
michael@0 89 nsJSID::GetID()
michael@0 90 {
michael@0 91 return &mID;
michael@0 92 }
michael@0 93
michael@0 94 NS_IMETHODIMP
michael@0 95 nsJSID::GetValid(bool *aValid)
michael@0 96 {
michael@0 97 if (!aValid)
michael@0 98 return NS_ERROR_NULL_POINTER;
michael@0 99
michael@0 100 *aValid = IsValid();
michael@0 101 return NS_OK;
michael@0 102 }
michael@0 103
michael@0 104 NS_IMETHODIMP
michael@0 105 nsJSID::Equals(nsIJSID *other, bool *_retval)
michael@0 106 {
michael@0 107 if (!_retval)
michael@0 108 return NS_ERROR_NULL_POINTER;
michael@0 109
michael@0 110 if (!other || mID.Equals(GetInvalidIID())) {
michael@0 111 *_retval = false;
michael@0 112 return NS_OK;
michael@0 113 }
michael@0 114
michael@0 115 *_retval = other->GetID()->Equals(mID);
michael@0 116 return NS_OK;
michael@0 117 }
michael@0 118
michael@0 119 NS_IMETHODIMP
michael@0 120 nsJSID::Initialize(const char *idString)
michael@0 121 {
michael@0 122 if (!idString)
michael@0 123 return NS_ERROR_NULL_POINTER;
michael@0 124
michael@0 125 if (*idString != '\0' && mID.Equals(GetInvalidIID())) {
michael@0 126 Reset();
michael@0 127
michael@0 128 if (idString[0] == '{') {
michael@0 129 if (mID.Parse(idString)) {
michael@0 130 return NS_OK;
michael@0 131 }
michael@0 132
michael@0 133 // error - reset to invalid state
michael@0 134 mID = GetInvalidIID();
michael@0 135 }
michael@0 136 }
michael@0 137 return NS_ERROR_FAILURE;
michael@0 138 }
michael@0 139
michael@0 140 bool
michael@0 141 nsJSID::InitWithName(const nsID& id, const char *nameString)
michael@0 142 {
michael@0 143 MOZ_ASSERT(nameString, "no name");
michael@0 144 Reset();
michael@0 145 mID = id;
michael@0 146 return SetName(nameString);
michael@0 147 }
michael@0 148
michael@0 149 // try to use the name, if no name, then use the number
michael@0 150 NS_IMETHODIMP
michael@0 151 nsJSID::ToString(char **_retval)
michael@0 152 {
michael@0 153 if (mName && mName != gNoString)
michael@0 154 return GetName(_retval);
michael@0 155
michael@0 156 return GetNumber(_retval);
michael@0 157 }
michael@0 158
michael@0 159 const nsID&
michael@0 160 nsJSID::GetInvalidIID() const
michael@0 161 {
michael@0 162 // {BB1F47B0-D137-11d2-9841-006008962422}
michael@0 163 static const nsID invalid = {0xbb1f47b0, 0xd137, 0x11d2,
michael@0 164 {0x98, 0x41, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22}};
michael@0 165 return invalid;
michael@0 166 }
michael@0 167
michael@0 168 //static
michael@0 169 already_AddRefed<nsJSID>
michael@0 170 nsJSID::NewID(const char* str)
michael@0 171 {
michael@0 172 if (!str) {
michael@0 173 NS_ERROR("no string");
michael@0 174 return nullptr;
michael@0 175 }
michael@0 176
michael@0 177 nsRefPtr<nsJSID> idObj = new nsJSID();
michael@0 178 NS_ENSURE_SUCCESS(idObj->Initialize(str), nullptr);
michael@0 179 return idObj.forget();
michael@0 180 }
michael@0 181
michael@0 182 //static
michael@0 183 already_AddRefed<nsJSID>
michael@0 184 nsJSID::NewID(const nsID& id)
michael@0 185 {
michael@0 186 nsRefPtr<nsJSID> idObj = new nsJSID();
michael@0 187 idObj->mID = id;
michael@0 188 idObj->mName = nullptr;
michael@0 189 idObj->mNumber = nullptr;
michael@0 190 return idObj.forget();
michael@0 191 }
michael@0 192
michael@0 193
michael@0 194 /***************************************************************************/
michael@0 195 // Class object support so that we can share prototypes of wrapper
michael@0 196
michael@0 197 // This class exists just so we can have a shared scriptable helper for
michael@0 198 // the nsJSIID class. The instances implement their own helpers. But we
michael@0 199 // needed to be able to indicate to the shared prototypes this single flag:
michael@0 200 // nsIXPCScriptable::DONT_ENUM_STATIC_PROPS. And having a class to do it is
michael@0 201 // the only means we have. Setting this flag on any given instance scriptable
michael@0 202 // helper is not sufficient to convey the information that we don't want
michael@0 203 // static properties enumerated on the shared proto.
michael@0 204
michael@0 205 class SharedScriptableHelperForJSIID MOZ_FINAL : public nsIXPCScriptable
michael@0 206 {
michael@0 207 public:
michael@0 208 NS_DECL_ISUPPORTS
michael@0 209 NS_DECL_NSIXPCSCRIPTABLE
michael@0 210 SharedScriptableHelperForJSIID() {}
michael@0 211 };
michael@0 212
michael@0 213 NS_INTERFACE_MAP_BEGIN(SharedScriptableHelperForJSIID)
michael@0 214 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
michael@0 215 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCScriptable)
michael@0 216 NS_INTERFACE_MAP_END
michael@0 217
michael@0 218 NS_IMPL_ADDREF(SharedScriptableHelperForJSIID)
michael@0 219 NS_IMPL_RELEASE(SharedScriptableHelperForJSIID)
michael@0 220
michael@0 221 // The nsIXPCScriptable map declaration that will generate stubs for us...
michael@0 222 #define XPC_MAP_CLASSNAME SharedScriptableHelperForJSIID
michael@0 223 #define XPC_MAP_QUOTED_CLASSNAME "JSIID"
michael@0 224 #define XPC_MAP_FLAGS nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |\
michael@0 225 nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE
michael@0 226 #include "xpc_map_end.h" /* This will #undef the above */
michael@0 227
michael@0 228 static mozilla::StaticRefPtr<nsIXPCScriptable> gSharedScriptableHelperForJSIID;
michael@0 229 static bool gClassObjectsWereInited = false;
michael@0 230
michael@0 231 static void EnsureClassObjectsInitialized()
michael@0 232 {
michael@0 233 if (!gClassObjectsWereInited) {
michael@0 234 gSharedScriptableHelperForJSIID = new SharedScriptableHelperForJSIID();
michael@0 235
michael@0 236 gClassObjectsWereInited = true;
michael@0 237 }
michael@0 238 }
michael@0 239
michael@0 240 NS_METHOD GetSharedScriptableHelperForJSIID(uint32_t language,
michael@0 241 nsISupports **helper)
michael@0 242 {
michael@0 243 EnsureClassObjectsInitialized();
michael@0 244 if (language == nsIProgrammingLanguage::JAVASCRIPT) {
michael@0 245 nsCOMPtr<nsIXPCScriptable> temp = gSharedScriptableHelperForJSIID.get();
michael@0 246 temp.forget(helper);
michael@0 247 } else
michael@0 248 *helper = nullptr;
michael@0 249 return NS_OK;
michael@0 250 }
michael@0 251
michael@0 252 /******************************************************/
michael@0 253
michael@0 254 #define NULL_CID \
michael@0 255 { 0x00000000, 0x0000, 0x0000, \
michael@0 256 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
michael@0 257
michael@0 258 // We pass nsIClassInfo::DOM_OBJECT so that nsJSIID instances may be created
michael@0 259 // in unprivileged scopes.
michael@0 260 NS_DECL_CI_INTERFACE_GETTER(nsJSIID)
michael@0 261 NS_IMPL_CLASSINFO(nsJSIID, GetSharedScriptableHelperForJSIID,
michael@0 262 nsIClassInfo::DOM_OBJECT, NULL_CID)
michael@0 263
michael@0 264 NS_DECL_CI_INTERFACE_GETTER(nsJSCID)
michael@0 265 NS_IMPL_CLASSINFO(nsJSCID, nullptr, 0, NULL_CID)
michael@0 266
michael@0 267 void xpc_DestroyJSxIDClassObjects()
michael@0 268 {
michael@0 269 if (gClassObjectsWereInited) {
michael@0 270 NS_IF_RELEASE(NS_CLASSINFO_NAME(nsJSIID));
michael@0 271 NS_IF_RELEASE(NS_CLASSINFO_NAME(nsJSCID));
michael@0 272 gSharedScriptableHelperForJSIID = nullptr;
michael@0 273
michael@0 274 gClassObjectsWereInited = false;
michael@0 275 }
michael@0 276 }
michael@0 277
michael@0 278 /***************************************************************************/
michael@0 279
michael@0 280 NS_INTERFACE_MAP_BEGIN(nsJSIID)
michael@0 281 NS_INTERFACE_MAP_ENTRY(nsIJSID)
michael@0 282 NS_INTERFACE_MAP_ENTRY(nsIJSIID)
michael@0 283 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
michael@0 284 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSID)
michael@0 285 NS_IMPL_QUERY_CLASSINFO(nsJSIID)
michael@0 286 NS_INTERFACE_MAP_END
michael@0 287
michael@0 288 NS_IMPL_ADDREF(nsJSIID)
michael@0 289 NS_IMPL_RELEASE(nsJSIID)
michael@0 290 NS_IMPL_CI_INTERFACE_GETTER(nsJSIID, nsIJSID, nsIJSIID)
michael@0 291
michael@0 292 // The nsIXPCScriptable map declaration that will generate stubs for us...
michael@0 293 #define XPC_MAP_CLASSNAME nsJSIID
michael@0 294 #define XPC_MAP_QUOTED_CLASSNAME "nsJSIID"
michael@0 295 #define XPC_MAP_WANT_NEWRESOLVE
michael@0 296 #define XPC_MAP_WANT_ENUMERATE
michael@0 297 #define XPC_MAP_WANT_HASINSTANCE
michael@0 298 #define XPC_MAP_FLAGS nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |\
michael@0 299 nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE
michael@0 300 #include "xpc_map_end.h" /* This will #undef the above */
michael@0 301
michael@0 302
michael@0 303 nsJSIID::nsJSIID(nsIInterfaceInfo* aInfo)
michael@0 304 : mInfo(aInfo)
michael@0 305 {
michael@0 306 }
michael@0 307
michael@0 308 nsJSIID::~nsJSIID() {}
michael@0 309
michael@0 310 // If mInfo is present we use it and ignore mDetails, else we use mDetails.
michael@0 311
michael@0 312 NS_IMETHODIMP nsJSIID::GetName(char * *aName)
michael@0 313 {
michael@0 314 return mInfo->GetName(aName);
michael@0 315 }
michael@0 316
michael@0 317 NS_IMETHODIMP nsJSIID::GetNumber(char * *aNumber)
michael@0 318 {
michael@0 319 char str[NSID_LENGTH];
michael@0 320 const nsIID* id;
michael@0 321 mInfo->GetIIDShared(&id);
michael@0 322 id->ToProvidedString(str);
michael@0 323 *aNumber = (char*) nsMemory::Clone(str, NSID_LENGTH);
michael@0 324 return *aNumber ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
michael@0 325 }
michael@0 326
michael@0 327 NS_IMETHODIMP_(const nsID*) nsJSIID::GetID()
michael@0 328 {
michael@0 329 const nsIID* id;
michael@0 330 mInfo->GetIIDShared(&id);
michael@0 331 return id;
michael@0 332 }
michael@0 333
michael@0 334 NS_IMETHODIMP nsJSIID::GetValid(bool *aValid)
michael@0 335 {
michael@0 336 *aValid = true;
michael@0 337 return NS_OK;
michael@0 338 }
michael@0 339
michael@0 340 NS_IMETHODIMP nsJSIID::Equals(nsIJSID *other, bool *_retval)
michael@0 341 {
michael@0 342 if (!_retval)
michael@0 343 return NS_ERROR_NULL_POINTER;
michael@0 344
michael@0 345 if (!other) {
michael@0 346 *_retval = false;
michael@0 347 return NS_OK;
michael@0 348 }
michael@0 349
michael@0 350 mInfo->IsIID(other->GetID(), _retval);
michael@0 351 return NS_OK;
michael@0 352 }
michael@0 353
michael@0 354 NS_IMETHODIMP nsJSIID::Initialize(const char *idString)
michael@0 355 {
michael@0 356 return NS_ERROR_FAILURE;
michael@0 357 }
michael@0 358
michael@0 359 NS_IMETHODIMP nsJSIID::ToString(char **_retval)
michael@0 360 {
michael@0 361 return mInfo->GetName(_retval);
michael@0 362 }
michael@0 363
michael@0 364 // static
michael@0 365 already_AddRefed<nsJSIID>
michael@0 366 nsJSIID::NewID(nsIInterfaceInfo* aInfo)
michael@0 367 {
michael@0 368 if (!aInfo) {
michael@0 369 NS_ERROR("no info");
michael@0 370 return nullptr;
michael@0 371 }
michael@0 372
michael@0 373 bool canScript;
michael@0 374 if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
michael@0 375 return nullptr;
michael@0 376
michael@0 377 nsRefPtr<nsJSIID> idObj = new nsJSIID(aInfo);
michael@0 378 return idObj.forget();
michael@0 379 }
michael@0 380
michael@0 381
michael@0 382 /* bool resolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id); */
michael@0 383 NS_IMETHODIMP
michael@0 384 nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper,
michael@0 385 JSContext * cx, JSObject * objArg,
michael@0 386 jsid idArg, JSObject * *objp,
michael@0 387 bool *_retval)
michael@0 388 {
michael@0 389 RootedObject obj(cx, objArg);
michael@0 390 RootedId id(cx, idArg);
michael@0 391 XPCCallContext ccx(JS_CALLER, cx);
michael@0 392
michael@0 393 AutoMarkingNativeInterfacePtr iface(ccx);
michael@0 394
michael@0 395 const nsIID* iid;
michael@0 396 mInfo->GetIIDShared(&iid);
michael@0 397
michael@0 398 iface = XPCNativeInterface::GetNewOrUsed(iid);
michael@0 399
michael@0 400 if (!iface)
michael@0 401 return NS_OK;
michael@0 402
michael@0 403 XPCNativeMember* member = iface->FindMember(id);
michael@0 404 if (member && member->IsConstant()) {
michael@0 405 RootedValue val(cx);
michael@0 406 if (!member->GetConstantValue(ccx, iface, val.address()))
michael@0 407 return NS_ERROR_OUT_OF_MEMORY;
michael@0 408
michael@0 409 *objp = obj;
michael@0 410 *_retval = JS_DefinePropertyById(cx, obj, id, val, nullptr, nullptr,
michael@0 411 JSPROP_ENUMERATE | JSPROP_READONLY |
michael@0 412 JSPROP_PERMANENT);
michael@0 413 }
michael@0 414
michael@0 415 return NS_OK;
michael@0 416 }
michael@0 417
michael@0 418 /* bool enumerate (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj); */
michael@0 419 NS_IMETHODIMP
michael@0 420 nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper,
michael@0 421 JSContext * cx, JSObject * objArg, bool *_retval)
michael@0 422 {
michael@0 423 // In this case, let's just eagerly resolve...
michael@0 424
michael@0 425 RootedObject obj(cx, objArg);
michael@0 426 XPCCallContext ccx(JS_CALLER, cx);
michael@0 427
michael@0 428 AutoMarkingNativeInterfacePtr iface(ccx);
michael@0 429
michael@0 430 const nsIID* iid;
michael@0 431 mInfo->GetIIDShared(&iid);
michael@0 432
michael@0 433 iface = XPCNativeInterface::GetNewOrUsed(iid);
michael@0 434
michael@0 435 if (!iface)
michael@0 436 return NS_OK;
michael@0 437
michael@0 438 uint16_t count = iface->GetMemberCount();
michael@0 439 for (uint16_t i = 0; i < count; i++) {
michael@0 440 XPCNativeMember* member = iface->GetMemberAt(i);
michael@0 441 if (member && member->IsConstant() &&
michael@0 442 !xpc_ForcePropertyResolve(cx, obj, member->GetName())) {
michael@0 443 return NS_ERROR_UNEXPECTED;
michael@0 444 }
michael@0 445 }
michael@0 446 return NS_OK;
michael@0 447 }
michael@0 448
michael@0 449 /*
michael@0 450 * HasInstance hooks need to find an appropriate reflector in order to function
michael@0 451 * properly. There are two complexities that we need to handle:
michael@0 452 *
michael@0 453 * 1 - Cross-compartment wrappers. Chrome uses over 100 compartments, all with
michael@0 454 * system principal. The success of an instanceof check should not depend
michael@0 455 * on which compartment an object comes from. At the same time, we want to
michael@0 456 * make sure we don't unwrap important security wrappers.
michael@0 457 * CheckedUnwrap does the right thing here.
michael@0 458 *
michael@0 459 * 2 - Prototype chains. Suppose someone creates a vanilla JS object |a| and
michael@0 460 * sets its __proto__ to some WN |b|. If |b instanceof nsIFoo| returns true,
michael@0 461 * one would expect |a instanceof nsIFoo| to return true as well, since
michael@0 462 * instanceof is transitive up the prototype chain in ECMAScript. Moreover,
michael@0 463 * there's chrome code that relies on this.
michael@0 464 *
michael@0 465 * This static method handles both complexities, returning either an XPCWN, a
michael@0 466 * DOM object, or null. The object may well be cross-compartment from |cx|.
michael@0 467 */
michael@0 468 static JSObject *
michael@0 469 FindObjectForHasInstance(JSContext *cx, HandleObject objArg)
michael@0 470 {
michael@0 471 RootedObject obj(cx, objArg), proto(cx);
michael@0 472
michael@0 473 while (obj && !IS_WN_REFLECTOR(obj) &&
michael@0 474 !IsDOMObject(obj) && !mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
michael@0 475 {
michael@0 476 if (js::IsWrapper(obj)) {
michael@0 477 obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
michael@0 478 continue;
michael@0 479 }
michael@0 480 if (!js::GetObjectProto(cx, obj, &proto))
michael@0 481 return nullptr;
michael@0 482 obj = proto;
michael@0 483 }
michael@0 484 return obj;
michael@0 485 }
michael@0 486
michael@0 487 nsresult
michael@0 488 xpc::HasInstance(JSContext *cx, HandleObject objArg, const nsID *iid, bool *bp)
michael@0 489 {
michael@0 490 *bp = false;
michael@0 491
michael@0 492 RootedObject obj(cx, FindObjectForHasInstance(cx, objArg));
michael@0 493 if (!obj)
michael@0 494 return NS_OK;
michael@0 495
michael@0 496 if (IsDOMObject(obj)) {
michael@0 497 // Not all DOM objects implement nsISupports. But if they don't,
michael@0 498 // there's nothing to do in this HasInstance hook.
michael@0 499 nsISupports *identity = UnwrapDOMObjectToISupports(obj);
michael@0 500 if (!identity)
michael@0 501 return NS_OK;;
michael@0 502 nsCOMPtr<nsISupports> supp;
michael@0 503 identity->QueryInterface(*iid, getter_AddRefs(supp));
michael@0 504 *bp = supp;
michael@0 505 return NS_OK;
michael@0 506 }
michael@0 507
michael@0 508 if (mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
michael@0 509 return mozilla::jsipc::JavaScriptParent::InstanceOf(obj, iid, bp);
michael@0 510
michael@0 511 MOZ_ASSERT(IS_WN_REFLECTOR(obj));
michael@0 512 XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
michael@0 513 if (!other_wrapper)
michael@0 514 return NS_OK;
michael@0 515
michael@0 516 // We'll trust the interface set of the wrapper if this is known
michael@0 517 // to be an interface that the objects *expects* to be able to
michael@0 518 // handle.
michael@0 519 if (other_wrapper->HasInterfaceNoQI(*iid)) {
michael@0 520 *bp = true;
michael@0 521 return NS_OK;
michael@0 522 }
michael@0 523
michael@0 524 // Otherwise, we'll end up Querying the native object to be sure.
michael@0 525 XPCCallContext ccx(JS_CALLER, cx);
michael@0 526
michael@0 527 AutoMarkingNativeInterfacePtr iface(ccx);
michael@0 528 iface = XPCNativeInterface::GetNewOrUsed(iid);
michael@0 529
michael@0 530 nsresult findResult = NS_OK;
michael@0 531 if (iface && other_wrapper->FindTearOff(iface, false, &findResult))
michael@0 532 *bp = true;
michael@0 533 if (NS_FAILED(findResult) && findResult != NS_ERROR_NO_INTERFACE)
michael@0 534 return findResult;
michael@0 535
michael@0 536 return NS_OK;
michael@0 537 }
michael@0 538
michael@0 539 /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
michael@0 540 NS_IMETHODIMP
michael@0 541 nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
michael@0 542 JSContext *cx, JSObject * /* unused */,
michael@0 543 HandleValue val, bool *bp, bool *_retval)
michael@0 544 {
michael@0 545 *bp = false;
michael@0 546
michael@0 547 if (val.isPrimitive())
michael@0 548 return NS_OK;
michael@0 549
michael@0 550 // we have a JSObject
michael@0 551 RootedObject obj(cx, &val.toObject());
michael@0 552
michael@0 553 const nsIID* iid;
michael@0 554 mInfo->GetIIDShared(&iid);
michael@0 555 return xpc::HasInstance(cx, obj, iid, bp);
michael@0 556 }
michael@0 557
michael@0 558 /***************************************************************************/
michael@0 559
michael@0 560 NS_INTERFACE_MAP_BEGIN(nsJSCID)
michael@0 561 NS_INTERFACE_MAP_ENTRY(nsIJSID)
michael@0 562 NS_INTERFACE_MAP_ENTRY(nsIJSCID)
michael@0 563 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
michael@0 564 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSID)
michael@0 565 NS_IMPL_QUERY_CLASSINFO(nsJSCID)
michael@0 566 NS_INTERFACE_MAP_END
michael@0 567
michael@0 568 NS_IMPL_ADDREF(nsJSCID)
michael@0 569 NS_IMPL_RELEASE(nsJSCID)
michael@0 570 NS_IMPL_CI_INTERFACE_GETTER(nsJSCID, nsIJSID, nsIJSCID)
michael@0 571
michael@0 572 // The nsIXPCScriptable map declaration that will generate stubs for us...
michael@0 573 #define XPC_MAP_CLASSNAME nsJSCID
michael@0 574 #define XPC_MAP_QUOTED_CLASSNAME "nsJSCID"
michael@0 575 #define XPC_MAP_WANT_CONSTRUCT
michael@0 576 #define XPC_MAP_WANT_HASINSTANCE
michael@0 577 #define XPC_MAP_FLAGS 0
michael@0 578 #include "xpc_map_end.h" /* This will #undef the above */
michael@0 579
michael@0 580 nsJSCID::nsJSCID() {}
michael@0 581 nsJSCID::~nsJSCID() {}
michael@0 582
michael@0 583 NS_IMETHODIMP nsJSCID::GetName(char * *aName)
michael@0 584 {ResolveName(); return mDetails.GetName(aName);}
michael@0 585
michael@0 586 NS_IMETHODIMP nsJSCID::GetNumber(char * *aNumber)
michael@0 587 {return mDetails.GetNumber(aNumber);}
michael@0 588
michael@0 589 NS_IMETHODIMP_(const nsID*) nsJSCID::GetID()
michael@0 590 {return &mDetails.ID();}
michael@0 591
michael@0 592 NS_IMETHODIMP nsJSCID::GetValid(bool *aValid)
michael@0 593 {return mDetails.GetValid(aValid);}
michael@0 594
michael@0 595 NS_IMETHODIMP nsJSCID::Equals(nsIJSID *other, bool *_retval)
michael@0 596 {return mDetails.Equals(other, _retval);}
michael@0 597
michael@0 598 NS_IMETHODIMP nsJSCID::Initialize(const char *idString)
michael@0 599 {return mDetails.Initialize(idString);}
michael@0 600
michael@0 601 NS_IMETHODIMP nsJSCID::ToString(char **_retval)
michael@0 602 {ResolveName(); return mDetails.ToString(_retval);}
michael@0 603
michael@0 604 void
michael@0 605 nsJSCID::ResolveName()
michael@0 606 {
michael@0 607 if (!mDetails.NameIsSet())
michael@0 608 mDetails.SetNameToNoString();
michael@0 609 }
michael@0 610
michael@0 611 //static
michael@0 612 already_AddRefed<nsJSCID>
michael@0 613 nsJSCID::NewID(const char* str)
michael@0 614 {
michael@0 615 if (!str) {
michael@0 616 NS_ERROR("no string");
michael@0 617 return nullptr;
michael@0 618 }
michael@0 619
michael@0 620 nsRefPtr<nsJSCID> idObj = new nsJSCID();
michael@0 621 if (str[0] == '{') {
michael@0 622 NS_ENSURE_SUCCESS(idObj->Initialize(str), nullptr);
michael@0 623 } else {
michael@0 624 nsCOMPtr<nsIComponentRegistrar> registrar;
michael@0 625 NS_GetComponentRegistrar(getter_AddRefs(registrar));
michael@0 626 NS_ENSURE_TRUE(registrar, nullptr);
michael@0 627
michael@0 628 nsCID *cid;
michael@0 629 if (NS_FAILED(registrar->ContractIDToCID(str, &cid)))
michael@0 630 return nullptr;
michael@0 631 bool success = idObj->mDetails.InitWithName(*cid, str);
michael@0 632 nsMemory::Free(cid);
michael@0 633 if (!success)
michael@0 634 return nullptr;
michael@0 635 }
michael@0 636 return idObj.forget();
michael@0 637 }
michael@0 638
michael@0 639 static const nsID*
michael@0 640 GetIIDArg(uint32_t argc, const JS::Value& val, JSContext* cx)
michael@0 641 {
michael@0 642 const nsID* iid;
michael@0 643
michael@0 644 // If an IID was passed in then use it
michael@0 645 if (argc) {
michael@0 646 JSObject* iidobj;
michael@0 647 if (JSVAL_IS_PRIMITIVE(val) ||
michael@0 648 !(iidobj = JSVAL_TO_OBJECT(val)) ||
michael@0 649 !(iid = xpc_JSObjectToID(cx, iidobj))) {
michael@0 650 return nullptr;
michael@0 651 }
michael@0 652 } else
michael@0 653 iid = &NS_GET_IID(nsISupports);
michael@0 654
michael@0 655 return iid;
michael@0 656 }
michael@0 657
michael@0 658 static void
michael@0 659 GetWrapperObject(MutableHandleObject obj)
michael@0 660 {
michael@0 661 obj.set(nullptr);
michael@0 662 nsXPConnect* xpc = nsXPConnect::XPConnect();
michael@0 663 nsAXPCNativeCallContext *ccxp = nullptr;
michael@0 664 xpc->GetCurrentNativeCallContext(&ccxp);
michael@0 665 if (!ccxp)
michael@0 666 return;
michael@0 667
michael@0 668 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
michael@0 669 ccxp->GetCalleeWrapper(getter_AddRefs(wrapper));
michael@0 670 obj.set(wrapper->GetJSObject());
michael@0 671 }
michael@0 672
michael@0 673 /* nsISupports createInstance (); */
michael@0 674 NS_IMETHODIMP
michael@0 675 nsJSCID::CreateInstance(HandleValue iidval, JSContext *cx,
michael@0 676 uint8_t optionalArgc, MutableHandleValue retval)
michael@0 677 {
michael@0 678 if (!mDetails.IsValid())
michael@0 679 return NS_ERROR_XPC_BAD_CID;
michael@0 680
michael@0 681 RootedObject obj(cx);
michael@0 682 GetWrapperObject(&obj);
michael@0 683 if (!obj) {
michael@0 684 return NS_ERROR_UNEXPECTED;
michael@0 685 }
michael@0 686
michael@0 687 nsIXPCSecurityManager* sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager();
michael@0 688 if (sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID()))) {
michael@0 689 NS_ERROR("how are we not being called from chrome here?");
michael@0 690 return NS_OK;
michael@0 691 }
michael@0 692
michael@0 693 // If an IID was passed in then use it
michael@0 694 const nsID* iid = GetIIDArg(optionalArgc, iidval, cx);
michael@0 695 if (!iid)
michael@0 696 return NS_ERROR_XPC_BAD_IID;
michael@0 697
michael@0 698 nsCOMPtr<nsIComponentManager> compMgr;
michael@0 699 nsresult rv = NS_GetComponentManager(getter_AddRefs(compMgr));
michael@0 700 if (NS_FAILED(rv))
michael@0 701 return NS_ERROR_UNEXPECTED;
michael@0 702
michael@0 703 nsCOMPtr<nsISupports> inst;
michael@0 704 rv = compMgr->CreateInstance(mDetails.ID(), nullptr, *iid, getter_AddRefs(inst));
michael@0 705 MOZ_ASSERT(NS_FAILED(rv) || inst, "component manager returned success, but instance is null!");
michael@0 706
michael@0 707 if (NS_FAILED(rv) || !inst)
michael@0 708 return NS_ERROR_XPC_CI_RETURNED_FAILURE;
michael@0 709
michael@0 710 rv = nsXPConnect::XPConnect()->WrapNativeToJSVal(cx, obj, inst, nullptr, iid, true, retval);
michael@0 711 if (NS_FAILED(rv) || retval.isPrimitive())
michael@0 712 return NS_ERROR_XPC_CANT_CREATE_WN;
michael@0 713 return NS_OK;
michael@0 714 }
michael@0 715
michael@0 716 /* nsISupports getService (); */
michael@0 717 NS_IMETHODIMP
michael@0 718 nsJSCID::GetService(HandleValue iidval, JSContext *cx, uint8_t optionalArgc,
michael@0 719 MutableHandleValue retval)
michael@0 720 {
michael@0 721 if (!mDetails.IsValid())
michael@0 722 return NS_ERROR_XPC_BAD_CID;
michael@0 723
michael@0 724 RootedObject obj(cx);
michael@0 725 GetWrapperObject(&obj);
michael@0 726 if (!obj) {
michael@0 727 return NS_ERROR_UNEXPECTED;
michael@0 728 }
michael@0 729
michael@0 730 nsIXPCSecurityManager *sm;
michael@0 731 sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager();
michael@0 732 if (sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID()))) {
michael@0 733 MOZ_ASSERT(JS_IsExceptionPending(cx),
michael@0 734 "security manager vetoed GetService without setting exception");
michael@0 735 return NS_OK;
michael@0 736 }
michael@0 737
michael@0 738 // If an IID was passed in then use it
michael@0 739 const nsID *iid = GetIIDArg(optionalArgc, iidval, cx);
michael@0 740 if (!iid)
michael@0 741 return NS_ERROR_XPC_BAD_IID;
michael@0 742
michael@0 743 nsCOMPtr<nsIServiceManager> svcMgr;
michael@0 744 nsresult rv = NS_GetServiceManager(getter_AddRefs(svcMgr));
michael@0 745 if (NS_FAILED(rv))
michael@0 746 return rv;
michael@0 747
michael@0 748 nsCOMPtr<nsISupports> srvc;
michael@0 749 rv = svcMgr->GetService(mDetails.ID(), *iid, getter_AddRefs(srvc));
michael@0 750 MOZ_ASSERT(NS_FAILED(rv) || srvc, "service manager returned success, but service is null!");
michael@0 751 if (NS_FAILED(rv) || !srvc)
michael@0 752 return NS_ERROR_XPC_GS_RETURNED_FAILURE;
michael@0 753
michael@0 754 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
michael@0 755 rv = nsXPConnect::XPConnect()->WrapNative(cx, obj, srvc, *iid, getter_AddRefs(holder));
michael@0 756 if (NS_FAILED(rv) || !holder || !holder->GetJSObject())
michael@0 757 return NS_ERROR_XPC_CANT_CREATE_WN;
michael@0 758
michael@0 759 retval.setObject(*holder->GetJSObject());
michael@0 760 return NS_OK;
michael@0 761 }
michael@0 762
michael@0 763 /* bool construct (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in uint32_t argc, in JSValPtr argv, in JSValPtr vp); */
michael@0 764 NS_IMETHODIMP
michael@0 765 nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper,
michael@0 766 JSContext *cx, JSObject *objArg,
michael@0 767 const CallArgs &args, bool *_retval)
michael@0 768 {
michael@0 769 RootedObject obj(cx, objArg);
michael@0 770 XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
michael@0 771 if (!rt)
michael@0 772 return NS_ERROR_FAILURE;
michael@0 773
michael@0 774 // 'push' a call context and call on it
michael@0 775 RootedId name(cx, rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE));
michael@0 776 XPCCallContext ccx(JS_CALLER, cx, obj, JS::NullPtr(), name, args.length(), args.array(),
michael@0 777 args.rval().address());
michael@0 778
michael@0 779 *_retval = XPCWrappedNative::CallMethod(ccx);
michael@0 780 return NS_OK;
michael@0 781 }
michael@0 782
michael@0 783 /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
michael@0 784 NS_IMETHODIMP
michael@0 785 nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper,
michael@0 786 JSContext *cx, JSObject * /* unused */,
michael@0 787 HandleValue val, bool *bp, bool *_retval)
michael@0 788 {
michael@0 789 *bp = false;
michael@0 790 nsresult rv = NS_OK;
michael@0 791
michael@0 792 if (val.isObject()) {
michael@0 793 // we have a JSObject
michael@0 794 RootedObject obj(cx, &val.toObject());
michael@0 795
michael@0 796 MOZ_ASSERT(obj, "when is an object not an object?");
michael@0 797
michael@0 798 // is this really a native xpcom object with a wrapper?
michael@0 799 nsIClassInfo *ci = nullptr;
michael@0 800 obj = FindObjectForHasInstance(cx, obj);
michael@0 801 if (!obj || !IS_WN_REFLECTOR(obj))
michael@0 802 return rv;
michael@0 803 if (XPCWrappedNative *other_wrapper = XPCWrappedNative::Get(obj))
michael@0 804 ci = other_wrapper->GetClassInfo();
michael@0 805
michael@0 806 // We consider CID equality to be the thing that matters here.
michael@0 807 // This is perhaps debatable.
michael@0 808 if (ci) {
michael@0 809 nsID cid;
michael@0 810 if (NS_SUCCEEDED(ci->GetClassIDNoAlloc(&cid)))
michael@0 811 *bp = cid.Equals(mDetails.ID());
michael@0 812 }
michael@0 813 }
michael@0 814
michael@0 815 return rv;
michael@0 816 }
michael@0 817
michael@0 818 /***************************************************************************/
michael@0 819 // additional utilities...
michael@0 820
michael@0 821 JSObject *
michael@0 822 xpc_NewIDObject(JSContext *cx, HandleObject jsobj, const nsID& aID)
michael@0 823 {
michael@0 824 RootedObject obj(cx);
michael@0 825
michael@0 826 nsCOMPtr<nsIJSID> iid = nsJSID::NewID(aID);
michael@0 827 if (iid) {
michael@0 828 nsXPConnect *xpc = nsXPConnect::XPConnect();
michael@0 829 if (xpc) {
michael@0 830 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
michael@0 831 nsresult rv = xpc->WrapNative(cx, jsobj,
michael@0 832 static_cast<nsISupports*>(iid),
michael@0 833 NS_GET_IID(nsIJSID),
michael@0 834 getter_AddRefs(holder));
michael@0 835 if (NS_SUCCEEDED(rv) && holder) {
michael@0 836 obj = holder->GetJSObject();
michael@0 837 }
michael@0 838 }
michael@0 839 }
michael@0 840 return obj;
michael@0 841 }
michael@0 842
michael@0 843 // note: returned pointer is only valid while |obj| remains alive!
michael@0 844 const nsID*
michael@0 845 xpc_JSObjectToID(JSContext *cx, JSObject *obj)
michael@0 846 {
michael@0 847 if (!cx || !obj)
michael@0 848 return nullptr;
michael@0 849
michael@0 850 // NOTE: this call does NOT addref
michael@0 851 XPCWrappedNative *wrapper = nullptr;
michael@0 852 obj = js::CheckedUnwrap(obj);
michael@0 853 if (obj && IS_WN_REFLECTOR(obj))
michael@0 854 wrapper = XPCWrappedNative::Get(obj);
michael@0 855 if (wrapper &&
michael@0 856 (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) ||
michael@0 857 wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
michael@0 858 wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSCID)))) {
michael@0 859 return ((nsIJSID*)wrapper->GetIdentityObject())->GetID();
michael@0 860 }
michael@0 861 return nullptr;
michael@0 862 }
michael@0 863
michael@0 864 bool
michael@0 865 xpc_JSObjectIsID(JSContext *cx, JSObject *obj)
michael@0 866 {
michael@0 867 MOZ_ASSERT(cx && obj, "bad param");
michael@0 868 // NOTE: this call does NOT addref
michael@0 869 XPCWrappedNative *wrapper = nullptr;
michael@0 870 obj = js::CheckedUnwrap(obj);
michael@0 871 if (obj && IS_WN_REFLECTOR(obj))
michael@0 872 wrapper = XPCWrappedNative::Get(obj);
michael@0 873 return wrapper &&
michael@0 874 (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) ||
michael@0 875 wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
michael@0 876 wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSCID)));
michael@0 877 }
michael@0 878
michael@0 879

mercurial