js/xpconnect/src/XPCJSID.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/xpconnect/src/XPCJSID.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,879 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* An xpcom implementation of the JavaScript nsIID and nsCID objects. */
    1.11 +
    1.12 +#include "xpcprivate.h"
    1.13 +#include "mozilla/dom/BindingUtils.h"
    1.14 +#include "mozilla/Attributes.h"
    1.15 +#include "JavaScriptParent.h"
    1.16 +#include "mozilla/StaticPtr.h"
    1.17 +
    1.18 +using namespace mozilla::dom;
    1.19 +using namespace JS;
    1.20 +
    1.21 +/***************************************************************************/
    1.22 +// nsJSID
    1.23 +
    1.24 +NS_IMPL_CLASSINFO(nsJSID, nullptr, 0, NS_JS_ID_CID)
    1.25 +NS_IMPL_ISUPPORTS_CI(nsJSID, nsIJSID)
    1.26 +
    1.27 +char nsJSID::gNoString[] = "";
    1.28 +
    1.29 +nsJSID::nsJSID()
    1.30 +    : mID(GetInvalidIID()), mNumber(gNoString), mName(gNoString)
    1.31 +{
    1.32 +}
    1.33 +
    1.34 +nsJSID::~nsJSID()
    1.35 +{
    1.36 +    if (mNumber && mNumber != gNoString)
    1.37 +        NS_Free(mNumber);
    1.38 +    if (mName && mName != gNoString)
    1.39 +        NS_Free(mName);
    1.40 +}
    1.41 +
    1.42 +void nsJSID::Reset()
    1.43 +{
    1.44 +    mID = GetInvalidIID();
    1.45 +
    1.46 +    if (mNumber && mNumber != gNoString)
    1.47 +        NS_Free(mNumber);
    1.48 +    if (mName && mName != gNoString)
    1.49 +        NS_Free(mName);
    1.50 +
    1.51 +    mNumber = mName = nullptr;
    1.52 +}
    1.53 +
    1.54 +bool
    1.55 +nsJSID::SetName(const char* name)
    1.56 +{
    1.57 +    MOZ_ASSERT(!mName || mName == gNoString ,"name already set");
    1.58 +    MOZ_ASSERT(name,"null name");
    1.59 +    mName = NS_strdup(name);
    1.60 +    return mName ? true : false;
    1.61 +}
    1.62 +
    1.63 +NS_IMETHODIMP
    1.64 +nsJSID::GetName(char * *aName)
    1.65 +{
    1.66 +    if (!aName)
    1.67 +        return NS_ERROR_NULL_POINTER;
    1.68 +
    1.69 +    if (!NameIsSet())
    1.70 +        SetNameToNoString();
    1.71 +    MOZ_ASSERT(mName, "name not set");
    1.72 +    *aName = NS_strdup(mName);
    1.73 +    return *aName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
    1.74 +}
    1.75 +
    1.76 +NS_IMETHODIMP
    1.77 +nsJSID::GetNumber(char * *aNumber)
    1.78 +{
    1.79 +    if (!aNumber)
    1.80 +        return NS_ERROR_NULL_POINTER;
    1.81 +
    1.82 +    if (!mNumber) {
    1.83 +        if (!(mNumber = mID.ToString()))
    1.84 +            mNumber = gNoString;
    1.85 +    }
    1.86 +
    1.87 +    *aNumber = NS_strdup(mNumber);
    1.88 +    return *aNumber ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
    1.89 +}
    1.90 +
    1.91 +NS_IMETHODIMP_(const nsID*)
    1.92 +nsJSID::GetID()
    1.93 +{
    1.94 +    return &mID;
    1.95 +}
    1.96 +
    1.97 +NS_IMETHODIMP
    1.98 +nsJSID::GetValid(bool *aValid)
    1.99 +{
   1.100 +    if (!aValid)
   1.101 +        return NS_ERROR_NULL_POINTER;
   1.102 +
   1.103 +    *aValid = IsValid();
   1.104 +    return NS_OK;
   1.105 +}
   1.106 +
   1.107 +NS_IMETHODIMP
   1.108 +nsJSID::Equals(nsIJSID *other, bool *_retval)
   1.109 +{
   1.110 +    if (!_retval)
   1.111 +        return NS_ERROR_NULL_POINTER;
   1.112 +
   1.113 +    if (!other || mID.Equals(GetInvalidIID())) {
   1.114 +        *_retval = false;
   1.115 +        return NS_OK;
   1.116 +    }
   1.117 +
   1.118 +    *_retval = other->GetID()->Equals(mID);
   1.119 +    return NS_OK;
   1.120 +}
   1.121 +
   1.122 +NS_IMETHODIMP
   1.123 +nsJSID::Initialize(const char *idString)
   1.124 +{
   1.125 +    if (!idString)
   1.126 +        return NS_ERROR_NULL_POINTER;
   1.127 +
   1.128 +    if (*idString != '\0' && mID.Equals(GetInvalidIID())) {
   1.129 +        Reset();
   1.130 +
   1.131 +        if (idString[0] == '{') {
   1.132 +            if (mID.Parse(idString)) {
   1.133 +                return NS_OK;
   1.134 +            }
   1.135 +
   1.136 +            // error - reset to invalid state
   1.137 +            mID = GetInvalidIID();
   1.138 +        }
   1.139 +    }
   1.140 +    return NS_ERROR_FAILURE;
   1.141 +}
   1.142 +
   1.143 +bool
   1.144 +nsJSID::InitWithName(const nsID& id, const char *nameString)
   1.145 +{
   1.146 +    MOZ_ASSERT(nameString, "no name");
   1.147 +    Reset();
   1.148 +    mID = id;
   1.149 +    return SetName(nameString);
   1.150 +}
   1.151 +
   1.152 +// try to use the name, if no name, then use the number
   1.153 +NS_IMETHODIMP
   1.154 +nsJSID::ToString(char **_retval)
   1.155 +{
   1.156 +    if (mName && mName != gNoString)
   1.157 +        return GetName(_retval);
   1.158 +
   1.159 +    return GetNumber(_retval);
   1.160 +}
   1.161 +
   1.162 +const nsID&
   1.163 +nsJSID::GetInvalidIID() const
   1.164 +{
   1.165 +    // {BB1F47B0-D137-11d2-9841-006008962422}
   1.166 +    static const nsID invalid = {0xbb1f47b0, 0xd137, 0x11d2,
   1.167 +                                  {0x98, 0x41, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22}};
   1.168 +    return invalid;
   1.169 +}
   1.170 +
   1.171 +//static
   1.172 +already_AddRefed<nsJSID>
   1.173 +nsJSID::NewID(const char* str)
   1.174 +{
   1.175 +    if (!str) {
   1.176 +        NS_ERROR("no string");
   1.177 +        return nullptr;
   1.178 +    }
   1.179 +
   1.180 +    nsRefPtr<nsJSID> idObj = new nsJSID();
   1.181 +    NS_ENSURE_SUCCESS(idObj->Initialize(str), nullptr);
   1.182 +    return idObj.forget();
   1.183 +}
   1.184 +
   1.185 +//static
   1.186 +already_AddRefed<nsJSID>
   1.187 +nsJSID::NewID(const nsID& id)
   1.188 +{
   1.189 +    nsRefPtr<nsJSID> idObj = new nsJSID();
   1.190 +    idObj->mID = id;
   1.191 +    idObj->mName = nullptr;
   1.192 +    idObj->mNumber = nullptr;
   1.193 +    return idObj.forget();
   1.194 +}
   1.195 +
   1.196 +
   1.197 +/***************************************************************************/
   1.198 +// Class object support so that we can share prototypes of wrapper
   1.199 +
   1.200 +// This class exists just so we can have a shared scriptable helper for
   1.201 +// the nsJSIID class. The instances implement their own helpers. But we
   1.202 +// needed to be able to indicate to the shared prototypes this single flag:
   1.203 +// nsIXPCScriptable::DONT_ENUM_STATIC_PROPS. And having a class to do it is
   1.204 +// the only means we have. Setting this flag on any given instance scriptable
   1.205 +// helper is not sufficient to convey the information that we don't want
   1.206 +// static properties enumerated on the shared proto.
   1.207 +
   1.208 +class SharedScriptableHelperForJSIID MOZ_FINAL : public nsIXPCScriptable
   1.209 +{
   1.210 +public:
   1.211 +    NS_DECL_ISUPPORTS
   1.212 +    NS_DECL_NSIXPCSCRIPTABLE
   1.213 +    SharedScriptableHelperForJSIID() {}
   1.214 +};
   1.215 +
   1.216 +NS_INTERFACE_MAP_BEGIN(SharedScriptableHelperForJSIID)
   1.217 +  NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
   1.218 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCScriptable)
   1.219 +NS_INTERFACE_MAP_END
   1.220 +
   1.221 +NS_IMPL_ADDREF(SharedScriptableHelperForJSIID)
   1.222 +NS_IMPL_RELEASE(SharedScriptableHelperForJSIID)
   1.223 +
   1.224 +// The nsIXPCScriptable map declaration that will generate stubs for us...
   1.225 +#define XPC_MAP_CLASSNAME           SharedScriptableHelperForJSIID
   1.226 +#define XPC_MAP_QUOTED_CLASSNAME   "JSIID"
   1.227 +#define XPC_MAP_FLAGS               nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |\
   1.228 +                                    nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE
   1.229 +#include "xpc_map_end.h" /* This will #undef the above */
   1.230 +
   1.231 +static mozilla::StaticRefPtr<nsIXPCScriptable> gSharedScriptableHelperForJSIID;
   1.232 +static bool gClassObjectsWereInited = false;
   1.233 +
   1.234 +static void EnsureClassObjectsInitialized()
   1.235 +{
   1.236 +    if (!gClassObjectsWereInited) {
   1.237 +        gSharedScriptableHelperForJSIID = new SharedScriptableHelperForJSIID();
   1.238 +
   1.239 +        gClassObjectsWereInited = true;
   1.240 +    }
   1.241 +}
   1.242 +
   1.243 +NS_METHOD GetSharedScriptableHelperForJSIID(uint32_t language,
   1.244 +                                            nsISupports **helper)
   1.245 +{
   1.246 +    EnsureClassObjectsInitialized();
   1.247 +    if (language == nsIProgrammingLanguage::JAVASCRIPT) {
   1.248 +        nsCOMPtr<nsIXPCScriptable> temp = gSharedScriptableHelperForJSIID.get();
   1.249 +        temp.forget(helper);
   1.250 +    } else
   1.251 +        *helper = nullptr;
   1.252 +    return NS_OK;
   1.253 +}
   1.254 +
   1.255 +/******************************************************/
   1.256 +
   1.257 +#define NULL_CID                                                              \
   1.258 +{ 0x00000000, 0x0000, 0x0000,                                                 \
   1.259 +  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
   1.260 +
   1.261 +// We pass nsIClassInfo::DOM_OBJECT so that nsJSIID instances may be created
   1.262 +// in unprivileged scopes.
   1.263 +NS_DECL_CI_INTERFACE_GETTER(nsJSIID)
   1.264 +NS_IMPL_CLASSINFO(nsJSIID, GetSharedScriptableHelperForJSIID,
   1.265 +                  nsIClassInfo::DOM_OBJECT, NULL_CID)
   1.266 +
   1.267 +NS_DECL_CI_INTERFACE_GETTER(nsJSCID)
   1.268 +NS_IMPL_CLASSINFO(nsJSCID, nullptr, 0, NULL_CID)
   1.269 +
   1.270 +void xpc_DestroyJSxIDClassObjects()
   1.271 +{
   1.272 +    if (gClassObjectsWereInited) {
   1.273 +        NS_IF_RELEASE(NS_CLASSINFO_NAME(nsJSIID));
   1.274 +        NS_IF_RELEASE(NS_CLASSINFO_NAME(nsJSCID));
   1.275 +        gSharedScriptableHelperForJSIID = nullptr;
   1.276 +
   1.277 +        gClassObjectsWereInited = false;
   1.278 +    }
   1.279 +}
   1.280 +
   1.281 +/***************************************************************************/
   1.282 +
   1.283 +NS_INTERFACE_MAP_BEGIN(nsJSIID)
   1.284 +  NS_INTERFACE_MAP_ENTRY(nsIJSID)
   1.285 +  NS_INTERFACE_MAP_ENTRY(nsIJSIID)
   1.286 +  NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
   1.287 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSID)
   1.288 +  NS_IMPL_QUERY_CLASSINFO(nsJSIID)
   1.289 +NS_INTERFACE_MAP_END
   1.290 +
   1.291 +NS_IMPL_ADDREF(nsJSIID)
   1.292 +NS_IMPL_RELEASE(nsJSIID)
   1.293 +NS_IMPL_CI_INTERFACE_GETTER(nsJSIID, nsIJSID, nsIJSIID)
   1.294 +
   1.295 +// The nsIXPCScriptable map declaration that will generate stubs for us...
   1.296 +#define XPC_MAP_CLASSNAME           nsJSIID
   1.297 +#define XPC_MAP_QUOTED_CLASSNAME   "nsJSIID"
   1.298 +#define                             XPC_MAP_WANT_NEWRESOLVE
   1.299 +#define                             XPC_MAP_WANT_ENUMERATE
   1.300 +#define                             XPC_MAP_WANT_HASINSTANCE
   1.301 +#define XPC_MAP_FLAGS               nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |\
   1.302 +                                    nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE
   1.303 +#include "xpc_map_end.h" /* This will #undef the above */
   1.304 +
   1.305 +
   1.306 +nsJSIID::nsJSIID(nsIInterfaceInfo* aInfo)
   1.307 +    : mInfo(aInfo)
   1.308 +{
   1.309 +}
   1.310 +
   1.311 +nsJSIID::~nsJSIID() {}
   1.312 +
   1.313 +// If mInfo is present we use it and ignore mDetails, else we use mDetails.
   1.314 +
   1.315 +NS_IMETHODIMP nsJSIID::GetName(char * *aName)
   1.316 +{
   1.317 +    return mInfo->GetName(aName);
   1.318 +}
   1.319 +
   1.320 +NS_IMETHODIMP nsJSIID::GetNumber(char * *aNumber)
   1.321 +{
   1.322 +    char str[NSID_LENGTH];
   1.323 +    const nsIID* id;
   1.324 +    mInfo->GetIIDShared(&id);
   1.325 +    id->ToProvidedString(str);
   1.326 +    *aNumber = (char*) nsMemory::Clone(str, NSID_LENGTH);
   1.327 +    return *aNumber ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
   1.328 +}
   1.329 +
   1.330 +NS_IMETHODIMP_(const nsID*) nsJSIID::GetID()
   1.331 +{
   1.332 +    const nsIID* id;
   1.333 +    mInfo->GetIIDShared(&id);
   1.334 +    return id;
   1.335 +}
   1.336 +
   1.337 +NS_IMETHODIMP nsJSIID::GetValid(bool *aValid)
   1.338 +{
   1.339 +    *aValid = true;
   1.340 +    return NS_OK;
   1.341 +}
   1.342 +
   1.343 +NS_IMETHODIMP nsJSIID::Equals(nsIJSID *other, bool *_retval)
   1.344 +{
   1.345 +    if (!_retval)
   1.346 +        return NS_ERROR_NULL_POINTER;
   1.347 +
   1.348 +    if (!other) {
   1.349 +        *_retval = false;
   1.350 +        return NS_OK;
   1.351 +    }
   1.352 +
   1.353 +    mInfo->IsIID(other->GetID(), _retval);
   1.354 +    return NS_OK;
   1.355 +}
   1.356 +
   1.357 +NS_IMETHODIMP nsJSIID::Initialize(const char *idString)
   1.358 +{
   1.359 +    return NS_ERROR_FAILURE;
   1.360 +}
   1.361 +
   1.362 +NS_IMETHODIMP nsJSIID::ToString(char **_retval)
   1.363 +{
   1.364 +    return mInfo->GetName(_retval);
   1.365 +}
   1.366 +
   1.367 +// static
   1.368 +already_AddRefed<nsJSIID>
   1.369 +nsJSIID::NewID(nsIInterfaceInfo* aInfo)
   1.370 +{
   1.371 +    if (!aInfo) {
   1.372 +        NS_ERROR("no info");
   1.373 +        return nullptr;
   1.374 +    }
   1.375 +
   1.376 +    bool canScript;
   1.377 +    if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
   1.378 +        return nullptr;
   1.379 +
   1.380 +    nsRefPtr<nsJSIID> idObj = new nsJSIID(aInfo);
   1.381 +    return idObj.forget();
   1.382 +}
   1.383 +
   1.384 +
   1.385 +/* bool resolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id); */
   1.386 +NS_IMETHODIMP
   1.387 +nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper,
   1.388 +                    JSContext * cx, JSObject * objArg,
   1.389 +                    jsid idArg, JSObject * *objp,
   1.390 +                    bool *_retval)
   1.391 +{
   1.392 +    RootedObject obj(cx, objArg);
   1.393 +    RootedId id(cx, idArg);
   1.394 +    XPCCallContext ccx(JS_CALLER, cx);
   1.395 +
   1.396 +    AutoMarkingNativeInterfacePtr iface(ccx);
   1.397 +
   1.398 +    const nsIID* iid;
   1.399 +    mInfo->GetIIDShared(&iid);
   1.400 +
   1.401 +    iface = XPCNativeInterface::GetNewOrUsed(iid);
   1.402 +
   1.403 +    if (!iface)
   1.404 +        return NS_OK;
   1.405 +
   1.406 +    XPCNativeMember* member = iface->FindMember(id);
   1.407 +    if (member && member->IsConstant()) {
   1.408 +        RootedValue val(cx);
   1.409 +        if (!member->GetConstantValue(ccx, iface, val.address()))
   1.410 +            return NS_ERROR_OUT_OF_MEMORY;
   1.411 +
   1.412 +        *objp = obj;
   1.413 +        *_retval = JS_DefinePropertyById(cx, obj, id, val, nullptr, nullptr,
   1.414 +                                         JSPROP_ENUMERATE | JSPROP_READONLY |
   1.415 +                                         JSPROP_PERMANENT);
   1.416 +    }
   1.417 +
   1.418 +    return NS_OK;
   1.419 +}
   1.420 +
   1.421 +/* bool enumerate (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj); */
   1.422 +NS_IMETHODIMP
   1.423 +nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper,
   1.424 +                   JSContext * cx, JSObject * objArg, bool *_retval)
   1.425 +{
   1.426 +    // In this case, let's just eagerly resolve...
   1.427 +
   1.428 +    RootedObject obj(cx, objArg);
   1.429 +    XPCCallContext ccx(JS_CALLER, cx);
   1.430 +
   1.431 +    AutoMarkingNativeInterfacePtr iface(ccx);
   1.432 +
   1.433 +    const nsIID* iid;
   1.434 +    mInfo->GetIIDShared(&iid);
   1.435 +
   1.436 +    iface = XPCNativeInterface::GetNewOrUsed(iid);
   1.437 +
   1.438 +    if (!iface)
   1.439 +        return NS_OK;
   1.440 +
   1.441 +    uint16_t count = iface->GetMemberCount();
   1.442 +    for (uint16_t i = 0; i < count; i++) {
   1.443 +        XPCNativeMember* member = iface->GetMemberAt(i);
   1.444 +        if (member && member->IsConstant() &&
   1.445 +            !xpc_ForcePropertyResolve(cx, obj, member->GetName())) {
   1.446 +            return NS_ERROR_UNEXPECTED;
   1.447 +        }
   1.448 +    }
   1.449 +    return NS_OK;
   1.450 +}
   1.451 +
   1.452 +/*
   1.453 + * HasInstance hooks need to find an appropriate reflector in order to function
   1.454 + * properly. There are two complexities that we need to handle:
   1.455 + *
   1.456 + * 1 - Cross-compartment wrappers. Chrome uses over 100 compartments, all with
   1.457 + *     system principal. The success of an instanceof check should not depend
   1.458 + *     on which compartment an object comes from. At the same time, we want to
   1.459 + *     make sure we don't unwrap important security wrappers.
   1.460 + *     CheckedUnwrap does the right thing here.
   1.461 + *
   1.462 + * 2 - Prototype chains. Suppose someone creates a vanilla JS object |a| and
   1.463 + *     sets its __proto__ to some WN |b|. If |b instanceof nsIFoo| returns true,
   1.464 + *     one would expect |a instanceof nsIFoo| to return true as well, since
   1.465 + *     instanceof is transitive up the prototype chain in ECMAScript. Moreover,
   1.466 + *     there's chrome code that relies on this.
   1.467 + *
   1.468 + * This static method handles both complexities, returning either an XPCWN, a
   1.469 + * DOM object, or null. The object may well be cross-compartment from |cx|.
   1.470 + */
   1.471 +static JSObject *
   1.472 +FindObjectForHasInstance(JSContext *cx, HandleObject objArg)
   1.473 +{
   1.474 +    RootedObject obj(cx, objArg), proto(cx);
   1.475 +
   1.476 +    while (obj && !IS_WN_REFLECTOR(obj) &&
   1.477 +           !IsDOMObject(obj) && !mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
   1.478 +    {
   1.479 +        if (js::IsWrapper(obj)) {
   1.480 +            obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
   1.481 +            continue;
   1.482 +        }
   1.483 +        if (!js::GetObjectProto(cx, obj, &proto))
   1.484 +            return nullptr;
   1.485 +        obj = proto;
   1.486 +    }
   1.487 +    return obj;
   1.488 +}
   1.489 +
   1.490 +nsresult
   1.491 +xpc::HasInstance(JSContext *cx, HandleObject objArg, const nsID *iid, bool *bp)
   1.492 +{
   1.493 +    *bp = false;
   1.494 +
   1.495 +    RootedObject obj(cx, FindObjectForHasInstance(cx, objArg));
   1.496 +    if (!obj)
   1.497 +        return NS_OK;
   1.498 +
   1.499 +    if (IsDOMObject(obj)) {
   1.500 +        // Not all DOM objects implement nsISupports. But if they don't,
   1.501 +        // there's nothing to do in this HasInstance hook.
   1.502 +        nsISupports *identity = UnwrapDOMObjectToISupports(obj);
   1.503 +        if (!identity)
   1.504 +            return NS_OK;;
   1.505 +        nsCOMPtr<nsISupports> supp;
   1.506 +        identity->QueryInterface(*iid, getter_AddRefs(supp));
   1.507 +        *bp = supp;
   1.508 +        return NS_OK;
   1.509 +    }
   1.510 +
   1.511 +    if (mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
   1.512 +        return mozilla::jsipc::JavaScriptParent::InstanceOf(obj, iid, bp);
   1.513 +
   1.514 +    MOZ_ASSERT(IS_WN_REFLECTOR(obj));
   1.515 +    XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
   1.516 +    if (!other_wrapper)
   1.517 +        return NS_OK;
   1.518 +
   1.519 +    // We'll trust the interface set of the wrapper if this is known
   1.520 +    // to be an interface that the objects *expects* to be able to
   1.521 +    // handle.
   1.522 +    if (other_wrapper->HasInterfaceNoQI(*iid)) {
   1.523 +        *bp = true;
   1.524 +        return NS_OK;
   1.525 +    }
   1.526 +
   1.527 +    // Otherwise, we'll end up Querying the native object to be sure.
   1.528 +    XPCCallContext ccx(JS_CALLER, cx);
   1.529 +
   1.530 +    AutoMarkingNativeInterfacePtr iface(ccx);
   1.531 +    iface = XPCNativeInterface::GetNewOrUsed(iid);
   1.532 +
   1.533 +    nsresult findResult = NS_OK;
   1.534 +    if (iface && other_wrapper->FindTearOff(iface, false, &findResult))
   1.535 +        *bp = true;
   1.536 +    if (NS_FAILED(findResult) && findResult != NS_ERROR_NO_INTERFACE)
   1.537 +        return findResult;
   1.538 +
   1.539 +    return NS_OK;
   1.540 +}
   1.541 +
   1.542 +/* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
   1.543 +NS_IMETHODIMP
   1.544 +nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
   1.545 +                     JSContext *cx, JSObject * /* unused */,
   1.546 +                     HandleValue val, bool *bp, bool *_retval)
   1.547 +{
   1.548 +    *bp = false;
   1.549 +
   1.550 +    if (val.isPrimitive())
   1.551 +        return NS_OK;
   1.552 +
   1.553 +    // we have a JSObject
   1.554 +    RootedObject obj(cx, &val.toObject());
   1.555 +
   1.556 +    const nsIID* iid;
   1.557 +    mInfo->GetIIDShared(&iid);
   1.558 +    return xpc::HasInstance(cx, obj, iid, bp);
   1.559 +}
   1.560 +
   1.561 +/***************************************************************************/
   1.562 +
   1.563 +NS_INTERFACE_MAP_BEGIN(nsJSCID)
   1.564 +  NS_INTERFACE_MAP_ENTRY(nsIJSID)
   1.565 +  NS_INTERFACE_MAP_ENTRY(nsIJSCID)
   1.566 +  NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
   1.567 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSID)
   1.568 +  NS_IMPL_QUERY_CLASSINFO(nsJSCID)
   1.569 +NS_INTERFACE_MAP_END
   1.570 +
   1.571 +NS_IMPL_ADDREF(nsJSCID)
   1.572 +NS_IMPL_RELEASE(nsJSCID)
   1.573 +NS_IMPL_CI_INTERFACE_GETTER(nsJSCID, nsIJSID, nsIJSCID)
   1.574 +
   1.575 +// The nsIXPCScriptable map declaration that will generate stubs for us...
   1.576 +#define XPC_MAP_CLASSNAME           nsJSCID
   1.577 +#define XPC_MAP_QUOTED_CLASSNAME   "nsJSCID"
   1.578 +#define                             XPC_MAP_WANT_CONSTRUCT
   1.579 +#define                             XPC_MAP_WANT_HASINSTANCE
   1.580 +#define XPC_MAP_FLAGS               0
   1.581 +#include "xpc_map_end.h" /* This will #undef the above */
   1.582 +
   1.583 +nsJSCID::nsJSCID()  {}
   1.584 +nsJSCID::~nsJSCID() {}
   1.585 +
   1.586 +NS_IMETHODIMP nsJSCID::GetName(char * *aName)
   1.587 +    {ResolveName(); return mDetails.GetName(aName);}
   1.588 +
   1.589 +NS_IMETHODIMP nsJSCID::GetNumber(char * *aNumber)
   1.590 +    {return mDetails.GetNumber(aNumber);}
   1.591 +
   1.592 +NS_IMETHODIMP_(const nsID*) nsJSCID::GetID()
   1.593 +    {return &mDetails.ID();}
   1.594 +
   1.595 +NS_IMETHODIMP nsJSCID::GetValid(bool *aValid)
   1.596 +    {return mDetails.GetValid(aValid);}
   1.597 +
   1.598 +NS_IMETHODIMP nsJSCID::Equals(nsIJSID *other, bool *_retval)
   1.599 +    {return mDetails.Equals(other, _retval);}
   1.600 +
   1.601 +NS_IMETHODIMP nsJSCID::Initialize(const char *idString)
   1.602 +    {return mDetails.Initialize(idString);}
   1.603 +
   1.604 +NS_IMETHODIMP nsJSCID::ToString(char **_retval)
   1.605 +    {ResolveName(); return mDetails.ToString(_retval);}
   1.606 +
   1.607 +void
   1.608 +nsJSCID::ResolveName()
   1.609 +{
   1.610 +    if (!mDetails.NameIsSet())
   1.611 +        mDetails.SetNameToNoString();
   1.612 +}
   1.613 +
   1.614 +//static
   1.615 +already_AddRefed<nsJSCID>
   1.616 +nsJSCID::NewID(const char* str)
   1.617 +{
   1.618 +    if (!str) {
   1.619 +        NS_ERROR("no string");
   1.620 +        return nullptr;
   1.621 +    }
   1.622 +
   1.623 +    nsRefPtr<nsJSCID> idObj = new nsJSCID();
   1.624 +    if (str[0] == '{') {
   1.625 +        NS_ENSURE_SUCCESS(idObj->Initialize(str), nullptr);
   1.626 +    } else {
   1.627 +        nsCOMPtr<nsIComponentRegistrar> registrar;
   1.628 +        NS_GetComponentRegistrar(getter_AddRefs(registrar));
   1.629 +        NS_ENSURE_TRUE(registrar, nullptr);
   1.630 +
   1.631 +        nsCID *cid;
   1.632 +        if (NS_FAILED(registrar->ContractIDToCID(str, &cid)))
   1.633 +            return nullptr;
   1.634 +        bool success = idObj->mDetails.InitWithName(*cid, str);
   1.635 +        nsMemory::Free(cid);
   1.636 +        if (!success)
   1.637 +            return nullptr;
   1.638 +    }
   1.639 +    return idObj.forget();
   1.640 +}
   1.641 +
   1.642 +static const nsID*
   1.643 +GetIIDArg(uint32_t argc, const JS::Value& val, JSContext* cx)
   1.644 +{
   1.645 +    const nsID* iid;
   1.646 +
   1.647 +    // If an IID was passed in then use it
   1.648 +    if (argc) {
   1.649 +        JSObject* iidobj;
   1.650 +        if (JSVAL_IS_PRIMITIVE(val) ||
   1.651 +            !(iidobj = JSVAL_TO_OBJECT(val)) ||
   1.652 +            !(iid = xpc_JSObjectToID(cx, iidobj))) {
   1.653 +            return nullptr;
   1.654 +        }
   1.655 +    } else
   1.656 +        iid = &NS_GET_IID(nsISupports);
   1.657 +
   1.658 +    return iid;
   1.659 +}
   1.660 +
   1.661 +static void
   1.662 +GetWrapperObject(MutableHandleObject obj)
   1.663 +{
   1.664 +    obj.set(nullptr);
   1.665 +    nsXPConnect* xpc = nsXPConnect::XPConnect();
   1.666 +    nsAXPCNativeCallContext *ccxp = nullptr;
   1.667 +    xpc->GetCurrentNativeCallContext(&ccxp);
   1.668 +    if (!ccxp)
   1.669 +        return;
   1.670 +
   1.671 +    nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
   1.672 +    ccxp->GetCalleeWrapper(getter_AddRefs(wrapper));
   1.673 +    obj.set(wrapper->GetJSObject());
   1.674 +}
   1.675 +
   1.676 +/* nsISupports createInstance (); */
   1.677 +NS_IMETHODIMP
   1.678 +nsJSCID::CreateInstance(HandleValue iidval, JSContext *cx,
   1.679 +                        uint8_t optionalArgc, MutableHandleValue retval)
   1.680 +{
   1.681 +    if (!mDetails.IsValid())
   1.682 +        return NS_ERROR_XPC_BAD_CID;
   1.683 +
   1.684 +    RootedObject obj(cx);
   1.685 +    GetWrapperObject(&obj);
   1.686 +    if (!obj) {
   1.687 +        return NS_ERROR_UNEXPECTED;
   1.688 +    }
   1.689 +
   1.690 +    nsIXPCSecurityManager* sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager();
   1.691 +    if (sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID()))) {
   1.692 +        NS_ERROR("how are we not being called from chrome here?");
   1.693 +        return NS_OK;
   1.694 +    }
   1.695 +
   1.696 +    // If an IID was passed in then use it
   1.697 +    const nsID* iid = GetIIDArg(optionalArgc, iidval, cx);
   1.698 +    if (!iid)
   1.699 +        return NS_ERROR_XPC_BAD_IID;
   1.700 +
   1.701 +    nsCOMPtr<nsIComponentManager> compMgr;
   1.702 +    nsresult rv = NS_GetComponentManager(getter_AddRefs(compMgr));
   1.703 +    if (NS_FAILED(rv))
   1.704 +        return NS_ERROR_UNEXPECTED;
   1.705 +
   1.706 +    nsCOMPtr<nsISupports> inst;
   1.707 +    rv = compMgr->CreateInstance(mDetails.ID(), nullptr, *iid, getter_AddRefs(inst));
   1.708 +    MOZ_ASSERT(NS_FAILED(rv) || inst, "component manager returned success, but instance is null!");
   1.709 +
   1.710 +    if (NS_FAILED(rv) || !inst)
   1.711 +        return NS_ERROR_XPC_CI_RETURNED_FAILURE;
   1.712 +
   1.713 +    rv = nsXPConnect::XPConnect()->WrapNativeToJSVal(cx, obj, inst, nullptr, iid, true, retval);
   1.714 +    if (NS_FAILED(rv) || retval.isPrimitive())
   1.715 +        return NS_ERROR_XPC_CANT_CREATE_WN;
   1.716 +    return NS_OK;
   1.717 +}
   1.718 +
   1.719 +/* nsISupports getService (); */
   1.720 +NS_IMETHODIMP
   1.721 +nsJSCID::GetService(HandleValue iidval, JSContext *cx, uint8_t optionalArgc,
   1.722 +                    MutableHandleValue retval)
   1.723 +{
   1.724 +    if (!mDetails.IsValid())
   1.725 +        return NS_ERROR_XPC_BAD_CID;
   1.726 +
   1.727 +    RootedObject obj(cx);
   1.728 +    GetWrapperObject(&obj);
   1.729 +    if (!obj) {
   1.730 +        return NS_ERROR_UNEXPECTED;
   1.731 +    }
   1.732 +
   1.733 +    nsIXPCSecurityManager *sm;
   1.734 +    sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager();
   1.735 +    if (sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID()))) {
   1.736 +        MOZ_ASSERT(JS_IsExceptionPending(cx),
   1.737 +                   "security manager vetoed GetService without setting exception");
   1.738 +        return NS_OK;
   1.739 +    }
   1.740 +
   1.741 +    // If an IID was passed in then use it
   1.742 +    const nsID *iid = GetIIDArg(optionalArgc, iidval, cx);
   1.743 +    if (!iid)
   1.744 +        return NS_ERROR_XPC_BAD_IID;
   1.745 +
   1.746 +    nsCOMPtr<nsIServiceManager> svcMgr;
   1.747 +    nsresult rv = NS_GetServiceManager(getter_AddRefs(svcMgr));
   1.748 +    if (NS_FAILED(rv))
   1.749 +        return rv;
   1.750 +
   1.751 +    nsCOMPtr<nsISupports> srvc;
   1.752 +    rv = svcMgr->GetService(mDetails.ID(), *iid, getter_AddRefs(srvc));
   1.753 +    MOZ_ASSERT(NS_FAILED(rv) || srvc, "service manager returned success, but service is null!");
   1.754 +    if (NS_FAILED(rv) || !srvc)
   1.755 +        return NS_ERROR_XPC_GS_RETURNED_FAILURE;
   1.756 +
   1.757 +    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   1.758 +    rv = nsXPConnect::XPConnect()->WrapNative(cx, obj, srvc, *iid, getter_AddRefs(holder));
   1.759 +    if (NS_FAILED(rv) || !holder || !holder->GetJSObject())
   1.760 +        return NS_ERROR_XPC_CANT_CREATE_WN;
   1.761 +
   1.762 +    retval.setObject(*holder->GetJSObject());
   1.763 +    return NS_OK;
   1.764 +}
   1.765 +
   1.766 +/* bool construct (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in uint32_t argc, in JSValPtr argv, in JSValPtr vp); */
   1.767 +NS_IMETHODIMP
   1.768 +nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper,
   1.769 +                   JSContext *cx, JSObject *objArg,
   1.770 +                   const CallArgs &args, bool *_retval)
   1.771 +{
   1.772 +    RootedObject obj(cx, objArg);
   1.773 +    XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
   1.774 +    if (!rt)
   1.775 +        return NS_ERROR_FAILURE;
   1.776 +
   1.777 +    // 'push' a call context and call on it
   1.778 +    RootedId name(cx, rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE));
   1.779 +    XPCCallContext ccx(JS_CALLER, cx, obj, JS::NullPtr(), name, args.length(), args.array(),
   1.780 +                       args.rval().address());
   1.781 +
   1.782 +    *_retval = XPCWrappedNative::CallMethod(ccx);
   1.783 +    return NS_OK;
   1.784 +}
   1.785 +
   1.786 +/* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
   1.787 +NS_IMETHODIMP
   1.788 +nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper,
   1.789 +                     JSContext *cx, JSObject * /* unused */,
   1.790 +                     HandleValue val, bool *bp, bool *_retval)
   1.791 +{
   1.792 +    *bp = false;
   1.793 +    nsresult rv = NS_OK;
   1.794 +
   1.795 +    if (val.isObject()) {
   1.796 +        // we have a JSObject
   1.797 +        RootedObject obj(cx, &val.toObject());
   1.798 +
   1.799 +        MOZ_ASSERT(obj, "when is an object not an object?");
   1.800 +
   1.801 +        // is this really a native xpcom object with a wrapper?
   1.802 +        nsIClassInfo *ci = nullptr;
   1.803 +        obj = FindObjectForHasInstance(cx, obj);
   1.804 +        if (!obj || !IS_WN_REFLECTOR(obj))
   1.805 +            return rv;
   1.806 +        if (XPCWrappedNative *other_wrapper = XPCWrappedNative::Get(obj))
   1.807 +            ci = other_wrapper->GetClassInfo();
   1.808 +
   1.809 +        // We consider CID equality to be the thing that matters here.
   1.810 +        // This is perhaps debatable.
   1.811 +        if (ci) {
   1.812 +            nsID cid;
   1.813 +            if (NS_SUCCEEDED(ci->GetClassIDNoAlloc(&cid)))
   1.814 +                *bp = cid.Equals(mDetails.ID());
   1.815 +        }
   1.816 +    }
   1.817 +
   1.818 +    return rv;
   1.819 +}
   1.820 +
   1.821 +/***************************************************************************/
   1.822 +// additional utilities...
   1.823 +
   1.824 +JSObject *
   1.825 +xpc_NewIDObject(JSContext *cx, HandleObject jsobj, const nsID& aID)
   1.826 +{
   1.827 +    RootedObject obj(cx);
   1.828 +
   1.829 +    nsCOMPtr<nsIJSID> iid = nsJSID::NewID(aID);
   1.830 +    if (iid) {
   1.831 +        nsXPConnect *xpc = nsXPConnect::XPConnect();
   1.832 +        if (xpc) {
   1.833 +            nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   1.834 +            nsresult rv = xpc->WrapNative(cx, jsobj,
   1.835 +                                          static_cast<nsISupports*>(iid),
   1.836 +                                          NS_GET_IID(nsIJSID),
   1.837 +                                          getter_AddRefs(holder));
   1.838 +            if (NS_SUCCEEDED(rv) && holder) {
   1.839 +                obj = holder->GetJSObject();
   1.840 +            }
   1.841 +        }
   1.842 +    }
   1.843 +    return obj;
   1.844 +}
   1.845 +
   1.846 +// note: returned pointer is only valid while |obj| remains alive!
   1.847 +const nsID*
   1.848 +xpc_JSObjectToID(JSContext *cx, JSObject *obj)
   1.849 +{
   1.850 +    if (!cx || !obj)
   1.851 +        return nullptr;
   1.852 +
   1.853 +    // NOTE: this call does NOT addref
   1.854 +    XPCWrappedNative *wrapper = nullptr;
   1.855 +    obj = js::CheckedUnwrap(obj);
   1.856 +    if (obj && IS_WN_REFLECTOR(obj))
   1.857 +        wrapper = XPCWrappedNative::Get(obj);
   1.858 +    if (wrapper &&
   1.859 +        (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID))  ||
   1.860 +         wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
   1.861 +         wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSCID)))) {
   1.862 +        return ((nsIJSID*)wrapper->GetIdentityObject())->GetID();
   1.863 +    }
   1.864 +    return nullptr;
   1.865 +}
   1.866 +
   1.867 +bool
   1.868 +xpc_JSObjectIsID(JSContext *cx, JSObject *obj)
   1.869 +{
   1.870 +    MOZ_ASSERT(cx && obj, "bad param");
   1.871 +    // NOTE: this call does NOT addref
   1.872 +    XPCWrappedNative *wrapper = nullptr;
   1.873 +    obj = js::CheckedUnwrap(obj);
   1.874 +    if (obj && IS_WN_REFLECTOR(obj))
   1.875 +        wrapper = XPCWrappedNative::Get(obj);
   1.876 +    return wrapper &&
   1.877 +           (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID))  ||
   1.878 +            wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
   1.879 +            wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSCID)));
   1.880 +}
   1.881 +
   1.882 +

mercurial