Merge extensions/python/xpcom changes from DOM_AGNOSTIC2_BRANCH into the

trunk.


git-svn-id: svn://10.0.0.236/trunk@187878 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
mhammond%skippinet.com.au
2006-01-20 05:50:28 +00:00
parent 28dfbf4814
commit d394dc834d
56 changed files with 1710 additions and 958 deletions

View File

@@ -38,11 +38,16 @@
DEPTH =../../..
include $(DEPTH)/config/autoconf.mk
DIRS = \
src \
test/test_component \
$(NULL)
ifdef ENABLE_TESTS
DIRS += test $(NULL)
endif
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
@@ -53,7 +58,7 @@ PYSRCS_XPCOM = \
components.py \
file.py \
nsError.py \
register.py \
primitives.py \
shutdown.py \
xpcom_consts.py \
xpt.py \

View File

@@ -39,18 +39,10 @@
# The XPCOM (Cross Platform COM) package.
import exceptions
import sys
#sys.stdout = open("pystdout.log", "w")
if sys.version_info >= (2, 3):
# sick off the new hex() warnings, and no time to digest what the
# impact will be!
import warnings
warnings.filterwarnings("ignore", category=FutureWarning, append=1)
# A global "verbose" flag - currently used by the
# server package to print trace messages
verbose = 0
# Map of nsresult -> constant_name.
hr_map = {}
# The standard XPCOM exception object.
@@ -72,10 +64,10 @@ class Exception(exceptions.Exception):
message = hr_map.get(self.errno)
if message is None:
message = ""
return "0x%x (%s)" % (self.errno, message)
return "%d (%s)" % (self.errno, message)
# An alias for Exception - allows code to say "from xpcom import COMException"
# rather than "Exception" - thereby preventing clashes.
# rather than "Exception", preventing clashes with the builtin Exception
COMException = Exception
# Exceptions thrown by servers. It can be good for diagnostics to
@@ -83,7 +75,7 @@ COMException = Exception
# and a normal exception which may simply be propagating down.
# (When ServerException objects are thrown across the XPConnect
# gateway they will be converted back to normal client exceptions if
# subsequently re-caught by Python
# subsequently re-caught by Python)
class ServerException(Exception):
def __init__(self, errno=None, *args, **kw):
if errno is None:
@@ -91,4 +83,82 @@ class ServerException(Exception):
errno = nsError.NS_ERROR_FAILURE
Exception.__init__(self, errno, *args, **kw)
# Some global functions.
# Logging support - setup the 'xpcom' logger to write to the Mozilla
# console service, and also to sys.stderr, or optionally a file.
# Environment variables supports:
# PYXPCOM_LOG_FILE=filename - if set, used instead of sys.stderr.
# PYXPCOM_LOG_LEVEL=level - level may be a number or a logging level
# constant (eg, 'debug', 'error')
# Later it may make sense to allow a different log level to be set for
# the file than for the console service.
import logging
class ConsoleServiceStream:
# enough of a stream to keep logging happy
def flush(self):
pass
def write(self, msg):
import _xpcom
_xpcom.LogConsoleMessage(msg)
def close(self):
pass
def setupLogging():
import sys, os, threading, thread
hdlr = logging.StreamHandler(ConsoleServiceStream())
fmt = logging.Formatter(logging.BASIC_FORMAT)
hdlr.setFormatter(fmt)
# There is a bug in 2.3 and 2.4.x logging module in that it doesn't
# use an RLock, leading to deadlocks in some cases (specifically,
# logger.warning("ob is %r", ob), and where repr(ob) itself tries to log)
# Later versions of logging use an RLock, so we detect an "old" style
# handler and update its lock
if type(hdlr.lock) == thread.LockType:
hdlr.lock = threading.RLock()
logger.addHandler(hdlr)
# The console handler in mozilla does not go to the console!?
# Add a handler to print to stderr, or optionally a file
# PYXPCOM_LOG_FILE can specify a filename
filename = os.environ.get("PYXPCOM_LOG_FILE")
stream = sys.stderr # this is what logging uses as default
if filename:
try:
# open without buffering so never pending output
stream = open(filename, "wU", 0)
except IOError, why:
print >> sys.stderr, "pyxpcom failed to open log file '%s': %s" \
% (filename, why)
# stream remains default
hdlr = logging.StreamHandler(stream)
# see above - fix a deadlock problem on this handler too.
if type(hdlr.lock) == thread.LockType:
hdlr.lock = threading.RLock()
fmt = logging.Formatter(logging.BASIC_FORMAT)
hdlr.setFormatter(fmt)
logger.addHandler(hdlr)
# Allow PYXPCOM_LOG_LEVEL to set the level
level = os.environ.get("PYXPCOM_LOG_LEVEL")
if level:
try:
level = int(level)
except ValueError:
try:
# might be a symbolic name - all are upper-case
level = int(getattr(logging, level.upper()))
except (AttributeError, ValueError):
logger.warning("The PYXPCOM_LOG_LEVEL variable specifies an "
"invalid level")
level = None
if level:
logger.setLevel(level)
logger = logging.getLogger('xpcom')
# If someone else has already setup this logger, leave things alone.
if len(logger.handlers) == 0:
setupLogging()
# Cleanup namespace - but leave 'logger' there for people to use, so they
# don't need to know the exact name of the logger.
del ConsoleServiceStream, logging, setupLogging

View File

@@ -37,15 +37,18 @@
import os
import new
from xpcom import xpt, COMException, nsError
import logging
from xpcom import xpt, COMException, nsError, logger
# Suck in stuff from _xpcom we use regularly to prevent a module lookup
from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, IID_nsISupportsCString, IID_nsISupportsWeakReference, \
IID_nsIWeakReference, XPTI_GetInterfaceInfoManager, GetComponentManager, XPTC_InvokeByIndex
from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, \
IID_nsISupportsCString, IID_nsISupportsString, \
IID_nsISupportsWeakReference, IID_nsIWeakReference, \
XPTI_GetInterfaceInfoManager, GetComponentManager, XPTC_InvokeByIndex
# Attribute names we may be __getattr__'d for, but know we don't want to delegate
# Could maybe just look for startswith("__") but this may screw things for some objects.
_special_getattr_names = ["__del__", "__len__", "__nonzero__"]
_special_getattr_names = ["__del__", "__len__", "__nonzero__", "__eq__", "__neq__"]
_just_int_interfaces = ["nsISupportsPRInt32", "nsISupportsPRInt16", "nsISupportsPRUint32", "nsISupportsPRUint16", "nsISupportsPRUint8", "nsISupportsPRBool"]
_just_long_interfaces = ["nsISupportsPRInt64", "nsISupportsPRUint64"]
@@ -176,6 +179,21 @@ class _XPCOMBase:
def __hash__(self):
return hash(self._comobj_)
# The basic rich compare ops for equality
def __eq__(self, other):
try:
other = other._comobj_
except AttributeError:
pass
return self._comobj_ == other
def __neq__(self, other):
try:
other = other._comobj_
except AttributeError:
pass
return self._comobj_ != other
# See if the object support strings.
def __str__(self):
try:
@@ -184,6 +202,13 @@ class _XPCOMBase:
except COMException:
return self.__repr__()
def __unicode__(self):
try:
prin = self._comobj_.QueryInterface(IID_nsISupportsString)
except COMException:
return unicode(str(self))
return prin.data
# Try the numeric support.
def _do_conversion(self, interface_names, cvt):
iim = XPTI_GetInterfaceInfoManager()
@@ -206,7 +231,7 @@ class _XPCOMBase:
return self._do_conversion(_float_interfaces, float)
class Component(_XPCOMBase):
def __init__(self, ob, iid):
def __init__(self, ob, iid = IID_nsISupports):
assert not hasattr(ob, "_comobj_"), "Should be a raw nsIWhatever, not a wrapped one"
ob_name = None
if not hasattr(ob, "IID"):
@@ -220,7 +245,7 @@ class Component(_XPCOMBase):
self.__dict__['_interfaces_'] = {} # keyed by IID
self.__dict__['_interface_names_'] = {} # keyed by IID name
self.__dict__['_interface_infos_'] = {} # keyed by IID
self.__dict__['_name_to_interface_name_'] = {}
self.__dict__['_name_to_interface_iid_'] = {}
self.__dict__['_tried_classinfo_'] = 0
if ob_name is None:
@@ -256,10 +281,11 @@ class Component(_XPCOMBase):
for nominated_iid in interface_infos:
# Interface may appear twice in the class info list, so check this here.
if not self.__dict__['_interface_infos_'].has_key(nominated_iid):
self._remember_interface_info(nominated_iid)
# Just invoke our QI on the object
self.queryInterface(nominated_iid)
if real_cid is not None:
contractid_info = {}
contractid_info['_name_to_interface_name_'] = self.__dict__['_name_to_interface_name_']
contractid_info['_name_to_interface_iid_'] = self.__dict__['_name_to_interface_iid_']
contractid_info['_interface_infos_'] = self.__dict__['_interface_infos_']
contractid_info_cache[real_cid] = contractid_info
else:
@@ -269,26 +295,28 @@ class Component(_XPCOMBase):
self.__dict__['_com_classinfo_'] = classinfo
def _remember_interface_info(self, iid):
method_infos, getters, setters, constants = BuildInterfaceInfo(iid)
# Remember all the names so we can delegate
assert not self.__dict__['_interface_infos_'].has_key(iid), "Already remembered this interface!"
self.__dict__['_interface_infos_'][iid] = method_infos, getters, setters, constants
interface_name = iid.name
names = self.__dict__['_name_to_interface_name_']
for name in method_infos.keys(): names[name] = interface_name
for name in getters.keys(): names[name] = interface_name
for name in setters.keys(): names[name] = interface_name
for name in constants.keys(): names[name] = interface_name
# XXX - there is no good reason to cache this only in each instance
# It should be cached at the module level, so we don't need to
# rebuild the world for each new object.
iis = self.__dict__['_interface_infos_']
assert not iis.has_key(iid), "Already remembered this interface!"
try:
method_infos, getters, setters, constants = BuildInterfaceInfo(iid)
except COMException, why:
# Failing to build an interface info generally isn't a real
# problem - its probably just that the interface is non-scriptable.
logger.info("Failed to build interface info for %s: %s", iid, why)
# Remember the fact we failed.
iis[iid] = None
return
def _make_interface_info(self, ob, iid):
interface_infos = self._interface_infos_
assert not self._interfaces_.has_key(iid), "Already have made this interface"
method_infos, getters, setters, constants = interface_infos[iid]
new_interface = _Interface(ob, iid, method_infos, getters, setters, constants)
self._interfaces_[iid] = new_interface
self._interface_names_[iid.name] = new_interface
# No point remembering these.
del interface_infos[iid]
# Remember all the names so we can delegate
iis[iid] = method_infos, getters, setters, constants
names = self.__dict__['_name_to_interface_iid_']
for name in method_infos.keys(): names[name] = iid
for name in getters.keys(): names[name] = iid
for name in setters.keys(): names[name] = iid
for name in constants.keys(): names[name] = iid
def QueryInterface(self, iid):
if self._interfaces_.has_key(iid):
@@ -297,10 +325,24 @@ class Component(_XPCOMBase):
# Haven't seen this before - do a real QI.
if not self._interface_infos_.has_key(iid):
self._remember_interface_info(iid)
ret = self._comobj_.QueryInterface(iid, 0)
# print "Component QI for", iid, "yielded", ret
self._make_interface_info(ret, iid)
assert self._interfaces_.has_key(iid) and self._interface_names_.has_key(iid.name), "Making the interface didn't update the maps"
iface_info = self._interface_infos_[iid]
if iface_info is None:
# We have tried, but failed, to get this interface info. Its
# unlikely to work later either - its probably non-scriptable.
# That means our component wrappers are useless - so just return a
# raw nsISupports object with no wrapper.
return self._comobj_.QueryInterface(iid, 0)
raw_iface = self._comobj_.QueryInterface(iid, 0)
method_infos, getters, setters, constants = iface_info
new_interface = _Interface(raw_iface, iid, method_infos,
getters, setters, constants)
self._interfaces_[iid] = new_interface
self._interface_names_[iid.name] = new_interface
# As we 'flatten' objects when possible, a QI on an object just
# returns ourself - all the methods etc on this interface are
# available.
return self
queryInterface = QueryInterface # Alternate name.
@@ -312,47 +354,51 @@ class Component(_XPCOMBase):
interface = self.__dict__['_interface_names_'].get(attr, None)
if interface is not None:
return interface
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
# See if we know the IID of an interface providing this attribute
iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
# This may be first time trying this interface - get the nsIClassInfo
if interface_name is None and not self._tried_classinfo_:
if iid is None and not self._tried_classinfo_:
self._build_all_supported_interfaces_()
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
if interface_name is not None:
interface = self.__dict__['_interface_names_'].get(interface_name, None)
iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
# If the request is for an interface name, it may now be
# available.
interface = self.__dict__['_interface_names_'].get(attr, None)
if interface is not None:
return interface
if iid is not None:
interface = self.__dict__['_interfaces_'].get(iid, None)
if interface is None:
iid = XPTI_GetInterfaceInfoManager().GetInfoForName(interface_name).GetIID()
self.QueryInterface(iid)
interface = self.__dict__['_interface_names_'][interface_name]
interface = self.__dict__['_interfaces_'][iid]
return getattr(interface, attr)
# Some interfaces may provide this name via "native" support.
# Loop over all interfaces, and if found, cache it for next time.
for interface in self.__dict__['_interfaces_'].values():
try:
ret = getattr(interface, attr)
self.__dict__['_name_to_interface_name_'][attr] = interface._iid_.name
self.__dict__['_name_to_interface_iid_'][attr] = interface._iid_
return ret
except AttributeError:
pass
raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
def __setattr__(self, attr, val):
interface_name = self._name_to_interface_name_.get(attr, None)
iid = self._name_to_interface_iid_.get(attr, None)
# This may be first time trying this interface - get the nsIClassInfo
if interface_name is None and not self._tried_classinfo_:
if iid is None and not self._tried_classinfo_:
self._build_all_supported_interfaces_()
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
if interface_name is not None:
interface = self._interface_names_.get(interface_name, None)
iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
if iid is not None:
interface = self._interfaces_.get(iid, None)
if interface is None:
iid = XPTI_GetInterfaceInfoManager().GetInfoForName(interface_name).GetIID()
self.QueryInterface(iid)
interface = self.__dict__['_interface_names_'][interface_name]
interface = self.__dict__['_interfaces_'][iid]
setattr(interface, attr, val)
return
raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
def __repr__(self):
# We can advantage from nsIClassInfo - use it.
def _get_classinfo_repr_(self):
try:
if not self._tried_classinfo_:
self._build_all_supported_interfaces_()
@@ -362,13 +408,21 @@ class Component(_XPCOMBase):
# we are flagged as *not* having built, so the error is seen
# by the first caller who actually *needs* this to work.
self.__dict__['_tried_classinfo_'] = 0
infos = self.__dict__['_interface_infos_']
if infos:
iface_names = ",".join([iid.name for iid in infos.keys()])
iface_desc = " (implementing %s)" % (iface_names,)
else:
iface_desc = " (with no class info)"
return "<XPCOM component '%s'%s>" % (self._object_name_,iface_desc)
iface_names = self.__dict__['_interface_names_'].keys()
try:
iface_names.remove("nsISupports")
except ValueError:
pass
iface_names.sort()
iface_desc = "implementing %s" % (",".join(iface_names),)
return iface_desc
def __repr__(self):
# We can advantage from nsIClassInfo - use it.
iface_desc = self._get_classinfo_repr_()
return "<XPCOM component '%s' (%s)>" % (self._object_name_,iface_desc)
class _Interface(_XPCOMBase):
def __init__(self, comobj, iid, method_infos, getters, setters, constants):
@@ -403,7 +457,7 @@ class _Interface(_XPCOMBase):
if len(param_infos)!=1: # Only expecting a retval
raise RuntimeError, "Can't get properties with this many args!"
args = ( param_infos, () )
return XPTC_InvokeByIndex(self, method_index, args)
return XPTC_InvokeByIndex(self._comobj_, method_index, args)
# See if we have a method info waiting to be turned into a method.
# Do this last as it is a one-off hit.
@@ -431,7 +485,7 @@ class _Interface(_XPCOMBase):
if len(param_infos)!=1: # Only expecting a single input val
raise RuntimeError, "Can't set properties with this many args!"
real_param_infos = ( param_infos, (val,) )
return XPTC_InvokeByIndex(self, method_index, real_param_infos)
return XPTC_InvokeByIndex(self._comobj_, method_index, real_param_infos)
def __repr__(self):
return "<XPCOM interface '%s'>" % (self._object_name_,)
@@ -453,7 +507,7 @@ class WeakReference:
>>> some_ob = components.classes['...']
>>> weak_ref = WeakReference(some_ob)
>>> new_ob = weak_ref() # new_ob is effectively "some_ob" at this point
>>> # EXCEPT: new_ob may be None of some_ob has already died - a
>>> # EXCEPT: new_ob may be None if some_ob has already died - a
>>> # weak reference does not keep the object alive (that is the point)
You should never hold onto this resulting strong object for a long time,

