diff options
Diffstat (limited to 'js/xpconnect/src/XPCComponents.cpp')
-rw-r--r-- | js/xpconnect/src/XPCComponents.cpp | 3563 |
1 files changed, 3563 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp new file mode 100644 index 000000000..ca78234c9 --- /dev/null +++ b/js/xpconnect/src/XPCComponents.cpp @@ -0,0 +1,3563 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* The "Components" xpcom objects for JavaScript. */ + +#include "xpcprivate.h" +#include "xpc_make_class.h" +#include "xpcIJSModuleLoader.h" +#include "XPCJSWeakReference.h" +#include "WrapperFactory.h" +#include "nsJSUtils.h" +#include "mozJSComponentLoader.h" +#include "nsContentUtils.h" +#include "nsCycleCollector.h" +#include "jsfriendapi.h" +#include "js/StructuredClone.h" +#include "mozilla/Attributes.h" +#include "mozilla/jsipc/CrossProcessObjectWrappers.h" +#include "mozilla/Preferences.h" +#include "nsJSEnvironment.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/XPTInterfaceInfoManager.h" +#include "mozilla/dom/DOMException.h" +#include "mozilla/dom/DOMExceptionBinding.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/StructuredCloneTags.h" +#include "mozilla/dom/WindowBinding.h" +#include "nsZipArchive.h" +#include "nsIDOMFileList.h" +#include "nsWindowMemoryReporter.h" +#include "nsDOMClassInfo.h" +#include "ShimInterfaceInfo.h" +#include "nsIAddonInterposition.h" +#include "nsISimpleEnumerator.h" +#include "nsPIDOMWindow.h" +#include "nsGlobalWindow.h" + +using namespace mozilla; +using namespace JS; +using namespace js; +using namespace xpc; +using mozilla::dom::Exception; + +/***************************************************************************/ +// stuff used by all + +nsresult +xpc::ThrowAndFail(nsresult errNum, JSContext* cx, bool* retval) +{ + XPCThrower::Throw(errNum, cx); + *retval = false; + return NS_OK; +} + +static bool +JSValIsInterfaceOfType(JSContext* cx, HandleValue v, REFNSIID iid) +{ + + nsCOMPtr<nsIXPConnectWrappedNative> wn; + nsCOMPtr<nsISupports> iface; + + if (v.isPrimitive()) + return false; + + nsXPConnect* xpc = nsXPConnect::XPConnect(); + RootedObject obj(cx, &v.toObject()); + return NS_SUCCEEDED(xpc->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wn))) && wn && + NS_SUCCEEDED(wn->Native()->QueryInterface(iid, getter_AddRefs(iface))) && iface; +} + +char* +xpc::CloneAllAccess() +{ + static const char allAccess[] = "AllAccess"; + return (char*)nsMemory::Clone(allAccess, sizeof(allAccess)); +} + +char* +xpc::CheckAccessList(const char16_t* wideName, const char* const list[]) +{ + nsAutoCString asciiName; + CopyUTF16toUTF8(nsDependentString(wideName), asciiName); + + for (const char* const* p = list; *p; p++) + if (!strcmp(*p, asciiName.get())) + return CloneAllAccess(); + + return nullptr; +} + +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ + + +class nsXPCComponents_Interfaces final : + public nsIXPCComponents_Interfaces, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCOMPONENTS_INTERFACES + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + +public: + nsXPCComponents_Interfaces(); + +private: + virtual ~nsXPCComponents_Interfaces(); + + nsCOMArray<nsIInterfaceInfo> mInterfaces; +}; + +NS_IMETHODIMP +nsXPCComponents_Interfaces::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCComponents_Interfaces) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Interfaces::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Interfaces::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_Interfaces::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCComponents_Interfaces"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Interfaces::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Interfaces::GetFlags(uint32_t* aFlags) +{ + // Mark ourselves as a DOM object so that instances may be created in + // unprivileged scopes. + *aFlags = nsIClassInfo::DOM_OBJECT; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Interfaces::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCComponents_Interfaces::nsXPCComponents_Interfaces() +{ +} + +nsXPCComponents_Interfaces::~nsXPCComponents_Interfaces() +{ + // empty +} + + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Interfaces) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Interfaces) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Interfaces) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_Interfaces) +NS_IMPL_RELEASE(nsXPCComponents_Interfaces) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_Interfaces +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Interfaces" +#define XPC_MAP_WANT_RESOLVE +#define XPC_MAP_WANT_NEWENUMERATE +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + + +NS_IMETHODIMP +nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* obj, + JS::AutoIdVector& properties, + bool* _retval) +{ + + // Lazily init the list of interfaces when someone tries to + // enumerate them. + if (mInterfaces.IsEmpty()) { + XPTInterfaceInfoManager::GetSingleton()-> + GetScriptableInterfaces(mInterfaces); + } + + if (!properties.reserve(mInterfaces.Length())) { + *_retval = false; + return NS_OK; + } + + for (uint32_t index = 0; index < mInterfaces.Length(); index++) { + nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(index); + if (!interface) + continue; + + const char* name; + if (NS_SUCCEEDED(interface->GetNameShared(&name)) && name) { + RootedString idstr(cx, JS_NewStringCopyZ(cx, name)); + if (!idstr) { + *_retval = false; + return NS_OK; + } + + RootedId id(cx); + if (!JS_StringToId(cx, idstr, &id)) { + *_retval = false; + return NS_OK; + } + + properties.infallibleAppend(id); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Interfaces::Resolve(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* objArg, + jsid idArg, bool* resolvedp, + bool* _retval) +{ + RootedObject obj(cx, objArg); + RootedId id(cx, idArg); + + if (!JSID_IS_STRING(id)) + return NS_OK; + + JSAutoByteString name; + RootedString str(cx, JSID_TO_STRING(id)); + + // we only allow interfaces by name here + if (name.encodeLatin1(cx, str) && name.ptr()[0] != '{') { + nsCOMPtr<nsIInterfaceInfo> info = + ShimInterfaceInfo::MaybeConstruct(name.ptr(), cx); + if (!info) { + XPTInterfaceInfoManager::GetSingleton()-> + GetInfoForName(name.ptr(), getter_AddRefs(info)); + } + if (!info) + return NS_OK; + + nsCOMPtr<nsIJSIID> nsid = nsJSIID::NewID(info); + + if (nsid) { + nsXPConnect* xpc = nsXPConnect::XPConnect(); + RootedObject idobj(cx); + if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, + static_cast<nsIJSIID*>(nsid), + NS_GET_IID(nsIJSIID), + idobj.address()))) { + if (idobj) { + *resolvedp = true; + *_retval = JS_DefinePropertyById(cx, obj, id, idobj, + JSPROP_ENUMERATE | + JSPROP_READONLY | + JSPROP_PERMANENT | + JSPROP_RESOLVING); + } + } + } + } + return NS_OK; +} + +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ + +class nsXPCComponents_InterfacesByID final : + public nsIXPCComponents_InterfacesByID, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCOMPONENTS_INTERFACESBYID + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + +public: + nsXPCComponents_InterfacesByID(); + +private: + virtual ~nsXPCComponents_InterfacesByID(); + + nsCOMArray<nsIInterfaceInfo> mInterfaces; +}; + +/***************************************************************************/ +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCComponents_InterfacesByID) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCComponents_InterfacesByID"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::GetFlags(uint32_t* aFlags) +{ + // Mark ourselves as a DOM object so that instances may be created in + // unprivileged scopes. + *aFlags = nsIClassInfo::DOM_OBJECT; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCComponents_InterfacesByID::nsXPCComponents_InterfacesByID() +{ +} + +nsXPCComponents_InterfacesByID::~nsXPCComponents_InterfacesByID() +{ + // empty +} + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_InterfacesByID) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_InterfacesByID) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_InterfacesByID) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_InterfacesByID) +NS_IMPL_RELEASE(nsXPCComponents_InterfacesByID) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_InterfacesByID +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_InterfacesByID" +#define XPC_MAP_WANT_RESOLVE +#define XPC_MAP_WANT_NEWENUMERATE +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* obj, + JS::AutoIdVector& properties, + bool* _retval) +{ + + if (mInterfaces.IsEmpty()) { + XPTInterfaceInfoManager::GetSingleton()-> + GetScriptableInterfaces(mInterfaces); + } + + if (!properties.reserve(mInterfaces.Length())) { + *_retval = false; + return NS_OK; + } + + for (uint32_t index = 0; index < mInterfaces.Length(); index++) { + nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(index); + if (!interface) + continue; + + nsIID const* iid; + if (NS_SUCCEEDED(interface->GetIIDShared(&iid))) { + char idstr[NSID_LENGTH]; + iid->ToProvidedString(idstr); + RootedString jsstr(cx, JS_NewStringCopyZ(cx, idstr)); + if (!jsstr) { + *_retval = false; + return NS_OK; + } + + RootedId id(cx); + if (!JS_StringToId(cx, jsstr, &id)) { + *_retval = false; + return NS_OK; + } + + properties.infallibleAppend(id); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_InterfacesByID::Resolve(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* objArg, + jsid idArg, bool* resolvedp, + bool* _retval) +{ + RootedObject obj(cx, objArg); + RootedId id(cx, idArg); + + if (!JSID_IS_STRING(id)) + return NS_OK; + + RootedString str(cx, JSID_TO_STRING(id)); + if (38 != JS_GetStringLength(str)) + return NS_OK; + + JSAutoByteString utf8str; + if (utf8str.encodeUtf8(cx, str)) { + nsID iid; + if (!iid.Parse(utf8str.ptr())) + return NS_OK; + + nsCOMPtr<nsIInterfaceInfo> info; + XPTInterfaceInfoManager::GetSingleton()-> + GetInfoForIID(&iid, getter_AddRefs(info)); + if (!info) + return NS_OK; + + nsCOMPtr<nsIJSIID> nsid = nsJSIID::NewID(info); + + if (!nsid) + return NS_ERROR_OUT_OF_MEMORY; + + nsXPConnect* xpc = nsXPConnect::XPConnect(); + RootedObject idobj(cx); + if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, + static_cast<nsIJSIID*>(nsid), + NS_GET_IID(nsIJSIID), + idobj.address()))) { + if (idobj) { + *resolvedp = true; + *_retval = + JS_DefinePropertyById(cx, obj, id, idobj, + JSPROP_ENUMERATE | + JSPROP_READONLY | + JSPROP_PERMANENT | + JSPROP_RESOLVING); + } + } + } + return NS_OK; +} + +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ + + + +class nsXPCComponents_Classes final : + public nsIXPCComponents_Classes, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCOMPONENTS_CLASSES + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + +public: + nsXPCComponents_Classes(); + +private: + virtual ~nsXPCComponents_Classes(); +}; + +/***************************************************************************/ +NS_IMETHODIMP +nsXPCComponents_Classes::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCComponents_Classes) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Classes::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Classes::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_Classes::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCComponents_Classes"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Classes::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Classes::GetFlags(uint32_t* aFlags) +{ + *aFlags = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Classes::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCComponents_Classes::nsXPCComponents_Classes() +{ +} + +nsXPCComponents_Classes::~nsXPCComponents_Classes() +{ + // empty +} + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Classes) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Classes) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Classes) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_Classes) +NS_IMPL_RELEASE(nsXPCComponents_Classes) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_Classes +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Classes" +#define XPC_MAP_WANT_RESOLVE +#define XPC_MAP_WANT_NEWENUMERATE +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + +NS_IMETHODIMP +nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* obj, + JS::AutoIdVector& properties, + bool* _retval) +{ + nsCOMPtr<nsIComponentRegistrar> compMgr; + if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsISimpleEnumerator> e; + if (NS_FAILED(compMgr->EnumerateContractIDs(getter_AddRefs(e))) || !e) + return NS_ERROR_UNEXPECTED; + + bool hasMore; + nsCOMPtr<nsISupports> isup; + while(NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore && + NS_SUCCEEDED(e->GetNext(getter_AddRefs(isup))) && isup) { + nsCOMPtr<nsISupportsCString> holder(do_QueryInterface(isup)); + if (!holder) + continue; + + nsAutoCString name; + if (NS_SUCCEEDED(holder->GetData(name))) { + RootedString idstr(cx, JS_NewStringCopyN(cx, name.get(), name.Length())); + if (!idstr) { + *_retval = false; + return NS_OK; + } + + RootedId id(cx); + if (!JS_StringToId(cx, idstr, &id)) { + *_retval = false; + return NS_OK; + } + + if (!properties.append(id)) { + *_retval = false; + return NS_OK; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Classes::Resolve(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* objArg, + jsid idArg, bool* resolvedp, + bool* _retval) + +{ + RootedId id(cx, idArg); + RootedObject obj(cx, objArg); + + JSAutoByteString name; + if (JSID_IS_STRING(id) && + name.encodeLatin1(cx, JSID_TO_STRING(id)) && + name.ptr()[0] != '{') { // we only allow contractids here + nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.ptr()); + if (nsid) { + nsXPConnect* xpc = nsXPConnect::XPConnect(); + RootedObject idobj(cx); + if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, + static_cast<nsIJSCID*>(nsid), + NS_GET_IID(nsIJSCID), + idobj.address()))) { + if (idobj) { + *resolvedp = true; + *_retval = JS_DefinePropertyById(cx, obj, id, idobj, + JSPROP_ENUMERATE | + JSPROP_READONLY | + JSPROP_PERMANENT | + JSPROP_RESOLVING); + } + } + } + } + return NS_OK; +} + +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ + +class nsXPCComponents_ClassesByID final : + public nsIXPCComponents_ClassesByID, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCOMPONENTS_CLASSESBYID + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + +public: + nsXPCComponents_ClassesByID(); + +private: + virtual ~nsXPCComponents_ClassesByID(); +}; + +/***************************************************************************/ +NS_IMETHODIMP +nsXPCComponents_ClassesByID::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCComponents_ClassesByID) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_ClassesByID::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_ClassesByID::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_ClassesByID::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCComponents_ClassesByID"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_ClassesByID::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_ClassesByID::GetFlags(uint32_t* aFlags) +{ + *aFlags = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_ClassesByID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCComponents_ClassesByID::nsXPCComponents_ClassesByID() +{ +} + +nsXPCComponents_ClassesByID::~nsXPCComponents_ClassesByID() +{ + // empty +} + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_ClassesByID) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_ClassesByID) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_ClassesByID) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_ClassesByID) +NS_IMPL_RELEASE(nsXPCComponents_ClassesByID) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_ClassesByID +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_ClassesByID" +#define XPC_MAP_WANT_RESOLVE +#define XPC_MAP_WANT_NEWENUMERATE +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + +NS_IMETHODIMP +nsXPCComponents_ClassesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* obj, + JS::AutoIdVector& properties, + bool* _retval) +{ + + nsCOMPtr<nsIComponentRegistrar> compMgr; + if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr) + return NS_ERROR_UNEXPECTED; + + nsISimpleEnumerator* e; + if (NS_FAILED(compMgr->EnumerateCIDs(&e)) || !e) + return NS_ERROR_UNEXPECTED; + + bool hasMore; + nsCOMPtr<nsISupports> isup; + while(NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore && + NS_SUCCEEDED(e->GetNext(getter_AddRefs(isup))) && isup) { + nsCOMPtr<nsISupportsID> holder(do_QueryInterface(isup)); + if (!holder) + continue; + + char* name; + if (NS_SUCCEEDED(holder->ToString(&name)) && name) { + RootedString idstr(cx, JS_NewStringCopyZ(cx, name)); + if (!idstr) { + *_retval = false; + return NS_OK; + } + + RootedId id(cx); + if (!JS_StringToId(cx, idstr, &id)) { + *_retval = false; + return NS_OK; + } + + if (!properties.append(id)) { + *_retval = false; + return NS_OK; + } + } + } + + return NS_OK; +} + +static bool +IsRegisteredCLSID(const char* str) +{ + bool registered; + nsID id; + + if (!id.Parse(str)) + return false; + + nsCOMPtr<nsIComponentRegistrar> compMgr; + if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr || + NS_FAILED(compMgr->IsCIDRegistered(id, ®istered))) + return false; + + return registered; +} + +NS_IMETHODIMP +nsXPCComponents_ClassesByID::Resolve(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* objArg, + jsid idArg, bool* resolvedp, + bool* _retval) +{ + RootedObject obj(cx, objArg); + RootedId id(cx, idArg); + + if (!JSID_IS_STRING(id)) + return NS_OK; + + JSAutoByteString name; + RootedString str(cx, JSID_TO_STRING(id)); + if (name.encodeLatin1(cx, str) && name.ptr()[0] == '{' && + IsRegisteredCLSID(name.ptr())) // we only allow canonical CLSIDs here + { + nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.ptr()); + if (nsid) { + nsXPConnect* xpc = nsXPConnect::XPConnect(); + RootedObject idobj(cx); + if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, + static_cast<nsIJSCID*>(nsid), + NS_GET_IID(nsIJSCID), + idobj.address()))) { + if (idobj) { + *resolvedp = true; + *_retval = JS_DefinePropertyById(cx, obj, id, idobj, + JSPROP_ENUMERATE | + JSPROP_READONLY | + JSPROP_PERMANENT | + JSPROP_RESOLVING); + } + } + } + } + return NS_OK; +} + + +/***************************************************************************/ + +// Currently the possible results do not change at runtime, so they are only +// cached once (unlike ContractIDs, CLSIDs, and IIDs) + +class nsXPCComponents_Results final : + public nsIXPCComponents_Results, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCOMPONENTS_RESULTS + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + +public: + nsXPCComponents_Results(); + +private: + virtual ~nsXPCComponents_Results(); +}; + +/***************************************************************************/ +NS_IMETHODIMP +nsXPCComponents_Results::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCComponents_Results) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Results::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Results::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_Results::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCComponents_Results"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Results::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Results::GetFlags(uint32_t* aFlags) +{ + // Mark ourselves as a DOM object so that instances may be created in + // unprivileged scopes. + *aFlags = nsIClassInfo::DOM_OBJECT; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Results::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCComponents_Results::nsXPCComponents_Results() +{ +} + +nsXPCComponents_Results::~nsXPCComponents_Results() +{ + // empty +} + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Results) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Results) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Results) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_Results) +NS_IMPL_RELEASE(nsXPCComponents_Results) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_Results +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Results" +#define XPC_MAP_WANT_RESOLVE +#define XPC_MAP_WANT_NEWENUMERATE +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + +NS_IMETHODIMP +nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* obj, + JS::AutoIdVector& properties, + bool* _retval) +{ + const char* name; + const void* iter = nullptr; + while (nsXPCException::IterateNSResults(nullptr, &name, nullptr, &iter)) { + RootedString idstr(cx, JS_NewStringCopyZ(cx, name)); + if (!idstr) { + *_retval = false; + return NS_OK; + } + + RootedId id(cx); + if (!JS_StringToId(cx, idstr, &id)) { + *_retval = false; + return NS_OK; + } + + if (!properties.append(id)) { + *_retval = false; + return NS_OK; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Results::Resolve(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* objArg, + jsid idArg, bool* resolvedp, + bool* _retval) +{ + RootedObject obj(cx, objArg); + RootedId id(cx, idArg); + JSAutoByteString name; + + if (JSID_IS_STRING(id) && name.encodeLatin1(cx, JSID_TO_STRING(id))) { + const char* rv_name; + const void* iter = nullptr; + nsresult rv; + while (nsXPCException::IterateNSResults(&rv, &rv_name, nullptr, &iter)) { + if (!strcmp(name.ptr(), rv_name)) { + *resolvedp = true; + if (!JS_DefinePropertyById(cx, obj, id, (uint32_t)rv, + JSPROP_ENUMERATE | + JSPROP_READONLY | + JSPROP_PERMANENT | + JSPROP_RESOLVING)) { + return NS_ERROR_UNEXPECTED; + } + } + } + } + return NS_OK; +} + +/***************************************************************************/ +// JavaScript Constructor for nsIJSID objects (Components.ID) + +class nsXPCComponents_ID final : + public nsIXPCComponents_ID, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCOMPONENTS_ID + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + + +public: + nsXPCComponents_ID(); + +private: + virtual ~nsXPCComponents_ID(); + static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, HandleObject obj, + const CallArgs& args, bool* _retval); +}; + +/***************************************************************************/ +NS_IMETHODIMP +nsXPCComponents_ID::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCComponents_ID) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_ID::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_ID::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_ID::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCComponents_ID"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_ID::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_ID::GetFlags(uint32_t* aFlags) +{ + *aFlags = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_ID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCComponents_ID::nsXPCComponents_ID() +{ +} + +nsXPCComponents_ID::~nsXPCComponents_ID() +{ + // empty +} + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_ID) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_ID) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_ID) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_ID) +NS_IMPL_RELEASE(nsXPCComponents_ID) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_ID +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_ID" +#define XPC_MAP_WANT_CALL +#define XPC_MAP_WANT_CONSTRUCT +#define XPC_MAP_WANT_HASINSTANCE +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + + +NS_IMETHODIMP +nsXPCComponents_ID::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, + const CallArgs& args, bool* _retval) +{ + RootedObject obj(cx, objArg); + return CallOrConstruct(wrapper, cx, obj, args, _retval); +} + +NS_IMETHODIMP +nsXPCComponents_ID::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, + const CallArgs& args, bool* _retval) +{ + RootedObject obj(cx, objArg); + return CallOrConstruct(wrapper, cx, obj, args, _retval); +} + +// static +nsresult +nsXPCComponents_ID::CallOrConstruct(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, HandleObject obj, + const CallArgs& args, bool* _retval) +{ + // make sure we have at least one arg + + if (args.length() < 1) + return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval); + + // Do the security check if necessary + + if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, nsJSID::GetCID()))) { + // the security manager vetoed. It should have set an exception. + *_retval = false; + return NS_OK; + } + + // convert the first argument into a string and see if it looks like an id + + JSString* jsstr; + JSAutoByteString bytes; + nsID id; + + if (!(jsstr = ToString(cx, args[0])) || + !bytes.encodeLatin1(cx, jsstr) || + !id.Parse(bytes.ptr())) { + return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval); + } + + // make the new object and return it. + + JSObject* newobj = xpc_NewIDObject(cx, obj, id); + if (!newobj) + return NS_ERROR_UNEXPECTED; + + args.rval().setObject(*newobj); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_ID::HasInstance(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, JSObject* obj, + HandleValue val, bool* bp, bool* _retval) +{ + if (bp) + *bp = JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIJSID)); + return NS_OK; +} + +/***************************************************************************/ +// JavaScript Constructor for nsIXPCException objects (Components.Exception) + +class nsXPCComponents_Exception final : + public nsIXPCComponents_Exception, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCOMPONENTS_EXCEPTION + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + + +public: + nsXPCComponents_Exception(); + +private: + virtual ~nsXPCComponents_Exception(); + static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, HandleObject obj, + const CallArgs& args, bool* _retval); +}; + +/***************************************************************************/ +NS_IMETHODIMP +nsXPCComponents_Exception::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCComponents_Exception) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Exception::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Exception::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_Exception::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCComponents_Exception"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Exception::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Exception::GetFlags(uint32_t* aFlags) +{ + *aFlags = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Exception::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCComponents_Exception::nsXPCComponents_Exception() +{ +} + +nsXPCComponents_Exception::~nsXPCComponents_Exception() +{ + // empty +} + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Exception) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Exception) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Exception) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_Exception) +NS_IMPL_RELEASE(nsXPCComponents_Exception) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_Exception +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Exception" +#define XPC_MAP_WANT_CALL +#define XPC_MAP_WANT_CONSTRUCT +#define XPC_MAP_WANT_HASINSTANCE +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + + +NS_IMETHODIMP +nsXPCComponents_Exception::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, + const CallArgs& args, bool* _retval) +{ + RootedObject obj(cx, objArg); + return CallOrConstruct(wrapper, cx, obj, args, _retval); +} + +NS_IMETHODIMP +nsXPCComponents_Exception::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, + JSObject* objArg, const CallArgs& args, bool* _retval) +{ + RootedObject obj(cx, objArg); + return CallOrConstruct(wrapper, cx, obj, args, _retval); +} + +struct MOZ_STACK_CLASS ExceptionArgParser +{ + ExceptionArgParser(JSContext* context, + nsXPConnect* xpconnect) + : eMsg("exception") + , eResult(NS_ERROR_FAILURE) + , cx(context) + , xpc(xpconnect) + {} + + // Public exception parameter values. During construction, these are + // initialized to the appropriate defaults. + const char* eMsg; + nsresult eResult; + nsCOMPtr<nsIStackFrame> eStack; + nsCOMPtr<nsISupports> eData; + + // Parse the constructor arguments into the above |eFoo| parameter values. + bool parse(const CallArgs& args) { + /* + * The Components.Exception takes a series of arguments, all of them + * optional: + * + * Argument 0: Exception message (defaults to 'exception'). + * Argument 1: Result code (defaults to NS_ERROR_FAILURE) _or_ options + * object (see below). + * Argument 2: Stack (defaults to the current stack, which we trigger + * by leaving this nullptr in the parser). + * Argument 3: Optional user data (defaults to nullptr). + * + * To dig our way out of this clunky API, we now support passing an + * options object as the second parameter (as opposed to a result code). + * If this is the case, all subsequent arguments are ignored, and the + * following properties are parsed out of the object (using the + * associated default if the property does not exist): + * + * result: Result code (see argument 1). + * stack: Call stack (see argument 2). + * data: User data (see argument 3). + */ + if (args.length() > 0 && !parseMessage(args[0])) + return false; + if (args.length() > 1) { + if (args[1].isObject()) { + RootedObject obj(cx, &args[1].toObject()); + return parseOptionsObject(obj); + } + if (!parseResult(args[1])) + return false; + } + if (args.length() > 2) { + if (!parseStack(args[2])) + return false; + } + if (args.length() > 3) { + if (!parseData(args[3])) + return false; + } + return true; + } + + protected: + + /* + * Parsing helpers. + */ + + bool parseMessage(HandleValue v) { + JSString* str = ToString(cx, v); + if (!str) + return false; + eMsg = messageBytes.encodeLatin1(cx, str); + return !!eMsg; + } + + bool parseResult(HandleValue v) { + return JS::ToUint32(cx, v, (uint32_t*) &eResult); + } + + bool parseStack(HandleValue v) { + if (!v.isObject()) { + // eStack has already been initialized to null, which is what we want + // for any non-object values (including null). + return true; + } + + return NS_SUCCEEDED(xpc->WrapJS(cx, &v.toObject(), + NS_GET_IID(nsIStackFrame), + getter_AddRefs(eStack))); + } + + bool parseData(HandleValue v) { + if (!v.isObject()) { + // eData has already been initialized to null, which is what we want + // for any non-object values (including null). + return true; + } + + return NS_SUCCEEDED(xpc->WrapJS(cx, &v.toObject(), + NS_GET_IID(nsISupports), + getter_AddRefs(eData))); + } + + bool parseOptionsObject(HandleObject obj) { + RootedValue v(cx); + + if (!getOption(obj, "result", &v) || + (!v.isUndefined() && !parseResult(v))) + return false; + + if (!getOption(obj, "stack", &v) || + (!v.isUndefined() && !parseStack(v))) + return false; + + if (!getOption(obj, "data", &v) || + (!v.isUndefined() && !parseData(v))) + return false; + + return true; + } + + bool getOption(HandleObject obj, const char* name, MutableHandleValue rv) { + // Look for the property. + bool found; + if (!JS_HasProperty(cx, obj, name, &found)) + return false; + + // If it wasn't found, indicate with undefined. + if (!found) { + rv.setUndefined(); + return true; + } + + // Get the property. + return JS_GetProperty(cx, obj, name, rv); + } + + /* + * Internal data members. + */ + + // If there's a non-default exception string, hold onto the allocated bytes. + JSAutoByteString messageBytes; + + // Various bits and pieces that are helpful to have around. + JSContext* cx; + nsXPConnect* xpc; +}; + +// static +nsresult +nsXPCComponents_Exception::CallOrConstruct(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, HandleObject obj, + const CallArgs& args, bool* _retval) +{ + nsXPConnect* xpc = nsXPConnect::XPConnect(); + + // Do the security check if necessary + + if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, Exception::GetCID()))) { + // the security manager vetoed. It should have set an exception. + *_retval = false; + return NS_OK; + } + + // Parse the arguments to the Exception constructor. + ExceptionArgParser parser(cx, xpc); + if (!parser.parse(args)) + return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); + + nsCOMPtr<nsIException> e = new Exception(nsCString(parser.eMsg), + parser.eResult, + EmptyCString(), + parser.eStack, + parser.eData); + + RootedObject newObj(cx); + if (NS_FAILED(xpc->WrapNative(cx, obj, e, NS_GET_IID(nsIXPCException), newObj.address())) || !newObj) { + return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval); + } + + args.rval().setObject(*newObj); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative* wrapper, + JSContext * cx, JSObject * obj, + HandleValue val, bool* bp, + bool* _retval) +{ + using namespace mozilla::dom; + + if (bp) { + *bp = (val.isObject() && + IS_INSTANCE_OF(Exception, &val.toObject())) || + JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIException)); + } + return NS_OK; +} + +/***************************************************************************/ +// This class is for the thing returned by "new Component.Constructor". + +// XXXjband we use this CID for security check, but security system can't see +// it since it has no registed factory. Security really kicks in when we try +// to build a wrapper around an instance. + +// {B4A95150-E25A-11d3-8F61-0010A4E73D9A} +#define NS_XPCCONSTRUCTOR_CID \ +{ 0xb4a95150, 0xe25a, 0x11d3, \ + { 0x8f, 0x61, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a } } + +class nsXPCConstructor : + public nsIXPCConstructor, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCCONSTRUCTOR_CID) +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCONSTRUCTOR + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + +public: + nsXPCConstructor() = delete; + nsXPCConstructor(nsIJSCID* aClassID, + nsIJSIID* aInterfaceID, + const char* aInitializer); + +private: + virtual ~nsXPCConstructor(); + nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, HandleObject obj, + const CallArgs& args, bool* _retval); +private: + RefPtr<nsIJSCID> mClassID; + RefPtr<nsIJSIID> mInterfaceID; + char* mInitializer; +}; + +/***************************************************************************/ +NS_IMETHODIMP +nsXPCConstructor::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCConstructor) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCConstructor::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCConstructor::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCConstructor::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCConstructor"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCConstructor::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCConstructor::GetFlags(uint32_t* aFlags) +{ + *aFlags = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCConstructor::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCConstructor::nsXPCConstructor(nsIJSCID* aClassID, + nsIJSIID* aInterfaceID, + const char* aInitializer) + : mClassID(aClassID), + mInterfaceID(aInterfaceID) +{ + mInitializer = aInitializer ? + (char*) nsMemory::Clone(aInitializer, strlen(aInitializer)+1) : + nullptr; +} + +nsXPCConstructor::~nsXPCConstructor() +{ + if (mInitializer) + free(mInitializer); +} + +NS_IMETHODIMP +nsXPCConstructor::GetClassID(nsIJSCID * *aClassID) +{ + RefPtr<nsIJSCID> rval = mClassID; + rval.forget(aClassID); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCConstructor::GetInterfaceID(nsIJSIID * *aInterfaceID) +{ + RefPtr<nsIJSIID> rval = mInterfaceID; + rval.forget(aInterfaceID); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCConstructor::GetInitializer(char * *aInitializer) +{ + XPC_STRING_GETTER_BODY(aInitializer, mInitializer); +} + +NS_INTERFACE_MAP_BEGIN(nsXPCConstructor) + NS_INTERFACE_MAP_ENTRY(nsIXPCConstructor) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCConstructor) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCConstructor) +NS_IMPL_RELEASE(nsXPCConstructor) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCConstructor +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCConstructor" +#define XPC_MAP_WANT_CALL +#define XPC_MAP_WANT_CONSTRUCT +#define XPC_MAP_FLAGS 0 +#include "xpc_map_end.h" /* This will #undef the above */ + + +NS_IMETHODIMP +nsXPCConstructor::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, + const CallArgs& args, bool* _retval) +{ + RootedObject obj(cx, objArg); + return CallOrConstruct(wrapper, cx, obj, args, _retval); + +} + +NS_IMETHODIMP +nsXPCConstructor::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, + const CallArgs& args, bool* _retval) +{ + RootedObject obj(cx, objArg); + return CallOrConstruct(wrapper, cx, obj, args, _retval); +} + +// static +nsresult +nsXPCConstructor::CallOrConstruct(nsIXPConnectWrappedNative* wrapper,JSContext* cx, + HandleObject obj, const CallArgs& args, bool* _retval) +{ + nsXPConnect* xpc = nsXPConnect::XPConnect(); + + // security check not required because we are going to call through the + // code which is reflected into JS which will do that for us later. + + RootedObject cidObj(cx); + RootedObject iidObj(cx); + + if (NS_FAILED(xpc->WrapNative(cx, obj, mClassID, NS_GET_IID(nsIJSCID), cidObj.address())) || !cidObj || + NS_FAILED(xpc->WrapNative(cx, obj, mInterfaceID, NS_GET_IID(nsIJSIID), iidObj.address())) || !iidObj) { + return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval); + } + + JS::Rooted<JS::Value> arg(cx, ObjectValue(*iidObj)); + RootedValue rval(cx); + if (!JS_CallFunctionName(cx, cidObj, "createInstance", JS::HandleValueArray(arg), &rval) || + rval.isPrimitive()) { + // createInstance will have thrown an exception + *_retval = false; + return NS_OK; + } + + args.rval().set(rval); + + // call initializer method if supplied + if (mInitializer) { + RootedObject newObj(cx, &rval.toObject()); + // first check existence of function property for better error reporting + RootedValue fun(cx); + if (!JS_GetProperty(cx, newObj, mInitializer, &fun) || + fun.isPrimitive()) { + return ThrowAndFail(NS_ERROR_XPC_BAD_INITIALIZER_NAME, cx, _retval); + } + + RootedValue dummy(cx); + if (!JS_CallFunctionValue(cx, newObj, fun, args, &dummy)) { + // function should have thrown an exception + *_retval = false; + return NS_OK; + } + } + + return NS_OK; +} + +/*******************************************************/ +// JavaScript Constructor for nsIXPCConstructor objects (Components.Constructor) + +class nsXPCComponents_Constructor final : + public nsIXPCComponents_Constructor, + public nsIXPCScriptable, + public nsIClassInfo +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCCOMPONENTS_CONSTRUCTOR + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSICLASSINFO + +public: + nsXPCComponents_Constructor(); + +private: + virtual ~nsXPCComponents_Constructor(); + static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, HandleObject obj, + const CallArgs& args, bool* _retval); +}; + +/***************************************************************************/ +NS_IMETHODIMP +nsXPCComponents_Constructor::GetInterfaces(uint32_t* aCount, nsIID * **aArray) +{ + const uint32_t count = 2; + *aCount = count; + nsIID** array; + *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + uint32_t index = 0; + nsIID* clone; +#define PUSH_IID(id) \ + clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ + sizeof(nsIID))); \ + if (!clone) \ + goto oom; \ + array[index++] = clone; + + PUSH_IID(nsIXPCComponents_Constructor) + PUSH_IID(nsIXPCScriptable) +#undef PUSH_IID + + return NS_OK; +oom: + while (index) + free(array[--index]); + free(array); + *aArray = nullptr; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Constructor::GetScriptableHelper(nsIXPCScriptable** retval) +{ + *retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Constructor::GetContractID(char * *aContractID) +{ + *aContractID = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_Constructor::GetClassDescription(char * *aClassDescription) +{ + static const char classDescription[] = "XPCComponents_Constructor"; + *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); + return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsXPCComponents_Constructor::GetClassID(nsCID * *aClassID) +{ + *aClassID = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Constructor::GetFlags(uint32_t* aFlags) +{ + *aFlags = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Constructor::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +nsXPCComponents_Constructor::nsXPCComponents_Constructor() +{ +} + +nsXPCComponents_Constructor::~nsXPCComponents_Constructor() +{ + // empty +} + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Constructor) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Constructor) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsIClassInfo) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Constructor) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_Constructor) +NS_IMPL_RELEASE(nsXPCComponents_Constructor) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_Constructor +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Constructor" +#define XPC_MAP_WANT_CALL +#define XPC_MAP_WANT_CONSTRUCT +#define XPC_MAP_WANT_HASINSTANCE +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + + +NS_IMETHODIMP +nsXPCComponents_Constructor::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, + JSObject* objArg, const CallArgs& args, bool* _retval) +{ + RootedObject obj(cx, objArg); + return CallOrConstruct(wrapper, cx, obj, args, _retval); +} + +NS_IMETHODIMP +nsXPCComponents_Constructor::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, + JSObject* objArg, const CallArgs& args, bool* _retval) +{ + RootedObject obj(cx, objArg); + return CallOrConstruct(wrapper, cx, obj, args, _retval); +} + +// static +nsresult +nsXPCComponents_Constructor::CallOrConstruct(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, HandleObject obj, + const CallArgs& args, bool* _retval) +{ + // make sure we have at least one arg + + if (args.length() < 1) + return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval); + + // get the various other object pointers we need + + nsXPConnect* xpc = nsXPConnect::XPConnect(); + XPCWrappedNativeScope* scope = ObjectScope(obj); + nsCOMPtr<nsIXPCComponents> comp; + + if (!xpc || !scope || !(comp = do_QueryInterface(scope->GetComponents()))) + return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); + + // Do the security check if necessary + + if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, nsXPCConstructor::GetCID()))) { + // the security manager vetoed. It should have set an exception. + *_retval = false; + return NS_OK; + } + + // initialization params for the Constructor object we will create + nsCOMPtr<nsIJSCID> cClassID; + nsCOMPtr<nsIJSIID> cInterfaceID; + const char* cInitializer = nullptr; + JSAutoByteString cInitializerBytes; + + if (args.length() >= 3) { + // args[2] is an initializer function or property name + RootedString str(cx, ToString(cx, args[2])); + if (!str || !(cInitializer = cInitializerBytes.encodeLatin1(cx, str))) + return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); + } + + if (args.length() >= 2) { + // args[1] is an iid name string + // XXXjband support passing "Components.interfaces.foo"? + + nsCOMPtr<nsIXPCComponents_Interfaces> ifaces; + RootedObject ifacesObj(cx); + + // we do the lookup by asking the Components.interfaces object + // for the property with this name - i.e. we let its caching of these + // nsIJSIID objects work for us. + + if (NS_FAILED(comp->GetInterfaces(getter_AddRefs(ifaces))) || + NS_FAILED(xpc->WrapNative(cx, obj, ifaces, + NS_GET_IID(nsIXPCComponents_Interfaces), + ifacesObj.address())) || !ifacesObj) { + return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); + } + + RootedString str(cx, ToString(cx, args[1])); + RootedId id(cx); + if (!str || !JS_StringToId(cx, str, &id)) + return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); + + RootedValue val(cx); + if (!JS_GetPropertyById(cx, ifacesObj, id, &val) || val.isPrimitive()) + return ThrowAndFail(NS_ERROR_XPC_BAD_IID, cx, _retval); + + nsCOMPtr<nsIXPConnectWrappedNative> wn; + if (NS_FAILED(xpc->GetWrappedNativeOfJSObject(cx, &val.toObject(), + getter_AddRefs(wn))) || !wn || + !(cInterfaceID = do_QueryWrappedNative(wn))) { + return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); + } + } else { + nsCOMPtr<nsIInterfaceInfo> info; + xpc->GetInfoForIID(&NS_GET_IID(nsISupports), getter_AddRefs(info)); + + if (info) { + cInterfaceID = nsJSIID::NewID(info); + } + if (!cInterfaceID) + return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); + } + + // a new scope to avoid warnings about shadowed names + { + // argv[0] is a contractid name string + // XXXjband support passing "Components.classes.foo"? + + // we do the lookup by asking the Components.classes object + // for the property with this name - i.e. we let its caching of these + // nsIJSCID objects work for us. + + nsCOMPtr<nsIXPCComponents_Classes> classes; + RootedObject classesObj(cx); + + if (NS_FAILED(comp->GetClasses(getter_AddRefs(classes))) || + NS_FAILED(xpc->WrapNative(cx, obj, classes, + NS_GET_IID(nsIXPCComponents_Classes), + classesObj.address())) || !classesObj) { + return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); + } + + RootedString str(cx, ToString(cx, args[0])); + RootedId id(cx); + if (!str || !JS_StringToId(cx, str, &id)) + return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); + + RootedValue val(cx); + if (!JS_GetPropertyById(cx, classesObj, id, &val) || val.isPrimitive()) + return ThrowAndFail(NS_ERROR_XPC_BAD_CID, cx, _retval); + + nsCOMPtr<nsIXPConnectWrappedNative> wn; + if (NS_FAILED(xpc->GetWrappedNativeOfJSObject(cx, val.toObjectOrNull(), + getter_AddRefs(wn))) || !wn || + !(cClassID = do_QueryWrappedNative(wn))) { + return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); + } + } + + nsCOMPtr<nsIXPCConstructor> ctor = new nsXPCConstructor(cClassID, cInterfaceID, cInitializer); + RootedObject newObj(cx); + + if (NS_FAILED(xpc->WrapNative(cx, obj, ctor, NS_GET_IID(nsIXPCConstructor), newObj.address())) || !newObj) { + return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval); + } + + args.rval().setObject(*newObj); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Constructor::HasInstance(nsIXPConnectWrappedNative* wrapper, + JSContext * cx, JSObject * obj, + HandleValue val, bool* bp, + bool* _retval) +{ + if (bp) + *bp = JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIXPCConstructor)); + return NS_OK; +} + +class nsXPCComponents_Utils final : + public nsIXPCComponents_Utils, + public nsIXPCScriptable +{ +public: + // all the interface method declarations... + NS_DECL_ISUPPORTS + NS_DECL_NSIXPCSCRIPTABLE + NS_DECL_NSIXPCCOMPONENTS_UTILS + +public: + nsXPCComponents_Utils() { } + +private: + virtual ~nsXPCComponents_Utils() { } + nsCOMPtr<nsIXPCComponents_utils_Sandbox> mSandbox; +}; + +NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Utils) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Utils) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Utils) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsXPCComponents_Utils) +NS_IMPL_RELEASE(nsXPCComponents_Utils) + +// The nsIXPCScriptable map declaration that will generate stubs for us... +#define XPC_MAP_CLASSNAME nsXPCComponents_Utils +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Utils" +#define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE +#include "xpc_map_end.h" /* This will #undef the above */ + +NS_IMETHODIMP +nsXPCComponents_Utils::GetSandbox(nsIXPCComponents_utils_Sandbox** aSandbox) +{ + NS_ENSURE_ARG_POINTER(aSandbox); + if (!mSandbox) + mSandbox = NewSandboxConstructor(); + + nsCOMPtr<nsIXPCComponents_utils_Sandbox> rval = mSandbox; + rval.forget(aSandbox); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ReportError(HandleValue error, JSContext* cx) +{ + // This function shall never fail! Silently eat any failure conditions. + + nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); + if (!console) + return NS_OK; + + nsGlobalWindow* globalWin = CurrentWindowOrNull(cx); + nsPIDOMWindowInner* win = globalWin ? globalWin->AsInner() : nullptr; + const uint64_t innerWindowID = win ? win->WindowID() : 0; + + RootedObject errorObj(cx, error.isObject() ? &error.toObject() : nullptr); + JSErrorReport* err = errorObj ? JS_ErrorFromException(cx, errorObj) : nullptr; + + nsCOMPtr<nsIScriptError> scripterr; + + if (errorObj) { + JS::RootedObject stackVal(cx, + FindExceptionStackForConsoleReport(win, error)); + if (stackVal) { + scripterr = new nsScriptErrorWithStack(stackVal); + } + } + + nsString fileName; + int32_t lineNo = 0; + + if (!scripterr) { + nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack(); + if (frame) { + frame->GetFilename(cx, fileName); + frame->GetLineNumber(cx, &lineNo); + JS::Rooted<JS::Value> stack(cx); + nsresult rv = frame->GetNativeSavedFrame(&stack); + if (NS_SUCCEEDED(rv) && stack.isObject()) { + JS::Rooted<JSObject*> stackObj(cx, &stack.toObject()); + scripterr = new nsScriptErrorWithStack(stackObj); + } + } + } + + if (!scripterr) { + scripterr = new nsScriptError(); + } + + if (err) { + // It's a proper JS Error + nsAutoString fileUni; + CopyUTF8toUTF16(err->filename, fileUni); + + uint32_t column = err->tokenOffset(); + + const char16_t* linebuf = err->linebuf(); + + nsresult rv = scripterr->InitWithWindowID( + err->message() ? NS_ConvertUTF8toUTF16(err->message().c_str()) + : EmptyString(), + fileUni, + linebuf ? nsDependentString(linebuf, err->linebufLength()) : EmptyString(), + err->lineno, + column, err->flags, "XPConnect JavaScript", innerWindowID); + NS_ENSURE_SUCCESS(rv, NS_OK); + + console->LogMessage(scripterr); + return NS_OK; + } + + // It's not a JS Error object, so we synthesize as best we're able. + RootedString msgstr(cx, ToString(cx, error)); + if (!msgstr) + return NS_OK; + + nsAutoJSString msg; + if (!msg.init(cx, msgstr)) + return NS_OK; + + nsresult rv = scripterr->InitWithWindowID( + msg, fileName, EmptyString(), lineNo, 0, 0, + "XPConnect JavaScript", innerWindowID); + NS_ENSURE_SUCCESS(rv, NS_OK); + + console->LogMessage(scripterr); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::EvalInSandbox(const nsAString& source, + HandleValue sandboxVal, + HandleValue version, + const nsACString& filenameArg, + int32_t lineNumber, + JSContext* cx, + uint8_t optionalArgc, + MutableHandleValue retval) +{ + RootedObject sandbox(cx); + if (!JS_ValueToObject(cx, sandboxVal, &sandbox) || !sandbox) + return NS_ERROR_INVALID_ARG; + + // Optional third argument: JS version, as a string. + JSVersion jsVersion = JSVERSION_DEFAULT; + if (optionalArgc >= 1) { + JSString* jsVersionStr = ToString(cx, version); + if (!jsVersionStr) + return NS_ERROR_INVALID_ARG; + + JSAutoByteString bytes(cx, jsVersionStr); + if (!bytes) + return NS_ERROR_INVALID_ARG; + + jsVersion = JS_StringToVersion(bytes.ptr()); + // Explicitly check for "latest", which we support for sandboxes but + // isn't in the set of web-exposed version strings. + if (jsVersion == JSVERSION_UNKNOWN && + !strcmp(bytes.ptr(), "latest")) + { + jsVersion = JSVERSION_LATEST; + } + if (jsVersion == JSVERSION_UNKNOWN) + return NS_ERROR_INVALID_ARG; + } + + // Optional fourth and fifth arguments: filename and line number. + int32_t lineNo = (optionalArgc >= 3) ? lineNumber : 1; + nsCString filename; + if (!filenameArg.IsVoid()) { + filename.Assign(filenameArg); + } else { + // Get the current source info from xpc. + nsresult rv; + nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIStackFrame> frame; + xpc->GetCurrentJSStack(getter_AddRefs(frame)); + if (frame) { + nsString frameFile; + frame->GetFilename(cx, frameFile); + CopyUTF16toUTF8(frameFile, filename); + frame->GetLineNumber(cx, &lineNo); + } + } + + return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo, + jsVersion, retval); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetSandboxAddonId(HandleValue sandboxVal, + JSContext* cx, MutableHandleValue rval) +{ + if (!sandboxVal.isObject()) + return NS_ERROR_INVALID_ARG; + + RootedObject sandbox(cx, &sandboxVal.toObject()); + sandbox = js::CheckedUnwrap(sandbox); + if (!sandbox || !xpc::IsSandbox(sandbox)) + return NS_ERROR_INVALID_ARG; + + return xpc::GetSandboxAddonId(cx, sandbox, rval); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetSandboxMetadata(HandleValue sandboxVal, + JSContext* cx, MutableHandleValue rval) +{ + if (!sandboxVal.isObject()) + return NS_ERROR_INVALID_ARG; + + RootedObject sandbox(cx, &sandboxVal.toObject()); + sandbox = js::CheckedUnwrap(sandbox); + if (!sandbox || !xpc::IsSandbox(sandbox)) + return NS_ERROR_INVALID_ARG; + + return xpc::GetSandboxMetadata(cx, sandbox, rval); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::SetSandboxMetadata(HandleValue sandboxVal, + HandleValue metadataVal, + JSContext* cx) +{ + if (!sandboxVal.isObject()) + return NS_ERROR_INVALID_ARG; + + RootedObject sandbox(cx, &sandboxVal.toObject()); + sandbox = js::CheckedUnwrap(sandbox); + if (!sandbox || !xpc::IsSandbox(sandbox)) + return NS_ERROR_INVALID_ARG; + + nsresult rv = xpc::SetSandboxMetadata(cx, sandbox, metadataVal); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::Import(const nsACString& registryLocation, + HandleValue targetObj, + JSContext* cx, + uint8_t optionalArgc, + MutableHandleValue retval) +{ + nsCOMPtr<xpcIJSModuleLoader> moduleloader = + do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); + if (!moduleloader) + return NS_ERROR_FAILURE; + return moduleloader->Import(registryLocation, targetObj, cx, optionalArgc, retval); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::IsModuleLoaded(const nsACString& registryLocation, bool* retval) +{ + nsCOMPtr<xpcIJSModuleLoader> moduleloader = + do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); + if (!moduleloader) + return NS_ERROR_FAILURE; + return moduleloader->IsModuleLoaded(registryLocation, retval); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::Unload(const nsACString & registryLocation) +{ + nsCOMPtr<xpcIJSModuleLoader> moduleloader = + do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); + if (!moduleloader) + return NS_ERROR_FAILURE; + return moduleloader->Unload(registryLocation); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ImportGlobalProperties(HandleValue aPropertyList, + JSContext* cx) +{ + RootedObject global(cx, CurrentGlobalOrNull(cx)); + MOZ_ASSERT(global); + + // Don't allow doing this if the global is a Window + nsGlobalWindow* win; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, &global, win))) { + return NS_ERROR_NOT_AVAILABLE; + } + + GlobalProperties options; + NS_ENSURE_TRUE(aPropertyList.isObject(), NS_ERROR_INVALID_ARG); + + RootedObject propertyList(cx, &aPropertyList.toObject()); + bool isArray; + if (NS_WARN_IF(!JS_IsArrayObject(cx, propertyList, &isArray))) { + return NS_ERROR_FAILURE; + } + if (NS_WARN_IF(!isArray)) { + return NS_ERROR_INVALID_ARG; + } + + if (!options.Parse(cx, propertyList) || + !options.DefineInXPCComponents(cx, global)) + { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetWeakReference(HandleValue object, JSContext* cx, + xpcIJSWeakReference** _retval) +{ + RefPtr<xpcJSWeakReference> ref = new xpcJSWeakReference(); + nsresult rv = ref->Init(cx, object); + NS_ENSURE_SUCCESS(rv, rv); + ref.forget(_retval); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ForceGC() +{ + JSContext* cx = nsXPConnect::GetContextInstance()->Context(); + PrepareForFullGC(cx); + GCForReason(cx, GC_NORMAL, gcreason::COMPONENT_UTILS); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ForceCC(nsICycleCollectorListener* listener) +{ + nsJSContext::CycleCollectNow(listener); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::FinishCC() +{ + nsCycleCollector_finishAnyCurrentCollection(); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::CcSlice(int64_t budget) +{ + nsJSContext::RunCycleCollectorWorkSlice(budget); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetMaxCCSliceTimeSinceClear(int32_t* out) +{ + *out = nsJSContext::GetMaxCCSliceTimeSinceClear(); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ClearMaxCCTime() +{ + nsJSContext::ClearMaxCCSliceTime(); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ForceShrinkingGC() +{ + JSContext* cx = dom::danger::GetJSContext(); + PrepareForFullGC(cx); + GCForReason(cx, GC_SHRINK, gcreason::COMPONENT_UTILS); + return NS_OK; +} + +class PreciseGCRunnable : public Runnable +{ + public: + PreciseGCRunnable(ScheduledGCCallback* aCallback, bool aShrinking) + : mCallback(aCallback), mShrinking(aShrinking) {} + + NS_IMETHOD Run() override + { + JSContext* cx = dom::danger::GetJSContext(); + if (JS_IsRunning(cx)) + return NS_DispatchToMainThread(this); + + nsJSContext::GarbageCollectNow(gcreason::COMPONENT_UTILS, + nsJSContext::NonIncrementalGC, + mShrinking ? + nsJSContext::ShrinkingGC : + nsJSContext::NonShrinkingGC); + + mCallback->Callback(); + return NS_OK; + } + + private: + RefPtr<ScheduledGCCallback> mCallback; + bool mShrinking; +}; + +NS_IMETHODIMP +nsXPCComponents_Utils::SchedulePreciseGC(ScheduledGCCallback* aCallback) +{ + RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, false); + return NS_DispatchToMainThread(event); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::SchedulePreciseShrinkingGC(ScheduledGCCallback* aCallback) +{ + RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, true); + return NS_DispatchToMainThread(event); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::UnlinkGhostWindows() +{ +#ifdef DEBUG + nsWindowMemoryReporter::UnlinkGhostWindows(); + return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetJSTestingFunctions(JSContext* cx, + MutableHandleValue retval) +{ + JSObject* obj = js::GetTestingFunctions(cx); + if (!obj) + return NS_ERROR_XPC_JAVASCRIPT_ERROR; + retval.setObject(*obj); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::CallFunctionWithAsyncStack(HandleValue function, + nsIStackFrame* stack, + const nsAString& asyncCause, + JSContext* cx, + MutableHandleValue retval) +{ + nsresult rv; + + if (!stack || asyncCause.IsEmpty()) { + return NS_ERROR_INVALID_ARG; + } + + JS::Rooted<JS::Value> asyncStack(cx); + rv = stack->GetNativeSavedFrame(&asyncStack); + if (NS_FAILED(rv)) + return rv; + if (!asyncStack.isObject()) { + JS_ReportErrorASCII(cx, "Must use a native JavaScript stack frame"); + return NS_ERROR_INVALID_ARG; + } + + JS::Rooted<JSObject*> asyncStackObj(cx, &asyncStack.toObject()); + + NS_ConvertUTF16toUTF8 utf8Cause(asyncCause); + JS::AutoSetAsyncStackForNewCalls sas(cx, asyncStackObj, utf8Cause.get(), + JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT); + + if (!JS_CallFunctionValue(cx, nullptr, function, + JS::HandleValueArray::empty(), retval)) + { + return NS_ERROR_XPC_JAVASCRIPT_ERROR; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetGlobalForObject(HandleValue object, + JSContext* cx, + MutableHandleValue retval) +{ + // First argument must be an object. + if (object.isPrimitive()) + return NS_ERROR_XPC_BAD_CONVERT_JS; + + // Wrappers are parented to their the global in their home compartment. But + // when getting the global for a cross-compartment wrapper, we really want + // a wrapper for the foreign global. So we need to unwrap before getting the + // parent, enter the compartment for the duration of the call, and wrap the + // result. + Rooted<JSObject*> obj(cx, &object.toObject()); + obj = js::UncheckedUnwrap(obj); + { + JSAutoCompartment ac(cx, obj); + obj = JS_GetGlobalForObject(cx, obj); + } + + if (!JS_WrapObject(cx, &obj)) + return NS_ERROR_FAILURE; + + // Get the WindowProxy if necessary. + obj = js::ToWindowProxyIfWindow(obj); + + retval.setObject(*obj); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::IsProxy(HandleValue vobj, JSContext* cx, bool* rval) +{ + if (!vobj.isObject()) { + *rval = false; + return NS_OK; + } + + RootedObject obj(cx, &vobj.toObject()); + obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false); + NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE); + + *rval = js::IsScriptedProxy(obj); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ExportFunction(HandleValue vfunction, HandleValue vscope, + HandleValue voptions, JSContext* cx, + MutableHandleValue rval) +{ + if (!xpc::ExportFunction(cx, vfunction, vscope, voptions, rval)) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::CreateObjectIn(HandleValue vobj, HandleValue voptions, + JSContext* cx, MutableHandleValue rval) +{ + RootedObject optionsObject(cx, voptions.isObject() ? &voptions.toObject() + : nullptr); + CreateObjectInOptions options(cx, optionsObject); + if (voptions.isObject() && + !options.Parse()) + { + return NS_ERROR_FAILURE; + } + + if (!xpc::CreateObjectIn(cx, vobj, options, rval)) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::MakeObjectPropsNormal(HandleValue vobj, JSContext* cx) +{ + if (!cx) + return NS_ERROR_FAILURE; + + // first argument must be an object + if (vobj.isPrimitive()) + return NS_ERROR_XPC_BAD_CONVERT_JS; + + RootedObject obj(cx, js::UncheckedUnwrap(&vobj.toObject())); + JSAutoCompartment ac(cx, obj); + Rooted<IdVector> ida(cx, IdVector(cx)); + if (!JS_Enumerate(cx, obj, &ida)) + return NS_ERROR_FAILURE; + + RootedId id(cx); + RootedValue v(cx); + for (size_t i = 0; i < ida.length(); ++i) { + id = ida[i]; + + if (!JS_GetPropertyById(cx, obj, id, &v)) + return NS_ERROR_FAILURE; + + if (v.isPrimitive()) + continue; + + RootedObject propobj(cx, &v.toObject()); + // TODO Deal with non-functions. + if (!js::IsWrapper(propobj) || !JS::IsCallable(propobj)) + continue; + + FunctionForwarderOptions forwarderOptions; + if (!NewFunctionForwarder(cx, id, propobj, forwarderOptions, &v) || + !JS_SetPropertyById(cx, obj, id, v)) + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::IsDeadWrapper(HandleValue obj, bool* out) +{ + *out = false; + if (obj.isPrimitive()) + return NS_ERROR_INVALID_ARG; + + // Make sure to unwrap first. Once a proxy is nuked, it ceases to be a + // wrapper, meaning that, if passed to another compartment, we'll generate + // a CCW for it. Make sure that IsDeadWrapper sees through the confusion. + *out = JS_IsDeadWrapper(js::CheckedUnwrap(&obj.toObject())); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::IsCrossProcessWrapper(HandleValue obj, bool* out) +{ + *out = false; + if (obj.isPrimitive()) + return NS_ERROR_INVALID_ARG; + + *out = jsipc::IsWrappedCPOW(&obj.toObject()); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetCrossProcessWrapperTag(HandleValue obj, nsACString& out) +{ + if (obj.isPrimitive() || !jsipc::IsWrappedCPOW(&obj.toObject())) + return NS_ERROR_INVALID_ARG; + + jsipc::GetWrappedCPOWTag(&obj.toObject(), out); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::PermitCPOWsInScope(HandleValue obj) +{ + if (!obj.isObject()) + return NS_ERROR_INVALID_ARG; + + JSObject* scopeObj = js::UncheckedUnwrap(&obj.toObject()); + CompartmentPrivate::Get(scopeObj)->allowCPOWs = true; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::RecomputeWrappers(HandleValue vobj, JSContext* cx) +{ + // Determine the compartment of the given object, if any. + JSCompartment* c = vobj.isObject() + ? js::GetObjectCompartment(js::UncheckedUnwrap(&vobj.toObject())) + : nullptr; + + // If no compartment was given, recompute all. + if (!c) + js::RecomputeWrappers(cx, js::AllCompartments(), js::AllCompartments()); + // Otherwise, recompute wrappers for the given compartment. + else + js::RecomputeWrappers(cx, js::SingleCompartment(c), js::AllCompartments()) && + js::RecomputeWrappers(cx, js::AllCompartments(), js::SingleCompartment(c)); + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::SetWantXrays(HandleValue vscope, JSContext* cx) +{ + if (!vscope.isObject()) + return NS_ERROR_INVALID_ARG; + JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject()); + JSCompartment* compartment = js::GetObjectCompartment(scopeObj); + CompartmentPrivate::Get(scopeObj)->wantXrays = true; + bool ok = js::RecomputeWrappers(cx, js::SingleCompartment(compartment), + js::AllCompartments()); + NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ForcePermissiveCOWs(JSContext* cx) +{ + CrashIfNotInAutomation(); + CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->forcePermissiveCOWs = true; + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::ForcePrivilegedComponentsForScope(HandleValue vscope, + JSContext* cx) +{ + if (!vscope.isObject()) + return NS_ERROR_INVALID_ARG; + CrashIfNotInAutomation(); + JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject()); + XPCWrappedNativeScope* scope = ObjectScope(scopeObj); + scope->ForcePrivilegedComponents(); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetComponentsForScope(HandleValue vscope, JSContext* cx, + MutableHandleValue rval) +{ + if (!vscope.isObject()) + return NS_ERROR_INVALID_ARG; + JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject()); + XPCWrappedNativeScope* scope = ObjectScope(scopeObj); + RootedObject components(cx); + if (!scope->GetComponentsJSObject(&components)) + return NS_ERROR_FAILURE; + if (!JS_WrapObject(cx, &components)) + return NS_ERROR_FAILURE; + rval.setObject(*components); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::Dispatch(HandleValue runnableArg, HandleValue scope, + JSContext* cx) +{ + RootedValue runnable(cx, runnableArg); + // Enter the given compartment, if any, and rewrap runnable. + Maybe<JSAutoCompartment> ac; + if (scope.isObject()) { + JSObject* scopeObj = js::UncheckedUnwrap(&scope.toObject()); + if (!scopeObj) + return NS_ERROR_FAILURE; + ac.emplace(cx, scopeObj); + if (!JS_WrapValue(cx, &runnable)) + return NS_ERROR_FAILURE; + } + + // Get an XPCWrappedJS for |runnable|. + if (!runnable.isObject()) + return NS_ERROR_INVALID_ARG; + + nsCOMPtr<nsIRunnable> run; + nsresult rv = nsXPConnect::XPConnect()->WrapJS(cx, &runnable.toObject(), + NS_GET_IID(nsIRunnable), + getter_AddRefs(run)); + NS_ENSURE_SUCCESS(rv, rv); + MOZ_ASSERT(run); + + // Dispatch. + return NS_DispatchToMainThread(run); +} + +#define GENERATE_JSCONTEXTOPTION_GETTER_SETTER(_attr, _getter, _setter) \ + NS_IMETHODIMP \ + nsXPCComponents_Utils::Get## _attr(JSContext* cx, bool* aValue) \ + { \ + *aValue = ContextOptionsRef(cx)._getter(); \ + return NS_OK; \ + } \ + NS_IMETHODIMP \ + nsXPCComponents_Utils::Set## _attr(JSContext* cx, bool aValue) \ + { \ + ContextOptionsRef(cx)._setter(aValue); \ + return NS_OK; \ + } + +GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict, extraWarnings, setExtraWarnings) +GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Werror, werror, setWerror) +GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict_mode, strictMode, setStrictMode) +GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Ion, ion, setIon) + +#undef GENERATE_JSCONTEXTOPTION_GETTER_SETTER + +NS_IMETHODIMP +nsXPCComponents_Utils::SetGCZeal(int32_t aValue, JSContext* cx) +{ +#ifdef JS_GC_ZEAL + JS_SetGCZeal(cx, uint8_t(aValue), JS_DEFAULT_ZEAL_FREQ); +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx) +{ + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS); + NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG); + JSObject* wrapper = &obj.toObject(); + NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG); + JSObject* sb = UncheckedUnwrap(wrapper); + NS_ENSURE_TRUE(IsSandbox(sb), NS_ERROR_INVALID_ARG); + NukeCrossCompartmentWrappers(cx, AllCompartments(), + SingleCompartment(GetObjectCompartment(sb)), + NukeWindowReferences); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::BlockScriptForGlobal(HandleValue globalArg, + JSContext* cx) +{ + NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); + RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), + /* stopAtWindowProxy = */ false)); + NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); + if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) { + JS_ReportErrorASCII(cx, "Script may not be disabled for system globals"); + return NS_ERROR_FAILURE; + } + Scriptability::Get(global).Block(); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::UnblockScriptForGlobal(HandleValue globalArg, + JSContext* cx) +{ + NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); + RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), + /* stopAtWindowProxy = */ false)); + NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); + if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) { + JS_ReportErrorASCII(cx, "Script may not be disabled for system globals"); + return NS_ERROR_FAILURE; + } + Scriptability::Get(global).Unblock(); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::IsXrayWrapper(HandleValue obj, bool* aRetval) +{ + *aRetval = + obj.isObject() && xpc::WrapperFactory::IsXrayWrapper(&obj.toObject()); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::WaiveXrays(HandleValue aVal, JSContext* aCx, MutableHandleValue aRetval) +{ + RootedValue value(aCx, aVal); + if (!xpc::WrapperFactory::WaiveXrayAndWrap(aCx, &value)) + return NS_ERROR_FAILURE; + aRetval.set(value); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::UnwaiveXrays(HandleValue aVal, JSContext* aCx, MutableHandleValue aRetval) +{ + if (!aVal.isObject()) { + aRetval.set(aVal); + return NS_OK; + } + + RootedObject obj(aCx, js::UncheckedUnwrap(&aVal.toObject())); + if (!JS_WrapObject(aCx, &obj)) + return NS_ERROR_FAILURE; + aRetval.setObject(*obj); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetClassName(HandleValue aObj, bool aUnwrap, JSContext* aCx, char** aRv) +{ + if (!aObj.isObject()) + return NS_ERROR_INVALID_ARG; + RootedObject obj(aCx, &aObj.toObject()); + if (aUnwrap) + obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false); + *aRv = NS_strdup(js::GetObjectClass(obj)->name); + NS_ENSURE_TRUE(*aRv, NS_ERROR_OUT_OF_MEMORY); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetDOMClassInfo(const nsAString& aClassName, + nsIClassInfo** aClassInfo) +{ + *aClassInfo = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetIncumbentGlobal(HandleValue aCallback, + JSContext* aCx, MutableHandleValue aOut) +{ + nsCOMPtr<nsIGlobalObject> global = mozilla::dom::GetIncumbentGlobal(); + RootedValue globalVal(aCx); + + if (!global) { + globalVal = NullValue(); + } else { + // Note: We rely on the wrap call for outerization. + globalVal = ObjectValue(*global->GetGlobalJSObject()); + if (!JS_WrapValue(aCx, &globalVal)) + return NS_ERROR_FAILURE; + } + + // Invoke the callback, if passed. + if (aCallback.isObject()) { + RootedValue ignored(aCx); + if (!JS_CallFunctionValue(aCx, nullptr, aCallback, JS::HandleValueArray(globalVal), &ignored)) + return NS_ERROR_FAILURE; + } + + aOut.set(globalVal); + return NS_OK; +} + +/* + * Below is a bunch of awkward junk to allow JS test code to trigger the + * creation of an XPCWrappedJS, such that it ends up in the map. We need to + * hand the caller some sort of reference to hold onto (to prevent the + * refcount from dropping to zero as soon as the function returns), but trying + * to return a bonafide XPCWrappedJS to script causes all sorts of trouble. So + * we create a benign holder class instead, which acts as an opaque reference + * that script can use to keep the XPCWrappedJS alive and in the map. + */ + +class WrappedJSHolder : public nsISupports +{ + NS_DECL_ISUPPORTS + WrappedJSHolder() {} + + RefPtr<nsXPCWrappedJS> mWrappedJS; + +private: + virtual ~WrappedJSHolder() {} +}; +NS_IMPL_ISUPPORTS0(WrappedJSHolder); + +NS_IMETHODIMP +nsXPCComponents_Utils::GenerateXPCWrappedJS(HandleValue aObj, HandleValue aScope, + JSContext* aCx, nsISupports** aOut) +{ + if (!aObj.isObject()) + return NS_ERROR_INVALID_ARG; + RootedObject obj(aCx, &aObj.toObject()); + RootedObject scope(aCx, aScope.isObject() ? js::UncheckedUnwrap(&aScope.toObject()) + : CurrentGlobalOrNull(aCx)); + JSAutoCompartment ac(aCx, scope); + if (!JS_WrapObject(aCx, &obj)) + return NS_ERROR_FAILURE; + + RefPtr<WrappedJSHolder> holder = new WrappedJSHolder(); + nsresult rv = nsXPCWrappedJS::GetNewOrUsed(obj, NS_GET_IID(nsISupports), + getter_AddRefs(holder->mWrappedJS)); + holder.forget(aOut); + return rv; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory, PRTime* aOut) +{ + WatchdogTimestampCategory category; + if (aCategory.EqualsLiteral("ContextStateChange")) + category = TimestampContextStateChange; + else if (aCategory.EqualsLiteral("WatchdogWakeup")) + category = TimestampWatchdogWakeup; + else if (aCategory.EqualsLiteral("WatchdogHibernateStart")) + category = TimestampWatchdogHibernateStart; + else if (aCategory.EqualsLiteral("WatchdogHibernateStop")) + category = TimestampWatchdogHibernateStop; + else + return NS_ERROR_INVALID_ARG; + *aOut = XPCJSContext::Get()->GetWatchdogTimestamp(category); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetJSEngineTelemetryValue(JSContext* cx, MutableHandleValue rval) +{ + RootedObject obj(cx, JS_NewPlainObject(cx)); + if (!obj) + return NS_ERROR_OUT_OF_MEMORY; + + unsigned attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT; + + size_t i = JS_SetProtoCalled(cx); + RootedValue v(cx, DoubleValue(i)); + if (!JS_DefineProperty(cx, obj, "setProto", v, attrs)) + return NS_ERROR_OUT_OF_MEMORY; + + i = JS_GetCustomIteratorCount(cx); + v.setDouble(i); + if (!JS_DefineProperty(cx, obj, "customIter", v, attrs)) + return NS_ERROR_OUT_OF_MEMORY; + + rval.setObject(*obj); + return NS_OK; +} + +bool +xpc::CloneInto(JSContext* aCx, HandleValue aValue, HandleValue aScope, + HandleValue aOptions, MutableHandleValue aCloned) +{ + if (!aScope.isObject()) + return false; + + RootedObject scope(aCx, &aScope.toObject()); + scope = js::CheckedUnwrap(scope); + if(!scope) { + JS_ReportErrorASCII(aCx, "Permission denied to clone object into scope"); + return false; + } + + if (!aOptions.isUndefined() && !aOptions.isObject()) { + JS_ReportErrorASCII(aCx, "Invalid argument"); + return false; + } + + RootedObject optionsObject(aCx, aOptions.isObject() ? &aOptions.toObject() + : nullptr); + StackScopedCloneOptions options(aCx, optionsObject); + if (aOptions.isObject() && !options.Parse()) + return false; + + { + JSAutoCompartment ac(aCx, scope); + aCloned.set(aValue); + if (!StackScopedClone(aCx, options, aCloned)) + return false; + } + + return JS_WrapValue(aCx, aCloned); +} + +NS_IMETHODIMP +nsXPCComponents_Utils::CloneInto(HandleValue aValue, HandleValue aScope, + HandleValue aOptions, JSContext* aCx, + MutableHandleValue aCloned) +{ + return xpc::CloneInto(aCx, aValue, aScope, aOptions, aCloned) ? + NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetWebIDLCallerPrincipal(nsIPrincipal** aResult) +{ + // This API may only be when the Entry Settings Object corresponds to a + // JS-implemented WebIDL call. In all other cases, the value will be null, + // and we throw. + nsCOMPtr<nsIPrincipal> callerPrin = mozilla::dom::GetWebIDLCallerPrincipal(); + if (!callerPrin) + return NS_ERROR_NOT_AVAILABLE; + callerPrin.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetObjectPrincipal(HandleValue val, JSContext* cx, + nsIPrincipal** result) +{ + if (!val.isObject()) + return NS_ERROR_INVALID_ARG; + RootedObject obj(cx, &val.toObject()); + obj = js::CheckedUnwrap(obj); + MOZ_ASSERT(obj); + + nsCOMPtr<nsIPrincipal> prin = nsContentUtils::ObjectPrincipal(obj); + prin.forget(result); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::GetCompartmentLocation(HandleValue val, + JSContext* cx, + nsACString& result) +{ + if (!val.isObject()) + return NS_ERROR_INVALID_ARG; + RootedObject obj(cx, &val.toObject()); + obj = js::CheckedUnwrap(obj); + MOZ_ASSERT(obj); + + result = xpc::CompartmentPrivate::Get(obj)->GetLocation(); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::SetAddonInterposition(const nsACString& addonIdStr, + nsIAddonInterposition* interposition, + JSContext* cx) +{ + JSAddonId* addonId = xpc::NewAddonId(cx, addonIdStr); + if (!addonId) + return NS_ERROR_FAILURE; + if (!XPCWrappedNativeScope::SetAddonInterposition(cx, addonId, interposition)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::SetAddonCallInterposition(HandleValue target, + JSContext* cx) +{ + NS_ENSURE_TRUE(target.isObject(), NS_ERROR_INVALID_ARG); + RootedObject targetObj(cx, &target.toObject()); + targetObj = js::CheckedUnwrap(targetObj); + NS_ENSURE_TRUE(targetObj, NS_ERROR_INVALID_ARG); + XPCWrappedNativeScope* xpcScope = ObjectScope(targetObj); + NS_ENSURE_TRUE(xpcScope, NS_ERROR_INVALID_ARG); + + xpcScope->SetAddonCallInterposition(); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::AllowCPOWsInAddon(const nsACString& addonIdStr, + bool allow, + JSContext* cx) +{ + JSAddonId* addonId = xpc::NewAddonId(cx, addonIdStr); + if (!addonId) + return NS_ERROR_FAILURE; + if (!XPCWrappedNativeScope::AllowCPOWsInAddon(cx, addonId, allow)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents_Utils::Now(double* aRetval) +{ + bool isInconsistent = false; + TimeStamp start = TimeStamp::ProcessCreation(isInconsistent); + *aRetval = (TimeStamp::Now() - start).ToMilliseconds(); + return NS_OK; +} + +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ + + +nsXPCComponentsBase::nsXPCComponentsBase(XPCWrappedNativeScope* aScope) + : mScope(aScope) +{ + MOZ_ASSERT(aScope, "aScope must not be null"); +} + +nsXPCComponents::nsXPCComponents(XPCWrappedNativeScope* aScope) + : nsXPCComponentsBase(aScope) +{ +} + +nsXPCComponentsBase::~nsXPCComponentsBase() +{ +} + +nsXPCComponents::~nsXPCComponents() +{ +} + +void +nsXPCComponentsBase::ClearMembers() +{ + mInterfaces = nullptr; + mInterfacesByID = nullptr; + mResults = nullptr; +} + +void +nsXPCComponents::ClearMembers() +{ + mClasses = nullptr; + mClassesByID = nullptr; + mID = nullptr; + mException = nullptr; + mConstructor = nullptr; + mUtils = nullptr; + + nsXPCComponentsBase::ClearMembers(); +} + +/*******************************************/ +#define XPC_IMPL_GET_OBJ_METHOD(_class, _n) \ +NS_IMETHODIMP _class::Get##_n(nsIXPCComponents_##_n * *a##_n) { \ + NS_ENSURE_ARG_POINTER(a##_n); \ + if (!m##_n) \ + m##_n = new nsXPCComponents_##_n(); \ + RefPtr<nsXPCComponents_##_n> ret = m##_n; \ + ret.forget(a##_n); \ + return NS_OK; \ +} + +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, Interfaces) +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, InterfacesByID) +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Classes) +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, ClassesByID) +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, Results) +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, ID) +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Exception) +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Constructor) +XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Utils) + +#undef XPC_IMPL_GET_OBJ_METHOD +/*******************************************/ + +NS_IMETHODIMP +nsXPCComponentsBase::IsSuccessCode(nsresult result, bool* out) +{ + *out = NS_SUCCEEDED(result); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents::GetStack(nsIStackFrame * *aStack) +{ + nsresult rv; + nsXPConnect* xpc = nsXPConnect::XPConnect(); + rv = xpc->GetCurrentJSStack(aStack); + return rv; +} + +NS_IMETHODIMP +nsXPCComponents::GetManager(nsIComponentManager * *aManager) +{ + MOZ_ASSERT(aManager, "bad param"); + return NS_GetComponentManager(aManager); +} + +NS_IMETHODIMP +nsXPCComponents::GetReturnCode(JSContext* aCx, MutableHandleValue aOut) +{ + nsresult res = XPCJSContext::Get()->GetPendingResult(); + aOut.setNumber(static_cast<uint32_t>(res)); + return NS_OK; +} + +NS_IMETHODIMP +nsXPCComponents::SetReturnCode(JSContext* aCx, HandleValue aCode) +{ + nsresult rv; + if (!ToUint32(aCx, aCode, (uint32_t*)&rv)) + return NS_ERROR_FAILURE; + XPCJSContext::Get()->SetPendingResult(rv); + return NS_OK; +} + +// static +NS_IMETHODIMP nsXPCComponents::ReportError(HandleValue error, JSContext* cx) +{ + NS_WARNING("Components.reportError deprecated, use Components.utils.reportError"); + + nsCOMPtr<nsIXPCComponents_Utils> utils; + nsresult rv = GetUtils(getter_AddRefs(utils)); + if (NS_FAILED(rv)) + return rv; + + return utils->ReportError(error, cx); +} + +/**********************************************/ + +class ComponentsSH : public nsIXPCScriptable +{ +public: + explicit constexpr ComponentsSH(unsigned dummy) + { + } + + // We don't actually inherit any ref counting infrastructure, but we don't + // need an nsAutoRefCnt member, so the _INHERITED macro is a hack to avoid + // having one. + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIXPCSCRIPTABLE + static nsresult Get(nsIXPCScriptable** helper) + { + *helper = &singleton; + return NS_OK; + } + +private: + static ComponentsSH singleton; +}; + +ComponentsSH ComponentsSH::singleton(0); + +// Singleton refcounting. +NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::AddRef(void) { return 1; } +NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::Release(void) { return 1; } + +NS_INTERFACE_MAP_BEGIN(ComponentsSH) + NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +#define NSXPCCOMPONENTSBASE_CID \ +{ 0xc62998e5, 0x95f1, 0x4058, \ + { 0xa5, 0x09, 0xec, 0x21, 0x66, 0x18, 0x92, 0xb9 } } + +#define NSXPCCOMPONENTS_CID \ +{ 0x3649f405, 0xf0ec, 0x4c28, \ + { 0xae, 0xb0, 0xaf, 0x9a, 0x51, 0xe4, 0x4c, 0x81 } } + +NS_IMPL_CLASSINFO(nsXPCComponentsBase, &ComponentsSH::Get, nsIClassInfo::DOM_OBJECT, NSXPCCOMPONENTSBASE_CID) +NS_IMPL_ISUPPORTS_CI(nsXPCComponentsBase, nsIXPCComponentsBase) + +NS_IMPL_CLASSINFO(nsXPCComponents, &ComponentsSH::Get, nsIClassInfo::DOM_OBJECT, NSXPCCOMPONENTS_CID) +// Below is more or less what NS_IMPL_ISUPPORTS_CI_INHERITED1 would look like +// if it existed. +NS_IMPL_ADDREF_INHERITED(nsXPCComponents, nsXPCComponentsBase) +NS_IMPL_RELEASE_INHERITED(nsXPCComponents, nsXPCComponentsBase) +NS_INTERFACE_MAP_BEGIN(nsXPCComponents) + NS_INTERFACE_MAP_ENTRY(nsIXPCComponents) + NS_IMPL_QUERY_CLASSINFO(nsXPCComponents) +NS_INTERFACE_MAP_END_INHERITING(nsXPCComponentsBase) +NS_IMPL_CI_INTERFACE_GETTER(nsXPCComponents, nsIXPCComponents) + +// The nsIXPCScriptable map declaration that will generate stubs for us +#define XPC_MAP_CLASSNAME ComponentsSH +#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents" +#define XPC_MAP_WANT_PRECREATE +#include "xpc_map_end.h" /* This will #undef the above */ + +NS_IMETHODIMP +ComponentsSH::PreCreate(nsISupports* nativeObj, JSContext* cx, JSObject* globalObj, JSObject** parentObj) +{ + nsXPCComponentsBase* self = static_cast<nsXPCComponentsBase*>(nativeObj); + // this should never happen + if (!self->GetScope()) { + NS_WARNING("mScope must not be null when nsXPCComponents::PreCreate is called"); + return NS_ERROR_FAILURE; + } + *parentObj = self->GetScope()->GetGlobalJSObject(); + return NS_OK; +} |