LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCJSID.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 252 391 64.5 %
Date: 2017-07-14 16:53:18 Functions: 51 72 70.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13