View File

@@ -251,24 +251,17 @@ def _TestLocalFile():
test_file.close()
# Make sure Python can read it OK.
f = open(fname, "r")
if f.read() != data:
print "Eeek - Python could not read the data back correctly!"
assert f.read() == data, "Eeek - Python could not read the data back correctly!"
f.close()
# For the sake of the test, try a re-init.
test_file.init(fname, "r")
got = str(test_file.read())
if got != data:
print "Read the wrong data back - %r" % (got,)
else:
print "Read the correct data."
assert got == data, got
test_file.close()
# Try reading in chunks.
test_file = LocalFile(fname, "r")
got = test_file.read(10) + test_file.read()
if got != data:
print "Chunks the wrong data back - %r" % (got,)
else:
print "Chunks read the correct data."
assert got == data, got
test_file.close()
# Open the same file again for writing - this should delete the old one.
if not os.path.isfile(fname):
@@ -278,16 +271,12 @@ def _TestLocalFile():
test_file.close()
# Make sure Python can read it OK.
f = open(fname, "r")
if f.read() != data:
print "Eeek - Python could not read the data back correctly after recreating an existing file!"
assert f.read() == data, "Eeek - Python could not read the data back correctly after recreating an existing file!"
f.close()
# XXX - todo - test "a" mode!
finally:
try:
os.unlink(fname)
except OSError, details:
print "Error removing temp test file:", details
os.unlink(fname)
def _TestAll():
# A mini test suite.
@@ -302,17 +291,13 @@ def _TestAll():
url = LocalFileToURL(fname)
# First try passing a URL as a string.
_DoTestRead( URIFile( url.spec), expected)
print "Open as string test worked."
# Now with a URL object.
_DoTestRead( URIFile( url ), expected)
print "Open as URL test worked."
_DoTestBufferRead( URIFile( url ), expected)
print "File test using buffers worked."
# For the sake of testing, do our pointless, demo object!
_DoTestRead( LocalFile(fname), expected )
print "Local file read test worked."
# Now do the full test of our pointless, demo object!
_TestLocalFile()
@@ -330,4 +315,4 @@ if __name__=='__main__':
print "No URL specified on command line - performing self-test"
_TestAll()
else:
_TestURI(sys.argv[1])
_TestURI(sys.argv[1])

View File

@@ -98,10 +98,13 @@ NS_ERROR_PROXY_INVALID_OUT_PARAMETER = ( -2147418095)
##### END OF GENERATED CODE
#####
def NS_ERROR_GENERATE_FAILURE(module,code):
return (NS_ERROR_SEVERITY_ERROR<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code)
# slightly optimized, and avoids 2.3->2.4 long/int changes
# return (NS_ERROR_SEVERITY_ERROR<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code)
return -2147483648 | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code)
def NS_ERROR_GENERATE_SUCCESS(module,code):
return (NS_ERROR_SEVERITY_SUCCESS<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code)
#return (NS_ERROR_SEVERITY_SUCCESS<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code)
return ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code)
NS_BASE_STREAM_CLOSED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 2)
NS_BASE_STREAM_OSERROR = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 3)

View File

@@ -0,0 +1,39 @@
# Various utilities for working with nsISupportsPrimitive
from xpcom import components
_primitives_map = {}
def _build_map():
ifaces = components.interfaces
iface = ifaces.nsISupportsPrimitive
m = _primitives_map
m[iface.TYPE_ID] = ifaces.nsISupportsID
m[iface.TYPE_CSTRING] = ifaces.nsISupportsCString
m[iface.TYPE_STRING] = ifaces.nsISupportsString
m[iface.TYPE_PRBOOL] = ifaces.nsISupportsPRBool
m[iface.TYPE_PRUINT8] = ifaces.nsISupportsPRUint8
m[iface.TYPE_PRUINT16] = ifaces.nsISupportsPRUint16
m[iface.TYPE_PRUINT32] = ifaces.nsISupportsPRUint32
m[iface.TYPE_PRUINT64] = ifaces.nsISupportsPRUint64
m[iface.TYPE_PRINT16] = ifaces.nsISupportsPRInt16
m[iface.TYPE_PRINT32] = ifaces.nsISupportsPRInt32
m[iface.TYPE_PRINT64] = ifaces.nsISupportsPRInt64
m[iface.TYPE_PRTIME] = ifaces.nsISupportsPRTime
m[iface.TYPE_CHAR] = ifaces.nsISupportsChar
m[iface.TYPE_FLOAT] = ifaces.nsISupportsFloat
m[iface.TYPE_DOUBLE] = ifaces.nsISupportsDouble
# Do interface pointer specially - it provides the IID.
#m[iface.TYPE_INTERFACE_POINTER] = ifaces.nsISupportsDouble
def GetPrimitive(ob):
if len(_primitives_map)==0:
_build_map()
prin = ob.QueryInterface(components.interfaces.nsISupportsPrimitive)
try:
better = _primitives_map[prin.type]
except KeyError:
raise ValueError, "This primitive type (%d) is not supported" % (prin.type,)
prin = prin.QueryInterface(better)
return prin.data

View File

@@ -39,8 +39,7 @@
#
# Hardly worth its own source file!
import xpcom
from xpcom import components, nsError, _xpcom
from xpcom import components, nsError, _xpcom, logger
class Factory:
_com_interfaces_ = components.interfaces.nsIFactory
@@ -53,18 +52,17 @@ class Factory:
if outer is not None:
raise xpcom.ServerException(nsError.NS_ERROR_NO_AGGREGATION)
if xpcom.verbose:
print "Python Factory creating", self.klass.__name__
logger.debug("Python Factory creating %s", self.klass.__name__)
try:
return self.klass()
except:
# An exception here may not be obvious to the user - none
# of their code has been called yet. It can be handy on
# failure to tell the user what class failed!
_xpcom.LogWarning("Creation of class '%r' failed!\nException details follow\n" % (self.klass,))
logger.error("Creation of class '%r' failed!\nException details follow\n",
self.klass)
# The framework itself will also report the error.
raise
def lockServer(self, lock):
if xpcom.verbose:
print "Python Factory LockServer called -", lock
logger.debug("Python Factory LockServer called '%s'", lock)

View File

@@ -36,7 +36,7 @@
# ***** END LICENSE BLOCK *****
import xpcom
from xpcom import components
from xpcom import components, nsError
import xpcom.shutdown
import module
@@ -93,6 +93,8 @@ class ModuleLoader:
def _getCOMModuleForLocation(self, componentFile):
fqn = componentFile.path
if not fqn.endswith(".py"):
raise xpcom.ServerException(nsError.NS_ERROR_INVALID_ARG)
mod = self.com_modules.get(fqn)
if mod is not None:
return mod

View File

@@ -35,12 +35,14 @@
#
# ***** END LICENSE BLOCK *****
from xpcom import xpcom_consts, _xpcom, client, nsError, ServerException, COMException
from xpcom import xpcom_consts, _xpcom, client, nsError, logger
from xpcom import ServerException, COMException
import xpcom
import traceback
import xpcom.server
import operator
import types
import logging
IID_nsISupports = _xpcom.IID_nsISupports
IID_nsIVariant = _xpcom.IID_nsIVariant
@@ -237,12 +239,11 @@ class DefaultPolicy:
if dt == xpcom_consts.VTYPE_ID:
return interface.getAsID()
# all else fails...
print "Warning: nsIVariant type %d not supported - returning a string" % (dt,)
logger.warning("Warning: nsIVariant type %d not supported - returning a string", dt)
try:
return interface.getAsString()
except COMException:
print "Error: failed to get Variant as a string - returning variant object"
traceback.print_exc()
logger.exception("Error: failed to get Variant as a string - returning variant object")
return interface
return client.Component(interface, iid)
@@ -278,17 +279,27 @@ class DefaultPolicy:
exc_val = exc_info[1]
is_server_exception = isinstance(exc_val, ServerException)
if is_server_exception:
if xpcom.verbose:
print "** Information: '%s' raised COM Exception %s" % (func_name, exc_val)
traceback.print_exception(exc_info[0], exc_val, exc_info[2])
print "** Returning nsresult from existing exception", exc_val
return exc_val.errno
# Unhandled exception - always print a warning.
print "** Unhandled exception calling '%s'" % (func_name,)
traceback.print_exception(exc_info[0], exc_val, exc_info[2])
print "** Returning nsresult of NS_ERROR_FAILURE"
return nsError.NS_ERROR_FAILURE
# When a component raised an explicit COM exception, it is
# considered 'normal' - however, we still write a debug log
# record to help track these otherwise silent exceptions.
# Note that Python 2.3 does not allow an explicit exc_info tuple
# and passing 'True' will not work as there is no exception pending.
# Trick things!
if logger.isEnabledFor(logging.DEBUG):
try:
raise exc_info[0], exc_info[1], exc_info[2]
except:
logger.debug("'%s' raised COM Exception %s",
func_name, exc_val, exc_info = 1)
return exc_val.errno
# Unhandled exception - always print a warning and the traceback.
# As above, trick the logging module to handle Python 2.3
try:
raise exc_info[0], exc_info[1], exc_info[2]
except:
logger.exception("Unhandled exception calling '%s'", func_name)
return nsError.NS_ERROR_FAILURE
# Called whenever an unhandled Python exception is detected as a result
# of _CallMethod_ - this exception may have been raised during the _CallMethod_
@@ -306,8 +317,12 @@ class DefaultPolicy:
import xpcom.xpt
m = xpcom.xpt.Method(info, index, None)
func_repr = m.Describe().lstrip()
except:
except COMException:
func_repr = "%s(%r)" % (name, param_descs)
except:
# any other errors are evil!? Log it
self._doHandleException("<building method repr>", sys.exc_info())
# And fall through to logging the original error.
return self._doHandleException(func_repr, exc_info)
# Called whenever a gateway fails due to anything other than _CallMethod_.
@@ -318,7 +333,7 @@ class DefaultPolicy:
_supports_primitives_data_ = [
("nsISupportsCString", "__str__", str),
("nsISupportsString", "__str__", str),
("nsISupportsString", "__unicode__", unicode),
("nsISupportsPRUint64", "__long__", long),
("nsISupportsPRInt64", "__long__", long),
("nsISupportsPRUint32", "__int__", int),

View File

@@ -55,81 +55,179 @@ static char *PyTraceback_AsString(PyObject *exc_tb);
// The internal helper that actually moves the
// formatted string to the target!
void LogMessage(const char *prefix, const char *pszMessageText)
// Only used in really bad situations!
static void _PanicErrorWrite(const char *msg)
{
nsCOMPtr<nsIConsoleService> consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
NS_ABORT_IF_FALSE(consoleService, "Where is the console service?");
if (consoleService)
consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(pszMessageText).get());
else
PR_fprintf(PR_STDERR,"%s\n", pszMessageText);
consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(msg).get());
PR_fprintf(PR_STDERR,"%s\n", msg);
}
void LogMessage(const char *prefix, nsACString &text)
// 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 ("<string>", 2). Ideally we would compile with a
// filename something similar to "<pydom error reporter>".
// 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!
PyObject *obMessage = PyString_FromString(pszMessageText);
if (obMessage) {
PyObject *repr = PyObject_Repr(obMessage);
if (repr) {
c += PyString_AsString(repr);
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(prefix, c);
LogMessage(methodName, c);
nsCRT::free(c);
}
// A helper for the various logging routines.
static void VLogF(const char *prefix, const char *fmt, va_list argptr)
static void VLogF(const char *methodName, const char *fmt, va_list argptr)
{
char buff[512];
// Use safer NS_ functions.
PR_vsnprintf(buff, sizeof(buff), fmt, argptr);
vsprintf(buff, fmt, argptr);
LogMessage(methodName, buff);
}
LogMessage(prefix, 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) {
streamout += PyString_AsString(temp);
Py_DECREF(temp);
} else
streamout += "Can't 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't convert exception value to a string!";
}
return PR_TRUE;
}
void PyXPCOM_LogError(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Error: ", fmt, marker);
// 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:
PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL;
PyErr_Fetch( &exc_typ, &exc_val, &exc_tb);
if (exc_typ) {
PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb);
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't 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't convert exception value to a string!";
}
streamout += "\n";
LogMessage("PyXPCOM Exception:", streamout);
nsCAutoString streamout(buff);
if (PyXPCOM_FormatCurrentException(streamout)) {
LogMessage(LOGGER_ERROR, streamout);
}
PyErr_Restore(exc_typ, exc_val, exc_tb);
}
void PyXPCOM_LogWarning(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Warning: ", fmt, marker);
VLogF(LOGGER_WARNING, fmt, marker);
}
void PyXPCOM_Log(const char *level, const nsCString &msg)
{
DoLogMessage(level, msg.get());
}
#ifdef DEBUG
@@ -137,7 +235,7 @@ void PyXPCOM_LogDebug(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Debug: ", fmt, marker);
VLogF(LOGGER_DEBUG, fmt, marker);
}
#endif
@@ -156,7 +254,17 @@ nsresult PyXPCOM_SetCOMErrorFromPyException()
if (!PyErr_Occurred())
// No error occurred
return NS_OK;
return NS_ERROR_FAILURE;
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.

View File

