js/xpconnect/src/XPCJSID.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial