From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/libs/xpcom18a4/python/src/ErrorUtils.cpp | 483 +++ src/libs/xpcom18a4/python/src/PyGBase.cpp | 852 ++++++ src/libs/xpcom18a4/python/src/PyGInputStream.cpp | 173 ++ src/libs/xpcom18a4/python/src/PyGModule.cpp | 297 ++ src/libs/xpcom18a4/python/src/PyGStub.cpp | 180 ++ src/libs/xpcom18a4/python/src/PyGWeakReference.cpp | 112 + src/libs/xpcom18a4/python/src/PyIClassInfo.cpp | 181 ++ .../xpcom18a4/python/src/PyIComponentManager.cpp | 138 + .../python/src/PyIComponentManagerObsolete.cpp | 203 ++ src/libs/xpcom18a4/python/src/PyIEnumerator.cpp | 235 ++ src/libs/xpcom18a4/python/src/PyIID.cpp | 410 +++ src/libs/xpcom18a4/python/src/PyIInputStream.cpp | 190 ++ src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp | 431 +++ .../python/src/PyIInterfaceInfoManager.cpp | 206 ++ .../xpcom18a4/python/src/PyISimpleEnumerator.cpp | 202 ++ src/libs/xpcom18a4/python/src/PyISupports.cpp | 621 ++++ src/libs/xpcom18a4/python/src/PyIVariant.cpp | 231 ++ src/libs/xpcom18a4/python/src/PyXPCOM.h | 1036 +++++++ src/libs/xpcom18a4/python/src/PyXPCOM_std.h | 56 + src/libs/xpcom18a4/python/src/Pyxpt_info.cpp | 197 ++ src/libs/xpcom18a4/python/src/TypeObject.cpp | 457 +++ src/libs/xpcom18a4/python/src/VariantUtils.cpp | 3112 ++++++++++++++++++++ src/libs/xpcom18a4/python/src/dllmain.cpp | 352 +++ src/libs/xpcom18a4/python/src/loader/pyloader.cpp | 435 +++ src/libs/xpcom18a4/python/src/module/_xpcom.cpp | 950 ++++++ src/libs/xpcom18a4/python/src/readme.html | 99 + 26 files changed, 11839 insertions(+) create mode 100644 src/libs/xpcom18a4/python/src/ErrorUtils.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGBase.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGInputStream.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGModule.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGStub.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGWeakReference.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIClassInfo.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIComponentManager.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIComponentManagerObsolete.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIEnumerator.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIID.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIInputStream.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIInterfaceInfoManager.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyISimpleEnumerator.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyISupports.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIVariant.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyXPCOM.h create mode 100644 src/libs/xpcom18a4/python/src/PyXPCOM_std.h create mode 100644 src/libs/xpcom18a4/python/src/Pyxpt_info.cpp create mode 100644 src/libs/xpcom18a4/python/src/TypeObject.cpp create mode 100644 src/libs/xpcom18a4/python/src/VariantUtils.cpp create mode 100644 src/libs/xpcom18a4/python/src/dllmain.cpp create mode 100644 src/libs/xpcom18a4/python/src/loader/pyloader.cpp create mode 100644 src/libs/xpcom18a4/python/src/module/_xpcom.cpp create mode 100644 src/libs/xpcom18a4/python/src/readme.html (limited to 'src/libs/xpcom18a4/python/src') diff --git a/src/libs/xpcom18a4/python/src/ErrorUtils.cpp b/src/libs/xpcom18a4/python/src/ErrorUtils.cpp new file mode 100644 index 00000000..9400799b --- /dev/null +++ b/src/libs/xpcom18a4/python/src/ErrorUtils.cpp @@ -0,0 +1,483 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsReadableUtils.h" +#include +#ifdef VBOX +# include +# include +# include +#endif +#include "nspr.h" // PR_fprintf + +static char *PyTraceback_AsString(PyObject *exc_tb); + +// The internal helper that actually moves the +// formatted string to the target! + +// Only used in really bad situations! +static void _PanicErrorWrite(const char *msg) +{ + nsCOMPtr consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (consoleService) + consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(msg).get()); + PR_fprintf(PR_STDERR,"%s\n", msg); +} + +// Called when our "normal" error logger fails. +static void HandleLogError(const char *pszMessageText) +{ + nsCAutoString streamout; + + _PanicErrorWrite("Failed to log an error record"); + if (PyXPCOM_FormatCurrentException(streamout)) + _PanicErrorWrite(streamout.get()); + _PanicErrorWrite("Original error follows:"); + _PanicErrorWrite(pszMessageText); +} + +static const char *LOGGER_WARNING = "warning"; +static const char *LOGGER_ERROR = "error"; +static const char *LOGGER_DEBUG = "debug"; + +// Our "normal" error logger - calls back to the logging module. +void DoLogMessage(const char *methodName, const char *pszMessageText) +{ + // We use the logging module now. Originally this code called + // the logging module directly by way of the C API's + // PyImport_ImportModule/PyObject_CallMethod etc. However, this + // causes problems when there is no Python caller on the stack - + // the logging module's findCaller method fails with a None frame. + // We now work around this by calling PyRun_SimpleString - this + // causes a new frame to be created for executing the compiled + // string, and the logging module no longer fails. + // XXX - this implementation is less than ideal - findCaller now + // returns ("", 2). Ideally we would compile with a + // filename something similar to "". + + // But this also means we need a clear error state... + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); +// We will execute: +// import logging +// logging.getLogger('xpcom').{warning/error/etc}("%s", {msg_text}) + nsCAutoString c("import logging\nlogging.getLogger('xpcom')."); + c += methodName; + c += "('%s', "; + // Pull a trick to ensure a valid string - use Python repr! +#if PY_MAJOR_VERSION <= 2 + PyObject *obMessage = PyString_FromString(pszMessageText); +#else + PyObject *obMessage = PyUnicode_FromString(pszMessageText); +#endif + if (obMessage) { + PyObject *repr = PyObject_Repr(obMessage); + if (repr) { +#if PY_MAJOR_VERSION <= 2 + c += PyString_AsString(repr); +#else + c += PyUnicode_AsUTF8(repr); +#endif + Py_DECREF(repr); + } + Py_DECREF(obMessage); + } + c += ")\n"; + if (PyRun_SimpleString(c.get()) != 0) { + HandleLogError(pszMessageText); + } + PyErr_Restore(exc_typ, exc_val, exc_tb); +} + +void LogMessage(const char *methodName, const char *pszMessageText) +{ + // Be careful to save and restore the Python exception state + // before calling back to Python, or we lose the original error. + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); + DoLogMessage(methodName, pszMessageText); + PyErr_Restore(exc_typ, exc_val, exc_tb); +} + + +void LogMessage(const char *methodName, nsACString &text) +{ + char *c = ToNewCString(text); + LogMessage(methodName, c); + nsCRT::free(c); +} + +// A helper for the various logging routines. +static void VLogF(const char *methodName, const char *fmt, va_list argptr) +{ + char buff[512]; +#ifdef VBOX /* Enable the use of VBox formatting types. */ + RTStrPrintfV(buff, sizeof(buff), fmt, argptr); +#else + // Use safer NS_ functions. + PR_vsnprintf(buff, sizeof(buff), fmt, argptr); +#endif + + LogMessage(methodName, buff); +} + +PRBool PyXPCOM_FormatCurrentException(nsCString &streamout) +{ + PRBool ok = PR_FALSE; + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); + PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb); + if (exc_typ) { + ok = PyXPCOM_FormatGivenException(streamout, exc_typ, exc_val, + exc_tb); + } + PyErr_Restore(exc_typ, exc_val, exc_tb); + return ok; +} + +PRBool PyXPCOM_FormatGivenException(nsCString &streamout, + PyObject *exc_typ, PyObject *exc_val, + PyObject *exc_tb) +{ + if (!exc_typ) + return PR_FALSE; + streamout += "\n"; + + if (exc_tb) { + const char *szTraceback = PyTraceback_AsString(exc_tb); + if (szTraceback == NULL) + streamout += "Can't get the traceback info!"; + else { + streamout += "Traceback (most recent call last):\n"; + streamout += szTraceback; + PyMem_Free((void *)szTraceback); + } + } + PyObject *temp = PyObject_Str(exc_typ); + if (temp) { +#if PY_MAJOR_VERSION <= 2 + streamout += PyString_AsString(temp); +#else + streamout += PyUnicode_AsUTF8(temp); +#endif + Py_DECREF(temp); + } else + streamout += "Can't convert exception to a string!"; + streamout += ": "; + if (exc_val != NULL) { + temp = PyObject_Str(exc_val); + if (temp) { +#if PY_MAJOR_VERSION <= 2 + streamout += PyString_AsString(temp); +#else + streamout += PyUnicode_AsUTF8(temp); +#endif + Py_DECREF(temp); + } else + streamout += "Can't convert exception value to a string!"; + } + return PR_TRUE; +} + +void PyXPCOM_LogError(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + // NOTE: It is tricky to use logger.exception here - the exception + // state when called back from the C code is clear. Only Python 2.4 + // and later allows an explicit exc_info tuple(). + + // Don't use VLogF here, instead arrange for exception info and + // traceback to be in the same buffer. + char buff[512]; + PR_vsnprintf(buff, sizeof(buff), fmt, marker); + // If we have a Python exception, also log that: + nsCAutoString streamout(buff); + if (PyXPCOM_FormatCurrentException(streamout)) { + LogMessage(LOGGER_ERROR, streamout); + } + va_end(marker); +} + +void PyXPCOM_LogWarning(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF(LOGGER_WARNING, fmt, marker); + va_end(marker); +} + +void PyXPCOM_Log(const char *level, const nsCString &msg) +{ + DoLogMessage(level, msg.get()); +} + +#ifdef DEBUG +void PyXPCOM_LogDebug(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF(LOGGER_DEBUG, fmt, marker); + va_end(marker); +} +#endif + +#ifdef VBOX +PyObject *PyXPCOM_BuildErrorMessage(nsresult r) +{ + char msg[512]; + bool gotMsg = false; + + if (!gotMsg) + { + nsresult rc; + nsCOMPtr es; + es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc); + if (NS_SUCCEEDED (rc)) + { + nsCOMPtr em; + rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); + if (NS_SUCCEEDED (rc)) + { + nsCOMPtr ex; + rc = em->GetExceptionFromProvider(r, NULL, getter_AddRefs (ex)); + if (NS_SUCCEEDED (rc) && ex) + { + nsXPIDLCString emsg; + ex->GetMessage(getter_Copies(emsg)); + PR_snprintf(msg, sizeof(msg), "%s", + emsg.get()); + gotMsg = true; + } + } + } + } + + if (!gotMsg) + { + const RTCOMERRMSG* pMsg = RTErrCOMGet(r); + if (strncmp(pMsg->pszMsgFull, "Unknown", 7) != 0) + { + PR_snprintf(msg, sizeof(msg), "%s (%s)", + pMsg->pszMsgFull, pMsg->pszDefine); + gotMsg = true; + } + } + + if (!gotMsg) + { + PR_snprintf(msg, sizeof(msg), "Error 0x%x in module 0x%x", + NS_ERROR_GET_CODE(r), NS_ERROR_GET_MODULE(r)); + } + PyObject *evalue = Py_BuildValue("is", r, msg); + return evalue; +} +#endif + +PyObject *PyXPCOM_BuildPyException(nsresult r) +{ +#ifndef VBOX + // Need the message etc. + PyObject *evalue = Py_BuildValue("i", r); +#else + PyObject *evalue = PyXPCOM_BuildErrorMessage(r); +#endif + PyErr_SetObject(PyXPCOM_Error, evalue); + Py_XDECREF(evalue); + return NULL; +} + +nsresult PyXPCOM_SetCOMErrorFromPyException() +{ + if (!PyErr_Occurred()) + // No error occurred + return NS_OK; + nsresult rv = NS_ERROR_FAILURE; + if (PyErr_ExceptionMatches(PyExc_MemoryError)) + rv = NS_ERROR_OUT_OF_MEMORY; + // todo: + // * Set an exception using the exception service. + + // Once we have returned to the xpcom caller, we don't want to leave a + // Python exception pending - it may get noticed when the next call + // is made on the same thread. + PyErr_Clear(); + return rv; +} + +/* Obtains a string from a Python traceback. + This is the exact same string as "traceback.print_exc" would return. + + Pass in a Python traceback object (probably obtained from PyErr_Fetch()) + Result is a string which must be free'd using PyMem_Free() +*/ +#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;} + +char *PyTraceback_AsString(PyObject *exc_tb) +{ + const char *errMsg = NULL; /* holds a local error message */ + char *result = NULL; /* a valid, allocated result. */ + PyObject *modStringIO = NULL; + PyObject *modTB = NULL; + PyObject *obFuncStringIO = NULL; + PyObject *obStringIO = NULL; + PyObject *obFuncTB = NULL; + PyObject *argsTB = NULL; + PyObject *obResult = NULL; + +#if PY_MAJOR_VERSION <= 2 + /* Import the modules we need - cStringIO and traceback */ + modStringIO = PyImport_ImportModule("cStringIO"); + if (modStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant import cStringIO\n"); + + modTB = PyImport_ImportModule("traceback"); + if (modTB==NULL) + TRACEBACK_FETCH_ERROR("cant import traceback\n"); + /* Construct a cStringIO object */ + obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n"); + obStringIO = PyObject_CallObject(obFuncStringIO, NULL); + if (obStringIO==NULL) + TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n"); +#else + /* Import the modules we need - io and traceback */ + modStringIO = PyImport_ImportModule("io"); + if (modStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant import io\n"); + + modTB = PyImport_ImportModule("traceback"); + if (modTB==NULL) + TRACEBACK_FETCH_ERROR("cant import traceback\n"); + /* Construct a StringIO object */ + obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find io.StringIO\n"); + obStringIO = PyObject_CallObject(obFuncStringIO, NULL); + if (obStringIO==NULL) + TRACEBACK_FETCH_ERROR("io.StringIO() failed\n"); +#endif + /* Get the traceback.print_exception function, and call it. */ + obFuncTB = PyObject_GetAttrString(modTB, "print_tb"); + if (obFuncTB==NULL) + TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n"); + + argsTB = Py_BuildValue("OOO", + exc_tb ? exc_tb : Py_None, + Py_None, + obStringIO); + if (argsTB==NULL) + TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n"); + + obResult = PyObject_CallObject(obFuncTB, argsTB); + if (obResult==NULL) + TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n"); + /* Now call the getvalue() method in the StringIO instance */ + Py_DECREF(obFuncStringIO); + obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find getvalue function\n"); + Py_DECREF(obResult); + obResult = PyObject_CallObject(obFuncStringIO, NULL); + if (obResult==NULL) + TRACEBACK_FETCH_ERROR("getvalue() failed.\n"); + + /* And it should be a string all ready to go - duplicate it. */ +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(obResult)) +#else + if (!PyUnicode_Check(obResult)) +#endif + TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n"); + + { // a temp scope so I can use temp locals. +#if PY_MAJOR_VERSION <= 2 + char *tempResult = PyString_AsString(obResult); +#else + /* PyUnicode_AsUTF8() is const char * as of Python 3.7, char * earlier. */ + const char *tempResult = (const char *)PyUnicode_AsUTF8(obResult); +#endif + result = (char *)PyMem_Malloc(strlen(tempResult)+1); + if (result==NULL) + TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string\n"); + + strcpy(result, tempResult); + } // end of temp scope. +done: + /* All finished - first see if we encountered an error */ + if (result==NULL && errMsg != NULL) { + result = (char *)PyMem_Malloc(strlen(errMsg)+1); + if (result != NULL) + /* if it does, not much we can do! */ + strcpy(result, errMsg); + } + Py_XDECREF(modStringIO); + Py_XDECREF(modTB); + Py_XDECREF(obFuncStringIO); + Py_XDECREF(obStringIO); + Py_XDECREF(obFuncTB); + Py_XDECREF(argsTB); + Py_XDECREF(obResult); + return result; +} + +// See comments in PyXPCOM.h for why we need this! +void PyXPCOM_MakePendingCalls() +{ + while (1) { + int rc = Py_MakePendingCalls(); + if (rc == 0) + break; + // An exception - just report it as normal. + // Note that a traceback is very unlikely! + PyXPCOM_LogError("Unhandled exception detected before entering Python.\n"); + PyErr_Clear(); + // And loop around again until we are told everything is done! + } +} diff --git a/src/libs/xpcom18a4/python/src/PyGBase.cpp b/src/libs/xpcom18a4/python/src/PyGBase.cpp new file mode 100644 index 00000000..e73b2a6d --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGBase.cpp @@ -0,0 +1,852 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// PyGBase.cpp - implementation of the PyG_Base class +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include +#include +#include + +static PRInt32 cGateways = 0; +PRInt32 _PyXPCOM_GetGatewayCount(void) +{ + return cGateways; +} + +extern PyG_Base *MakePyG_nsIModule(PyObject *); +extern PyG_Base *MakePyG_nsIComponentLoader(PyObject *instance); +extern PyG_Base *MakePyG_nsIInputStream(PyObject *instance); + +static char *PyXPCOM_szDefaultGatewayAttributeName = (char*)"_com_instance_default_gateway_"; +PyG_Base *GetDefaultGateway(PyObject *instance); +void AddDefaultGateway(PyObject *instance, nsISupports *gateway); +PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway); + +/*static*/ nsresult +PyG_Base::CreateNew(PyObject *pPyInstance, const nsIID &iid, void **ppResult) +{ + NS_PRECONDITION(ppResult && *ppResult==NULL, "NULL or uninitialized pointer"); + if (ppResult==nsnull) + return NS_ERROR_NULL_POINTER; + + PyG_Base *ret; + // Hack for few extra gateways we support. + if (iid.Equals(NS_GET_IID(nsIModule))) + ret = MakePyG_nsIModule(pPyInstance); + else if (iid.Equals(NS_GET_IID(nsIComponentLoader))) + ret = MakePyG_nsIComponentLoader(pPyInstance); + else if (iid.Equals(NS_GET_IID(nsIInputStream))) + ret = MakePyG_nsIInputStream(pPyInstance); + else + ret = new PyXPCOM_XPTStub(pPyInstance, iid); + if (ret==nsnull) + return NS_ERROR_OUT_OF_MEMORY; + ret->AddRef(); // The first reference for the caller. + *ppResult = ret->ThisAsIID(iid); + NS_ABORT_IF_FALSE(*ppResult != NULL, "ThisAsIID() gave NULL, but we know it supports it!"); + return *ppResult ? NS_OK : NS_ERROR_FAILURE; +} + +PyG_Base::PyG_Base(PyObject *instance, const nsIID &iid) +{ + // Note that "instance" is the _policy_ instance!! + PR_AtomicIncrement(&cGateways); + m_pBaseObject = GetDefaultGateway(instance); + // m_pWeakRef is an nsCOMPtr and needs no init. + + NS_ABORT_IF_FALSE(!(iid.Equals(NS_GET_IID(nsISupportsWeakReference)) || iid.Equals(NS_GET_IID(nsIWeakReference))),"Should not be creating gateways with weak-ref interfaces"); + m_iid = iid; + m_pPyObject = instance; + NS_PRECONDITION(instance, "NULL PyObject for PyXPCOM_XPTStub!"); + +#ifdef NS_BUILD_REFCNT_LOGGING + // If XPCOM reference count logging is enabled, then allow us to give the Python class. + PyObject *realInstance = PyObject_GetAttrString(instance, "_obj_"); + PyObject *r = PyObject_Repr(realInstance); + const char *szRepr; + if (r==NULL) { + PyXPCOM_LogError("Getting the __repr__ of the object failed"); + PyErr_Clear(); + szRepr = "(repr failed!)"; + } + else +#if PY_MAJOR_VERSION <= 2 + szRepr = PyString_AsString(r); +#else + szRepr = PyUnicode_AsUTF8(r); +#endif + if (szRepr==NULL) szRepr = ""; + int reprOffset = *szRepr=='<' ? 1 : 0; + static const char *reprPrefix = "component:"; + if (strncmp(reprPrefix, szRepr+reprOffset, strlen(reprPrefix)) == 0) + reprOffset += strlen(reprPrefix); + strncpy(refcntLogRepr, szRepr + reprOffset, sizeof(refcntLogRepr)-1); + refcntLogRepr[sizeof(refcntLogRepr)-1] = '\0'; + // See if we should get rid of the " at 0x12345" portion. + char *lastPos = strstr(refcntLogRepr, " at "); + if (lastPos) *lastPos = '\0'; + Py_XDECREF(realInstance); + Py_XDECREF(r); +#endif // NS_BUILD_REFCNT_LOGGING + +#ifdef DEBUG_LIFETIMES + { + char *iid_repr; + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + if (iim!=nsnull) + iim->GetNameForIID(&iid, &iid_repr); + PyObject *real_instance = PyObject_GetAttrString(instance, "_obj_"); + PyObject *real_repr = PyObject_Repr(real_instance); + + PYXPCOM_LOG_DEBUG("PyG_Base created at %p\n instance_repr=%s\n IID=%s\n", this, PyString_AsString(real_repr), iid_repr); + nsMemory::Free(iid_repr); + Py_XDECREF(real_instance); + Py_XDECREF(real_repr); + } +#endif // DEBUG_LIFETIMES + Py_XINCREF(instance); // instance should never be NULL - but whats an X between friends! + + PyXPCOM_DLLAddRef(); + +#ifdef DEBUG_FULL + LogF("PyGatewayBase: created %s", m_pPyObject ? PyXPCOM_ObTypeName(m_pPyObject) : ""); +#endif +} + +PyG_Base::~PyG_Base() +{ + PR_AtomicDecrement(&cGateways); +#ifdef DEBUG_LIFETIMES + PYXPCOM_LOG_DEBUG("PyG_Base: deleted %p", this); +#endif + if ( m_pPyObject ) { + CEnterLeavePython celp; + Py_DECREF(m_pPyObject); + } + if (m_pBaseObject) + m_pBaseObject->Release(); + if (m_pWeakRef) { + // Need to ensure some other thread isnt doing a QueryReferent on + // our weak reference at the same time + CEnterLeaveXPCOMFramework _celf; + PyXPCOM_GatewayWeakReference *p = (PyXPCOM_GatewayWeakReference *)(nsISupports *)m_pWeakRef; + p->m_pBase = nsnull; + m_pWeakRef = nsnull; + } + PyXPCOM_DLLRelease(); +} + +// Get the correct interface pointer for this object given the IID. +void *PyG_Base::ThisAsIID( const nsIID &iid ) +{ + if (this==NULL) return NULL; + if (iid.Equals(NS_GET_IID(nsISupports))) + return (nsISupports *)(nsIInternalPython *)this; + if (iid.Equals(NS_GET_IID(nsISupportsWeakReference))) + return (nsISupportsWeakReference *)this; + if (iid.Equals(NS_GET_IID(nsIInternalPython))) + return (nsISupports *)(nsIInternalPython *)this; + return NULL; +} + +// Call back into Python, passing a Python instance, and get back +// an interface object that wraps the instance. +/*static*/ PRBool +PyG_Base::AutoWrapPythonInstance(PyObject *ob, const nsIID &iid, nsISupports **ppret) +{ + NS_PRECONDITION(ppret!=NULL, "null pointer when wrapping a Python instance!"); + NS_PRECONDITION(ob && PyObject_HasAttrString(ob, "__class__"), + "AutoWrapPythonInstance is expecting an non-NULL instance!"); + PRBool ok = PR_FALSE; + // XXX - todo - this static object leaks! (but Python on Windows leaks 2000+ objects as it is ;-) + static PyObject *func = NULL; // fetch this once and remember! + PyObject *obIID = NULL; + PyObject *wrap_ret = NULL; + PyObject *args = NULL; + if (func==NULL) { // not thread-safe, but nothing bad can happen, except an extra reference leak + PyObject *mod = PyImport_ImportModule("xpcom.server"); + if (mod) + func = PyObject_GetAttrString(mod, "WrapObject"); + Py_XDECREF(mod); + if (func==NULL) goto done; + } + // See if the instance has previously been wrapped. + if (CheckDefaultGateway(ob, iid, ppret)) { + ok = PR_TRUE; // life is good! + } else { + PyErr_Clear(); + + obIID = Py_nsIID::PyObjectFromIID(iid); + if (obIID==NULL) goto done; + args = Py_BuildValue("OOzi", ob, obIID, NULL, 0); + if (args==NULL) goto done; + wrap_ret = PyEval_CallObject(func, args); + if (wrap_ret==NULL) goto done; + ok = Py_nsISupports::InterfaceFromPyObject(wrap_ret, iid, ppret, PR_FALSE, PR_FALSE); +#ifdef DEBUG + if (ok) + // Check we _now_ have a default gateway + { + nsISupports *temp = NULL; + NS_ABORT_IF_FALSE(CheckDefaultGateway(ob, iid, &temp), "Auto-wrapped object didnt get a default gateway!"); + if (temp) temp->Release(); + } +#endif + } +done: +// Py_XDECREF(func); -- func is static for performance reasons. + Py_XDECREF(obIID); + Py_XDECREF(wrap_ret); + Py_XDECREF(args); + return ok; +} + +// Call back into Python, passing a raw nsIInterface object, getting back +// the object to actually use as the gateway parameter for this interface. +// For example, it is expected that the policy will wrap the interface +// object in one of the xpcom.client.Interface objects, allowing +// natural usage of the interface from Python clients. +// Note that piid will usually be NULL - this is because the runtime +// reflection interfaces dont provide this information to me. +// In this case, the Python code may choose to lookup the complete +// interface info to obtain the IID. +// It is expected (but should not be assumed) that the method info +// or the IID will be NULL. +// Worst case, the code should provide a wrapper for the nsiSupports interface, +// so at least the user can simply QI the object. +PyObject * +PyG_Base::MakeInterfaceParam(nsISupports *pis, + const nsIID *piid, + int methodIndex /* = -1 */, + const XPTParamDescriptor *d /* = NULL */, + int paramIndex /* = -1 */) +{ + if (pis==NULL) { + Py_INCREF(Py_None); + return Py_None; + } + // This condition is true today, but not necessarily so. + // But if it ever triggers, the poor Python code has no real hope + // of returning something useful, so we should at least do our + // best to provide the useful data. + NS_WARN_IF_FALSE( ((piid != NULL) ^ (d != NULL)) == 1, "No information on the interface available - Python's gunna have a hard time doing much with it!"); + PyObject *obIID = NULL; + PyObject *obISupports = NULL; + PyObject *obParamDesc = NULL; + PyObject *result = NULL; + + // get the basic interface first, as if we fail, we can try and use this. + // If we don't know the IID, we must explicitly query for nsISupports. + nsCOMPtr piswrap; + nsIID iid_check; + if (piid) { + iid_check = *piid; + piswrap = pis; + } else { + /* HACK ALERT! Dropping the python interpreter lock here while + doing QueryInterface because it may involve IPC to a python + object in the same interpreter and deadlock. Not at all + sure if this is a good idea or not for the internal PyXPCOM + state, but it might fix the deadloock... Hoping for the best. */ + Py_BEGIN_ALLOW_THREADS; + iid_check = NS_GET_IID(nsISupports); + pis->QueryInterface(iid_check, getter_AddRefs(piswrap)); + Py_END_ALLOW_THREADS; + } + + obISupports = Py_nsISupports::PyObjectFromInterface(piswrap, iid_check, PR_FALSE); + if (!obISupports) + goto done; + if (piid==NULL) { + obIID = Py_None; + Py_INCREF(Py_None); + } else + obIID = Py_nsIID::PyObjectFromIID(*piid); + if (obIID==NULL) + goto done; + obParamDesc = PyObject_FromXPTParamDescriptor(d); + if (obParamDesc==NULL) + goto done; + + result = PyObject_CallMethod(m_pPyObject, + (char*)"_MakeInterfaceParam_", + (char*)"OOiOi", + obISupports, + obIID, + methodIndex, + obParamDesc, + paramIndex); +done: + if (PyErr_Occurred()) { + NS_WARN_IF_FALSE(result==NULL, "Have an error, but also a result!"); + PyXPCOM_LogError("Wrapping an interface object for the gateway failed\n"); + } + Py_XDECREF(obIID); + Py_XDECREF(obParamDesc); + if (result==NULL) { // we had an error. + PyErr_Clear(); // but are not reporting it back to Python itself! + // return our obISupports. If NULL, we are really hosed and nothing we can do. + return obISupports; + } + // Dont need to return this - we have a better result. + Py_XDECREF(obISupports); + return result; +} + +NS_IMETHODIMP +PyG_Base::QueryInterface(REFNSIID iid, void** ppv) +{ +#ifdef PYXPCOM_DEBUG_FULL + { + char *sziid = iid.ToString(); + LogF("PyGatewayBase::QueryInterface: %s", sziid); + Allocator::Free(sziid); + } +#endif + NS_PRECONDITION(ppv, "NULL pointer"); + if (ppv==nsnull) + return NS_ERROR_NULL_POINTER; + *ppv = nsnull; + // If one of our native interfaces (but NOT nsISupports if we have a base) + // return this. + // It is important is that nsISupports come from the base object + // to ensure that we live by XPCOM identity rules (other interfaces need + // not abide by this rule - only nsISupports.) + if ( (m_pBaseObject==NULL || !iid.Equals(NS_GET_IID(nsISupports))) + && (*ppv=ThisAsIID(iid)) != NULL ) { + AddRef(); + return NS_OK; + } + // If we have a "base object", then we need to delegate _every_ remaining + // QI to it. + if (m_pBaseObject != NULL) + return m_pBaseObject->QueryInterface(iid, ppv); + + // Call the Python policy to see if it (says it) supports the interface + PRBool supports = PR_FALSE; + { // temp scope for Python lock + CEnterLeavePython celp; + + PyObject * ob = Py_nsIID::PyObjectFromIID(iid); + // must say this is an 'internal' call, else we recurse QI into + // oblivion. + PyObject * this_interface_ob = Py_nsISupports::PyObjectFromInterface( + (nsXPTCStubBase *)this, + iid, PR_FALSE, PR_TRUE); + if ( !ob || !this_interface_ob) { + Py_XDECREF(ob); + Py_XDECREF(this_interface_ob); + return NS_ERROR_OUT_OF_MEMORY; + } + + PyObject *result = PyObject_CallMethod(m_pPyObject, (char*)"_QueryInterface_", + (char*)"OO", + this_interface_ob, ob); + Py_DECREF(ob); + Py_DECREF(this_interface_ob); + + if ( result ) { + if (Py_nsISupports::InterfaceFromPyObject(result, iid, (nsISupports **)ppv, PR_TRUE)) { + // If OK, but NULL, _QI_ returned None, which simply means + // "no such interface" + supports = (*ppv!=NULL); + // result has been QI'd and AddRef'd all ready for return. + } else { + // Dump this message and any Python exception before + // reporting the fact that QI failed - this error + // may provide clues! + PyXPCOM_LogError("The _QueryInterface_ method returned an object of type '%s', but an interface was expected\n", PyXPCOM_ObTypeName(result)); + // supports remains false + } + Py_DECREF(result); + } else { + NS_ABORT_IF_FALSE(PyErr_Occurred(), "Got NULL result, but no Python error flagged!"); + NS_WARN_IF_FALSE(!supports, "Have failure with success flag set!"); + PyXPCOM_LogError("The _QueryInterface_ processing failed.\n"); + // supports remains false. + // We have reported the error, and are returning to COM, + // so we should clear it. + PyErr_Clear(); + } + } // end of temp scope for Python lock - lock released here! + if ( !supports ) + return NS_ERROR_NO_INTERFACE; + return NS_OK; +} + +nsrefcnt +PyG_Base::AddRef(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt); +#ifdef NS_BUILD_REFCNT_LOGGING + // If we have no pBaseObject, then we need to ignore them + if (m_pBaseObject == NULL) + NS_LOG_ADDREF(this, cnt, refcntLogRepr, sizeof(*this)); +#endif + return cnt; +} + +nsrefcnt +PyG_Base::Release(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt); +#ifdef NS_BUILD_REFCNT_LOGGING + if (m_pBaseObject == NULL) + NS_LOG_RELEASE(this, cnt, refcntLogRepr); +#endif + if ( cnt == 0 ) + delete this; + return cnt; +} + +NS_IMETHODIMP +PyG_Base::GetWeakReference(nsIWeakReference **ret) +{ + // always delegate back to the "base" gateway for the object, as this tear-off + // interface may not live as long as the base. So we recurse back to the base. + if (m_pBaseObject) { + NS_PRECONDITION(m_pWeakRef == nsnull, "Not a base object, but do have a weak-ref!"); + return m_pBaseObject->GetWeakReference(ret); + } + NS_PRECONDITION(ret, "null pointer"); + if (ret==nsnull) return NS_ERROR_INVALID_POINTER; + if (!m_pWeakRef) { + // First query for a weak reference - create it. + // XXX - this looks like it needs thread safety!? + m_pWeakRef = new PyXPCOM_GatewayWeakReference(this); + NS_ABORT_IF_FALSE(m_pWeakRef, "Shouldn't be able to fail creating a weak reference!"); + if (!m_pWeakRef) + return NS_ERROR_UNEXPECTED; + } + *ret = m_pWeakRef; + (*ret)->AddRef(); + return NS_OK; +} + +nsresult PyG_Base::HandleNativeGatewayError(const char *szMethodName) +{ + nsresult rc = NS_OK; + if (PyErr_Occurred()) { + // The error handling - fairly involved, but worth it as + // good error reporting is critical for users to know WTF + // is going on - especially with TypeErrors etc in their + // return values (ie, after the Python code has successfully + // exited, but we encountered errors unpacking their + // result values for the COM caller - there is literally no + // way to catch these exceptions from Python code, as their + // is no Python function directly on the call-stack) + + // First line of attack in an error is to call-back on the policy. + // If the callback of the error handler succeeds and returns an + // integer (for the nsresult), we take no further action. + + // If this callback fails, we log _2_ exceptions - the error + // handler error, and the original error. + + PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing! + PyObject *exc_typ, *exc_val, *exc_tb; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); + + PyObject *err_result = PyObject_CallMethod(m_pPyObject, + (char*)"_GatewayException_", + (char*)"z(OOO)", + szMethodName, + exc_typ ? exc_typ : Py_None, // should never be NULL, but defensive programming... + exc_val ? exc_val : Py_None, // may well be NULL. + exc_tb ? exc_tb : Py_None); // may well be NULL. + if (err_result == NULL) { + PyXPCOM_LogError("The exception handler _CallMethodException_ failed!\n"); + } else if (err_result == Py_None) { + // The exception handler has chosen not to do anything with + // this error, so we still need to print it! + ; + } else if (PyInt_Check(err_result)) { + // The exception handler has given us the nresult. + rc = PyInt_AsLong(err_result); + bProcessMainError = PR_FALSE; + } else { + // The exception handler succeeded, but returned other than + // int or None. + PyXPCOM_LogError("The _CallMethodException_ handler returned object of type '%s' - None or an integer expected\n", PyXPCOM_ObTypeName(err_result)); + } + Py_XDECREF(err_result); + PyErr_Restore(exc_typ, exc_val, exc_tb); + if (bProcessMainError) { + PyXPCOM_LogError("The function '%s' failed\n", szMethodName); + rc = PyXPCOM_SetCOMErrorFromPyException(); + } + PyErr_Clear(); + } + return rc; +} + +static nsresult do_dispatch( + PyObject *pPyObject, + PyObject **ppResult, + const char *szMethodName, + const char *szFormat, + va_list va + ) +{ + NS_PRECONDITION(ppResult, "Must provide a result buffer"); + *ppResult = nsnull; + // Build the Invoke arguments... + PyObject *args = NULL; + PyObject *method = NULL; + PyObject *real_ob = NULL; + nsresult ret = NS_ERROR_FAILURE; + if ( szFormat ) + args = Py_VaBuildValue((char *)szFormat, va); + else + args = PyTuple_New(0); + if ( !args ) + goto done; + + // make sure a tuple. + if ( !PyTuple_Check(args) ) { + PyObject *a = PyTuple_New(1); + if ( a == NULL ) + { + Py_DECREF(args); + goto done; + } + PyTuple_SET_ITEM(a, 0, args); + args = a; + } + // Bit to a hack here to maintain the use of a policy. + // We actually get the policies underlying object + // to make the call on. + real_ob = PyObject_GetAttrString(pPyObject, "_obj_"); + if (real_ob == NULL) { + PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute."); + goto done; + } + method = PyObject_GetAttrString(real_ob, (char *)szMethodName); + if ( !method ) { + PyErr_Clear(); + ret = NS_PYXPCOM_NO_SUCH_METHOD; + goto done; + } + // Make the call + *ppResult = PyEval_CallObject(method, args); + ret = *ppResult ? NS_OK : NS_ERROR_FAILURE; +done: + Py_XDECREF(method); + Py_XDECREF(real_ob); + Py_XDECREF(args); + return ret; +} + + +nsresult PyG_Base::InvokeNativeViaPolicyInternal( + const char *szMethodName, + PyObject **ppResult, + const char *szFormat, + va_list va + ) +{ + if ( m_pPyObject == NULL || szMethodName == NULL ) + return NS_ERROR_NULL_POINTER; + + PyObject *temp = nsnull; + if (ppResult == nsnull) + ppResult = &temp; + nsresult nr = do_dispatch(m_pPyObject, ppResult, szMethodName, szFormat, va); + + // If temp is NULL, they provided a buffer, and we dont touch it. + // If not NULL, *ppResult = temp, and _we_ do own it. + Py_XDECREF(temp); + return nr; +} + +nsresult PyG_Base::InvokeNativeViaPolicy( + const char *szMethodName, + PyObject **ppResult /* = NULL */, + const char *szFormat /* = NULL */, + ... + ) +{ + va_list va; + va_start(va, szFormat); + nsresult nr = InvokeNativeViaPolicyInternal(szMethodName, ppResult, szFormat, va); + va_end(va); + + if (nr == NS_PYXPCOM_NO_SUCH_METHOD) { + // Only problem was missing method. + PyErr_Format(PyExc_AttributeError, "The object does not have a '%s' function.", szMethodName); + } + return nr == NS_OK ? NS_OK : HandleNativeGatewayError(szMethodName); +} + +nsresult PyG_Base::InvokeNativeGetViaPolicy( + const char *szPropertyName, + PyObject **ppResult /* = NULL */ + ) +{ + PyObject *ob_ret = NULL; + nsresult ret = NS_OK; + PyObject *real_ob = NULL; + if ( m_pPyObject == NULL || szPropertyName == NULL ) + return NS_ERROR_NULL_POINTER; + // First see if we have a method of that name. + char buf[256]; + strcpy(buf, "get_"); + strncat(buf, szPropertyName, sizeof(buf)*sizeof(buf[0])-strlen(buf)-1); + buf[sizeof(buf)/sizeof(buf[0])-1] = '\0'; + ret = InvokeNativeViaPolicyInternal(buf, ppResult, nsnull, nsnull); + if (ret == NS_PYXPCOM_NO_SUCH_METHOD) { + // No method of that name - just try a property. + // Bit to a hack here to maintain the use of a policy. + // We actually get the policies underlying object + // to make the call on. + real_ob = PyObject_GetAttrString(m_pPyObject, "_obj_"); + if (real_ob == NULL) { + PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute."); + ret = HandleNativeGatewayError(szPropertyName); + goto done; + } + ob_ret = PyObject_GetAttrString(real_ob, (char *)szPropertyName); + if (ob_ret==NULL) { + PyErr_Format(PyExc_AttributeError, + "The object does not have a 'get_%s' function, or a '%s attribute.", + szPropertyName, szPropertyName); + } else { + ret = NS_OK; + if (ppResult) + *ppResult = ob_ret; + else + Py_XDECREF(ob_ret); + } + } + if (ret != NS_OK) + ret = HandleNativeGatewayError(szPropertyName); + +done: + Py_XDECREF(real_ob); + return ret; +} + +nsresult PyG_Base::InvokeNativeSetViaPolicy( + const char *szPropertyName, + ... + ) +{ + if ( m_pPyObject == NULL || szPropertyName == NULL ) + return NS_ERROR_NULL_POINTER; + nsresult ret = NS_OK; + PyObject *real_ob = NULL; + char buf[256]; + strcpy(buf, "set_"); + strncat(buf, szPropertyName, sizeof(buf)*sizeof(buf[0])-strlen(buf)-1); + buf[sizeof(buf)/sizeof(buf[0])-1] = '\0'; + va_list va; + va_start(va, szPropertyName); + ret = InvokeNativeViaPolicyInternal(buf, NULL, "O", va); + va_end(va); + if (ret == NS_PYXPCOM_NO_SUCH_METHOD) { + // No method of that name - just try a property. + // Bit to a hack here to maintain the use of a policy. + // We actually get the policies underlying object + // to make the call on. + real_ob = PyObject_GetAttrString(m_pPyObject, "_obj_"); + if (real_ob == NULL) { + PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute."); + ret = HandleNativeGatewayError(szPropertyName); + goto done; + } + va_list va2; + va_start(va2, szPropertyName); + PyObject *arg = va_arg( va2, PyObject *); + va_end(va2); + if (PyObject_SetAttrString(real_ob, (char *)szPropertyName, arg) == 0) + ret = NS_OK; + else { + PyErr_Format(PyExc_AttributeError, + "The object does not have a 'set_%s' function, or a '%s attribute.", + szPropertyName, szPropertyName); + } + } + if (ret != NS_OK) + ret = HandleNativeGatewayError(szPropertyName); +done: + Py_XDECREF(real_ob); + return ret; +} + +// Get at the underlying Python object. +PyObject *PyG_Base::UnwrapPythonObject(void) +{ + Py_INCREF(m_pPyObject); + return m_pPyObject; +} +/****************************************************** + + Some special support to help with object identity. + + In the simplest case, assume a Python XPCOM object is + supporting a function "nsIWhatever GetWhatever()", + so implements it as: + return self + it is almost certain they intend returning + the same COM OBJECT to the caller! Thus, if a user of this COM + object does: + + p1 = foo.GetWhatever(); + p2 = foo.GetWhatever(); + + We almost certainly expect p1==p2==foo. + + We previously _did_ have special support for the "self" + example above, but this implements a generic scheme that + works for _all_ objects. + + Whenever we are asked to "AutoWrap" a Python object, the + first thing we do is see if it has been auto-wrapped before. + + If not, we create a new wrapper, then make a COM weak reference + to that wrapper, and store it directly back into the instance + we are auto-wrapping! The use of a weak-reference prevents + cycles. + + The existance of this attribute in an instance indicates if it + has been previously auto-wrapped. + + If it _has_ previously been auto-wrapped, we de-reference the + weak reference, and use that gateway. + +*********************************************************************/ + +PyG_Base *GetDefaultGateway(PyObject *policy) +{ + // NOTE: Instance is the policy, not the real instance + PyObject *instance = PyObject_GetAttrString(policy, "_obj_"); + if (instance == nsnull) + return nsnull; + PyObject *ob_existing_weak = PyObject_GetAttrString(instance, PyXPCOM_szDefaultGatewayAttributeName); + Py_DECREF(instance); + if (ob_existing_weak != NULL) { + PRBool ok = PR_TRUE; + nsCOMPtr pWeakRef; + ok = NS_SUCCEEDED(Py_nsISupports::InterfaceFromPyObject(ob_existing_weak, + NS_GET_IID(nsIWeakReference), + getter_AddRefs(pWeakRef), + PR_FALSE)); + Py_DECREF(ob_existing_weak); + nsISupports *pip; + if (ok) { + nsresult nr = pWeakRef->QueryReferent( NS_GET_IID(nsIInternalPython), (void **)&pip); + if (NS_FAILED(nr)) + return nsnull; + return (PyG_Base *)(nsIInternalPython *)pip; + } + } else + PyErr_Clear(); + return nsnull; +} + +PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway) +{ + NS_ABORT_IF_FALSE(real_inst, "Did not have an _obj_ attribute"); + if (real_inst==NULL) { + PyErr_Clear(); + return PR_FALSE; + } + PyObject *ob_existing_weak = PyObject_GetAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName); + if (ob_existing_weak != NULL) { + // We have an existing default, but as it is a weak reference, it + // may no longer be valid. Check it. + PRBool ok = PR_TRUE; + nsCOMPtr pWeakRef; + ok = NS_SUCCEEDED(Py_nsISupports::InterfaceFromPyObject(ob_existing_weak, + NS_GET_IID(nsIWeakReference), + getter_AddRefs(pWeakRef), + PR_FALSE)); + Py_DECREF(ob_existing_weak); + if (ok) { + Py_BEGIN_ALLOW_THREADS; + ok = NS_SUCCEEDED(pWeakRef->QueryReferent( iid, (void **)(ret_gateway))); + Py_END_ALLOW_THREADS; + } + if (!ok) { + // We have the attribute, but not valid - wipe it + // before restoring it. + if (0 != PyObject_DelAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName)) + PyErr_Clear(); + } + return ok; + } + PyErr_Clear(); + return PR_FALSE; +} + +void AddDefaultGateway(PyObject *instance, nsISupports *gateway) +{ + // NOTE: Instance is the _policy_! + PyObject *real_inst = PyObject_GetAttrString(instance, "_obj_"); + NS_ABORT_IF_FALSE(real_inst, "Could not get the '_obj_' element"); + if (!real_inst) return; + if (!PyObject_HasAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName)) { + nsCOMPtr swr( do_QueryInterface((nsISupportsWeakReference *)(gateway)) ); + NS_ABORT_IF_FALSE(swr, "Our gateway failed with a weak reference query"); + // Create the new default gateway - get a weak reference for our gateway. + if (swr) { + nsCOMPtr pWeakReference; + swr->GetWeakReference( getter_AddRefs(pWeakReference) ); + if (pWeakReference) { + PyObject *ob_new_weak = Py_nsISupports::PyObjectFromInterface(pWeakReference, + NS_GET_IID(nsIWeakReference), + PR_FALSE ); /* bMakeNicePyObject */ + // pWeakReference reference consumed. + if (ob_new_weak) { + PyObject_SetAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName, ob_new_weak); + Py_DECREF(ob_new_weak); + } + } + } + } + Py_DECREF(real_inst); +} diff --git a/src/libs/xpcom18a4/python/src/PyGInputStream.cpp b/src/libs/xpcom18a4/python/src/PyGInputStream.cpp new file mode 100644 index 00000000..d7c27043 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGInputStream.cpp @@ -0,0 +1,173 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// PyGInputStream.cpp +// +// This code is part of the XPCOM extensions for Python. +// +// Written October 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +class PyG_nsIInputStream : public PyG_Base, public nsIInputStream +{ +public: + PyG_nsIInputStream(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIInputStream)) {;} + PYGATEWAY_BASE_SUPPORT(nsIInputStream, PyG_Base); + + NS_IMETHOD Close(void); + NS_IMETHOD Available(PRUint32 *_retval); + NS_IMETHOD Read(char * buf, PRUint32 count, PRUint32 *_retval); + NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval); + NS_IMETHOD IsNonBlocking(PRBool *aNonBlocking); +}; + + +PyG_Base *MakePyG_nsIInputStream(PyObject *instance) +{ + return new PyG_nsIInputStream(instance); +} + +NS_IMETHODIMP +PyG_nsIInputStream::Close() +{ + CEnterLeavePython _celp; + const char *methodName = "close"; + return InvokeNativeViaPolicy(methodName, NULL); +} + +NS_IMETHODIMP +PyG_nsIInputStream::Available(PRUint32 *_retval) +{ + NS_PRECONDITION(_retval, "null pointer"); + CEnterLeavePython _celp; + PyObject *ret; + const char *methodName = "available"; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret); + if (NS_SUCCEEDED(nr)) { + *_retval = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + Py_XDECREF(ret); + } + return nr; +} + +NS_IMETHODIMP +PyG_nsIInputStream::Read(char * buf, PRUint32 count, PRUint32 *_retval) +{ + NS_PRECONDITION(_retval, "null pointer"); + NS_PRECONDITION(buf, "null pointer"); + CEnterLeavePython _celp; + PyObject *ret; + const char *methodName = "read"; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "i", count); + if (NS_SUCCEEDED(nr)) { +#if 0 /* VBox: new buffer protocol (though I could use it for Py_LIMITED_API and ditch the warning, but cpython specific) */ + Py_buffer py_view; + if (PyObject_GetBuffer(ret, &py_view, PyBUF_SIMPLE) == 0) { + if (py_view.len <= count) { + count = py_view.len; + } else { + PyXPCOM_LogWarning("nsIInputStream::read() was asked for %d bytes, but the string returned is %d bytes - truncating!\n", count, py_size); + } + memcpy(buf, py_view.py_buf, count); + PyBuffer_Release(&py_view); + *_retval = count; + } else { + PyErr_Format(PyExc_TypeError, "nsIInputStream::read() method must return a buffer object - not a '%s' object", PyXPCOM_ObTypeName(ret)); + nr = HandleNativeGatewayError(methodName); + } +#else /* Old protocol: */ +# ifndef VBOX /* unsafe cast on 64-bit hosts. */ + PRUint32 py_size; + const void *py_buf; + if (PyObject_AsReadBuffer(ret, &py_buf, (Py_ssize_t*)&py_size)!=0) { +# else /* VBOX */ + const void *py_buf; +# if PY_VERSION_HEX >= 0x02050000 || defined(PY_SSIZE_T_MIN) + Py_ssize_t py_size; +# else + int py_size; +# endif + if (PyObject_AsReadBuffer(ret, &py_buf, &py_size)!=0) { +# endif /* VBOX */ + PyErr_Format(PyExc_TypeError, "nsIInputStream::read() method must return a buffer object - not a '%s' object", PyXPCOM_ObTypeName(ret)); + nr = HandleNativeGatewayError(methodName); + } else { + if (py_size > count) { + PyXPCOM_LogWarning("nsIInputStream::read() was asked for %d bytes, but the string returned is %d bytes - truncating!\n", count, py_size); + py_size = count; + } + memcpy(buf, py_buf, py_size); + *_retval = py_size; + } +#endif + } + return nr; +} + + +NS_IMETHODIMP +PyG_nsIInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_WARNING("ReadSegments() not implemented!!!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +PyG_nsIInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + NS_PRECONDITION(aNonBlocking, "null pointer"); + CEnterLeavePython _celp; + PyObject *ret; + const char *methodName = "isNonBlocking"; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret); + if (NS_SUCCEEDED(nr)) { + *aNonBlocking = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + Py_XDECREF(ret); + } + return nr; +} diff --git a/src/libs/xpcom18a4/python/src/PyGModule.cpp b/src/libs/xpcom18a4/python/src/PyGModule.cpp new file mode 100644 index 00000000..599e0f87 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGModule.cpp @@ -0,0 +1,297 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +// Unfortunately, we can not use an XPConnect object for +// the nsiModule and nsiComponentLoader interfaces. +// As XPCOM shuts down, it shuts down the interface manager before +// it releases all the modules. This is a bit of a problem for +// us, as it means we can't get runtime info on the interface at shutdown time. + +#include "PyXPCOM_std.h" +#include +#include + +class PyG_nsIModule : public PyG_Base, public nsIModule +{ +public: + PyG_nsIModule(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIModule)) {;} + PYGATEWAY_BASE_SUPPORT(nsIModule, PyG_Base); + + NS_DECL_NSIMODULE +}; + +PyG_Base *MakePyG_nsIModule(PyObject *instance) +{ + return new PyG_nsIModule(instance); +} + + +// Create a factory object for creating instances of aClass. +NS_IMETHODIMP +PyG_nsIModule::GetClassObject(nsIComponentManager *aCompMgr, + const nsCID& aClass, + const nsIID& aIID, + void** r_classObj) +{ + NS_PRECONDITION(r_classObj, "null pointer"); + *r_classObj = nsnull; + CEnterLeavePython _celp; + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *iid = Py_nsIID::PyObjectFromIID(aIID); + PyObject *clsid = Py_nsIID::PyObjectFromIID(aClass); + const char *methodName = "getClassObject"; + PyObject *ret = NULL; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "OOO", cm, clsid, iid); + Py_XDECREF(cm); + Py_XDECREF(iid); + Py_XDECREF(clsid); + if (NS_SUCCEEDED(nr)) { + nr = Py_nsISupports::InterfaceFromPyObject(ret, aIID, (nsISupports **)r_classObj, PR_FALSE); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + if (NS_FAILED(nr)) { + NS_ABORT_IF_FALSE(*r_classObj==NULL, "returning error result with an interface - probable leak!"); + } + Py_XDECREF(ret); + return nr; +} + +NS_IMETHODIMP +PyG_nsIModule::RegisterSelf(nsIComponentManager *aCompMgr, + nsIFile* aPath, + const char* registryLocation, + const char* componentType) +{ + NS_PRECONDITION(aCompMgr, "null pointer"); + NS_PRECONDITION(aPath, "null pointer"); + CEnterLeavePython _celp; + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *path = PyObject_FromNSInterface(aPath, NS_GET_IID(nsIFile)); + const char *methodName = "registerSelf"; + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OOzz", cm, path, registryLocation, componentType); + Py_XDECREF(cm); + Py_XDECREF(path); + return nr; +} + +NS_IMETHODIMP +PyG_nsIModule::UnregisterSelf(nsIComponentManager* aCompMgr, + nsIFile* aPath, + const char* registryLocation) +{ + NS_PRECONDITION(aCompMgr, "null pointer"); + NS_PRECONDITION(aPath, "null pointer"); + CEnterLeavePython _celp; + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *path = PyObject_FromNSInterface(aPath, NS_GET_IID(nsIFile)); + const char *methodName = "unregisterSelf"; + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OOz", cm, path, registryLocation); + Py_XDECREF(cm); + Py_XDECREF(path); + return nr; +} + +NS_IMETHODIMP +PyG_nsIModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload) +{ + NS_PRECONDITION(aCompMgr, "null pointer"); + NS_PRECONDITION(okToUnload, "null pointer"); + CEnterLeavePython _celp; + // we are shutting down - don't ask for a nice wrapped object. + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_FALSE); + const char *methodName = "canUnload"; + PyObject *ret = NULL; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "O", cm); + Py_XDECREF(cm); + if (NS_SUCCEEDED(nr)) { + *okToUnload = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/////////////////////////////////////////////////////////////////////////////////// + +class PyG_nsIComponentLoader : public PyG_Base, public nsIComponentLoader +{ +public: + PyG_nsIComponentLoader(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIComponentLoader)) {;} + PYGATEWAY_BASE_SUPPORT(nsIComponentLoader, PyG_Base); + + NS_DECL_NSICOMPONENTLOADER +}; + +PyG_Base *MakePyG_nsIComponentLoader(PyObject *instance) +{ + return new PyG_nsIComponentLoader(instance); +} + +/* nsIFactory getFactory (in nsIIDRef aCID, in string aLocation, in string aType); */ +NS_IMETHODIMP PyG_nsIComponentLoader::GetFactory(const nsIID & aCID, const char *aLocation, const char *aType, nsIFactory **_retval) +{ + CEnterLeavePython _celp; + const char *methodName = "getFactory"; + PyObject *iid = Py_nsIID::PyObjectFromIID(aCID); + PyObject *ret = NULL; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "Ozz", + iid, + aLocation, + aType); + Py_XDECREF(iid); + if (NS_SUCCEEDED(nr)) { + Py_nsISupports::InterfaceFromPyObject(ret, NS_GET_IID(nsIFactory), (nsISupports **)_retval, PR_FALSE); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/* void init (in nsIComponentManager aCompMgr, in nsISupports aRegistry); */ +NS_IMETHODIMP PyG_nsIComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aRegistry) +{ + CEnterLeavePython _celp; + const char *methodName = "init"; + PyObject *c = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *r = PyObject_FromNSInterface(aRegistry, NS_GET_IID(nsISupports)); + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OO", c, r); + Py_XDECREF(c); + Py_XDECREF(r); + return nr; +} + +/* void onRegister (in nsIIDRef aCID, in string aType, in string aClassName, in string aContractID, in string aLocation, in boolean aReplace, in boolean aPersist); */ +NS_IMETHODIMP PyG_nsIComponentLoader::OnRegister(const nsIID & aCID, const char *aType, const char *aClassName, const char *aContractID, const char *aLocation, PRBool aReplace, PRBool aPersist) +{ + CEnterLeavePython _celp; + const char *methodName = "onRegister"; + PyObject *iid = Py_nsIID::PyObjectFromIID(aCID); + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "Ossssii", + iid, + aType, + aClassName, + aContractID, + aLocation, + aReplace, + aPersist); + Py_XDECREF(iid); + return nr; +} + +/* void autoRegisterComponents (in long aWhen, in nsIFile aDirectory); */ +NS_IMETHODIMP PyG_nsIComponentLoader::AutoRegisterComponents(PRInt32 aWhen, nsIFile *aDirectory) +{ + CEnterLeavePython _celp; + const char *methodName = "autoRegisterComponents"; + PyObject *c = PyObject_FromNSInterface(aDirectory, NS_GET_IID(nsIFile)); + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "iO", aWhen, c); + Py_XDECREF(c); + return nr; +} + +/* boolean autoRegisterComponent (in long aWhen, in nsIFile aComponent); */ +NS_IMETHODIMP PyG_nsIComponentLoader::AutoRegisterComponent(PRInt32 aWhen, nsIFile *aComponent, PRBool *_retval) +{ + CEnterLeavePython _celp; + const char *methodName = "autoRegisterComponent"; + PyObject *ret = NULL; + PyObject *c = PyObject_FromNSInterface(aComponent, NS_GET_IID(nsIFile)); + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "iO", aWhen, c); + Py_XDECREF(c); + if (NS_SUCCEEDED(nr)) { + *_retval = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/* boolean autoUnregisterComponent (in long aWhen, in nsIFile aComponent); */ +NS_IMETHODIMP PyG_nsIComponentLoader::AutoUnregisterComponent(PRInt32 aWhen, nsIFile *aComponent, PRBool *_retval) +{ + CEnterLeavePython _celp; + const char *methodName = "autoUnregisterComponent"; + PyObject *ret = NULL; + PyObject *c = PyObject_FromNSInterface(aComponent, NS_GET_IID(nsIFile)); + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "iO", aWhen, c); + Py_XDECREF(c); + if (NS_SUCCEEDED(nr)) { + *_retval = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/* boolean registerDeferredComponents (in long aWhen); */ +NS_IMETHODIMP PyG_nsIComponentLoader::RegisterDeferredComponents(PRInt32 aWhen, PRBool *_retval) +{ + CEnterLeavePython _celp; + const char *methodName = "registerDeferredComponents"; + PyObject *ret = NULL; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "i", aWhen); + if (NS_SUCCEEDED(nr)) { + *_retval = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/* void unloadAll (in long aWhen); */ +NS_IMETHODIMP PyG_nsIComponentLoader::UnloadAll(PRInt32 aWhen) +{ + CEnterLeavePython _celp; + const char *methodName = "unloadAll"; + return InvokeNativeViaPolicy(methodName, NULL, "i", aWhen); +} diff --git a/src/libs/xpcom18a4/python/src/PyGStub.cpp b/src/libs/xpcom18a4/python/src/PyGStub.cpp new file mode 100644 index 00000000..6f219333 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGStub.cpp @@ -0,0 +1,180 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// PyXPTStub - the stub for implementing interfaces. +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +void *PyXPCOM_XPTStub::ThisAsIID(const nsIID &iid) +{ + if (iid.Equals(NS_GET_IID(nsISupports))) + return (nsISupports *)(nsXPTCStubBase *)this; + else if (iid.Equals(m_iid)) + return (nsISupports *)(nsXPTCStubBase *)this; + else + return PyG_Base::ThisAsIID(iid); +} + + +NS_IMETHODIMP +PyXPCOM_XPTStub::GetInterfaceInfo(nsIInterfaceInfo** info) +{ + NS_PRECONDITION(info, "NULL pointer"); + if (info==nsnull) + return NS_ERROR_NULL_POINTER; + // Simply get the XPCOM runtime to provide this + // (but there must be some reason why they dont get it themselves!? + // Maybe because they dont know the IID? + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!"); + if (iim==nsnull) + return NS_ERROR_FAILURE; + + return iim->GetInfoForIID( &m_iid, info); +} + +// call this method and return result +NS_IMETHODIMP +PyXPCOM_XPTStub::CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant* params) +{ + nsresult rc = NS_ERROR_FAILURE; + NS_PRECONDITION(info, "NULL methodinfo pointer"); + NS_PRECONDITION(params, "NULL variant pointer"); + CEnterLeavePython _celp; + PyObject *obParams = NULL; + PyObject *result = NULL; + PyObject *obThisObject = NULL; + PyObject *obMI = PyObject_FromXPTMethodDescriptor(info); + PyXPCOM_GatewayVariantHelper arg_helper(this, methodIndex, info, params); + if (obMI==NULL) + goto done; + // base object is passed raw. + obThisObject = PyObject_FromNSInterface((nsXPTCStubBase *)this, + m_iid, PR_FALSE); + obParams = arg_helper.MakePyArgs(); + if (obParams==NULL) + goto done; + result = PyObject_CallMethod(m_pPyObject, + (char*)"_CallMethod_", + (char*)"OiOO", + obThisObject, + (int)methodIndex, + obMI, + obParams); + if (result!=NULL) { + rc = arg_helper.ProcessPythonResult(result); + // Use an xor to check failure && pyerr, or !failure && !pyerr. + NS_ABORT_IF_FALSE( ((NS_FAILED(rc)!=0)^(PyErr_Occurred()!=0)) == 0, "We must have failure with a Python error, or success without a Python error."); + } +done: + if (PyErr_Occurred()) { + // The error handling - fairly involved, but worth it as + // good error reporting is critical for users to know WTF + // is going on - especially with TypeErrors etc in their + // return values (ie, after the Python code has successfully + // exited, but we encountered errors unpacking the + // result values for the COM caller - there is literally no + // way to catch these exceptions from Python code, as their + // is no Python function on the call-stack) + + // First line of attack in an error is to call-back on the policy. + // If the callback of the error handler succeeds and returns an + // integer (for the nsresult), we take no further action. + + // If this callback fails, we log _2_ exceptions - the error handler + // error, and the original error. + + PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing! + PyObject *exc_typ, *exc_val, *exc_tb; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); + PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb); + + PyObject *err_result = PyObject_CallMethod(m_pPyObject, + (char*)"_CallMethodException_", + (char*)"OiOO(OOO)", + obThisObject, + (int)methodIndex, + obMI, + obParams, + exc_typ ? exc_typ : Py_None, // should never be NULL, but defensive programming... + exc_val ? exc_val : Py_None, // may well be NULL. + exc_tb ? exc_tb : Py_None); // may well be NULL. + if (err_result == NULL) { + PyXPCOM_LogError("The exception handler _CallMethodException_ failed!\n"); + } else if (err_result == Py_None) { + // The exception handler has chosen not to do anything with + // this error, so we still need to print it! + ; + } else if (PyInt_Check(err_result)) { + // The exception handler has given us the nresult. + rc = PyInt_AsLong(err_result); + bProcessMainError = PR_FALSE; + } else { + // The exception handler succeeded, but returned other than + // int or None. + PyXPCOM_LogError("The _CallMethodException_ handler returned object of type '%s' - None or an integer expected\n", PyXPCOM_ObTypeName(err_result)); + } + Py_XDECREF(err_result); + PyErr_Restore(exc_typ, exc_val, exc_tb); + if (bProcessMainError) { + PyXPCOM_LogError("The function '%s' failed\n", info->GetName()); + rc = PyXPCOM_SetCOMErrorFromPyException(); + } + // else everything is already setup, + // just clear the Python error state. + PyErr_Clear(); + } + + Py_XDECREF(obMI); + Py_XDECREF(obParams); + Py_XDECREF(obThisObject); + Py_XDECREF(result); + return rc; +} diff --git a/src/libs/xpcom18a4/python/src/PyGWeakReference.cpp b/src/libs/xpcom18a4/python/src/PyGWeakReference.cpp new file mode 100644 index 00000000..e5254acc --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGWeakReference.cpp @@ -0,0 +1,112 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// PyGWeakReference - implements weak references for gateways. +// +// This code is part of the XPCOM extensions for Python. +// +// Written November 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" + +PyXPCOM_GatewayWeakReference::PyXPCOM_GatewayWeakReference( PyG_Base *base ) +{ + m_pBase = base; + +#ifdef NS_BUILD_REFCNT_LOGGING + // bloat view uses 40 chars - stick "(WR)" at the end of this position. + strncpy(refcntLogRepr, m_pBase->refcntLogRepr, sizeof(refcntLogRepr)); + refcntLogRepr[sizeof(refcntLogRepr)-1] = '\0'; + char *dest = refcntLogRepr + ((strlen(refcntLogRepr) > 36) ? 36 : strlen(refcntLogRepr)); + strcpy(dest, "(WR)"); +#endif // NS_BUILD_REFCNT_LOGGING +} + +PyXPCOM_GatewayWeakReference::~PyXPCOM_GatewayWeakReference() +{ + // Simply zap my reference to the gateway! + // No need to zap my gateway's reference to me, as + // it already holds a reference, so if we are destructing, + // then it can't possibly hold one. + m_pBase = NULL; +} + +nsrefcnt +PyXPCOM_GatewayWeakReference::AddRef(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt); +#ifdef NS_BUILD_REFCNT_LOGGING + NS_LOG_ADDREF(this, cnt, refcntLogRepr, sizeof(*this)); +#endif + return cnt; +} + +nsrefcnt +PyXPCOM_GatewayWeakReference::Release(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt); +#ifdef NS_BUILD_REFCNT_LOGGING + NS_LOG_RELEASE(this, cnt, refcntLogRepr); +#endif + if ( cnt == 0 ) + delete this; + return cnt; +} + +NS_IMPL_THREADSAFE_QUERY_INTERFACE1(PyXPCOM_GatewayWeakReference, nsIWeakReference) + +NS_IMETHODIMP +PyXPCOM_GatewayWeakReference::QueryReferent(REFNSIID iid, void * *ret) +{ + { + // Temp scope for lock. We can't hold the lock during + // a QI, as this may itself need the lock. + // Make sure our object isn't dieing right now on another thread. + CEnterLeaveXPCOMFramework _celf; + if (m_pBase == NULL) + return NS_ERROR_NULL_POINTER; + m_pBase->AddRef(); // Can't die while we have a ref. + } // end of lock scope - lock unlocked. + nsresult nr = m_pBase->QueryInterface(iid, ret); + m_pBase->Release(); + return nr; +} diff --git a/src/libs/xpcom18a4/python/src/PyIClassInfo.cpp b/src/libs/xpcom18a4/python/src/PyIClassInfo.cpp new file mode 100644 index 00000000..6d0f499d --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIClassInfo.cpp @@ -0,0 +1,181 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. Portions created by ActiveState Tool Corp. are Copyright (C) 2001 ActiveState Tool Corp. All Rights Reserved. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2001 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2001, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsIClassInfo.h" + +static nsIClassInfo *_GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIClassInfo); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIClassInfo *)Py_nsISupports::GetI(self); +} + +static PyObject *PyGetInterfaces(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsIClassInfo *pI = _GetI(self); + if (pI==NULL) + return NULL; + + nsIID** iidArray = nsnull; + PRUint32 iidCount = 0; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInterfaces(&iidCount, &iidArray); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + PyObject *ret = PyTuple_New(iidCount); + if (ret==NULL) + return NULL; + for (PRUint32 i=0;i pi; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetHelperForLanguage(language, getter_AddRefs(pi)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsISupports)); +} + +static PyObject *MakeStringOrNone(char *v) +{ + if (v) +#if PY_MAJOR_VERSION <= 2 + return PyString_FromString(v); +#else + return PyUnicode_FromString(v); +#endif + Py_INCREF(Py_None); + return Py_None; +} + +#define GETATTR_CHECK_RESULT(nr) if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr) + +PyObject * +Py_nsIClassInfo::getattr(const char *name) +{ + nsIClassInfo *pI = _GetI(this); + if (pI==NULL) + return NULL; + + nsresult nr; + PyObject *ret = NULL; + if (strcmp(name, "contractID")==0) { + char *str_ret = NULL; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetContractID(&str_ret); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = MakeStringOrNone(str_ret); + nsMemory::Free(str_ret); + } else if (strcmp(name, "classDescription")==0) { + char *str_ret = NULL; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetClassDescription(&str_ret); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = MakeStringOrNone(str_ret); + nsMemory::Free(str_ret); + } else if (strcmp(name, "classID")==0) { + nsIID *iid = NULL; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetClassID(&iid); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = Py_nsIID::PyObjectFromIID(*iid); + nsMemory::Free(iid); + } else if (strcmp(name, "implementationLanguage")==0) { + PRUint32 i; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetImplementationLanguage(&i); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = PyInt_FromLong(i); + } else { + ret = Py_nsISupports::getattr(name); + } + return ret; +} + +int +Py_nsIClassInfo::setattr(const char *name, PyObject *v) +{ + return Py_nsISupports::setattr(name, v); + +} + +struct PyMethodDef +PyMethods_IClassInfo[] = +{ + { "getInterfaces", PyGetInterfaces, 1}, + { "GetInterfaces", PyGetInterfaces, 1}, + { "getHelperForLanguage", PyGetHelperForLanguage, 1}, + { "GetHelperForLanguage", PyGetHelperForLanguage, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIComponentManager.cpp b/src/libs/xpcom18a4/python/src/PyIComponentManager.cpp new file mode 100644 index 00000000..c3b89112 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIComponentManager.cpp @@ -0,0 +1,138 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" + +static nsIComponentManager *GetI(PyObject *self) { + static const nsIID iid = NS_GET_IID(nsIComponentManager); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return NS_STATIC_CAST(nsIComponentManager*, Py_nsISupports::GetI(self)); +} + +static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args) +{ + // second arg to CreateInstanceByContractID is a "delegate" - we + // aren't sure of the semantics of this yet and it seems rarely used, + // so we just punt for now. + char *pid, *notyet = NULL; + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "s|zO", &pid, ¬yet, &obIID)) + return NULL; + if (notyet != NULL) { + PyErr_SetString(PyExc_ValueError, "2nd arg must be none"); + return NULL; + } + nsIComponentManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + if (obIID==NULL) + iid = NS_GET_IID(nsISupports); + else + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr pis; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CreateInstanceByContractID(pid, NULL, iid, getter_AddRefs(pis)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE); +} + +static PyObject *PyCreateInstance(PyObject *self, PyObject *args) +{ + char *notyet = NULL; + PyObject *obClassID = NULL, *obIID = NULL; + if (!PyArg_ParseTuple(args, "O|zO", &obClassID, ¬yet, &obIID)) + return NULL; + if (notyet != NULL) { + PyErr_SetString(PyExc_ValueError, "2nd arg must be none"); + return NULL; + } + nsIComponentManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID classID; + if (!Py_nsIID::IIDFromPyObject(obClassID, &classID)) + return NULL; + nsIID iid; + if (obIID==NULL) + iid = NS_GET_IID(nsISupports); + else + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr pis; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CreateInstance(classID, NULL, iid, getter_AddRefs(pis)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE); +} + +struct PyMethodDef +PyMethods_IComponentManager[] = +{ + { "createInstanceByContractID", PyCreateInstanceByContractID, 1}, + { "createInstance", PyCreateInstance, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIComponentManagerObsolete.cpp b/src/libs/xpcom18a4/python/src/PyIComponentManagerObsolete.cpp new file mode 100644 index 00000000..7d07d421 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIComponentManagerObsolete.cpp @@ -0,0 +1,203 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" + +static nsIComponentManagerObsolete *GetI(PyObject *self) { + static const nsIID iid = NS_GET_IID(nsIComponentManagerObsolete); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIComponentManagerObsolete *)Py_nsISupports::GetI(self); +} + +static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args) +{ + char *pid, *notyet = NULL; + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "s|zO", &pid, ¬yet, &obIID)) + return NULL; + if (notyet != NULL) { + PyErr_SetString(PyExc_ValueError, "2nd arg must be none"); + return NULL; + } + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + if (obIID==NULL) + iid = NS_GET_IID(nsISupports); + else + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsISupports *pis; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CreateInstanceByContractID(pid, NULL, iid, (void **)&pis); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE, PR_FALSE); +} + +static PyObject *PyContractIDToClassID(PyObject *self, PyObject *args) +{ + char *pid; + if (!PyArg_ParseTuple(args, "s", &pid)) + return NULL; + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->ContractIDToClassID(pid, &iid); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsIID::PyObjectFromIID(iid); +} + +static PyObject *PyCLSIDToContractID(PyObject *self, PyObject *args) +{ + PyObject *obIID; + if (!PyArg_ParseTuple(args, "O", &obIID)) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + char *ret_pid = nsnull; + char *ret_class = nsnull; + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CLSIDToContractID(iid, &ret_class, &ret_pid); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + +#if PY_MAJOR_VERSION <= 2 + PyObject *ob_pid = PyString_FromString(ret_pid); + PyObject *ob_class = PyString_FromString(ret_class); +#else + PyObject *ob_pid = PyUnicode_FromString(ret_pid); + PyObject *ob_class = PyUnicode_FromString(ret_class); +#endif + PyObject *ret = Py_BuildValue("OO", ob_pid, ob_class); + nsMemory::Free(ret_pid); + nsMemory::Free(ret_class); + Py_XDECREF(ob_pid); + Py_XDECREF(ob_class); + return ret; +} + +static PyObject *PyEnumerateCLSIDs(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIEnumerator *pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->EnumerateCLSIDs(&pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator), PR_FALSE); +} + +static PyObject *PyEnumerateContractIDs(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIEnumerator *pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->EnumerateContractIDs(&pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator), PR_FALSE); +} + +struct PyMethodDef +PyMethods_IComponentManagerObsolete[] = +{ + { "CreateInstanceByContractID", PyCreateInstanceByContractID, 1}, + { "createInstanceByContractID", PyCreateInstanceByContractID, 1}, + { "EnumerateCLSIDs", PyEnumerateCLSIDs, 1}, + { "enumerateCLSIDs", PyEnumerateCLSIDs, 1}, + { "EnumerateContractIDs", PyEnumerateContractIDs, 1}, + { "enumerateContractIDs", PyEnumerateContractIDs, 1}, + { "ContractIDToClassID", PyContractIDToClassID, 1}, + { "contractIDToClassID", PyContractIDToClassID, 1}, + { "CLSIDToContractID", PyCLSIDToContractID, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIEnumerator.cpp b/src/libs/xpcom18a4/python/src/PyIEnumerator.cpp new file mode 100644 index 00000000..b196d956 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIEnumerator.cpp @@ -0,0 +1,235 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +static nsIEnumerator *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIEnumerator); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIEnumerator *)Py_nsISupports::GetI(self); +} + +static PyObject *PyFirst(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":First")) + return NULL; + + nsIEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->First(); + Py_END_ALLOW_THREADS; + return PyInt_FromLong(r); +} + +static PyObject *PyNext(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":Next")) + return NULL; + + nsIEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->Next(); + Py_END_ALLOW_THREADS; + return PyInt_FromLong(r); +} + +static PyObject *PyCurrentItem(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "|O:CurrentItem", &obIID)) + return NULL; + + nsIID iid(NS_GET_IID(nsISupports)); + if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsIEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsISupports *pRet = nsnull; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CurrentItem(&pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + if (obIID) { + nsISupports *temp; + Py_BEGIN_ALLOW_THREADS; + r = pRet->QueryInterface(iid, (void **)&temp); + pRet->Release(); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) { + return PyXPCOM_BuildPyException(r); + } + pRet = temp; + } + PyObject *ret = Py_nsISupports::PyObjectFromInterface(pRet, iid); + NS_IF_RELEASE(pRet); + return ret; +} + +// A method added for Python performance if you really need +// it. Allows you to fetch a block of objects in one +// hit, allowing the loop to remain implemented in C. +static PyObject *PyFetchBlock(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + int n_wanted; + int n_fetched = 0; + if (!PyArg_ParseTuple(args, "i|O:FetchBlock", &n_wanted, &obIID)) + return NULL; + + nsIID iid(NS_GET_IID(nsISupports)); + if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsIEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + // We want to fetch with the thread-lock released, + // but this means we can not append to the PyList + nsISupports **fetched = new nsISupports*[n_wanted]; + if (fetched==nsnull) { + PyErr_NoMemory(); + return NULL; + } + memset(fetched, 0, sizeof(nsISupports *) * n_wanted); + nsresult r = NS_OK; + Py_BEGIN_ALLOW_THREADS; + for (;n_fetchedCurrentItem(&pNew); + if (NS_FAILED(r)) { + r = 0; // Normal enum end + break; + } + if (obIID) { + nsISupports *temp; + r = pNew->QueryInterface(iid, (void **)&temp); + pNew->Release(); + if ( NS_FAILED(r) ) { + break; + } + pNew = temp; + } + fetched[n_fetched] = pNew; + n_fetched++; // must increment before breaking out. + if (NS_FAILED(pI->Next())) + break; // not an error condition. + } + Py_END_ALLOW_THREADS; + PyObject *ret; + if (NS_SUCCEEDED(r)) { + ret = PyList_New(n_fetched); + if (ret) + for (int i=0;iRelease(); + + } + delete [] fetched; + return ret; +} + +static PyObject *PyIsDone(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":IsDone")) + return NULL; + + nsIEnumerator *pI = GetI(self); + nsresult r; + if (pI==NULL) + return NULL; + + Py_BEGIN_ALLOW_THREADS; + r = pI->IsDone(); + Py_END_ALLOW_THREADS; + if (NS_FAILED(r)) + return PyXPCOM_BuildPyException(r); + PyObject *ret = r==NS_OK ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} + +struct PyMethodDef +PyMethods_IEnumerator[] = +{ + { "First", PyFirst, 1}, + { "first", PyFirst, 1}, + { "Next", PyNext, 1}, + { "next", PyNext, 1}, + { "CurrentItem", PyCurrentItem, 1}, + { "currentItem", PyCurrentItem, 1}, + { "IsDone", PyIsDone, 1}, + { "isDone", PyIsDone, 1}, + { "FetchBlock", PyFetchBlock, 1}, + { "fetchBlock", PyFetchBlock, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIID.cpp b/src/libs/xpcom18a4/python/src/PyIID.cpp new file mode 100644 index 00000000..f24ae20e --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIID.cpp @@ -0,0 +1,410 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// Py_nsIID.cpp -- IID type for Python/XPCOM +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. +// +// @doc + +#include "PyXPCOM_std.h" +#include + +nsIID Py_nsIID_NULL = {0,0,0,{0,0,0,0,0,0,0,0}}; + +// @pymethod |xpcom|IID|Creates a new IID object +PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args) +{ + PyObject *obIID; + PyObject *obBuf; + if ( PyArg_ParseTuple(args, "O", &obBuf)) { +#if PY_MAJOR_VERSION <= 2 + if (PyBuffer_Check(obBuf)) { + PyBufferProcs *pb = NULL; + pb = obBuf->ob_type->tp_as_buffer; + void *buf = NULL; + int size = (*pb->bf_getreadbuffer)(obBuf, 0, &buf); +#else + if (PyObject_CheckBuffer(obBuf)) { +# ifndef Py_LIMITED_API + Py_buffer view; + if (PyObject_GetBuffer(obBuf, &view, PyBUF_CONTIG_RO) != 0) { + PyErr_Format(PyExc_ValueError, "Could not get contiguous buffer from object"); + return NULL; + } + Py_ssize_t size = view.len; + const void *buf = view.buf; +# else /* Py_LIMITED_API - the buffer API is non-existant, from what I can tell */ + const void *buf = NULL; + Py_ssize_t size = 0; + if (PyObject_AsReadBuffer(obBuf, &buf, &size) != 0) { + PyErr_Format(PyExc_ValueError, "Could not get read-only buffer from object"); + return NULL; + } +# endif /* Py_LIMITED_API */ +#endif + if (size != sizeof(nsIID) || buf==NULL) { +#if PY_MAJOR_VERSION >= 3 && !defined(Py_LIMITED_API) + PyBuffer_Release(&view); +#endif +#ifdef VBOX + PyErr_Format(PyExc_ValueError, "A buffer object to be converted to an IID must be exactly %d bytes long", (int)sizeof(nsIID)); +#else + PyErr_Format(PyExc_ValueError, "A buffer object to be converted to an IID must be exactly %d bytes long", sizeof(nsIID)); +#endif + return NULL; + } + nsIID iid; + unsigned char const *ptr = (unsigned char const *)buf; + iid.m0 = XPT_SWAB32(*((PRUint32 *)ptr)); + ptr = ((unsigned char const *)buf) + offsetof(nsIID, m1); + iid.m1 = XPT_SWAB16(*((PRUint16 *)ptr)); + ptr = ((unsigned char const *)buf) + offsetof(nsIID, m2); + iid.m2 = XPT_SWAB16(*((PRUint16 *)ptr)); + ptr = ((unsigned char const *)buf) + offsetof(nsIID, m3); + for (int i=0;i<8;i++) { + iid.m3[i] = *((PRUint8 const *)ptr); + ptr += sizeof(PRUint8); + } +#if PY_MAJOR_VERSION >= 3 && !defined(Py_LIMITED_API) + PyBuffer_Release(&view); +#endif + return new Py_nsIID(iid); + } + } + PyErr_Clear(); + // @pyparm string/Unicode|iidString||A string representation of an IID, or a ContractID. + if ( !PyArg_ParseTuple(args, "O", &obIID) ) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + return new Py_nsIID(iid); +} + +/*static*/ PRBool +Py_nsIID::IIDFromPyObject(PyObject *ob, nsIID *pRet) { + PRBool ok = PR_TRUE; + nsIID iid; + if (ob==NULL) { + PyErr_SetString(PyExc_RuntimeError, "The IID object is invalid!"); + return PR_FALSE; + } +#if PY_MAJOR_VERSION <= 2 + if (PyString_Check(ob)) { + ok = iid.Parse(PyString_AsString(ob)); +#else + if (PyUnicode_Check(ob)) { + ok = iid.Parse(PyUnicode_AsUTF8(ob)); +#endif + if (!ok) { + PyXPCOM_BuildPyException(NS_ERROR_ILLEGAL_VALUE); + return PR_FALSE; + } +#ifndef Py_LIMITED_API + } else if (ob->ob_type == &type) { +#else + } else if (ob->ob_type == Py_nsIID::GetTypeObject()) { +#endif + iid = ((Py_nsIID *)ob)->m_iid; + } else if (PyObject_HasAttrString(ob, "__class__")) { + // Get the _iidobj_ attribute + PyObject *use_ob = PyObject_GetAttrString(ob, "_iidobj_"); + if (use_ob==NULL) { + PyErr_SetString(PyExc_TypeError, "Only instances with _iidobj_ attributes can be used as IID objects"); + return PR_FALSE; + } +#ifndef Py_LIMITED_API + if (use_ob->ob_type != &type) { +#else + if (use_ob->ob_type != Py_nsIID::GetTypeObject()) { +#endif + Py_DECREF(use_ob); + PyErr_SetString(PyExc_TypeError, "instance _iidobj_ attributes must be raw IID object"); + return PR_FALSE; + } + iid = ((Py_nsIID *)use_ob)->m_iid; + Py_DECREF(use_ob); + } else { + PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an IID", PyXPCOM_ObTypeName(ob)); + ok = PR_FALSE; + } + if (ok) *pRet = iid; + return ok; +} + + +// @object Py_nsIID|A Python object, representing an IID/CLSID. +// All pythoncom functions that return a CLSID/IID will return one of these +// objects. However, in almost all cases, functions that expect a CLSID/IID +// as a param will accept either a string object, or a native Py_nsIID object. +#ifndef Py_LIMITED_API +PyTypeObject Py_nsIID::type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "IID", + sizeof(Py_nsIID), + 0, + PyTypeMethod_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + PyTypeMethod_getattr, /* tp_getattr */ + 0, /* tp_setattr */ +#if PY_MAJOR_VERSION <= 2 + PyTypeMethod_compare, /* tp_compare */ +#else + 0, /* reserved */ +#endif + PyTypeMethod_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + PyTypeMethod_hash, /* tp_hash */ + 0, /* tp_call */ + PyTypeMethod_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + PyTypeMethod_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ +}; +#else /* Py_LIMITED_API */ +NS_EXPORT_STATIC_MEMBER_(PyTypeObject *) Py_nsIID::s_pType = NULL; + +PyTypeObject *Py_nsIID::GetTypeObject(void) +{ + PyTypeObject *pTypeObj = Py_nsIID::s_pType; + if (pTypeObj) + return pTypeObj; + + PyType_Slot aTypeSlots[] = { + { Py_tp_base, &PyType_Type }, + { Py_tp_dealloc, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_dealloc }, + { Py_tp_getattr, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_getattr }, + { Py_tp_repr, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_repr }, + { Py_tp_hash, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_hash }, + { Py_tp_str, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_str }, + { Py_tp_richcompare, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_richcompare }, + { 0, NULL } /* terminator */ + }; + PyType_Spec TypeSpec = { + /* .name: */ "IID", + /* .basicsize: */ sizeof(Py_nsIID), + /* .itemsize: */ 0, + /* .flags: */ 0, + /* .slots: */ aTypeSlots, + }; + + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); /* goes south in PyType_Ready if we don't clear exceptions first. */ + + pTypeObj = (PyTypeObject *)PyType_FromSpec(&TypeSpec); + assert(pTypeObj); + + PyErr_Restore(exc_typ, exc_val, exc_tb); + Py_nsIID::s_pType = pTypeObj; + return pTypeObj; +} +#endif /* Py_LIMITED_API */ + +Py_nsIID::Py_nsIID(const nsIID &riid) +{ +#ifndef Py_LIMITED_API + ob_type = &type; +#else + ob_type = GetTypeObject(); +#endif +#if 1 /* VBox: Must use for 3.9+, includes _Py_NewReferences. Works for all older versions too. @bugref{10079} */ + PyObject_Init(this, ob_type); +#else + _Py_NewReference(this); +#endif + + m_iid = riid; +} + +/*static*/PyObject * +Py_nsIID::PyTypeMethod_getattr(PyObject *self, char *name) +{ + Py_nsIID *me = (Py_nsIID *)self; + if (strcmp(name, "name")==0) { + char *iid_repr = nsnull; + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + if (iim!=nsnull) + iim->GetNameForIID(&me->m_iid, &iid_repr); + if (iid_repr==nsnull) + iid_repr = me->m_iid.ToString(); + PyObject *ret; + if (iid_repr != nsnull) { +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(iid_repr); +#else + ret = PyUnicode_FromString(iid_repr); +#endif + nsMemory::Free(iid_repr); + } else +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(""); +#else + ret = PyUnicode_FromString(""); +#endif + return ret; + } + return PyErr_Format(PyExc_AttributeError, "IID objects have no attribute '%s'", name); +} + +#if PY_MAJOR_VERSION <= 2 +/* static */ int +Py_nsIID::PyTypeMethod_compare(PyObject *self, PyObject *other) +{ + Py_nsIID *s_iid = (Py_nsIID *)self; + Py_nsIID *o_iid = (Py_nsIID *)other; + int rc = memcmp(&s_iid->m_iid, &o_iid->m_iid, sizeof(s_iid->m_iid)); + return rc == 0 ? 0 : (rc < 0 ? -1 : 1); +} +#endif + +/* static */ PyObject * +Py_nsIID::PyTypeMethod_richcompare(PyObject *self, PyObject *other, int op) +{ + PyObject *result = NULL; + Py_nsIID *s_iid = (Py_nsIID *)self; + Py_nsIID *o_iid = (Py_nsIID *)other; + int rc = memcmp(&s_iid->m_iid, &o_iid->m_iid, sizeof(s_iid->m_iid)); + switch (op) + { + case Py_LT: + result = rc < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = rc <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = rc == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = rc != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = rc > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = rc >= 0 ? Py_True : Py_False; + break; + } + Py_XINCREF(result); + return result; +} + +/* static */ PyObject * +Py_nsIID::PyTypeMethod_repr(PyObject *self) +{ + Py_nsIID *s_iid = (Py_nsIID *)self; + char buf[256]; + char *sziid = s_iid->m_iid.ToString(); +#ifdef VBOX + snprintf(buf, sizeof(buf), "_xpcom.ID('%s')", sziid); +#else + sprintf(buf, "_xpcom.IID('%s')", sziid); +#endif + nsMemory::Free(sziid); +#if PY_MAJOR_VERSION <= 2 + return PyString_FromString(buf); +#else + return PyUnicode_FromString(buf); +#endif +} + +/* static */ PyObject * +Py_nsIID::PyTypeMethod_str(PyObject *self) +{ + Py_nsIID *s_iid = (Py_nsIID *)self; + char *sziid = s_iid->m_iid.ToString(); +#if PY_MAJOR_VERSION <= 2 + PyObject *ret = PyString_FromString(sziid); +#else + PyObject *ret = PyUnicode_FromString(sziid); +#endif + nsMemory::Free(sziid); + return ret; +} + +#if PY_VERSION_HEX >= 0x03020000 +/* static */Py_hash_t +Py_nsIID::PyTypeMethod_hash(PyObject *self) +#else +/* static */long +Py_nsIID::PyTypeMethod_hash(PyObject *self) +#endif +{ + const nsIID &iid = ((Py_nsIID *)self)->m_iid; + +#if PY_VERSION_HEX >= 0x03020000 + Py_hash_t ret = iid.m0 + iid.m1 + iid.m2; +#else + long ret = iid.m0 + iid.m1 + iid.m2; +#endif + for (int i=0;i<7;i++) + ret += iid.m3[i]; + if ( ret == -1 ) + return -2; + return ret; +} + +/*static*/ void +Py_nsIID::PyTypeMethod_dealloc(PyObject *ob) +{ + delete (Py_nsIID *)ob; +} diff --git a/src/libs/xpcom18a4/python/src/PyIInputStream.cpp b/src/libs/xpcom18a4/python/src/PyIInputStream.cpp new file mode 100644 index 00000000..b290a3e4 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIInputStream.cpp @@ -0,0 +1,190 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written September 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsIInputStream.h" + +// Prevents us needing to use an nsIScriptableInputStream +// (and even that can't read binary data!!!) + +static nsIInputStream *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIInputStream); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIInputStream *)Py_nsISupports::GetI(self); +} + +static PyObject *DoPyRead_Buffer(nsIInputStream *pI, PyObject *obBuffer, PRUint32 n) +{ + PRUint32 nread; + void *buf; +#ifndef VBOX /* unsafe cast on 64-bit hosts. */ + PRUint32 buf_len; + if (PyObject_AsWriteBuffer(obBuffer, &buf, (Py_ssize_t *)&buf_len) != 0) { +#else /* VBOX */ +# if PY_VERSION_HEX >= 0x02050000 || defined(PY_SSIZE_T_MIN) + Py_ssize_t buf_len; +# else + int buf_len; +# endif /* VBOX */ + if (PyObject_AsWriteBuffer(obBuffer, &buf, &buf_len) != 0) { +#endif + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "The buffer object does not have a write buffer!"); + return NULL; + } + if (n==(PRUint32)-1) { + n = buf_len; + } else { + if (n > buf_len) { + NS_WARNING("Warning: PyIInputStream::read() was passed an integer size greater than the size of the passed buffer! Buffer size used.\n"); + n = buf_len; + } + } + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->Read((char *)buf, n, &nread); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(nread); +} + +static PyObject *DoPyRead_Size(nsIInputStream *pI, PRUint32 n) +{ + if (n==(PRUint32)-1) { + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->Available(&n); + Py_END_ALLOW_THREADS; + if (NS_FAILED(r)) + return PyXPCOM_BuildPyException(r); + } + if (n==0) { // mozilla will assert if we alloc zero bytes. +#if PY_MAJOR_VERSION <= 2 + return PyBuffer_New(0); +#else + return PyBytes_FromString(""); +#endif + } + char *buf = (char *)nsMemory::Alloc(n); + if (buf==NULL) { + PyErr_NoMemory(); + return NULL; + } + nsresult r; + PRUint32 nread; + Py_BEGIN_ALLOW_THREADS; + r = pI->Read(buf, n, &nread); + Py_END_ALLOW_THREADS; + PyObject *rc = NULL; + if ( NS_SUCCEEDED(r) ) { +#if PY_MAJOR_VERSION <= 2 + rc = PyBuffer_New(nread); + if (rc != NULL) { + void *ob_buf; +#ifndef VBOX /* unsafe cast on 64-bit hosts. */ + PRUint32 buf_len; + if (PyObject_AsWriteBuffer(rc, &ob_buf, (Py_ssize_t *)&buf_len) != 0) { +#else /* VBOX */ +# if PY_VERSION_HEX >= 0x02050000 || defined(PY_SSIZE_T_MIN) + Py_ssize_t buf_len; +# else + int buf_len; +# endif /* VBOX */ + if (PyObject_AsWriteBuffer(rc, &ob_buf, &buf_len) != 0) { +#endif + // should never fail - we just created it! + return NULL; + } + if (buf_len != nread) { + PyErr_SetString(PyExc_RuntimeError, "New buffer isnt the size we create it!"); + return NULL; + } + memcpy(ob_buf, buf, nread); + } +#else + rc = PyBytes_FromStringAndSize(buf, nread); +#endif + } else + PyXPCOM_BuildPyException(r); + nsMemory::Free(buf); + return rc; +} + +static PyObject *PyRead(PyObject *self, PyObject *args) +{ + PyObject *obBuffer = NULL; + PRUint32 n = (PRUint32)-1; + + nsIInputStream *pI = GetI(self); + if (pI==NULL) + return NULL; + if (PyArg_ParseTuple(args, "|i", (int *)&n)) + // This worked - no args, or just an int. + return DoPyRead_Size(pI, n); + // try our other supported arg format. + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "O|i", &obBuffer, (int *)&n)) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "'read()' must be called as (buffer_ob, int_size=-1) or (int_size=-1)"); + return NULL; + } + return DoPyRead_Buffer(pI, obBuffer, n); +} + + +struct PyMethodDef +PyMethods_IInputStream[] = +{ + { "read", PyRead, 1}, + // The rest are handled as normal + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp b/src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp new file mode 100644 index 00000000..7e1a9466 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp @@ -0,0 +1,431 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" + + +static nsIInterfaceInfo *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIInterfaceInfo); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIInterfaceInfo *)Py_nsISupports::GetI(self); +} + +static PyObject *PyGetName(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetName")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + char *name; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetName(&name); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); +#if PY_MAJOR_VERSION <= 2 + PyObject *ret = PyString_FromString(name); +#else + PyObject *ret = PyUnicode_FromString(name); +#endif + nsMemory::Free(name); + return ret; +} + +static PyObject *PyGetIID(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetIID")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID *iid_ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInterfaceIID(&iid_ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + PyObject *ret = Py_nsIID::PyObjectFromIID(*iid_ret); + nsMemory::Free(iid_ret); + return ret; +} + +static PyObject *PyIsScriptable(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":IsScriptable")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + PRBool b_ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->IsScriptable(&b_ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(b_ret); +} + +static PyObject *PyGetParent(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetParent")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsCOMPtr pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetParent(getter_AddRefs(pRet)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE); +} + +static PyObject *PyGetMethodCount(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetMethodCount")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + PRUint16 ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetMethodCount(&ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(ret); +} + + +static PyObject *PyGetConstantCount(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetConstantCount")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + PRUint16 ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetConstantCount(&ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(ret); +} + +static PyObject *PyGetMethodInfo(PyObject *self, PyObject *args) +{ + PRUint16 index; + if (!PyArg_ParseTuple(args, "h:GetMethodInfo", &index)) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + PRUint16 nmethods; + pI->GetMethodCount(&nmethods); + if (index>=nmethods) { + PyErr_SetString(PyExc_ValueError, "The method index is out of range"); + return NULL; + } + + const nsXPTMethodInfo *pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetMethodInfo(index, &pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyObject_FromXPTMethodDescriptor(pRet); +} + +static PyObject *PyGetMethodInfoForName(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s:GetMethodInfoForName", &name)) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + const nsXPTMethodInfo *pRet; + PRUint16 index; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetMethodInfoForName(name, &index, &pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + PyObject *ret_i = PyObject_FromXPTMethodDescriptor(pRet); + if (ret_i==NULL) + return NULL; + PyObject *real_ret = Py_BuildValue("iO", (int)index, ret_i); + Py_DECREF(ret_i); + return real_ret; +} + + +static PyObject *PyGetConstant(PyObject *self, PyObject *args) +{ + PRUint16 index; + if (!PyArg_ParseTuple(args, "h:GetConstant", &index)) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + const nsXPTConstant *pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetConstant(index, &pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyObject_FromXPTConstant(pRet); +} + +static PRBool __GetMethodInfoHelper(nsIInterfaceInfo *pii, int mi, int pi, const nsXPTMethodInfo **ppmi) +{ + PRUint16 nmethods=0; + pii->GetMethodCount(&nmethods); + if (mi<0 || mi>=nmethods) { + PyErr_SetString(PyExc_ValueError, "The method index is out of range"); + return PR_FALSE; + } + const nsXPTMethodInfo *pmi; + nsresult r = pii->GetMethodInfo(mi, &pmi); + if ( NS_FAILED(r) ) { + PyXPCOM_BuildPyException(r); + return PR_FALSE; + } + + int nparams=0; + nparams = pmi->GetParamCount(); + if (pi<0 || pi>=nparams) { + PyErr_SetString(PyExc_ValueError, "The param index is out of range"); + return PR_FALSE; + } + *ppmi = pmi; + return PR_TRUE; +} + +static PyObject *PyGetInfoForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi; + if (!PyArg_ParseTuple(args, "hh:GetInfoForParam", &mi, &pi)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsCOMPtr pnewii; + nsresult n = pii->GetInfoForParam(mi, ¶m_info, getter_AddRefs(pnewii)); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return Py_nsISupports::PyObjectFromInterface(pnewii, NS_GET_IID(nsIInterfaceInfo)); +} + +static PyObject *PyGetIIDForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi; + if (!PyArg_ParseTuple(args, "hh:GetIIDForParam", &mi, &pi)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsIID *piid; + nsresult n = pii->GetIIDForParam(mi, ¶m_info, &piid); + if (NS_FAILED(n) || piid==nsnull) + return PyXPCOM_BuildPyException(n); + PyObject *rc = Py_nsIID::PyObjectFromIID(*piid); + nsMemory::Free((void*)piid); + return rc; +} + +static PyObject *PyGetTypeForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi, dim; + if (!PyArg_ParseTuple(args, "hhh:GetTypeForParam", &mi, &pi, &dim)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + nsXPTType datumType; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsresult n = pii->GetTypeForParam(mi, ¶m_info, dim, &datumType); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return PyObject_FromXPTType(&datumType); +} + +static PyObject *PyGetSizeIsArgNumberForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi, dim; + if (!PyArg_ParseTuple(args, "hhh:GetSizeIsArgNumberForParam", &mi, &pi, &dim)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + PRUint8 ret; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsresult n = pii->GetSizeIsArgNumberForParam(mi, ¶m_info, dim, &ret); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return PyInt_FromLong(ret); +} + +static PyObject *PyGetLengthIsArgNumberForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi, dim; + if (!PyArg_ParseTuple(args, "hhh:GetLengthIsArgNumberForParam", &mi, &pi, &dim)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + PRUint8 ret; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsresult n = pii->GetLengthIsArgNumberForParam(mi, ¶m_info, dim, &ret); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return PyInt_FromLong(ret); +} + +static PyObject *PyGetInterfaceIsArgNumberForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi; + if (!PyArg_ParseTuple(args, "hhh:GetInterfaceIsArgNumberForParam", &mi, &pi)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + PRUint8 ret; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsresult n = pii->GetInterfaceIsArgNumberForParam(mi, ¶m_info, &ret); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return PyInt_FromLong(ret); +} + +struct PyMethodDef +PyMethods_IInterfaceInfo[] = +{ + { "GetName", PyGetName, 1}, + { "GetIID", PyGetIID, 1}, + { "IsScriptable", PyIsScriptable, 1}, + { "GetParent", PyGetParent, 1}, + { "GetMethodCount", PyGetMethodCount, 1}, + { "GetConstantCount", PyGetConstantCount, 1}, + { "GetMethodInfo", PyGetMethodInfo, 1}, + { "GetMethodInfoForName", PyGetMethodInfoForName, 1}, + { "GetConstant", PyGetConstant, 1}, + { "GetInfoForParam", PyGetInfoForParam, 1}, + { "GetIIDForParam", PyGetIIDForParam, 1}, + { "GetTypeForParam", PyGetTypeForParam, 1}, + { "GetSizeIsArgNumberForParam", PyGetSizeIsArgNumberForParam, 1}, + { "GetLengthIsArgNumberForParam", PyGetLengthIsArgNumberForParam, 1}, + { "GetInterfaceIsArgNumberForParam", PyGetInterfaceIsArgNumberForParam, 1}, + {NULL} +}; + +/* + NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info) = 0; + NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info) = 0; + NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant) = 0; + NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) = 0; + NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) = 0; + NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval) = 0; + NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) = 0; + NS_IMETHOD GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) = 0; + NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval) = 0; + +*/ diff --git a/src/libs/xpcom18a4/python/src/PyIInterfaceInfoManager.cpp b/src/libs/xpcom18a4/python/src/PyIInterfaceInfoManager.cpp new file mode 100644 index 00000000..7c629413 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIInterfaceInfoManager.cpp @@ -0,0 +1,206 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +static nsIInterfaceInfoManager *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIInterfaceInfoManager); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIInterfaceInfoManager *)Py_nsISupports::GetI(self); +} + +static PyObject *PyGetInfoForIID(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "O", &obIID)) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr pi; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInfoForIID(&iid, getter_AddRefs(pi)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + nsIID new_iid = NS_GET_IID(nsIInterfaceInfo); + // Can not auto-wrap the interface info manager as it is critical to + // building the support we need for autowrap. + return Py_nsISupports::PyObjectFromInterface(pi, new_iid, PR_FALSE); +} + +static PyObject *PyGetInfoForName(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsCOMPtr pi; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInfoForName(name, getter_AddRefs(pi)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + // Can not auto-wrap the interface info manager as it is critical to + // building the support we need for autowrap. + return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsIInterfaceInfo), PR_FALSE); +} + +static PyObject *PyGetNameForIID(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "O", &obIID)) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + char *ret_name = NULL; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetNameForIID(&iid, &ret_name); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + +#if PY_MAJOR_VERSION <= 2 + PyObject *ret = PyString_FromString(ret_name); +#else + PyObject *ret = PyUnicode_FromString(ret_name); +#endif + nsMemory::Free(ret_name); + return ret; +} + +static PyObject *PyGetIIDForName(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID *iid_ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetIIDForName(name, &iid_ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + PyObject *ret = Py_nsIID::PyObjectFromIID(*iid_ret); + nsMemory::Free(iid_ret); + return ret; +} + +static PyObject *PyEnumerateInterfaces(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsCOMPtr pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->EnumerateInterfaces(getter_AddRefs(pRet)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator)); +} + +// TODO: +// void autoRegisterInterfaces(); + +PyMethodDef +PyMethods_IInterfaceInfoManager[] = +{ + { "GetInfoForIID", PyGetInfoForIID, 1}, + { "getInfoForIID", PyGetInfoForIID, 1}, + { "GetInfoForName", PyGetInfoForName, 1}, + { "getInfoForName", PyGetInfoForName, 1}, + { "GetIIDForName", PyGetIIDForName, 1}, + { "getIIDForName", PyGetIIDForName, 1}, + { "GetNameForIID", PyGetNameForIID, 1}, + { "getNameForIID", PyGetNameForIID, 1}, + { "EnumerateInterfaces", PyEnumerateInterfaces, 1}, + { "enumerateInterfaces", PyEnumerateInterfaces, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyISimpleEnumerator.cpp b/src/libs/xpcom18a4/python/src/PyISimpleEnumerator.cpp new file mode 100644 index 00000000..b94d8eb2 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyISimpleEnumerator.cpp @@ -0,0 +1,202 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +static nsISimpleEnumerator *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsISimpleEnumerator); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsISimpleEnumerator *)Py_nsISupports::GetI(self); +} + + +static PyObject *PyHasMoreElements(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":HasMoreElements")) + return NULL; + + nsISimpleEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsresult r; + PRBool more; + Py_BEGIN_ALLOW_THREADS; + r = pI->HasMoreElements(&more); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(more); +} + +static PyObject *PyGetNext(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "|O:GetNext", &obIID)) + return NULL; + + nsIID iid(NS_GET_IID(nsISupports)); + if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsISimpleEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsISupports *pRet = nsnull; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetNext(&pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + if (obIID) { + nsISupports *temp; + Py_BEGIN_ALLOW_THREADS; + r = pRet->QueryInterface(iid, (void **)&temp); + pRet->Release(); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) { + return PyXPCOM_BuildPyException(r); + } + pRet = temp; + } + PyObject *ret = Py_nsISupports::PyObjectFromInterface(pRet, iid); + NS_IF_RELEASE(pRet); + return ret; +} + +// A method added for Python performance if you really need +// it. Allows you to fetch a block of objects in one +// hit, allowing the loop to remain implemented in C. +static PyObject *PyFetchBlock(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + int n_wanted; + int n_fetched = 0; + if (!PyArg_ParseTuple(args, "i|O:FetchBlock", &n_wanted, &obIID)) + return NULL; + + nsIID iid(NS_GET_IID(nsISupports)); + if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsISimpleEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + // We want to fetch with the thread-lock released, + // but this means we can not append to the PyList + nsISupports **fetched = new nsISupports*[n_wanted]; + if (fetched==nsnull) { + PyErr_NoMemory(); + return NULL; + } + memset(fetched, 0, sizeof(nsISupports *) * n_wanted); + nsresult r = NS_OK; + PRBool more; + Py_BEGIN_ALLOW_THREADS; + for (;n_fetchedHasMoreElements(&more); + if (NS_FAILED(r)) + break; // this _is_ an error! + if (!more) + break; // Normal enum end. + nsISupports *pNew; + r = pI->GetNext(&pNew); + if (NS_FAILED(r)) // IS an error + break; + if (obIID) { + nsISupports *temp; + r = pNew->QueryInterface(iid, (void **)&temp); + pNew->Release(); + if ( NS_FAILED(r) ) { + break; + } + pNew = temp; + } + fetched[n_fetched] = pNew; + n_fetched++; + } + Py_END_ALLOW_THREADS; + PyObject *ret; + if (NS_SUCCEEDED(r)) { + ret = PyList_New(n_fetched); + if (ret) + for (int i=0;iRelease(); + + } + delete [] fetched; + return ret; +} + + +struct PyMethodDef +PyMethods_ISimpleEnumerator[] = +{ + { "HasMoreElements", PyHasMoreElements, 1}, + { "hasMoreElements", PyHasMoreElements, 1}, + { "GetNext", PyGetNext, 1}, + { "getNext", PyGetNext, 1}, + { "FetchBlock", PyFetchBlock, 1}, + { "fetchBlock", PyFetchBlock, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyISupports.cpp b/src/libs/xpcom18a4/python/src/PyISupports.cpp new file mode 100644 index 00000000..84504038 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyISupports.cpp @@ -0,0 +1,621 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsISupportsPrimitives.h" + +static PRInt32 cInterfaces=0; +static PyObject *g_obFuncMakeInterfaceCount = NULL; // XXX - never released!!! + +#ifdef VBOX_DEBUG_LIFETIMES +# include +# include + +/*static*/ RTLISTNODE Py_nsISupports::g_List; +/*static*/ RTONCE Py_nsISupports::g_Once = RTONCE_INITIALIZER; +/*static*/ RTCRITSECT Py_nsISupports::g_CritSect; + +/*static*/ DECLCALLBACK(int32_t) +Py_nsISupports::initOnceCallback(void *pvUser1) +{ + NOREF(pvUser1); + RTListInit(&g_List); + return RTCritSectInit(&g_CritSect); +} + +/*static*/ void +Py_nsISupports::dumpList(void) +{ + RTOnce(&g_Once, initOnceCallback, NULL); + RTCritSectEnter(&g_CritSect); + + uint32_t i = 0; + Py_nsISupports *pCur; + RTListForEach(&g_List, pCur, Py_nsISupports, m_ListEntry) + { + nsISupports *pISup = pCur->m_obj; + PyXPCOM_LogWarning("#%u: %p iid=%RTuuid obj=%p", i, pCur, &pCur->m_iid, pISup); + i++; + } + + RTCritSectLeave(&g_CritSect); +} + +/*static*/ void +Py_nsISupports::dumpListToStdOut() +{ + RTOnce(&g_Once, initOnceCallback, NULL); + RTCritSectEnter(&g_CritSect); + + uint32_t i = 0; + Py_nsISupports *pCur; + RTListForEach(&g_List, pCur, Py_nsISupports, m_ListEntry) + { + nsISupports *pISup = pCur->m_obj; + RTPrintf("#%u: %p iid=%RTuuid obj=%p\n", i, pCur, &pCur->m_iid, pISup); + i++; + } + + RTCritSectLeave(&g_CritSect); +} + +PRInt32 +_PyXPCOM_DumpInterfaces(void) +{ + Py_nsISupports::dumpListToStdOut(); + return NS_OK; +} + +#endif /* _DEBUG_LIFETIMES */ + + + +PyObject *PyObject_FromNSInterface( nsISupports *aInterface, + const nsIID &iid, + PRBool bMakeNicePyObject /*= PR_TRUE */) +{ + return Py_nsISupports::PyObjectFromInterface(aInterface, iid, + bMakeNicePyObject); +} + +PRInt32 +_PyXPCOM_GetInterfaceCount(void) +{ + return cInterfaces; +} + +#ifndef Py_LIMITED_API +Py_nsISupports::Py_nsISupports(nsISupports *punk, const nsIID &iid, PyTypeObject *this_type) +#else +Py_nsISupports::Py_nsISupports(nsISupports *punk, const nsIID &iid, PyXPCOM_TypeObject *this_type) +#endif +{ +#ifndef Py_LIMITED_API + ob_type = this_type; +#else + ob_type = this_type->m_pTypeObj; + m_pMyTypeObj = this_type; +#endif + m_obj = punk; + m_iid = iid; + // refcnt of object managed by caller. + PR_AtomicIncrement(&cInterfaces); + PyXPCOM_DLLAddRef(); +#if 1 /* VBox: Must use for 3.9+, includes _Py_NewReferences. Works for all older versions too. @bugref{10079} */ + PyObject_Init(this, ob_type); +#else + _Py_NewReference(this); +#endif + +#ifdef VBOX_DEBUG_LIFETIMES + RTOnce(&g_Once, initOnceCallback, NULL); + RTCritSectEnter(&g_CritSect); + RTListAppend(&g_List, &m_ListEntry); + RTCritSectLeave(&g_CritSect); + PyXPCOM_LogWarning("Creating %p: iid=%RTuuid obj=%p", this, &m_iid, punk); +#endif +} + +Py_nsISupports::~Py_nsISupports() +{ +#ifdef VBOX_DEBUG_LIFETIMES + RTCritSectEnter(&g_CritSect); + nsISupports *punk = m_obj; + RTListNodeRemove(&m_ListEntry); + RTCritSectLeave(&g_CritSect); + PyXPCOM_LogWarning("Destroying %p: iid=%RTuuid obj=%p", this, &m_iid, punk); +#endif + + SafeRelease(this); + PR_AtomicDecrement(&cInterfaces); + PyXPCOM_DLLRelease(); +} + +/*static*/ nsISupports * +Py_nsISupports::GetI(PyObject *self, nsIID *ret_iid) +{ + if (self==NULL) { + PyErr_SetString(PyExc_ValueError, "The Python object is invalid"); + return NULL; + } + Py_nsISupports *pis = (Py_nsISupports *)self; + if (pis->m_obj==NULL) { + // This should never be able to happen. + PyErr_SetString(PyExc_ValueError, "Internal Error - The XPCOM object has been released."); + return NULL; + } + if (ret_iid) + *ret_iid = pis->m_iid; + return pis->m_obj; +} + +/*static*/ void +Py_nsISupports::SafeRelease(Py_nsISupports *ob) +{ + if (!ob) + return; + if (ob->m_obj) + { + Py_BEGIN_ALLOW_THREADS; + ob->m_obj = nsnull; + Py_END_ALLOW_THREADS; + } +} + +/* virtual */ PyObject * +Py_nsISupports::getattr(const char *name) +{ + if (strcmp(name, "IID")==0) + return Py_nsIID::PyObjectFromIID( m_iid ); + + // Support for __unicode__ until we get a tp_unicode slot. + if (strcmp(name, "__unicode__")==0) { + nsresult rv; + PRUnichar *val = NULL; + Py_BEGIN_ALLOW_THREADS; + { // scope to kill pointer while thread-lock released. + nsCOMPtr ss( do_QueryInterface(m_obj, &rv )); + if (NS_SUCCEEDED(rv)) + rv = ss->ToString(&val); + } // end-scope + Py_END_ALLOW_THREADS; + PyObject *ret = NS_FAILED(rv) ? + PyXPCOM_BuildPyException(rv) : + PyObject_FromNSString(val); + if (val) nsMemory::Free(val); + return ret; + } +#ifndef Py_LIMITED_API + PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)ob_type; +#else + PyXPCOM_TypeObject *this_type = m_pMyTypeObj; +#endif +#if PY_MAJOR_VERSION <= 2 + return Py_FindMethodInChain(&this_type->chain, this, (char *)name); +#else + PyMethodChain *chain = &this_type->chain; + if (name[0] == '_' && name[1] == '_') { +# ifndef Py_LIMITED_API /** @todo ? */ + if (!strcmp(name, "__doc__")) { + const char *doc = ob_type->tp_doc; + if (doc) + return PyUnicode_FromString(doc); + } +# endif + } + while (chain) { + PyMethodDef *ml = chain->methods; + for (; ml->ml_name; ml++) { + if (!strcmp(name, ml->ml_name)) + return PyCFunction_New(ml, this); + } + chain = chain->link; + } + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +#endif +} + +/* virtual */ int +Py_nsISupports::setattr(const char *name, PyObject *v) +{ + char buf[128]; +#ifdef VBOX + snprintf(buf, sizeof(buf), "%s has read-only attributes", PyXPCOM_ObTypeName(this) ); +#else + sprintf(buf, "%s has read-only attributes", PyXPCOM_ObTypeName(this) ); +#endif + PyErr_SetString(PyExc_TypeError, buf); + return -1; +} + +/*static*/ Py_nsISupports * +Py_nsISupports::Constructor(nsISupports *pInitObj, const nsIID &iid) +{ + return new Py_nsISupports(pInitObj, + iid, + type); +} + +PRBool +Py_nsISupports::InterfaceFromPyISupports(PyObject *ob, + const nsIID &iid, + nsISupports **ppv) +{ + nsISupports *pis; + PRBool rc = PR_FALSE; + if ( !Check(ob) ) + { + PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be used as COM objects", PyXPCOM_ObTypeName(ob)); + goto done; + } + nsIID already_iid; + pis = GetI(ob, &already_iid); + if ( !pis ) + goto done; /* exception was set by GetI() */ + /* note: we don't (yet) explicitly hold a reference to pis */ + if (iid.Equals(Py_nsIID_NULL)) { + // a bit of a hack - we are asking for the arbitary interface + // wrapped by this object, not some other specific interface - + // so no QI, just an AddRef(); + Py_BEGIN_ALLOW_THREADS + pis->AddRef(); + Py_END_ALLOW_THREADS + *ppv = pis; + } else { + // specific interface requested - if it is not already the + // specific interface, QI for it and discard pis. + if (iid.Equals(already_iid)) { + *ppv = pis; + pis->AddRef(); + } else { + nsresult r; + Py_BEGIN_ALLOW_THREADS + r = pis->QueryInterface(iid, (void **)ppv); + Py_END_ALLOW_THREADS + if ( NS_FAILED(r) ) + { + PyXPCOM_BuildPyException(r); + goto done; + } + /* note: the QI added a ref for the return value */ + } + } + rc = PR_TRUE; +done: + return rc; +} + +PRBool +Py_nsISupports::InterfaceFromPyObject(PyObject *ob, + const nsIID &iid, + nsISupports **ppv, + PRBool bNoneOK, + PRBool bTryAutoWrap /* = PR_TRUE */) +{ + if ( ob == NULL ) + { + // don't overwrite an error message + if ( !PyErr_Occurred() ) + PyErr_SetString(PyExc_TypeError, "The Python object is invalid"); + return PR_FALSE; + } + if ( ob == Py_None ) + { + if ( bNoneOK ) + { + *ppv = NULL; + return PR_TRUE; + } + else + { + PyErr_SetString(PyExc_TypeError, "None is not a invalid interface object in this context"); + return PR_FALSE; + } + } + + // support nsIVariant + if (iid.Equals(NS_GET_IID(nsIVariant)) || iid.Equals(NS_GET_IID(nsIWritableVariant))) { + // Check it is not already nsIVariant + if (PyObject_HasAttrString(ob, "__class__")) { + PyObject *sub_ob = PyObject_GetAttrString(ob, "_comobj_"); + if (sub_ob==NULL) { + PyErr_Clear(); + } else { + if (InterfaceFromPyISupports(sub_ob, iid, ppv)) { + Py_DECREF(sub_ob); + return PR_TRUE; + } + PyErr_Clear(); + Py_DECREF(sub_ob); + } + } + nsresult nr = PyObject_AsVariant(ob, (nsIVariant **)ppv); + if (NS_FAILED(nr)) { + PyXPCOM_BuildPyException(nr); + return PR_FALSE; + } + NS_ASSERTION(ppv != nsnull, "PyObject_AsVariant worked but gave null!"); + return PR_TRUE; + } + // end of variant support. + + if (PyObject_HasAttrString(ob, "__class__")) { + // Get the _comobj_ attribute + PyObject *use_ob = PyObject_GetAttrString(ob, "_comobj_"); + if (use_ob==NULL) { + PyErr_Clear(); + if (bTryAutoWrap) + // Try and auto-wrap it - errors will leave Py exception set, + return PyXPCOM_XPTStub::AutoWrapPythonInstance(ob, iid, ppv); + PyErr_SetString(PyExc_TypeError, "The Python instance can not be converted to an XPCOM object"); + return PR_FALSE; + } else + ob = use_ob; + + } else { + Py_INCREF(ob); + } + PRBool rc = InterfaceFromPyISupports(ob, iid, ppv); + Py_DECREF(ob); + return rc; +} + + +// Interface conversions +/*static*/void +#ifndef Py_LIMITED_API +Py_nsISupports::RegisterInterface( const nsIID &iid, PyTypeObject *t) +#else +Py_nsISupports::RegisterInterface( const nsIID &iid, PyXPCOM_TypeObject *t) +#endif +{ + if (mapIIDToType==NULL) + mapIIDToType = PyDict_New(); + + if (mapIIDToType) { + PyObject *key = Py_nsIID::PyObjectFromIID(iid); + if (key) + PyDict_SetItem(mapIIDToType, key, (PyObject *)t); + Py_XDECREF(key); + } +} + +/*static */PyObject * +Py_nsISupports::PyObjectFromInterface(nsISupports *pis, + const nsIID &riid, + PRBool bMakeNicePyObject, /* = PR_TRUE */ + PRBool bIsInternalCall /* = PR_FALSE */) +{ + // Quick exit. + if (pis==NULL) { + Py_INCREF(Py_None); + return Py_None; + } + + if (!bIsInternalCall) { +#ifdef NS_DEBUG + nsISupports *queryResult = nsnull; + Py_BEGIN_ALLOW_THREADS; + pis->QueryInterface(riid, (void **)&queryResult); + Py_END_ALLOW_THREADS; + NS_ASSERTION(queryResult == pis, "QueryInterface needed"); + NS_IF_RELEASE(queryResult); +#endif + } + +#ifndef Py_LIMITED_API + PyTypeObject *createType = NULL; +#else + PyXPCOM_TypeObject *createType = NULL; +#endif + // If the IID is for nsISupports, dont bother with + // a map lookup as we know the type! + if (!riid.Equals(NS_GET_IID(nsISupports))) { + // Look up the map + PyObject *obiid = Py_nsIID::PyObjectFromIID(riid); + if (!obiid) return NULL; + + if (mapIIDToType != NULL) +#ifndef Py_LIMITED_API + createType = (PyTypeObject *)PyDict_GetItem(mapIIDToType, obiid); +#else + createType = (PyXPCOM_TypeObject *)PyDict_GetItem(mapIIDToType, obiid); +#endif + Py_DECREF(obiid); + } + if (createType==NULL) + createType = Py_nsISupports::type; +#ifndef Py_LIMITED_API + // Check it is indeed one of our types. + if (!PyXPCOM_TypeObject::IsType(createType)) { + PyErr_SetString(PyExc_RuntimeError, "The type map is invalid"); + return NULL; + } + // we can now safely cast the thing to a PyComTypeObject and use it + PyXPCOM_TypeObject *myCreateType = (PyXPCOM_TypeObject *)createType; +#else /* Since the mapIIDToType is only updated by us, there should be no need for the above. */ + PyXPCOM_TypeObject * const myCreateType = createType; +#endif + if (myCreateType->ctor==NULL) { + PyErr_SetString(PyExc_TypeError, "The type does not declare a PyCom constructor"); + return NULL; + } + + Py_nsISupports *ret = (*myCreateType->ctor)(pis, riid); +#ifdef _DEBUG_LIFETIMES + PyXPCOM_LogF("XPCOM Object created at 0x%0xld, nsISupports at 0x%0xld", + ret, ret->m_obj); +#endif + if (ret && bMakeNicePyObject) + return MakeDefaultWrapper(ret, riid); + return ret; +} + +// Call back into Python, passing a raw nsIInterface object, getting back +// the object to actually pass to Python. +PyObject * +Py_nsISupports::MakeDefaultWrapper(PyObject *pyis, + const nsIID &iid) +{ + NS_PRECONDITION(pyis, "NULL pyobject!"); + PyObject *obIID = NULL; + PyObject *args = NULL; + PyObject *mod = NULL; + PyObject *ret = NULL; + + obIID = Py_nsIID::PyObjectFromIID(iid); + if (obIID==NULL) + goto done; + + if (g_obFuncMakeInterfaceCount==NULL) { + PyObject *mod = PyImport_ImportModule("xpcom.client"); + if (mod) + g_obFuncMakeInterfaceCount = PyObject_GetAttrString(mod, "MakeInterfaceResult"); + Py_XDECREF(mod); + } + if (g_obFuncMakeInterfaceCount==NULL) goto done; + + args = Py_BuildValue("OO", pyis, obIID); + if (args==NULL) goto done; + ret = PyEval_CallObject(g_obFuncMakeInterfaceCount, args); +done: + if (PyErr_Occurred()) { + NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!"); + PyXPCOM_LogError("Creating an interface object to be used as a result failed\n"); + PyErr_Clear(); + } + Py_XDECREF(mod); + Py_XDECREF(args); + Py_XDECREF(obIID); + if (ret==NULL) // eek - error - return the original with no refcount mod. + ret = pyis; + else + // no error - decref the old object + Py_DECREF(pyis); + // return our obISupports. If NULL, we are really hosed and nothing we can do. + return ret; +} + +// @pymethod |Py_nsISupports|QueryInterface|Queries an object for a specific interface. +PyObject * +Py_nsISupports::QueryInterface(PyObject *self, PyObject *args) +{ + PyObject *obiid; + int bWrap = 1; + // @pyparm IID|iid||The IID requested. + // @rdesc The result is always a object. + // Any error (including E_NOINTERFACE) will generate a exception. + if (!PyArg_ParseTuple(args, "O|i:QueryInterface", &obiid, &bWrap)) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obiid, &iid)) + return NULL; + + nsISupports *pMyIS = GetI(self); + if (pMyIS==NULL) return NULL; + + // Optimization, If we already wrap the IID, just return + // ourself. + if (!bWrap && iid.Equals(((Py_nsISupports *)self)->m_iid)) { + Py_INCREF(self); + return self; + } + + nsCOMPtr pis; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pMyIS->QueryInterface(iid, getter_AddRefs(pis)); + Py_END_ALLOW_THREADS; + + /* Note that this failure may include E_NOINTERFACE */ + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + return ((Py_nsISupports *)self)->MakeInterfaceResult(pis, iid, (PRBool)bWrap); +} + + +#ifdef VBOX +static PyObject * +QueryErrorObject(PyObject *self, PyObject *args) +{ + nsresult rc = 0; + + if (!PyArg_ParseTuple(args, "i", &rc)) + return NULL; + + return PyXPCOM_BuildErrorMessage(rc); +} +#endif + +// @object Py_nsISupports|The base object for all PythonCOM objects. Wraps a COM nsISupports interface. +/*static*/ struct PyMethodDef +Py_nsISupports::methods[] = +{ + { "queryInterface", Py_nsISupports::QueryInterface, 1, "Queries the object for an interface."}, + { "QueryInterface", Py_nsISupports::QueryInterface, 1, "An alias for queryInterface."}, +#ifdef VBOX + { "QueryErrorObject", QueryErrorObject, 1, "Query an error object for given status code."}, +#endif + {NULL} +}; + +/*static*/void Py_nsISupports::InitType(void) +{ + type = new PyXPCOM_TypeObject( + "nsISupports", + NULL, + sizeof(Py_nsISupports), + methods, + Constructor); +} + +PyXPCOM_TypeObject *Py_nsISupports::type = NULL; +PyObject *Py_nsISupports::mapIIDToType = NULL; diff --git a/src/libs/xpcom18a4/python/src/PyIVariant.cpp b/src/libs/xpcom18a4/python/src/PyIVariant.cpp new file mode 100644 index 00000000..cd9f79c4 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIVariant.cpp @@ -0,0 +1,231 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * Mark Hammond. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// This code is part of the XPCOM extensions for Python. +// +// Written April 2002 + +#include "PyXPCOM_std.h" +#include "nsIVariant.h" + +// Prevents us needing to use an nsIScriptableInputStream +// (and even that can't read binary data!!!) + +static nsIVariant *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIVariant); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIVariant *)Py_nsISupports::GetI(self); +} + +static PyObject *MyBool( PRBool v) { + PyObject *ret = v ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} +static PyObject *MyChar( char c) { +#if PY_MAJOR_VERSION <= 2 + return PyString_FromStringAndSize(&c, 1); +#else + return PyUnicode_FromStringAndSize(&c, 1); +#endif +} +static PyObject *MyUChar( PRUnichar c) { + return PyObject_FromNSString( &c, 1); +} +static PyObject *MyUnicode( PRUnichar *p) { + return PyObject_FromNSString(p); +} + +#define GET_SIMPLE(Type, FuncGet, FuncConvert) \ +static PyObject *FuncGet(PyObject *self, PyObject *args) { \ + nsIVariant *pI = GetI(self); \ + if (pI==NULL) return NULL; \ + if (!PyArg_ParseTuple(args, ":" #FuncGet)) return NULL; \ + Type t; \ + nsresult nr = pI->FuncGet(&t); \ + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); \ + return FuncConvert(t); \ +} + +#define GET_ALLOCATED(Type, FuncGet, FuncConvert, FuncFree) \ +static PyObject *FuncGet(PyObject *self, PyObject *args) { \ + nsIVariant *pI = GetI(self); \ + if (pI==NULL) return NULL; \ + if (!PyArg_ParseTuple(args, ":" #FuncGet)) return NULL; \ + Type t; \ + nsresult nr = pI->FuncGet(&t); \ + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); \ + PyObject *ret = FuncConvert(t); \ + FuncFree(t); \ + return ret; \ +} + +#define GET_ALLOCATED_SIZE(Type, FuncGet, FuncConvert, FuncFree) \ +static PyObject *FuncGet(PyObject *self, PyObject *args) { \ + nsIVariant *pI = GetI(self); \ + if (pI==NULL) return NULL; \ + if (!PyArg_ParseTuple(args, ":" #FuncGet)) return NULL; \ + Type t; PRUint32 size; \ + nsresult nr = pI->FuncGet(&size, &t); \ + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); \ + PyObject *ret = FuncConvert(t, size); \ + FuncFree(t); \ + return ret; \ +} + +GET_SIMPLE(PRUint8, GetAsInt8, PyInt_FromLong) +GET_SIMPLE(PRUint8, GetAsUint8, PyInt_FromLong) +GET_SIMPLE(PRInt16, GetAsInt16, PyInt_FromLong) +GET_SIMPLE(PRUint16, GetAsUint16, PyInt_FromLong) +GET_SIMPLE(PRInt32, GetAsInt32, PyInt_FromLong) +GET_SIMPLE(PRUint32, GetAsUint32, PyInt_FromLong) +GET_SIMPLE(PRInt64, GetAsInt64, PyLong_FromLongLong) +GET_SIMPLE(PRUint64, GetAsUint64, PyLong_FromUnsignedLongLong) +GET_SIMPLE(float, GetAsFloat, PyFloat_FromDouble) +GET_SIMPLE(double, GetAsDouble, PyFloat_FromDouble) +GET_SIMPLE(PRBool, GetAsBool, MyBool) +GET_SIMPLE(char, GetAsChar, MyChar) +GET_SIMPLE(PRUnichar, GetAsWChar, MyUChar) +GET_SIMPLE(nsIID, GetAsID, Py_nsIID::PyObjectFromIID) + +#if PY_MAJOR_VERSION <= 2 +GET_ALLOCATED(char *, GetAsString, PyString_FromString, nsMemory::Free) +#else +GET_ALLOCATED(char *, GetAsString, PyUnicode_FromString, nsMemory::Free) +#endif +GET_ALLOCATED(PRUnichar *, GetAsWString, MyUnicode, nsMemory::Free) +#if PY_MAJOR_VERSION <= 2 +GET_ALLOCATED_SIZE(char *, GetAsStringWithSize, PyString_FromStringAndSize, nsMemory::Free) +#else +GET_ALLOCATED_SIZE(char *, GetAsStringWithSize, PyUnicode_FromStringAndSize, nsMemory::Free) +#endif +GET_ALLOCATED_SIZE(PRUnichar *, GetAsWStringWithSize, PyObject_FromNSString, nsMemory::Free) + +static PyObject *GetAsInterface(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":GetAsInterface")) return NULL; + nsCOMPtr p; + nsIID *iid; + nsresult nr = pI->GetAsInterface(&iid, getter_AddRefs(p)); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + return Py_nsISupports::PyObjectFromInterface(p, *iid); +} + +static PyObject *GetAsISupports(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":GetAsInterface")) return NULL; + nsCOMPtr p; + nsIID *iid; + nsresult nr = pI->GetAsInterface(&iid, getter_AddRefs(p)); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + return Py_nsISupports::PyObjectFromInterface(p, *iid); +} + +extern PyObject *PyObject_FromVariantArray( Py_nsISupports*, nsIVariant *v); + +static PyObject *GetAsArray(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":GetAsArray")) return NULL; + return PyObject_FromVariantArray((Py_nsISupports *)self, pI); +} + +static PyObject *Get(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":Get")) return NULL; + return PyObject_FromVariant((Py_nsISupports *)self, pI); +} + +struct PyMethodDef +PyMethods_IVariant[] = +{ + { "getAsInt8", GetAsInt8, 1}, + { "getAsUint8", GetAsUint8, 1}, + { "getAsInt16", GetAsInt16, 1}, + { "getAsUint16", GetAsUint16, 1}, + { "getAsInt32", GetAsInt32, 1}, + { "getAsUint32", GetAsUint32, 1}, + { "getAsInt64", GetAsInt64, 1}, + { "getAsUint64", GetAsUint64, 1}, + { "getAsFloat", GetAsFloat, 1}, + { "getAsDouble", GetAsDouble, 1}, + { "getAsBool", GetAsBool, 1}, + { "getAsChar", GetAsChar, 1}, + { "getAsWChar", GetAsWChar, 1}, + { "getAsString", GetAsString, 1}, + { "getAsWString", GetAsWString, 1}, + { "getAsStringWithSize", GetAsStringWithSize, 1}, + { "getAsWStringWithSize", GetAsWStringWithSize, 1}, + { "getAsISupports", GetAsISupports, 1}, + { "getAsInterface", GetAsInterface, 1}, + { "getAsArray", GetAsArray, 1}, + { "getAsID", GetAsID, 1}, + { "get", Get, 1}, + {NULL} +}; + +PyObject * +Py_nsIVariant::getattr(const char *name) +{ + + PyObject *ret = NULL; + if (strcmp(name, "dataType")==0) { + nsIVariant *pI = ::GetI(this); + if (pI) { + PRUint16 dt; + nsresult nr = pI->GetDataType(&dt); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + ret = PyInt_FromLong(dt); + } + } else { + ret = Py_nsISupports::getattr(name); + } + return ret; +} + +int +Py_nsIVariant::setattr(const char *name, PyObject *v) +{ + return Py_nsISupports::setattr(name, v); +} diff --git a/src/libs/xpcom18a4/python/src/PyXPCOM.h b/src/libs/xpcom18a4/python/src/PyXPCOM.h new file mode 100644 index 00000000..91bc8d12 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyXPCOM.h @@ -0,0 +1,1036 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// PyXPCOM.h - the main header file for the Python XPCOM support. +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#ifndef __PYXPCOM_H__ +#define __PYXPCOM_H__ + +#include "nsIAllocator.h" +#include "nsIWeakReference.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIClassInfo.h" +#include "nsIComponentManager.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIServiceManager.h" +#include "nsIInputStream.h" +#include "nsIVariant.h" +#include "nsIModule.h" + +#include "nsXPIDLString.h" +#include "nsCRT.h" +#include "xptcall.h" +#include "xpt_xdr.h" + +#ifdef VBOX_DEBUG_LIFETIMES +# include +# include +# include +#endif + +#ifdef HAVE_LONG_LONG + // Mozilla also defines this - we undefine it to + // prevent a compiler warning. +# undef HAVE_LONG_LONG +#endif // HAVE_LONG_LONG + +#ifdef _POSIX_C_SOURCE // Ditto here +# undef _POSIX_C_SOURCE +#endif // _POSIX_C_SOURCE + +#ifdef VBOX_PYXPCOM +// unfortunatelly, if SOLARIS is defined Python porting layer +// defines gethostname() in invalid fashion what kills compilation +# ifdef SOLARIS +# undef SOLARIS +# define SOLARIS_WAS_DEFINED +# endif + +// Python.h/pyconfig.h redefines _XOPEN_SOURCE on some hosts +# ifdef _XOPEN_SOURCE +# define VBOX_XOPEN_SOURCE_DEFINED _XOPEN_SOURCE +# undef _XOPEN_SOURCE +# endif + +#endif /* VBOX_PYXPCOM */ + +#include + +#ifdef VBOX_PYXPCOM + +# ifdef SOLARIS_WAS_DEFINED +# define SOLARIS +# undef SOLARIS_WAS_DEFINED +# endif + +// restore the old value of _XOPEN_SOURCE if not defined by Python.h/pyconfig.h +# if !defined(_XOPEN_SOURCE) && defined(VBOX_XOPEN_SOURCE_DEFINED) +# define _XOPEN_SOURCE VBOX_XOPEN_SOURCE_DEFINED +# endif +# undef VBOX_XOPEN_SOURCE_DEFINED + +# if (PY_VERSION_HEX <= 0x02040000) +// although in more recent versions of Python this type is ssize_t, earlier +// it was used as int +typedef int Py_ssize_t; +# endif + +# if (PY_VERSION_HEX <= 0x02030000) +// this one not defined before +inline PyObject *PyBool_FromLong(long ok) +{ + PyObject *result; + if (ok) + result = Py_True; + else + result = Py_False; + Py_INCREF(result); + return result; +} +# endif + +# if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong(l) PyLong_FromLong(l) +# define PyInt_Check(o) PyLong_Check(o) +# define PyInt_AsLong(o) PyLong_AsLong(o) +# define PyNumber_Int(o) PyNumber_Long(o) +# if !defined(Py_LIMITED_API) && PY_VERSION_HEX <= 0x03030000 /* 3.3 added PyUnicode_AsUTF8AndSize */ +# ifndef PyUnicode_AsUTF8 +# define PyUnicode_AsUTF8(o) _PyUnicode_AsString(o) +# endif +# ifndef PyUnicode_AsUTF8AndSize +# define PyUnicode_AsUTF8AndSize(o,s) _PyUnicode_AsStringAndSize(o,s) +# endif +# endif +typedef struct PyMethodChain +{ + PyMethodDef *methods; + struct PyMethodChain *link; +} PyMethodChain; +# endif + +#endif /* VBOX_PYXPCOM */ + +#ifdef BUILD_PYXPCOM + /* We are building the main dll */ +# define PYXPCOM_EXPORT NS_EXPORT +#else + /* This module uses the dll */ +# define PYXPCOM_EXPORT NS_IMPORT +#endif // BUILD_PYXPCOM + +// An IID we treat as NULL when passing as a reference. +extern PYXPCOM_EXPORT nsIID Py_nsIID_NULL; + +class Py_nsISupports; + + +/** @name VBox limited API hacks: + * @{ */ +#ifndef Py_LIMITED_API + +# define PyXPCOM_ObTypeName(obj) (Py_TYPE(obj)->tp_name) + +#else /* Py_LIMITED_API */ + +# if PY_VERSION_HEX <= 0x03030000 +# error "Py_LIMITED_API mode only works for Python 3.3 and higher." +# endif + +const char *PyXPCOMGetObTypeName(PyTypeObject *pTypeObj); +# define PyXPCOM_ObTypeName(obj) PyXPCOMGetObTypeName(Py_TYPE(obj)) + +# if Py_LIMITED_API < 0x030A0000 +/* Note! While we should not technically be using PyUnicode_AsUTF8AndSize, it was + made part of the limited API in 3.10 (see https://bugs.python.org/issue41784 and + https://github.com/python/cpython/commit/a05195ac61f1908ac5990cccb5aa82442bdaf15d). */ +extern "C" PyAPI_FUNC(const char *) PyUnicode_AsUTF8AndSize(PyObject *, Py_ssize_t *); +# endif + +/* PyUnicode_AsUTF8 is just PyUnicode_AsUTF8AndSize without returning a size. */ +# define PyUnicode_AsUTF8(o) PyUnicode_AsUTF8AndSize(o, NULL) + +DECLINLINE(int) PyRun_SimpleString(const char *pszCode) +{ + /* Get the main mode dictionary: */ + PyObject *pMainMod = PyImport_AddModule("__main__"); + if (pMainMod) { + PyObject *pMainModDict = PyModule_GetDict(pMainMod); + + /* Compile and run the code. */ + PyObject *pCodeObject = Py_CompileString(pszCode, "PyXPCOM", Py_file_input); + if (pCodeObject) { + PyObject *pResult = PyEval_EvalCode(pCodeObject, pMainModDict, pMainModDict); + Py_DECREF(pCodeObject); + if (pResult) { + Py_DECREF(pResult); + return 0; + } + PyErr_Print(); + } + } + return -1; +} + +DECLINLINE(PyObject *) PyTuple_GET_ITEM(PyObject *pTuple, Py_ssize_t idx) +{ + return PyTuple_GetItem(pTuple, idx); +} + +DECLINLINE(int) PyTuple_SET_ITEM(PyObject *pTuple, Py_ssize_t idx, PyObject *pItem) +{ + int rc = PyTuple_SetItem(pTuple, idx, pItem); /* Steals pItem ref, just like PyTuple_SET_ITEM. */ + Assert(rc == 0); + return rc; +} + +DECLINLINE(int) PyList_SET_ITEM(PyObject *pList, Py_ssize_t idx, PyObject *pItem) +{ + int rc = PyList_SetItem(pList, idx, pItem); /* Steals pItem ref, just like PyList_SET_ITEM. */ + Assert(rc == 0); + return rc; +} + +DECLINLINE(Py_ssize_t) PyBytes_GET_SIZE(PyObject *pBytes) +{ + return PyBytes_Size(pBytes); +} + +DECLINLINE(const char *) PyBytes_AS_STRING(PyObject *pBytes) +{ + return PyBytes_AsString(pBytes); +} + +DECLINLINE(Py_ssize_t) PyUnicode_GET_SIZE(PyObject *pUnicode) +{ + /* Note! Currently only used for testing for zero or 1 codepoints, so we don't + really need to deal with the different way these two treats surrogate pairs. */ +# if Py_LIMITED_API >= 0x03030000 + return PyUnicode_GetLength(pUnicode); +# else + return PyUnicode_GetSize(pUnicode); +# endif +} + +# define PyObject_CheckBuffer(pAllegedBuffer) PyObject_CheckReadBuffer(pAllegedBuffer) + +# include +DECLINLINE(Py_hash_t) _Py_HashPointer(void *p) +{ + Py_hash_t uHash = (Py_hash_t)RT_CONCAT(ASMRotateRightU,ARCH_BITS)((uintptr_t)p, 4); + return uHash != -1 ? uHash : -2; +} + +#endif /* Py_LIMITED_API */ +/** @} */ + + +/************************************************************************* +************************************************************************** + + Error and exception related function. + +************************************************************************** +*************************************************************************/ + +#define NS_PYXPCOM_NO_SUCH_METHOD \ + NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_PYXPCOM, 0) + +// The exception object (loaded from the xpcom .py code) +extern PYXPCOM_EXPORT PyObject *PyXPCOM_Error; + +// Client related functions - generally called by interfaces before +// they return NULL back to Python to indicate the error. +// All these functions return NULL so interfaces can generally +// just "return PyXPCOM_BuildPyException(hr, punk, IID_IWhatever)" +PYXPCOM_EXPORT PyObject *PyXPCOM_BuildPyException(nsresult res); + +#ifdef VBOX +// Build human readable error message out of XPCOM error +PYXPCOM_EXPORT PyObject *PyXPCOM_BuildErrorMessage(nsresult r); +#endif + +// Used in gateways to handle the current Python exception +// NOTE: this function assumes it is operating within the Python context +PYXPCOM_EXPORT nsresult PyXPCOM_SetCOMErrorFromPyException(); + +// Write current exception and traceback to a string. +PYXPCOM_EXPORT PRBool PyXPCOM_FormatCurrentException(nsCString &streamout); +// Write specified exception and traceback to a string. +PYXPCOM_EXPORT PRBool PyXPCOM_FormatGivenException(nsCString &streamout, + PyObject *exc_typ, PyObject *exc_val, + PyObject *exc_tb); + +// A couple of logging/error functions. These probably end up +// being written to the console service. + +// Log a warning for the user - something at runtime +// they may care about, but nothing that prevents us actually +// working. +// As it's designed for user error/warning, it exists in non-debug builds. +PYXPCOM_EXPORT void PyXPCOM_LogWarning(const char *fmt, ...); + +// Log an error for the user - something that _has_ prevented +// us working. This is probably accompanied by a traceback. +// As it's designed for user error/warning, it exists in non-debug builds. +PYXPCOM_EXPORT void PyXPCOM_LogError(const char *fmt, ...); + +// The raw one +PYXPCOM_EXPORT void PyXPCOM_Log(const char *level, const nsCString &msg); + +#ifdef DEBUG +// Mainly designed for developers of the XPCOM package. +// Only enabled in debug builds. +PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...); +#define PYXPCOM_LOG_DEBUG PyXPCOM_LogDebug +#else +#define PYXPCOM_LOG_DEBUG() +#endif // DEBUG + +// Some utility converters +// moz strings to PyObject. +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsACString &s, + PRBool bAssumeUTF8 = PR_FALSE ); +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsAString &s ); +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const PRUnichar *s, + PRUint32 len = (PRUint32)-1); + +// PyObjects to moz strings. As per the moz string guide, we pass a reference +// to an abstract string +PYXPCOM_EXPORT PRBool PyObject_AsNSString( PyObject *ob, nsAString &aStr); + +// Variants. +PYXPCOM_EXPORT nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet); +PYXPCOM_EXPORT PyObject *PyObject_FromVariant( Py_nsISupports *parent, + nsIVariant *v); + +// Interfaces - these are the "official" functions +PYXPCOM_EXPORT PyObject *PyObject_FromNSInterface( nsISupports *aInterface, + const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE); + +/************************************************************************* +************************************************************************** + + Support for CALLING (ie, using) interfaces. + +************************************************************************** +*************************************************************************/ + +typedef Py_nsISupports* (* PyXPCOM_I_CTOR)(nsISupports *, const nsIID &); + +////////////////////////////////////////////////////////////////////////// +// class PyXPCOM_TypeObject +// Base class for (most of) the type objects. + +#ifndef Py_LIMITED_API +class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyTypeObject { +#else +class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyObject { +#endif +public: + PyXPCOM_TypeObject( + const char *name, + PyXPCOM_TypeObject *pBaseType, + int typeSize, + struct PyMethodDef* methodList, + PyXPCOM_I_CTOR ctor); + ~PyXPCOM_TypeObject(); + + PyMethodChain chain; + PyXPCOM_TypeObject *baseType; + PyXPCOM_I_CTOR ctor; + + static PRBool IsType(PyTypeObject *t); + // Static methods for the Python type. + static void Py_dealloc(PyObject *ob); + static PyObject *Py_repr(PyObject *ob); + static PyObject *Py_str(PyObject *ob); + static PyObject *Py_getattr(PyObject *self, char *name); + static int Py_setattr(PyObject *op, char *name, PyObject *v); + static int Py_cmp(PyObject *ob1, PyObject *ob2); + static PyObject *Py_richcmp(PyObject *ob1, PyObject *ob2, int op); +#if PY_VERSION_HEX >= 0x03020000 + static Py_hash_t Py_hash(PyObject *self); +#else + static long Py_hash(PyObject *self); +#endif +#ifdef Py_LIMITED_API + PyTypeObject *m_pTypeObj; /**< The python type object we wrap. */ +#endif +}; + +////////////////////////////////////////////////////////////////////////// +// class Py_nsISupports +// This class serves 2 purposes: +// * It is a base class for other interfaces we support "natively" +// * It is instantiated for _all_ other interfaces. +// +// This is different than win32com, where a PyIUnknown only +// ever holds an IUnknown - but here, we could be holding +// _any_ interface. +class PYXPCOM_EXPORT Py_nsISupports : public PyObject +{ +public: + // Check if a Python object can safely be cast to an Py_nsISupports, + // and optionally check that the object is wrapping the specified + // interface. + static PRBool Check( PyObject *ob, const nsIID &checkIID = Py_nsIID_NULL) { + Py_nsISupports *self = static_cast(ob); + if (ob==NULL || !PyXPCOM_TypeObject::IsType(ob->ob_type )) + return PR_FALSE; + if (!checkIID.Equals(Py_nsIID_NULL)) + return self->m_iid.Equals(checkIID) != 0; + return PR_TRUE; + } + // Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED + static nsISupports *GetI(PyObject *self, nsIID *ret_iid = NULL); + nsCOMPtr m_obj; + nsIID m_iid; +#ifdef Py_LIMITED_API + /** Because PyXPCOM_TypeObject cannot inherit from PyTypeObject in + * Py_LIMITED_API mode, we cannot use ob_type to get to the method list. + * Instead of we store it here. */ + PyXPCOM_TypeObject *m_pMyTypeObj; +#endif + + // Given an nsISupports and an Interface ID, create and return an object + // Does not QI the object - the caller must ensure the nsISupports object + // is really a pointer to an object identified by the IID (although + // debug builds should check this) + // PRBool bMakeNicePyObject indicates if we should call back into + // Python to wrap the object. This allows Python code to + // see the correct xpcom.client.Interface object even when calling + // xpcom functions directly from C++. + // NOTE: There used to be a bAddRef param to this as an internal + // optimization, but since removed. This function *always* takes a + // reference to the nsISupports. + static PyObject *PyObjectFromInterface(nsISupports *ps, + const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE, + PRBool bIsInternalCall = PR_FALSE); + + // Given a Python object that is a registered COM type, return a given + // interface pointer on its underlying object, with a NEW REFERENCE ADDED. + // bTryAutoWrap indicates if a Python instance object should attempt to + // be automatically wrapped in an XPCOM object. This is really only + // provided to stop accidental recursion should the object returned by + // the wrap process itself be in instance (where it should already be + // a COM object. + // If |iid|==nsIVariant, then arbitary Python objects will be wrapped + // in an nsIVariant. + static PRBool InterfaceFromPyObject( + PyObject *ob, + const nsIID &iid, + nsISupports **ppret, + PRBool bNoneOK, + PRBool bTryAutoWrap = PR_TRUE); + + // Given a Py_nsISupports, return an interface. + // Object *must* be Py_nsISupports - there is no + // "autowrap", no "None" support, etc + static PRBool InterfaceFromPyISupports(PyObject *ob, + const nsIID &iid, + nsISupports **ppv); + + static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid); + // The Python methods + static PyObject *QueryInterface(PyObject *self, PyObject *args); + + // Internal (sort-of) objects. + static NS_EXPORT_STATIC_MEMBER_(PyXPCOM_TypeObject) *type; + static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[]; + static PyObject *mapIIDToType; + static void SafeRelease(Py_nsISupports *ob); +#ifndef Py_LIMITED_API + static void RegisterInterface( const nsIID &iid, PyTypeObject *t); +#else + static void RegisterInterface( const nsIID &iid, PyXPCOM_TypeObject *t); +#endif + static void InitType(); +#ifdef VBOX_DEBUG_LIFETIMES + static void dumpList(void); + static void dumpListToStdOut(void); +#endif + + virtual ~Py_nsISupports(); + virtual PyObject *getattr(const char *name); + virtual int setattr(const char *name, PyObject *val); + // A virtual function to sub-classes can customize the way + // nsISupports objects are returned from their methods. + // ps is a new object just obtained from some operation performed on us + virtual PyObject *MakeInterfaceResult(nsISupports *ps, const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE) { + return PyObjectFromInterface(ps, iid, bMakeNicePyObject); + } + +protected: + // ctor is protected - must create objects via + // PyObjectFromInterface() + Py_nsISupports(nsISupports *p, + const nsIID &iid, +#ifndef Py_LIMITED_API + PyTypeObject *type); +#else + PyXPCOM_TypeObject *type); +#endif + + // Make a default wrapper for an ISupports (which is an + // xpcom.client.Component instance) + static PyObject *MakeDefaultWrapper(PyObject *pyis, const nsIID &iid); + +#ifdef VBOX_DEBUG_LIFETIMES + static DECLCALLBACK(int32_t) initOnceCallback(void *pvUser1); + + RTLISTNODE m_ListEntry; /**< List entry. */ + + static RTONCE g_Once; /**< Init list and critsect once. */ + static RTCRITSECT g_CritSect; /**< Critsect protecting the list. */ + static RTLISTANCHOR g_List; /**< List of live interfaces.*/ +#endif +}; + +// Python/XPCOM IID support +class PYXPCOM_EXPORT Py_nsIID : public PyObject +{ +public: + Py_nsIID(const nsIID &riid); + nsIID m_iid; + + PRBool + IsEqual(const nsIID &riid) { + return m_iid.Equals(riid); + } + + PRBool + IsEqual(PyObject *ob) { + return ob && +#ifndef Py_LIMITED_API + ob->ob_type== &type && +#else + ob->ob_type == s_pType && +#endif + m_iid.Equals(((Py_nsIID *)ob)->m_iid); + } + + PRBool + IsEqual(Py_nsIID &iid) { + return m_iid.Equals(iid.m_iid); + } + + static PyObject * + PyObjectFromIID(const nsIID &iid) { + return new Py_nsIID(iid); + } + + static PRBool IIDFromPyObject(PyObject *ob, nsIID *pRet); + /* Python support */ + static PyObject *PyTypeMethod_getattr(PyObject *self, char *name); +#if PY_MAJOR_VERSION <= 2 + static int PyTypeMethod_compare(PyObject *self, PyObject *ob); +#endif + static PyObject *PyTypeMethod_richcompare(PyObject *self, PyObject *ob, int op); + static PyObject *PyTypeMethod_repr(PyObject *self); +#if PY_VERSION_HEX >= 0x03020000 + static Py_hash_t PyTypeMethod_hash(PyObject *self); +#else + static long PyTypeMethod_hash(PyObject *self); +#endif + static PyObject *PyTypeMethod_str(PyObject *self); + static void PyTypeMethod_dealloc(PyObject *self); +#ifndef Py_LIMITED_API + static NS_EXPORT_STATIC_MEMBER_(PyTypeObject) type; +#else + static NS_EXPORT_STATIC_MEMBER_(PyTypeObject *) s_pType; + static PyTypeObject *GetTypeObject(void); +#endif + static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[]; +}; + +/////////////////////////////////////////////////////// +// +// Helper classes for managing arrays of variants. +class PythonTypeDescriptor; // Forward declare. + +class PYXPCOM_EXPORT PyXPCOM_InterfaceVariantHelper { +public: + PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent, int methodindex); + ~PyXPCOM_InterfaceVariantHelper(); + PRBool Init(PyObject *obParams); + PRBool FillArray(); + + PyObject *MakePythonResult(); + + nsXPTCVariant *m_var_array; + int m_num_array; + int m_methodindex; +protected: + PyObject *MakeSinglePythonResult(int index); + PRBool FillInVariant(const PythonTypeDescriptor &, int, int); + PRBool PrepareOutVariant(const PythonTypeDescriptor &td, int value_index); + PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size); + PRUint32 GetSizeIs( int var_index, PRBool is_arg1); + + PyObject *m_pyparams; // sequence of actual params passed (ie, not including hidden) + PyObject *m_typedescs; // desc of _all_ params, including hidden. + PythonTypeDescriptor *m_python_type_desc_array; + void **m_buffer_array; + Py_nsISupports *m_parent; + +}; + +/************************************************************************* +************************************************************************** + + Support for IMPLEMENTING interfaces. + +************************************************************************** +*************************************************************************/ +#define NS_IINTERNALPYTHON_IID_STR "AC7459FC-E8AB-4f2e-9C4F-ADDC53393A20" +#define NS_IINTERNALPYTHON_IID \ + { 0xac7459fc, 0xe8ab, 0x4f2e, { 0x9c, 0x4f, 0xad, 0xdc, 0x53, 0x39, 0x3a, 0x20 } } + +class PyXPCOM_GatewayWeakReference; + +// This interface is needed primarily to give us a known vtable base. +// If we QI a Python object for this interface, we can safely cast the result +// to a PyG_Base. Any other interface, we do now know which vtable we will get. +// We also allow the underlying PyObject to be extracted +class nsIInternalPython : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IINTERNALPYTHON_IID) + // Get the underlying Python object with new reference added + virtual PyObject *UnwrapPythonObject(void) = 0; +}; + +// This is roughly equivalent to PyGatewayBase in win32com +// +class PYXPCOM_EXPORT PyG_Base : public nsIInternalPython, public nsISupportsWeakReference +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSWEAKREFERENCE + PyObject *UnwrapPythonObject(void); + + // A static "constructor" - the real ctor is protected. + static nsresult CreateNew(PyObject *pPyInstance, + const nsIID &iid, + void **ppResult); + + // A utility to auto-wrap an arbitary Python instance + // in a COM gateway. + static PRBool AutoWrapPythonInstance(PyObject *ob, + const nsIID &iid, + nsISupports **ppret); + + + // A helper that creates objects to be passed for nsISupports + // objects. See extensive comments in PyG_Base.cpp. + PyObject *MakeInterfaceParam(nsISupports *pis, + const nsIID *piid, + int methodIndex = -1, + const XPTParamDescriptor *d = NULL, + int paramIndex = -1); + + // A helper that ensures all casting and vtable offsetting etc + // done against this object happens in the one spot! + virtual void *ThisAsIID( const nsIID &iid ) = 0; + + // Helpers for "native" interfaces. + // Not used by the generic stub interface. + nsresult HandleNativeGatewayError(const char *szMethodName); + + // These data members used by the converter helper functions - hence public + nsIID m_iid; + PyObject * m_pPyObject; + // We keep a reference count on this object, and the object + // itself uses normal refcount rules - thus, it will only + // die when we die, and all external references are removed. + // This means that once we have created it (and while we + // are alive) it will never die. + nsCOMPtr m_pWeakRef; +#ifdef NS_BUILD_REFCNT_LOGGING + char refcntLogRepr[64]; // sigh - I wish I knew how to use the Moz string classes :( OK for debug only tho. +#endif +protected: + PyG_Base(PyObject *instance, const nsIID &iid); + virtual ~PyG_Base(); + PyG_Base *m_pBaseObject; // A chain to implement identity rules. + nsresult InvokeNativeViaPolicy( const char *szMethodName, + PyObject **ppResult = NULL, + const char *szFormat = NULL, + ... + ); + nsresult InvokeNativeViaPolicyInternal( const char *szMethodName, + PyObject **ppResult, + const char *szFormat, + va_list va); + nsresult InvokeNativeGetViaPolicy(const char *szPropertyName, + PyObject **ppResult = NULL + ); + nsresult InvokeNativeSetViaPolicy(const char *szPropertyName, + ...); +}; + +class PYXPCOM_EXPORT PyXPCOM_XPTStub : public PyG_Base, public nsXPTCStubBase +{ +friend class PyG_Base; +public: + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \ + {return PyG_Base::QueryInterface(aIID, aInstancePtr);} \ + NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();} \ + NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();} \ + + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info); + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant* params); + + virtual void *ThisAsIID(const nsIID &iid); +protected: + PyXPCOM_XPTStub(PyObject *instance, const nsIID &iid) : PyG_Base(instance, iid) {;} +private: +}; + +// For the Gateways we manually implement. +#define PYGATEWAY_BASE_SUPPORT(INTERFACE, GATEWAY_BASE) \ + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \ + {return PyG_Base::QueryInterface(aIID, aInstancePtr);} \ + NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();} \ + NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();} \ + virtual void *ThisAsIID(const nsIID &iid) { \ + if (iid.Equals(NS_GET_IID(INTERFACE))) return (INTERFACE *)this; \ + return GATEWAY_BASE::ThisAsIID(iid); \ + } \ + +extern PYXPCOM_EXPORT void AddDefaultGateway(PyObject *instance, nsISupports *gateway); + +extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_GetGatewayCount(void); +extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_GetInterfaceCount(void); +#ifdef VBOX_DEBUG_LIFETIMES +extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_DumpInterfaces(void); +#endif + + +// Weak Reference class. This is a true COM object, representing +// a weak reference to a Python object. For each Python XPCOM object, +// there is exactly zero or one corresponding weak reference instance. +// When both are alive, each holds a pointer to the other. When the main +// object dies due to XPCOM reference counting, it zaps the pointer +// in its corresponding weak reference object. Thus, the weak-reference +// can live beyond the object (possibly with a NULL pointer back to the +// "real" object, but as implemented, the weak reference will never be +// destroyed before the object +class PYXPCOM_EXPORT PyXPCOM_GatewayWeakReference : public nsIWeakReference { +public: + PyXPCOM_GatewayWeakReference(PyG_Base *base); + virtual ~PyXPCOM_GatewayWeakReference(); + NS_DECL_ISUPPORTS + NS_DECL_NSIWEAKREFERENCE + PyG_Base *m_pBase; // NO REF COUNT!!! +#ifdef NS_BUILD_REFCNT_LOGGING + char refcntLogRepr[41]; +#endif +}; + + +// Helpers classes for our gateways. +class PYXPCOM_EXPORT PyXPCOM_GatewayVariantHelper +{ +public: + PyXPCOM_GatewayVariantHelper( PyG_Base *gateway, + int methodIndex, + const nsXPTMethodInfo *info, + nsXPTCMiniVariant* params ); + ~PyXPCOM_GatewayVariantHelper(); + PyObject *MakePyArgs(); + nsresult ProcessPythonResult(PyObject *ob); + PyG_Base *m_gateway; +private: + nsresult BackFillVariant( PyObject *ob, int index); + PyObject *MakeSingleParam(int index, PythonTypeDescriptor &td); + PRBool GetIIDForINTERFACE_ID(int index, const nsIID **ppret); + nsresult GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **ppiid); + PRUint32 GetSizeIs( int var_index, PRBool is_arg1); + PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size); + PRBool CanSetSizeIs( int var_index, PRBool is_arg1 ); + nsIInterfaceInfo *GetInterfaceInfo(); // NOTE: no ref count on result. + + + nsXPTCMiniVariant* m_params; + const nsXPTMethodInfo *m_info; + int m_method_index; + PythonTypeDescriptor *m_python_type_desc_array; + int m_num_type_descs; + nsCOMPtr m_interface_info; +}; + +// Misc converters. +PyObject *PyObject_FromXPTType( const nsXPTType *d); +// XPTTypeDescriptor derived from XPTType - latter is automatically processed via PyObject_FromXPTTypeDescriptor XPTTypeDescriptor +PyObject *PyObject_FromXPTTypeDescriptor( const XPTTypeDescriptor *d); + +PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d); +PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d); +PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *d); + +// DLL reference counting functions. +// Although we maintain the count, we never actually +// finalize Python when it hits zero! +void PyXPCOM_DLLAddRef(); +void PyXPCOM_DLLRelease(); + +/************************************************************************* +************************************************************************** + + LOCKING AND THREADING + +************************************************************************** +*************************************************************************/ + +// +// We have 2 discrete locks in use (when no free-threaded is used, anyway). +// The first type of lock is the global Python lock. This is the standard lock +// in use by Python, and must be used as documented by Python. Specifically, no +// 2 threads may _ever_ call _any_ Python code (including INCREF/DECREF) without +// first having this thread lock. +// +// The second type of lock is a "global framework lock", and used whenever 2 threads +// of C code need access to global data. This is different than the Python +// lock - this lock is used when no Python code can ever be called by the +// threads, but the C code still needs thread-safety. + +// We also supply helper classes which make the usage of these locks a one-liner. + +// The "framework" lock, implemented as a PRLock +PYXPCOM_EXPORT void PyXPCOM_AcquireGlobalLock(void); +PYXPCOM_EXPORT void PyXPCOM_ReleaseGlobalLock(void); + +// Helper class for the DLL global lock. +// +// This class magically waits for PyXPCOM framework global lock, and releases it +// when finished. +// NEVER new one of these objects - only use on the stack! +class CEnterLeaveXPCOMFramework { +public: + CEnterLeaveXPCOMFramework() {PyXPCOM_AcquireGlobalLock();} + ~CEnterLeaveXPCOMFramework() {PyXPCOM_ReleaseGlobalLock();} +}; + +// Python thread-lock stuff. Free-threading patches use different semantics, but +// these are abstracted away here... +//#include + +// Helper class for Enter/Leave Python +// +// This class magically waits for the Python global lock, and releases it +// when finished. + +// Nested invocations will deadlock, so be careful. + +// NEVER new one of these objects - only use on the stack! + +PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls(); +PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure(); + +// For 2.3, use the PyGILState_ calls +#if (PY_VERSION_HEX >= 0x02030000) +#define PYXPCOM_USE_PYGILSTATE +#endif + +#ifdef PYXPCOM_USE_PYGILSTATE +class CEnterLeavePython { +public: + CEnterLeavePython() { + state = PyGILState_Ensure(); + // See "pending calls" comment below. We reach into the Python + // implementation to see if we are the first call on the stack. +# ifndef Py_LIMITED_API + if (PyThreadState_Get()->gilstate_counter==1) { +# else + if (state == PyGILState_UNLOCKED) { +# endif + PyXPCOM_MakePendingCalls(); + } + } + ~CEnterLeavePython() { + PyGILState_Release(state); + } + PyGILState_STATE state; +}; +#else + +extern PYXPCOM_EXPORT PyInterpreterState *PyXPCOM_InterpreterState; +PYXPCOM_EXPORT PRBool PyXPCOM_ThreadState_Ensure(); +PYXPCOM_EXPORT void PyXPCOM_ThreadState_Free(); +PYXPCOM_EXPORT void PyXPCOM_ThreadState_Clear(); +PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Acquire(); +PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Release(); + +// Pre 2.3 thread-state dances. +class CEnterLeavePython { +public: + CEnterLeavePython() { + created = PyXPCOM_ThreadState_Ensure(); + PyXPCOM_InterpreterLock_Acquire(); + if (created) { + // If pending python calls are waiting as we enter Python, + // it will generally mean an asynch signal handler, etc. + // We can either call it here, or wait for Python to call it + // as part of its "even 'n' opcodes" check. If we wait for + // Python to check it and the pending call raises an exception, + // then it is _our_ code that will fail - this is unfair, + // as the signal was raised before we were entered - indeed, + // we may be directly responding to the signal! + // Thus, we flush all the pending calls here, and report any + // exceptions via our normal exception reporting mechanism. + // We can then execute our code in the knowledge that only + // signals raised _while_ we are executing will cause exceptions. + PyXPCOM_MakePendingCalls(); + } + } + ~CEnterLeavePython() { + // The interpreter state must be cleared + // _before_ we release the lock, as some of + // the sys. attributes cleared (eg, the current exception) + // may need the lock to invoke their destructors - + // specifically, when exc_value is a class instance, and + // the exception holds the last reference! + if ( created ) + PyXPCOM_ThreadState_Clear(); + PyXPCOM_InterpreterLock_Release(); + if ( created ) + PyXPCOM_ThreadState_Free(); + } +private: + PRBool created; +}; +#endif // PYXPCOM_USE_PYGILSTATE + +// Our classes. +// Hrm - So we can't have templates, eh?? +// preprocessor to the rescue, I guess. +#define PyXPCOM_INTERFACE_DECLARE(ClassName, InterfaceName, Methods ) \ + \ +extern struct PyMethodDef Methods[]; \ + \ +class ClassName : public Py_nsISupports \ +{ \ +public: \ + static PYXPCOM_EXPORT PyXPCOM_TypeObject *type; \ + static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ + return new ClassName(pInitObj, iid); \ + } \ + static void InitType() { \ + type = new PyXPCOM_TypeObject( \ + #InterfaceName, \ + Py_nsISupports::type, \ + sizeof(ClassName), \ + Methods, \ + Constructor); \ + const nsIID &iid = NS_GET_IID(InterfaceName); \ + RegisterInterface(iid, type); \ + } \ +protected: \ + ClassName(nsISupports *p, const nsIID &iid) : \ + Py_nsISupports(p, iid, type) { \ + /* The IID _must_ be the IID of the interface we are wrapping! */ \ + NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \ + } \ +}; \ + \ +// End of PyXPCOM_INTERFACE_DECLARE macro + +#define PyXPCOM_ATTR_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )\ + \ +extern struct PyMethodDef Methods[]; \ + \ +class ClassName : public Py_nsISupports \ +{ \ +public: \ + static PyXPCOM_TypeObject *type; \ + static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ + return new ClassName(pInitObj, iid); \ + } \ + static void InitType() { \ + type = new PyXPCOM_TypeObject( \ + #InterfaceName, \ + Py_nsISupports::type, \ + sizeof(ClassName), \ + Methods, \ + Constructor); \ + const nsIID &iid = NS_GET_IID(InterfaceName); \ + RegisterInterface(iid, type); \ +} \ + virtual PyObject *getattr(const char *name); \ + virtual int setattr(const char *name, PyObject *val); \ +protected: \ + ClassName(nsISupports *p, const nsIID &iid) : \ + Py_nsISupports(p, iid, type) { \ + /* The IID _must_ be the IID of the interface we are wrapping! */ \ + NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \ + } \ +}; \ + \ +// End of PyXPCOM_ATTR_INTERFACE_DECLARE macro + +#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \ +PyXPCOM_TypeObject *ClassName::type = NULL; + + +// And the classes +PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) +PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) +PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) +PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) +PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIVariant, nsIVariant, PyMethods_IVariant) +// deprecated, but retained for backward compatibility: +PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete) +#endif // __PYXPCOM_H__ diff --git a/src/libs/xpcom18a4/python/src/PyXPCOM_std.h b/src/libs/xpcom18a4/python/src/PyXPCOM_std.h new file mode 100644 index 00000000..b7b7ff8c --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyXPCOM_std.h @@ -0,0 +1,56 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// standard include - sets up all the defines used by +// the mozilla make process - too lazy to work out how to integrate +// with their make, so this will do! + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +// This header is considered internal - hence +// we can use it to trigger "exports" +#define BUILD_PYXPCOM + +#include "PyXPCOM.h" diff --git a/src/libs/xpcom18a4/python/src/Pyxpt_info.cpp b/src/libs/xpcom18a4/python/src/Pyxpt_info.cpp new file mode 100644 index 00000000..d1df54fe --- /dev/null +++ b/src/libs/xpcom18a4/python/src/Pyxpt_info.cpp @@ -0,0 +1,197 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// Pyxpt_info.cpp - wrappers for the xpt_info objects. +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. +#include "PyXPCOM_std.h" + +PyObject *PyObject_FromXPTType( const nsXPTType *d) +{ + if (d==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + // build an object using the same format as a TypeDescriptor. + return Py_BuildValue("bzzz", + d->flags, + NULL, NULL, NULL); +} + +PyObject *PyObject_FromXPTTypeDescriptor( const XPTTypeDescriptor *d) +{ + if (d==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + return Py_BuildValue("bbbh", + d->prefix.flags, + d->argnum, + d->argnum2, + d->type.iface // this is actually a union! + ); +} + +PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d) +{ + if (d==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + PyObject *ob = PyObject_FromXPTTypeDescriptor(&d->type); + PyObject *ret = Py_BuildValue("bO", d->flags, ob); + Py_DECREF(ob); + return ret; +} + +PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d) +{ + if (d==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + PyObject *ob_params = PyTuple_New(d->num_args); + if (ob_params==NULL) + return NULL; + for (int i=0;inum_args;i++) + PyTuple_SET_ITEM(ob_params, i, PyObject_FromXPTParamDescriptor(d->params+i)); + PyObject *ob_ret = PyObject_FromXPTParamDescriptor(d->result); + PyObject *ret = Py_BuildValue("bsOO", d->flags, d->name, ob_params, ob_ret); + Py_XDECREF(ob_ret); + Py_XDECREF(ob_params); + return ret; +} + +PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *c) +{ + if (c==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + PyObject *ob_type = PyObject_FromXPTTypeDescriptor(&c->type); + if (ob_type==NULL) + return NULL; + PyObject *v = NULL; + switch (c->type.prefix.flags) { + case TD_INT8: + v = PyInt_FromLong( c->value.i8 ); + break; + case TD_INT16: + v = PyInt_FromLong( c->value.i16 ); + break; + case TD_INT32: + v = PyInt_FromLong( c->value.i32 ); + break; + case TD_INT64: + v = PyLong_FromLongLong(c->value.i64); + break; + case TD_UINT8: + v = PyInt_FromLong( c->value.ui8 ); + break; + case TD_UINT16: + v = PyInt_FromLong( c->value.ui16 ); + break; + case TD_UINT32: + v = PyInt_FromLong( c->value.ui32 ); + break; + case TD_UINT64: + v = PyLong_FromUnsignedLongLong(c->value.ui64); + break; + case TD_FLOAT: + v = PyFloat_FromDouble(c->value.flt); + break; + case TD_DOUBLE: + v = PyFloat_FromDouble(c->value.dbl); + break; + case TD_BOOL: + v = c->value.bul ? Py_True : Py_False; + Py_INCREF(v); + break; + case TD_CHAR: +#if PY_MAJOR_VERSION <= 2 + v = PyString_FromStringAndSize(&c->value.ch, 1); +#else + v = PyUnicode_FromStringAndSize(&c->value.ch, 1); +#endif + break; + case TD_WCHAR: + v = PyObject_FromNSString((PRUnichar *)&c->value.wch, 1); + break; + // TD_VOID = 13, + case TD_PNSIID: + v = Py_nsIID::PyObjectFromIID(*c->value.iid); + break; + // TD_DOMSTRING = 15, + case TD_PSTRING: +#if PY_MAJOR_VERSION <= 2 + v = PyString_FromString(c->value.str); +#else + v = PyUnicode_FromString(c->value.str); +#endif + break; + case TD_PWSTRING: + v = PyObject_FromNSString((PRUnichar *)c->value.wstr, nsCRT::strlen((PRUnichar *)c->value.wstr)); + break; + // TD_INTERFACE_TYPE = 18, + // TD_INTERFACE_IS_TYPE = 19, + // TD_ARRAY = 20, + // TD_PSTRING_SIZE_IS = 21, + // TD_PWSTRING_SIZE_IS = 22 + // TD_UTF8STRING = 23, + // TD_CSTRING = 24, + // TD_ASTRING = 25 + default: +#if PY_MAJOR_VERSION <= 2 + v = PyString_FromString("Unknown type code!!"); +#else + v = PyUnicode_FromString("Unknown type code!!"); +#endif + break; + + } + PyObject *ret = Py_BuildValue("sbO", c->name, ob_type, v); + Py_DECREF(ob_type); + Py_DECREF(v); + return ret; +} diff --git a/src/libs/xpcom18a4/python/src/TypeObject.cpp b/src/libs/xpcom18a4/python/src/TypeObject.cpp new file mode 100644 index 00000000..37cc13d7 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/TypeObject.cpp @@ -0,0 +1,457 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include +#include +#include + +#if defined(Py_LIMITED_API) && defined(RT_OS_LINUX) +# include +# ifdef __GLIBC_PREREQ +# if __GLIBC_PREREQ(2,9) +# define PYXPCOM_HAVE_PIPE2 +# include +# endif +# endif +#endif + + +#ifndef Py_LIMITED_API +static PyTypeObject PyInterfaceType_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "interface-type", /* Name of this type */ + sizeof(PyTypeObject), /* Basic object size */ + 0, /* Item size for varobject */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + PyType_Type.tp_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + PyType_Type.tp_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /* tp_getattro */ + 0, /*tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + "Define the behavior of a PythonCOM Interface type.", +}; + +#else /* Py_LIMITED_API */ + +/** The offset of PyTypeObject::ob_name. */ +static size_t g_offObTypeNameMember = sizeof(PyVarObject); + +/** + * Base type object for XPCOM interfaces. Created dynamicially. + */ +static PyTypeObject *g_pPyInterfaceTypeObj = NULL; + +/** + * Gets the base XPCOM interface type object, creating it if needed. + */ +static PyTypeObject *PyXPCOM_CreateInterfaceType(void) +{ + static char g_szTypeDoc[] = "Define the behavior of a PythonCOM Interface type."; /* need non-const */ + PyType_Slot aTypeSlots[] = { + { Py_tp_doc, g_szTypeDoc }, + { 0, NULL } /* terminator */ + }; + static const char g_szClassNm[] = "interface-type"; + PyType_Spec TypeSpec = { + /* .name: */ g_szClassNm, + /* .basicsize: */ 0, + /* .itemsize: */ 0, + /* .flags: */ Py_TPFLAGS_BASETYPE, + /* .slots: */ aTypeSlots, + }; + + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); /* goes south in PyType_Ready if we don't clear exceptions first. */ + + PyTypeObject *pTypeObj = (PyTypeObject *)PyType_FromSpec(&TypeSpec); + assert(pTypeObj); + + PyErr_Restore(exc_typ, exc_val, exc_tb); + g_pPyInterfaceTypeObj = pTypeObj; + + /* + * Verify/correct g_offObTypeNameMember. + * + * Using pipe+write to probe the memory content, banking on the kernel + * to return EFAULT when we pass it an invalid address. + */ + for (size_t off = sizeof(PyVarObject); off < sizeof(PyVarObject) + 64; off += sizeof(char *)) { + const char * const pszProbe = *(const char **)((uintptr_t)(pTypeObj) + off); + if (RT_VALID_PTR(pszProbe)) { + int fds[2] = { -1, -1 }; +# ifdef PYXPCOM_HAVE_PIPE2 + int rc = pipe2(fds, O_CLOEXEC); +# else + int rc = pipe(fds); +# endif + if (rc) + break; + + ssize_t cbWritten = write(fds[1], pszProbe, sizeof(g_szClassNm)); + if (cbWritten == (ssize_t)sizeof(g_szClassNm)) { + char szReadBack[sizeof(g_szClassNm)]; + ssize_t offRead = 0; + while (offRead < cbWritten) { + ssize_t cbRead = read(fds[0], &szReadBack[offRead], cbWritten - offRead); + if (cbRead >= 0) { + offRead += cbRead; + } else if (errno != EINTR) + break; + } + if ( cbWritten == offRead + && memcmp(szReadBack, g_szClassNm, sizeof(szReadBack)) == 0) { + g_offObTypeNameMember = off; + close(fds[0]); + close(fds[1]); + return pTypeObj; + } + } + close(fds[0]); + close(fds[1]); + } + } + assert(0); + + return pTypeObj; +} + +/** + * Gets the base XPCOM interface type object, creating it if needed. + */ +static PyTypeObject *PyXPCOM_GetInterfaceType(void) +{ + PyTypeObject *pTypeObj = g_pPyInterfaceTypeObj; + if (pTypeObj) + return pTypeObj; + return PyXPCOM_CreateInterfaceType(); +} + +/** + * Get the PyTypeObject::ob_name value. + * + * @todo This is _horrible_, but there appears to be no simple tp_name getter + * till https://bugs.python.org/issue31497 (2017 / 3.7.0). But even then + * it is not part of the limited API. + */ +const char *PyXPCOMGetObTypeName(PyTypeObject *pTypeObj) +{ + return *(const char **)((uintptr_t)(pTypeObj) + g_offObTypeNameMember); +} + +#endif /* Py_LIMITED_API */ + +/*static*/ PRBool +PyXPCOM_TypeObject::IsType(PyTypeObject *t) +{ +#if PY_MAJOR_VERSION <= 2 + return t->ob_type == &PyInterfaceType_Type; +#elif !defined(Py_LIMITED_API) + return Py_TYPE(t) == &PyInterfaceType_Type; +#else + return Py_TYPE(t) == g_pPyInterfaceTypeObj /* Typically not the case as t->ob_type is &PyType_Type */ + || PyType_IsSubtype(t, g_pPyInterfaceTypeObj); /* rather than g_pPyInterfaceTypeObj because of PyType_FromSpec(). */ +#endif +} + +//////////////////////////////////////////////////////////////////// +// +// The type methods +// +/*static*/PyObject * +PyXPCOM_TypeObject::Py_getattr(PyObject *self, char *name) +{ + return ((Py_nsISupports *)self)->getattr(name); +} + +/*static*/int +PyXPCOM_TypeObject::Py_setattr(PyObject *op, char *name, PyObject *v) +{ + return ((Py_nsISupports *)op)->setattr(name, v); +} + +// @pymethod int|Py_nsISupports|__cmp__|Implements XPCOM rules for object identity. +/*static*/int +PyXPCOM_TypeObject::Py_cmp(PyObject *self, PyObject *other) +{ + // @comm NOTE: Copied from COM - have not confirmed these rules are true for XPCOM + // @comm As per the XPCOM rules for object identity, both objects are queried for nsISupports, and these values compared. + // The only meaningful test is for equality - the result of other comparisons is undefined + // (ie, determined by the object's relative addresses in memory. + nsISupports *pUnkOther; + nsISupports *pUnkThis; + if (!Py_nsISupports::InterfaceFromPyObject(self, NS_GET_IID(nsISupports), &pUnkThis, PR_FALSE)) + return -1; + if (!Py_nsISupports::InterfaceFromPyObject(other, NS_GET_IID(nsISupports), &pUnkOther, PR_FALSE)) { + pUnkThis->Release(); + return -1; + } + int rc = pUnkThis==pUnkOther ? 0 : + (pUnkThis < pUnkOther ? -1 : 1); + pUnkThis->Release(); + pUnkOther->Release(); + return rc; +} + +/*static*/PyObject * +PyXPCOM_TypeObject::Py_richcmp(PyObject *self, PyObject *other, int op) +{ + PyObject *result = NULL; + int rc = Py_cmp(self, other); + switch (op) + { + case Py_LT: + result = rc < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = rc <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = rc == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = rc != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = rc > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = rc >= 0 ? Py_True : Py_False; + break; + } + Py_XINCREF(result); + return result; +} + +// @pymethod int|Py_nsISupports|__hash__|Implement a hash-code for the XPCOM object using XPCOM identity rules. +#if PY_VERSION_HEX >= 0x03020000 +/*static*/Py_hash_t PyXPCOM_TypeObject::Py_hash(PyObject *self) +#else +/*static*/long PyXPCOM_TypeObject::Py_hash(PyObject *self) +#endif +{ + // We always return the value of the nsISupports *. + nsISupports *pUnkThis; + if (!Py_nsISupports::InterfaceFromPyObject(self, NS_GET_IID(nsISupports), &pUnkThis, PR_FALSE)) + return -1; +#if PY_VERSION_HEX >= 0x03020000 + Py_hash_t ret = _Py_HashPointer(pUnkThis); +#else + long ret = _Py_HashPointer(pUnkThis); +#endif + pUnkThis->Release(); + return ret; +} + +// @method string|Py_nsISupports|__repr__|Called to create a representation of a Py_nsISupports object +/*static */PyObject * +PyXPCOM_TypeObject::Py_repr(PyObject *self) +{ + // @comm The repr of this object displays both the object's address, and its attached nsISupports's address + Py_nsISupports *pis = (Py_nsISupports *)self; + // Try and get the IID name. + char *iid_repr = nsnull; + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + if (iim!=nsnull) + iim->GetNameForIID(&pis->m_iid, &iid_repr); + if (iid_repr==nsnull) + // no IIM available, or it doesnt know the name. + iid_repr = pis->m_iid.ToString(); + // XXX - need some sort of buffer overflow. + char buf[512]; +#ifdef VBOX + snprintf(buf, sizeof(buf), "", + iid_repr, (void *)self, (void *)pis->m_obj.get()); +#else + sprintf(buf, "", + iid_repr, (void *)self, (void *)pis->m_obj.get()); +#endif + nsMemory::Free(iid_repr); +#if PY_MAJOR_VERSION <= 2 + return PyString_FromString(buf); +#else + return PyUnicode_FromString(buf); +#endif +} + +/*static */PyObject * +PyXPCOM_TypeObject::Py_str(PyObject *self) +{ + Py_nsISupports *pis = (Py_nsISupports *)self; + nsresult rv; + char *val = NULL; + Py_BEGIN_ALLOW_THREADS; + { // scope to kill pointer while thread-lock released. + nsCOMPtr ss( do_QueryInterface(pis->m_obj, &rv )); + if (NS_SUCCEEDED(rv)) + rv = ss->ToString(&val); + } // end-scope + Py_END_ALLOW_THREADS; + PyObject *ret; + if (NS_FAILED(rv)) + ret = Py_repr(self); + else +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(val); +#else + ret = PyUnicode_FromString(val); +#endif + if (val) nsMemory::Free(val); + return ret; +} + +/* static */void +PyXPCOM_TypeObject::Py_dealloc(PyObject *self) +{ + delete (Py_nsISupports *)self; +} + +PyXPCOM_TypeObject::PyXPCOM_TypeObject( const char *name, PyXPCOM_TypeObject *pBase, int typeSize, struct PyMethodDef* methodList, PyXPCOM_I_CTOR thector) +{ +#ifndef Py_LIMITED_API + static const PyTypeObject type_template = { + PyVarObject_HEAD_INIT(&PyInterfaceType_Type, 0) + "XPCOMTypeTemplate", /*tp_name*/ + sizeof(Py_nsISupports), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + Py_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + Py_getattr, /* tp_getattr */ + Py_setattr, /* tp_setattr */ +#if PY_MAJOR_VERSION <= 2 + Py_cmp, /* tp_compare */ +#else + 0, /* reserved */ +#endif + Py_repr, /* tp_repr */ + 0, /* tp_as_number*/ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + Py_hash, /* tp_hash */ + 0, /* tp_call */ + Py_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + Py_richcmp, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + }; + + *((PyTypeObject *)this) = type_template; +#else /* Py_LIMITED_API */ + /* Create the type specs: */ + PyType_Slot aTypeSlots[] = { + { Py_tp_base, PyXPCOM_GetInterfaceType() }, + { Py_tp_dealloc, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_dealloc }, + { Py_tp_getattr, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_getattr }, + { Py_tp_setattr, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_setattr }, + { Py_tp_repr, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_repr }, + { Py_tp_hash, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_hash }, + { Py_tp_str, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_str }, + { Py_tp_richcompare, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_richcmp }, + { 0, NULL } /* terminator */ + }; + PyType_Spec TypeSpec = { + /* .name: */ name, + /* .basicsize: */ typeSize, + /* .itemsize: */ 0, + /* .flags: */ Py_TPFLAGS_BASETYPE /*?*/, + /* .slots: */ aTypeSlots, + }; + + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); /* goes south in PyType_Ready if we don't clear exceptions first. */ + + m_pTypeObj = (PyTypeObject *)PyType_FromSpec(&TypeSpec); + assert(m_pTypeObj); + + PyErr_Restore(exc_typ, exc_val, exc_tb); + + /* Initialize the PyObject part - needed so we can keep instance in a PyDict: */ + ob_type = PyXPCOM_GetInterfaceType(); + PyObject_Init(this, ob_type); /* VBox: Needed for 3.9 and up (also works on Python 2.7), includes _Py_NewReferences. @bugref{10079} */ + +#endif /* Py_LIMITED_API */ + + chain.methods = methodList; + chain.link = pBase ? &pBase->chain : NULL; + + baseType = pBase; + ctor = thector; + +#ifndef Py_LIMITED_API + // cast away const, as Python doesnt use it. + tp_name = (char *)name; + tp_basicsize = typeSize; +#endif +} + +PyXPCOM_TypeObject::~PyXPCOM_TypeObject() +{ +} + diff --git a/src/libs/xpcom18a4/python/src/VariantUtils.cpp b/src/libs/xpcom18a4/python/src/VariantUtils.cpp new file mode 100644 index 00000000..ac14a2cf --- /dev/null +++ b/src/libs/xpcom18a4/python/src/VariantUtils.cpp @@ -0,0 +1,3112 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Unicode corrections by Shane Hathaway (http://hathawaymix.org), + * inspired by Mikhail Sobolev + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include +#include +#include +#include + +// ------------------------------------------------------------------------ +// nsString utilities +// ------------------------------------------------------------------------ +// one day we may know what they look like. +inline +PRBool +IsNullDOMString( const nsAString& aString ) +{ + return PR_FALSE; +} + +inline +PRBool +IsNullDOMString( const nsACString& aString ) +{ + return PR_FALSE; +} + +#define PyUnicode_FromPRUnichar(src, size) \ + PyUnicode_DecodeUTF16((char*)(src),sizeof(PRUnichar)*(size),NULL,NULL) + +// Create a zero-terminated PRUnichar buffer from a Python unicode. +// On success, returns 0. On failure, returns -1 and sets an exception. +// dest_out must not be null. size_out may be null. +static int +PyUnicode_AsPRUnichar(PyObject *obj, PRUnichar **dest_out, PRUint32 *size_out) +{ + PRUint32 size; + PyObject *s; + const void *src; + PRUnichar *dest; + + s = PyUnicode_AsUTF16String(obj); + if (!s) + return -1; + // Drop the UTF-16 byte order mark at the beginning of + // the string. (See the docs on PyUnicode_AsUTF16String.) + // Some Mozilla libraries don't like the mark. +#if PY_MAJOR_VERSION <= 2 + size = (PyString_GET_SIZE(s) - 2) / sizeof(PRUnichar); + src = PyString_AS_STRING(s) + 2; +#else + if (!PyBytes_Check(s)) { + PyErr_SetString(PyExc_TypeError, "internal error in PyXPCOM, parameter must be a bytes object"); + return -1; + } + size = (PyBytes_GET_SIZE(s) - 2) / sizeof(PRUnichar); + src = PyBytes_AS_STRING(s) + 2; +#endif + dest = (PRUnichar *)nsMemory::Alloc(sizeof(PRUnichar) * (size + 1)); + if (!dest) { + PyErr_NoMemory(); + Py_DECREF(s); + return -1; + } + memcpy(dest, src, sizeof(PRUnichar) * size); + Py_DECREF(s); + dest[size] = 0; + *dest_out = dest; + if (size_out) + *size_out = size; + return 0; +} + +PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 /*= PR_FALSE */) +{ + PyObject *ret; + if (IsNullDOMString(s)) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + if (bAssumeUTF8) { + const nsPromiseFlatCString& temp = PromiseFlatCString(s); + ret = PyUnicode_DecodeUTF8(temp.get(), temp.Length(), NULL); + } else { +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromStringAndSize(NULL, s.Length()); +#else + ret = PyUnicode_FromStringAndSize(NULL, s.Length()); +#endif + if (!ret) + return NULL; + // Need "CopyAsciiTo"!? + nsACString::const_iterator fromBegin, fromEnd; +#if PY_MAJOR_VERSION <= 2 + char* dest = (char *)PyString_AS_STRING(ret); +#else + char* dest = (char *)PyUnicode_AsUTF8(ret); +#endif + copy_string(s.BeginReading(fromBegin), s.EndReading(fromEnd), dest); + } + } + return ret; +} + +PyObject *PyObject_FromNSString( const nsAString &s ) +{ + PyObject *ret; + if (IsNullDOMString(s)) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + const nsPromiseFlatString& temp = PromiseFlatString(s); + ret = PyUnicode_FromPRUnichar(temp.get(), temp.Length()); + } + return ret; +} + +PyObject *PyObject_FromNSString( const PRUnichar *s, + PRUint32 len /* = (PRUint32)-1*/) +{ + return PyUnicode_FromPRUnichar(s, + len==((PRUint32)-1)? nsCRT::strlen(s) : len); +} + +PRBool PyObject_AsNSString( PyObject *val, nsAString &aStr) +{ + if (val == Py_None) { + aStr.Truncate(); + return NS_OK; + } + PyObject *val_use = NULL; + PRBool ok = PR_TRUE; +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + ok = PR_FALSE; + } + if (ok && (val_use = PyUnicode_FromObject(val))==NULL) + ok = PR_FALSE; +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + ok = PR_FALSE; + } + val_use = val; + Py_INCREF(val_use); +#endif + if (ok) { + if (PyUnicode_GET_SIZE(val_use) == 0) { + aStr.Truncate(); + } + else { + PRUint32 nch; + PRUnichar *tempo; + // can we do this without the copy? + if (PyUnicode_AsPRUnichar(val_use, &tempo, &nch) < 0) + return PR_FALSE; + aStr.Assign(tempo, nch); + nsMemory::Free(tempo); + } + } + Py_XDECREF(val_use); + return ok; +} + +// Array utilities +static PRUint32 GetArrayElementSize( PRUint8 t) +{ + PRUint32 ret; + switch (t & XPT_TDP_TAGMASK) { + case nsXPTType::T_U8: + case nsXPTType::T_I8: + ret = sizeof(PRInt8); + break; + case nsXPTType::T_I16: + case nsXPTType::T_U16: + ret = sizeof(PRInt16); + break; + case nsXPTType::T_I32: + case nsXPTType::T_U32: + ret = sizeof(PRInt32); + break; + case nsXPTType::T_I64: + case nsXPTType::T_U64: + ret = sizeof(PRInt64); + break; + case nsXPTType::T_FLOAT: + ret = sizeof(float); + break; + case nsXPTType::T_DOUBLE: + ret = sizeof(double); + break; + case nsXPTType::T_BOOL: + ret = sizeof(PRBool); + break; + case nsXPTType::T_CHAR: + ret = sizeof(char); + break; + case nsXPTType::T_WCHAR: + ret = sizeof(PRUnichar); + break; + case nsXPTType::T_IID: + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_INTERFACE: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_INTERFACE_IS: + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_CSTRING: + case nsXPTType::T_ASTRING: + case nsXPTType::T_UTF8STRING: + + ret = sizeof( void * ); + break; + default: + NS_ABORT_IF_FALSE(0, "Unknown array type code!"); + ret = 0; + break; + } + return ret; +} + +static nsresult +GetArrayElementIID(Py_nsISupports* self, + nsXPTCVariant* dispatchParams, + PRUint16 methodIndex, + PRUint8 paramIndex, + nsIID *result) +{ + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr ii; + nsresult rc; + + rc = iim->GetInfoForIID(&self->m_iid, getter_AddRefs(ii)); + if (NS_FAILED(rc)) + return rc; + + + const nsXPTMethodInfo *mi; + rc = ii->GetMethodInfo(methodIndex, &mi); + if (NS_FAILED(rc)) + return rc; + + const nsXPTParamInfo& paramInfo = mi->GetParam(paramIndex); + + if (!paramInfo.GetType().IsArray()) { + PyXPCOM_LogWarning("Passing non-array to GetArrayElementIID\n"); + return NS_ERROR_INVALID_ARG; + } + + nsXPTType elemType; + rc = ii->GetTypeForParam(methodIndex, ¶mInfo, 1, &elemType); + if (NS_FAILED(rc)) + return rc; + + PRUint8 tag = elemType.TagPart(); + if (tag == nsXPTType::T_INTERFACE) + { + rc = ii->GetIIDForParamNoAlloc(methodIndex, ¶mInfo, result); + } + else if (tag == nsXPTType::T_INTERFACE_IS) + { + PyXPCOM_LogWarning("Unable to handle T_INTERFACE_IS yet\n"); + return NS_ERROR_NOT_IMPLEMENTED; + } + else + { + // this may be valid case, for arrays of other types + // we don't need IID for + rc = NS_ERROR_INVALID_ARG; + } + + return rc; +} + + +void FreeSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type) +{ + // Free each array element - NOT the array itself + // Thus, we only need to free arrays or pointers. + void **p = (void **)array_ptr; + PRUint32 i; + switch(array_type & XPT_TDP_TAGMASK) { + case nsXPTType::T_IID: + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + for (i=0; iRelease(); + Py_END_ALLOW_THREADS; + } + break; + + // Ones we know need no deallocation + case nsXPTType::T_U8: + case nsXPTType::T_I8: + case nsXPTType::T_I16: + case nsXPTType::T_U16: + case nsXPTType::T_I32: + case nsXPTType::T_U32: + case nsXPTType::T_I64: + case nsXPTType::T_U64: + case nsXPTType::T_FLOAT: + case nsXPTType::T_DOUBLE: + case nsXPTType::T_BOOL: + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + break; + + // And a warning should new type codes appear, as they may need deallocation. + default: + PyXPCOM_LogWarning("Deallocating unknown type %d (0x%x) - possible memory leak\n"); + break; + } +} + +#define FILL_SIMPLE_POINTER( type, val ) *((type *)pthis) = (type)(val) +#define BREAK_FALSE {rc=PR_FALSE;break;} + + +PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence_size, + PRUint32 array_element_size, PRUint8 array_type, nsIID *pIID) +{ + PRUint8 *pthis = (PRUint8 *)array_ptr; + NS_ABORT_IF_FALSE(pthis, "Don't have a valid array to fill!"); + PRBool rc = PR_TRUE; + // We handle T_U8 specially as a string/Unicode. + // If it is NOT a string, we just fall through and allow the standard + // sequence unpack code process it (just slower!) +#if PY_MAJOR_VERSION <= 2 + if ( array_type == nsXPTType::T_U8 && + (PyString_Check(sequence_ob) || PyUnicode_Check(sequence_ob))) { +#else + if ( array_type == nsXPTType::T_U8 && PyUnicode_Check(sequence_ob)) { +#endif + + PRBool release_seq; + if (PyUnicode_Check(sequence_ob)) { + release_seq = PR_TRUE; +#if PY_MAJOR_VERSION <= 2 + sequence_ob = PyObject_Str(sequence_ob); +#else + sequence_ob = PyUnicode_AsUTF8String(sequence_ob); +#endif + } else + release_seq = PR_FALSE; + if (!sequence_ob) // presumably a memory error, or Unicode encoding error. + return PR_FALSE; +#if PY_MAJOR_VERSION <= 2 + memcpy(pthis, PyString_AS_STRING(sequence_ob), sequence_size); +#else + memcpy(pthis, PyUnicode_AsUTF8(sequence_ob), sequence_size); +#endif + if (release_seq) + { + Py_DECREF(sequence_ob); + } + return PR_TRUE; + } + + for (PRUint32 i=0; rc && iRelease(); + Py_END_ALLOW_THREADS; + } + *pp = pnew; // ref-count added by InterfaceFromPyObject + break; + } + default: + // try and limp along in this case. + // leave rc TRUE + PyXPCOM_LogWarning("Converting Python object for an array element - The object type (0x%x) is unknown - leaving param alone!\n", array_type); + break; + } + Py_XDECREF(val_use); + Py_DECREF(val); + } + return rc; +} + +static PyObject *UnpackSingleArray(Py_nsISupports *parent, void *array_ptr, + PRUint32 sequence_size, PRUint8 array_type, nsIID *iid) +{ + if (array_ptr==NULL) { + Py_INCREF(Py_None); + return Py_None; + } + if (array_type == nsXPTType::T_U8) +#if PY_MAJOR_VERSION <= 2 + return PyString_FromStringAndSize( (char *)array_ptr, sequence_size ); +#else + return PyBytes_FromStringAndSize( (char *)array_ptr, sequence_size ); +#endif + + PRUint32 array_element_size = GetArrayElementSize(array_type); + PyObject *list_ret = PyList_New(sequence_size); + PRUint8 *pthis = (PRUint8 *)array_ptr; + for (PRUint32 i=0; iEquals(NS_GET_IID(nsIVariant))) + val = PyObject_FromVariant(parent, (nsIVariant *)*pp); + else if (parent) + val = parent->MakeInterfaceResult(*pp, iid ? *iid : NS_GET_IID(nsISupports)); + else + val = Py_nsISupports::PyObjectFromInterface( + *pp, + iid ? *iid : NS_GET_IID(nsISupports), + PR_TRUE); + break; + } + default: { + char buf[128]; + sprintf(buf, "Unknown XPCOM array type flags (0x%x)", array_type); + PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf); +#if PY_MAJOR_VERSION <= 2 + val = PyString_FromString(buf); +#else + val = PyUnicode_FromString(buf); +#endif + break; + } + } + if (val==NULL) { + NS_ABORT_IF_FALSE(PyErr_Occurred(), "NULL result in array conversion, but no error set!"); + return NULL; + } + PyList_SET_ITEM(list_ret, i, val); // ref-count consumed. + } + return list_ret; +} + + +// ------------------------------------------------------------------------ +// nsIVariant utilities +// ------------------------------------------------------------------------ +struct BVFTResult { + BVFTResult() {pis = NULL;iid=Py_nsIID_NULL;} + nsISupports *pis; + nsIID iid; +}; + +static PRUint16 BestVariantTypeForPyObject( PyObject *ob, BVFTResult *pdata = NULL) +{ + nsISupports *ps = NULL; + nsIID iid; + // start with some fast concrete checks. + if (ob==Py_None) + return nsIDataType::VTYPE_EMPTY; + if (ob==Py_True || ob == Py_False) + return nsIDataType::VTYPE_BOOL; + if (PyInt_Check(ob)) + return nsIDataType::VTYPE_INT32; + if (PyLong_Check(ob)) + return nsIDataType::VTYPE_INT64; + if (PyFloat_Check(ob)) + return nsIDataType::VTYPE_DOUBLE; +#if PY_MAJOR_VERSION <= 2 + if (PyString_Check(ob)) + return nsIDataType::VTYPE_STRING_SIZE_IS; +#endif + if (PyUnicode_Check(ob)) + return nsIDataType::VTYPE_WSTRING_SIZE_IS; + if (PyTuple_Check(ob) || PyList_Check(ob)) { + if (PySequence_Length(ob)) + return nsIDataType::VTYPE_ARRAY; + return nsIDataType::VTYPE_EMPTY_ARRAY; + } + // Now do expensive or abstract checks. + if (Py_nsISupports::InterfaceFromPyObject(ob, NS_GET_IID(nsISupports), &ps, PR_TRUE)) { + if (pdata) { + pdata->pis = ps; + pdata->iid = NS_GET_IID(nsISupports); + } else + ps->Release(); + return nsIDataType::VTYPE_INTERFACE_IS; + } else + PyErr_Clear(); + if (Py_nsIID::IIDFromPyObject(ob, &iid)) { + if (pdata) + pdata->iid = iid; + return nsIDataType::VTYPE_ID; + } else + PyErr_Clear(); + if (PySequence_Check(ob)) { + if (PySequence_Length(ob)) + return nsIDataType::VTYPE_ARRAY; + return nsIDataType::VTYPE_EMPTY_ARRAY; + } + return (PRUint16)-1; +} + +nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet) +{ + nsresult nr = NS_OK; + nsCOMPtr v = do_CreateInstance("@mozilla.org/variant;1", &nr); + NS_ENSURE_SUCCESS(nr, nr); + // *sigh* - I tried the abstract API (PyNumber_Check, etc) + // but our COM instances too often qualify. + BVFTResult cvt_result; + PRUint16 dt = BestVariantTypeForPyObject(ob, &cvt_result); + switch (dt) { + case nsIDataType::VTYPE_BOOL: + nr = v->SetAsBool(ob==Py_True); + break; + case nsIDataType::VTYPE_INT32: + nr = v->SetAsInt32(PyInt_AsLong(ob)); + break; + case nsIDataType::VTYPE_INT64: + nr = v->SetAsInt64(PyLong_AsLongLong(ob)); + break; + case nsIDataType::VTYPE_DOUBLE: + nr = v->SetAsDouble(PyFloat_AsDouble(ob)); + break; + case nsIDataType::VTYPE_STRING_SIZE_IS: + { +#if PY_MAJOR_VERSION <= 2 + nr = v->SetAsStringWithSize(PyString_Size(ob), PyString_AsString(ob)); +#else + Py_ssize_t cb = 0; + const char *psz = PyUnicode_AsUTF8AndSize(ob, &cb); + nr = v->SetAsStringWithSize(cb, psz); +#endif + break; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: +#if PY_VERSION_HEX >= 0x03030000 + if (PyUnicode_GetLength(ob) == 0) { +#else + if (PyUnicode_GetSize(ob) == 0) { +#endif + nr = v->SetAsWStringWithSize(0, (PRUnichar*)NULL); + } + else { + PRUint32 nch; + PRUnichar *p; + if (PyUnicode_AsPRUnichar(ob, &p, &nch) < 0) { + PyXPCOM_LogWarning("Failed to convert object to unicode", PyXPCOM_ObTypeName(ob)); + nr = NS_ERROR_UNEXPECTED; + break; + } + nr = v->SetAsWStringWithSize(nch, p); + nsMemory::Free(p); + } + break; + case nsIDataType::VTYPE_INTERFACE_IS: + { + nsISupports *ps = cvt_result.pis; + nr = v->SetAsInterface(cvt_result.iid, ps); + if (ps) { + Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires. + ps->Release(); + Py_END_ALLOW_THREADS; + } + break; + } + case nsIDataType::VTYPE_ID: + nr = v->SetAsID(cvt_result.iid); + break; + case nsIDataType::VTYPE_ARRAY: + { + int seq_length = PySequence_Length(ob); + NS_ABORT_IF_FALSE(seq_length!=0, "VTYPE_ARRAY assumes at least one element!"); + PyObject *first = PySequence_GetItem(ob, 0); + if (!first) break; + int array_type = BestVariantTypeForPyObject(first); + Py_DECREF(first); + // Arrays can't handle all types. This means we lost embedded NULLs. + // This should really be fixed in XPCOM. + if (array_type == nsIDataType::VTYPE_STRING_SIZE_IS) array_type = nsIDataType::VTYPE_CHAR_STR; + if (array_type == nsIDataType::VTYPE_WSTRING_SIZE_IS) array_type = nsIDataType::VTYPE_WCHAR_STR; + PRUint32 element_size = GetArrayElementSize(array_type); + int cb_buffer_pointer = seq_length * element_size; + void *buffer_pointer; + if ((buffer_pointer = (void *)nsMemory::Alloc(cb_buffer_pointer)) == nsnull) { + nr = NS_ERROR_OUT_OF_MEMORY; + break; + } + memset(buffer_pointer, 0, cb_buffer_pointer); + if (FillSingleArray(buffer_pointer, ob, seq_length, element_size, array_type, nsnull)) { + nr = v->SetAsArray(array_type, &NS_GET_IID(nsISupports), seq_length, buffer_pointer); + FreeSingleArray(buffer_pointer, seq_length, array_type); + } else + nr = NS_ERROR_UNEXPECTED; + nsMemory::Free(buffer_pointer); + break; + } + case nsIDataType::VTYPE_EMPTY: + nr = v->SetAsEmpty(); + break; + case nsIDataType::VTYPE_EMPTY_ARRAY: + nr = v->SetAsEmptyArray(); + break; + case (PRUint16)-1: + PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", PyXPCOM_ObTypeName(ob)); + nr = NS_ERROR_UNEXPECTED; + default: + NS_ABORT_IF_FALSE(0, "BestVariantTypeForPyObject() returned a variant type not handled here!"); + PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", PyXPCOM_ObTypeName(ob)); + nr = NS_ERROR_UNEXPECTED; + } + if (NS_FAILED(nr)) + return nr; + return v->QueryInterface(NS_GET_IID(nsIVariant), (void **)aRet); +} + +static PyObject *MyBool_FromBool(PRBool v) +{ + PyObject *ret = v ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} + +#define GET_FROM_V(Type, FuncGet, FuncConvert) { \ + Type t; \ + if (NS_FAILED(nr = FuncGet( &t ))) goto done;\ + ret = FuncConvert(t);\ + break; \ +} + +PyObject *PyObject_FromVariantArray( Py_nsISupports *parent, nsIVariant *v) +{ + nsresult nr; + NS_PRECONDITION(v, "NULL variant!"); + if (!v) + return PyXPCOM_BuildPyException(NS_ERROR_INVALID_POINTER); +#ifdef NS_DEBUG + PRUint16 dt; + nr = v->GetDataType(&dt); + NS_ABORT_IF_FALSE(dt == nsIDataType::VTYPE_ARRAY, "expected an array variant"); +#endif + nsIID iid; + void *p; + PRUint16 type; + PRUint32 count; + nr = v->GetAsArray(&type, &iid, &count, &p); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + PyObject *ret = UnpackSingleArray(parent, p, count, (PRUint8)type, &iid); + FreeSingleArray(p, count, (PRUint8)type); + nsMemory::Free(p); + return ret; +} + +PyObject *PyObject_FromVariant( Py_nsISupports *parent, nsIVariant *v) +{ + if (!v) { + Py_INCREF(Py_None); + return Py_None; + } + PRUint16 dt; + nsresult nr; + PyObject *ret = NULL; + nr = v->GetDataType(&dt); + if (NS_FAILED(nr)) goto done; + switch (dt) { + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_EMPTY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + ret = Py_None; + Py_INCREF(Py_None); + break; + case nsIDataType::VTYPE_ARRAY: + ret = PyObject_FromVariantArray(parent, v); + break; + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + GET_FROM_V(PRInt32, v->GetAsInt32, PyInt_FromLong); + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + GET_FROM_V(PRUint32, v->GetAsUint32, PyLong_FromUnsignedLong); + case nsIDataType::VTYPE_INT64: + GET_FROM_V(PRInt64, v->GetAsInt64, PyLong_FromLongLong); + case nsIDataType::VTYPE_UINT64: + GET_FROM_V(PRUint64, v->GetAsUint64, PyLong_FromUnsignedLongLong); + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + GET_FROM_V(double, v->GetAsDouble, PyFloat_FromDouble); + case nsIDataType::VTYPE_BOOL: + GET_FROM_V(PRBool, v->GetAsBool, MyBool_FromBool); + default: + PyXPCOM_LogWarning("Converting variant to Python object - variant type '%d' unknown - using string.\n", dt); + // Fall through to the string case + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_CSTRING: { + nsCAutoString s; + if (NS_FAILED(nr=v->GetAsACString(s))) goto done; + ret = PyObject_FromNSString(s); + break; + } + case nsIDataType::VTYPE_WCHAR: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_ASTRING: { + nsAutoString s; + if (NS_FAILED(nr=v->GetAsAString(s))) goto done; + ret = PyObject_FromNSString(s); + break; + } + case nsIDataType::VTYPE_ID: + GET_FROM_V(nsIID, v->GetAsID, Py_nsIID::PyObjectFromIID); + case nsIDataType::VTYPE_INTERFACE: { + nsCOMPtr p; + if (NS_FAILED(nr=v->GetAsISupports(getter_AddRefs(p)))) goto done; + if (parent) + ret = parent->MakeInterfaceResult(p, NS_GET_IID(nsISupports)); + else + ret = Py_nsISupports::PyObjectFromInterface( + p, NS_GET_IID(nsISupports), PR_TRUE); + break; + } + case nsIDataType::VTYPE_INTERFACE_IS: { + nsCOMPtr p; + nsIID *iid; + if (NS_FAILED(nr=v->GetAsInterface(&iid, getter_AddRefs(p)))) goto done; + // If the variant itself holds a variant, we should + // probably unpack that too? + ret = parent->MakeInterfaceResult(p, *iid); + break; + // case nsIDataType::VTYPE_WCHAR_STR + // case nsIDataType::VTYPE_UTF8STRING + } + } +done: + if (NS_FAILED(nr)) { + NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!"); + PyXPCOM_BuildPyException(nr); + } + return ret; +} + +// ------------------------------------------------------------------------ +// TypeDescriptor helper class +// ------------------------------------------------------------------------ +class PythonTypeDescriptor { +public: + PythonTypeDescriptor() { + param_flags = type_flags = argnum = argnum2 = 0; + extra = NULL; + is_auto_out = PR_FALSE; + is_auto_in = PR_FALSE; + have_set_auto = PR_FALSE; + } + ~PythonTypeDescriptor() { + Py_XDECREF(extra); + } + PRUint8 param_flags; + PRUint8 type_flags; + PRUint8 argnum; /* used for iid_is and size_is */ + PRUint8 argnum2; /* used for length_is */ + PyObject *extra; // The IID object, or the type of the array. + // Extra items to help our processing. + // Is this auto-filled by some other "in" param? + PRBool is_auto_in; + // Is this auto-filled by some other "out" param? + PRBool is_auto_out; + // If is_auto_out, have I already filled it? Used when multiple + // params share a size_is fields - first time sets it, subsequent + // time check it. + PRBool have_set_auto; +}; + +static int ProcessPythonTypeDescriptors(PythonTypeDescriptor *pdescs, int num) +{ + // Loop over the array, checking all the params marked as having an arg. + // If these args nominate another arg as the size_is param, then + // we reset the size_is param to _not_ requiring an arg. + int i; + for (i=0;iRelease(); + Py_END_ALLOW_THREADS; + } + } + if (ns_v.IsValDOMString() && ns_v.val.p) { + delete (const nsAString *)ns_v.val.p; + } + if (ns_v.IsValCString() && ns_v.val.p) { + delete (const nsACString *)ns_v.val.p; + } + if (ns_v.IsValUTF8String() && ns_v.val.p) { + delete (const nsACString *)ns_v.val.p; + } + if (ns_v.IsValArray()) { + nsXPTCVariant &ns_v = m_var_array[i]; + if (ns_v.val.p) { + PRUint8 array_type = (PRUint8)PyInt_AsLong(m_python_type_desc_array[i].extra); + PRUint32 seq_size = GetSizeIs(i, PR_FALSE); + FreeSingleArray(ns_v.val.p, seq_size, array_type); + } + } + // IsOwned must be the last check of the loop, as + // this frees the underlying data used above (eg, by the array free process) + if (ns_v.IsValAllocated() && !ns_v.IsValInterface() && !ns_v.IsValDOMString()) { + NS_ABORT_IF_FALSE(ns_v.IsPtrData(), "expecting a pointer to free"); + nsMemory::Free(ns_v.val.p); + } + } + if (m_buffer_array && m_buffer_array[i]) + nsMemory::Free(m_buffer_array[i]); + } + delete [] m_python_type_desc_array; + delete [] m_buffer_array; + delete [] m_var_array; +} + +PRBool PyXPCOM_InterfaceVariantHelper::Init(PyObject *obParams) +{ + PRBool ok = PR_FALSE; + int i; + int total_params_needed = 0; + if (!PySequence_Check(obParams) || PySequence_Length(obParams)!=2) { + PyErr_Format(PyExc_TypeError, "Param descriptors must be a sequence of exactly length 2"); + return PR_FALSE; + } + PyObject *typedescs = PySequence_GetItem(obParams, 0); + if (typedescs==NULL) + return PR_FALSE; + // NOTE: The length of the typedescs may be different than the + // args actually passed. The typedescs always include all + // hidden params (such as "size_is"), while the actual + // args never include this. + m_num_array = PySequence_Length(typedescs); + if (PyErr_Occurred()) goto done; + + m_pyparams = PySequence_GetItem(obParams, 1); + if (m_pyparams==NULL) goto done; + + m_python_type_desc_array = new PythonTypeDescriptor[m_num_array]; + if (!m_python_type_desc_array) goto done; + + // Pull apart the type descs and stash them. + for (i=0;iMakeInterfaceResult(iret, iid); + break; + } + case nsXPTType::T_INTERFACE_IS: { + nsIID iid; + nsXPTCVariant &ns_viid = m_var_array[td.argnum]; + NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!"); + if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID) { + nsIID *piid = (nsIID *)ns_viid.val.p; + if (piid==NULL) + // Also serious, but like below, not our fault! + iid = NS_GET_IID(nsISupports); + else + iid = *piid; + } else { + // This is a pretty serious problem, but not Python's fault! + // Just return an nsISupports and hope the caller does whatever + // QI they need before using it. + NS_ERROR("Failed to get the IID for T_INTERFACE_IS!"); + iid = NS_GET_IID(nsISupports); + } + nsISupports *iret = *((nsISupports **)ns_v.ptr); + if (iid.Equals(NS_GET_IID(nsIVariant))) + ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret); + else + ret = m_parent->MakeInterfaceResult(iret, iid); + break; + } + case nsXPTType::T_ARRAY: { + if ( (* ((void **)ns_v.ptr)) == NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } + if (!PyInt_Check(td.extra)) { + PyErr_SetString(PyExc_TypeError, "The array info is not valid"); + break; + } + PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra); + PRUint32 seq_size = GetSizeIs(index, PR_FALSE); + nsXPTCVariant &ns_viid = m_var_array[td.argnum]; + nsIID iid; + nsresult res = GetArrayElementIID(m_parent, + m_var_array, + m_methodindex, + index, + &iid); + ret = UnpackSingleArray(m_parent, * ((void **)ns_v.ptr), + seq_size, array_type&XPT_TDP_TAGMASK, + NS_SUCCEEDED(res) ? &iid : NULL); + break; + } + + case nsXPTType::T_PSTRING_SIZE_IS: + if (*((char **)ns_v.ptr) == NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + PRUint32 string_size = GetSizeIs(index, PR_TRUE); +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromStringAndSize( *((char **)ns_v.ptr), string_size ); +#else + ret = PyUnicode_FromStringAndSize( *((char **)ns_v.ptr), string_size ); +#endif + } + break; + + case nsXPTType::T_PWSTRING_SIZE_IS: + if (*((PRUnichar **)ns_v.ptr) == NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + PRUint32 string_size = GetSizeIs(index, PR_TRUE); + ret = PyUnicode_FromPRUnichar( *((PRUnichar **)ns_v.ptr), string_size ); + } + break; + default: + PyErr_Format(PyExc_ValueError, "Unknown XPCOM type code (0x%x)", XPT_TDP_TAG(ns_v.type)); + /* ret remains nsnull */ + break; + } + return ret; +} + + +PyObject *PyXPCOM_InterfaceVariantHelper::MakePythonResult() +{ + // First we count the results. + int i = 0; + int n_results = 0; + PyObject *ret = NULL; + PRBool have_retval = PR_FALSE; + for (i=0;i 1) { + ret = PyTuple_New(n_results); + if (ret==NULL) + return NULL; + } + int ret_index = 0; + int max_index = m_num_array; + // Stick the retval at the front if we have have + if (have_retval && n_results > 1) { + PyObject *val = MakeSinglePythonResult(m_num_array-1); + if (val==NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(ret, 0, val); + max_index--; + ret_index++; + + } + for (i=0;ret_index < n_results && i < max_index;i++) { + if (!m_python_type_desc_array[i].is_auto_out) { + if (XPT_PD_IS_OUT(m_python_type_desc_array[i].param_flags) || XPT_PD_IS_DIPPER(m_python_type_desc_array[i].param_flags)) { + PyObject *val = MakeSinglePythonResult(i); + if (val==NULL) { + Py_XDECREF(ret); + return NULL; + } + if (n_results > 1) { + PyTuple_SET_ITEM(ret, ret_index, val); + ret_index++; + } else { + NS_ABORT_IF_FALSE(ret==NULL, "shouldnt already have a ret!"); + ret = val; + } + } + } + } + + } + return ret; +} + +/************************************************************************* +************************************************************************** + + Helpers when IMPLEMENTING interfaces. + +************************************************************************** +*************************************************************************/ + +PyXPCOM_GatewayVariantHelper::PyXPCOM_GatewayVariantHelper( PyG_Base *gw, int method_index, const nsXPTMethodInfo *info, nsXPTCMiniVariant* params ) +{ + m_params = params; + m_info = info; + // no references added - this class is only alive for + // a single gateway invocation + m_gateway = gw; + m_method_index = method_index; + m_python_type_desc_array = NULL; + m_num_type_descs = 0; +} + +PyXPCOM_GatewayVariantHelper::~PyXPCOM_GatewayVariantHelper() +{ + delete [] m_python_type_desc_array; +} + +PyObject *PyXPCOM_GatewayVariantHelper::MakePyArgs() +{ + NS_PRECONDITION(sizeof(XPTParamDescriptor) == sizeof(nsXPTParamInfo), "We depend on nsXPTParamInfo being a wrapper over the XPTParamDescriptor struct"); + // Setup our array of Python typedescs, and determine the number of objects we + // pass to Python. + m_num_type_descs = m_info->num_args; + m_python_type_desc_array = new PythonTypeDescriptor[m_num_type_descs]; + if (m_python_type_desc_array==nsnull) + return PyErr_NoMemory(); + + // First loop to count the number of objects + // we pass to Python + int i; + for (i=0;inum_args;i++) { + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i; + PythonTypeDescriptor &td = m_python_type_desc_array[i]; + td.param_flags = pi->flags; + td.type_flags = pi->type.prefix.flags; + td.argnum = pi->type.argnum; + td.argnum2 = pi->type.argnum2; + } + int num_args = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_type_descs); + PyObject *ret = PyTuple_New(num_args); + if (ret==NULL) + return NULL; + int this_arg = 0; + for (i=0;i=0 && this_arg= m_num_type_descs) { + PyErr_SetString(PyExc_ValueError, "dont have a valid size_is indicator for this param"); + return PR_FALSE; + } + PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags); + nsXPTCMiniVariant &ns_v = m_params[argnum]; + NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32"); + return is_out ? *((PRUint32 *)ns_v.val.p) : ns_v.val.u32; +} + +#undef DEREF_IN_OR_OUT +#define DEREF_IN_OR_OUT( element, ret_type ) (ret_type)(is_out ? *((ret_type *)ns_v.val.p) : (ret_type)(element)) + +PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDescriptor &td) +{ + NS_PRECONDITION(XPT_PD_IS_IN(td.param_flags), "Must be an [in] param!"); + nsXPTCMiniVariant &ns_v = m_params[index]; + PyObject *ret = NULL; + PRBool is_out = XPT_PD_IS_OUT(td.param_flags); + + switch (td.type_flags & XPT_TDP_TAGMASK) { + case nsXPTType::T_I8: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i8, PRInt8 ) ); + break; + case nsXPTType::T_I16: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i16, PRInt16) ); + break; + case nsXPTType::T_I32: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i32, PRInt32) ); + break; + case nsXPTType::T_I64: + ret = PyLong_FromLongLong( DEREF_IN_OR_OUT(ns_v.val.i64, PRInt64) ); + break; + case nsXPTType::T_U8: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u8, PRUint8) ); + break; + case nsXPTType::T_U16: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u16, PRUint16) ); + break; + case nsXPTType::T_U32: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u32, PRUint32) ); + break; + case nsXPTType::T_U64: + ret = PyLong_FromUnsignedLongLong( DEREF_IN_OR_OUT(ns_v.val.u64, PRUint64) ); + break; + case nsXPTType::T_FLOAT: + ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.f, float) ); + break; + case nsXPTType::T_DOUBLE: + ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.d, double) ); + break; + case nsXPTType::T_BOOL: { + PRBool temp = DEREF_IN_OR_OUT(ns_v.val.b, PRBool); + ret = temp ? Py_True : Py_False; + Py_INCREF(ret); + break; + } + case nsXPTType::T_CHAR: { + char temp = DEREF_IN_OR_OUT(ns_v.val.c, char); +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromStringAndSize(&temp, 1); +#else + ret = PyUnicode_FromStringAndSize(&temp, 1); +#endif + break; + } + case nsXPTType::T_WCHAR: { + PRUnichar temp = (PRUnichar)DEREF_IN_OR_OUT(ns_v.val.wc, PRUnichar); + ret = PyUnicode_FromPRUnichar(&temp, 1); + break; + } +// case nsXPTType::T_VOID: + case nsXPTType::T_IID: { + ret = Py_nsIID::PyObjectFromIID( * DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *) ); + break; + } + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: { + NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout"); + const nsAString *rs = (const nsAString *)ns_v.val.p; + ret = PyObject_FromNSString(*rs); + break; + } + case nsXPTType::T_CSTRING: + case nsXPTType::T_UTF8STRING: { + NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout"); + const nsCString *rs = (const nsCString *)ns_v.val.p; + ret = PyObject_FromNSString(*rs, (td.type_flags & XPT_TDP_TAGMASK)==nsXPTType::T_UTF8STRING); + break; + } + case nsXPTType::T_CHAR_STR: { + char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *); + if (t==NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(t); +#else + ret = PyUnicode_FromString(t); +#endif + break; + } + + case nsXPTType::T_WCHAR_STR: { + PRUnichar *us = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *); + if (us==NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us)); + } + break; + } + case nsXPTType::T_INTERFACE_IS: // our Python code does it :-) + case nsXPTType::T_INTERFACE: { + nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *); + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index; + ret = m_gateway->MakeInterfaceParam(iret, NULL, m_method_index, pi, index); + break; + } +/*** + nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *); + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index; + nsXPTCMiniVariant &ns_viid = m_params[td.argnum]; + NS_ABORT_IF_FALSE((m_python_type_desc_array[td.argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!"); + const nsIID * iid = NULL; + if (XPT_PD_IS_IN(m_python_type_desc_array[td.argnum].param_flags)) + // may still be inout! + iid = DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *); + + ret = m_gateway->MakeInterfaceParam(iret, iid, m_method_index, pi, index); + break; + } +****/ + case nsXPTType::T_ARRAY: { + void *t = DEREF_IN_OR_OUT(ns_v.val.p, void *); + if (t==NULL) { + // JS may send us a NULL here occasionally - as the + // type is array, we silently convert this to a zero + // length list, a-la JS. + ret = PyList_New(0); + } else { + PRUint8 array_type; + nsIID *piid; + nsresult ns = GetArrayType(index, &array_type, &piid); + if (NS_FAILED(ns)) { + PyXPCOM_BuildPyException(ns); + break; + } + PRUint32 seq_size = GetSizeIs(index, PR_FALSE); + ret = UnpackSingleArray(NULL, t, seq_size, array_type&XPT_TDP_TAGMASK, piid); + } + break; + } + case nsXPTType::T_PSTRING_SIZE_IS: { + char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *); + PRUint32 string_size = GetSizeIs(index, PR_TRUE); + if (t==NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromStringAndSize(t, string_size); +#else + ret = PyUnicode_FromStringAndSize(t, string_size); +#endif + break; + } + case nsXPTType::T_PWSTRING_SIZE_IS: { + PRUnichar *t = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *); + PRUint32 string_size = GetSizeIs(index, PR_TRUE); + if (t==NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + ret = PyUnicode_FromPRUnichar(t, string_size); + } + break; + } + default: + // As this is called by external components, + // we return _something_ rather than failing before any user code has run! + { + char buf[128]; + sprintf(buf, "Unknown XPCOM type flags (0x%x)", td.type_flags); + PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf); +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(buf); +#else + ret = PyUnicode_FromString(buf); +#endif + break; + } + } + return ret; +} + +nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **iid) +{ + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!"); + if (iim==nsnull) + return NS_ERROR_FAILURE; + + nsCOMPtr ii; + nsresult rc = iim->GetInfoForIID( &m_gateway->m_iid, getter_AddRefs(ii)); + if (NS_FAILED(rc)) + return rc; + nsXPTType datumType; + const nsXPTParamInfo& param_info = m_info->GetParam((PRUint8)index); + rc = ii->GetTypeForParam(m_method_index, ¶m_info, 1, &datumType); + if (NS_FAILED(rc)) + return rc; + if (iid) { + *iid = (nsIID *)&NS_GET_IID(nsISupports); + if (XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE || + XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE_IS || + XPT_TDP_TAG(datumType)==nsXPTType::T_ARRAY) + ii->GetIIDForParam(m_method_index, ¶m_info, iid); + } + *ret = datumType.flags; + return NS_OK; +} + +PRBool PyXPCOM_GatewayVariantHelper::GetIIDForINTERFACE_ID(int index, const nsIID **ppret) +{ + // Not sure if the IID pointed at by by this is allows to be + // in or out, so we will allow it. + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index; + nsXPTType typ = pi->GetType(); + NS_WARN_IF_FALSE(XPT_TDP_TAG(typ) == nsXPTType::T_IID, "INTERFACE_IS IID param isnt an IID!"); + NS_ABORT_IF_FALSE(typ.IsPointer(), "Expecting to re-fill a pointer value."); + if (XPT_TDP_TAG(typ) != nsXPTType::T_IID) + *ppret = &NS_GET_IID(nsISupports); + else { + nsXPTCMiniVariant &ns_v = m_params[index]; + if (pi->IsOut()) { + nsIID **pp = (nsIID **)ns_v.val.p; + if (pp && *pp) + *ppret = *pp; + else + *ppret = &NS_GET_IID(nsISupports); + } else if (pi->IsIn()) { + nsIID *p = (nsIID *)ns_v.val.p; + if (p) + *ppret = p; + else + *ppret = &NS_GET_IID(nsISupports); + } else { + NS_ERROR("Param is not in or out!"); + *ppret = &NS_GET_IID(nsISupports); + } + } + return PR_TRUE; +} + +nsIInterfaceInfo *PyXPCOM_GatewayVariantHelper::GetInterfaceInfo() +{ + if (!m_interface_info) { + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + if (iim) + iim->GetInfoForIID(&m_gateway->m_iid, getter_AddRefs(m_interface_info)); + } + return m_interface_info; +} + +#undef FILL_SIMPLE_POINTER +#define FILL_SIMPLE_POINTER( type, ob ) *((type *)ns_v.val.p) = (type)(ob) + +nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index) +{ + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index; + NS_ABORT_IF_FALSE(pi->IsOut() || pi->IsDipper(), "The value must be marked as [out] (or a dipper) to be back-filled!"); + NS_ABORT_IF_FALSE(!pi->IsShared(), "Dont know how to back-fill a shared out param"); + nsXPTCMiniVariant &ns_v = m_params[index]; + + nsXPTType typ = pi->GetType(); + PyObject* val_use = NULL; + + NS_ABORT_IF_FALSE(pi->IsDipper() || ns_v.val.p, "No space for result!"); + if (!pi->IsDipper() && !ns_v.val.p) return NS_ERROR_INVALID_POINTER; + + PRBool rc = PR_TRUE; + switch (XPT_TDP_TAG(typ)) { + case nsXPTType::T_I8: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_I16: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_I32: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_I64: + if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) ); + break; + case nsXPTType::T_U8: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_U16: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_U32: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_U64: + if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) ); + break; + case nsXPTType::T_FLOAT: + if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE + FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) ); + break; + case nsXPTType::T_DOUBLE: + if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE + FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) ); + break; + case nsXPTType::T_BOOL: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE + FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_CHAR: +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + if ((val_use = PyObject_Str(val))==NULL) + BREAK_FALSE; + // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode! + NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!"); + FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) ); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } +# ifndef Py_LIMITED_API + FILL_SIMPLE_POINTER( char, *PyUnicode_AS_UNICODE(val) ); +# else + FILL_SIMPLE_POINTER( char, PyUnicode_ReadChar(val, 0) ); +# endif +#endif + break; + + case nsXPTType::T_WCHAR: +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a Unicode object"); + BREAK_FALSE; + } +#endif + if ((val_use = PyUnicode_FromObject(val))==NULL) + BREAK_FALSE; + NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!"); + // Lossy! +#ifndef Py_LIMITED_API + FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) ); +#else + FILL_SIMPLE_POINTER( PRUnichar, PyUnicode_ReadChar(val_use, 0) ); +#endif + break; + +// case nsXPTType::T_VOID: + case nsXPTType::T_IID: { + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(val, &iid)) + BREAK_FALSE; + nsIID **pp = (nsIID **)ns_v.val.p; + // If there is an existing [in] IID, free it. + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID)); + if (*pp==NULL) { + PyErr_NoMemory(); + BREAK_FALSE; + } + memcpy(*pp, &iid, sizeof(iid)); + break; + } + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: { + nsAString *ws = (nsAString *)ns_v.val.p; + NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??"); + if (!PyObject_AsNSString(val, *ws)) + BREAK_FALSE; + break; + } + case nsXPTType::T_CSTRING: { + nsCString *ws = (nsCString *)ns_v.val.p; + NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??"); + if (val == Py_None) { + NS_ABORT_IF_FALSE(0, "dont handle None here yet"); + } else { +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + val_use = PyObject_Str(val); + NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!"); + const char *sz = PyString_AS_STRING(val_use); + ws->Assign(sz, PyString_GET_SIZE(val_use)); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + val_use = PyUnicode_AsUTF8String(val); + const char *sz = PyBytes_AS_STRING(val_use); + ws->Assign(sz, PyBytes_GET_SIZE(val_use)); +#endif + } + break; + } + case nsXPTType::T_UTF8STRING: { + nsCString *ws = (nsCString *)ns_v.val.p; + NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??"); + if (val == Py_None) { + NS_ABORT_IF_FALSE(0, "dont handle None here yet"); + } else { +#if PY_MAJOR_VERSION <= 2 + if (PyString_Check(val)) { + val_use = val; + Py_INCREF(val); + } + else +#endif + if (PyUnicode_Check(val)) { + val_use = PyUnicode_AsUTF8String(val); + } else { +#if PY_MAJOR_VERSION <= 2 + PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects"); +#else + PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be unicode objects"); +#endif + BREAK_FALSE; + } +#if PY_MAJOR_VERSION <= 2 + NS_ABORT_IF_FALSE(PyString_Check(val_use), "must have a string object!"); + const char *sz = PyString_AS_STRING(val_use); + ws->Assign(sz, PyString_GET_SIZE(val_use)); +#else + NS_ABORT_IF_FALSE(PyBytes_Check(val_use), "must have a bytes object!"); + const char *sz = PyBytes_AS_STRING(val_use); + ws->Assign(sz, PyBytes_GET_SIZE(val_use)); +#endif + } + break; + } + + case nsXPTType::T_CHAR_STR: { + // If it is an existing string, free it. + char **pp = (char **)ns_v.val.p; + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = nsnull; + + if (val == Py_None) + break; // Remains NULL. +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + if ((val_use = PyObject_Str(val))==NULL) + BREAK_FALSE; + // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode! + NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!"); + + const char *sz = PyString_AS_STRING(val_use); + int nch = PyString_GET_SIZE(val_use); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + if ((val_use = PyUnicode_AsUTF8String(val))==NULL) + BREAK_FALSE; + + const char *sz = PyBytes_AS_STRING(val_use); + int nch = PyBytes_GET_SIZE(val_use); +#endif + + *pp = (char *)nsMemory::Alloc(nch+1); + if (*pp==NULL) { + PyErr_NoMemory(); + BREAK_FALSE; + } + strncpy(*pp, sz, nch+1); + break; + } + case nsXPTType::T_WCHAR_STR: { + // If it is an existing string, free it. + PRUnichar **pp = (PRUnichar **)ns_v.val.p; + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = nsnull; + if (val == Py_None) + break; // Remains NULL. +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + val_use = PyUnicode_FromObject(val); + NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!"); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + val_use = val; + Py_INCREF(val_use); +#endif + if (PyUnicode_AsPRUnichar(val_use, pp, NULL) < 0) + BREAK_FALSE; + break; + } + case nsXPTType::T_INTERFACE: { + nsISupports *pnew = nsnull; + // Find out what IID we are declared to use. + nsIID *iid = NULL; + nsIInterfaceInfo *ii = GetInterfaceInfo(); + if (ii) + ii->GetIIDForParam(m_method_index, pi, &iid); + + // Get it the "standard" way. + // We do allow NULL here, even tho doing so will no-doubt crash some objects. + // (but there will certainly be objects out there that will allow NULL :-( + nsIID iid_use = iid ? *iid : NS_GET_IID(nsISupports); + if (!Py_nsISupports::InterfaceFromPyObject(val, iid_use, &pnew, PR_TRUE)) + BREAK_FALSE; + nsISupports **pp = (nsISupports **)ns_v.val.p; + if (*pp && pi->IsIn()) { + Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires. + (*pp)->Release(); + Py_END_ALLOW_THREADS; + } + + *pp = pnew; // ref-count added by InterfaceFromPyObject + break; + } + case nsXPTType::T_INTERFACE_IS: { + const nsIID *piid; + if (!GetIIDForINTERFACE_ID(pi->type.argnum, &piid)) + BREAK_FALSE; + + nsISupports *pnew = nsnull; + // Get it the "standard" way. + // We do allow NULL here, even tho doing so will no-doubt crash some objects. + // (but there will certainly be objects out there that will allow NULL :-( + if (!Py_nsISupports::InterfaceFromPyObject(val, *piid, &pnew, PR_TRUE)) + BREAK_FALSE; + nsISupports **pp = (nsISupports **)ns_v.val.p; + if (*pp && pi->IsIn()) { + Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires. + (*pp)->Release(); + Py_END_ALLOW_THREADS; + } + + *pp = pnew; // ref-count added by InterfaceFromPyObject + break; + } + + case nsXPTType::T_PSTRING_SIZE_IS: { + const char *sz = nsnull; + PRUint32 nch = 0; + if (val != Py_None) { +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + if ((val_use = PyObject_Str(val))==NULL) + BREAK_FALSE; + // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode! + NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!"); + + sz = PyString_AS_STRING(val_use); + nch = PyString_GET_SIZE(val_use); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + if ((val_use = PyUnicode_AsUTF8String(val))==NULL) + BREAK_FALSE; + + sz = PyBytes_AS_STRING(val_use); + nch = PyBytes_GET_SIZE(val_use); +#endif + } + PRBool bBackFill = PR_FALSE; + PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE); + // If we can not change the size, check our sequence is correct. + if (!bCanSetSizeIs) { + PRUint32 existing_size = GetSizeIs(index, PR_TRUE); + if (nch != existing_size) { + PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch); + BREAK_FALSE; + } + // It we have an "inout" param, but an "in" count, then + // it is probably a buffer the caller expects us to + // fill in-place! + bBackFill = pi->IsIn(); + } + if (bBackFill) { + memcpy(*(char **)ns_v.val.p, sz, nch); + } else { + // If we have an existing string, free it! + char **pp = (char **)ns_v.val.p; + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = nsnull; + if (sz==nsnull) // None specified. + break; // Remains NULL. + *pp = (char *)nsMemory::Alloc(nch); + if (*pp==NULL) { + PyErr_NoMemory(); + BREAK_FALSE; + } + memcpy(*pp, sz, nch); + if (bCanSetSizeIs) + rc = SetSizeIs(index, PR_TRUE, nch); + else { + NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size"); + } + } + break; + } + + case nsXPTType::T_PWSTRING_SIZE_IS: { + PRUnichar *sz = nsnull; + PRUint32 nch = 0; + PRUint32 nbytes = 0; + + if (val != Py_None) { +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + val_use = PyUnicode_FromObject(val); + NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!"); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + val_use = val; + Py_INCREF(val_use); +#endif + if (PyUnicode_AsPRUnichar(val_use, &sz, &nch) < 0) + BREAK_FALSE; + nbytes = sizeof(PRUnichar) * nch; + } + PRBool bBackFill = PR_FALSE; + PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE); + // If we can not change the size, check our sequence is correct. + if (!bCanSetSizeIs) { + // It is a buffer the caller prolly wants us to fill in-place! + PRUint32 existing_size = GetSizeIs(index, PR_TRUE); + if (nch != existing_size) { + PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch); + BREAK_FALSE; + } + // It we have an "inout" param, but an "in" count, then + // it is probably a buffer the caller expects us to + // fill in-place! + bBackFill = pi->IsIn(); + } + if (bBackFill) { + memcpy(*(PRUnichar **)ns_v.val.p, sz, nbytes); + } else { + // If it is an existing string, free it. + PRUnichar **pp = (PRUnichar **)ns_v.val.p; + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = sz; + sz = nsnull; + if (bCanSetSizeIs) + rc = SetSizeIs(index, PR_TRUE, nch); + else { + NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size"); + } + } + if (sz) + nsMemory::Free(sz); + break; + } + case nsXPTType::T_ARRAY: { + // If it is an existing array of the correct size, keep it. + PRUint32 sequence_size = 0; + PRUint8 array_type; + nsIID *piid; + nsresult ns = GetArrayType(index, &array_type, &piid); + if (NS_FAILED(ns)) + return ns; + PRUint32 element_size = GetArrayElementSize(array_type); + if (val != Py_None) { + if (!PySequence_Check(val)) { + PyErr_Format(PyExc_TypeError, "Object for xpcom array must be a sequence, not type '%s'", PyXPCOM_ObTypeName(val)); + BREAK_FALSE; + } + sequence_size = PySequence_Length(val); + } + PRUint32 existing_size = GetSizeIs(index, PR_FALSE); + PRBool bBackFill = PR_FALSE; + PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_FALSE); + // If we can not change the size, check our sequence is correct. + if (!bCanSetSizeIs) { + // It is a buffer the caller prolly wants us to fill in-place! + if (sequence_size != existing_size) { + PyErr_Format(PyExc_ValueError, "This function is expecting a sequence of exactly length %d - %d items were passed", existing_size, sequence_size); + BREAK_FALSE; + } + // It we have an "inout" param, but an "in" count, then + // it is probably a buffer the caller expects us to + // fill in-place! + bBackFill = pi->IsIn(); + } + if (bBackFill) + rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid); + else { + // If it is an existing array, free it. + void **pp = (void **)ns_v.val.p; + if (*pp && pi->IsIn()) { + FreeSingleArray(*pp, existing_size, array_type); + nsMemory::Free(*pp); + } + *pp = nsnull; + if (val == Py_None) + break; // Remains NULL. + size_t nbytes = sequence_size * element_size; + if (nbytes==0) nbytes = 1; // avoid assertion about 0 bytes + *pp = (void *)nsMemory::Alloc(nbytes); + memset(*pp, 0, nbytes); + rc = FillSingleArray(*pp, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid); + if (!rc) break; + if (bCanSetSizeIs) + rc = SetSizeIs(index, PR_FALSE, sequence_size); + else { + NS_ABORT_IF_FALSE(GetSizeIs(index, PR_FALSE) == sequence_size, "Can't set sizeis, but string isnt correct size"); + } + } + break; + } + default: + // try and limp along in this case. + // leave rc TRUE + PyXPCOM_LogWarning("Converting Python object for an [out] param - The object type (0x%x) is unknown - leaving param alone!\n", XPT_TDP_TAG(typ)); + break; + } + Py_XDECREF(val_use); + if (!rc) + return NS_ERROR_FAILURE; + return NS_OK; +} + +nsresult PyXPCOM_GatewayVariantHelper::ProcessPythonResult(PyObject *ret_ob) +{ + // NOTE - although we return an nresult, if we leave a Python + // exception set, then our caller may take additional action + // (ie, translating our nsresult to a more appropriate nsresult + // for the Python exception.) + NS_PRECONDITION(!PyErr_Occurred(), "Expecting no Python exception to be pending when processing the return result"); + + nsresult rc = NS_OK; + // If we dont get a tuple back, then the result is only + // an int nresult for the underlying function. + // (ie, the policy is expected to return (NS_OK, user_retval), + // but can also return (say), NS_ERROR_FAILURE + if (PyInt_Check(ret_ob)) + return PyInt_AsLong(ret_ob); + // Now it must be the tuple. + if (!PyTuple_Check(ret_ob) || + PyTuple_Size(ret_ob)!=2 || + !PyInt_Check(PyTuple_GET_ITEM(ret_ob, 0))) { + PyErr_SetString(PyExc_TypeError, "The Python result must be a single integer or a tuple of length==2 and first item an int."); + return NS_ERROR_FAILURE; + } + PyObject *user_result = PyTuple_GET_ITEM(ret_ob, 1); + // Count up how many results our function needs. + int i; + int num_results = 0; + int last_result = -1; // optimization if we only have one - this is it! + int index_retval = -1; + for (i=0;iparams+i; + if (!m_python_type_desc_array[i].is_auto_out) { + if (pi->IsOut() || pi->IsDipper()) { + num_results++; + last_result = i; + } + if (pi->IsRetval()) + index_retval = i; + } + } + + if (num_results==0) { + ; // do nothing + } else if (num_results==1) { + // May or may not be the nominated retval - who cares! + NS_ABORT_IF_FALSE(last_result >=0 && last_result < m_num_type_descs, "Have one result, but dont know its index!"); + rc = BackFillVariant( user_result, last_result ); + } else { + // Loop over each one, filling as we go. + // We allow arbitary sequences here, but _not_ strings + // or Unicode! + // NOTE - We ALWAYS do the nominated retval first. + // The Python pattern is always: + // return retval [, byref1 [, byref2 ...] ] + // But the retval is often the last param described in the info. + if (!PySequence_Check(user_result) || +#if PY_MAJOR_VERSION <= 2 + PyString_Check(user_result) || +#else + PyBytes_Check(user_result) || +#endif + PyUnicode_Check(user_result)) { + PyErr_SetString(PyExc_TypeError, "This function has multiple results, but a sequence was not given to fill them"); + return NS_ERROR_FAILURE; + } + int num_user_results = PySequence_Length(user_result); + // If they havent given enough, we dont really care. + // although a warning is probably appropriate. + if (num_user_results != num_results) { + const char *method_name = m_info->GetName(); + PyXPCOM_LogWarning("The method '%s' has %d out params, but %d were supplied by the Python code\n", + method_name, + num_results, + num_user_results); + } + int this_py_index = 0; + if (index_retval != -1) { + // We always return the nominated result first! + PyObject *sub = PySequence_GetItem(user_result, 0); + if (sub==NULL) + return NS_ERROR_FAILURE; + rc = BackFillVariant(sub, index_retval); + Py_DECREF(sub); + this_py_index = 1; + } + for (i=0;NS_SUCCEEDED(rc) && iGetParamCount();i++) { + // If weve already done it, or dont need to do it! + if (i==index_retval || m_python_type_desc_array[i].is_auto_out) + continue; + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i; + if (pi->IsOut()) { + PyObject *sub = PySequence_GetItem(user_result, this_py_index); + if (sub==NULL) + return NS_ERROR_FAILURE; + rc = BackFillVariant(sub, i); + Py_DECREF(sub); + this_py_index++; + } + } + } + return rc; +} diff --git a/src/libs/xpcom18a4/python/src/dllmain.cpp b/src/libs/xpcom18a4/python/src/dllmain.cpp new file mode 100644 index 00000000..4cc08578 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/dllmain.cpp @@ -0,0 +1,352 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include +#include "nsIThread.h" +#include "nsILocalFile.h" + +#ifdef XP_WIN +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include "windows.h" +#endif + +static PRInt32 g_cLockCount = 0; +static PRLock *g_lockMain = nsnull; + +PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL; + +PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) +PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) +PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) +PyXPCOM_INTERFACE_DEFINE(Py_nsIVariant, nsIVariant, PyMethods_IVariant) +// deprecated, but retained for backward compatibility: +PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete) + +#ifndef PYXPCOM_USE_PYGILSTATE + +//////////////////////////////////////////////////////////// +// Thread-state helpers/global functions. +// Only used if there is no Python PyGILState_* API +// +static PyThreadState *ptsGlobal = nsnull; +PyInterpreterState *PyXPCOM_InterpreterState = nsnull; +PRUintn tlsIndex = 0; + + +// This function must be called at some time when the interpreter lock and state is valid. +// Called by init{module} functions and also COM factory entry point. +void PyXPCOM_InterpreterState_Ensure() +{ + if (PyXPCOM_InterpreterState==NULL) { + PyThreadState *threadStateSave = PyThreadState_Swap(NULL); + if (threadStateSave==NULL) + Py_FatalError("Can not setup interpreter state, as current state is invalid"); + + PyXPCOM_InterpreterState = threadStateSave->interp; + PyThreadState_Swap(threadStateSave); + } +} + +void PyXPCOM_InterpreterState_Free() +{ + PyXPCOM_ThreadState_Free(); + PyXPCOM_InterpreterState = NULL; // Eek - should I be freeing something? +} + +// This structure is stored in the TLS slot. At this stage only a Python thread state +// is kept, but this may change in the future... +struct ThreadData{ + PyThreadState *ts; +}; + +// Ensure that we have a Python thread state available to use. +// If this is called for the first time on a thread, it will allocate +// the thread state. This does NOT change the state of the Python lock. +// Returns TRUE if a new thread state was created, or FALSE if a +// thread state already existed. +PRBool PyXPCOM_ThreadState_Ensure() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + if (pData==NULL) { /* First request on this thread */ + /* Check we have an interpreter state */ + if (PyXPCOM_InterpreterState==NULL) { + Py_FatalError("Can not setup thread state, as have no interpreter state"); + } + pData = (ThreadData *)nsMemory::Alloc(sizeof(ThreadData)); + if (!pData) + Py_FatalError("Out of memory allocating thread state."); + memset(pData, 0, sizeof(*pData)); + if (NS_FAILED( PR_SetThreadPrivate( tlsIndex, pData ) ) ) { + NS_ABORT_IF_FALSE(0, "Could not create thread data for this thread!"); + Py_FatalError("Could not thread private thread data!"); + } + pData->ts = PyThreadState_New(PyXPCOM_InterpreterState); + return PR_TRUE; // Did create a thread state state + } + return PR_FALSE; // Thread state was previously created +} + +// Asuming we have a valid thread state, acquire the Python lock. +void PyXPCOM_InterpreterLock_Acquire() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!"); + PyThreadState *thisThreadState = pData->ts; + PyEval_AcquireThread(thisThreadState); +} + +// Asuming we have a valid thread state, release the Python lock. +void PyXPCOM_InterpreterLock_Release() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!"); + PyThreadState *thisThreadState = pData->ts; + PyEval_ReleaseThread(thisThreadState); +} + +// Free the thread state for the current thread +// (Presumably previously create with a call to +// PyXPCOM_ThreadState_Ensure) +void PyXPCOM_ThreadState_Free() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + if (!pData) return; + PyThreadState *thisThreadState = pData->ts; + PyThreadState_Delete(thisThreadState); + PR_SetThreadPrivate(tlsIndex, NULL); + nsMemory::Free(pData); +} + +void PyXPCOM_ThreadState_Clear() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + PyThreadState *thisThreadState = pData->ts; + PyThreadState_Clear(thisThreadState); +} +#endif // PYXPCOM_USE_PYGILSTATE + +//////////////////////////////////////////////////////////// +// Lock/exclusion global functions. +// +void PyXPCOM_AcquireGlobalLock(void) +{ + NS_PRECONDITION(g_lockMain != nsnull, "Cant acquire a NULL lock!"); + PR_Lock(g_lockMain); +} +void PyXPCOM_ReleaseGlobalLock(void) +{ + NS_PRECONDITION(g_lockMain != nsnull, "Cant release a NULL lock!"); + PR_Unlock(g_lockMain); +} + +void PyXPCOM_DLLAddRef(void) +{ + // Must be thread-safe, although cant have the Python lock! + CEnterLeaveXPCOMFramework _celf; + PRInt32 cnt = PR_AtomicIncrement(&g_cLockCount); + if (cnt==1) { // First call + if (!Py_IsInitialized()) { + Py_Initialize(); + // Make sure our Windows framework is all setup. + PyXPCOM_Globals_Ensure(); + // Make sure we have _something_ as sys.argv. + if (PySys_GetObject((char*)"argv")==NULL) { + PyObject *path = PyList_New(0); +#if PY_MAJOR_VERSION <= 2 + PyObject *str = PyString_FromString(""); +#else + PyObject *str = PyUnicode_FromString(""); +#endif + PyList_Append(path, str); + PySys_SetObject((char*)"argv", path); + Py_XDECREF(path); + Py_XDECREF(str); + } + + // Must force Python to start using thread locks, as + // we are free-threaded (maybe, I think, sometimes :-) + PyEval_InitThreads(); +#ifndef PYXPCOM_USE_PYGILSTATE + // Release Python lock, as first thing we do is re-get it. + ptsGlobal = PyEval_SaveThread(); +#endif + // NOTE: We never finalize Python!! + } + } +} +void PyXPCOM_DLLRelease(void) +{ + PR_AtomicDecrement(&g_cLockCount); +} + +void pyxpcom_construct(void) +{ + g_lockMain = PR_NewLock(); +#ifndef PYXPCOM_USE_PYGILSTATE + PRStatus status; + status = PR_NewThreadPrivateIndex( &tlsIndex, NULL ); + NS_WARN_IF_FALSE(status==0, "Could not allocate TLS storage"); + if (NS_FAILED(status)) { + PR_DestroyLock(g_lockMain); + return; // PR_FALSE; + } +#endif // PYXPCOM_USE_PYGILSTATE + return; // PR_TRUE; +} + +void pyxpcom_destruct(void) +{ + PR_DestroyLock(g_lockMain); +#ifndef PYXPCOM_USE_PYGILSTATE + // I can't locate a way to kill this - + // should I pass a dtor to PR_NewThreadPrivateIndex?? + // TlsFree(tlsIndex); +#endif // PYXPCOM_USE_PYGILSTATE +} + +// Yet another attempt at cross-platform library initialization and finalization. +struct DllInitializer { + DllInitializer() { + pyxpcom_construct(); + } + ~DllInitializer() { + pyxpcom_destruct(); + } +} dll_initializer; + +//////////////////////////////////////////////////////////// +// Other helpers/global functions. +// +PRBool PyXPCOM_Globals_Ensure() +{ + PRBool rc = PR_TRUE; + +#ifndef PYXPCOM_USE_PYGILSTATE + PyXPCOM_InterpreterState_Ensure(); +#endif + + // The exception object - we load it from .py code! + if (PyXPCOM_Error == NULL) { + rc = PR_FALSE; + PyObject *mod = NULL; + + mod = PyImport_ImportModule("xpcom"); + if (mod!=NULL) { + PyXPCOM_Error = PyObject_GetAttrString(mod, "Exception"); + Py_DECREF(mod); + } + rc = (PyXPCOM_Error != NULL); + } + if (!rc) + return rc; + + static PRBool bHaveInitXPCOM = PR_FALSE; + if (!bHaveInitXPCOM) { + nsCOMPtr thread_check; + // xpcom appears to assert if already initialized + // Is there an official way to determine this? + if (NS_FAILED(nsIThread::GetMainThread(getter_AddRefs(thread_check)))) { + // not already initialized. +#ifdef XP_WIN + // On Windows, we need to locate the Mozilla bin + // directory. This by using locating a Moz DLL we depend + // on, and assume it lives in that bin dir. Different + // moz build types (eg, xulrunner, suite) package + // XPCOM itself differently - but all appear to require + // nspr4.dll - so this is what we use. + char landmark[MAX_PATH+1]; + HMODULE hmod = GetModuleHandle("nspr4.dll"); + if (hmod==NULL) { + PyErr_SetString(PyExc_RuntimeError, "We dont appear to be linked against nspr4.dll."); + return PR_FALSE; + } + GetModuleFileName(hmod, landmark, sizeof(landmark)/sizeof(landmark[0])); + char *end = landmark + (strlen(landmark)-1); + while (end > landmark && *end != '\\') + end--; + if (end > landmark) *end = '\0'; + + nsCOMPtr ns_bin_dir; + NS_ConvertASCIItoUCS2 strLandmark(landmark); + NS_NewLocalFile(strLandmark, PR_FALSE, getter_AddRefs(ns_bin_dir)); + nsresult rv = NS_InitXPCOM2(nsnull, ns_bin_dir, nsnull); +#else + // Elsewhere, Mozilla can find it itself (we hope!) + nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); +#endif // XP_WIN + if (NS_FAILED(rv)) { + PyErr_SetString(PyExc_RuntimeError, "The XPCOM subsystem could not be initialized"); + return PR_FALSE; + } + } + // Even if xpcom was already init, we want to flag it as init! + bHaveInitXPCOM = PR_TRUE; + // Register our custom interfaces. + + Py_nsISupports::InitType(); + Py_nsIComponentManager::InitType(); + Py_nsIInterfaceInfoManager::InitType(); + Py_nsIEnumerator::InitType(); + Py_nsISimpleEnumerator::InitType(); + Py_nsIInterfaceInfo::InitType(); + Py_nsIInputStream::InitType(); + Py_nsIClassInfo::InitType(); + Py_nsIVariant::InitType(); + // for backward compatibility: + Py_nsIComponentManagerObsolete::InitType(); + + } + return rc; +} + diff --git a/src/libs/xpcom18a4/python/src/loader/pyloader.cpp b/src/libs/xpcom18a4/python/src/loader/pyloader.cpp new file mode 100644 index 00000000..dc116f1d --- /dev/null +++ b/src/libs/xpcom18a4/python/src/loader/pyloader.cpp @@ -0,0 +1,435 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// pyloader +// +// Not part of the main Python _xpcom package, but a separate, thin DLL. +// +// The main loader and registrar for Python. A thin DLL that is designed to live in +// the xpcom "components" directory. Simply locates and loads the standard +// pyxpcom core library and transfers control to that. + +#include + +#include "nsDirectoryServiceDefs.h" +#include "nsILocalFile.h" + +#include "nspr.h" // PR_fprintf + +#if (PY_VERSION_HEX >= 0x02030000) +#define PYXPCOM_USE_PYGILSTATE +#endif + +static char *PyTraceback_AsString(PyObject *exc_tb); + +#ifdef XP_WIN +#include "windows.h" +#endif + +#ifdef XP_UNIX +#include +#include + +#endif + +#include "nsITimelineService.h" + +typedef nsresult (*pfnPyXPCOM_NSGetModule)(nsIComponentManager *servMgr, + nsIFile* location, + nsIModule** result); + + +static void LogError(const char *fmt, ...); +static void LogDebug(const char *fmt, ...); + +// Ensure that any paths guaranteed by this package exist on sys.path +// Only called once as we are first loaded into the process. +void AddStandardPaths() +{ + // Put {bin}\Python on the path if it exists. + nsresult rv; + nsCOMPtr aFile; + rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(aFile)); + if (NS_FAILED(rv)) { + LogError("The Python XPCOM loader could not locate the 'bin' directory\n"); + return; + } + aFile->Append(NS_LITERAL_STRING("python")); + nsAutoString pathBuf; + aFile->GetPath(pathBuf); + PyObject *obPath = PySys_GetObject("path"); + if (!obPath) { + LogError("The Python XPCOM loader could not get the Python sys.path variable\n"); + return; + } + NS_LossyConvertUCS2toASCII pathCBuf(pathBuf); + LogDebug("The Python XPCOM loader is adding '%s' to sys.path\n", pathCBuf.get()); + PyObject *newStr = PyString_FromString(pathCBuf.get()); + PyList_Insert(obPath, 0, newStr); + Py_XDECREF(newStr); + // And now try and get Python to process this directory as a "site dir" + // - ie, look for .pth files, etc + nsCAutoString cmdBuf(NS_LITERAL_CSTRING("import site;site.addsitedir(r'") + pathCBuf + NS_LITERAL_CSTRING("')\n")); + if (0 != PyRun_SimpleString((char *)cmdBuf.get())) { + LogError("The directory '%s' could not be added as a site directory", pathCBuf.get()); + PyErr_Clear(); + } + // and somewhat like Python itself (site, citecustomize), we attempt + // to import "sitepyxpcom" ignoring ImportError + if (NULL==PyImport_ImportModule("sitepyxpcom")) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + LogError("Failed to import 'sitepyxpcom'"); + PyErr_Clear(); + } +} + +//////////////////////////////////////////////////////////// +// This is the main entry point that delegates into Python +nsresult PyXPCOM_NSGetModule(nsIComponentManager *servMgr, + nsIFile* location, + nsIModule** result) +{ + NS_PRECONDITION(result!=NULL, "null result pointer in PyXPCOM_NSGetModule!"); + NS_PRECONDITION(location!=NULL, "null nsIFile pointer in PyXPCOM_NSGetModule!"); + NS_PRECONDITION(servMgr!=NULL, "null servMgr pointer in PyXPCOM_NSGetModule!"); +#ifndef LOADER_LINKS_WITH_PYTHON + if (!Py_IsInitialized()) { + Py_Initialize(); + if (!Py_IsInitialized()) { + PyXPCOM_LogError("Python initialization failed!\n"); + return NS_ERROR_FAILURE; + } + PyEval_InitThreads(); +#ifndef PYXPCOM_USE_PYGILSTATE + PyXPCOM_InterpreterState_Ensure(); +#endif + PyEval_SaveThread(); + } +#endif // LOADER_LINKS_WITH_PYTHON + CEnterLeavePython _celp; + PyObject *func = NULL; + PyObject *obServMgr = NULL; + PyObject *obLocation = NULL; + PyObject *wrap_ret = NULL; + PyObject *args = NULL; + PyObject *mod = PyImport_ImportModule("xpcom.server"); + if (!mod) goto done; + func = PyObject_GetAttrString(mod, "NS_GetModule"); + if (func==NULL) goto done; + obServMgr = Py_nsISupports::PyObjectFromInterface(servMgr, NS_GET_IID(nsIComponentManager)); + if (obServMgr==NULL) goto done; + obLocation = Py_nsISupports::PyObjectFromInterface(location, NS_GET_IID(nsIFile)); + if (obLocation==NULL) goto done; + args = Py_BuildValue("OO", obServMgr, obLocation); + if (args==NULL) goto done; + wrap_ret = PyEval_CallObject(func, args); + if (wrap_ret==NULL) goto done; + Py_nsISupports::InterfaceFromPyObject(wrap_ret, NS_GET_IID(nsIModule), (nsISupports **)result, PR_FALSE, PR_FALSE); +done: + nsresult nr = NS_OK; + if (PyErr_Occurred()) { + PyXPCOM_LogError("Obtaining the module object from Python failed.\n"); + nr = PyXPCOM_SetCOMErrorFromPyException(); + } + Py_XDECREF(func); + Py_XDECREF(obServMgr); + Py_XDECREF(obLocation); + Py_XDECREF(wrap_ret); + Py_XDECREF(mod); + Py_XDECREF(args); + return nr; +} + +extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, + nsIFile* location, + nsIModule** result) +{ +#ifdef XP_UNIX + // *sob* - seems necessary to open the .so as RTLD_GLOBAL + dlopen(PYTHON_SO,RTLD_NOW | RTLD_GLOBAL); +#endif + PRBool bDidInitPython = !Py_IsInitialized(); // well, I will next line, anyway :-) + if (bDidInitPython) { + NS_TIMELINE_START_TIMER("PyXPCOM: Python initializing"); + Py_Initialize(); + if (!Py_IsInitialized()) { + LogError("Python initialization failed!\n"); + return NS_ERROR_FAILURE; + } +#ifndef NS_DEBUG + Py_OptimizeFlag = 1; +#endif // NS_DEBUG + PyEval_InitThreads(); + NS_TIMELINE_STOP_TIMER("PyXPCOM: Python initializing"); + NS_TIMELINE_MARK_TIMER("PyXPCOM: Python initializing"); + } + // Get the Python interpreter state + NS_TIMELINE_START_TIMER("PyXPCOM: Python threadstate setup"); +#ifndef PYXPCOM_USE_PYGILSTATE + PyThreadState *threadStateCreated = NULL; + PyThreadState *threadState = PyThreadState_Swap(NULL); + if (threadState==NULL) { + // no thread-state - set one up. + // *sigh* - what I consider a bug is that Python + // will deadlock unless we own the lock before creating + // a new interpreter (it appear Py_NewInterpreter has + // really only been tested/used with no thread lock + PyEval_AcquireLock(); + threadState = threadStateCreated = Py_NewInterpreter(); + PyThreadState_Swap(NULL); + } + PyEval_ReleaseLock(); + PyEval_AcquireThread(threadState); +#else + PyGILState_STATE state = PyGILState_Ensure(); +#endif // PYXPCOM_USE_PYGILSTATE +#ifdef MOZ_TIMELINE + // If the timeline service is installed, see if we can install our hooks. + if (NULL==PyImport_ImportModule("timeline_hook")) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + LogError("Failed to import 'timeline_hook'"); + PyErr_Clear(); // but don't care if we can't. + } +#endif + // Add the standard paths always - we may not have been the first to + // init Python. + AddStandardPaths(); + +#ifndef PYXPCOM_USE_PYGILSTATE + // Abandon the thread-lock, as the first thing Python does + // is re-establish the lock (the Python thread-state story SUCKS!!!) + if (threadStateCreated) { + Py_EndInterpreter(threadStateCreated); + PyEval_ReleaseLock(); // see Py_NewInterpreter call above + } else { + PyEval_ReleaseThread(threadState); + PyThreadState *threadStateSave = PyThreadState_Swap(NULL); + if (threadStateSave) + PyThreadState_Delete(threadStateSave); + } +#else + // If we initialized Python, then we will also have acquired the thread + // lock. In that case, we want to leave it unlocked, so other threads + // are free to run, even if they aren't running Python code. + PyGILState_Release(bDidInitPython ? PyGILState_UNLOCKED : state); +#endif + + NS_TIMELINE_STOP_TIMER("PyXPCOM: Python threadstate setup"); + NS_TIMELINE_MARK_TIMER("PyXPCOM: Python threadstate setup"); + NS_TIMELINE_START_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); + nsresult rc = PyXPCOM_NSGetModule(servMgr, location, result); + NS_TIMELINE_STOP_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); + NS_TIMELINE_MARK_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); + return rc; +} + +// The internal helper that actually moves the +// formatted string to the target! + +void LogMessage(const char *prefix, const char *pszMessageText) +{ + PR_fprintf(PR_STDERR, "%s", pszMessageText); +} + +void LogMessage(const char *prefix, nsACString &text) +{ + LogMessage(prefix, nsPromiseFlatCString(text).get()); +} + +// A helper for the various logging routines. +static void VLogF(const char *prefix, const char *fmt, va_list argptr) +{ + char buff[512]; + + vsprintf(buff, fmt, argptr); + + LogMessage(prefix, buff); +} + +static void LogError(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF("PyXPCOM Loader Error: ", fmt, marker); + // If we have a Python exception, also log that: + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); + if (exc_typ) { + nsCAutoString streamout; + + if (exc_tb) { + const char *szTraceback = PyTraceback_AsString(exc_tb); + if (szTraceback == NULL) + streamout += "Can't get the traceback info!"; + else { + streamout += "Traceback (most recent call last):\n"; + streamout += szTraceback; + PyMem_Free((void *)szTraceback); + } + } + PyObject *temp = PyObject_Str(exc_typ); + if (temp) { + streamout += PyString_AsString(temp); + Py_DECREF(temp); + } else + streamout += "Can convert exception to a string!"; + streamout += ": "; + if (exc_val != NULL) { + temp = PyObject_Str(exc_val); + if (temp) { + streamout += PyString_AsString(temp); + Py_DECREF(temp); + } else + streamout += "Can convert exception value to a string!"; + } + streamout += "\n"; + LogMessage("PyXPCOM Exception:", streamout); + } + PyErr_Restore(exc_typ, exc_val, exc_tb); + va_end(marker); +} +/*** - not currently used - silence compiler warning. +static void LogWarning(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF("PyXPCOM Loader Warning: ", fmt, marker); +} +***/ +#ifdef DEBUG +static void LogDebug(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF("PyXPCOM Loader Debug: ", fmt, marker); + va_end(marker); +} +#else +static void LogDebug(const char *fmt, ...) +{ +} +#endif + +/* Obtains a string from a Python traceback. + This is the exact same string as "traceback.print_exc" would return. + + Pass in a Python traceback object (probably obtained from PyErr_Fetch()) + Result is a string which must be free'd using PyMem_Free() +*/ +#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;} + +char *PyTraceback_AsString(PyObject *exc_tb) +{ + char *errMsg = NULL; /* a static that hold a local error message */ + char *result = NULL; /* a valid, allocated result. */ + PyObject *modStringIO = NULL; + PyObject *modTB = NULL; + PyObject *obFuncStringIO = NULL; + PyObject *obStringIO = NULL; + PyObject *obFuncTB = NULL; + PyObject *argsTB = NULL; + PyObject *obResult = NULL; + + /* Import the modules we need - cStringIO and traceback */ + modStringIO = PyImport_ImportModule("cStringIO"); + if (modStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant import cStringIO\n"); + + modTB = PyImport_ImportModule("traceback"); + if (modTB==NULL) + TRACEBACK_FETCH_ERROR("cant import traceback\n"); + /* Construct a cStringIO object */ + obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n"); + obStringIO = PyObject_CallObject(obFuncStringIO, NULL); + if (obStringIO==NULL) + TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n"); + /* Get the traceback.print_exception function, and call it. */ + obFuncTB = PyObject_GetAttrString(modTB, "print_tb"); + if (obFuncTB==NULL) + TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n"); + + argsTB = Py_BuildValue("OOO", + exc_tb ? exc_tb : Py_None, + Py_None, + obStringIO); + if (argsTB==NULL) + TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n"); + + obResult = PyObject_CallObject(obFuncTB, argsTB); + if (obResult==NULL) + TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n"); + /* Now call the getvalue() method in the StringIO instance */ + Py_DECREF(obFuncStringIO); + obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find getvalue function\n"); + Py_DECREF(obResult); + obResult = PyObject_CallObject(obFuncStringIO, NULL); + if (obResult==NULL) + TRACEBACK_FETCH_ERROR("getvalue() failed.\n"); + + /* And it should be a string all ready to go - duplicate it. */ + if (!PyString_Check(obResult)) + TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n"); + + { // a temp scope so I can use temp locals. + char *tempResult = PyString_AsString(obResult); + result = (char *)PyMem_Malloc(strlen(tempResult)+1); + if (result==NULL) + TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string"); + + strcpy(result, tempResult); + } // end of temp scope. +done: + /* All finished - first see if we encountered an error */ + if (result==NULL && errMsg != NULL) { + result = (char *)PyMem_Malloc(strlen(errMsg)+1); + if (result != NULL) + /* if it does, not much we can do! */ + strcpy(result, errMsg); + } + Py_XDECREF(modStringIO); + Py_XDECREF(modTB); + Py_XDECREF(obFuncStringIO); + Py_XDECREF(obStringIO); + Py_XDECREF(obFuncTB); + Py_XDECREF(argsTB); + Py_XDECREF(obResult); + return result; +} diff --git a/src/libs/xpcom18a4/python/src/module/_xpcom.cpp b/src/libs/xpcom18a4/python/src/module/_xpcom.cpp new file mode 100644 index 00000000..d40d2b52 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/module/_xpcom.cpp @@ -0,0 +1,950 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM.h" +#include "nsXPCOM.h" +#include "nsISupportsPrimitives.h" +#include "nsIFile.h" +#include "nsIComponentRegistrar.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIConsoleService.h" +#include "nspr.h" // PR_fprintf +#ifdef VBOX +# include "nsEventQueueUtils.h" +#endif + +#ifdef XP_WIN +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include "windows.h" +#endif + +#include "nsIEventQueue.h" +#include "nsIProxyObjectManager.h" + +#define LOADER_LINKS_WITH_PYTHON + +#ifndef PYXPCOM_USE_PYGILSTATE +extern PYXPCOM_EXPORT void PyXPCOM_InterpreterState_Ensure(); +#endif + +#ifdef VBOX_PYXPCOM +# include +# include +# ifndef MODULE_NAME_SUFFIX +# define MANGLE_MODULE_NAME(a_szName) a_szName +# define MANGLE_MODULE_INIT(a_Name) a_Name +# else +# define MANGLE_MODULE_NAME(a_szName) a_szName RT_XSTR(MODULE_NAME_SUFFIX) +# define MANGLE_MODULE_INIT(a_Name) RT_CONCAT(a_Name, MODULE_NAME_SUFFIX) +# endif +# if defined(VBOX_PYXPCOM_VERSIONED) && !defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# if PY_VERSION_HEX >= 0x030a0000 && PY_VERSION_HEX < 0x030b0000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_10") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_10) + +# elif PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_9") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_9) + +# elif PY_VERSION_HEX >= 0x03080000 && PY_VERSION_HEX < 0x03090000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_8") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_8) + +# elif PY_VERSION_HEX >= 0x03070000 && PY_VERSION_HEX < 0x03080000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_7") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_7) + +# elif PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x03070000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_6") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_6) + +# elif PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03060000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_5") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_5) + +# elif PY_VERSION_HEX >= 0x03040000 && PY_VERSION_HEX < 0x03050000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_4") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_4) + +# elif PY_VERSION_HEX >= 0x03030000 && PY_VERSION_HEX < 0x03040000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_3") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_3) + +# elif PY_VERSION_HEX >= 0x03020000 && PY_VERSION_HEX < 0x03030000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_2") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_2) + +# elif PY_VERSION_HEX >= 0x03010000 && PY_VERSION_HEX < 0x03020000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_1") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_1) + +# elif PY_VERSION_HEX >= 0x02080000 && PY_VERSION_HEX < 0x02090000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_8") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_8) + +# elif PY_VERSION_HEX >= 0x02070000 && PY_VERSION_HEX < 0x02080000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_7") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_7) + +# elif PY_VERSION_HEX >= 0x02060000 && PY_VERSION_HEX < 0x02070000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_6") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_6) +# else +# error "Fix module versioning. This Python version is not recognized." +# endif +# else +# if PY_MAJOR_VERSION <= 2 && defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2) +# elif PY_MAJOR_VERSION <= 2 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython) +# elif defined(Py_LIMITED_API) || defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3) +# else +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython) +# endif +# endif +#else +#define MODULE_NAME "_xpcom" +#endif + +// "boot-strap" methods - interfaces we need to get the base +// interface support! + +#ifndef VBOX +/* deprecated, included for backward compatibility */ +static PyObject * +PyXPCOMMethod_NS_GetGlobalComponentManager(PyObject *self, PyObject *args) +{ + if (PyErr_Warn(PyExc_DeprecationWarning, "Use GetComponentManager instead") < 0) + return NULL; + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentManager(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + nsCOMPtr ocm(do_QueryInterface(cm, &rv)); + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(ocm, NS_GET_IID(nsIComponentManagerObsolete), PR_FALSE); +} +#endif + +static PyObject * +PyXPCOMMethod_GetComponentManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentManager(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsIComponentManager), PR_FALSE); +} + +// No xpcom callable way to get at the registrar, even though the interface +// is scriptable. +static PyObject * +PyXPCOMMethod_GetComponentRegistrar(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentRegistrar(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsISupports), PR_FALSE); +} + +static PyObject * +PyXPCOMMethod_GetServiceManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr sm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetServiceManager(getter_AddRefs(sm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + // Return a type based on the IID. + return Py_nsISupports::PyObjectFromInterface(sm, NS_GET_IID(nsIServiceManager)); +} + +#ifndef VBOX +/* deprecated, included for backward compatibility */ +static PyObject * +PyXPCOMMethod_GetGlobalServiceManager(PyObject *self, PyObject *args) +{ + if (PyErr_Warn(PyExc_DeprecationWarning, "Use GetServiceManager instead") < 0) + return NULL; + + return PyXPCOMMethod_GetComponentManager(self, args); +} +#endif + +static PyObject * +PyXPCOMMethod_XPTI_GetInterfaceInfoManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsIInterfaceInfoManager* im; + Py_BEGIN_ALLOW_THREADS; + im = XPTI_GetInterfaceInfoManager(); + Py_END_ALLOW_THREADS; + if ( im == nsnull ) + return PyXPCOM_BuildPyException(NS_ERROR_FAILURE); + + /* Return a type based on the IID (with no extra ref) */ + // Can not auto-wrap the interface info manager as it is critical to + // building the support we need for autowrap. + PyObject *ret = Py_nsISupports::PyObjectFromInterface(im, NS_GET_IID(nsIInterfaceInfoManager), PR_FALSE); + NS_IF_RELEASE(im); + return ret; +} + +static PyObject * +PyXPCOMMethod_XPTC_InvokeByIndex(PyObject *self, PyObject *args) +{ + PyObject *obIS, *obParams; + nsCOMPtr pis; + int index; + + // We no longer rely on PyErr_Occurred() for our error state, + // but keeping this assertion can't hurt - it should still always be true! + NS_WARN_IF_FALSE(!PyErr_Occurred(), "Should be no pending Python error!"); + + if (!PyArg_ParseTuple(args, "OiO", &obIS, &index, &obParams)) + return NULL; + + if (!Py_nsISupports::Check(obIS)) { + return PyErr_Format(PyExc_TypeError, + "First param must be a native nsISupports wrapper (got %s)", + PyXPCOM_ObTypeName(obIS)); + } + // Ack! We must ask for the "native" interface supported by + // the object, not specifically nsISupports, else we may not + // back the same pointer (eg, Python, following identity rules, + // will return the "original" gateway when QI'd for nsISupports) + if (!Py_nsISupports::InterfaceFromPyObject( + obIS, + Py_nsIID_NULL, + getter_AddRefs(pis), + PR_FALSE)) + return NULL; + + PyXPCOM_InterfaceVariantHelper arg_helper((Py_nsISupports *)obIS, index); + if (!arg_helper.Init(obParams)) + return NULL; + + if (!arg_helper.FillArray()) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = XPTC_InvokeByIndex(pis, index, arg_helper.m_num_array, arg_helper.m_var_array); +/** @todo bird: Maybe we could processing pending XPCOM events here to make + * life a bit simpler inside python? */ + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return arg_helper.MakePythonResult(); +} + +static PyObject * +PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args) +{ + PyObject *ob, *obIID; + int bWrapClient = 1; + if (!PyArg_ParseTuple(args, "OO|i", &ob, &obIID, &bWrapClient)) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr ret; + nsresult r = PyXPCOM_XPTStub::CreateNew(ob, iid, getter_AddRefs(ret)); + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + // _ALL_ wrapped objects are associated with a weak-ref + // to their "main" instance. + AddDefaultGateway(ob, ret); // inject a weak reference to myself into the instance. + + // Now wrap it in an interface. + return Py_nsISupports::PyObjectFromInterface(ret, iid, bWrapClient); +} + +static PyObject * +PyXPCOMMethod_UnwrapObject(PyObject *self, PyObject *args) +{ + PyObject *ob; + if (!PyArg_ParseTuple(args, "O", &ob)) + return NULL; + + nsISupports *uob = NULL; + nsIInternalPython *iob = NULL; + PyObject *ret = NULL; + if (!Py_nsISupports::InterfaceFromPyObject(ob, + NS_GET_IID(nsISupports), + &uob, + PR_FALSE)) + goto done; + if (NS_FAILED(uob->QueryInterface(NS_GET_IID(nsIInternalPython), reinterpret_cast(&iob)))) { + PyErr_SetString(PyExc_ValueError, "This XPCOM object is not implemented by Python"); + goto done; + } + ret = iob->UnwrapPythonObject(); +done: + Py_BEGIN_ALLOW_THREADS; + NS_IF_RELEASE(uob); + NS_IF_RELEASE(iob); + Py_END_ALLOW_THREADS; + return ret; +} + +// @pymethod int|pythoncom|_GetInterfaceCount|Retrieves the number of interface objects currently in existance +static PyObject * +PyXPCOMMethod_GetInterfaceCount(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":_GetInterfaceCount")) + return NULL; + return PyInt_FromLong(_PyXPCOM_GetInterfaceCount()); + // @comm If is occasionally a good idea to call this function before your Python program + // terminates. If this function returns non-zero, then you still have PythonCOM objects + // alive in your program (possibly in global variables). +} + +#ifdef VBOX_DEBUG_LIFETIMES +// @pymethod int|pythoncom|_DumpInterfaces|Dumps the interfaces still in existance to standard output +static PyObject * +PyXPCOMMethod_DumpInterfaces(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":_DumpInterfaces")) + return NULL; + return PyInt_FromLong(_PyXPCOM_DumpInterfaces()); +} +#endif + +// @pymethod int|pythoncom|_GetGatewayCount|Retrieves the number of gateway objects currently in existance +static PyObject * +PyXPCOMMethod_GetGatewayCount(PyObject *self, PyObject *args) +{ + // @comm This is the number of Python object that implement COM servers which + // are still alive (ie, serving a client). The only way to reduce this count + // is to have the process which uses these PythonCOM servers release its references. + if (!PyArg_ParseTuple(args, ":_GetGatewayCount")) + return NULL; + return PyInt_FromLong(_PyXPCOM_GetGatewayCount()); +} + +static PyObject * +PyXPCOMMethod_NS_ShutdownXPCOM(PyObject *self, PyObject *args) +{ + // @comm This is the number of Python object that implement COM servers which + // are still alive (ie, serving a client). The only way to reduce this count + // is to have the process which uses these PythonCOM servers release its references. + if (!PyArg_ParseTuple(args, ":NS_ShutdownXPCOM")) + return NULL; + nsresult nr; + Py_BEGIN_ALLOW_THREADS; + nr = NS_ShutdownXPCOM(nsnull); + Py_END_ALLOW_THREADS; + +#ifdef VBOX_DEBUG_LIFETIME + Py_nsISupports::dumpList(); +#endif + + // Dont raise an exception - as we are probably shutting down + // and dont really case - just return the status + return PyInt_FromLong(nr); +} + +static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); + +// A hack to work around their magic constants! +static PyObject * +PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args) +{ + PyObject *obQueue, *obIID, *obOb; + int flags; + if (!PyArg_ParseTuple(args, "OOOi", &obQueue, &obIID, &obOb, &flags)) + return NULL; + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsCOMPtr pob; + if (!Py_nsISupports::InterfaceFromPyObject(obOb, iid, getter_AddRefs(pob), PR_FALSE)) + return NULL; + nsIEventQueue *pQueue = NULL; + nsIEventQueue *pQueueRelease = NULL; + + if (PyInt_Check(obQueue)) { + pQueue = (nsIEventQueue *)PyInt_AsLong(obQueue); + } else { + if (!Py_nsISupports::InterfaceFromPyObject(obQueue, NS_GET_IID(nsIEventQueue), (nsISupports **)&pQueue, PR_TRUE)) + return NULL; + pQueueRelease = pQueue; + } + + nsresult rv_proxy; + nsCOMPtr presult; + Py_BEGIN_ALLOW_THREADS; + nsCOMPtr proxyMgr = + do_GetService(kProxyObjectManagerCID, &rv_proxy); + + if ( NS_SUCCEEDED(rv_proxy) ) { + rv_proxy = proxyMgr->GetProxyForObject(pQueue, + iid, + pob, + flags, + getter_AddRefs(presult)); + } + if (pQueueRelease) + pQueueRelease->Release(); + Py_END_ALLOW_THREADS; + + PyObject *result; + if (NS_SUCCEEDED(rv_proxy) ) { + result = Py_nsISupports::PyObjectFromInterface(presult, iid); + } else { + result = PyXPCOM_BuildPyException(rv_proxy); + } + return result; +} + +static PyObject * +PyXPCOMMethod_MakeVariant(PyObject *self, PyObject *args) +{ + PyObject *ob; + if (!PyArg_ParseTuple(args, "O:MakeVariant", &ob)) + return NULL; + nsCOMPtr pVar; + nsresult nr = PyObject_AsVariant(ob, getter_AddRefs(pVar)); + if (NS_FAILED(nr)) + return PyXPCOM_BuildPyException(nr); + if (pVar == nsnull) { + NS_ERROR("PyObject_AsVariant worked but returned a NULL ptr!"); + return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + } + return Py_nsISupports::PyObjectFromInterface(pVar, NS_GET_IID(nsIVariant)); +} + +static PyObject * +PyXPCOMMethod_GetVariantValue(PyObject *self, PyObject *args) +{ + PyObject *ob, *obParent = NULL; + if (!PyArg_ParseTuple(args, "O|O:GetVariantValue", &ob, &obParent)) + return NULL; + + nsCOMPtr var; + if (!Py_nsISupports::InterfaceFromPyObject(ob, + NS_GET_IID(nsISupports), + getter_AddRefs(var), + PR_FALSE)) + return PyErr_Format(PyExc_ValueError, + "Object is not an nsIVariant (got %s)", + PyXPCOM_ObTypeName(ob)); + + Py_nsISupports *parent = nsnull; + if (obParent && obParent != Py_None) { + if (!Py_nsISupports::Check(obParent)) { + PyErr_SetString(PyExc_ValueError, + "Object not an nsISupports wrapper"); + return NULL; + } + parent = (Py_nsISupports *)obParent; + } + return PyObject_FromVariant(parent, var); +} + +PyObject *PyGetSpecialDirectory(PyObject *self, PyObject *args) +{ + char *dirname; + if (!PyArg_ParseTuple(args, "s:GetSpecialDirectory", &dirname)) + return NULL; + nsCOMPtr file; + nsresult r = NS_GetSpecialDirectory(dirname, getter_AddRefs(file)); + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + // returned object swallows our reference. + return Py_nsISupports::PyObjectFromInterface(file, NS_GET_IID(nsIFile)); +} + +PyObject *AllocateBuffer(PyObject *self, PyObject *args) +{ + int bufSize; + if (!PyArg_ParseTuple(args, "i", &bufSize)) + return NULL; +#if PY_MAJOR_VERSION <= 2 + return PyBuffer_New(bufSize); +#else + return PyBytes_FromStringAndSize(NULL, bufSize); +#endif +} + +// Writes a message to the console service. This could be done via pure +// Python code, but is useful when the logging code is actually the +// xpcom .py framework itself (ie, we don't want our logging framework to +// call back into the very code generating the log messages! +PyObject *LogConsoleMessage(PyObject *self, PyObject *args) +{ + char *msg; + if (!PyArg_ParseTuple(args, "s", &msg)) + return NULL; + + nsCOMPtr consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (consoleService) + consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(msg).get()); + else { + // This either means no such service, or in shutdown - hardly worth + // the warning, and not worth reporting an error to Python about - its + // log handler would just need to catch and ignore it. + // And as this is only called by this logging setup, any messages should + // still go to stderr or a logfile. + NS_WARNING("pyxpcom can't log console message."); + } + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef VBOX + +# include +# include + +static PyObject * +PyXPCOMMethod_WaitForEvents(PyObject *self, PyObject *args) +{ + long lTimeout; + if (!PyArg_ParseTuple(args, "l", &lTimeout)) + return NULL; + + int rc; + com::NativeEventQueue* aEventQ = com::NativeEventQueue::getMainEventQueue(); + NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue"); + if (!aEventQ) + { + PyErr_SetString(PyExc_TypeError, "the main event queue is NULL"); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + + RTMSINTERVAL cMsTimeout = (RTMSINTERVAL)lTimeout; + if (lTimeout < 0 || (long)cMsTimeout != lTimeout) + cMsTimeout = RT_INDEFINITE_WAIT; + rc = aEventQ->processEventQueue(cMsTimeout); + + Py_END_ALLOW_THREADS + if (RT_SUCCESS(rc)) + return PyInt_FromLong(0); + + if ( rc == VERR_TIMEOUT + || rc == VERR_INTERRUPTED) + return PyInt_FromLong(1); + + if (rc == VERR_INVALID_CONTEXT) + { + PyErr_SetString(PyExc_Exception, "wrong thread, use the main thread"); + return NULL; + } + + return PyInt_FromLong(2); +} + +static PyObject* +PyXPCOMMethod_InterruptWait(PyObject *self, PyObject *args) +{ + com::NativeEventQueue* aEventQ = com::NativeEventQueue::getMainEventQueue(); + NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue"); + if (!aEventQ) + return NULL; + + int rc = aEventQ->interruptEventQueueProcessing(); + return PyBool_FromLong(RT_SUCCESS(rc)); +} + +static nsresult deinitVBoxPython(); + +static PyObject* +PyXPCOMMethod_DeinitCOM(PyObject *self, PyObject *args) +{ + nsresult nr; + Py_BEGIN_ALLOW_THREADS; + nr = deinitVBoxPython(); + Py_END_ALLOW_THREADS; + return PyInt_FromLong(nr); +} + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +static PyObject* +PyXPCOMMethod_AttachThread(PyObject *self, PyObject *args) +{ + nsresult rv; + PRInt32 result = 0; + nsCOMPtr eqs; + + // Create the Event Queue for this thread... + Py_BEGIN_ALLOW_THREADS; + eqs = + do_GetService(kEventQueueServiceCID, &rv); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 1; + goto done; + } + + Py_BEGIN_ALLOW_THREADS; + rv = eqs->CreateThreadEventQueue(); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 2; + goto done; + } + + done: + /** @todo: better throw an exception on error */ + return PyInt_FromLong(result); +} + +static PyObject* +PyXPCOMMethod_DetachThread(PyObject *self, PyObject *args) +{ + nsresult rv; + PRInt32 result = 0; + nsCOMPtr eqs; + + // Destroy the Event Queue for this thread... + Py_BEGIN_ALLOW_THREADS; + eqs = + do_GetService(kEventQueueServiceCID, &rv); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 1; + goto done; + } + + Py_BEGIN_ALLOW_THREADS; + rv = eqs->DestroyThreadEventQueue(); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 2; + goto done; + } + + done: + /** @todo: better throw an exception on error */ + return PyInt_FromLong(result); +} + +#endif /* VBOX */ + +extern PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args); + +static struct PyMethodDef xpcom_methods[]= +{ + {"GetComponentManager", PyXPCOMMethod_GetComponentManager, 1}, + {"GetComponentRegistrar", PyXPCOMMethod_GetComponentRegistrar, 1}, +#ifndef VBOX + {"NS_GetGlobalComponentManager", PyXPCOMMethod_NS_GetGlobalComponentManager, 1}, // deprecated +#endif + {"XPTI_GetInterfaceInfoManager", PyXPCOMMethod_XPTI_GetInterfaceInfoManager, 1}, + {"XPTC_InvokeByIndex", PyXPCOMMethod_XPTC_InvokeByIndex, 1}, + {"GetServiceManager", PyXPCOMMethod_GetServiceManager, 1}, +#ifndef VBOX + {"GetGlobalServiceManager", PyXPCOMMethod_GetGlobalServiceManager, 1}, // deprecated + {"IID", PyXPCOMMethod_IID, 1}, // IID is wrong - deprecated - not just IID, but CID, etc. +#endif + {"ID", PyXPCOMMethod_IID, 1}, // This is the official name. + {"NS_ShutdownXPCOM", PyXPCOMMethod_NS_ShutdownXPCOM, 1}, + {"WrapObject", PyXPCOMMethod_WrapObject, 1}, + {"UnwrapObject", PyXPCOMMethod_UnwrapObject, 1}, + {"_GetInterfaceCount", PyXPCOMMethod_GetInterfaceCount, 1}, + {"_GetGatewayCount", PyXPCOMMethod_GetGatewayCount, 1}, + {"getProxyForObject", PyXPCOMMethod_GetProxyForObject, 1}, + {"GetProxyForObject", PyXPCOMMethod_GetProxyForObject, 1}, + {"GetSpecialDirectory", PyGetSpecialDirectory, 1}, + {"AllocateBuffer", AllocateBuffer, 1}, + {"LogConsoleMessage", LogConsoleMessage, 1, "Write a message to the xpcom console service"}, + {"MakeVariant", PyXPCOMMethod_MakeVariant, 1}, + {"GetVariantValue", PyXPCOMMethod_GetVariantValue, 1}, +#ifdef VBOX + {"WaitForEvents", PyXPCOMMethod_WaitForEvents, 1}, + {"InterruptWait", PyXPCOMMethod_InterruptWait, 1}, + {"DeinitCOM", PyXPCOMMethod_DeinitCOM, 1}, + {"AttachThread", PyXPCOMMethod_AttachThread, 1}, + {"DetachThread", PyXPCOMMethod_DetachThread, 1}, +#endif +#ifdef VBOX_DEBUG_LIFETIMES + {"_DumpInterfaces", PyXPCOMMethod_DumpInterfaces, 1}, +#endif + // These should no longer be used - just use the logging.getLogger('pyxpcom')... + /* bird: The above comment refers to LogWarning and LogError. Both now removed. */ + { NULL } +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef xpcom_module = +{ + PyModuleDef_HEAD_INIT, + MODULE_NAME, /* name of module */ + NULL, /* module documentation */ + -1, /* size of per-interpreter state or -1 if using globals */ + xpcom_methods +}; +#endif + + +#define REGISTER_IID(t) { \ + PyObject *iid_ob = Py_nsIID::PyObjectFromIID(NS_GET_IID(t)); \ + PyDict_SetItemString(dict, "IID_"#t, iid_ob); \ + Py_DECREF(iid_ob); \ + } + +#define REGISTER_INT(val) { \ + PyObject *ob = PyInt_FromLong(val); \ + PyDict_SetItemString(dict, #val, ob); \ + Py_DECREF(ob); \ + } + + +//////////////////////////////////////////////////////////// +// The module init code. +// +#if PY_MAJOR_VERSION <= 2 +extern "C" NS_EXPORT +void +#else +PyObject * +#endif +init_xpcom() { + PyObject *oModule; + + // ensure the framework has valid state to work with. + if (!PyXPCOM_Globals_Ensure()) +#if PY_MAJOR_VERSION <= 2 + return; +#else + return NULL; +#endif + + // Must force Python to start using thread locks + PyEval_InitThreads(); + + // Create the module and add the functions +#if PY_MAJOR_VERSION <= 2 + oModule = Py_InitModule(MODULE_NAME, xpcom_methods); +#else + oModule = PyModule_Create(&xpcom_module); +#endif + + PyObject *dict = PyModule_GetDict(oModule); + PyObject *pycom_Error = PyXPCOM_Error; + if (pycom_Error == NULL || PyDict_SetItemString(dict, "error", pycom_Error) != 0) + { + PyErr_SetString(PyExc_MemoryError, "can't define error"); +#if PY_MAJOR_VERSION <= 2 + return; +#else + return NULL; +#endif + } +#ifndef Py_LIMITED_API + PyDict_SetItemString(dict, "IIDType", (PyObject *)&Py_nsIID::type); +#else + PyDict_SetItemString(dict, "IIDType", (PyObject *)Py_nsIID::GetTypeObject()); +#endif + + REGISTER_IID(nsISupports); + REGISTER_IID(nsISupportsCString); + REGISTER_IID(nsISupportsString); + REGISTER_IID(nsIModule); + REGISTER_IID(nsIFactory); + REGISTER_IID(nsIWeakReference); + REGISTER_IID(nsISupportsWeakReference); + REGISTER_IID(nsIClassInfo); + REGISTER_IID(nsIServiceManager); + REGISTER_IID(nsIComponentRegistrar); + + // Register our custom interfaces. + REGISTER_IID(nsIComponentManager); + REGISTER_IID(nsIInterfaceInfoManager); + REGISTER_IID(nsIEnumerator); + REGISTER_IID(nsISimpleEnumerator); + REGISTER_IID(nsIInterfaceInfo); + REGISTER_IID(nsIInputStream); + REGISTER_IID(nsIClassInfo); + REGISTER_IID(nsIVariant); + // for backward compatibility: + REGISTER_IID(nsIComponentManagerObsolete); + + // No good reason not to expose this impl detail, and tests can use it + REGISTER_IID(nsIInternalPython); + // We have special support for proxies - may as well add their constants! + REGISTER_INT(PROXY_SYNC); + REGISTER_INT(PROXY_ASYNC); + REGISTER_INT(PROXY_ALWAYS); + // Build flags that may be useful. + PyObject *ob = PyBool_FromLong( +#ifdef NS_DEBUG + 1 +#else + 0 +#endif + ); + PyDict_SetItemString(dict, "NS_DEBUG", ob); + Py_DECREF(ob); +#if PY_MAJOR_VERSION >= 3 + return oModule; +#endif +} + +#ifdef VBOX_PYXPCOM +# include +using namespace com; + +# include +# include +# include +# include + +/** Set if NS_ShutdownXPCOM has been called successfully already and we don't + * need to do it again during module termination. This avoids assertion in the + * VBoxCOM glue code. */ +static bool g_fComShutdownAlready = true; + +# if PY_MAJOR_VERSION <= 2 +extern "C" NS_EXPORT +void +# else +/** @todo r=klaus this is hacky, but as Python3 doesn't deal with ELF + * visibility, assuming that all globals are visible (which is ugly and not + * true in our case). */ +# undef PyMODINIT_FUNC +# define PyMODINIT_FUNC extern "C" NS_EXPORT PyObject* +PyMODINIT_FUNC +# endif +initVBoxPython() { /* NOTE! This name is redefined at the top of the file! */ + static bool s_vboxInited = false; + if (!s_vboxInited) { + int rc = 0; /* Error handling in this code is NON-EXISTING. Sigh. */ + +# if defined(VBOX_PATH_APP_PRIVATE_ARCH) && defined(VBOX_PATH_SHARED_LIBS) + rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); +# else + const char *home = getenv("VBOX_PROGRAM_PATH"); + if (home) { + size_t len = strlen(home); + char *exepath = (char *)alloca(len + 32); + memcpy(exepath, home, len); + memcpy(exepath + len, "/pythonfake", sizeof("/pythonfake")); + rc = RTR3InitEx(RTR3INIT_VER_CUR, RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_UNOBTRUSIVE, 0, NULL, exepath); + } else { + rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + } +# endif + + rc = com::Initialize(); + g_fComShutdownAlready = false; + +# if PY_MAJOR_VERSION <= 2 + init_xpcom(); +# else + return init_xpcom(); +# endif + } +# if PY_MAJOR_VERSION >= 3 + return NULL; +# endif +} + +static +nsresult deinitVBoxPython() +{ + nsresult nr; + if (!g_fComShutdownAlready) + { + nr = com::Shutdown(); + if (!NS_FAILED(nr)) + g_fComShutdownAlready = true; + } + else + nr = NS_ERROR_NOT_INITIALIZED; + return nr; +} + +#endif /* VBOX_PYXPCOM */ diff --git a/src/libs/xpcom18a4/python/src/readme.html b/src/libs/xpcom18a4/python/src/readme.html new file mode 100644 index 00000000..b049dbad --- /dev/null +++ b/src/libs/xpcom18a4/python/src/readme.html @@ -0,0 +1,99 @@ + + + + + + + + +Building the Python XPCOM package + + + + +

Building the Python XPCOM package.

+ +

This file describes how to build the Python XPCOM C++ sources.

+

There are the following steps

+ +

Testing etc is described in the main readme.

+

Configuring environment variables

+

MOZ_SRC 

+

Windows: Run the standard MOZENV.BAT used to build Mozilla.  This +sets MOZ_SRC

+

Unix: Set MOZ_SRC to point to the base source directory - assumes +"mozilla" sub-directory with mozilla directory tree under that. eg: assuming +/home/user/src/mozilla/dist/..."

+
export MOZ_SRC=/home/user/src
+

PYTHON_SRC

+

Windows: Set PYTHON_SRC to point to the base Python source directory.  +eg: assuming c:\src\python\PCBuild\...

set PYTHON_SRC=c:\src\python
+

Unix: Set PYTHON_SRC to point to the base of an "installed" Python +tree. eg:

export PYTHON_SRC=/usr/local/ActivePython-1.6
+

Building the sources

+

You must ensure some environment variables are setup.  The section on configuring +environment variables explains how.

+

There are 2 build processes to run All C++ sources are in the xpcom\src + directory.:

+

Windows

+
    +
  • Execute "compile.py" in this directory. This will take Setup.in, create an MSDev project, and build + ..\_xpcom.pyd and ..\_xpcom_d.pyd"
  • +
  • Change to the loader directory.
  • +
  • Run nmake -f makefile.win. This will create pyloader.dll, and + automatically copy it to the Mozilla build directory.
  • + +
+

Finally, run the tests, + where we also test everything imports correctly.

+

Linux

+

NOTE: Do not attempt to use "Setup.in" to create a Makefile 

+
    +
  • Run "make" in this directory.  This will create ../_xpcommodule.so
  • +
  • Run "make" in the loader directory. This will create libpyloader.so, + and copy it to the Mozilla directory.
  • + +
+

Finally, running the tests, + where we also test everything imports correctly.

+ + + + -- cgit v1.2.3