@@ -43,22 +43,23 @@ srcdir = @srcdir@
VPATH = @srcdir@
pyexecdir = @libdir@/python$(PYTHON_VER_DOTTED)/site-packages
DIRS = loader $(NULL)
DIRS = module loader $(NULL)
include $(DEPTH)/config/autoconf.mk
MODULE = pyxpcom
LIBRARY_NAME = _xpcom$(PYTHON_DEBUG_SUFFIX)
LIBRARY_NAME = pyxpcom
#MODULE_NAME =
REQUIRES = xpcom string $(NULL)
MOZILLA_INTERNAL_API = 1
FORCE_SHARED_LIB = 1
FORCE_USE_PIC = 1
DLL_SUFFIX=$(PYTHON_DLL_SUFFIX)
LOCAL_INCLUDES = $(PYTHON_INCLUDES)
EXTRA_LIBS += $(PYTHON_LIBS)
EXPORTS = PyXPCOM.h
CPPSRCS= \
ErrorUtils.cpp \
PyGBase.cpp \
@@ -80,33 +81,18 @@ CPPSRCS= \
TypeObject.cpp \
VariantUtils.cpp \
dllmain.cpp \
xpcom.cpp \
$(NULL)
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk
EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS)
IMPORT_LIBRARY := $(SHARED_LIBRARY:.pyd=.lib)
# Install into our Python directory
# default build installs into bin and lib - remove them
libs::
ifeq ($(OS_ARCH),WINNT)
$(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin/python/xpcom
ifeq ($(OS_ARCH),Darwin)
# Don't use the EXTRA_DSO_LDOPTS from rules.mk, it breaks the python module
EXTRA_DSO_LDOPTS = -bundle $(MOZ_COMPONENT_LIBS)
else
$(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin/python/xpcom
mv $(DIST)/bin/python/xpcom/$(SHARED_LIBRARY) $(DIST)/bin/python/xpcom/_xpcom.so
endif
rm -f $(DIST)/bin/$(SHARED_LIBRARY)
rm -f $(DIST)/lib/$(IMPORT_LIBRARY)
install::
ifneq ($(OS_ARCH),WINNT)
$(SYSINSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(DISTDIR)$(pyexecdir)/xpcom
mv $(DISTDIR)$(pyexecdir)/xpcom/$(SHARED_LIBRARY) $(DISTDIR)$(pyexecdir)/xpcom/_xpcom$(PYTHON_DLL_SUFFIX)
EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS)
endif
clobber::
rm -f *.ilk *.pdb
rm -f *.ilk *.pdb *.exp *.lib *.pyd

View File

@@ -271,8 +271,18 @@ PyG_Base::MakeInterfaceParam(nsISupports *pis,
PyObject *result = NULL;
// get the basic interface first, as if we fail, we can try and use this.
nsIID iid_check = piid ? *piid : NS_GET_IID(nsISupports);
obISupports = Py_nsISupports::PyObjectFromInterface(pis, iid_check, PR_TRUE, PR_FALSE);
// If we don't know the IID, we must explicitly query for nsISupports.
nsCOMPtr<nsISupports> piswrap;
nsIID iid_check;
if (piid) {
iid_check = *piid;
piswrap = pis;
} else {
iid_check = NS_GET_IID(nsISupports);
pis->QueryInterface(iid_check, getter_AddRefs(piswrap));
}
obISupports = Py_nsISupports::PyObjectFromInterface(piswrap, iid_check, PR_FALSE);
if (!obISupports)
goto done;
if (piid==NULL) {
@@ -346,7 +356,11 @@ PyG_Base::QueryInterface(REFNSIID iid, void** ppv)
CEnterLeavePython celp;
PyObject * ob = Py_nsIID::PyObjectFromIID(iid);
PyObject * this_interface_ob = Py_nsISupports::PyObjectFromInterface((nsIInternalPython *)this, NS_GET_IID(nsISupports), PR_TRUE, PR_FALSE);
// 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);
@@ -355,7 +369,7 @@ PyG_Base::QueryInterface(REFNSIID iid, void** ppv)
PyObject *result = PyObject_CallMethod(m_pPyObject, "_QueryInterface_",
"OO",
this_interface_ob, ob);
this_interface_ob, ob);
Py_DECREF(ob);
Py_DECREF(this_interface_ob);
@@ -426,6 +440,7 @@ PyG_Base::GetWeakReference(nsIWeakReference **ret)
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)
@@ -444,17 +459,17 @@ nsresult PyG_Base::HandleNativeGatewayError(const char *szMethodName)
// 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
// existed, but we encountered errors unpacking their
// 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 on the call-stack)
// 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.
// 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;
@@ -696,10 +711,10 @@ PyObject *PyG_Base::UnwrapPythonObject(void)
Some special support to help with object identity.
In the simplest case, assume a Python COM object is
In the simplest case, assume a Python XPCOM object is
supporting a function "nsIWhatever GetWhatever()",
so implements it as:
return this
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:
@@ -709,7 +724,7 @@ PyObject *PyG_Base::UnwrapPythonObject(void)
We almost certainly expect p1==p2==foo.
We previously _did_ have special support for the "this"
We previously _did_ have special support for the "self"
example above, but this implements a generic scheme that
works for _all_ objects.
@@ -803,12 +818,11 @@ void AddDefaultGateway(PyObject *instance, nsISupports *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) {
nsIWeakReference *pWeakReference = NULL;
swr->GetWeakReference( &pWeakReference );
nsCOMPtr<nsIWeakReference> pWeakReference;
swr->GetWeakReference( getter_AddRefs(pWeakReference) );
if (pWeakReference) {
PyObject *ob_new_weak = Py_nsISupports::PyObjectFromInterface(pWeakReference,
NS_GET_IID(nsIWeakReference),
PR_FALSE, /* bAddRef */
PR_FALSE ); /* bMakeNicePyObject */
// pWeakReference reference consumed.
if (ob_new_weak) {

View File

@@ -80,7 +80,7 @@ PyG_nsIModule::GetClassObject(nsIComponentManager *aCompMgr,
NS_PRECONDITION(r_classObj, "null pointer");
*r_classObj = nsnull;
CEnterLeavePython _celp;
PyObject *cm = Py_nsISupports::PyObjectFromInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_TRUE);
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";
@@ -110,8 +110,8 @@ PyG_nsIModule::RegisterSelf(nsIComponentManager *aCompMgr,
NS_PRECONDITION(aCompMgr, "null pointer");
NS_PRECONDITION(aPath, "null pointer");
CEnterLeavePython _celp;
PyObject *cm = Py_nsISupports::PyObjectFromInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_TRUE);
PyObject *path = Py_nsISupports::PyObjectFromInterface(aPath, NS_GET_IID(nsIFile), PR_TRUE);
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);
@@ -127,8 +127,8 @@ PyG_nsIModule::UnregisterSelf(nsIComponentManager* aCompMgr,
NS_PRECONDITION(aCompMgr, "null pointer");
NS_PRECONDITION(aPath, "null pointer");
CEnterLeavePython _celp;
PyObject *cm = Py_nsISupports::PyObjectFromInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_TRUE);
PyObject *path = Py_nsISupports::PyObjectFromInterface(aPath, NS_GET_IID(nsIFile), PR_TRUE);
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);
@@ -143,7 +143,7 @@ PyG_nsIModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload)
NS_PRECONDITION(okToUnload, "null pointer");
CEnterLeavePython _celp;
// we are shutting down - don't ask for a nice wrapped object.
PyObject *cm = Py_nsISupports::PyObjectFromInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_TRUE, PR_FALSE);
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);

View File

@@ -96,7 +96,8 @@ PyXPCOM_XPTStub::CallMethod(PRUint16 methodIndex,
if (obMI==NULL)
goto done;
// base object is passed raw.
obThisObject = Py_nsISupports::PyObjectFromInterface((nsIInternalPython*)this, NS_GET_IID(nsISupports), PR_TRUE, PR_FALSE);
obThisObject = PyObject_FromNSInterface((nsXPTCStubBase *)this,
m_iid, PR_FALSE);
obParams = arg_helper.MakePyArgs();
if (obParams==NULL)
goto done;

View File

@@ -93,14 +93,14 @@ static PyObject *PyGetHelperForLanguage(PyObject *self, PyObject *args)
return NULL;
nsresult r;
nsISupports *pi;
nsCOMPtr<nsISupports> pi;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetHelperForLanguage(language, &pi);
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), PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsISupports));
}
static PyObject *MakeStringOrNone(char *v)

View File

@@ -81,16 +81,16 @@ static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args)
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsISupports *pis;
nsCOMPtr<nsISupports> pis;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->CreateInstanceByContractID(pid, NULL, iid, (void **)&pis);
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, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE);
}
static PyObject *PyCreateInstance(PyObject *self, PyObject *args)
@@ -117,16 +117,16 @@ static PyObject *PyCreateInstance(PyObject *self, PyObject *args)
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsISupports *pis;
nsCOMPtr<nsISupports> pis;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->CreateInstance(classID, NULL, iid, (void **)&pis);
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, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE);
}
struct PyMethodDef

View File

@@ -121,7 +121,9 @@ static PyObject *PyCurrentItem(PyObject *self, PyObject *args)
}
pRet = temp;
}
return Py_nsISupports::PyObjectFromInterface(pRet, iid, PR_FALSE);
PyObject *ret = Py_nsISupports::PyObjectFromInterface(pRet, iid);
NS_IF_RELEASE(pRet);
return ret;
}
// A method added for Python performance if you really need
@@ -179,7 +181,8 @@ static PyObject *PyFetchBlock(PyObject *self, PyObject *args)
ret = PyList_New(n_fetched);
if (ret)
for (int i=0;i<n_fetched;i++) {
PyObject *new_ob = Py_nsISupports::PyObjectFromInterface(fetched[i], iid, PR_FALSE);
PyObject *new_ob = Py_nsISupports::PyObjectFromInterface(fetched[i], iid);
NS_IF_RELEASE(fetched[i]);
PyList_SET_ITEM(ret, i, new_ob);
}
} else

View File

@@ -54,7 +54,7 @@
nsIID Py_nsIID_NULL = {0,0,0,{0,0,0,0,0,0,0,0}};
// @pymethod <o Py_nsIID>|xpcom|IID|Creates a new IID object
PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args)
PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args)
{
PyObject *obIID;
PyObject *obBuf;

View File

@@ -128,14 +128,14 @@ static PyObject *PyGetParent(PyObject *self, PyObject *args)
if (pI==NULL)
return NULL;
nsIInterfaceInfo *pRet;
nsCOMPtr<nsIInterfaceInfo> pRet;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetParent(&pRet);
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, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE);
}
static PyObject *PyGetMethodCount(PyObject *self, PyObject *args)
@@ -288,11 +288,11 @@ static PyObject *PyGetInfoForParam(PyObject *self, PyObject *args)
if (!__GetMethodInfoHelper(pii, mi, pi, &pmi))
return NULL;
const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi);
nsIInterfaceInfo *pnewii = nsnull;
nsresult n = pii->GetInfoForParam(mi, &param_info, &pnewii);
nsCOMPtr<nsIInterfaceInfo> pnewii;
nsresult n = pii->GetInfoForParam(mi, &param_info, getter_AddRefs(pnewii));
if (NS_FAILED(n))
return PyXPCOM_BuildPyException(n);
return Py_nsISupports::PyObjectFromInterface(pnewii, NS_GET_IID(nsIInterfaceInfo), PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pnewii, NS_GET_IID(nsIInterfaceInfo));
}
static PyObject *PyGetIIDForParam(PyObject *self, PyObject *args)

View File

