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 +