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