@@ -73,10 +73,10 @@ static PyObject *PyGetInfoForIID(PyObject *self, PyObject *args)
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsIInterfaceInfo *pi;
nsCOMPtr<nsIInterfaceInfo> pi;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetInfoForIID(&iid, &pi);
r = pI->GetInfoForIID(&iid, getter_AddRefs(pi));
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
@@ -85,7 +85,7 @@ static PyObject *PyGetInfoForIID(PyObject *self, PyObject *args)
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, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pi, new_iid, PR_FALSE);
}
static PyObject *PyGetInfoForName(PyObject *self, PyObject *args)
@@ -98,10 +98,10 @@ static PyObject *PyGetInfoForName(PyObject *self, PyObject *args)
if (pI==NULL)
return NULL;
nsIInterfaceInfo *pi;
nsCOMPtr<nsIInterfaceInfo> pi;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->GetInfoForName(name, &pi);
r = pI->GetInfoForName(name, getter_AddRefs(pi));
Py_END_ALLOW_THREADS;
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
@@ -109,7 +109,7 @@ static PyObject *PyGetInfoForName(PyObject *self, PyObject *args)
/* 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, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsIInterfaceInfo), PR_FALSE);
}
static PyObject *PyGetNameForIID(PyObject *self, PyObject *args)
@@ -171,15 +171,15 @@ static PyObject *PyEnumerateInterfaces(PyObject *self, PyObject *args)
if (pI==NULL)
return NULL;
nsIEnumerator *pRet;
nsCOMPtr<nsIEnumerator> pRet;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pI->EnumerateInterfaces(&pRet);
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), PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator));
}
// TODO:

View File

@@ -109,7 +109,9 @@ static PyObject *PyGetNext(PyObject *self, PyObject *args)
}
pRet = temp;
}
return Py_nsISupports::PyObjectFromInterface(pRet, iid, PR_FALSE);
PyObject *ret = Py_nsISupports::PyObjectFromInterface(pRet, iid);
NS_IF_RELEASE(pRet);
return ret;
}
// A method added for Python performance if you really need
@@ -169,7 +171,8 @@ static PyObject *PyFetchBlock(PyObject *self, PyObject *args)
ret = PyList_New(n_fetched);
if (ret)
for (int i=0;i<n_fetched;i++) {
PyObject *new_ob = Py_nsISupports::PyObjectFromInterface(fetched[i], iid, PR_FALSE);
PyObject *new_ob = Py_nsISupports::PyObjectFromInterface(fetched[i], iid);
NS_IF_RELEASE(fetched[i]);
PyList_SET_ITEM(ret, i, new_ob);
}
} else

View File

@@ -46,10 +46,19 @@
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include "nsISupportsPrimitives.h"
static PRInt32 cInterfaces=0;
static PyObject *g_obFuncMakeInterfaceCount = NULL; // XXX - never released!!!
PyObject *PyObject_FromNSInterface( nsISupports *aInterface,
const nsIID &iid,
PRBool bMakeNicePyObject /*= PR_TRUE */)
{
return Py_nsISupports::PyObjectFromInterface(aInterface, iid,
bMakeNicePyObject);
}
PRInt32
_PyXPCOM_GetInterfaceCount(void)
{
@@ -99,15 +108,9 @@ Py_nsISupports::SafeRelease(Py_nsISupports *ob)
return;
if (ob->m_obj)
{
long rcnt;
Py_BEGIN_ALLOW_THREADS;
rcnt = ob->m_obj->Release();
ob->m_obj = nsnull;
Py_END_ALLOW_THREADS;
#ifdef _DEBUG_LIFETIMES
LogF(buf, " SafeRelease(%ld) -> %s at 0x%0lx, nsISupports at 0x%0lx - Release() returned %ld",GetCurrentThreadId(), ob->ob_type->tp_name,ob, ob->m_obj,rcnt);
#endif
ob->m_obj = NULL;
}
}
@@ -117,6 +120,23 @@ 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<nsISupportsString> 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;
}
PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)ob_type;
return Py_FindMethodInChain(&this_type->chain, this, (char *)name);
}
@@ -231,8 +251,13 @@ Py_nsISupports::InterfaceFromPyObject(PyObject *ob,
Py_DECREF(sub_ob);
}
}
*ppv = PyObject_AsVariant(ob);
return *ppv != NULL;
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.
@@ -273,33 +298,11 @@ Py_nsISupports::RegisterInterface( const nsIID &iid, PyTypeObject *t)
}
}
/*static */PyObject *
Py_nsISupports::PyObjectFromInterfaceOrVariant(nsISupports *pis,
const nsIID &riid,
PRBool bAddRef,
PRBool bMakeNicePyObject /* = PR_TRUE */)
{
// Quick exit.
if (pis==NULL) {
Py_INCREF(Py_None);
return Py_None;
}
if (riid.Equals(NS_GET_IID(nsIVariant))) {
PyObject *ret = PyObject_FromVariant((nsIVariant *)pis);
// If we were asked not to add a reference, then there
// will be a spare reference on pis() - remove it.
if (!bAddRef)
pis->Release();
return ret;
}
return PyObjectFromInterface(pis, riid, bAddRef, bMakeNicePyObject);
}
/*static */PyObject *
Py_nsISupports::PyObjectFromInterface(nsISupports *pis,
const nsIID &riid,
PRBool bAddRef,
PRBool bMakeNicePyObject /* = PR_TRUE */)
PRBool bMakeNicePyObject, /* = PR_TRUE */
PRBool bIsInternalCall /* = PR_FALSE */)
{
// Quick exit.
if (pis==NULL) {
@@ -307,9 +310,15 @@ Py_nsISupports::PyObjectFromInterface(nsISupports *pis,
return Py_None;
}
// FIXME: if !bAddRef, in all error cases, do NS_RELEASE(pis) before return
// since that means we have a spare reference
if (!bIsInternalCall) {
#ifdef NS_DEBUG
nsISupports *queryResult = nsnull;
pis->QueryInterface(riid, (void **)&queryResult);
NS_ASSERTION(queryResult == pis, "QueryInterface needed");
NS_IF_RELEASE(queryResult);
#endif
}
PyTypeObject *createType = NULL;
// If the IID is for nsISupports, don't bother with
// a map lookup as we know the type!
@@ -341,16 +350,15 @@ Py_nsISupports::PyObjectFromInterface(nsISupports *pis,
PyXPCOM_LogF("XPCOM Object created at 0x%0xld, nsISupports at 0x%0xld",
ret, ret->m_obj);
#endif
if (ret && bAddRef && pis) pis->AddRef();
if (ret && bMakeNicePyObject)
return MakeInterfaceResult(ret, riid);
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::MakeInterfaceResult(PyObject *pyis,
Py_nsISupports::MakeDefaultWrapper(PyObject *pyis,
const nsIID &iid)
{
NS_PRECONDITION(pyis, "NULL pyobject!");
@@ -411,10 +419,17 @@ Py_nsISupports::QueryInterface(PyObject *self, PyObject *args)
nsISupports *pMyIS = GetI(self);
if (pMyIS==NULL) return NULL;
nsISupports *pis;
// 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<nsISupports> pis;
nsresult r;
Py_BEGIN_ALLOW_THREADS;
r = pMyIS->QueryInterface(iid, (void **)&pis);
r = pMyIS->QueryInterface(iid, getter_AddRefs(pis));
Py_END_ALLOW_THREADS;
/* Note that this failure may include E_NOINTERFACE */
@@ -422,7 +437,7 @@ Py_nsISupports::QueryInterface(PyObject *self, PyObject *args)
return PyXPCOM_BuildPyException(r);
/* Return a type based on the IID (with no extra ref) */
return PyObjectFromInterface(pis, iid, PR_FALSE, (PRBool)bWrap);
return ((Py_nsISupports *)self)->MakeInterfaceResult(pis, iid, (PRBool)bWrap);
}

View File

@@ -64,13 +64,10 @@ static PyObject *MyChar( char c) {
return PyString_FromStringAndSize(&c, 1);
}
static PyObject *MyUChar( PRUnichar c) {
return PyUnicode_FromPRUnichar(&c, 1);
return PyObject_FromNSString( &c, 1);
}
static PyObject *MyUnicode( PRUnichar *p) {
return PyUnicode_FromPRUnichar(p, nsCRT::strlen(p));
}
static PyObject *MyISupports( nsISupports *p) {
return Py_nsISupports::PyObjectFromInterface(p, NS_GET_IID(nsISupports), PR_FALSE);
return PyObject_FromNSString(p);
}
#define GET_SIMPLE(Type, FuncGet, FuncConvert) \
@@ -123,32 +120,49 @@ GET_SIMPLE(double, GetAsDouble, PyFloat_FromDouble)
GET_SIMPLE(PRBool, GetAsBool, MyBool)
GET_SIMPLE(char, GetAsChar, MyChar)
GET_SIMPLE(PRUnichar, GetAsWChar, MyUChar)
GET_SIMPLE(nsISupports *, GetAsISupports, MyISupports)
GET_SIMPLE(nsIID, GetAsID, Py_nsIID::PyObjectFromIID)
GET_ALLOCATED(char *, GetAsString, PyString_FromString, nsMemory::Free)
GET_ALLOCATED(PRUnichar *, GetAsWString, MyUnicode, nsMemory::Free)
GET_ALLOCATED_SIZE(char *, GetAsStringWithSize, PyString_FromStringAndSize, nsMemory::Free)
GET_ALLOCATED_SIZE(PRUnichar *, GetAsWStringWithSize, PyUnicode_FromPRUnichar, nsMemory::Free)
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;
nsISupports *p;
nsCOMPtr<nsISupports> p;
nsIID *iid;
nsresult nr = pI->GetAsInterface(&iid, (void **)&p);
nsresult nr = pI->GetAsInterface(&iid, getter_AddRefs(p));
if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr);
return Py_nsISupports::PyObjectFromInterface(p, *iid, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(p, *iid);
}
extern PyObject *PyObject_FromVariantArray( nsIVariant *v);
static PyObject *GetAsISupports(PyObject *self, PyObject *args) {
nsIVariant *pI = GetI(self);
if (pI==NULL) return NULL;
if (!PyArg_ParseTuple(args, ":GetAsInterface")) return NULL;
nsCOMPtr<nsISupports> 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(pI);
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
@@ -175,6 +189,7 @@ PyMethods_IVariant[] =
{ "getAsInterface", GetAsInterface, 1},
{ "getAsArray", GetAsArray, 1},
{ "getAsID", GetAsID, 1},
{ "get", Get, 1},
{NULL}
};

View File

@@ -49,26 +49,46 @@
#ifndef __PYXPCOM_H__
#define __PYXPCOM_H__
#ifdef XP_WIN
# ifdef BUILD_PYXPCOM
/* We are building the main dll */
# define PYXPCOM_EXPORT __declspec(dllexport)
# else
/* This module uses the dll */
# define PYXPCOM_EXPORT __declspec(dllimport)
# endif // BUILD_PYXPCOM
#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"
// We need these libs!
# pragma comment(lib, "xpcom.lib")
# pragma comment(lib, "nspr4.lib")
#include "nsXPIDLString.h"
#include "nsCRT.h"
#include "xptcall.h"
#include "xpt_xdr.h"
#else // XP_WIN
# define PYXPCOM_EXPORT
#endif // XP_WIN
#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
#include <Python.h>
#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 nsIID Py_nsIID_NULL;
extern PYXPCOM_EXPORT nsIID Py_nsIID_NULL;
class Py_nsISupports;
/*************************************************************************
**************************************************************************
@@ -94,6 +114,13 @@ PYXPCOM_EXPORT PyObject *PyXPCOM_BuildPyException(nsresult res);
// 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.
@@ -108,6 +135,9 @@ PYXPCOM_EXPORT void PyXPCOM_LogWarning(const char *fmt, ...);
// 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.
@@ -117,9 +147,27 @@ PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...);
#define PYXPCOM_LOG_DEBUG()
#endif // DEBUG
// Create a Unicode Object from the PRUnichar buffer src of the given size
#define PyUnicode_FromPRUnichar(src, size) \
PyUnicode_DecodeUTF16((char*)(src),sizeof(PRUnichar)*(size),NULL,NULL)
// 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);
/*************************************************************************
**************************************************************************
@@ -129,8 +177,6 @@ PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...);
**************************************************************************
*************************************************************************/
class Py_nsISupports;
typedef Py_nsISupports* (* PyXPCOM_I_CTOR)(nsISupports *, const nsIID &);
//////////////////////////////////////////////////////////////////////////
@@ -174,6 +220,9 @@ public:
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<Py_nsISupports *>(ob);
if (ob==NULL || !PyXPCOM_TypeObject::IsType(ob->ob_type ))
@@ -184,31 +233,24 @@ public:
}
// Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED
static nsISupports *GetI(PyObject *self, nsIID *ret_iid = NULL);
nsISupports *m_obj;
nsCOMPtr<nsISupports> m_obj;
nsIID m_iid;
// 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.
// PRBool bAddRef indicates if a COM reference count should be added to the interface.
// This depends purely on the context in which it is called. If the interface is obtained
// from a function that creates a new ref (eg, ???) then you should use
// FALSE. If you receive the pointer as (eg) a param to a gateway function, then
// you normally need to pass TRUE, as this is truly a new reference.
// *** ALWAYS take the time to get this right. ***
// 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 function directly.
// 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 bAddRef,
PRBool bMakeNicePyObject = PR_TRUE);
static PyObject *PyObjectFromInterfaceOrVariant(nsISupports *ps,
const nsIID &iid,
PRBool bAddRef,
PRBool bMakeNicePyObject = PR_TRUE);
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.
@@ -238,8 +280,8 @@ public:
static PyObject *QueryInterface(PyObject *self, PyObject *args);
// Internal (sort-of) objects.
static PyXPCOM_TypeObject *type;
static PyMethodDef methods[];
static NS_EXPORT_STATIC_MEMBER_(PyXPCOM_TypeObject) *type;
static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[];
static PyObject *mapIIDToType;
static void SafeRelease(Py_nsISupports *ob);
static void RegisterInterface( const nsIID &iid, PyTypeObject *t);
@@ -248,6 +290,14 @@ public:
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()
@@ -255,7 +305,9 @@ protected:
const nsIID &iid,
PyTypeObject *type);
static PyObject *MakeInterfaceResult(PyObject *pyis, const nsIID &iid);
// Make a default wrapper for an ISupports (which is an
// xpcom.client.Component instance)
static PyObject *MakeDefaultWrapper(PyObject *pyis, const nsIID &iid);
};
@@ -296,8 +348,8 @@ public:
static long PyTypeMethod_hash(PyObject *self);
static PyObject *PyTypeMethod_str(PyObject *self);
static void PyTypeMethod_dealloc(PyObject *self);
static PyTypeObject type;
static PyMethodDef methods[];
static NS_EXPORT_STATIC_MEMBER_(PyTypeObject) type;
static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[];
};
///////////////////////////////////////////////////////
@@ -307,7 +359,7 @@ class PythonTypeDescriptor; // Forward declare.
class PYXPCOM_EXPORT PyXPCOM_InterfaceVariantHelper {
public:
PyXPCOM_InterfaceVariantHelper();
PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent);
~PyXPCOM_InterfaceVariantHelper();
PRBool Init(PyObject *obParams);
PRBool FillArray();
@@ -327,6 +379,7 @@ protected:
PyObject *m_typedescs; // desc of _all_ params, including hidden.
PythonTypeDescriptor *m_python_type_desc_array;
void **m_buffer_array;
Py_nsISupports *m_parent;
};
@@ -457,6 +510,11 @@ private:
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);
// Weak Reference class. This is a true COM object, representing
// a weak reference to a Python object. For each Python XPCOM object,
@@ -496,7 +554,7 @@ 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);
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 );
@@ -520,9 +578,6 @@ PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d);
PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d);
PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *d);
nsIVariant *PyObject_AsVariant( PyObject *ob);
PyObject *PyObject_FromVariant( nsIVariant *v);
// DLL reference counting functions.
// Although we maintain the count, we never actually
// finalize Python when it hits zero!
@@ -579,8 +634,8 @@ public:
// NEVER new one of these objects - only use on the stack!
extern PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls();
extern PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure();
PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls();
PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure();
// For 2.3, use the PyGILState_ calls
#if (PY_VERSION_HEX >= 0x02030000)
@@ -605,12 +660,12 @@ public:
};
#else
extern PYXPCOM_EXPORT PyInterpreterState *PyXPCOM_InterpreterState;
extern PYXPCOM_EXPORT PRBool PyXPCOM_ThreadState_Ensure();
extern PYXPCOM_EXPORT void PyXPCOM_ThreadState_Free();
extern PYXPCOM_EXPORT void PyXPCOM_ThreadState_Clear();
extern PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Acquire();
extern PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Release();
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 {
@@ -662,11 +717,11 @@ extern struct PyMethodDef Methods[]; \
class ClassName : public Py_nsISupports \
{ \
public: \
static PyXPCOM_TypeObject *type; \
static PYXPCOM_EXPORT PyXPCOM_TypeObject *type; \
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
return new ClassName(pInitObj, iid); \
} \
static void InitType(PyObject *iidNameDict) { \
static void InitType() { \
type = new PyXPCOM_TypeObject( \
#InterfaceName, \
Py_nsISupports::type, \
@@ -675,9 +730,6 @@ public: \
Constructor); \
const nsIID &iid = NS_GET_IID(InterfaceName); \
RegisterInterface(iid, type); \
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \
PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
Py_DECREF(iid_ob); \
} \
protected: \
ClassName(nsISupports *p, const nsIID &iid) : \
@@ -700,7 +752,7 @@ public: \
static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \
return new ClassName(pInitObj, iid); \
} \
static void InitType(PyObject *iidNameDict) { \
static void InitType() { \
type = new PyXPCOM_TypeObject( \
#InterfaceName, \
Py_nsISupports::type, \
@@ -709,9 +761,6 @@ public: \
Constructor); \
const nsIID &iid = NS_GET_IID(InterfaceName); \
RegisterInterface(iid, type); \
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \
PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \
Py_DECREF(iid_ob); \
} \
virtual PyObject *getattr(const char *name); \
virtual int setattr(const char *name, PyObject *val); \
@@ -740,5 +789,4 @@ PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassIn
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__

View File

@@ -49,29 +49,6 @@
//
// (c) 2000, ActiveState corp.
#include <Python.h>
#ifdef HAVE_LONG_LONG
// Mozilla also defines this - we undefine it to
// prevent a compiler warning.
# undef HAVE_LONG_LONG
#endif // HAVE_LONG_LONG
#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 "nsXPIDLString.h"
#include "nsCRT.h"
#include "xptcall.h"
#include "xpt_xdr.h"
// This header is considered internal - hence
// we can use it to trigger "exports"
#define BUILD_PYXPCOM

View File

@@ -152,7 +152,7 @@ PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *c)
v = PyString_FromStringAndSize(&c->value.ch, 1);
break;
case TD_WCHAR:
v = PyUnicode_FromPRUnichar((PRUnichar *)&c->value.wch, 1);
v = PyObject_FromNSString((PRUnichar *)&c->value.wch, 1);
break;
// TD_VOID = 13,
case TD_PNSIID:
@@ -163,7 +163,7 @@ PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *c)
v = PyString_FromString(c->value.str);
break;
case TD_PWSTRING:
v = PyUnicode_FromPRUnichar((PRUnichar *)c->value.wstr, nsCRT::strlen((PRUnichar *)c->value.wstr));
v = PyObject_FromNSString((PRUnichar *)c->value.wstr, nsCRT::strlen((PRUnichar *)c->value.wstr));
break;
// TD_INTERFACE_TYPE = 18,
// TD_INTERFACE_IS_TYPE = 19,

