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