View File

@@ -69,10 +69,10 @@ static PyTypeObject PyInterfaceType_Type = {
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_xxx1*/
0, /*tp_xxx2*/
0, /*tp_xxx3*/
0, /*tp_xxx4*/
0, /* tp_getattro */
0, /*tp_setattro */
0, /* tp_as_buffer */
0, /* tp_flags */
"Define the behavior of a PythonCOM Interface type.",
};
@@ -149,7 +149,8 @@ PyXPCOM_TypeObject::Py_repr(PyObject *self)
iid_repr = pis->m_iid.ToString();
// XXX - need some sort of buffer overflow.
char buf[512];
sprintf(buf, "<XPCOM object (%s) at 0x%p/0x%p>", iid_repr, self, pis->m_obj);
sprintf(buf, "<XPCOM object (%s) at 0x%p/0x%p>",
iid_repr, (void *)self, (void *)pis->m_obj.get());
nsMemory::Free(iid_repr);
return PyString_FromString(buf);
}
@@ -199,9 +200,24 @@ PyXPCOM_TypeObject::PyXPCOM_TypeObject( const char *name, PyXPCOM_TypeObject *pB
0, /* tp_as_number*/
0, /* tp_as_sequence */
0, /* tp_as_mapping */
Py_hash, /* tp_hash */
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 */
0, /* 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;

View File

@@ -72,6 +72,9 @@ 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.
@@ -104,7 +107,7 @@ PyUnicode_AsPRUnichar(PyObject *obj, PRUnichar **dest_out, PRUint32 *size_out)
return 0;
}
PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 = PR_FALSE )
PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 /*= PR_FALSE */)
{
PyObject *ret;
if (IsNullDOMString(s)) {
@@ -134,12 +137,51 @@ PyObject *PyObject_FromNSString( const nsAString &s )
ret = Py_None;
Py_INCREF(Py_None);
} else {
const nsPromiseFlatString& temp = PromiseFlatString(s);
ret = PyUnicode_FromPRUnichar(temp.get(), temp.Length());
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 (!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;
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)
{
@@ -247,7 +289,8 @@ void FreeSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type
#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)
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!");
@@ -441,7 +484,8 @@ PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence
return rc;
}
PyObject *UnpackSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type, nsIID *iid)
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);
@@ -514,7 +558,17 @@ PyObject *UnpackSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 arr
case nsXPTType::T_INTERFACE_IS:
case nsXPTType::T_INTERFACE: {
nsISupports **pp = (nsISupports **)pthis;
val = Py_nsISupports::PyObjectFromInterface(*pp, iid ? *iid : NS_GET_IID(nsISupports), PR_TRUE);
// If we have an owning parent, let it create
// the object for us.
if (iid && iid->Equals(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: {
@@ -592,14 +646,11 @@ static PRUint16 BestVariantTypeForPyObject( PyObject *ob, BVFTResult *pdata = NU
return (PRUint16)-1;
}
nsIVariant *PyObject_AsVariant( PyObject *ob)
nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet)
{
nsresult nr = NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIWritableVariant> v = do_CreateInstance("@mozilla.org/variant;1", &nr);
if (NS_FAILED(nr)) {
PyXPCOM_BuildPyException(nr);
return NULL;
}
nsresult nr = NS_OK;
nsCOMPtr<nsIWritableVariant> 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;
@@ -628,6 +679,7 @@ nsIVariant *PyObject_AsVariant( PyObject *ob)
PRUint32 nch;
PRUnichar *p;
if (PyUnicode_AsPRUnichar(ob, &p, &nch) < 0) {
PyXPCOM_LogWarning("Failed to convert object to unicode", ob->ob_type->tp_name);
nr = NS_ERROR_UNEXPECTED;
break;
}
@@ -665,12 +717,11 @@ nsIVariant *PyObject_AsVariant( PyObject *ob)
int cb_buffer_pointer = seq_length * element_size;
void *buffer_pointer;
if ((buffer_pointer = (void *)nsMemory::Alloc(cb_buffer_pointer)) == nsnull) {
PyErr_NoMemory();
nr = NS_ERROR_UNEXPECTED;
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)) {
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
@@ -679,22 +730,22 @@ nsIVariant *PyObject_AsVariant( PyObject *ob)
break;
}
case nsIDataType::VTYPE_EMPTY:
v->SetAsEmpty();
nr = v->SetAsEmpty();
break;
case nsIDataType::VTYPE_EMPTY_ARRAY:
v->SetAsEmptyArray();
nr = v->SetAsEmptyArray();
break;
case (PRUint16)-1:
PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
return NULL;
PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
nr = NS_ERROR_UNEXPECTED;
default:
NS_ABORT_IF_FALSE(0, "BestVariantTypeForPyObject() returned a variant type not handled here!");
PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
return NULL;
PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
nr = NS_ERROR_UNEXPECTED;
}
nsIVariant *ret;
v->QueryInterface(NS_GET_IID(nsIVariant), (void **)&ret);
return ret;
if (NS_FAILED(nr))
return nr;
return v->QueryInterface(NS_GET_IID(nsIVariant), (void **)aRet);
}
static PyObject *MyBool_FromBool(PRBool v)
@@ -703,10 +754,6 @@ static PyObject *MyBool_FromBool(PRBool v)
Py_INCREF(ret);
return ret;
}
static PyObject *MyObject_FromInterface(nsISupports *p)
{
return Py_nsISupports::PyObjectFromInterface(p, NS_GET_IID(nsISupports), PR_FALSE);
}
#define GET_FROM_V(Type, FuncGet, FuncConvert) { \
Type t; \
@@ -715,7 +762,7 @@ static PyObject *MyObject_FromInterface(nsISupports *p)
break; \
}
PyObject *PyObject_FromVariantArray( nsIVariant *v)
PyObject *PyObject_FromVariantArray( Py_nsISupports *parent, nsIVariant *v)
{
nsresult nr;
NS_PRECONDITION(v, "NULL variant!");
@@ -732,13 +779,13 @@ PyObject *PyObject_FromVariantArray( nsIVariant *v)
PRUint32 count;
nr = v->GetAsArray(&type, &iid, &count, &p);
if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr);
PyObject *ret = UnpackSingleArray(p, count, (PRUint8)type, &iid);
PyObject *ret = UnpackSingleArray(parent, p, count, (PRUint8)type, &iid);
FreeSingleArray(p, count, (PRUint8)type);
nsMemory::Free(p);
return ret;
}
PyObject *PyObject_FromVariant( nsIVariant *v)
PyObject *PyObject_FromVariant( Py_nsISupports *parent, nsIVariant *v)
{
if (!v) {
Py_INCREF(Py_None);
@@ -757,7 +804,7 @@ PyObject *PyObject_FromVariant( nsIVariant *v)
Py_INCREF(Py_None);
break;
case nsIDataType::VTYPE_ARRAY:
ret = PyObject_FromVariantArray(v);
ret = PyObject_FromVariantArray(parent, v);
break;
case nsIDataType::VTYPE_INT8:
case nsIDataType::VTYPE_INT16:
@@ -799,13 +846,23 @@ PyObject *PyObject_FromVariant( nsIVariant *v)
}
case nsIDataType::VTYPE_ID:
GET_FROM_V(nsIID, v->GetAsID, Py_nsIID::PyObjectFromIID);
case nsIDataType::VTYPE_INTERFACE:
GET_FROM_V(nsISupports *, v->GetAsISupports, MyObject_FromInterface);
case nsIDataType::VTYPE_INTERFACE: {
nsCOMPtr<nsISupports> 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: {
nsISupports *p;
nsCOMPtr<nsISupports> p;
nsIID *iid;
if (NS_FAILED(nr=v->GetAsInterface(&iid, (void **)&p))) goto done;
ret = Py_nsISupports::PyObjectFromInterface(p, *iid, PR_FALSE);
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
@@ -899,16 +956,20 @@ Helpers when CALLING interfaces.
**************************************************************************
*************************************************************************/
PyXPCOM_InterfaceVariantHelper::PyXPCOM_InterfaceVariantHelper()
PyXPCOM_InterfaceVariantHelper::PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent)
{
m_var_array=nsnull;
m_buffer_array=nsnull;
m_pyparams=nsnull;
m_num_array = 0;
// Parent should never die before we do, but let's not take the chance.
m_parent = parent;
Py_INCREF(parent);
}
PyXPCOM_InterfaceVariantHelper::~PyXPCOM_InterfaceVariantHelper()
{
Py_DECREF(m_parent);
Py_XDECREF(m_pyparams);
for (int i=0;i<m_num_array;i++) {
if (m_var_array) {
@@ -1217,35 +1278,17 @@ PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor
break;
case nsXPTType::T_ASTRING:
case nsXPTType::T_DOMSTRING: {
if (val==Py_None) {
ns_v.val.p = new nsString();
} else {
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 = PyUnicode_FromObject(val))==NULL)
BREAK_FALSE;
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a unicode object!");
if (PyUnicode_GET_SIZE(val_use) == 0) {
ns_v.val.p = new nsString();
}
else {
PRUint32 nch;
PRUnichar *tempo;
if (PyUnicode_AsPRUnichar(val_use, &tempo, &nch) < 0)
BREAK_FALSE;
ns_v.val.p = new nsString(tempo, nch);
nsMemory::Free(tempo);
}
}
if (!ns_v.val.p) {
nsString *s = new nsString();
if (!s) {
PyErr_NoMemory();
BREAK_FALSE;
}
ns_v.val.p = s;
// We created it - flag as such for cleanup.
ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
if (!PyObject_AsNSString(val, *s))
BREAK_FALSE;
break;
}
case nsXPTType::T_CSTRING:
@@ -1440,7 +1483,7 @@ PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor
cb_this_buffer_pointer = 1;
MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
memset(this_buffer_pointer, 0, cb_this_buffer_pointer);
rc = FillSingleArray(this_buffer_pointer, val, seq_length, element_size, array_type&XPT_TDP_TAGMASK);
rc = FillSingleArray(this_buffer_pointer, val, seq_length, element_size, array_type&XPT_TDP_TAGMASK, nsnull);
if (!rc) break;
rc = SetSizeIs(value_index, PR_FALSE, seq_length);
if (!rc) break;
@@ -1658,9 +1701,12 @@ PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
break;
nsISupports *iret = *((nsISupports **)ns_v.ptr);
// We _do_ add a reference here, as our cleanup code will
// remove this reference should we own it.
ret = Py_nsISupports::PyObjectFromInterfaceOrVariant(iret, iid, PR_TRUE);
// Our cleanup code manages iret reference ownership, and our
// new object takes its own.
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_INTERFACE_IS: {
@@ -1674,15 +1720,18 @@ PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
iid = NS_GET_IID(nsISupports);
else
iid = *piid;
} else
} 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);
// We _do_ add a reference here, as our cleanup code will
// remove this reference should we own it.
ret = Py_nsISupports::PyObjectFromInterfaceOrVariant(iret, iid, PR_TRUE);
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: {
@@ -1696,7 +1745,7 @@ PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
}
PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra);
PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
ret = UnpackSingleArray(* ((void **)ns_v.ptr), seq_size, array_type&XPT_TDP_TAGMASK, NULL);
ret = UnpackSingleArray(m_parent, * ((void **)ns_v.ptr), seq_size, array_type&XPT_TDP_TAGMASK, NULL);
break;
}
@@ -2032,17 +2081,20 @@ PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDes
case nsXPTType::T_ARRAY: {
void *t = DEREF_IN_OR_OUT(ns_v.val.p, void *);
if (t==NULL) {
ret = Py_None;
Py_INCREF(Py_None);
// 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;
nsresult ns = GetArrayType(index, &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(t, seq_size, array_type&XPT_TDP_TAGMASK, NULL);
ret = UnpackSingleArray(NULL, t, seq_size, array_type&XPT_TDP_TAGMASK, piid);
}
break;
}
@@ -2081,7 +2133,7 @@ PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDes
return ret;
}
nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret)
nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **iid)
{
nsCOMPtr<nsIInterfaceInfoManager> iim(do_GetService(
NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
@@ -2098,6 +2150,13 @@ nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret)
rc = ii->GetTypeForParam(m_method_index, &param_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, &param_info, iid);
}
*ret = datumType.flags;
return NS_OK;
}
@@ -2253,29 +2312,8 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index
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 (val == Py_None) {
(*ws) = (PRUnichar *)nsnull;
} else {
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);
if (!val_use)
BREAK_FALSE;
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didn't return a Unicode object!");
if (PyUnicode_GET_SIZE(val_use) == 0) {
ws->Assign((PRUnichar*)NULL, 0);
}
else {
PRUint32 nch;
PRUnichar *sz;
if (PyUnicode_AsPRUnichar(val_use, &sz, &nch) < 0)
BREAK_FALSE;
ws->Assign(sz, nch);
nsMemory::Free(sz);
}
}
if (!PyObject_AsNSString(val, *ws))
BREAK_FALSE;
break;
}
case nsXPTType::T_CSTRING: {
@@ -2389,8 +2427,6 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index
break;
}
case nsXPTType::T_INTERFACE_IS: {
// 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 :-(
const nsIID *piid;
if (!GetIIDForINTERFACE_ID(pi->type.argnum, &piid))
BREAK_FALSE;
@@ -2521,7 +2557,8 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index
// If it is an existing array of the correct size, keep it.
PRUint32 sequence_size = 0;
PRUint8 array_type;
nsresult ns = GetArrayType(index, &array_type);
nsIID *piid;
nsresult ns = GetArrayType(index, &array_type, &piid);
if (NS_FAILED(ns))
return ns;
PRUint32 element_size = GetArrayElementSize(array_type);
@@ -2548,7 +2585,7 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index
bBackFill = pi->IsIn();
}
if (bBackFill)
rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK);
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;
@@ -2563,7 +2600,7 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index
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);
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);

View File

@@ -47,6 +47,8 @@
#include "PyXPCOM_std.h"
#include <prthread.h>
#include "nsIThread.h"
#include "nsILocalFile.h"
#ifdef XP_WIN
#ifndef WIN32_LEAN_AND_MEAN
@@ -58,6 +60,17 @@
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)
#ifndef PYXPCOM_USE_PYGILSTATE
////////////////////////////////////////////////////////////
@@ -245,3 +258,86 @@ struct 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<nsIThread> 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<nsILocalFile> 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();
}
return rc;
}

View File

@@ -46,14 +46,22 @@ include $(DEPTH)/config/autoconf.mk
LIBRARY_NAME = pyloader
IS_COMPONENT = 1
REQUIRES = xpcom string xpcom_obsolete $(NULL)
REQUIRES = pyxpcom xpcom string xpcom_obsolete $(NULL)
MOZILLA_INTERNAL_API = 1
FORCE_SHARED_LIB = 1
FORCE_USE_PIC = 1
LOCAL_INCLUDES = $(PYTHON_INCLUDES)
EXTRA_LIBS += $(PYTHON_LIBS)
ifeq ($(OS_ARCH), WINNT)
EXTRA_LIBS += $(DIST)/lib/pyxpcom.lib
else
EXTRA_LIBS += -lpyxpcom
endif
CPPSRCS = \
pyloader.cpp \
$(NULL)

View File

@@ -41,26 +41,13 @@
//
// 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
// _xpcom support module and transfers control to that.
// pyxpcom core library and transfers control to that.
#include <Python.h>
#include <PyXPCOM.h>
#ifdef HAVE_LONG_LONG
#undef HAVE_LONG_LONG
#endif
#include "nsISupports.h"
#include "nsIModule.h"
#include "nsDirectoryServiceDefs.h"
#include "nsILocalFile.h"
#include "nsString.h"
#include "nsXPIDLString.h"
#include "nsString.h"
#include "stdlib.h"
#include "stdarg.h"
#include "nsReadableUtils.h"
#include "nsCRT.h"
#include "nspr.h" // PR_fprintf
#if (PY_VERSION_HEX >= 0x02030000)
@@ -86,9 +73,6 @@ typedef nsresult (*pfnPyXPCOM_NSGetModule)(nsIComponentManager *servMgr,
nsIModule** result);
pfnPyXPCOM_NSGetModule pfnEntryPoint = nsnull;
static void LogError(const char *fmt, ...);
static void LogDebug(const char *fmt, ...);
@@ -133,6 +117,63 @@ void AddStandardPaths()
}
}
////////////////////////////////////////////////////////////
// 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)
@@ -152,7 +193,6 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
#ifndef NS_DEBUG
Py_OptimizeFlag = 1;
#endif // NS_DEBUG
AddStandardPaths();
PyEval_InitThreads();
NS_TIMELINE_STOP_TIMER("PyXPCOM: Python initializing");
NS_TIMELINE_MARK_TIMER("PyXPCOM: Python initializing");
@@ -177,25 +217,6 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
#else
PyGILState_STATE state = PyGILState_Ensure();
#endif // PYXPCOM_USE_PYGILSTATE
if (pfnEntryPoint == nsnull) {
PyObject *mod = PyImport_ImportModule("xpcom._xpcom");
if (mod==NULL) {
LogError("Could not import the Python XPCOM extension\n");
return NS_ERROR_FAILURE;
}
PyObject *obpfn = PyObject_GetAttrString(mod, "_NSGetModule_FuncPtr");
void *pfn = NULL;
if (obpfn) {
NS_ABORT_IF_FALSE(PyLong_Check(obpfn)||PyInt_Check(obpfn), "xpcom._NSGetModule_FuncPtr is not a long!");
pfn = PyLong_AsVoidPtr(obpfn);
}
pfnEntryPoint = (pfnPyXPCOM_NSGetModule)pfn;
}
if (pfnEntryPoint==NULL) {
LogError("Could not load main Python entry point\n");
return NS_ERROR_FAILURE;
}
#ifdef MOZ_TIMELINE
// If the timeline service is installed, see if we can install our hooks.
if (NULL==PyImport_ImportModule("timeline_hook")) {
@@ -204,6 +225,10 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
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!!!)
@@ -226,7 +251,7 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
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 = (*pfnEntryPoint)(servMgr, location, result);
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;

View File

@@ -0,0 +1,94 @@
# ***** 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 mozilla.org code.
#
# The Initial Developer of the Original Code is mozilla.org
# Portions created by the Initial Developer are Copyright (C) 2002
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mark Hammond <mhammond@skippinet.com.au> (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 *****
# The xpcom._xpcom module
DEPTH=../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
pyexecdir = @libdir@/python$(PYTHON_VER_DOTTED)/site-packages
include $(DEPTH)/config/autoconf.mk
LIBRARY_NAME = _xpcom$(PYTHON_DEBUG_SUFFIX)
REQUIRES = pyxpcom xpcom string $(NULL)
MOZILLA_INTERNAL_API = 1
FORCE_SHARED_LIB = 1
FORCE_USE_PIC = 1
DLL_SUFFIX=$(PYTHON_DLL_SUFFIX)
LOCAL_INCLUDES = $(PYTHON_INCLUDES)
EXTRA_LIBS += $(PYTHON_LIBS)
ifeq ($(OS_ARCH), WINNT)
EXTRA_LIBS += $(DIST)/lib/pyxpcom.lib
else
EXTRA_LIBS += -lpyxpcom
endif
CPPSRCS= \
_xpcom.cpp \
$(NULL)
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk
EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS)
IMPORT_LIBRARY := $(SHARED_LIBRARY:.pyd=.lib)
# Install into our Python directory
# default build installs into bin and lib - remove them
libs::
ifeq ($(OS_ARCH),WINNT)
$(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin/python/xpcom
else
$(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin/python/xpcom
mv $(DIST)/bin/python/xpcom/$(SHARED_LIBRARY) $(DIST)/bin/python/xpcom/_xpcom.so
endif
rm -f $(DIST)/bin/$(SHARED_LIBRARY)
rm -f $(DIST)/lib/$(IMPORT_LIBRARY)
install::
ifneq ($(OS_ARCH),WINNT)
$(SYSINSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(DISTDIR)$(pyexecdir)/xpcom
mv $(DISTDIR)$(pyexecdir)/xpcom/$(SHARED_LIBRARY) $(DISTDIR)$(pyexecdir)/xpcom/_xpcom$(PYTHON_DLL_SUFFIX)
endif
clobber::
rm -f *.ilk *.pdb

View File

@@ -45,14 +45,13 @@
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include "nsIThread.h"
#include "PyXPCOM.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "nsIModule.h"
#include "nsIFile.h"
#include "nsILocalFile.h"
#include "nsIComponentRegistrar.h"
#include "nsIConsoleService.h"
#include "nspr.h" // PR_fprintf
#ifdef XP_WIN
#ifndef WIN32_LEAN_AND_MEAN
@@ -64,85 +63,12 @@
#include "nsIEventQueue.h"
#include "nsIProxyObjectManager.h"
PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL;
extern PRInt32 _PyXPCOM_GetGatewayCount(void);
extern PRInt32 _PyXPCOM_GetInterfaceCount(void);
extern void AddDefaultGateway(PyObject *instance, nsISupports *gateway);
#define LOADER_LINKS_WITH_PYTHON
#ifndef PYXPCOM_USE_PYGILSTATE
extern void PyXPCOM_InterpreterState_Ensure();
extern PYXPCOM_EXPORT void PyXPCOM_InterpreterState_Ensure();
#endif
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)
////////////////////////////////////////////////////////////
// This is the main entry point called by the Python component
// loader.
extern "C" NS_EXPORT 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), PR_TRUE);
if (obServMgr==NULL) goto done;
obLocation = Py_nsISupports::PyObjectFromInterface(location, NS_GET_IID(nsIFile), PR_TRUE);
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;
}
// "boot-strap" methods - interfaces we need to get the base
// interface support!
@@ -151,15 +77,33 @@ PyXPCOMMethod_GetComponentManager(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIComponentManager* cm;
nsCOMPtr<nsIComponentManager> cm;
nsresult rv;
Py_BEGIN_ALLOW_THREADS;
rv = NS_GetComponentManager(&cm);
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, PR_FALSE);
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<nsIComponentRegistrar> 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 *
@@ -167,16 +111,16 @@ PyXPCOMMethod_GetServiceManager(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
nsIServiceManager* sm;
nsCOMPtr<nsIServiceManager> sm;
nsresult rv;
Py_BEGIN_ALLOW_THREADS;
rv = NS_GetServiceManager(&sm);
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), PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(sm, NS_GET_IID(nsIServiceManager));
}
static PyObject *
@@ -192,7 +136,7 @@ PyXPCOMMethod_XPTI_GetInterfaceInfoManager(PyObject *self, PyObject *args)
/* 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(im, NS_GET_IID(nsIInterfaceInfoManager), PR_TRUE, PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(im, NS_GET_IID(nsIInterfaceInfoManager), PR_FALSE);
}
static PyObject *
@@ -209,6 +153,11 @@ PyXPCOMMethod_XPTC_InvokeByIndex(PyObject *self, PyObject *args)
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)",
obIS->ob_type->tp_name);
}
// 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,
@@ -220,7 +169,7 @@ PyXPCOMMethod_XPTC_InvokeByIndex(PyObject *self, PyObject *args)
PR_FALSE))
return NULL;
PyXPCOM_InterfaceVariantHelper arg_helper;
PyXPCOM_InterfaceVariantHelper arg_helper((Py_nsISupports *)obIS);
if (!arg_helper.Init(obParams))
return NULL;
@@ -249,8 +198,8 @@ PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args)
if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
return NULL;
nsISupports *ret = NULL;
nsresult r = PyXPCOM_XPTStub::CreateNew(ob, iid, (void **)&ret);
nsCOMPtr<nsISupports> ret;
nsresult r = PyXPCOM_XPTStub::CreateNew(ob, iid, getter_AddRefs(ret));
if ( NS_FAILED(r) )
return PyXPCOM_BuildPyException(r);
@@ -259,7 +208,7 @@ PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args)
AddDefaultGateway(ob, ret); // inject a weak reference to myself into the instance.
// Now wrap it in an interface.
return Py_nsISupports::PyObjectFromInterface(ret, iid, PR_FALSE, bWrapClient);
return Py_nsISupports::PyObjectFromInterface(ret, iid, bWrapClient);
}
static PyObject *
@@ -327,8 +276,8 @@ PyXPCOMMethod_NS_ShutdownXPCOM(PyObject *self, PyObject *args)
nr = NS_ShutdownXPCOM(nsnull);
Py_END_ALLOW_THREADS;
// Don't raise an exception - as we are probably shutting down
// and don't really care - just return the status
// Dont raise an exception - as we are probably shutting down
// and dont really case - just return the status
return PyInt_FromLong(nr);
}
@@ -360,7 +309,7 @@ PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args)
}
nsresult rv_proxy;
nsISupports *presult = nsnull;
nsCOMPtr<nsISupports> presult;
Py_BEGIN_ALLOW_THREADS;
nsCOMPtr<nsIProxyObjectManager> proxyMgr =
do_GetService(kProxyObjectManagerCID, &rv_proxy);
@@ -370,7 +319,7 @@ PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args)
iid,
pob,
flags,
(void **)&presult);
getter_AddRefs(presult));
}
if (pQueueRelease)
pQueueRelease->Release();
@@ -378,24 +327,69 @@ PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args)
PyObject *result;
if (NS_SUCCEEDED(rv_proxy) ) {
result = Py_nsISupports::PyObjectFromInterface(presult, iid, PR_FALSE);
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<nsIVariant> 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<nsIVariant> 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)",
ob->ob_type->tp_name);
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;
nsIFile *file = NULL;
nsresult r = NS_GetSpecialDirectory(dirname, &file);
nsCOMPtr<nsIFile> 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), PR_FALSE);
return Py_nsISupports::PyObjectFromInterface(file, NS_GET_IID(nsIFile));
}
PyObject *AllocateBuffer(PyObject *self, PyObject *args)
@@ -406,31 +400,38 @@ PyObject *AllocateBuffer(PyObject *self, PyObject *args)
return PyBuffer_New(bufSize);
}
PyObject *LogWarning(PyObject *self, PyObject *args)
// 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;
PyXPCOM_LogWarning("%s", msg);
nsCOMPtr<nsIConsoleService> 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;
}
PyObject *LogError(PyObject *self, PyObject *args)
{
char *msg;
if (!PyArg_ParseTuple(args, "s", &msg))
return NULL;
PyXPCOM_LogError("%s", msg);
Py_INCREF(Py_None);
return Py_None;
}
extern PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args);
extern PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args);
static struct PyMethodDef xpcom_methods[]=
{
{"GetComponentManager", PyXPCOMMethod_GetComponentManager, 1},
{"GetComponentRegistrar", PyXPCOMMethod_GetComponentRegistrar, 1},
{"XPTI_GetInterfaceInfoManager", PyXPCOMMethod_XPTI_GetInterfaceInfoManager, 1},
{"XPTC_InvokeByIndex", PyXPCOMMethod_XPTC_InvokeByIndex, 1},
{"GetServiceManager", PyXPCOMMethod_GetServiceManager, 1},
@@ -445,83 +446,13 @@ static struct PyMethodDef xpcom_methods[]=
{"GetProxyForObject", PyXPCOMMethod_GetProxyForObject, 1},
{"GetSpecialDirectory", PyGetSpecialDirectory, 1},
{"AllocateBuffer", AllocateBuffer, 1},
{"LogWarning", LogWarning, 1},
{"LogError", LogError, 1},
{"LogConsoleMessage", LogConsoleMessage, 1, "Write a message to the xpcom console service"},
{"MakeVariant", PyXPCOMMethod_MakeVariant, 1},
{"GetVariantValue", PyXPCOMMethod_GetVariantValue, 1},
// These should no longer be used - just use the logging.getLogger('pyxpcom')...
{ NULL }
};
////////////////////////////////////////////////////////////
// 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<nsIThread> 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<nsILocalFile> 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;
}
return rc;
}
#define REGISTER_IID(t) { \
PyObject *iid_ob = Py_nsIID::PyObjectFromIID(NS_GET_IID(t)); \
PyDict_SetItemString(dict, "IID_"#t, iid_ob); \
@@ -562,16 +493,9 @@ init_xpcom() {
}
PyDict_SetItemString(dict, "IIDType", (PyObject *)&Py_nsIID::type);
// register our entry point.
PyObject *obFuncPtr = PyLong_FromVoidPtr((void *)&PyXPCOM_NSGetModule);
if (obFuncPtr)
PyDict_SetItemString(dict,
"_NSGetModule_FuncPtr",
obFuncPtr);
Py_XDECREF(obFuncPtr);
REGISTER_IID(nsISupports);
REGISTER_IID(nsISupportsCString);
REGISTER_IID(nsISupportsString);
REGISTER_IID(nsIModule);
REGISTER_IID(nsIFactory);
REGISTER_IID(nsIWeakReference);
@@ -579,20 +503,33 @@ init_xpcom() {
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);
Py_nsISupports::InitType();
Py_nsIComponentManager::InitType(dict);
Py_nsIInterfaceInfoManager::InitType(dict);
Py_nsIEnumerator::InitType(dict);
Py_nsISimpleEnumerator::InitType(dict);
Py_nsIInterfaceInfo::InitType(dict);
Py_nsIInputStream::InitType(dict);
Py_nsIClassInfo::InitType(dict);
Py_nsIVariant::InitType(dict);
// 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);
}

View File

@@ -0,0 +1,52 @@
# ***** 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 mozilla.org code
#
# The Initial Developer of the Original Code is mozilla.org.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mark Hammond: 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 *****
DEPTH =../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
DIRS = test_component $(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
check::
@echo "Running Python XPCOM tests"
@$(PYTHON)$(PYTHON_DEBUG_SUFFIX) $(srcdir)/regrtest.py

View File

@@ -1,8 +0,0 @@
test_com_exceptions
** Unhandled exception calling 'int8 do_short(in int16, inout int16, out int16, out retval int16);'
** Returning nsresult of NS_ERROR_FAILURE
** Unhandled exception calling 'int8 do_unsigned_short(in uint16, inout uint16, out uint16, out retval uint16);'
** Returning nsresult of NS_ERROR_FAILURE
** Unhandled exception calling 'int8 do_unsigned_long_long(in uint64, inout uint64, out uint64, out retval uint64);'
** Returning nsresult of NS_ERROR_FAILURE
The xpcom exception tests passed

View File

@@ -1,7 +0,0 @@
test_comfile
Open as string test worked.
Open as URL test worked.
File test using buffers worked.
Local file read test worked.
Read the correct data.
Chunks read the correct data.

View File

@@ -1,4 +0,0 @@
test_components
The interfaces object appeared to work!
The classes object appeared to work!
The ID function appeared to work!

View File

@@ -1,2 +0,0 @@
test_isupports_primitives
The nsISupports primitive interface tests appeared to work

View File

@@ -1 +0,0 @@
test_streams

View File

@@ -1,4 +0,0 @@
test_test_component
Testing the Python.TestComponent component
The Python test component worked!
Javascript could successfully use the Python test component.

View File

@@ -1,2 +0,0 @@
test_weakreferences
Weak-reference tests appear to have worked!

View File

@@ -1,4 +1,6 @@
# test tools for the pyxpcom
# test tools for the pyxpcom bindings
from xpcom import _xpcom
import unittest
# export a "getmemusage()" function that returns a useful "bytes used" count
# for the current process. Growth in this when doing the same thing over and
@@ -70,3 +72,55 @@ if have_pdh:
else:
def getmemusage():
return 0
# Test runner utilities, including some support for builtin leak tests.
class TestLoader(unittest.TestLoader):
def loadTestsFromTestCase(self, testCaseClass):
"""Return a suite of all tests cases contained in testCaseClass"""
leak_tests = []
for name in self.getTestCaseNames(testCaseClass):
real_test = testCaseClass(name)
leak_test = self._getTestWrapper(real_test)
leak_tests.append(leak_test)
return self.suiteClass(leak_tests)
def _getTestWrapper(self, test):
# later! see pywin32's win32/test/util.py
return test
def loadTestsFromModule(self, mod):
if hasattr(mod, "suite"):
ret = mod.suite()
else:
ret = unittest.TestLoader.loadTestsFromModule(self, mod)
assert ret.countTestCases() > 0, "No tests in %r" % (mod,)
return ret
def loadTestsFromName(self, name, module=None):
test = unittest.TestLoader.loadTestsFromName(self, name, module)
if isinstance(test, unittest.TestSuite):
pass # hmmm? print "Don't wrap suites yet!", test._tests
elif isinstance(test, unittest.TestCase):
test = self._getTestWrapper(test)
else:
print "XXX - what is", test
return test
# A base class our tests should derive from (well, one day it will be)
TestCase = unittest.TestCase
def suite_from_functions(*funcs):
suite = unittest.TestSuite()
for func in funcs:
suite.addTest(unittest.FunctionTestCase(func))
return suite
def testmain(*args, **kw):
new_kw = kw.copy()
if not new_kw.has_key('testLoader'):
new_kw['testLoader'] = TestLoader()
try:
unittest.main(*args, **new_kw)
finally:
_xpcom.NS_ShutdownXPCOM()
ni = _xpcom._GetInterfaceCount()
ng = _xpcom._GetGatewayCount()
if ni or ng:
print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng)

View File

@@ -42,28 +42,50 @@ import os
import sys
import unittest
import test.regrtest # The standard Python test suite.
path = os.path.abspath(os.path.split(sys.argv[0])[0])
# This sucks - python now uses "test." - so to worm around this,
# we append our test path to the test packages!
test.__path__.append(path)
# A little magic to create a single "test suite" from all test_ files
# in this dir. A single suite makes for prettier output test :)
def suite():
# Loop over all test_*.py files here
try:
me = __file__
except NameError:
me = sys.argv[0]
me = os.path.abspath(me)
files = os.listdir(os.path.dirname(me))
suite = unittest.TestSuite()
# XXX - add the others here!
#suite.addTest(unittest.FunctionTestCase(import_all))
for file in files:
base, ext = os.path.splitext(file)
if ext=='.py' and os.path.basename(base).startswith("test_"):
mod = __import__(base)
if hasattr(mod, "suite"):
test = mod.suite()
else:
test = unittest.defaultTestLoader.loadTestsFromModule(mod)
suite.addTest(test)
return suite
class CustomLoader(unittest.TestLoader):
def loadTestsFromModule(self, module):
return suite()
tests = []
for arg in sys.argv[1:]:
if arg[0] not in "-/":
tests.append(arg)
tests = tests or test.regrtest.findtests(path, [])
try:
# unittest based tests first - hopefully soon this will be the default!
if not sys.argv[1:]:
for t in "test_misc test_streams".split():
m = __import__(t)
try:
unittest.main(m)
except SystemExit:
pass
test.regrtest.main(tests, path)
unittest.TestProgram(testLoader=CustomLoader())(argv=sys.argv)
finally:
from xpcom import _xpcom
_xpcom.NS_ShutdownXPCOM() # To get leak stats and otherwise ensure life is good.
ni = _xpcom._GetInterfaceCount()
ng = _xpcom._GetGatewayCount()
if ni or ng:
# The old 'regrtest' that was not based purely on unittest did not
# do this check at the end - it relied on each module doing it itself.
# Thus, these leaks are not new, just newly noticed :) Likely to be
# something silly like module globals.
if ni == 6 and ng == 1:
print "Sadly, there are 6/1 leaks, but these appear normal and benign"
else:
print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng)
else:
print "yay! Our leaks have all vanished!"

View File

@@ -36,8 +36,12 @@
# Test pyxpcom exception.
from xpcom import components, nsError, ServerException, COMException
from xpcom import components, nsError, ServerException, COMException, logger
from xpcom.server import WrapObject
from pyxpcom_test_tools import testmain
import unittest
import logging
class PythonFailingComponent:
# Re-use the test interface for this test.
@@ -75,29 +79,46 @@ class PythonFailingComponent:
# Report of a crash in this case - test it!
raise ServerException, "A bad exception param"
def _testit(expected_errno, func, *args):
try:
apply(func, args)
except COMException, what:
if what.errno != expected_errno:
raise
class TestHandler(logging.Handler):
def __init__(self, level=logging.ERROR): # only counting error records
logging.Handler.__init__(self, level)
self.records = []
def reset(self):
self.records = []
def test():
# For the benefit of the test suite, we print some reassuring messages.
import sys
sys.__stderr__.write("***** NOTE: Three tracebacks below this is normal\n")
ob = WrapObject( PythonFailingComponent(), components.interfaces.nsIPythonTestInterfaceExtra)
_testit(nsError.NS_ERROR_FAILURE, ob.do_boolean, 0, 0)
_testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_octet, 0, 0)
_testit(nsError.NS_ERROR_FAILURE, ob.do_short, 0, 0)
_testit(nsError.NS_ERROR_FAILURE, ob.do_unsigned_short, 0, 0)
_testit(nsError.NS_ERROR_FAILURE, ob.do_long, 0, 0)
_testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_unsigned_long, 0, 0)
_testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_long_long, 0, 0)
_testit(nsError.NS_ERROR_FAILURE, ob.do_unsigned_long_long, 0, 0)
print "The xpcom exception tests passed"
# For the benefit of the test suite, some more reassuring messages.
sys.__stderr__.write("***** NOTE: Three tracebacks printed above this is normal\n")
sys.__stderr__.write("***** It is testing the Python XPCOM Exception semantics\n")
def handle(self, record):
self.records.append(record)
test()
class ExceptionTests(unittest.TestCase):
def _testit(self, expected_errno, num_tracebacks, func, *args):
# Screw with the logger
old_handlers = logger.handlers
test_handler = TestHandler()
logger.handlers = [test_handler]
try:
try:
apply(func, args)
except COMException, what:
if what.errno != expected_errno:
raise
finally:
logger.handlers = old_handlers
self.failUnlessEqual(num_tracebacks, len(test_handler.records))
def testEmAll(self):
ob = WrapObject( PythonFailingComponent(), components.interfaces.nsIPythonTestInterfaceExtra)
self._testit(nsError.NS_ERROR_FAILURE, 0, ob.do_boolean, 0, 0)
self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_octet, 0, 0)
self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_short, 0, 0)
self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_unsigned_short, 0, 0)
self._testit(nsError.NS_ERROR_FAILURE, 0, ob.do_long, 0, 0)
self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_unsigned_long, 0, 0)
self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_long_long, 0, 0)
self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_unsigned_long_long, 0, 0)
if __name__=='__main__':
testmain()

View File

@@ -36,6 +36,14 @@
# ***** END LICENSE BLOCK *****
"""Test the xpcom.file module."""
# Called "test_comfile" as Python has a standard test called test_file :-(
from pyxpcom_test_tools import suite_from_functions, testmain
import xpcom.file
xpcom.file._TestAll()
# Make this test run under our std test suite
def suite():
return suite_from_functions(xpcom.file._TestAll)
if __name__=='__main__':
testmain()

View File

@@ -212,6 +212,7 @@ interface nsIPythonTestInterfaceExtra : nsIPythonTestInterface
void AppendArray(inout PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]inout PRInt32 array2);
void AppendVariant(in nsIVariant variant, inout nsIVariant result);
nsIVariant CopyVariant(in nsIVariant variant);
nsIVariant SumVariants(in PRUint32 incount, [array, size_is(incount)]in nsIVariant variants);
};
// DOM String support is a "recent" (01/2001) addition to XPCOM. These test

View File

@@ -365,6 +365,14 @@ class PythonTestComponent:
def CopyVariant(self, invar):
return invar
def SumVariants(self, variants):
if len(variants) == 0:
return None
result = variants[0]
for v in variants[1:]:
result += v
return result
# Some tests for the "new" (Feb-2001) DOMString type.
def GetDOMStringResult( self, length ):
# Result: DOMString &

View File

@@ -39,6 +39,7 @@
"""
import xpcom.components
from pyxpcom_test_tools import suite_from_functions, testmain
if not __debug__:
raise RuntimeError, "This test uses assert, so must be run in debug mode"
@@ -63,9 +64,7 @@ def test_interfaces():
assert len(xpcom.components.interfaces.keys()) == len(xpcom.components.interfaces.values()) == \
len(xpcom.components.interfaces.items()) == len(xpcom.components.interfaces) == \
num_fetched, "The collection lengths were wrong"
if num_nsisupports != 1:
print "Didn't find exactly 1 nsiSupports!"
print "The interfaces object appeared to work!"
assert num_nsisupports == 1, "Didn't find exactly 1 nsiSupports!"
def test_classes():
# Need a well-known contractID here?
@@ -81,8 +80,7 @@ def test_classes():
for name, klass in xpcom.components.classes.items():
num_fetched = num_fetched + 1
if name == prog_id:
if klass.clsid != clsid:
print "Eeek - didn't get the correct IID - got", klass.clsid
assert klass.clsid == clsid, "Eeek - didn't get the correct IID - got %s" %klass.clsid
num_mine = num_mine + 1
# xpcom appears to add charset info to the contractid!?
@@ -98,15 +96,14 @@ def test_classes():
raise RuntimeError, "Didn't get any classes!!!"
if num_mine != 1:
raise RuntimeError, "Didn't find exactly 1 of my contractid! (%d)" % (num_mine,)
print "The classes object appeared to work!"
def test_id():
id = xpcom.components.ID(str(xpcom._xpcom.IID_nsISupports))
assert id == xpcom._xpcom.IID_nsISupports
print "The ID function appeared to work!"
# Make this test run under our std test suite
def suite():
return suite_from_functions(test_interfaces, test_classes, test_id)
# regrtest doesn't like if __name__=='__main__' blocks - it fails when running as a test!
test_interfaces()
test_classes()
test_id()
if __name__=='__main__':
testmain()

View File

@@ -41,10 +41,13 @@
# only if our class doesn't provide explicit support.
from xpcom import components
from xpcom import primitives
import xpcom.server, xpcom.client
from pyxpcom_test_tools import testmain
import unittest
class NoSupportsString:
_com_interfaces_ = [components.interfaces.nsISupports]
pass
class ImplicitSupportsString:
_com_interfaces_ = [components.interfaces.nsISupports]
@@ -52,13 +55,36 @@ class ImplicitSupportsString:
return "<MyImplicitStrObject>"
class ExplicitSupportsString:
_com_interfaces_ = [components.interfaces.nsISupports, components.interfaces.nsISupportsCString]
_com_interfaces_ = [components.interfaces.nsISupportsPrimitive,
components.interfaces.nsISupportsCString]
type = components.interfaces.nsISupportsPrimitive.TYPE_CSTRING
test_data = "<MyExplicitStrObject>"
# __str__ will be ignored by XPCOM, as we have _explicit_ support.
def __str__(self):
return "<MyImplicitStrObject>"
# This is the one that will be used.
# These are the ones that will be used.
def get_data(self):
return self.test_data
def toString(self):
return "<MyExplicitStrObject>"
return self.test_data
class ImplicitSupportsUnicode:
_com_interfaces_ = [components.interfaces.nsISupports]
test_data = u"Copyright \xa9 the initial developer"
def __unicode__(self):
# An extended character in unicode tests can't hurt!
return self.test_data
class ExplicitSupportsUnicode:
_com_interfaces_ = [components.interfaces.nsISupportsPrimitive,
components.interfaces.nsISupportsString]
type = components.interfaces.nsISupportsPrimitive.TYPE_STRING
# __unicode__ will be ignored by XPCOM, as we have _explicit_ support.
test_data = u"Copyright \xa9 the initial developer"
def __unicode__(self):
return self.test_data
def get_data(self):
return self.test_data
class ImplicitSupportsInt:
_com_interfaces_ = [components.interfaces.nsISupports]
@@ -66,7 +92,9 @@ class ImplicitSupportsInt:
return 99
class ExplicitSupportsInt:
_com_interfaces_ = [components.interfaces.nsISupportsPRInt32]
_com_interfaces_ = [components.interfaces.nsISupportsPrimitive,
components.interfaces.nsISupportsPRInt32]
type = components.interfaces.nsISupportsPrimitive.TYPE_PRINT32
def get_data(self):
return 99
@@ -76,12 +104,16 @@ class ImplicitSupportsLong:
return 99L
class ExplicitSupportsLong:
_com_interfaces_ = [components.interfaces.nsISupportsPRInt64]
_com_interfaces_ = [components.interfaces.nsISupportsPrimitive,
components.interfaces.nsISupportsPRInt64]
type = components.interfaces.nsISupportsPrimitive.TYPE_PRINT64
def get_data(self):
return 99
class ExplicitSupportsFloat:
_com_interfaces_ = [components.interfaces.nsISupportsDouble]
_com_interfaces_ = [components.interfaces.nsISupportsPrimitive,
components.interfaces.nsISupportsDouble]
type = components.interfaces.nsISupportsPrimitive.TYPE_DOUBLE
def get_data(self):
return 99.99
@@ -90,61 +122,86 @@ class ImplicitSupportsFloat:
def __float__(self):
return 99.99
def test():
import xpcom.server, xpcom.client
ob = xpcom.server.WrapObject( NoSupportsString(), components.interfaces.nsISupports)
if not str(ob).startswith("<XPCOM "):
raise RuntimeError, "Wrong str() value: %s" % (ob,)
class PrimitivesTestCase(unittest.TestCase):
def testNoSupports(self):
ob = xpcom.server.WrapObject( NoSupportsString(), components.interfaces.nsISupports)
if not str(ob).startswith("<XPCOM "):
raise RuntimeError, "Wrong str() value: %s" % (ob,)
ob = xpcom.server.WrapObject( ImplicitSupportsString(), components.interfaces.nsISupports)
if str(ob) != "<MyImplicitStrObject>":
raise RuntimeError, "Wrong str() value: %s" % (ob,)
def testImplicitString(self):
ob = xpcom.server.WrapObject( ImplicitSupportsString(), components.interfaces.nsISupports)
self.failUnlessEqual(str(ob), "<MyImplicitStrObject>")
ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports)
if str(ob) != "<MyExplicitStrObject>":
raise RuntimeError, "Wrong str() value: %s" % (ob,)
def testExplicitString(self):
ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports)
self.failUnlessEqual(str(ob), "<MyExplicitStrObject>")
# Try our conversions.
try:
int(ob)
raise RuntimeError, "Expected to get a ValueError converting this COM object to an int"
except ValueError:
pass
ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports)
if int(ob) != 99:
raise RuntimeError, "Bad value: %s" % (int(ob),)
if float(ob) != 99.0:
raise RuntimeError, "Bad value: %s" % (float(ob),)
def testImplicitUnicode(self):
ob = xpcom.server.WrapObject( ImplicitSupportsUnicode(), components.interfaces.nsISupports)
self.failUnlessEqual(unicode(ob), ImplicitSupportsUnicode.test_data)
ob = xpcom.server.WrapObject( ImplicitSupportsInt(), components.interfaces.nsISupports)
if int(ob) != 99:
raise RuntimeError, "Bad value: %s" % (int(ob),)
if float(ob) != 99.0:
raise RuntimeError, "Bad value: %s" % (float(ob),)
def testExplicitUnicode(self):
ob = xpcom.server.WrapObject( ExplicitSupportsUnicode(), components.interfaces.nsISupports)
self.failUnlessEqual(unicode(ob), ExplicitSupportsUnicode.test_data)
ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports)
if long(ob) != 99 or not repr(long(ob)).endswith("L"):
raise RuntimeError, "Bad value: %s" % (repr(long(ob)),)
if float(ob) != 99.0:
raise RuntimeError, "Bad value: %s" % (float(ob),)
def testConvertInt(self):
# Try our conversions.
ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports)
self.failUnlessRaises( ValueError, int, ob)
ob = xpcom.server.WrapObject( ImplicitSupportsLong(), components.interfaces.nsISupports)
if long(ob) != 99 or not repr(long(ob)).endswith("L"):
raise RuntimeError, "Bad value: %s" % (repr(long(ob)),)
if float(ob) != 99.0:
raise RuntimeError, "Bad value: %s" % (float(ob),)
def testExplicitInt(self):
ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports)
self.failUnlessAlmostEqual(float(ob), 99.0)
self.failUnlessEqual(int(ob), 99)
ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports)
if float(ob) != 99.99:
raise RuntimeError, "Bad value: %s" % (float(ob),)
if int(ob) != 99:
raise RuntimeError, "Bad value: %s" % (int(ob),)
def testImplicitInt(self):
ob = xpcom.server.WrapObject( ImplicitSupportsInt(), components.interfaces.nsISupports)
self.failUnlessAlmostEqual(float(ob), 99.0)
self.failUnlessEqual(int(ob), 99)
ob = xpcom.server.WrapObject( ImplicitSupportsFloat(), components.interfaces.nsISupports)
if float(ob) != 99.99:
raise RuntimeError, "Bad value: %s" % (float(ob),)
if int(ob) != 99:
raise RuntimeError, "Bad value: %s" % (int(ob),)
def testExplicitLong(self):
ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports)
if long(ob) != 99 or not repr(long(ob)).endswith("L"):
raise RuntimeError, "Bad value: %s" % (repr(long(ob)),)
self.failUnlessAlmostEqual(float(ob), 99.0)
print "The nsISupports primitive interface tests appeared to work"
test()
def testImplicitLong(self):
ob = xpcom.server.WrapObject( ImplicitSupportsLong(), components.interfaces.nsISupports)
if long(ob) != 99 or not repr(long(ob)).endswith("L"):
raise RuntimeError, "Bad value: %s" % (repr(long(ob)),)
self.failUnlessAlmostEqual(float(ob), 99.0)
def testExplicitFloat(self):
ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports)
self.failUnlessEqual(float(ob), 99.99)
self.failUnlessEqual(int(ob), 99)
def testImplicitFloat(self):
ob = xpcom.server.WrapObject( ImplicitSupportsFloat(), components.interfaces.nsISupports)
self.failUnlessEqual(float(ob), 99.99)
self.failUnlessEqual(int(ob), 99)
class PrimitivesModuleTestCase(unittest.TestCase):
def testExplicitString(self):
ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports)
self.failUnlessEqual(primitives.GetPrimitive(ob), "<MyExplicitStrObject>")
def testExplicitUnicode(self):
ob = xpcom.server.WrapObject( ExplicitSupportsUnicode(), components.interfaces.nsISupports)
self.failUnlessEqual(primitives.GetPrimitive(ob), ExplicitSupportsUnicode.test_data)
self.failUnlessEqual(type(primitives.GetPrimitive(ob)), unicode)
def testExplicitInt(self):
ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports)
self.failUnlessEqual(primitives.GetPrimitive(ob), 99)
def testExplicitLong(self):
ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports)
self.failUnlessEqual(primitives.GetPrimitive(ob), 99)
def testExplicitFloat(self):
ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports)
self.failUnlessEqual(primitives.GetPrimitive(ob), 99.99)
if __name__=='__main__':
testmain()

View File

@@ -41,6 +41,7 @@ import xpcom.server
import xpcom._xpcom
import xpcom.components
import string
from pyxpcom_test_tools import testmain
import unittest
@@ -223,10 +224,13 @@ class TestUnwrap(unittest.TestCase):
return
self.failUnlessRaises(ValueError, xpcom.server.UnwrapObject, ob)
class TestNonScriptable(unittest.TestCase):
def testQI(self):
# Test we can QI for a non-scriptable interface. We can't *do* much
# with it (other than pass it on), but we should still work and get
# a basic wrapper.
ob = xpcom.components.classes["Python.TestComponent"].createInstance()
ob = ob.queryInterface(xpcom._xpcom.IID_nsIInternalPython)
if __name__=='__main__':
unittest.main()
xpcom._xpcom.NS_ShutdownXPCOM()
ni = xpcom._xpcom._GetInterfaceCount()
ng = xpcom._xpcom._GetGatewayCount()
if ni or ng:
print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng)
testmain()

View File

@@ -39,6 +39,7 @@ import xpcom
from xpcom import _xpcom, components, COMException, ServerException, nsError
from StringIO import StringIO
import unittest
from pyxpcom_test_tools import testmain
test_data = "abcdefeghijklmnopqrstuvwxyz"
@@ -92,4 +93,4 @@ class StreamTests(unittest.TestCase):
# stream observer mechanism has changed - we should test that.
if __name__=='__main__':
unittest.main()
testmain()

View File

@@ -130,5 +130,9 @@ v2[3] = 6;
if (c.SumArrays(v.length, v, v2) != 21)
throw("Could not sum an array of integers!");
var count = new Object();
count.value = 0;
var out = [];
c.DoubleStringArray(count, out);
print("javascript successfully tested the Python test component.");

View File

@@ -40,6 +40,8 @@ import xpcom.components
import xpcom._xpcom
import xpcom.nsError
MakeVariant = xpcom._xpcom.MakeVariant
try:
import gc
except ImportError:
@@ -406,11 +408,19 @@ def test_derived_interface(c, test_flat = 0):
test_method(c.CopyVariant, (("foo","bar"),), ["foo", "bar"])
test_method(c.CopyVariant, ((component_iid,component_iid),), [component_iid,component_iid])
test_method(c.CopyVariant, ((c,c),), [c,c])
sup = c.queryInterface(xpcom.components.interfaces.nsISupports)._comobj_
test_method(c.CopyVariant, ((sup, sup),), [sup,sup])
test_method(c.AppendVariant, (1,2), 3)
test_method(c.AppendVariant, ((1,2),(3,4)), 10)
test_method(c.AppendVariant, ("bar", "foo"), "foobar")
test_method(c.AppendVariant, (None, None), None)
test_method(c.SumVariants, ([],), None)
# Array's dont expose their interface, so we are unable to auto-wrap
# variant arrays, as they aren't aware if the IID of the array
test_method(c.SumVariants, ([MakeVariant(1),MakeVariant(2),MakeVariant(3)],), 6)
test_method(c.SumVariants, ([MakeVariant('foo'), MakeVariant('bar')],), 'foobar')
if not test_flat:
c = c.queryInterface(xpcom.components.interfaces.nsIPythonTestInterfaceDOMStrings)
# NULL DOM strings don't work yet.
@@ -491,29 +501,20 @@ def test_from_js():
raise RuntimeError, "Can not find '%s'" % (fname,)
# Note we _dont_ pump the test output out, as debug "xpcshell" spews
# extra debug info that will cause our output comparison to fail.
try:
data = os.popen('xpcshell "' + fname + '"').readlines()
good = 0
for line in data:
if line.strip() == "javascript successfully tested the Python test component.":
good = 1
if good:
print "Javascript could successfully use the Python test component."
else:
print "** The javascript test appeared to fail! Test output follows **"
print "".join(data)
print "** End of javascript test output **"
except os.error, why:
print "Error executing the javascript test program:", why
data = os.popen('xpcshell "' + fname + '"').readlines()
good = 0
for line in data:
if line.strip() == "javascript successfully tested the Python test component.":
good = 1
if not good:
print "** The javascript test appeared to fail! Test output follows **"
print "".join(data)
print "** End of javascript test output **"
raise RuntimeError, "test failed"
def doit(num_loops = -1):
if "-v" in sys.argv: # Hack the verbose flag for the server
xpcom.verbose = 1
# Do the test lots of times - can help shake-out ref-count bugs.
print "Testing the Python.TestComponent component"
if num_loops == -1: num_loops = 10
if num_loops == -1: num_loops = 5
for i in xrange(num_loops):
test_all()
@@ -535,38 +536,40 @@ def doit(num_loops = -1):
# Sometimes we get spurious counts off by 1 or 2.
# This can't indicate a real leak, as we have looped
# more than twice!
if abs(lost)>2:
if abs(lost)>3: # 2 or 3 :)
print "*** Lost %d references" % (lost,)
# sleep to allow the OS to recover
time.sleep(1)
mem_lost = getmemusage() - mem_usage
# working set size is fickle, and when we were leaking strings, this test
# would report a leak of 100MB. So we allow a 2MB buffer - but even this
# would report a leak of 100MB. So we allow a 3MB buffer - but even this
# may still occasionally report spurious warnings. If you are really
# worried, bump the counter to a huge value, and if there is a leak it will
# show.
if mem_lost > 2000000:
if mem_lost > 3000000:
print "*** Lost %.6f MB of memory" % (mem_lost/1000000.0,)
if num_errors:
print "There were", num_errors, "errors testing the Python component :-("
else:
print "The Python test component worked!"
assert num_errors==0, "There were %d errors testing the Python component" % (num_errors,)
# regrtest doesn't like if __name__=='__main__' blocks - it fails when running as a test!
num_iters = -1
if __name__=='__main__' and len(sys.argv) > 1:
num_iters = int(sys.argv[1])
doit(num_iters)
test_from_js()
def suite():
from pyxpcom_test_tools import suite_from_functions
return suite_from_functions(doit, test_from_js)
if __name__=='__main__':
# But we can only do this if _not_ testing - otherwise we
# screw up any tests that want to run later.
num_iters = 10 # times times is *lots* - we do a fair bit of work!
if __name__=='__main__' and len(sys.argv) > 1:
num_iters = int(sys.argv[1])
if "-v" in sys.argv: # Hack the verbose flag for the server
xpcom.verbose = 1
print "Testing the Python.TestComponent component"
doit(num_iters)
print "The Python test component worked."
test_from_js()
print "JS successfully used our Python test component."
xpcom._xpcom.NS_ShutdownXPCOM()
ni = xpcom._xpcom._GetInterfaceCount()
ng = xpcom._xpcom._GetGatewayCount()
if ni or ng:
print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng)
print "test completed with %d interfaces and %d objects." % (ni, ng)

View File

@@ -38,6 +38,7 @@
# test_weakreferences.py - Test our weak reference implementation.
from xpcom import components, _xpcom
import xpcom.server, xpcom.client
from pyxpcom_test_tools import suite_from_functions, testmain
try:
from sys import gettotalrefcount
@@ -104,13 +105,10 @@ def test_refcount(num_loops=-1):
# more than twice!
if abs(lost)>2:
print "*** Lost %d references" % (lost,)
test_refcount()
print "Weak-reference tests appear to have worked!"
# Make this test run under our std test suite
def suite():
return suite_from_functions(test_refcount)
if __name__=='__main__':
_xpcom.NS_ShutdownXPCOM()
ni = xpcom._xpcom._GetInterfaceCount()
ng = xpcom._xpcom._GetGatewayCount()
if ni or ng:
print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng)
testmain()

View File

@@ -36,32 +36,33 @@
# ***** END LICENSE BLOCK *****
# regxpcom.py - basically the standard regxpcom.cpp ported to Python.
# In general, you should use regxpcom.exe instead of this.
from xpcom import components, _xpcom
from xpcom.client import Component
import sys
import os
registrar = Component(_xpcom.GetComponentRegistrar(),
components.interfaces.nsIComponentRegistrar)
def ProcessArgs(args):
unregister = 0
for arg in args:
spec = components.classes['@mozilla.org/file/local;1'].createInstance()
spec = spec.QueryInterface(components.interfaces.nsILocalFile)
spec.initWithPath(os.path.abspath(arg))
if arg == "-u":
unregister = 1
registrar.autoUnregister(spec)
print "Successfully unregistered", spec.path
else:
spec = components.classes['@mozilla.org/file/local;1'].createInstance()
spec = spec.QueryInterface(components.interfaces.nsILocalFile)
spec.initWithPath(os.path.abspath(arg))
if unregister:
components.manager.autoUnregisterComponent( components.manager.NS_Startup, spec)
print "Successfully unregistered", spec.path
else:
components.manager.autoRegisterComponent( components.manager.NS_Startup, spec)
print "Successfully registered", spec.path
unregister = 0
registrar.autoRegister(spec)
print "Successfully registered", spec.path
import xpcom
if len(sys.argv) < 2:
components.manager.autoRegister( components.manager.NS_Startup, None)
registrar.autoRegister( None)
else:
ProcessArgs(sys.argv[1:])
_xpcom.NS_ShutdownXPCOM()
#_xpcom.NS_ShutdownXPCOM()

View File

@@ -76,15 +76,10 @@ from xpcom_consts import *
class Interface:
def __init__(self, iid):
iim = xpcom._xpcom.XPTI_GetInterfaceInfoManager()
try:
if hasattr(iid, "upper"): # Is it a stringy thing.
item = iim.GetInfoForName(iid)
else:
item = iim.GetInfoForIID(iid)
except xpcom.COMException:
name = getattr(iid, "name", str(iid))
print "Failed to get info for IID '%s'" % (name,)
raise
if hasattr(iid, "upper"): # Is it a stringy thing.
item = iim.GetInfoForName(iid)
else:
item = iim.GetInfoForIID(iid)
self.interface_info = item
self.namespace = "" # where does this come from?
self.methods = Methods(item)