diff options
author | Xisco Fauli <anistenis@gmail.com> | 2011-08-21 21:50:13 +0200 |
---|---|---|
committer | Xisco Fauli <anistenis@gmail.com> | 2011-08-21 21:50:13 +0200 |
commit | 6c76e4db034fd2c43884698b1a30225fd00b3bfd (patch) | |
tree | 1937cb9be81cd2b9f3d0ad27adcc7a7531b8f29d /pyuno | |
parent | e9440fb5a0579096423c081b0f0a2185b628e896 (diff) | |
parent | 36703ca1de68cd62782d0d425123521a5bc6732b (diff) |
Merge branch 'master' into feature/gsoc2011_wizards
Conflicts:
automation/source/inc/cmdbasestream.hxx
automation/source/server/cmdbasestream.cxx
automation/source/server/retstrm.hxx
automation/source/testtool/cmdstrm.cxx
automation/source/testtool/cmdstrm.hxx
automation/source/testtool/tcommuni.cxx
basctl/prj/d.lst
basctl/uiconfig/basicide/toolbar/findbar.xml
cui/source/dialogs/about.cxx
cui/source/dialogs/about.src
cui/source/inc/about.hxx
extensions/source/abpilot/abpservices.cxx
extensions/source/dbpilots/dbpservices.cxx
extensions/source/propctrlr/pcrservices.cxx
extensions/source/svg/makefile.mk
forms/Library_frm.mk
lingucomponent/source/hyphenator/altlinuxhyph/hyphen/hyphenimp.cxx
lingucomponent/source/spellcheck/spell/sspellimp.cxx
package/prj/d.lst
package/source/zipapi/XMemoryStream.cxx
package/source/zipapi/XMemoryStream.hxx
setup_native/prj/d.lst
setup_native/source/win32/customactions/relnotes/makefile.mk
tools/test/export.map
wizards/com/sun/star/wizards/common/ConfigGroup.py
wizards/com/sun/star/wizards/common/ConfigNode.py
wizards/com/sun/star/wizards/common/Configuration.py
wizards/com/sun/star/wizards/common/Desktop.py
wizards/com/sun/star/wizards/common/FileAccess.py
wizards/com/sun/star/wizards/common/Helper.py
wizards/com/sun/star/wizards/common/SystemDialog.py
wizards/com/sun/star/wizards/document/OfficeDocument.py
wizards/com/sun/star/wizards/fax/FaxDocument.py
wizards/com/sun/star/wizards/fax/FaxWizardDialog.py
wizards/com/sun/star/wizards/fax/FaxWizardDialogConst.py
wizards/com/sun/star/wizards/fax/FaxWizardDialogImpl.py
wizards/com/sun/star/wizards/fax/FaxWizardDialogResources.py
wizards/com/sun/star/wizards/letter/LetterDocument.py
wizards/com/sun/star/wizards/letter/LetterWizardDialog.py
wizards/com/sun/star/wizards/letter/LetterWizardDialogConst.py
wizards/com/sun/star/wizards/letter/LetterWizardDialogImpl.py
wizards/com/sun/star/wizards/letter/LetterWizardDialogResources.py
wizards/com/sun/star/wizards/text/TextDocument.py
wizards/com/sun/star/wizards/text/TextFieldHandler.py
wizards/com/sun/star/wizards/text/TextSectionHandler.py
wizards/com/sun/star/wizards/text/ViewHandler.py
wizards/com/sun/star/wizards/ui/UnoDialog.py
wizards/com/sun/star/wizards/ui/UnoDialog2.py
wizards/com/sun/star/wizards/ui/WizardDialog.py
wizards/com/sun/star/wizards/ui/event/CommonListener.py
wizards/com/sun/star/wizards/ui/event/DataAware.py
wizards/com/sun/star/wizards/ui/event/RadioDataAware.py
wizards/com/sun/star/wizards/ui/event/UnoDataAware.py
wizards/util/helpids.h
wizards/util/hidother.src
xmlsecurity/prj/build.lst
xmlsecurity/prj/d.lst
xmlsecurity/qa/certext/SanCertExt.cxx
Diffstat (limited to 'pyuno')
38 files changed, 7704 insertions, 0 deletions
diff --git a/pyuno/demo/Addons.xcu b/pyuno/demo/Addons.xcu new file mode 100644 index 000000000000..75ec5188e6d0 --- /dev/null +++ b/pyuno/demo/Addons.xcu @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<oor:node xmlns:oor="http://openoffice.org/2001/registry" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + oor:name="Addons" oor:package="org.openoffice.Office"> +<node oor:name="AddonUI"> + <node oor:name="AddonMenu"> + <node oor:name="org.openoffice.comp.pyuno.demo.HelloWorld" oor:op="replace"> + <prop oor:name="URL" oor:type="xs:string"> + <value>service:org.openoffice.comp.pyuno.demo.HelloWorld?insert</value> + </prop> + <prop oor:name="ImageIdentifier" oor:type="xs:string"> + <value>private:image/3216</value> + </prop> + <prop oor:name="Title" oor:type="xs:string"> + <value xml:lang="x-no-translate">Insert Hello World</value> + <value xml:lang="en-US">Insert Hello World</value> + </prop> + </node> + </node> +</node> +</oor:node> diff --git a/pyuno/demo/biblioaccess.py b/pyuno/demo/biblioaccess.py new file mode 100644 index 000000000000..59d843ad6c01 --- /dev/null +++ b/pyuno/demo/biblioaccess.py @@ -0,0 +1,36 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +import uno +from com.sun.star.sdb.CommandType import COMMAND + +def main(): + connectionString = "socket,host=localhost,port=2002" + + url = "uno:" + connectionString + ";urp;StarOffice.ComponentContext" + + localCtx = uno.getComponentContext() + localSmgr = localCtx.ServiceManager + resolver = localSmgr.createInstanceWithContext( + "com.sun.star.bridge.UnoUrlResolver", localCtx) + ctx = resolver.resolve(url) + smgr = ctx.ServiceManager + + rowset =smgr.createInstanceWithContext("com.sun.star.sdb.RowSet", ctx) + rowset.DataSourceName = "Bibliography" + rowset.CommandType = COMMAND + rowset.Command = "SELECT IDENTIFIER, AUTHOR FROM biblio" + + rowset.execute(); + + print("Identifier\tAuthor") + + id = rowset.findColumn("IDENTIFIER") + author = rowset.findColumn("AUTHOR") + while rowset.next(): + print(rowset.getString(id) + "\t" + repr(rowset.getString(author))) + + rowset.dispose(); + +main() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/demo/hello_world_comp.py b/pyuno/demo/hello_world_comp.py new file mode 100644 index 000000000000..32f40562856d --- /dev/null +++ b/pyuno/demo/hello_world_comp.py @@ -0,0 +1,43 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +import uno +import unohelper + +from com.sun.star.task import XJobExecutor + +# implement a UNO component by deriving from the standard unohelper.Base class +# and from the interface(s) you want to implement. +class HelloWorldJob(unohelper.Base, XJobExecutor): + def __init__(self, ctx): + # store the component context for later use + self.ctx = ctx + + def trigger(self, args): + # note: args[0] == "HelloWorld", see below config settings + + # retrieve the desktop object + desktop = self.ctx.ServiceManager.createInstanceWithContext( + "com.sun.star.frame.Desktop", self.ctx) + + # get current document model + model = desktop.getCurrentComponent() + + # access the document's text property + text = model.Text + + # create a cursor + cursor = text.createTextCursor() + + # insert the text into the document + text.insertString(cursor, "Hello World", 0) + +# pythonloader looks for a static g_ImplementationHelper variable +g_ImplementationHelper = unohelper.ImplementationHelper() + +g_ImplementationHelper.addImplementation( \ + HelloWorldJob, # UNO object class + "org.openoffice.comp.pyuno.demo.HelloWorld", # implemenation name + ("com.sun.star.task.Job",),) # list of implemented services + # (the only service) + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/demo/makefile.mk b/pyuno/demo/makefile.mk new file mode 100644 index 000000000000..e00a2fb7ca56 --- /dev/null +++ b/pyuno/demo/makefile.mk @@ -0,0 +1,42 @@ +PRJNAME=pyuno +PRJ=.. + +.INCLUDE : settings.mk +.INCLUDE : pyversion.mk + +ROOT=$(MISC)/pyuno-doc + +FILES=\ + $(ROOT)/python-bridge.html \ + $(ROOT)/customized_setup.png \ + $(ROOT)/mode_component.png \ + $(ROOT)/mode_ipc.png \ + $(ROOT)/modes.sxd \ + $(ROOT)/optional_components.png \ + $(ROOT)/samples/swriter.py \ + $(ROOT)/samples/swritercomp.py \ + $(ROOT)/samples/ooextract.py \ + $(ROOT)/samples/biblioaccess.py \ + $(ROOT)/samples/swritercompclient.py \ + $(ROOT)/samples/hello_world_pyuno.zip + + +$(MISC)/pyuno-doc.zip : dirs $(FILES) + -rm -f $@ + cd $(MISC) && zip -r pyuno-doc.zip pyuno-doc + +dirs .PHONY : + -mkdir $(ROOT) + -mkdir $(ROOT)/samples + +$(ROOT)/samples/hello_world_pyuno.zip : hello_world_comp.py Addons.xcu + -rm -f $@ + zip $@ hello_world_comp.py Addons.xcu + +$(ROOT)/samples/% : % + -rm -f $@ + $(COPY) $? $@ + +$(ROOT)/% : ../doc/% + -rm -f $@ + $(COPY) $? $@ diff --git a/pyuno/demo/ooextract.py b/pyuno/demo/ooextract.py new file mode 100644 index 000000000000..3959bf74b200 --- /dev/null +++ b/pyuno/demo/ooextract.py @@ -0,0 +1,112 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +import getopt,sys +import uno +from unohelper import Base,systemPathToFileUrl, absolutize +from os import getcwd + +from com.sun.star.beans import PropertyValue +from com.sun.star.beans.PropertyState import DIRECT_VALUE +from com.sun.star.uno import Exception as UnoException +from com.sun.star.io import IOException,XInputStream, XOutputStream + +class OutputStream(Base, XOutputStream): + def __init__(self): + self.closed = 0 + + def closeOutput(self): + self.closed = 1 + + def writeBytes(self, seq): + sys.stdout.write(seq.value) + + def flush(self): + pass + +def main(): + retVal = 0 + doc = None + + try: + opts, args = getopt.getopt(sys.argv[1:], "hc:", ["help", "connection-string=", "html"]) + format = None + url = "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" + filterName = "Text (Encoded)" + for o, a in opts: + if o in ("-h", "--help"): + usage() + sys.exit() + if o in ("-c", "--connection-string"): + url = "uno:" + a + ";urp;StarOffice.ComponentContext" + if o == "--html": + filterName = "HTML (StarWriter)" + + print(filterName) + if not len(args): + usage() + sys.exit() + + ctxLocal = uno.getComponentContext() + smgrLocal = ctxLocal.ServiceManager + + resolver = smgrLocal.createInstanceWithContext( + "com.sun.star.bridge.UnoUrlResolver", ctxLocal) + ctx = resolver.resolve(url) + smgr = ctx.ServiceManager + + desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx) + + cwd = systemPathToFileUrl(getcwd()) + outProps = ( + PropertyValue("FilterName" , 0, filterName, 0), + PropertyValue("OutputStream", 0, OutputStream(), 0)) + inProps = PropertyValue("Hidden", 0 , True, 0), + for path in args: + try: + fileUrl = uno.absolutize(cwd, systemPathToFileUrl(path)) + doc = desktop.loadComponentFromURL(fileUrl , "_blank", 0, inProps) + + if not doc: + raise UnoException("Could not open stream for unknown reason", None) + + doc.storeToURL("private:stream", outProps) + except IOException as e: + sys.stderr.write("Error during conversion: " + e.Message + "\n") + retVal = 1 + except UnoException as e: + sys.stderr.write("Error (" + repr(e.__class__) + ") during conversion: " + e.Message + "\n") + retVal = 1 + if doc: + doc.dispose() + + except UnoException as e: + sys.stderr.write("Error (" + repr(e.__class__) + "): " + e.Message + "\n") + retVal = 1 + except getopt.GetoptError as e: + sys.stderr.write(str(e) + "\n") + usage() + retVal = 1 + + sys.exit(retVal) + +def usage(): + sys.stderr.write("usage: ooextract.py --help |\n"+ + " [-c <connection-string> | --connection-string=<connection-string>\n"+ + " file1 file2 ...\n"+ + "\n" + + "Extracts plain text from documents and prints it to stdout.\n" + + "Requires an OpenOffice.org instance to be running. The script and the\n"+ + "running OpenOffice.org instance must be able to access the file with\n"+ + "by the same system path.\n" + "\n"+ + "-c <connection-string> | --connection-string=<connection-string>\n" + + " The connection-string part of a uno url to where the\n" + + " the script should connect to in order to do the conversion.\n" + + " The strings defaults to socket,host=localhost,port=2002\n" + "--html \n" + " Instead of the text filter, the writer html filter is used\n" + ) + +main() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/demo/pyunoenv.bat b/pyuno/demo/pyunoenv.bat new file mode 100644 index 000000000000..1a8239992a4b --- /dev/null +++ b/pyuno/demo/pyunoenv.bat @@ -0,0 +1,6 @@ +set OOOHOME= + + +set PYTHONPATH=.;%OOOHOME%\program;%OOOHOME%\program\pydemo;%OOOHOME%\program\python-2.2.2;%PYTHONPATH% +set PATH=%OOOHOME%\program;%PYTHONHOME%;%OOOHOME%\program\python-2.2.2\bin;%PATH% + diff --git a/pyuno/demo/pyunoenv.tcsh b/pyuno/demo/pyunoenv.tcsh new file mode 100644 index 000000000000..dbe69d0ec66c --- /dev/null +++ b/pyuno/demo/pyunoenv.tcsh @@ -0,0 +1,32 @@ +# the path to the office installation (e.g. /home/joe/OpenOffice.org1.1Beta) +setenv OOOHOME /src4/OpenOffice.org1.1Beta2 + +# don't modify anything beyond these lines +#--------------------------------------------- +setenv PYTHONHOME $OOOHOME/program/python + +if( ! $?LD_LIBRARY_PATH ) then + setenv LD_LIBRARY_PATH +endif + +if(! $?PYTHONPATH ) then + setenv PYTHONPATH +endif + +if( ! $?LD_LIBRARY_PATH ) then +setenv LD_LIBRARY_PATH +endif + +if( "$PYTHONPATH" != "" ) then + setenv PYTHONPATH $OOOHOME/program:$OOOHOME/program/pydemo:$OOOHOME/program/python/lib:$PYTHONPATH +else + setenv PYTHONPATH $OOOHOME/program:$OOOHOME/program/pydemo:$OOOHOME/program/python/lib +endif + +setenv LD_LIBRARY_PATH $OOOHOME/program:$LD_LIBRARY_PATH + +if( $?PYTHONHOME ) then +setenv PATH $PYTHONHOME/bin:$PATH +endif + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/demo/swriter.py b/pyuno/demo/swriter.py new file mode 100644 index 000000000000..bf40a56e99f1 --- /dev/null +++ b/pyuno/demo/swriter.py @@ -0,0 +1,105 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +# bootstrap uno component context +import uno +import unohelper + +from com.sun.star.lang import IllegalArgumentException + +# a UNO struct later needed to create a document +from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK +from com.sun.star.text.TextContentAnchorType import AS_CHARACTER +from com.sun.star.awt import Size + + +def insertTextIntoCell( table, cellName, text, color ): + tableText = table.getCellByName( cellName ) + cursor = tableText.createTextCursor() + cursor.setPropertyValue( "CharColor", color ) + tableText.setString( text ) + +localContext = uno.getComponentContext() + +resolver = localContext.ServiceManager.createInstanceWithContext( + "com.sun.star.bridge.UnoUrlResolver", localContext ) + +smgr = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" ) +remoteContext = smgr.getPropertyValue( "DefaultContext" ) + +#remoteContext = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" ) +#smgr = remoteContext.ServiceManager + +desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",remoteContext) + +# open a writer document +doc = desktop.loadComponentFromURL( "private:factory/swriter","_blank", 0, () ) + +text = doc.Text +cursor = text.createTextCursor() +text.insertString( cursor, "The first line in the newly created text document.\n", 0 ) +text.insertString( cursor, "Now we are in the second line\n" , 0 ) + +# create a text table +table = doc.createInstance( "com.sun.star.text.TextTable" ) + +# with 4 rows and 4 columns +table.initialize(4, 4) + +text.insertTextContent( cursor, table, 0 ) +rows = table.Rows + +table.setPropertyValue( "BackTransparent", False ) +table.setPropertyValue( "BackColor", 13421823 ) +row = rows.getByIndex(0) +row.setPropertyValue( "BackTransparent", False ) +row.setPropertyValue( "BackColor", 6710932 ) + +textColor = 16777215 + +insertTextIntoCell( table, "A1", "FirstColumn", textColor ) +insertTextIntoCell( table, "B1", "SecondColumn", textColor ) +insertTextIntoCell( table, "C1", "ThirdColumn", textColor ) +insertTextIntoCell( table, "D1", "SUM", textColor ) + +table.getCellByName("A2").setValue(22.5) +table.getCellByName("B2").setValue(5615.3) +table.getCellByName("C2").setValue(-2315.7) +table.getCellByName("D2").setFormula("sum <A2:C2>") + +table.getCellByName("A3").setValue(21.5) +table.getCellByName("B3").setValue(615.3) +table.getCellByName("C3").setValue(-315.7) +table.getCellByName("D3").setFormula("sum <A3:C3>") + +table.getCellByName("A4").setValue(121.5) +table.getCellByName("B4").setValue(-615.3) +table.getCellByName("C4").setValue(415.7) +table.getCellByName("D4").setFormula("sum <A4:C4>") + + +cursor.setPropertyValue( "CharColor", 255 ) +cursor.setPropertyValue( "CharShadowed", True ) + +text.insertControlCharacter( cursor, PARAGRAPH_BREAK, 0 ) +text.insertString( cursor, " This is a colored Text - blue with shadow\n" , 0 ) +text.insertControlCharacter( cursor, PARAGRAPH_BREAK, 0 ) + +textFrame = doc.createInstance( "com.sun.star.text.TextFrame" ) +textFrame.setSize( Size(15000,400)) +textFrame.setPropertyValue( "AnchorType" , AS_CHARACTER ) + + +text.insertTextContent( cursor, textFrame, 0 ) + +textInTextFrame = textFrame.getText() +cursorInTextFrame = textInTextFrame.createTextCursor() +textInTextFrame.insertString( cursorInTextFrame, "The first line in the newly created text frame.", 0 ) +textInTextFrame.insertString( cursorInTextFrame, "\nWith this second line the height of the rame raises.",0) +text.insertControlCharacter( cursor, PARAGRAPH_BREAK, 0 ) + +cursor.setPropertyValue( "CharColor", 65536 ) +cursor.setPropertyValue( "CharShadowed", False ) + +text.insertString( cursor, " That's all for now!" , 0 ) + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/demo/swritercomp.py b/pyuno/demo/swritercomp.py new file mode 100644 index 000000000000..fd7025f0426f --- /dev/null +++ b/pyuno/demo/swritercomp.py @@ -0,0 +1,111 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +# just a simple copy of the swriter.py demo, but implemented as a component. The advantage is, +# that the component may run within the office process which may give a performance improvement. + +import unohelper +import uno + +# a UNO struct later needed to create a document +from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK +from com.sun.star.text.TextContentAnchorType import AS_CHARACTER +from com.sun.star.awt import Size + +from com.sun.star.lang import XMain + +def insertTextIntoCell( table, cellName, text, color ): + tableText = table.getCellByName( cellName ) + cursor = tableText.createTextCursor() + cursor.setPropertyValue( "CharColor", color ) + tableText.setString( text ) + +# the UNO component +# implementing the interface com.sun.star.lang.XMain +# unohelper.Base implements the XTypeProvider interface +class SWriterComp(XMain,unohelper.Base): + def __init__( self, ctx ): + self.ctx = ctx + + # implementation for XMain.run( [in] sequence< any > ) + def run( self,args ): + ctx = self.ctx + smgr = ctx.ServiceManager + desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx) + + # open a writer document + doc = desktop.loadComponentFromURL( "private:factory/swriter","_blank", 0, () ) + + text = doc.Text + cursor = text.createTextCursor() + text.insertString( cursor, "The first line in the newly created text document.\n", 0 ) + text.insertString( cursor, "Now we are in the second line\n" , 0 ) + + # create a text table + table = doc.createInstance( "com.sun.star.text.TextTable" ) + + # with 4 rows and 4 columns + table.initialize( 4,4) + + text.insertTextContent( cursor, table, 0 ) + rows = table.Rows + + table.setPropertyValue( "BackTransparent", uno.Bool(0) ) + table.setPropertyValue( "BackColor", 13421823 ) + row = rows.getByIndex(0) + row.setPropertyValue( "BackTransparent", uno.Bool(0) ) + row.setPropertyValue( "BackColor", 6710932 ) + + textColor = 16777215 + + insertTextIntoCell( table, "A1", "FirstColumn", textColor ) + insertTextIntoCell( table, "B1", "SecondColumn", textColor ) + insertTextIntoCell( table, "C1", "ThirdColumn", textColor ) + insertTextIntoCell( table, "D1", "SUM", textColor ) + + table.getCellByName("A2").setValue(22.5) + table.getCellByName("B2").setValue(5615.3) + table.getCellByName("C2").setValue(-2315.7) + table.getCellByName("D2").setFormula("sum <A2:C2>") + + table.getCellByName("A3").setValue(21.5) + table.getCellByName("B3").setValue(615.3) + table.getCellByName("C3").setValue(-315.7) + table.getCellByName("D3").setFormula("sum <A3:C3>") + + table.getCellByName("A4").setValue(121.5) + table.getCellByName("B4").setValue(-615.3) + table.getCellByName("C4").setValue(415.7) + table.getCellByName("D4").setFormula("sum <A4:C4>") + + + cursor.setPropertyValue( "CharColor", 255 ) + cursor.setPropertyValue( "CharShadowed", uno.Bool(1) ) + + text.insertControlCharacter( cursor, PARAGRAPH_BREAK, 0 ) + text.insertString( cursor, " This is a colored Text - blue with shadow\n" , 0 ) + text.insertControlCharacter( cursor, PARAGRAPH_BREAK, 0 ) + + textFrame = doc.createInstance( "com.sun.star.text.TextFrame" ) + textFrame.setSize( Size(15000,400)) + textFrame.setPropertyValue( "AnchorType" , AS_CHARACTER ) + + text.insertTextContent( cursor, textFrame, 0 ) + + textInTextFrame = textFrame.getText() + cursorInTextFrame = textInTextFrame.createTextCursor() + textInTextFrame.insertString( cursorInTextFrame, "The first line in the newly created text frame.", 0 ) + textInTextFrame.insertString( cursorInTextFrame, "\nWith this second line the height of the rame raises.",0) + text.insertControlCharacter( cursor, PARAGRAPH_BREAK, 0 ) + + cursor.setPropertyValue( "CharColor", 65536 ) + cursor.setPropertyValue( "CharShadowed", uno.Bool(0) ) + + text.insertString( cursor, " That's all for now!" , 0 ) + return 0 + +# pythonloader looks for a static g_ImplementationHelper variable +g_ImplementationHelper = unohelper.ImplementationHelper() +g_ImplementationHelper.addImplementation( \ + SWriterComp,"org.openoffice.comp.pyuno.swriter",("org.openoffice.demo.SWriter",),) + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/demo/swritercompclient.py b/pyuno/demo/swritercompclient.py new file mode 100644 index 000000000000..19ca6b5c1c46 --- /dev/null +++ b/pyuno/demo/swritercompclient.py @@ -0,0 +1,15 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +import uno + +localContext = uno.getComponentContext() +resolver = localContext.ServiceManager.createInstanceWithContext( + "com.sun.star.bridge.UnoUrlResolver", localContext ) +remoteContext = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" ) +remoteSmgr = remoteContext.ServiceManager + +pyComp = remoteSmgr.createInstanceWithContext( "org.openoffice.demo.SWriter" , remoteContext ) + +pyComp.run( (), ) + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/doc/modes.sxd b/pyuno/doc/modes.sxd Binary files differnew file mode 100644 index 000000000000..848912b923a1 --- /dev/null +++ b/pyuno/doc/modes.sxd diff --git a/pyuno/inc/pyuno/pyuno.hxx b/pyuno/inc/pyuno/pyuno.hxx new file mode 100644 index 000000000000..e1bac60d96be --- /dev/null +++ b/pyuno/inc/pyuno/pyuno.hxx @@ -0,0 +1,303 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +#ifndef _PYUNO_PYUNO_HXX_ +#define _PYUNO_PYUNO_HXX_ + +#ifndef Py_PYTHON_H +#if defined _MSC_VER +#pragma warning(push, 1) +#endif +#ifdef _DEBUG +#undef _DEBUG +#include <Python.h> +#define _DEBUG +#else +#include <Python.h> +#endif // #ifdef _DEBUG +#if defined _MSC_VER +#pragma warning(pop) +#endif +#endif // #ifdef Py_PYTHON_H +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/script/CannotConvertException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +/** + External interface of the Python UNO bridge. + + This is a C++ interface, because the core UNO components + invocation and proxyfactory are used to implement the bridge. + + This interface is somewhat private and my change in future. + + A scripting framework implementation may use this interface + to do the necessary conversions. +*/ + +#ifdef WIN32 +#define PY_DLLEXPORT __declspec(dllexport) +#else +#define PY_DLLEXPORT +#endif + +/** function called by the python runtime to initialize the + pyuno module. + + preconditions: python has been initialized before and + the global interpreter lock is held +*/ +extern "C" PY_DLLEXPORT +#if PY_MAJOR_VERSION >= 3 + PyObject* SAL_CALL PyInit_pyuno(); +#else + void SAL_CALL initpyuno(); +#endif + +namespace pyuno +{ + +/** Helper class for keeping references to python objects. + BEWARE: Look up every python function you use to check + wether you get an acquired or not acquired object pointer + (python terminus for a not acquired object pointer + is 'borrowed reference'). Use in the acquired pointer cases the + PyRef( pointer, SAL_NO_ACQUIRE) ctor. + + precondition: python has been initialized before and + the global interpreter lock is held + +*/ +class PyRef +{ + PyObject *m; +public: + PyRef () : m(0) {} + PyRef( PyObject * p ) : m( p ) { Py_XINCREF( m ); } + + PyRef( PyObject * p, __sal_NoAcquire ) : m( p ) {} + + PyRef( const PyRef &r ) : m( r.get() ) { Py_XINCREF( m ); } + + ~PyRef() { Py_XDECREF( m ); } + + PyObject *get() const { return m; } + + PyObject * getAcquired() const + { + Py_XINCREF( const_cast< PyObject*> (m) ); + return m; + } + + PyRef & operator = ( const PyRef & r ) + { + PyObject *tmp = m; + m = r.getAcquired(); + Py_XDECREF( tmp ); + return *this; + } + + bool operator == ( const PyRef & r ) const + { + return r.get() == m; + } + + /** clears the reference without decreasing the reference count + only seldomly needed ! */ + void scratch() + { + m = 0; + } + + /** clears the reference decreasing the refcount of the holded object. + */ + void clear() + { + Py_XDECREF( m ); + m = 0; + } + + /** returns 1 when the reference points to a python object python object, + otherwise 0. + */ + sal_Bool is() const + { + return m != 0; + } + + struct Hash + { + sal_IntPtr operator () ( const PyRef &r) const { return sal_IntPtr( r.get() ); } + }; +}; + +struct stRuntimeImpl; +typedef struct stRuntimeImpl RuntimeImpl; + +enum ConversionMode { ACCEPT_UNO_ANY, REJECT_UNO_ANY }; + + +/** The pyuno::Runtime class keeps the internal state of the python UNO bridge + for the currently in use python interpreter. + + You may keep a Runtime instance, use it from a different thread, etc. But you must + make sure to fulfill all preconditions mentioned for the specific methods. +*/ + +class PY_DLLEXPORT Runtime +{ + RuntimeImpl *impl; +public: + ~Runtime( ); + + /** + preconditions: python has been initialized before, + the global interpreter lock is held and pyuno + has been initialized for the currently used interpreter. + + Note: This method exists for efficiency reasons to save + lookup costs for any2PyObject and pyObject2Any + + @throw RuntimeException in case the runtime has not been + initialized before + */ + Runtime() throw( com::sun::star::uno::RuntimeException ); + + Runtime( const Runtime & ); + Runtime & operator = ( const Runtime & ); + + /** Initializes the python-UNO bridge. May be called only once per python interpreter. + + @param ctx the component context is used to instantiate bridge services needed + for bridging such as invocation, typeconverter, invocationadapterfactory, etc. + + preconditions: python has been initialized before and + the global interpreter lock is held and pyuno is not + initialized (see isInitialized() ). + + @throw RuntimeException in case the thread is not attached or the runtime + has not been initialized. + */ + static void SAL_CALL initialize( + const com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > & ctx ) + throw ( com::sun::star::uno::RuntimeException ); + + + /** Checks, whether the uno runtime is already initialized in the current python interpreter. + */ + static bool SAL_CALL isInitialized() throw (com::sun::star::uno::RuntimeException); + + + /** disposes the UNO bridge in this interpreter. All existing stubs/proxies + become non-functional, using these proxies/stubs leads to runtime errors. + + preconditions: python has been initialized before and + the global interpreter lock is held and pyuno was + initialized before for the currently in use interpreter. + */ + static void SAL_CALL finalize() throw(com::sun::star::uno::RuntimeException ); + + /** converts something contained in an UNO Any to a Python object + + preconditions: python has been initialized before, + the global interpreter lock is held and pyuno::Runtime + has been initialized. + */ + PyRef any2PyObject (const com::sun::star::uno::Any &source ) const + throw ( com::sun::star::script::CannotConvertException, + com::sun::star::lang::IllegalArgumentException, + com::sun::star::uno::RuntimeException ); + + /** converts a Python object to a UNO any + + preconditions: python has been initialized before, + the global interpreter lock is held and pyuno + has been initialized + */ + com::sun::star::uno::Any pyObject2Any ( + const PyRef & source , enum ConversionMode mode = REJECT_UNO_ANY ) const + throw ( com::sun::star::uno::RuntimeException); + + /** extracts a proper uno exception from a given python exception + */ + com::sun::star::uno::Any extractUnoException( + const PyRef & excType, const PyRef & excValue, const PyRef & excTraceback) const; + + /** Returns the internal handle. Should only be used by the module implementation + */ + RuntimeImpl *getImpl() const { return impl; } +}; + + +/** helper class for attaching the current thread to the python runtime. + + Attaching is done creating a new threadstate for the given interpreter + and acquiring the global interpreter lock. + + Usage: + + ... don't use python here + { + PyThreadAttach guard( PyInterpreterState_Head() ); + { + ... do whatever python code you want + { + PyThreadDetach antiguard; + ... don't use python here + } + ... do whatever python code you want + } + } + ... don't use python here + + Note: The additional scope brackets after the PyThreadAttach are needed, + e.g. when you would leave them away, dtors of potential pyrefs + may be called after the thread has detached again. + */ +class PY_DLLEXPORT PyThreadAttach +{ + PyThreadState *tstate; + PyThreadAttach ( const PyThreadAttach & ); // not implemented + PyThreadAttach & operator = ( const PyThreadAttach & ); +public: + + /** Creates a new python threadstate and acquires the global interpreter lock. + precondition: The current thread MUST NOT hold the global interpreter lock. + postcondition: The global interpreter lock is acquired + + @raises com::sun::star::uno::RuntimeException + in case no pythread state could be created + */ + PyThreadAttach( PyInterpreterState *interp) throw ( com::sun::star::uno::RuntimeException ); + + + /** Releases the global interpreter lock and destroys the thread state. + */ + ~PyThreadAttach(); +}; + +/** helper class for detaching the current thread from the python runtime + to do some blocking, non-python related operation. + + @see PyThreadAttach +*/ +class PY_DLLEXPORT PyThreadDetach +{ + PyThreadState *tstate; + PyThreadDetach ( const PyThreadDetach & ); // not implemented + PyThreadDetach & operator = ( const PyThreadDetach & ); // not implemented + +public: + /** Releases the global interpreter lock. + + precondition: The current thread MUST hold the global interpreter lock. + postcondition: The current thread does not hold the global interpreter lock anymore. + */ + PyThreadDetach() throw ( com::sun::star::uno::RuntimeException ); + /** Acquires the global interpreter lock again + */ + ~PyThreadDetach(); +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/prj/build.lst b/pyuno/prj/build.lst new file mode 100644 index 000000000000..e6e0914eb6e3 --- /dev/null +++ b/pyuno/prj/build.lst @@ -0,0 +1,5 @@ +bgpu pyuno : stoc DESKTOP:cpputools cppuhelper bridges tools PYTHON:python LIBXSLT:libxslt NULL +pu pyuno usr1 - all br_mkout NULL +pu pyuno\zipcore nmake - all pu_zipcore NULL +pu pyuno\source\module nmake - all pu_module NULL +pu pyuno\source\loader nmake - all pu_loader pu_module NULL diff --git a/pyuno/prj/d.lst b/pyuno/prj/d.lst new file mode 100644 index 000000000000..38ae95de2b23 --- /dev/null +++ b/pyuno/prj/d.lst @@ -0,0 +1,27 @@ +mkdir: %_DEST%\bin\pyuno +mkdir: %_DEST%\lib\pyuno + +..\%__SRC%\lib\libpyuno.so %_DEST%\lib\libpyuno.so +..\%__SRC%\lib\libpyuno.dylib %_DEST%\lib\libpyuno.dylib +..\%__SRC%\lib\pyuno.so %_DEST%\lib\pyuno.so +..\%__SRC%\lib\pyuno.dylib %_DEST%\lib\pyuno.dylib +..\%__SRC%\lib\pythonloader.uno.so %_DEST%\lib\pythonloader.uno.so +..\%__SRC%\lib\pythonloader.uno.dylib %_DEST%\lib\pythonloader.uno.dylib +..\%__SRC%\lib\unohelper.py %_DEST%\lib\pyuno\unohelper.py +..\%__SRC%\lib\pythonloader.py %_DEST%\lib\pyuno\pythonloader.py +..\%__SRC%\lib\uno.py %_DEST%\lib\pyuno\uno.py +..\%__SRC%\misc\pythonloader.component %_DEST%\xml\pythonloader.component + +..\%__SRC%\bin\unohelper.py %_DEST%\bin\pyuno\unohelper.py +..\%__SRC%\bin\pythonloader.py %_DEST%\bin\pyuno\pythonloader.py +..\%__SRC%\bin\uno.py %_DEST%\bin\pyuno\uno.py +..\%__SRC%\bin\pyuno.pyd %_DEST%\bin\pyuno.pyd +..\%__SRC%\bin\pyuno.dll %_DEST%\bin\pyuno.dll +..\%__SRC%\bin\pythonl*.dll %_DEST%\bin\pythonl*.dll + +..\%__SRC%\misc\pyunorc %_DEST%\lib\pyunorc +..\%__SRC%\misc\pyuno.ini %_DEST%\bin\pyuno.ini +..\%__SRC%\bin\python-core-*.zip %_DEST%\bin\python-core-*.zip +..\%__SRC%\bin\python.bin %_DEST%\bin\python.bin +..\%__SRC%\bin\python.sh %_DEST%\bin\pyuno\python +..\%__SRC%\bin\python.exe %_DEST%\bin\pyuno\python.exe diff --git a/pyuno/source/loader/makefile.mk b/pyuno/source/loader/makefile.mk new file mode 100644 index 000000000000..3f7a33ced13d --- /dev/null +++ b/pyuno/source/loader/makefile.mk @@ -0,0 +1,94 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=../.. + +PRJNAME=pyuno +TARGET=pythonloader.uno +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.IF "$(L10N_framework)"=="" +DLLPRE = + +#------------------------------------------------------------------- + +.IF "$(OS)$(COMEX)" == "SOLARIS4" +# no -Bdirect for SunWS CC +DIRECT= $(LINKFLAGSDEFS) +.ENDIF + +.IF "$(SYSTEM_PYTHON)" == "YES" +PYTHONLIB=$(PYTHON_LIBS) +CFLAGS+=$(PYTHON_CFLAGS) +.IF "$(EXTRA_CFLAGS)"!="" +PYTHONLIB+=-framework Python +.ENDIF # "$(EXTRA_CFLAGS)"!="" +.ELSE +.INCLUDE : pyversion.mk + +CFLAGS+=-I$(SOLARINCDIR)/python +.ENDIF + +SHL1TARGET=$(TARGET) + +SHL1STDLIBS= \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(SALLIB) \ + $(PYUNOLIB) \ + $(PYTHONLIB) + +SHL1VERSIONMAP=$(SOLARENV)/src/component.map +SHL1DEPN= +SHL1IMPLIB=i$(TARGET) +SHL1LIBS=$(SLB)/$(TARGET).lib +SHL1DEF=$(MISC)/$(SHL1TARGET).def + +DEF1NAME=$(SHL1TARGET) +SLOFILES=$(SLO)/pyuno_loader.obj + +# --- Targets ------------------------------------------------------ + +ALL : ALLTAR \ + $(DLLDEST)/pythonloader.py +.ENDIF # L10N_framework + +.INCLUDE : target.mk +.IF "$(L10N_framework)"=="" +$(DLLDEST)/%.py: %.py + cp $? $@ +.ENDIF # L10N_framework + +ALLTAR : $(MISC)/pythonloader.component + +$(MISC)/pythonloader.component .ERRREMOVE : \ + $(SOLARENV)/bin/createcomponent.xslt pythonloader.component + $(XSLTPROC) --nonet --stringparam uri \ + 'vnd.sun.star.expand:$$OOO_BASE_DIR/program/$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt pythonloader.component diff --git a/pyuno/source/loader/pythonloader.component b/pyuno/source/loader/pythonloader.component new file mode 100644 index 000000000000..583b6ed38771 --- /dev/null +++ b/pyuno/source/loader/pythonloader.component @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--********************************************************************** +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2010 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +**********************************************************************--> + +<component loader="com.sun.star.loader.SharedLibrary" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.pyuno.Loader"> + <service name="com.sun.star.loader.Python"/> + </implementation> +</component> diff --git a/pyuno/source/loader/pythonloader.py b/pyuno/source/loader/pythonloader.py new file mode 100644 index 000000000000..ad72cca86266 --- /dev/null +++ b/pyuno/source/loader/pythonloader.py @@ -0,0 +1,152 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +import uno +import unohelper +import sys +import imp +import os +from com.sun.star.uno import Exception,RuntimeException +from com.sun.star.loader import XImplementationLoader +from com.sun.star.lang import XServiceInfo + +MODULE_PROTOCOL = "vnd.openoffice.pymodule:" +DEBUG = 0 + +g_supportedServices = "com.sun.star.loader.Python", # referenced by the native C++ loader ! +g_implementationName = "org.openoffice.comp.pyuno.Loader" # referenced by the native C++ loader ! + +def splitUrl( url ): + nColon = url.find( ":" ) + if -1 == nColon: + raise RuntimeException( "PythonLoader: No protocol in url " + url, None ) + return url[0:nColon], url[nColon+1:len(url)] + +g_loadedComponents = {} +def checkForPythonPathBesideComponent( url ): + path = unohelper.fileUrlToSystemPath( url+"/pythonpath.zip" ); + if DEBUG == 1: + print("checking for existence of " + encfile( path )) + if 1 == os.access( encfile( path ), os.F_OK) and not path in sys.path: + if DEBUG == 1: + print("adding " + encfile( path ) + " to sys.path") + sys.path.append( path ) + + path = unohelper.fileUrlToSystemPath( url+"/pythonpath" ); + if 1 == os.access( encfile( path ), os.F_OK) and not path in sys.path: + if DEBUG == 1: + print("adding " + encfile( path ) + " to sys.path") + sys.path.append( path ) + +def encfile(uni): + return uni.encode( sys.getfilesystemencoding()) + +class Loader( XImplementationLoader, XServiceInfo, unohelper.Base ): + def __init__(self, ctx ): + if DEBUG: + print("pythonloader.Loader ctor") + self.ctx = ctx + + def getModuleFromUrl( self, url ): + if DEBUG: + print("pythonloader: interpreting url " + url) + protocol, dependent = splitUrl( url ) + if "vnd.sun.star.expand" == protocol: + exp = self.ctx.getValueByName( "/singletons/com.sun.star.util.theMacroExpander" ) + url = exp.expandMacros(dependent) + protocol,dependent = splitUrl( url ) + + if DEBUG: + print("pythonloader: after expansion " + protocol + ":" + dependent) + + try: + if "file" == protocol: + # remove \..\ sequence, which may be useful e.g. in the build env + url = unohelper.absolutize( url, url ) + + # did we load the module already ? + mod = g_loadedComponents.get( url ) + if not mod: + mod = imp.new_module("uno_component") + + # check for pythonpath.zip beside .py files + checkForPythonPathBesideComponent( url[0:url.rfind('/')] ) + + # read the file + filename = unohelper.fileUrlToSystemPath( url ) + fileHandle = file( filename ) + src = fileHandle.read().replace("\r","") + if not src.endswith( "\n" ): + src = src + "\n" + + # compile and execute the module + codeobject = compile( src, encfile(filename), "exec" ) + exec(codeobject, mod.__dict__) + mod.__file__ = encfile(filename) + g_loadedComponents[url] = mod + return mod + elif "vnd.openoffice.pymodule" == protocol: + return __import__( dependent ) + else: + raise RuntimeException( "PythonLoader: Unknown protocol " + + protocol + " in url " +url, self ) + except ImportError as e: + raise RuntimeException( "Couldn't load " + url + " for reason " + str(e), None ) + return None + + def activate( self, implementationName, dummy, locationUrl, regKey ): + if DEBUG: + print("pythonloader.Loader.activate") + + mod = self.getModuleFromUrl( locationUrl ) + implHelper = mod.__dict__.get( "g_ImplementationHelper" , None ) + if implHelper == None: + return mod.getComponentFactory( implementationName, self.ctx.ServiceManager, regKey ) + else: + return implHelper.getComponentFactory( implementationName,regKey,self.ctx.ServiceManager) + + def writeRegistryInfo( self, regKey, dummy, locationUrl ): + if DEBUG: + print( "pythonloader.Loader.writeRegistryInfo" ) + + mod = self.getModuleFromUrl( locationUrl ) + implHelper = mod.__dict__.get( "g_ImplementationHelper" , None ) + if implHelper == None: + return mod.writeRegistryInfo( self.ctx.ServiceManager, regKey ) + else: + return implHelper.writeRegistryInfo( regKey, self.ctx.ServiceManager ) + + def getImplementationName( self ): + return g_implementationName + + def supportsService( self, ServiceName ): + return ServiceName in self.serviceNames + + def getSupportedServiceNames( self ): + return g_supportedServices + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/source/loader/pyuno_loader.cxx b/pyuno/source/loader/pyuno_loader.cxx new file mode 100644 index 000000000000..f7a909fbd0fc --- /dev/null +++ b/pyuno/source/loader/pyuno_loader.cxx @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <pyuno/pyuno.hxx> + +#include <osl/process.h> +#include <osl/file.hxx> +#include <osl/thread.h> + +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/bootstrap.hxx> + +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/factory.hxx> + +using rtl::OUString; +using rtl::OUStringBuffer; +using rtl::OString; + +using pyuno::PyRef; +using pyuno::Runtime; +using pyuno::PyThreadAttach; + +using com::sun::star::registry::XRegistryKey; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::RuntimeException; + +namespace pyuno_loader +{ + +static void raiseRuntimeExceptionWhenNeeded() throw ( RuntimeException ) +{ + if( PyErr_Occurred() ) + { + PyRef excType, excValue, excTraceback; + PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback); + Runtime runtime; + com::sun::star::uno::Any a = runtime.extractUnoException( excType, excValue, excTraceback ); + OUStringBuffer buf; + buf.appendAscii( "python-loader:" ); + if( a.hasValue() ) + buf.append( ((com::sun::star::uno::Exception *)a.getValue())->Message ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () ); + } +} + +static PyRef getLoaderModule() throw( RuntimeException ) +{ + PyRef module( + PyImport_ImportModule( "pythonloader" ), + SAL_NO_ACQUIRE ); + raiseRuntimeExceptionWhenNeeded(); + if( !module.is() ) + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pythonloader: Couldn't load pythonloader module" ) ), + Reference< XInterface > () ); + } + return PyRef( PyModule_GetDict( module.get() )); +} + +static PyRef getObjectFromLoaderModule( const char * func ) + throw ( RuntimeException ) +{ + PyRef object( PyDict_GetItemString(getLoaderModule().get(), (char*)func ) ); + if( !object.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "pythonloader: couldn't find core element pythonloader." ); + buf.appendAscii( func ); + throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >()); + } + return object; +} + +OUString getImplementationName() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.pyuno.Loader" ) ); +} + +Sequence< OUString > getSupportedServiceNames() +{ + OUString serviceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.loader.Python" ) ); + return Sequence< OUString > ( &serviceName, 1 ); +} + +static void setPythonHome ( const OUString & pythonHome ) +{ + OUString systemPythonHome; + osl_getSystemPathFromFileURL( pythonHome.pData, &(systemPythonHome.pData) ); + OString o = rtl::OUStringToOString( systemPythonHome, osl_getThreadTextEncoding() ); +#if PY_MAJOR_VERSION >= 3 + // static because Py_SetPythonHome just copies the "wide" pointer + // PATH_MAX is defined in Python.h + static wchar_t wide[PATH_MAX + 1]; + size_t len = mbstowcs(wide, o.pData->buffer, PATH_MAX + 1); + if(len == (size_t)-1) + { + PyErr_SetString(PyExc_SystemError, "invalid multibyte sequence in python home path"); + return; + } + if(len == PATH_MAX + 1) + { + PyErr_SetString(PyExc_SystemError, "python home path is too long"); + return; + } + Py_SetPythonHome(wide); +#else + rtl_string_acquire(o.pData); // increase reference count + Py_SetPythonHome(o.pData->buffer); +#endif +} + +static void prependPythonPath( const OUString & pythonPathBootstrap ) +{ + rtl::OUStringBuffer bufPYTHONPATH( 256 ); + sal_Int32 nIndex = 0; + while( 1 ) + { + sal_Int32 nNew = pythonPathBootstrap.indexOf( ' ', nIndex ); + OUString fileUrl; + if( nNew == -1 ) + { + fileUrl = OUString( &( pythonPathBootstrap[nIndex] ) ); + } + else + { + fileUrl = OUString( &(pythonPathBootstrap[nIndex]) , nNew - nIndex ); + } + OUString systemPath; + osl_getSystemPathFromFileURL( fileUrl.pData, &(systemPath.pData) ); + bufPYTHONPATH.append( systemPath ); + bufPYTHONPATH.append( static_cast<sal_Unicode>(SAL_PATHSEPARATOR) ); + if( nNew == -1 ) + break; + nIndex = nNew + 1; + } + const char * oldEnv = getenv( "PYTHONPATH"); + if( oldEnv ) + bufPYTHONPATH.append( rtl::OUString(oldEnv, strlen(oldEnv), osl_getThreadTextEncoding()) ); + + rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("PYTHONPATH")); + rtl::OUString envValue(bufPYTHONPATH.makeStringAndClear()); + osl_setEnvironment(envVar.pData, envValue.pData); +} + +Reference< XInterface > CreateInstance( const Reference< XComponentContext > & ctx ) +{ + Reference< XInterface > ret; + + if( ! Py_IsInitialized() ) + { + OUString pythonPath; + OUString pythonHome; + OUString path( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR/program/" SAL_CONFIGFILE("pythonloader.uno" ))); + rtl::Bootstrap::expandMacros(path); //TODO: detect failure + rtl::Bootstrap bootstrap(path); + + // look for pythonhome + bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONHOME") ), pythonHome ); + bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONPATH" ) ) , pythonPath ); + + // pythonhome+pythonpath must be set before Py_Initialize(), otherwise there appear warning on the console + // sadly, there is no api for setting the pythonpath, we have to use the environment variable + if( pythonHome.getLength() ) + setPythonHome( pythonHome ); + + if( pythonPath.getLength() ) + prependPythonPath( pythonPath ); + +#if WNT + //extend PATH under windows to include the branddir/program so ssl libs will be found + //for use by terminal mailmerge dependency _ssl.pyd + rtl::OUString sEnvName(RTL_CONSTASCII_USTRINGPARAM("PATH")); + rtl::OUString sPath; + osl_getEnvironment(sEnvName.pData, &sPath.pData); + rtl::OUString sBrandLocation(RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program")); + rtl::Bootstrap::expandMacros(sBrandLocation); + osl::FileBase::getSystemPathFromFileURL(sBrandLocation, sBrandLocation); + sPath = rtl::OUStringBuffer(sPath). + append(static_cast<sal_Unicode>(SAL_PATHSEPARATOR)). + append(sBrandLocation).makeStringAndClear(); + osl_setEnvironment(sEnvName.pData, sPath.pData); +#endif + +#if PY_MAJOR_VERSION >= 3 + PyImport_AppendInittab( (char*)"pyuno", PyInit_pyuno ); +#else + PyImport_AppendInittab( (char*)"pyuno", initpyuno ); +#endif + // initialize python + Py_Initialize(); + PyEval_InitThreads(); + + PyThreadState *tstate = PyThreadState_Get(); + PyEval_ReleaseThread( tstate ); + } + + PyThreadAttach attach( PyInterpreterState_Head() ); + { + if( ! Runtime::isInitialized() ) + { + Runtime::initialize( ctx ); + } + Runtime runtime; + + PyRef pyCtx = runtime.any2PyObject( + com::sun::star::uno::makeAny( ctx ) ); + + PyRef clazz = getObjectFromLoaderModule( "Loader" ); + PyRef args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE ); + PyTuple_SetItem( args.get(), 0 , pyCtx.getAcquired() ); + PyRef pyInstance( PyObject_CallObject( clazz.get() , args.get() ), SAL_NO_ACQUIRE ); + runtime.pyObject2Any( pyInstance ) >>= ret; + } + return ret; +} + +} + + +static struct cppu::ImplementationEntry g_entries[] = +{ + { + pyuno_loader::CreateInstance, pyuno_loader::getImplementationName, + pyuno_loader::getSupportedServiceNames, cppu::createSingleComponentFactory, + 0 , 0 + }, + { 0, 0, 0, 0, 0, 0 } +}; + +extern "C" +{ + +SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/makefile.mk b/pyuno/source/module/makefile.mk new file mode 100644 index 000000000000..f72e1c3031fe --- /dev/null +++ b/pyuno/source/module/makefile.mk @@ -0,0 +1,159 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=../.. + +PRJNAME=pyuno +TARGET=pyuno +ENABLE_EXCEPTIONS=TRUE + +LINKFLAGSDEFS = # do not fail with missing symbols + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.IF "$(L10N_framework)"=="" + +#------------------------------------------------------------------- + +.IF "$(OS)$(COMEX)" == "SOLARIS4" +# no -Bdirect for SunWS CC +DIRECT = $(LINKFLAGSDEFS) +.ENDIF + +# special setting from environment +.IF "$(EXTRA_CFLAGS)"!="" +EXTRA_FRAMEWORK_FLAG=-framework Python +.ENDIF # .IF "$(EXTRA_CFLAGS)"!="" + +.IF "$(GUI)" == "UNX" +PYUNORC=pyunorc +.ELSE +.IF "$(CROSS_COMPILING)" != "YES" +.INCLUDE : pyversion.mk +.ENDIF +PYUNORC=pyuno.ini +DLLPOST=.pyd +.ENDIF + +.IF "$(SYSTEM_PYTHON)" == "YES" +PYTHONLIB=$(PYTHON_LIBS) +CFLAGS+=$(PYTHON_CFLAGS) +.ELSE # "$(SYSTEM_PYTHON)" == "YES" +.INCLUDE : pyversion.mk +CFLAGS+=-I$(SOLARINCDIR)/python +.ENDIF # "$(SYSTEM_PYTHON)" == "YES" + +SHL1TARGET=$(TARGET) +SLOFILES= \ + $(SLO)/pyuno_runtime.obj \ + $(SLO)/pyuno.obj \ + $(SLO)/pyuno_callable.obj \ + $(SLO)/pyuno_module.obj \ + $(SLO)/pyuno_type.obj \ + $(SLO)/pyuno_util.obj \ + $(SLO)/pyuno_except.obj \ + $(SLO)/pyuno_adapter.obj \ + $(SLO)/pyuno_gc.obj + +# remove this, when issue i35064 is integrated +.IF "$(COM)"=="GCC" +NOOPTFILES= \ + $(SLO)/pyuno_module.obj +.ENDIF # "$(COM)"=="GCC" + +SHL1STDLIBS= \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(SALLIB) \ + $(PYTHONLIB) \ + $(EXTRA_FRAMEWORK_FLAG) + +SHL1DEPN=$(eq,$(OS),MACOSX $(MISC)/framework_link $(NULL)) +SHL1LIBS=$(SLB)/$(TARGET).lib +SHL1IMPLIB=i$(TARGET) + +SHL1DEF=$(MISC)/$(SHL1TARGET).def + +DEF1NAME=$(SHL1TARGET) +DEF1DEPN=$(MISC)/pyuno.flt + +DEFLIB1NAME=$(TARGET) + +# --- Targets ------------------------------------------------------ + +.IF "$(GUI)$(COM)"=="WNTGCC" +ALLTAR : \ + $(DLLDEST)/uno.py \ + $(DLLDEST)/unohelper.py \ + $(MISC)/$(PYUNORC) \ + $(LB)/lib$(TARGET).a + +$(LB)/lib$(TARGET).a: $(MISC)/$(TARGET).def + $(DLLTOOL) --dllname $(TARGET)$(DLLPOST) --input-def=$(MISC)/$(TARGET).def --kill-at --output-lib=$(LB)/lib$(TARGET).a +.ELSE + +.IF "$(GUI)"!="WNT" +# For some reason the build breaks on Windows if this is listed in the +# prerequisite list of ALLTAR, but pyuno.pyd still gets produced. Go +# figure. But we need it on non-Windows. +targetdll=$(LB)/$(TARGET)$(DLLPOST) +.ENDIF + +ALLTAR : \ + $(DLLDEST)/uno.py \ + $(DLLDEST)/unohelper.py \ + $(targetdll) \ + $(MISC)/$(PYUNORC) +.ENDIF +.ENDIF + +.INCLUDE : target.mk +.IF "$(L10N_framework)"=="" +$(DLLDEST)/%.py: %.py + cp $? $@ + +# make checkdll happy +$(MISC)/framework_link : + $(COMMAND_ECHO)ln -sf $(SOLARLIBDIR)/OOoPython.framework $(LB)/OOoPython.framework + @touch $@ + +$(MISC)/$(PYUNORC) : pyuno + -rm -f $@ + cat pyuno > $@ + +$(MISC)/pyuno.flt : pyuno.flt + -rm -f $@ + cat $? > $@ + +.IF "$(DLLPRE)"!="" +# python does not accept the "lib" prefix in the module library +$(LB)/$(TARGET)$(DLLPOST) : $(LB)/$(DLLPRE)$(TARGET)$(DLLPOST) + -rm -f $@ + ln -s $? $@ +.ENDIF + +.ENDIF # L10N_framework diff --git a/pyuno/source/module/pyuno b/pyuno/source/module/pyuno new file mode 100644 index 000000000000..5d13997bfde6 --- /dev/null +++ b/pyuno/source/module/pyuno @@ -0,0 +1,4 @@ +# The bootstrap variable PYUNOLIBDIR will be set by the pyuno runtime library +PYUNO_BINPATH=$PYUNOLIBDIR/../bin$UPDMINOREXT +UNO_TYPES=$PYUNO_BINPATH/types.rdb +UNO_SERVICES=$PYUNO_BINPATH/pyuno_services.rdb diff --git a/pyuno/source/module/pyuno.cxx b/pyuno/source/module/pyuno.cxx new file mode 100644 index 000000000000..2bfbe7b64002 --- /dev/null +++ b/pyuno/source/module/pyuno.cxx @@ -0,0 +1,761 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "pyuno_impl.hxx" + +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> + +#include <osl/thread.h> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMaterialHolder.hpp> + +#define TO_ASCII(x) OUStringToOString( x , RTL_TEXTENCODING_ASCII_US).getStr() + +using rtl::OStringBuffer; +using rtl::OUStringBuffer; +using rtl::OUStringToOString; +using rtl::OUString; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Type; +using com::sun::star::uno::TypeClass; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::Exception; +using com::sun::star::uno::XComponentContext; +using com::sun::star::lang::XSingleServiceFactory; +using com::sun::star::lang::XServiceInfo; +using com::sun::star::lang::XTypeProvider; +using com::sun::star::script::XTypeConverter; +using com::sun::star::script::XInvocation2; +using com::sun::star::beans::XMaterialHolder; + +namespace pyuno +{ + +PyObject *PyUNO_str( PyObject * self ); + +void PyUNO_del (PyObject* self) +{ + PyUNO* me = reinterpret_cast< PyUNO* > (self); + { + PyThreadDetach antiguard; + delete me->members; + } + PyObject_Del (self); +} + + + +OUString val2str( const void * pVal, typelib_TypeDescriptionReference * pTypeRef , sal_Int32 mode ) SAL_THROW( () ) +{ + OSL_ASSERT( pVal ); + if (pTypeRef->eTypeClass == typelib_TypeClass_VOID) + return OUString( RTL_CONSTASCII_USTRINGPARAM("void") ); + + OUStringBuffer buf( 64 ); + buf.append( (sal_Unicode)'(' ); + buf.append( pTypeRef->pTypeName ); + buf.append( (sal_Unicode)')' ); + + switch (pTypeRef->eTypeClass) + { + case typelib_TypeClass_INTERFACE: + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( reinterpret_cast< sal_IntPtr >(*(void **)pVal), 16 ); + if( VAL2STR_MODE_DEEP == mode ) + { + buf.appendAscii( "{" ); Reference< XInterface > r = *( Reference< XInterface > * ) pVal; + Reference< XServiceInfo > serviceInfo( r, UNO_QUERY); + Reference< XTypeProvider > typeProvider(r,UNO_QUERY); + if( serviceInfo.is() ) + { + buf.appendAscii("implementationName=" ); + buf.append(serviceInfo->getImplementationName() ); + buf.appendAscii(", supportedServices={" ); + Sequence< OUString > seq = serviceInfo->getSupportedServiceNames(); + for( int i = 0 ; i < seq.getLength() ; i ++ ) + { + buf.append( seq[i] ); + if( i +1 != seq.getLength() ) + buf.appendAscii( "," ); + } + buf.appendAscii("}"); + } + + if( typeProvider.is() ) + { + buf.appendAscii(", supportedInterfaces={" ); + Sequence< Type > seq (typeProvider->getTypes()); + for( int i = 0 ; i < seq.getLength() ; i ++ ) + { + buf.append(seq[i].getTypeName()); + if( i +1 != seq.getLength() ) + buf.appendAscii( "," ); + } + buf.appendAscii("}"); + } + buf.appendAscii( "}" ); + } + + break; + } + case typelib_TypeClass_UNION: + { + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); + OSL_ASSERT( pTypeDescr ); + + typelib_CompoundTypeDescription * pCompType = (typelib_CompoundTypeDescription *)pTypeDescr; + sal_Int32 nDescr = pCompType->nMembers; + + if (pCompType->pBaseTypeDescription) + { + buf.append( val2str( pVal, ((typelib_TypeDescription *)pCompType->pBaseTypeDescription)->pWeakRef,mode ) ); + if (nDescr) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + + typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs; + sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets; + rtl_uString ** ppMemberNames = pCompType->ppMemberNames; + + for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos ) + { + buf.append( ppMemberNames[nPos] ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" = ") ); + typelib_TypeDescription * pMemberType = 0; + TYPELIB_DANGER_GET( &pMemberType, ppTypeRefs[nPos] ); + buf.append( val2str( (char *)pVal + pMemberOffsets[nPos], pMemberType->pWeakRef, mode ) ); + TYPELIB_DANGER_RELEASE( pMemberType ); + if (nPos < (nDescr -1)) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + + TYPELIB_DANGER_RELEASE( pTypeDescr ); + + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + break; + } + case typelib_TypeClass_SEQUENCE: + { + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); + + uno_Sequence * pSequence = *(uno_Sequence **)pVal; + typelib_TypeDescription * pElementTypeDescr = 0; + TYPELIB_DANGER_GET( &pElementTypeDescr, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType ); + + sal_Int32 nElementSize = pElementTypeDescr->nSize; + sal_Int32 nElements = pSequence->nElements; + + if (nElements) + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + char * pElements = pSequence->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + buf.append( val2str( pElements + (nElementSize * nPos), pElementTypeDescr->pWeakRef, mode ) ); + if (nPos < (nElements -1)) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + } + else + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{}") ); + } + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + break; + } + case typelib_TypeClass_ANY: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + buf.append( val2str( ((uno_Any *)pVal)->pData, + ((uno_Any *)pVal)->pType , + mode) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + break; + case typelib_TypeClass_TYPE: + buf.append( (*(typelib_TypeDescriptionReference **)pVal)->pTypeName ); + break; + case typelib_TypeClass_STRING: + buf.append( (sal_Unicode)'\"' ); + buf.append( *(rtl_uString **)pVal ); + buf.append( (sal_Unicode)'\"' ); + break; + case typelib_TypeClass_ENUM: + { + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); + + sal_Int32 * pValues = ((typelib_EnumTypeDescription *)pTypeDescr)->pEnumValues; + sal_Int32 nPos = ((typelib_EnumTypeDescription *)pTypeDescr)->nEnumValues; + while (nPos--) + { + if (pValues[nPos] == *(int *)pVal) + break; + } + if (nPos >= 0) + buf.append( ((typelib_EnumTypeDescription *)pTypeDescr)->ppEnumNames[nPos] ); + else + buf.append( (sal_Unicode)'?' ); + + TYPELIB_DANGER_RELEASE( pTypeDescr ); + break; + } + case typelib_TypeClass_BOOLEAN: + if (*(sal_Bool *)pVal) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("true") ); + else + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("false") ); + break; + case typelib_TypeClass_CHAR: + buf.append( (sal_Unicode)'\'' ); + buf.append( *(sal_Unicode *)pVal ); + buf.append( (sal_Unicode)'\'' ); + break; + case typelib_TypeClass_FLOAT: + buf.append( *(float *)pVal ); + break; + case typelib_TypeClass_DOUBLE: + buf.append( *(double *)pVal ); + break; + case typelib_TypeClass_BYTE: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int32)*(sal_Int8 *)pVal, 16 ); + break; + case typelib_TypeClass_SHORT: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int32)*(sal_Int16 *)pVal, 16 ); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int32)*(sal_uInt16 *)pVal, 16 ); + break; + case typelib_TypeClass_LONG: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( *(sal_Int32 *)pVal, 16 ); + break; + case typelib_TypeClass_UNSIGNED_LONG: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int64)*(sal_uInt32 *)pVal, 16 ); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); +#if defined(GCC) && defined(SPARC) + { + sal_Int64 aVal; + *(sal_Int32 *)&aVal = *(sal_Int32 *)pVal; + *((sal_Int32 *)&aVal +1)= *((sal_Int32 *)pVal +1); + buf.append( aVal, 16 ); + } +#else + buf.append( *(sal_Int64 *)pVal, 16 ); +#endif + break; + + case typelib_TypeClass_VOID: + case typelib_TypeClass_ARRAY: + case typelib_TypeClass_UNKNOWN: + case typelib_TypeClass_SERVICE: + case typelib_TypeClass_MODULE: + default: + buf.append( (sal_Unicode)'?' ); + } + + return buf.makeStringAndClear(); +} + + +PyObject *PyUNO_repr( PyObject * self ) +{ + PyUNO *me = (PyUNO * ) self; + PyObject * ret = 0; + + if( me->members->wrappedObject.getValueType().getTypeClass() + == com::sun::star::uno::TypeClass_EXCEPTION ) + { + Reference< XMaterialHolder > rHolder(me->members->xInvocation,UNO_QUERY); + if( rHolder.is() ) + { + Any a = rHolder->getMaterial(); + Exception e; + a >>= e; + ret = ustring2PyUnicode(e.Message ).getAcquired(); + } + } + else + { + ret = PyUNO_str( self ); + } + return ret; +} + +PyObject *PyUNO_invoke( PyObject *object, const char *name , PyObject *args ) +{ + PyRef ret; + try + { + Runtime runtime; + + PyRef paras,callable; + if( PyObject_IsInstance( object, getPyUnoClass( runtime ).get() ) ) + { + PyUNO* me = (PyUNO*) object; + OUString attrName = OUString::createFromAscii(name); + if (! me->members->xInvocation->hasMethod (attrName)) + { + OUStringBuffer buf; + buf.appendAscii( "Attribute " ); + buf.append( attrName ); + buf.appendAscii( " unknown" ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + callable = PyUNO_callable_new ( + me->members->xInvocation, + attrName, + runtime.getImpl()->cargo->xInvocation, + runtime.getImpl()->cargo->xTypeConverter, + ACCEPT_UNO_ANY); + paras = args; + } + else + { + // clean the tuple from uno.Any ! + int size = PyTuple_Size( args ); + { // for CC, keeping ref-count of tuple being 1 + paras = PyRef(PyTuple_New( size ), SAL_NO_ACQUIRE); + } + for( int i = 0 ; i < size ;i ++ ) + { + PyObject * element = PyTuple_GetItem( args , i ); + if( PyObject_IsInstance( element , getAnyClass( runtime ).get() ) ) + { + element = PyObject_GetAttrString( + element, "value" ); + } + else + { + Py_XINCREF( element ); + } + PyTuple_SetItem( paras.get(), i , element ); + } + callable = PyRef( PyObject_GetAttrString( object , (char*)name ), SAL_NO_ACQUIRE ); + if( !callable.is() ) + return 0; + } + ret = PyRef( PyObject_CallObject( callable.get(), paras.get() ), SAL_NO_ACQUIRE ); + } + catch (::com::sun::star::lang::IllegalArgumentException &e) + { + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + catch (::com::sun::star::script::CannotConvertException &e) + { + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + catch (::com::sun::star::uno::RuntimeException &e) + { + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + catch (::com::sun::star::uno::Exception &e) + { + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + + return ret.getAcquired(); +} + +PyObject *PyUNO_str( PyObject * self ) +{ + PyUNO *me = ( PyUNO * ) self; + + OStringBuffer buf; + + + if( me->members->wrappedObject.getValueType().getTypeClass() + == com::sun::star::uno::TypeClass_STRUCT || + me->members->wrappedObject.getValueType().getTypeClass() + == com::sun::star::uno::TypeClass_EXCEPTION) + { + Reference< XMaterialHolder > rHolder(me->members->xInvocation,UNO_QUERY); + if( rHolder.is() ) + { + PyThreadDetach antiguard; + Any a = rHolder->getMaterial(); + OUString s = val2str( (void*) a.getValue(), a.getValueType().getTypeLibType() ); + buf.append( OUStringToOString(s,RTL_TEXTENCODING_ASCII_US) ); + } + } + else + { + // a common UNO object + PyThreadDetach antiguard; + buf.append( "pyuno object " ); + + OUString s = val2str( (void*)me->members->wrappedObject.getValue(), + me->members->wrappedObject.getValueType().getTypeLibType() ); + buf.append( OUStringToOString(s,RTL_TEXTENCODING_ASCII_US) ); + } + + return PyString_FromString( buf.getStr()); +} + +PyObject* PyUNO_getattr (PyObject* self, char* name) +{ + PyUNO* me; + + try + { + + Runtime runtime; + + me = (PyUNO*) self; + //Handle Python dir () stuff first... + if (strcmp (name, "__members__") == 0) + { + PyObject* member_list; + Sequence<OUString> oo_member_list; + + oo_member_list = me->members->xInvocation->getMemberNames (); + member_list = PyList_New (oo_member_list.getLength ()); + for (int i = 0; i < oo_member_list.getLength (); i++) + { + // setitem steals a reference + PyList_SetItem (member_list, i, ustring2PyString(oo_member_list[i]).getAcquired() ); + } + return member_list; + } + + if (strcmp (name, "__dict__") == 0) + { + Py_INCREF (Py_None); + return Py_None; + } + if (strcmp (name, "__methods__") == 0) + { + Py_INCREF (Py_None); + return Py_None; + } + if (strcmp (name, "__class__") == 0) + { + if( me->members->wrappedObject.getValueTypeClass() == + com::sun::star::uno::TypeClass_STRUCT || + me->members->wrappedObject.getValueTypeClass() == + com::sun::star::uno::TypeClass_EXCEPTION ) + { + return getClass( + me->members->wrappedObject.getValueType().getTypeName(), runtime ).getAcquired(); + } + Py_INCREF (Py_None); + return Py_None; + } + + OUString attrName( OUString::createFromAscii( name ) ); + //We need to find out if it's a method... + if (me->members->xInvocation->hasMethod (attrName)) + { + //Create a callable object to invoke this... + PyRef ret = PyUNO_callable_new ( + me->members->xInvocation, + attrName, + runtime.getImpl()->cargo->xInvocation, + runtime.getImpl()->cargo->xTypeConverter); + Py_XINCREF( ret.get() ); + return ret.get(); + + } + + //or a property + if (me->members->xInvocation->hasProperty ( attrName)) + { + //Return the value of the property + Any anyRet; + { + PyThreadDetach antiguard; + anyRet = me->members->xInvocation->getValue (attrName); + } + PyRef ret = runtime.any2PyObject(anyRet); + Py_XINCREF( ret.get() ); + return ret.get(); + } + + //or else... + PyErr_SetString (PyExc_AttributeError, name); + } + catch( com::sun::star::reflection::InvocationTargetException & e ) + { + raisePyExceptionWithAny( makeAny(e.TargetException) ); + } + catch( com::sun::star::beans::UnknownPropertyException & e ) + { + raisePyExceptionWithAny( makeAny(e) ); + } + catch( com::sun::star::lang::IllegalArgumentException &e ) + { + raisePyExceptionWithAny( makeAny(e) ); + } + catch( com::sun::star::script::CannotConvertException &e ) + { + raisePyExceptionWithAny( makeAny(e) ); + } + catch( RuntimeException &e ) + { + raisePyExceptionWithAny( makeAny(e) ); + } + + return NULL; +} + +int PyUNO_setattr (PyObject* self, char* name, PyObject* value) +{ + PyUNO* me; + + me = (PyUNO*) self; + try + { + Runtime runtime; + Any val= runtime.pyObject2Any(value, ACCEPT_UNO_ANY); + + OUString attrName( OUString::createFromAscii( name ) ); + { + PyThreadDetach antiguard; + if (me->members->xInvocation->hasProperty (attrName)) + { + me->members->xInvocation->setValue (attrName, val); + return 0; //Keep with Python's boolean system + } + } + } + catch( com::sun::star::reflection::InvocationTargetException & e ) + { + raisePyExceptionWithAny( makeAny(e.TargetException) ); + return 1; + } + catch( com::sun::star::beans::UnknownPropertyException & e ) + { + raisePyExceptionWithAny( makeAny(e) ); + return 1; + } + catch( com::sun::star::script::CannotConvertException &e ) + { + raisePyExceptionWithAny( makeAny(e) ); + return 1; + } + catch( RuntimeException & e ) + { + raisePyExceptionWithAny( makeAny( e ) ); + return 1; + } + PyErr_SetString (PyExc_AttributeError, name); + return 1; //as above. +} + +// ensure object identity and struct equality +static PyObject* PyUNO_cmp( PyObject *self, PyObject *that, int op ) +{ + if(op != Py_EQ && op != Py_NE) + { + PyErr_SetString(PyExc_TypeError, "only '==' and '!=' comparisions are defined"); + return 0; + } + if( self == that ) + { + return (op == Py_EQ ? Py_True : Py_False); + } + try + { + Runtime runtime; + if( PyObject_IsInstance( that, getPyUnoClass( runtime ).get() ) ) + { + + PyUNO *me = reinterpret_cast< PyUNO*> ( self ); + PyUNO *other = reinterpret_cast< PyUNO *> (that ); + com::sun::star::uno::TypeClass tcMe = me->members->wrappedObject.getValueTypeClass(); + com::sun::star::uno::TypeClass tcOther = other->members->wrappedObject.getValueTypeClass(); + + if( tcMe == tcOther ) + { + if( tcMe == com::sun::star::uno::TypeClass_STRUCT || + tcMe == com::sun::star::uno::TypeClass_EXCEPTION ) + { + Reference< XMaterialHolder > xMe( me->members->xInvocation,UNO_QUERY); + Reference< XMaterialHolder > xOther( other->members->xInvocation,UNO_QUERY ); + if( xMe->getMaterial() == xOther->getMaterial() ) + { + return (op == Py_EQ ? Py_True : Py_False); + } + } + else if( tcMe == com::sun::star::uno::TypeClass_INTERFACE ) + { + if( me->members->wrappedObject == other->members->wrappedObject ) + { + return (op == Py_EQ ? Py_True : Py_False); + } + } + } + } + } + catch( com::sun::star::uno::RuntimeException & e) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + return Py_False; +} + +static PyTypeObject PyUNOType = +{ + PyVarObject_HEAD_INIT( &PyType_Type, 0 ) + "pyuno", + sizeof (PyUNO), + 0, + (destructor) PyUNO_del, + (printfunc) 0, + (getattrfunc) PyUNO_getattr, + (setattrfunc) PyUNO_setattr, + 0, + (reprfunc) PyUNO_repr, + 0, + 0, + 0, + (hashfunc) 0, + (ternaryfunc) 0, + (reprfunc) PyUNO_str, + (getattrofunc)0, + (setattrofunc)0, + NULL, + 0, + NULL, + (traverseproc)0, + (inquiry)0, + (richcmpfunc) PyUNO_cmp, + 0, + (getiterfunc)0, + (iternextfunc)0, + NULL, + NULL, + NULL, + NULL, + NULL, + (descrgetfunc)0, + (descrsetfunc)0, + 0, + (initproc)0, + (allocfunc)0, + (newfunc)0, + (freefunc)0, + (inquiry)0, + NULL, + NULL, + NULL, + NULL, + NULL, + (destructor)0 +#if PY_VERSION_HEX >= 0x02060000 + , 0 +#endif +}; + +PyRef getPyUnoClass( const Runtime &) +{ + return PyRef( reinterpret_cast< PyObject * > ( &PyUNOType ) ); +} + +PyObject* PyUNO_new ( + const Any & targetInterface, const Reference<XSingleServiceFactory> &ssf) +{ + Reference<XInterface> tmp_interface; + + targetInterface >>= tmp_interface; + + if (!tmp_interface.is ()) + { + // empty reference ! + Py_INCREF( Py_None ); + return Py_None; + } + return PyUNO_new_UNCHECKED (targetInterface, ssf); +} + + +PyObject* PyUNO_new_UNCHECKED ( + const Any &targetInterface, + const Reference<XSingleServiceFactory> &ssf ) +{ + PyUNO* self; + Sequence<Any> arguments (1); + Reference<XInterface> tmp_interface; + + self = PyObject_New (PyUNO, &PyUNOType); + if (self == NULL) + return NULL; // == error + self->members = new PyUNOInternals(); + + arguments[0] <<= targetInterface; + { + PyThreadDetach antiguard; + tmp_interface = ssf->createInstanceWithArguments (arguments); + + if (!tmp_interface.is ()) + { + Py_INCREF( Py_None ); + return Py_None; + } + + Reference<XInvocation2> tmp_invocation (tmp_interface, UNO_QUERY); + if (!tmp_invocation.is()) { + throw RuntimeException (rtl::OUString::createFromAscii ( + "XInvocation2 not implemented, cannot interact with object"), + Reference< XInterface > ()); + } + + self->members->xInvocation = tmp_invocation; + self->members->wrappedObject = targetInterface; + } + return (PyObject*) self; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno.flt b/pyuno/source/module/pyuno.flt new file mode 100755 index 000000000000..f4b498a6964c --- /dev/null +++ b/pyuno/source/module/pyuno.flt @@ -0,0 +1,14 @@ +??_R0?AVException@uno@star@sun@com@@@8??0Exception@uno@star@sun@com@@QAE@ABV01234@@Z8 +??_R0?AVIllegalArgumentException@lang@star@sun@com@@@8??0IllegalArgumentException@lang@star@sun@com@@QAE@ABV01234@@Z12 +??_R0?AVInvocationTargetException@reflection@star@sun@com@@@8??0InvocationTargetException@reflection@star@sun@com@@QAE@ABV01234@@Z20 +??_R0?AVRuntimeException@uno@star@sun@com@@@8??0RuntimeException@uno@star@sun@com@@QAE@ABV01234@@Z8 +??_R0?AVUnknownPropertyException@beans@star@sun@com@@@8??0UnknownPropertyException@beans@star@sun@com@@QAE@ABV01234@@Z8 +??_R0?AVWrappedTargetException@lang@star@sun@com@@@8??0WrappedTargetException@lang@star@sun@com@@QAE@ABV01234@@Z20 +?AVIllegalArgumentException@lang@star@sun@com@@ +?AVRuntimeException@uno@star@sun@com@@ +?AVUnknownPropertyException@beans@star@sun@com@@ +?AVInvocationTargetException@reflection@star@sun@com@@ +__CT??_R0?AVbad_alloc@std@@@8??0bad_alloc@std@@QAE@ABV01@@Z12 +__CT??_R0?AVexception@@@8??0exception@@QAE@ABV0@@Z12 +__CTA2?AVbad_alloc@std@@ +__CT?? diff --git a/pyuno/source/module/pyuno_adapter.cxx b/pyuno/source/module/pyuno_adapter.cxx new file mode 100644 index 000000000000..df3f9fae5443 --- /dev/null +++ b/pyuno/source/module/pyuno_adapter.cxx @@ -0,0 +1,440 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include "pyuno_impl.hxx" + +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> + +#include <com/sun/star/beans/MethodConcept.hpp> + +#include <cppuhelper/typeprovider.hxx> + +using rtl::OUStringToOString; +using rtl::OUString; +using rtl::OUStringBuffer; +using rtl::OString; +using rtl::OStringBuffer; + +using com::sun::star::beans::XIntrospectionAccess; +using com::sun::star::beans::XIntrospection; +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Type; +using com::sun::star::lang::XUnoTunnel; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::beans::UnknownPropertyException; +using com::sun::star::script::CannotConvertException; +using com::sun::star::reflection::InvocationTargetException; +using com::sun::star::reflection::XIdlMethod; +using com::sun::star::reflection::ParamInfo; +using com::sun::star::reflection::XIdlClass; + +#define TO_ASCII(x) OUStringToOString( x , RTL_TEXTENCODING_ASCII_US).getStr() + +namespace pyuno +{ + +Adapter::Adapter( const PyRef & ref, const Sequence< Type > &types ) + : mWrappedObject( ref ), + mInterpreter( (PyThreadState_Get()->interp) ), + mTypes( types ) +{} + +Adapter::~Adapter() +{ + // Problem: We don't know, if we have the python interpreter lock + // There is no runtime function to get to know this. + decreaseRefCount( mInterpreter, mWrappedObject.get() ); + mWrappedObject.scratch(); +} + +static cppu::OImplementationId g_id( sal_False ); + +Sequence<sal_Int8> Adapter::getUnoTunnelImplementationId() +{ + return g_id.getImplementationId(); +} + +sal_Int64 Adapter::getSomething( const Sequence< sal_Int8 > &id) throw (RuntimeException) +{ + if( id == g_id.getImplementationId() ) + return reinterpret_cast<sal_Int64>(this); + return 0; +} + +void raiseInvocationTargetExceptionWhenNeeded( const Runtime &runtime ) + throw ( InvocationTargetException ) +{ + if( PyErr_Occurred() ) + { + PyRef excType, excValue, excTraceback; + PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback); + Any unoExc( runtime.extractUnoException( excType, excValue, excTraceback ) ); + throw InvocationTargetException( + ((com::sun::star::uno::Exception*)unoExc.getValue())->Message, + Reference<XInterface>(), unoExc ); + } +} + +Reference< XIntrospectionAccess > Adapter::getIntrospection() + throw ( RuntimeException ) +{ + // not supported + return Reference< XIntrospectionAccess > (); +} + +Sequence< sal_Int16 > Adapter::getOutIndexes( const OUString & functionName ) +{ + Sequence< sal_Int16 > ret; + MethodOutIndexMap::const_iterator ii = m_methodOutIndexMap.find( functionName ); + if( ii == m_methodOutIndexMap.end() ) + { + + Runtime runtime; + { + PyThreadDetach antiguard; + + // retrieve the adapter object again. It will be the same instance as before, + // (the adapter factory keeps a weak map inside, which I couldn't have outside) + Reference< XInterface > unoAdapterObject = + runtime.getImpl()->cargo->xAdapterFactory->createAdapter( this, mTypes ); + + // uuuh, that's really expensive. The alternative would have been, to store + // an instance of the introspection at (this), but this results in a cyclic + // reference, which is never broken (as it is up to OOo1.1.0). + Reference< XIntrospectionAccess > introspection = + runtime.getImpl()->cargo->xIntrospection->inspect( makeAny( unoAdapterObject ) ); + + if( !introspection.is() ) + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno bridge: Couldn't inspect uno adapter ( the python class must implement com.sun.star.lang.XTypeProvider !)" ) ), + Reference< XInterface > () ); + } + + Reference< XIdlMethod > method = introspection->getMethod( + functionName, com::sun::star::beans::MethodConcept::ALL ); + if( ! method.is( ) ) + { + throw RuntimeException( + (OUString( + RTL_CONSTASCII_USTRINGPARAM( + "pyuno bridge: Couldn't get reflection for method ")) + + functionName), + Reference< XInterface > () ); + } + + Sequence< ParamInfo > seqInfo = method->getParameterInfos(); + int i; + int nOuts = 0; + for( i = 0 ; i < seqInfo.getLength() ; i ++ ) + { + if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT || + seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT ) + { + // sequence must be interpreted as return value/outparameter tuple ! + nOuts ++; + } + } + + if( nOuts ) + { + ret.realloc( nOuts ); + sal_Int32 nOutsAssigned = 0; + for( i = 0 ; i < seqInfo.getLength() ; i ++ ) + { + if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT || + seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT ) + { + ret[nOutsAssigned] = (sal_Int16) i; + nOutsAssigned ++; + } + } + } + } + // guard active again ! + m_methodOutIndexMap[ functionName ] = ret; + } + else + { + ret = ii->second; + } + return ret; +} + +Any Adapter::invoke( const OUString &aFunctionName, + const Sequence< Any >& aParams, + Sequence< sal_Int16 > &aOutParamIndex, + Sequence< Any > &aOutParam) + throw (IllegalArgumentException,CannotConvertException,InvocationTargetException,RuntimeException) +{ + Any ret; + + // special hack for the uno object identity concept. The XUnoTunnel.getSomething() call is + // always handled by the adapter directly. + if( aParams.getLength() == 1 && 0 == aFunctionName.compareToAscii( "getSomething" ) ) + { + Sequence< sal_Int8 > id; + if( aParams[0] >>= id ) + return com::sun::star::uno::makeAny( getSomething( id ) ); + + } + + RuntimeCargo *cargo = 0; + try + { + PyThreadAttach guard( mInterpreter ); + { + // convert parameters to python args + // TODO: Out parameter + Runtime runtime; + cargo = runtime.getImpl()->cargo; + if( isLog( cargo, LogLevel::CALL ) ) + { + logCall( cargo, "try uno->py[0x", + mWrappedObject.get(), aFunctionName, aParams ); + } + + sal_Int32 size = aParams.getLength(); + PyRef argsTuple(PyTuple_New( size ), SAL_NO_ACQUIRE ); + int i; + // fill tuple with default values in case of exceptions + for( i = 0 ;i < size ; i ++ ) + { + Py_INCREF( Py_None ); + PyTuple_SetItem( argsTuple.get(), i, Py_None ); + } + + // convert args to python + for( i = 0; i < size ; i ++ ) + { + PyRef val = runtime.any2PyObject( aParams[i] ); + PyTuple_SetItem( argsTuple.get(), i, val.getAcquired() ); + } + + // get callable + PyRef method(PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aFunctionName)), + SAL_NO_ACQUIRE); + raiseInvocationTargetExceptionWhenNeeded( runtime); + if( !method.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno::Adapater: Method " ).append( aFunctionName ); + buf.appendAscii( " is not implemented at object " ); + PyRef str( PyObject_Repr( mWrappedObject.get() ), SAL_NO_ACQUIRE ); + buf.appendAscii( PyString_AsString( str.get() )); + throw IllegalArgumentException( buf.makeStringAndClear(), Reference< XInterface > (),0 ); + } + + PyRef pyRet( PyObject_CallObject( method.get(), argsTuple.get() ), SAL_NO_ACQUIRE ); + raiseInvocationTargetExceptionWhenNeeded( runtime); + if( pyRet.is() ) + { + ret = runtime.pyObject2Any( pyRet ); + + if( ret.hasValue() && + ret.getValueTypeClass() == com::sun::star::uno::TypeClass_SEQUENCE && + 0 != aFunctionName.compareToAscii( "getTypes" ) && // needed by introspection itself ! + 0 != aFunctionName.compareToAscii( "getImplementationId" ) ) // needed by introspection itself ! + { + // the sequence can either be + // 1) a simple sequence return value + // 2) a sequence, where the first element is the return value + // and the following elements are interpreted as the outparameter + // I can only decide for one solution by checking the method signature, + // so I need the reflection of the adapter ! + aOutParamIndex = getOutIndexes( aFunctionName ); + if( aOutParamIndex.getLength() ) + { + // out parameters exist, extract the sequence + Sequence< Any > seq; + if( ! ( ret >>= seq ) ) + { + throw RuntimeException( + (OUString( + RTL_CONSTASCII_USTRINGPARAM( + "pyuno bridge: Couldn't extract out" + " parameters for method ")) + + aFunctionName), + Reference< XInterface > () ); + } + + if( aOutParamIndex.getLength() +1 != seq.getLength() ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno bridge: expected for method " ); + buf.append( aFunctionName ); + buf.appendAscii( " one return value and " ); + buf.append( (sal_Int32) aOutParamIndex.getLength() ); + buf.appendAscii( " out parameters, got a sequence of " ); + buf.append( seq.getLength() ); + buf.appendAscii( " elements as return value." ); + throw RuntimeException(buf.makeStringAndClear(), *this ); + } + + aOutParam.realloc( aOutParamIndex.getLength() ); + ret = seq[0]; + for( i = 0 ; i < aOutParamIndex.getLength() ; i ++ ) + { + aOutParam[i] = seq[1+i]; + } + } + // else { sequence is a return value !} + } + } + + // log the reply, if desired + if( isLog( cargo, LogLevel::CALL ) ) + { + logReply( cargo, "success uno->py[0x" , + mWrappedObject.get(), aFunctionName, ret, aOutParam ); + } + } + + } + catch(InvocationTargetException & e ) + { + if( isLog( cargo, LogLevel::CALL ) ) + { + logException( + cargo, "except uno->py[0x" , + mWrappedObject.get(), aFunctionName, + e.TargetException.getValue(),e.TargetException.getValueType() ); + } + throw; + } + catch( RuntimeException & e ) + { + if( cargo && isLog( cargo, LogLevel::CALL ) ) + { + logException( + cargo, "except uno->py[0x" , + mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) ); + } + throw; + } + catch( CannotConvertException & e ) + { + if( isLog( cargo, LogLevel::CALL ) ) + { + logException( + cargo, "except uno->py[0x" , + mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) ); + } + throw; + } + catch( IllegalArgumentException & e ) + { + if( isLog( cargo, LogLevel::CALL ) ) + { + logException( + cargo, "except uno->py[0x" , + mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) ); + } + throw; + } + return ret; +} + +void Adapter::setValue( const OUString & aPropertyName, const Any & value ) + throw( UnknownPropertyException, CannotConvertException, InvocationTargetException,RuntimeException) +{ + PyThreadAttach guard( mInterpreter ); + try + { + Runtime runtime; + PyRef obj = runtime.any2PyObject( value ); + + if( !hasProperty( aPropertyName ) ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName ); + buf.appendAscii( " is unknown." ); + throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + + PyObject_SetAttrString( + mWrappedObject.get(), (char*)TO_ASCII(aPropertyName), obj.get() ); + raiseInvocationTargetExceptionWhenNeeded( runtime); + + } + catch( IllegalArgumentException & exc ) + { + throw InvocationTargetException( exc.Message, *this, com::sun::star::uno::makeAny( exc ) ); + } +} + +Any Adapter::getValue( const OUString & aPropertyName ) + throw ( UnknownPropertyException, RuntimeException ) +{ + Any ret; + PyThreadAttach guard( mInterpreter ); + { + Runtime runtime; + PyRef pyRef( + PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aPropertyName) ), + SAL_NO_ACQUIRE ); + + raiseInvocationTargetExceptionWhenNeeded( runtime); + if( !pyRef.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName ); + buf.appendAscii( " is unknown." ); + throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + ret = runtime.pyObject2Any( pyRef ); + } + return ret; +} + +sal_Bool Adapter::hasMethod( const OUString & aMethodName ) + throw ( RuntimeException ) +{ + return hasProperty( aMethodName ); +} + +sal_Bool Adapter::hasProperty( const OUString & aPropertyName ) + throw ( RuntimeException ) +{ + bool bRet = false; + PyThreadAttach guard( mInterpreter ); + { + bRet = PyObject_HasAttrString( + mWrappedObject.get() , (char*) TO_ASCII( aPropertyName )); + } + return bRet; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_callable.cxx b/pyuno/source/module/pyuno_callable.cxx new file mode 100644 index 000000000000..e5c943fa7022 --- /dev/null +++ b/pyuno/source/module/pyuno_callable.cxx @@ -0,0 +1,277 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include "pyuno_impl.hxx" + +#include <osl/thread.h> +#include <rtl/ustrbuf.hxx> + +using rtl::OUStringToOString; +using rtl::OUString; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::TypeClass; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::XComponentContext; +using com::sun::star::lang::XSingleServiceFactory; +using com::sun::star::script::XTypeConverter; +using com::sun::star::script::XInvocation2; + +namespace pyuno +{ +typedef struct +{ + Reference<XInvocation2> xInvocation; + Reference<XSingleServiceFactory> xInvocationFactory; + Reference<XTypeConverter> xTypeConverter; + OUString methodName; + ConversionMode mode; +} PyUNO_callable_Internals; + +typedef struct +{ + PyObject_HEAD + PyUNO_callable_Internals* members; +} PyUNO_callable; + +void PyUNO_callable_del (PyObject* self) +{ + PyUNO_callable* me; + + me = (PyUNO_callable*) self; + delete me->members; + PyObject_Del (self); + + return; +} + +PyObject* PyUNO_callable_call (PyObject* self, PyObject* args, PyObject*) +{ + PyUNO_callable* me; + + Sequence<short> aOutParamIndex; + Sequence<Any> aOutParam; + Sequence<Any> aParams; + Sequence<Type> aParamTypes; + Any any_params; + Any out_params; + Any ret_value; + RuntimeCargo *cargo = 0; + me = (PyUNO_callable*) self; + + PyRef ret; + try + { + Runtime runtime; + cargo = runtime.getImpl()->cargo; + any_params = runtime.pyObject2Any (args, me->members->mode); + + if (any_params.getValueTypeClass () == com::sun::star::uno::TypeClass_SEQUENCE) + { + any_params >>= aParams; + } + else + { + aParams.realloc (1); + aParams [0] <<= any_params; + } + + { + PyThreadDetach antiguard; //pyhton free zone + + // do some logging if desired ... + if( isLog( cargo, LogLevel::CALL ) ) + { + logCall( cargo, "try py->uno[0x", me->members->xInvocation.get(), + me->members->methodName, aParams ); + } + + // do the call + ret_value = me->members->xInvocation->invoke ( + me->members->methodName, aParams, aOutParamIndex, aOutParam); + + // log the reply, if desired + if( isLog( cargo, LogLevel::CALL ) ) + { + logReply( cargo, "success py->uno[0x", me->members->xInvocation.get(), + me->members->methodName, ret_value, aOutParam); + } + } + + + PyRef temp = runtime.any2PyObject (ret_value); + if( aOutParam.getLength() ) + { + PyRef return_list( PyTuple_New (1+aOutParam.getLength()), SAL_NO_ACQUIRE ); + PyTuple_SetItem (return_list.get(), 0, temp.getAcquired()); + + // initialize with defaults in case of exceptions + int i; + for( i = 1 ; i < 1+aOutParam.getLength() ; i ++ ) + { + Py_INCREF( Py_None ); + PyTuple_SetItem( return_list.get() , i , Py_None ); + } + + for( i = 0 ; i < aOutParam.getLength() ; i ++ ) + { + PyRef ref = runtime.any2PyObject( aOutParam[i] ); + PyTuple_SetItem (return_list.get(), 1+i, ref.getAcquired()); + } + ret = return_list; + } + else + { + ret = temp; + } + } + catch( com::sun::star::reflection::InvocationTargetException & e ) + { + + if( isLog( cargo, LogLevel::CALL ) ) + { + logException( cargo, "except py->uno[0x", me->members->xInvocation.get() , + me->members->methodName, e.TargetException.getValue(), e.TargetException.getValueTypeRef()); + } + raisePyExceptionWithAny( e.TargetException ); + } + catch( com::sun::star::script::CannotConvertException &e ) + { + if( isLog( cargo, LogLevel::CALL ) ) + { + logException( cargo, "error py->uno[0x", me->members->xInvocation.get() , + me->members->methodName, &e, getCppuType(&e).getTypeLibType()); + } + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + catch( com::sun::star::lang::IllegalArgumentException &e ) + { + if( isLog( cargo, LogLevel::CALL ) ) + { + logException( cargo, "error py->uno[0x", me->members->xInvocation.get() , + me->members->methodName, &e, getCppuType(&e).getTypeLibType()); + } + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + catch (::com::sun::star::uno::RuntimeException &e) + { + if( cargo && isLog( cargo, LogLevel::CALL ) ) + { + logException( cargo, "error py->uno[0x", me->members->xInvocation.get() , + me->members->methodName, &e, getCppuType(&e).getTypeLibType()); + } + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + + return ret.getAcquired(); +} + + +static PyTypeObject PyUNO_callable_Type = +{ + PyVarObject_HEAD_INIT( &PyType_Type, 0 ) + "PyUNO_callable", + sizeof (PyUNO_callable), + 0, + (destructor) ::pyuno::PyUNO_callable_del, + (printfunc) 0, + (getattrfunc) 0, + (setattrfunc) 0, + 0, + (reprfunc) 0, + 0, + 0, + 0, + (hashfunc) 0, + (ternaryfunc) ::pyuno::PyUNO_callable_call, + (reprfunc) 0, + (getattrofunc)0, + (setattrofunc)0, + NULL, + 0, + NULL, + (traverseproc)0, + (inquiry)0, + (richcmpfunc)0, + 0, + (getiterfunc)0, + (iternextfunc)0, + NULL, + NULL, + NULL, + NULL, + NULL, + (descrgetfunc)0, + (descrsetfunc)0, + 0, + (initproc)0, + (allocfunc)0, + (newfunc)0, + (freefunc)0, + (inquiry)0, + NULL, + NULL, + NULL, + NULL, + NULL, + (destructor)0 +#if PY_VERSION_HEX >= 0x02060000 + , 0 +#endif +}; + +PyRef PyUNO_callable_new ( + const Reference<XInvocation2> &my_inv, + const OUString & methodName, + const Reference<XSingleServiceFactory> &xInvocationFactory, + const Reference<XTypeConverter> &tc, + enum ConversionMode mode ) +{ + PyUNO_callable* self; + + OSL_ENSURE (my_inv.is(), "XInvocation must be valid"); + + self = PyObject_New (PyUNO_callable, &PyUNO_callable_Type); + if (self == NULL) + return NULL; //NULL == Error! + + self->members = new PyUNO_callable_Internals; + self->members->xInvocation = my_inv; + self->members->methodName = methodName; + self->members->xInvocationFactory = xInvocationFactory; + self->members->xTypeConverter = tc; + self->members->mode = mode; + + return PyRef( (PyObject*)self, SAL_NO_ACQUIRE ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_dlopenwrapper.c b/pyuno/source/module/pyuno_dlopenwrapper.c new file mode 100644 index 000000000000..1ace0442ced6 --- /dev/null +++ b/pyuno/source/module/pyuno_dlopenwrapper.c @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <rtl/string.h> + +#include <stdlib.h> +#include <string.h> + +#ifdef LINUX +# ifndef __USE_GNU +# define __USE_GNU +# endif +#endif +#include <dlfcn.h> + +void initpyuno () +{ + Dl_info dl_info; + void (*func)(void); + + if (dladdr((void*)&initpyuno, &dl_info) != 0) { + void* h = 0; + size_t len = strrchr(dl_info.dli_fname, '/') - dl_info.dli_fname + 1; + char* libname = malloc(len + RTL_CONSTASCII_LENGTH( SAL_DLLPREFIX "pyuno" SAL_DLLEXTENSION ) + 1); + strncpy(libname, dl_info.dli_fname, len); + strcpy(libname + (len), SAL_DLLPREFIX "pyuno" SAL_DLLEXTENSION); + + h = dlopen (libname, RTLD_NOW | RTLD_GLOBAL); + free(libname); + if( h ) + { + func = (void (*)())dlsym (h, "initpyuno"); + (func) (); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_except.cxx b/pyuno/source/module/pyuno_except.cxx new file mode 100644 index 000000000000..97b876fbcc31 --- /dev/null +++ b/pyuno/source/module/pyuno_except.cxx @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include "pyuno_impl.hxx" + +#include <rtl/ustrbuf.hxx> + +#include <typelib/typedescription.hxx> + +using rtl::OUString; +using rtl::OUStringBuffer; +using rtl::OUStringToOString; + +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Type; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::TypeDescription; + +namespace pyuno +{ + +void raisePyExceptionWithAny( const com::sun::star::uno::Any &anyExc ) +{ + try + { + Runtime runtime; + PyRef exc = runtime.any2PyObject( anyExc ); + if( exc.is() ) + { + PyRef type( getClass( anyExc.getValueType().getTypeName(),runtime ) ); + PyErr_SetObject( type.get(), exc.get()); + } + else + { + com::sun::star::uno::Exception e; + anyExc >>= e; + + OUStringBuffer buf; + buf.appendAscii( "Couldn't convert uno exception to a python exception (" ); + buf.append(anyExc.getValueType().getTypeName()); + buf.appendAscii( ": " ); + buf.append(e.Message ); + buf.appendAscii( ")" ); + PyErr_SetString( + PyExc_SystemError, + OUStringToOString(buf.makeStringAndClear(),RTL_TEXTENCODING_ASCII_US) ); + } + } + catch( com::sun::star::lang::IllegalArgumentException & e) + { + PyErr_SetString( PyExc_SystemError, + OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) ); + } + catch( com::sun::star::script::CannotConvertException & e) + { + PyErr_SetString( PyExc_SystemError, + OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) ); + } + catch( RuntimeException & e) + { + PyErr_SetString( PyExc_SystemError, + OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) ); + } +} + + +static PyRef createClass( const OUString & name, const Runtime &runtime ) + throw ( RuntimeException ) +{ + // assuming that this is never deleted ! + // note I don't have the knowledge how to initialize these type objects correctly ! + TypeDescription desc( name ); + if( ! desc.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno.getClass: uno exception " ); + buf.append(name).appendAscii( " is unknown" ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + + sal_Bool isStruct = desc.get()->eTypeClass == typelib_TypeClass_STRUCT; + sal_Bool isExc = desc.get()->eTypeClass == typelib_TypeClass_EXCEPTION; + sal_Bool isInterface = desc.get()->eTypeClass == typelib_TypeClass_INTERFACE; + if( !isStruct && !isExc && ! isInterface ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno.getClass: " ).append(name).appendAscii( "is a " ); + buf.appendAscii( + typeClassToString( (com::sun::star::uno::TypeClass) desc.get()->eTypeClass)); + buf.appendAscii( ", expected EXCEPTION, STRUCT or INTERFACE" ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface>() ); + } + + // retrieve base class + PyRef base; + if( isInterface ) + { + typelib_InterfaceTypeDescription *pDesc = (typelib_InterfaceTypeDescription * )desc.get(); + if( pDesc->pBaseTypeDescription ) + { + base = getClass( pDesc->pBaseTypeDescription->aBase.pTypeName, runtime ); + } + else + { + // must be XInterface ! + } + } + else + { + typelib_CompoundTypeDescription *pDesc = (typelib_CompoundTypeDescription*)desc.get(); + if( pDesc->pBaseTypeDescription ) + { + base = getClass( pDesc->pBaseTypeDescription->aBase.pTypeName, runtime ); + } + else + { + if( isExc ) + // we are currently creating the root UNO exception + base = PyRef(PyExc_Exception); + } + } + PyRef args( PyTuple_New( 3 ), SAL_NO_ACQUIRE ); + + PyRef pyTypeName = ustring2PyString( name /*.replace( '.', '_' )*/ ); + + PyRef bases; + if( base.is() ) + { + { // for CC, keeping ref-count being 1 + bases = PyRef( PyTuple_New( 1 ), SAL_NO_ACQUIRE ); + } + PyTuple_SetItem( bases.get(), 0 , base.getAcquired() ); + } + else + { + bases = PyRef( PyTuple_New( 0 ), SAL_NO_ACQUIRE ); + } + + PyTuple_SetItem( args.get(), 0, pyTypeName.getAcquired()); + PyTuple_SetItem( args.get(), 1, bases.getAcquired() ); + PyTuple_SetItem( args.get(), 2, PyDict_New() ); + + PyRef ret( + PyObject_CallObject(reinterpret_cast<PyObject *>(&PyType_Type) , args.get()), + SAL_NO_ACQUIRE ); + + // now overwrite ctor and attrib functions + if( isInterface ) + { + PyObject_SetAttrString( + ret.get(), "__pyunointerface__", + ustring2PyString(name).get() ); + } + else + { + PyRef ctor = getObjectFromUnoModule( runtime,"_uno_struct__init__" ); + PyRef setter = getObjectFromUnoModule( runtime,"_uno_struct__setattr__" ); + PyRef getter = getObjectFromUnoModule( runtime,"_uno_struct__getattr__" ); + PyRef repr = getObjectFromUnoModule( runtime,"_uno_struct__repr__" ); + PyRef eq = getObjectFromUnoModule( runtime,"_uno_struct__eq__" ); + + PyObject_SetAttrString( + ret.get(), "__pyunostruct__", + ustring2PyString(name).get() ); + PyObject_SetAttrString( + ret.get(), "typeName", + ustring2PyString(name).get() ); + PyObject_SetAttrString( + ret.get(), "__init__", ctor.get() ); + PyObject_SetAttrString( + ret.get(), "__getattr__", getter.get() ); + PyObject_SetAttrString( + ret.get(), "__setattr__", setter.get() ); + PyObject_SetAttrString( + ret.get(), "__repr__", repr.get() ); + PyObject_SetAttrString( + ret.get(), "__str__", repr.get() ); + PyObject_SetAttrString( + ret.get(), "__eq__", eq.get() ); + } + return ret; +} + +bool isInstanceOfStructOrException( PyObject *obj) +{ + PyRef attr( + PyObject_GetAttrString(obj, "__class__"), + SAL_NO_ACQUIRE ); + return PyObject_HasAttrString( + attr.get(), "__pyunostruct__"); +} + +sal_Bool isInterfaceClass( const Runtime &runtime, PyObject * obj ) +{ + const ClassSet & set = runtime.getImpl()->cargo->interfaceSet; + return set.find( obj ) != set.end(); +} + +PyRef getClass( const OUString & name , const Runtime &runtime) +{ + PyRef ret; + + RuntimeCargo *cargo =runtime.getImpl()->cargo; + ExceptionClassMap::iterator ii = cargo->exceptionMap.find( name ); + if( ii == cargo->exceptionMap.end() ) + { + ret = createClass( name, runtime ); + cargo->exceptionMap[name] = ret; + if( PyObject_HasAttrString( + ret.get(), "__pyunointerface__" ) ) + cargo->interfaceSet.insert( ret ); + + PyObject_SetAttrString( + ret.get(), "__pyunointerface__", + ustring2PyString(name).get() ); + } + else + { + ret = ii->second; + } + + return ret; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_gc.cxx b/pyuno/source/module/pyuno_gc.cxx new file mode 100644 index 000000000000..77eb6885d04e --- /dev/null +++ b/pyuno/source/module/pyuno_gc.cxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <pyuno_impl.hxx> +#include <osl/thread.hxx> +namespace pyuno +{ + +bool g_destructorsOfStaticObjectsHaveBeenCalled; +class StaticDestructorGuard +{ +public: + ~StaticDestructorGuard() + { + g_destructorsOfStaticObjectsHaveBeenCalled = true; + } +}; +StaticDestructorGuard guard; + +static bool isAfterUnloadOrPy_Finalize() +{ + return g_destructorsOfStaticObjectsHaveBeenCalled || + !Py_IsInitialized(); +} + +class GCThread : public ::osl::Thread +{ + PyObject *mPyObject; + PyInterpreterState *mPyInterpreter; + GCThread( const GCThread & ); // not implemented + GCThread &operator =( const GCThread & ); // not implemented + +public: + GCThread( PyInterpreterState *interpreter, PyObject * object ); + virtual void SAL_CALL run(); + virtual void SAL_CALL onTerminated(); +}; + + +GCThread::GCThread( PyInterpreterState *interpreter, PyObject * object ) : + mPyObject( object ), mPyInterpreter( interpreter ) +{} + +void GCThread::run() +{ + // otherwise we crash here, when main has been left already + if( isAfterUnloadOrPy_Finalize() ) + return; + try + { + PyThreadAttach g( (PyInterpreterState*)mPyInterpreter ); + { + Runtime runtime; + + // remove the reference from the pythonobject2adapter map + PyRef2Adapter::iterator ii = + runtime.getImpl()->cargo->mappedObjects.find( mPyObject ); + if( ii != runtime.getImpl()->cargo->mappedObjects.end() ) + { + runtime.getImpl()->cargo->mappedObjects.erase( ii ); + } + + Py_XDECREF( mPyObject ); + } + } + catch( com::sun::star::uno::RuntimeException & e ) + { + rtl::OString msg; + msg = rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ); + fprintf( stderr, "Leaking python objects bridged to UNO for reason %s\n",msg.getStr()); + } +} + + +void GCThread::onTerminated() +{ + delete this; +} + +void decreaseRefCount( PyInterpreterState *interpreter, PyObject *object ) +{ + // otherwise we crash in the last after main ... + if( isAfterUnloadOrPy_Finalize() ) + return; + + // delegate to a new thread, because there does not seem + // to be a method, which tells, whether the global + // interpreter lock is held or not + // TODO: Look for a more efficient solution + osl::Thread *t = new GCThread( interpreter, object ); + t->create(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_impl.hxx b/pyuno/source/module/pyuno_impl.hxx new file mode 100644 index 000000000000..ff6ca8716e69 --- /dev/null +++ b/pyuno/source/module/pyuno_impl.hxx @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _PYUNO_IMPL_ +#define _PYUNO_IMPL_ + +#include <Python.h> + +//Must define PyVarObject_HEAD_INIT for Python 2.5 or older +#ifndef PyVarObject_HEAD_INIT +#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, +#endif + +#include <pyuno/pyuno.hxx> + +#include <boost/unordered_map.hpp> +#include <boost/unordered_set.hpp> + +#include <com/sun/star/beans/XIntrospection.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/script/XInvocation2.hpp> +#include <com/sun/star/script/XInvocationAdapterFactory2.hpp> + +#include <com/sun/star/reflection/XIdlReflection.hpp> + +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> + +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +#include <cppuhelper/implbase2.hxx> +#include <cppuhelper/weakref.hxx> + +// In Python 3, the PyString_* functions have been replaced by PyBytes_* +// and PyUnicode_* functions. +#if PY_MAJOR_VERSION >= 3 +inline char* PyString_AsString(PyObject *object) +{ + // check whether object is already of type "PyBytes" + if(PyBytes_Check(object)) + { + return PyBytes_AsString(object); + } + + // object is not encoded yet, so encode it to utf-8 + PyObject *pystring; + pystring = PyUnicode_AsUTF8String(object); + if(!pystring) + { + PyErr_SetString(PyExc_ValueError, "cannot utf-8 decode string"); + return 0; + } + return PyBytes_AsString(pystring); +} + +inline PyObject* PyString_FromString(const char *string) +{ + return PyUnicode_FromString(string); +} + +inline int PyString_Check(PyObject *object) +{ + return PyBytes_Check(object); +} + +inline Py_ssize_t PyString_Size(PyObject *object) +{ + return PyBytes_Size(object); +} + +inline PyObject* PyString_FromStringAndSize(const char *string, Py_ssize_t len) +{ + return PyBytes_FromStringAndSize(string, len); +} +#endif /* PY_MAJOR_VERSION >= 3 */ + +namespace pyuno +{ + +//-------------------------------------------------- +// Logging API - implementation can be found in pyuno_util +//-------------------------------------------------- +struct RuntimeCargo; +namespace LogLevel +{ +// when you add a loglevel, extend the log function ! +static const sal_Int32 NONE = 0; +static const sal_Int32 CALL = 1; +static const sal_Int32 ARGS = 2; +} + +bool isLog( RuntimeCargo *cargo, sal_Int32 loglevel ); +void log( RuntimeCargo *cargo, sal_Int32 level, const rtl::OUString &logString ); +void log( RuntimeCargo *cargo, sal_Int32 level, const char *str ); +void logCall( RuntimeCargo *cargo, const char *intro, + void * ptr, const rtl::OUString & aFunctionName, + const com::sun::star::uno::Sequence< com::sun::star::uno::Any > & args ); +void logReply( RuntimeCargo *cargo, const char *intro, + void * ptr, const rtl::OUString & aFunctionName, + const com::sun::star::uno::Any &returnValue, + const com::sun::star::uno::Sequence< com::sun::star::uno::Any > & args ); +void logException( RuntimeCargo *cargo, const char *intro, + void * ptr, const rtl::OUString &aFunctionName, + const void * data, const com::sun::star::uno::Type & type ); +static const sal_Int32 VAL2STR_MODE_DEEP = 0; +static const sal_Int32 VAL2STR_MODE_SHALLOW = 1; +rtl::OUString val2str( const void * pVal, typelib_TypeDescriptionReference * pTypeRef, sal_Int32 mode = VAL2STR_MODE_DEEP ) SAL_THROW( () ); +//-------------------------------------------------- + +typedef ::boost::unordered_map +< + PyRef, + com::sun::star::uno::WeakReference< com::sun::star::script::XInvocation >, + PyRef::Hash, + std::equal_to< PyRef > +> PyRef2Adapter; + + +typedef ::boost::unordered_map +< +rtl::OUString, +PyRef, +rtl::OUStringHash, +std::equal_to<rtl::OUString> +> ExceptionClassMap; + +typedef ::boost::unordered_map +< + rtl::OUString, + com::sun::star::uno::Sequence< sal_Int16 >, + rtl::OUStringHash, + std::equal_to< rtl::OUString > +> MethodOutIndexMap; + +typedef ::boost::unordered_set< PyRef , PyRef::Hash , std::equal_to<PyRef> > ClassSet; + +PyObject* PyUNO_new( + const com::sun::star::uno::Any & targetInterface, + const com::sun::star::uno::Reference<com::sun::star::lang::XSingleServiceFactory> & ssf); + +PyObject* PyUNO_new_UNCHECKED ( + const com::sun::star::uno::Any & targetInterface, + const com::sun::star::uno::Reference<com::sun::star::lang::XSingleServiceFactory> & ssf); + +typedef struct +{ + com::sun::star::uno::Reference <com::sun::star::script::XInvocation2> xInvocation; + com::sun::star::uno::Any wrappedObject; +} PyUNOInternals; + +typedef struct +{ + PyObject_HEAD + PyUNOInternals* members; +} PyUNO; + +PyRef ustring2PyUnicode( const rtl::OUString &source ); +PyRef ustring2PyString( const ::rtl::OUString & source ); +rtl::OUString pyString2ustring( PyObject *str ); + + +PyRef AnyToPyObject (const com::sun::star::uno::Any & a, const Runtime &r ) + throw ( com::sun::star::uno::RuntimeException ); + +com::sun::star::uno::Any PyObjectToAny (PyObject* o) + throw ( com::sun::star::uno::RuntimeException ); + +void raiseInvocationTargetExceptionWhenNeeded( const Runtime &runtime ) + throw ( com::sun::star::reflection::InvocationTargetException ); + +com::sun::star::uno::TypeClass StringToTypeClass (char* string); + +PyRef PyUNO_callable_new ( + const com::sun::star::uno::Reference<com::sun::star::script::XInvocation2> &xInv, + const rtl::OUString &methodName, + const com::sun::star::uno::Reference<com::sun::star::lang::XSingleServiceFactory> &ssf, + const com::sun::star::uno::Reference<com::sun::star::script::XTypeConverter> &tc, + ConversionMode mode = REJECT_UNO_ANY ); + +PyObject* PyUNO_Type_new (const char *typeName , com::sun::star::uno::TypeClass t , const Runtime &r ); +PyObject* PyUNO_Enum_new( const char *enumBase, const char *enumValue, const Runtime &r ); +PyObject* PyUNO_char_new (sal_Unicode c , const Runtime &r); +PyObject *PyUNO_ByteSequence_new( const com::sun::star::uno::Sequence< sal_Int8 > &, const Runtime &r ); + +PyObject *importToGlobal( PyObject *typeName, PyObject *dict, PyObject *targetName ); + +PyRef getTypeClass( const Runtime &); +PyRef getEnumClass( const Runtime &); +PyRef getBoolClass( const Runtime &); +PyRef getCharClass( const Runtime &); +PyRef getByteSequenceClass( const Runtime & ); +PyRef getPyUnoClass( const Runtime &); +PyRef getClass( const rtl::OUString & name , const Runtime & runtime ); +PyRef getAnyClass( const Runtime &); +PyObject *PyUNO_invoke( PyObject *object, const char *name , PyObject *args ); + +com::sun::star::uno::Any PyEnum2Enum( PyObject *obj ) + throw ( com::sun::star::uno::RuntimeException ); +sal_Bool PyBool2Bool( PyObject *o, const Runtime & r ) + throw ( com::sun::star::uno::RuntimeException ); +sal_Unicode PyChar2Unicode( PyObject *o ) + throw ( com::sun::star::uno::RuntimeException ); +com::sun::star::uno::Type PyType2Type( PyObject * o ) + throw( com::sun::star::uno::RuntimeException ); + +void raisePyExceptionWithAny( const com::sun::star::uno::Any &a ); +const char *typeClassToString( com::sun::star::uno::TypeClass t ); + +PyRef getObjectFromUnoModule( const Runtime &runtime, const char * object ) + throw ( com::sun::star::uno::RuntimeException ); + +sal_Bool isInterfaceClass( const Runtime &, PyObject *obj ); +bool isInstanceOfStructOrException( PyObject *obj); +com::sun::star::uno::Sequence<com::sun::star::uno::Type> implementsInterfaces( + const Runtime & runtime, PyObject *obj ); + +struct RuntimeCargo +{ + com::sun::star::uno::Reference< com::sun::star::lang::XSingleServiceFactory > xInvocation; + com::sun::star::uno::Reference< com::sun::star::script::XTypeConverter> xTypeConverter; + com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > xContext; + com::sun::star::uno::Reference< com::sun::star::reflection::XIdlReflection > xCoreReflection; + com::sun::star::uno::Reference< com::sun::star::container::XHierarchicalNameAccess > xTdMgr; + com::sun::star::uno::Reference< com::sun::star::script::XInvocationAdapterFactory2 > xAdapterFactory; + com::sun::star::uno::Reference< com::sun::star::beans::XIntrospection > xIntrospection; + PyRef dictUnoModule; + bool valid; + ExceptionClassMap exceptionMap; + ClassSet interfaceSet; + PyRef2Adapter mappedObjects; + FILE *logFile; + sal_Int32 logLevel; + + PyRef getUnoModule(); +}; + +struct stRuntimeImpl +{ + PyObject_HEAD + struct RuntimeCargo *cargo; +public: + static void del( PyObject *self ); + + static PyRef create( + const com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > & xContext ) + throw ( com::sun::star::uno::RuntimeException ); +}; + + +class Adapter : public cppu::WeakImplHelper2< + com::sun::star::script::XInvocation, com::sun::star::lang::XUnoTunnel > +{ + PyRef mWrappedObject; + PyInterpreterState *mInterpreter; // interpreters don't seem to be refcounted ! + com::sun::star::uno::Sequence< com::sun::star::uno::Type > mTypes; + MethodOutIndexMap m_methodOutIndexMap; + +private: + com::sun::star::uno::Sequence< sal_Int16 > getOutIndexes( const rtl::OUString & functionName ); + +public: +public: + Adapter( const PyRef &obj, + const com::sun::star::uno::Sequence< com::sun::star::uno::Type > & types ); + + static com::sun::star::uno::Sequence< sal_Int8 > getUnoTunnelImplementationId(); + PyRef getWrappedObject() { return mWrappedObject; } + com::sun::star::uno::Sequence< com::sun::star::uno::Type > getWrappedTypes() { return mTypes; } + virtual ~Adapter(); + + // XInvocation + virtual com::sun::star::uno::Reference< ::com::sun::star::beans::XIntrospectionAccess > + SAL_CALL getIntrospection( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL invoke( + const ::rtl::OUString& aFunctionName, + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aParams, + ::com::sun::star::uno::Sequence< sal_Int16 >& aOutParamIndex, + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aOutParam ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::script::CannotConvertException, + ::com::sun::star::reflection::InvocationTargetException, + ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL setValue( + const ::rtl::OUString& aPropertyName, + const ::com::sun::star::uno::Any& aValue ) + throw (::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::script::CannotConvertException, + ::com::sun::star::reflection::InvocationTargetException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Any SAL_CALL getValue( const ::rtl::OUString& aPropertyName ) + throw (::com::sun::star::beans::UnknownPropertyException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasMethod( const ::rtl::OUString& aName ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasProperty( const ::rtl::OUString& aName ) + throw (::com::sun::star::uno::RuntimeException); + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( + const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) + throw (::com::sun::star::uno::RuntimeException); +}; + + +/** releases a refcount on the interpreter object and on another given python object. + + The function can be called from any thread regardless of whether the global + interpreter lock is held. + + */ +void decreaseRefCount( PyInterpreterState *interpreter, PyObject *object ); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_module.cxx b/pyuno/source/module/pyuno_module.cxx new file mode 100644 index 000000000000..a126152ef8c0 --- /dev/null +++ b/pyuno/source/module/pyuno_module.cxx @@ -0,0 +1,852 @@ +/* -*- Mode: C++; eval:(c-set-style "bsd"); tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "pyuno_impl.hxx" + +#include <boost/unordered_map.hpp> +#include <utility> + +#include <osl/module.hxx> +#include <osl/thread.h> +#include <osl/file.hxx> + +#include <typelib/typedescription.hxx> + +#include <rtl/ustring.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/uuid.h> +#include <rtl/bootstrap.hxx> + +#include <uno/current_context.hxx> +#include <cppuhelper/bootstrap.hxx> + +#include <com/sun/star/reflection/XIdlReflection.hpp> +#include <com/sun/star/reflection/XIdlClass.hpp> +#include <com/sun/star/registry/InvalidRegistryException.hpp> + +using osl::Module; + +using rtl::OString; +using rtl::OUString; +using rtl::OUStringHash; +using rtl::OUStringToOString; +using rtl::OUStringBuffer; +using rtl::OStringBuffer; + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::TypeDescription; +using com::sun::star::uno::XComponentContext; +using com::sun::star::container::NoSuchElementException; +using com::sun::star::reflection::XIdlReflection; +using com::sun::star::reflection::XIdlClass; +using com::sun::star::script::XInvocation2; + +using namespace pyuno; + +namespace { + +/** + @ index of the next to be used member in the initializer list ! + */ +// LEM TODO: export member names as keyword arguments in initialiser? +// Python supports very flexible variadic functions. By marking +// variables with one asterisk (e.g. *var) the given variable is +// defined to be a tuple of all the extra arguments. By marking +// variables with two asterisks (e.g. **var) the given variable is a +// dictionary of all extra keyword arguments; the keys are strings, +// which are the names that were used to identify the arguments. If +// they exist, these arguments must be the last one in the list. + +class fillStructState +{ + typedef boost::unordered_map <const OUString, bool, OUStringHash> initialised_t; + // Keyword arguments used + PyObject *used; + // Which structure members are initialised + boost::unordered_map <const OUString, bool, OUStringHash> initialised; + // How many positional arguments are consumed + // This is always the so-many first ones + sal_Int32 nPosConsumed; + // The total number of members set, either by a keyword argument or a positional argument + unsigned int nMembersSet; + +public: + fillStructState() + : used (PyDict_New()) + , initialised () + , nPosConsumed (0) + , nMembersSet (0) + { + if ( ! used ) + throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("pyuno._createUnoStructHelper failed to create new dictionary")), Reference< XInterface > ()); + } + ~fillStructState() + { + Py_DECREF(used); + } + void setUsed(PyObject *key) + { + PyDict_SetItem(used, key, Py_True); + } + bool isUsed(PyObject *key) const + { + return Py_True == PyDict_GetItem(used, key); + } + void setInitialised(OUString key, sal_Int32 pos = -1) + { + if (initialised[key]) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno._createUnoStructHelper: member '"); + buf.append(key); + buf.appendAscii( "'"); + if ( pos >= 0 ) + { + buf.appendAscii( " at position "); + buf.append(pos); + } + buf.appendAscii( " initialised multiple times."); + throw RuntimeException(buf.makeStringAndClear(), Reference< XInterface > ()); + } + initialised[key] = true; + ++nMembersSet; + if ( pos >= 0 ) + ++nPosConsumed; + } + bool isInitialised(OUString key) + { + return initialised[key]; + } + PyObject *getUsed() const + { + return used; + } + sal_Int32 getCntConsumed() const + { + return nPosConsumed; + } + int getCntMembersSet() const + { + return nMembersSet; + } +}; + +static void fillStruct( + const Reference< XInvocation2 > &inv, + typelib_CompoundTypeDescription *pCompType, + PyObject *initializer, + PyObject *kwinitializer, + fillStructState &state, + const Runtime &runtime) throw ( RuntimeException ) +{ + if( pCompType->pBaseTypeDescription ) + fillStruct( inv, pCompType->pBaseTypeDescription, initializer, kwinitializer, state, runtime ); + + const sal_Int32 nMembers = pCompType->nMembers; + { + for( int i = 0 ; i < nMembers ; i ++ ) + { + const OUString OUMemberName (pCompType->ppMemberNames[i]); + PyObject *pyMemberName = PyString_FromString(::rtl::OUStringToOString( OUMemberName, RTL_TEXTENCODING_UTF8 ).getStr()); + if ( PyObject *element = PyDict_GetItem(kwinitializer, pyMemberName ) ) + { + state.setInitialised(OUMemberName); + state.setUsed(pyMemberName); + Any a = runtime.pyObject2Any( element, ACCEPT_UNO_ANY ); + inv->setValue( OUMemberName, a ); + } + } + } + { + const int remainingPosInitialisers = PyTuple_Size(initializer) - state.getCntConsumed(); + for( int i = 0 ; i < remainingPosInitialisers && i < nMembers ; i ++ ) + { + const int tupleIndex = state.getCntConsumed(); + const OUString pMemberName (pCompType->ppMemberNames[i]); + state.setInitialised(pMemberName, tupleIndex); + PyObject *element = PyTuple_GetItem( initializer, tupleIndex ); + Any a = runtime.pyObject2Any( element, ACCEPT_UNO_ANY ); + inv->setValue( pMemberName, a ); + } + } + for ( int i = 0; i < nMembers ; ++i) + { + const OUString memberName (pCompType->ppMemberNames[i]); + if ( ! state.isInitialised( memberName ) ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno._createUnoStructHelper: member '"); + buf.append(memberName); + buf.appendAscii( "' of struct type '"); + buf.append(pCompType->aBase.pTypeName); + buf.appendAscii( "' not given a value."); + throw RuntimeException(buf.makeStringAndClear(), Reference< XInterface > ()); + } + } +} + +OUString getLibDir() +{ + static OUString *pLibDir; + if( !pLibDir ) + { + osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); + if( ! pLibDir ) + { + static OUString libDir; + + // workarounds the $(ORIGIN) until it is available + if( Module::getUrlFromAddress( + reinterpret_cast< oslGenericFunction >(getLibDir), libDir ) ) + { + libDir = OUString( libDir.getStr(), libDir.lastIndexOf('/' ) ); + OUString name ( RTL_CONSTASCII_USTRINGPARAM( "PYUNOLIBDIR" ) ); + rtl_bootstrap_set( name.pData, libDir.pData ); + } + pLibDir = &libDir; + } + } + return *pLibDir; +} + +void raisePySystemException( const char * exceptionType, const OUString & message ) +{ + OStringBuffer buf; + buf.append( "Error during bootstrapping uno ("); + buf.append( exceptionType ); + buf.append( "):" ); + buf.append( OUStringToOString( message, osl_getThreadTextEncoding() ) ); + PyErr_SetString( PyExc_SystemError, buf.makeStringAndClear().getStr() ); +} + +extern "C" { + +static PyObject* getComponentContext (PyObject*, PyObject*) +{ + PyRef ret; + try + { + Reference<XComponentContext> ctx; + + // getLibDir() must be called in order to set bootstrap variables correctly ! + OUString path( getLibDir()); + if( Runtime::isInitialized() ) + { + Runtime runtime; + ctx = runtime.getImpl()->cargo->xContext; + } + else + { + OUString iniFile; + if( !path.getLength() ) + { + PyErr_SetString( + PyExc_RuntimeError, "osl_getUrlFromAddress fails, that's why I cannot find ini " + "file for bootstrapping python uno bridge\n" ); + return NULL; + } + + OUStringBuffer iniFileName; + iniFileName.append( path ); + iniFileName.appendAscii( "/" ); + iniFileName.appendAscii( SAL_CONFIGFILE( "pyuno" ) ); + iniFile = iniFileName.makeStringAndClear(); + osl::DirectoryItem item; + if( osl::DirectoryItem::get( iniFile, item ) == item.E_None ) + { + // in case pyuno.ini exists, use this file for bootstrapping + PyThreadDetach antiguard; + ctx = cppu::defaultBootstrap_InitialComponentContext (iniFile); + } + else + { + // defaulting to the standard bootstrapping + PyThreadDetach antiguard; + ctx = cppu::defaultBootstrap_InitialComponentContext (); + } + + } + + if( ! Runtime::isInitialized() ) + { + Runtime::initialize( ctx ); + } + Runtime runtime; + ret = runtime.any2PyObject( makeAny( ctx ) ); + } + catch (com::sun::star::registry::InvalidRegistryException &e) + { + // can't use raisePyExceptionWithAny() here, because the function + // does any conversions, which will not work with a + // wrongly bootstrapped pyuno! + raisePySystemException( "InvalidRegistryException", e.Message ); + } + catch( com::sun::star::lang::IllegalArgumentException & e) + { + raisePySystemException( "IllegalArgumentException", e.Message ); + } + catch( com::sun::star::script::CannotConvertException & e) + { + raisePySystemException( "CannotConvertException", e.Message ); + } + catch (com::sun::star::uno::RuntimeException & e) + { + raisePySystemException( "RuntimeException", e.Message ); + } + catch (com::sun::star::uno::Exception & e) + { + raisePySystemException( "uno::Exception", e.Message ); + } + return ret.getAcquired(); +} + +PyObject * extractOneStringArg( PyObject *args, char const *funcName ) +{ + if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 ) + { + OStringBuffer buf; + buf.append( funcName ).append( ": expecting one string argument" ); + PyErr_SetString( PyExc_RuntimeError, buf.getStr() ); + return NULL; + } + PyObject *obj = PyTuple_GetItem( args, 0 ); + if(!PyString_Check(obj) && !PyUnicode_Check(obj)) + { + OStringBuffer buf; + buf.append( funcName ).append( ": expecting one string argument" ); + PyErr_SetString( PyExc_TypeError, buf.getStr()); + return NULL; + } + return obj; +} + +static PyObject *createUnoStructHelper(PyObject *, PyObject* args, PyObject* keywordArgs) +{ + Any IdlStruct; + PyRef ret; + try + { + Runtime runtime; + if( PyTuple_Size( args ) == 2 ) + { + PyObject *structName = PyTuple_GetItem(args, 0); + PyObject *initializer = PyTuple_GetItem(args, 1); + + // Perhaps in Python 3, only PyUnicode_Check returns true and + // in Python 2, only PyString_Check returns true. + if(PyString_Check(structName) || PyUnicode_Check(structName)) + { + if( PyTuple_Check( initializer ) && PyDict_Check ( keywordArgs ) ) + { + OUString typeName( OUString::createFromAscii(PyString_AsString(structName))); + RuntimeCargo *c = runtime.getImpl()->cargo; + Reference<XIdlClass> idl_class ( c->xCoreReflection->forName (typeName),UNO_QUERY); + if (idl_class.is ()) + { + idl_class->createObject (IdlStruct); + PyUNO *me = (PyUNO*)PyUNO_new_UNCHECKED( IdlStruct, c->xInvocation ); + PyRef returnCandidate( (PyObject*)me, SAL_NO_ACQUIRE ); + TypeDescription desc( typeName ); + OSL_ASSERT( desc.is() ); // could already instantiate an XInvocation2 ! + + typelib_CompoundTypeDescription *pCompType = + ( typelib_CompoundTypeDescription * ) desc.get(); + fillStructState state; + if ( PyTuple_Size( initializer ) > 0 || PyDict_Size( keywordArgs ) > 0 ) + fillStruct( me->members->xInvocation, pCompType, initializer, keywordArgs, state, runtime ); + if( state.getCntConsumed() != PyTuple_Size(initializer) ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno._createUnoStructHelper: too many "); + buf.appendAscii( "elements in the initializer list, expected " ); + buf.append( state.getCntConsumed() ); + buf.appendAscii( ", got " ); + buf.append( (sal_Int32) PyTuple_Size(initializer) ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > ()); + } + ret = PyRef( PyTuple_Pack(2, returnCandidate.get(), state.getUsed()), SAL_NO_ACQUIRE); + } + else + { + OStringBuffer buf; + buf.append( "UNO struct " ); + buf.append( PyString_AsString(structName) ); + buf.append( " is unkown" ); + PyErr_SetString (PyExc_RuntimeError, buf.getStr()); + } + } + else + { + PyErr_SetString( + PyExc_RuntimeError, + "pyuno._createUnoStructHelper: 2nd argument (initializer sequence) is no tuple" ); + } + } + else + { + PyErr_SetString (PyExc_AttributeError, "createUnoStruct: first argument wasn't a string"); + } + } + else + { + PyErr_SetString (PyExc_AttributeError, "pyuno._createUnoStructHelper: expects exactly two non-keyword arguments:\n\tStructure Name\n\tinitialiser tuple; may be the empty tuple"); + } + } + catch( com::sun::star::uno::RuntimeException & e ) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + catch( com::sun::star::script::CannotConvertException & e ) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + catch( com::sun::star::uno::Exception & e ) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + return ret.getAcquired(); +} + +static PyObject *getTypeByName( PyObject *, PyObject *args ) +{ + PyObject * ret = NULL; + + try + { + char *name; + + if (PyArg_ParseTuple (args, "s", &name)) + { + OUString typeName ( OUString::createFromAscii( name ) ); + TypeDescription typeDesc( typeName ); + if( typeDesc.is() ) + { + Runtime runtime; + ret = PyUNO_Type_new( + name, (com::sun::star::uno::TypeClass)typeDesc.get()->eTypeClass, runtime ); + } + else + { + OStringBuffer buf; + buf.append( "Type " ).append(name).append( " is unknown" ); + PyErr_SetString( PyExc_RuntimeError, buf.getStr() ); + } + } + } + catch ( RuntimeException & e ) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + return ret; +} + +static PyObject *getConstantByName( PyObject *, PyObject *args ) +{ + PyObject *ret = 0; + try + { + char *name; + + if (PyArg_ParseTuple (args, "s", &name)) + { + OUString typeName ( OUString::createFromAscii( name ) ); + Runtime runtime; + Any a = runtime.getImpl()->cargo->xTdMgr->getByHierarchicalName(typeName); + if( a.getValueType().getTypeClass() == + com::sun::star::uno::TypeClass_INTERFACE ) + { + // a idl constant cannot be an instance of an uno-object, thus + // this cannot be a constant + OUStringBuffer buf; + buf.appendAscii( "pyuno.getConstantByName: " ).append( typeName ); + buf.appendAscii( "is not a constant" ); + throw RuntimeException(buf.makeStringAndClear(), Reference< XInterface > () ); + } + PyRef constant = runtime.any2PyObject( a ); + ret = constant.getAcquired(); + } + } + catch( NoSuchElementException & e ) + { + // to the python programmer, this is a runtime exception, + // do not support tweakings with the type system + RuntimeException runExc( e.Message, Reference< XInterface > () ); + raisePyExceptionWithAny( makeAny( runExc ) ); + } + catch( com::sun::star::script::CannotConvertException & e) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + catch( com::sun::star::lang::IllegalArgumentException & e) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + catch( RuntimeException & e ) + { + raisePyExceptionWithAny( makeAny(e) ); + } + return ret; +} + +static PyObject *checkType( PyObject *, PyObject *args ) +{ + if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 ) + { + OStringBuffer buf; + buf.append( "pyuno.checkType : expecting one uno.Type argument" ); + PyErr_SetString( PyExc_RuntimeError, buf.getStr() ); + return NULL; + } + PyObject *obj = PyTuple_GetItem( args, 0 ); + + try + { + PyType2Type( obj ); + } + catch( RuntimeException & e) + { + raisePyExceptionWithAny( makeAny( e ) ); + return NULL; + } + Py_INCREF( Py_None ); + return Py_None; +} + +static PyObject *checkEnum( PyObject *, PyObject *args ) +{ + if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 ) + { + OStringBuffer buf; + buf.append( "pyuno.checkType : expecting one uno.Type argument" ); + PyErr_SetString( PyExc_RuntimeError, buf.getStr() ); + return NULL; + } + PyObject *obj = PyTuple_GetItem( args, 0 ); + + try + { + PyEnum2Enum( obj ); + } + catch( RuntimeException & e) + { + raisePyExceptionWithAny( makeAny( e) ); + return NULL; + } + Py_INCREF( Py_None ); + return Py_None; +} + +static PyObject *getClass( PyObject *, PyObject *args ) +{ + PyObject *obj = extractOneStringArg( args, "pyuno.getClass"); + if( ! obj ) + return NULL; + + try + { + Runtime runtime; + PyRef ret = getClass( + OUString( PyString_AsString( obj), strlen(PyString_AsString(obj)),RTL_TEXTENCODING_ASCII_US), + runtime ); + Py_XINCREF( ret.get() ); + return ret.get(); + } + catch( RuntimeException & e) + { + // NOOPT !!! + // gcc 3.2.3 crashes here in the regcomp test scenario + // only since migration to python 2.3.4 ???? strange thing + // optimization switched off for this module ! + raisePyExceptionWithAny( makeAny(e) ); + } + return NULL; +} + +static PyObject *isInterface( PyObject *, PyObject *args ) +{ + + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + { + PyObject *obj = PyTuple_GetItem( args, 0 ); + Runtime r; + return PyLong_FromLong( isInterfaceClass( r, obj ) ); + } + return PyLong_FromLong( 0 ); +} + +static PyObject * generateUuid( PyObject *, PyObject * ) +{ + Sequence< sal_Int8 > seq( 16 ); + rtl_createUuid( (sal_uInt8*)seq.getArray() , 0 , sal_False ); + PyRef ret; + try + { + Runtime runtime; + ret = runtime.any2PyObject( makeAny( seq ) ); + } + catch( RuntimeException & e ) + { + raisePyExceptionWithAny( makeAny(e) ); + } + return ret.getAcquired(); +} + +static PyObject *systemPathToFileUrl( PyObject *, PyObject * args ) +{ + PyObject *obj = extractOneStringArg( args, "pyuno.systemPathToFileUrl" ); + if( ! obj ) + return NULL; + + OUString sysPath = pyString2ustring( obj ); + OUString url; + osl::FileBase::RC e = osl::FileBase::getFileURLFromSystemPath( sysPath, url ); + + if( e != osl::FileBase::E_None ) + { + OUStringBuffer buf; + buf.appendAscii( "Couldn't convert " ); + buf.append( sysPath ); + buf.appendAscii( " to a file url for reason (" ); + buf.append( (sal_Int32) e ); + buf.appendAscii( ")" ); + raisePyExceptionWithAny( + makeAny( RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () ))); + return NULL; + } + return ustring2PyUnicode( url ).getAcquired(); +} + +static PyObject * fileUrlToSystemPath( PyObject *, PyObject * args ) +{ + PyObject *obj = extractOneStringArg( args, "pyuno.fileUrlToSystemPath" ); + if( ! obj ) + return NULL; + + OUString url = pyString2ustring( obj ); + OUString sysPath; + osl::FileBase::RC e = osl::FileBase::getSystemPathFromFileURL( url, sysPath ); + + if( e != osl::FileBase::E_None ) + { + OUStringBuffer buf; + buf.appendAscii( "Couldn't convert file url " ); + buf.append( sysPath ); + buf.appendAscii( " to a system path for reason (" ); + buf.append( (sal_Int32) e ); + buf.appendAscii( ")" ); + raisePyExceptionWithAny( + makeAny( RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () ))); + return NULL; + } + return ustring2PyUnicode( sysPath ).getAcquired(); +} + +static PyObject * absolutize( PyObject *, PyObject * args ) +{ + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 2 ) + { + OUString ouPath = pyString2ustring( PyTuple_GetItem( args , 0 ) ); + OUString ouRel = pyString2ustring( PyTuple_GetItem( args, 1 ) ); + OUString ret; + oslFileError e = osl_getAbsoluteFileURL( ouPath.pData, ouRel.pData, &(ret.pData) ); + if( e != osl_File_E_None ) + { + OUStringBuffer buf; + buf.appendAscii( "Couldn't absolutize " ); + buf.append( ouRel ); + buf.appendAscii( " using root " ); + buf.append( ouPath ); + buf.appendAscii( " for reason (" ); + buf.append( (sal_Int32) e ); + buf.appendAscii( ")" ); + + PyErr_SetString( + PyExc_OSError, + OUStringToOString(buf.makeStringAndClear(),osl_getThreadTextEncoding())); + return 0; + } + return ustring2PyUnicode( ret ).getAcquired(); + } + return 0; +} + +static PyObject * invoke(PyObject *, PyObject *args) +{ + PyObject *ret = 0; + if(PyTuple_Check(args) && PyTuple_Size(args) == 3) + { + PyObject *object = PyTuple_GetItem(args, 0); + PyObject *item1 = PyTuple_GetItem(args, 1); + if(PyString_Check(item1) || PyUnicode_Check(item1)) + { + const char *name = PyString_AsString(item1); + PyObject *item2 = PyTuple_GetItem(args, 2); + if(PyTuple_Check(item2)) + { + ret = PyUNO_invoke(object, name, item2); + } + else + { + OStringBuffer buf; + buf.append("uno.invoke expects a tuple as 3rd argument, got "); + buf.append(PyString_AsString(PyObject_Str(item2))); + PyErr_SetString(PyExc_RuntimeError, buf.makeStringAndClear()); + } + } + else + { + OStringBuffer buf; + buf.append("uno.invoke expected a string as 2nd argument, got "); + buf.append(PyString_AsString(PyObject_Str(item1))); + PyErr_SetString(PyExc_RuntimeError, buf.makeStringAndClear()); + } + } + else + { + OStringBuffer buf; + buf.append("uno.invoke expects object, name, (arg1, arg2, ... )\n"); + PyErr_SetString(PyExc_RuntimeError, buf.makeStringAndClear()); + } + return ret; +} + +static PyObject *getCurrentContext( PyObject *, PyObject * ) +{ + PyRef ret; + try + { + Runtime runtime; + ret = runtime.any2PyObject( + makeAny( com::sun::star::uno::getCurrentContext() ) ); + } + catch( com::sun::star::uno::Exception & e ) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + return ret.getAcquired(); +} + +static PyObject *setCurrentContext( PyObject *, PyObject * args ) +{ + PyRef ret; + try + { + if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 ) + { + + Runtime runtime; + Any a = runtime.pyObject2Any( PyTuple_GetItem( args, 0 ) ); + + Reference< com::sun::star::uno::XCurrentContext > context; + + if( (a.hasValue() && (a >>= context)) || ! a.hasValue() ) + { + ret = com::sun::star::uno::setCurrentContext( context ) ? Py_True : Py_False; + } + else + { + OStringBuffer buf; + buf.append( "uno.setCurrentContext expects an XComponentContext implementation, got " ); + buf.append( PyString_AsString( PyObject_Str( PyTuple_GetItem( args, 0) ) ) ); + PyErr_SetString( PyExc_RuntimeError, buf.makeStringAndClear() ); + } + } + else + { + OStringBuffer buf; + buf.append( "uno.setCurrentContext expects exactly one argument (the current Context)\n" ); + PyErr_SetString( PyExc_RuntimeError, buf.makeStringAndClear() ); + } + } + catch( com::sun::star::uno::Exception & e ) + { + raisePyExceptionWithAny( makeAny( e ) ); + } + return ret.getAcquired(); +} + +} + +struct PyMethodDef PyUNOModule_methods [] = +{ + {"getComponentContext", getComponentContext, METH_VARARGS, NULL}, + {"_createUnoStructHelper", reinterpret_cast<PyCFunction>(createUnoStructHelper), METH_VARARGS | METH_KEYWORDS, NULL}, + {"getTypeByName", getTypeByName, METH_VARARGS, NULL}, + {"getConstantByName", getConstantByName, METH_VARARGS, NULL}, + {"getClass", getClass, METH_VARARGS, NULL}, + {"checkEnum", checkEnum, METH_VARARGS, NULL}, + {"checkType", checkType, METH_VARARGS, NULL}, + {"generateUuid", generateUuid, METH_VARARGS, NULL}, + {"systemPathToFileUrl", systemPathToFileUrl, METH_VARARGS, NULL}, + {"fileUrlToSystemPath", fileUrlToSystemPath, METH_VARARGS, NULL}, + {"absolutize", absolutize, METH_VARARGS | METH_KEYWORDS, NULL}, + {"isInterface", isInterface, METH_VARARGS, NULL}, + {"invoke", invoke, METH_VARARGS | METH_KEYWORDS, NULL}, + {"setCurrentContext", setCurrentContext, METH_VARARGS, NULL}, + {"getCurrentContext", getCurrentContext, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +} + +extern "C" PY_DLLEXPORT +#if PY_MAJOR_VERSION >= 3 +PyObject* PyInit_pyuno() +{ + // noop when called already, otherwise needed to allow multiple threads + PyEval_InitThreads(); + static struct PyModuleDef moduledef = + { + PyModuleDef_HEAD_INIT, + "pyuno", // module name + 0, // module documentation + -1, // module keeps state in global variables, + PyUNOModule_methods, // modules methods + 0, // m_reload (must be 0) + 0, // m_traverse + 0, // m_clear + 0, // m_free + }; + return PyModule_Create(&moduledef); +} +#else +void initpyuno() +{ + PyEval_InitThreads(); + Py_InitModule ("pyuno", PyUNOModule_methods); +} +#endif /* PY_MAJOR_VERSION >= 3 */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_runtime.cxx b/pyuno/source/module/pyuno_runtime.cxx new file mode 100644 index 000000000000..c09cc5c17b0f --- /dev/null +++ b/pyuno/source/module/pyuno_runtime.cxx @@ -0,0 +1,1103 @@ +/* -*- Mode: C++; eval:(c-set-style "bsd"); tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "pyuno_impl.hxx" + +#include <osl/thread.h> +#include <osl/module.h> +#include <osl/process.h> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/bootstrap.hxx> +#include <locale.h> + +#include <typelib/typedescription.hxx> + +#include <com/sun/star/beans/XMaterialHolder.hpp> + +using rtl::OUString; +using rtl::OUStringToOString; +using rtl::OUStringBuffer; +using rtl::OStringBuffer; +using rtl::OString; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Any; +using com::sun::star::uno::TypeDescription; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Type; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Exception; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::XComponentContext; +using com::sun::star::lang::XSingleServiceFactory; +using com::sun::star::lang::XUnoTunnel; +using com::sun::star::reflection::XIdlReflection; +using com::sun::star::script::XTypeConverter; +using com::sun::star::script::XInvocationAdapterFactory2; +using com::sun::star::script::XInvocation; +using com::sun::star::beans::XMaterialHolder; +using com::sun::star::beans::XIntrospection; + +#include <vector> + +namespace pyuno +{ +#define USTR_ASCII(x) OUString( RTL_CONSTASCII_USTRINGPARAM( x ) ) + +static PyTypeObject RuntimeImpl_Type = +{ + PyVarObject_HEAD_INIT (&PyType_Type, 0) + "pyuno_runtime", + sizeof (RuntimeImpl), + 0, + (destructor) RuntimeImpl::del, + (printfunc) 0, + (getattrfunc) 0, + (setattrfunc) 0, + 0, + (reprfunc) 0, + 0, + 0, + 0, + (hashfunc) 0, + (ternaryfunc) 0, + (reprfunc) 0, + (getattrofunc)0, + (setattrofunc)0, + NULL, + 0, + NULL, + (traverseproc)0, + (inquiry)0, + (richcmpfunc)0, + 0, + (getiterfunc)0, + (iternextfunc)0, + NULL, + NULL, + NULL, + NULL, + NULL, + (descrgetfunc)0, + (descrsetfunc)0, + 0, + (initproc)0, + (allocfunc)0, + (newfunc)0, + (freefunc)0, + (inquiry)0, + NULL, + NULL, + NULL, + NULL, + NULL, + (destructor)0 +#if PY_VERSION_HEX >= 0x02060000 + , 0 +#endif +}; + +/*---------------------------------------------------------------------- + Runtime implementation + -----------------------------------------------------------------------*/ +static void getRuntimeImpl( PyRef & globalDict, PyRef &runtimeImpl ) + throw ( com::sun::star::uno::RuntimeException ) +{ + PyThreadState * state = PyThreadState_Get(); + if( ! state ) + { + throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM( + "python global interpreter must be held (thread must be attached)" )), + Reference< XInterface > () ); + } + + globalDict = PyRef( PyModule_GetDict(PyImport_AddModule("__main__"))); + + if( ! globalDict.is() ) // FATAL ! + { + throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM( + "can't find __main__ module" )), Reference< XInterface > ()); + } + runtimeImpl = PyDict_GetItemString( globalDict.get() , "pyuno_runtime" ); +} + +static PyRef importUnoModule( ) throw ( RuntimeException ) +{ + // import the uno module + PyRef module( PyImport_ImportModule( "uno" ), SAL_NO_ACQUIRE ); + if( PyErr_Occurred() ) + { + PyRef excType, excValue, excTraceback; + PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback); + // As of Python 2.7 this gives a rather non-useful "<traceback object at 0xADDRESS>", + // but it is the best we can do in the absence of uno._uno_extract_printable_stacktrace + // Who knows, a future Python might print something better. + PyRef str( PyObject_Str( excTraceback.get() ), SAL_NO_ACQUIRE ); + + OUStringBuffer buf; + buf.appendAscii( "python object raised an unknown exception (" ); + PyRef valueRep( PyObject_Repr( excValue.get() ), SAL_NO_ACQUIRE ); + buf.appendAscii( PyString_AsString( valueRep.get())).appendAscii( ", traceback follows\n" ); + buf.appendAscii( PyString_AsString( str.get() ) ); + buf.appendAscii( ")" ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + PyRef dict( PyModule_GetDict( module.get() ) ); + return dict; +} + +static void readLoggingConfig( sal_Int32 *pLevel, FILE **ppFile ) +{ + *pLevel = LogLevel::NONE; + *ppFile = 0; + OUString fileName; + osl_getModuleURLFromFunctionAddress( + reinterpret_cast< oslGenericFunction >(readLoggingConfig), + (rtl_uString **) &fileName ); + fileName = OUString( fileName.getStr(), fileName.lastIndexOf( '/' )+1 ); + fileName += OUString(RTL_CONSTASCII_USTRINGPARAM( SAL_CONFIGFILE("pyuno") )); + rtl::Bootstrap bootstrapHandle( fileName ); + + OUString str; + if( bootstrapHandle.getFrom( USTR_ASCII( "PYUNO_LOGLEVEL" ), str ) ) + { + if( str.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "NONE" ) ) ) + *pLevel = LogLevel::NONE; + else if( str.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CALL" ) ) ) + *pLevel = LogLevel::CALL; + else if( str.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ARGS" ) ) ) + *pLevel = LogLevel::ARGS; + else + { + fprintf( stderr, "unknown loglevel %s\n", + OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + if( *pLevel > LogLevel::NONE ) + { + *ppFile = stdout; + if( bootstrapHandle.getFrom( USTR_ASCII( "PYUNO_LOGTARGET" ), str ) ) + { + if( str.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "stdout" ) ) ) + *ppFile = stdout; + else if( str.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "stderr" ) ) ) + *ppFile = stderr; + else + { + oslProcessInfo data; + data.Size = sizeof( data ); + osl_getProcessInfo( + 0 , osl_Process_IDENTIFIER , &data ); + osl_getSystemPathFromFileURL( str.pData, &str.pData); + OString o = OUStringToOString( str, osl_getThreadTextEncoding() ); + o += "."; + o += OString::valueOf( (sal_Int32)data.Ident ); + + *ppFile = fopen( o.getStr() , "w" ); + if ( *ppFile ) + { + // do not buffer (useful if e.g. analyzing a crash) + setvbuf( *ppFile, 0, _IONBF, 0 ); + } + else + { + fprintf( stderr, "couldn't create file %s\n", + OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() ); + + } + } + } + } +} + +/*------------------------------------------------------------------- + RuntimeImpl implementations + *-------------------------------------------------------------------*/ +PyRef stRuntimeImpl::create( const Reference< XComponentContext > &ctx ) + throw( com::sun::star::uno::RuntimeException ) +{ + RuntimeImpl *me = PyObject_New (RuntimeImpl, &RuntimeImpl_Type); + if( ! me ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "cannot instantiate pyuno::RuntimeImpl" ) ), + Reference< XInterface > () ); + me->cargo = 0; + // must use a different struct here, as the PyObject_New + // makes C++ unusable + RuntimeCargo *c = new RuntimeCargo(); + readLoggingConfig( &(c->logLevel) , &(c->logFile) ); + log( c, LogLevel::CALL, "Instantiating pyuno bridge" ); + + c->valid = 1; + c->xContext = ctx; + c->xInvocation = Reference< XSingleServiceFactory > ( + ctx->getServiceManager()->createInstanceWithContext( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.script.Invocation" ) ), + ctx ), + UNO_QUERY ); + if( ! c->xInvocation.is() ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate invocation service" ) ), + Reference< XInterface > () ); + + c->xTypeConverter = Reference< XTypeConverter > ( + ctx->getServiceManager()->createInstanceWithContext( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.script.Converter" ) ), + ctx ), + UNO_QUERY ); + if( ! c->xTypeConverter.is() ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate typeconverter service" )), + Reference< XInterface > () ); + + c->xCoreReflection = Reference< XIdlReflection > ( + ctx->getServiceManager()->createInstanceWithContext( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.reflection.CoreReflection" ) ), + ctx ), + UNO_QUERY ); + if( ! c->xCoreReflection.is() ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate corereflection service" )), + Reference< XInterface > () ); + + c->xAdapterFactory = Reference< XInvocationAdapterFactory2 > ( + ctx->getServiceManager()->createInstanceWithContext( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.script.InvocationAdapterFactory" ) ), + ctx ), + UNO_QUERY ); + if( ! c->xAdapterFactory.is() ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate invocation adapter factory service" )), + Reference< XInterface > () ); + + c->xIntrospection = Reference< XIntrospection > ( + ctx->getServiceManager()->createInstanceWithContext( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.Introspection" ) ), + ctx ), + UNO_QUERY ); + if( ! c->xIntrospection.is() ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate introspection service" )), + Reference< XInterface > () ); + + Any a = ctx->getValueByName(OUString( + RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.reflection.theTypeDescriptionManager" )) ); + a >>= c->xTdMgr; + if( ! c->xTdMgr.is() ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't retrieve typedescriptionmanager" )), + Reference< XInterface > () ); + + me->cargo =c; + return PyRef( reinterpret_cast< PyObject * > ( me ), SAL_NO_ACQUIRE ); +} + +void stRuntimeImpl::del(PyObject* self) +{ + RuntimeImpl *me = reinterpret_cast< RuntimeImpl * > ( self ); + if( me->cargo->logFile ) + fclose( me->cargo->logFile ); + delete me->cargo; + PyObject_Del (self); +} + + +void Runtime::initialize( const Reference< XComponentContext > & ctx ) + throw ( RuntimeException ) +{ + PyRef globalDict, runtime; + getRuntimeImpl( globalDict , runtime ); + RuntimeImpl *impl = reinterpret_cast< RuntimeImpl * > (runtime.get()); + + if( runtime.is() && impl->cargo->valid ) + { + throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM( + "pyuno runtime has already been initialized before" ) ), + Reference< XInterface > () ); + } + PyRef keep( RuntimeImpl::create( ctx ) ); + PyDict_SetItemString( globalDict.get(), "pyuno_runtime" , keep.get() ); + Py_XINCREF( keep.get() ); +} + + +bool Runtime::isInitialized() throw ( RuntimeException ) +{ + PyRef globalDict, runtime; + getRuntimeImpl( globalDict , runtime ); + RuntimeImpl *impl = reinterpret_cast< RuntimeImpl * > (runtime.get()); + return runtime.is() && impl->cargo->valid; +} + +void Runtime::finalize() throw (RuntimeException) +{ + PyRef globalDict, runtime; + getRuntimeImpl( globalDict , runtime ); + RuntimeImpl *impl = reinterpret_cast< RuntimeImpl * > (runtime.get()); + if( !runtime.is() || ! impl->cargo->valid ) + { + throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM( + "pyuno bridge must have been initialized before finalizing" )), + Reference< XInterface > () ); + } + impl->cargo->valid = false; + impl->cargo->xInvocation.clear(); + impl->cargo->xContext.clear(); + impl->cargo->xTypeConverter.clear(); +} + +Runtime::Runtime() throw( RuntimeException ) + : impl( 0 ) +{ + PyRef globalDict, runtime; + getRuntimeImpl( globalDict , runtime ); + if( ! runtime.is() ) + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM("pyuno runtime is not initialized, " + "(the pyuno.bootstrap needs to be called before using any uno classes)")), + Reference< XInterface > () ); + } + impl = reinterpret_cast< RuntimeImpl * > (runtime.get()); + Py_XINCREF( runtime.get() ); +} + +Runtime::Runtime( const Runtime & r ) +{ + impl = r.impl; + Py_XINCREF( reinterpret_cast< PyObject * >(impl) ); +} + +Runtime::~Runtime() +{ + Py_XDECREF( reinterpret_cast< PyObject * >(impl) ); +} + +Runtime & Runtime::operator = ( const Runtime & r ) +{ + PyRef temp( reinterpret_cast< PyObject * >(r.impl) ); + Py_XINCREF( temp.get() ); + Py_XDECREF( reinterpret_cast< PyObject * >(impl) ); + impl = r.impl; + return *this; +} + +PyRef Runtime::any2PyObject (const Any &a ) const + throw ( com::sun::star::script::CannotConvertException, + com::sun::star::lang::IllegalArgumentException, + RuntimeException) +{ + if( ! impl->cargo->valid ) + { + throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM( + "pyuno runtime must be initialized before calling any2PyObject" )), + Reference< XInterface > () ); + } + + switch (a.getValueTypeClass ()) + { + case typelib_TypeClass_VOID: + { + Py_INCREF (Py_None); + return PyRef(Py_None); + } + case typelib_TypeClass_CHAR: + { + sal_Unicode c = *(sal_Unicode*)a.getValue(); + return PyRef( PyUNO_char_new( c , *this ), SAL_NO_ACQUIRE ); + } + case typelib_TypeClass_BOOLEAN: + { + sal_Bool b = sal_Bool(); + if ((a >>= b) && b) + return Py_True; + else + return Py_False; + } + case typelib_TypeClass_BYTE: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_LONG: + { + sal_Int32 l = 0; + a >>= l; + return PyRef( PyLong_FromLong (l), SAL_NO_ACQUIRE ); + } + case typelib_TypeClass_UNSIGNED_LONG: + { + sal_uInt32 l = 0; + a >>= l; + return PyRef( PyLong_FromUnsignedLong (l), SAL_NO_ACQUIRE ); + } + case typelib_TypeClass_HYPER: + { + sal_Int64 l = 0; + a >>= l; + return PyRef( PyLong_FromLongLong (l), SAL_NO_ACQUIRE); + } + case typelib_TypeClass_UNSIGNED_HYPER: + { + sal_uInt64 l = 0; + a >>= l; + return PyRef( PyLong_FromUnsignedLongLong (l), SAL_NO_ACQUIRE); + } + case typelib_TypeClass_FLOAT: + { + float f = 0.0; + a >>= f; + return PyRef(PyFloat_FromDouble (f), SAL_NO_ACQUIRE); + } + case typelib_TypeClass_DOUBLE: + { + double d = 0.0; + a >>= d; + return PyRef( PyFloat_FromDouble (d), SAL_NO_ACQUIRE); + } + case typelib_TypeClass_STRING: + { + OUString tmp_ostr; + a >>= tmp_ostr; + return ustring2PyUnicode( tmp_ostr ); + } + case typelib_TypeClass_TYPE: + { + Type t; + a >>= t; + OString o = OUStringToOString( t.getTypeName(), RTL_TEXTENCODING_ASCII_US ); + return PyRef( + PyUNO_Type_new ( + o.getStr(), (com::sun::star::uno::TypeClass)t.getTypeClass(), *this), + SAL_NO_ACQUIRE); + } + case typelib_TypeClass_ANY: + { + //I don't think this can happen. + Py_INCREF (Py_None); + return Py_None; + } + case typelib_TypeClass_ENUM: + { + sal_Int32 l = *(sal_Int32 *) a.getValue(); + TypeDescription desc( a.getValueType() ); + if( desc.is() ) + { + desc.makeComplete(); + typelib_EnumTypeDescription *pEnumDesc = + (typelib_EnumTypeDescription *) desc.get(); + for( int i = 0 ; i < pEnumDesc->nEnumValues ; i ++ ) + { + if( pEnumDesc->pEnumValues[i] == l ) + { + OString v = OUStringToOString( pEnumDesc->ppEnumNames[i], RTL_TEXTENCODING_ASCII_US); + OString e = OUStringToOString( pEnumDesc->aBase.pTypeName, RTL_TEXTENCODING_ASCII_US); + return PyRef( PyUNO_Enum_new(e.getStr(),v.getStr(), *this ), SAL_NO_ACQUIRE ); + } + } + } + OUStringBuffer buf; + buf.appendAscii( "Any carries enum " ); + buf.append( a.getValueType().getTypeName()); + buf.appendAscii( " with invalid value " ).append( l ); + throw RuntimeException( buf.makeStringAndClear() , Reference< XInterface > () ); + } + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_STRUCT: + { + PyRef excClass = getClass( a.getValueType().getTypeName(), *this ); + PyRef value = PyRef( PyUNO_new_UNCHECKED (a, getImpl()->cargo->xInvocation), SAL_NO_ACQUIRE); + PyRef argsTuple( PyTuple_New( 1 ) , SAL_NO_ACQUIRE ); + PyTuple_SetItem( argsTuple.get() , 0 , value.getAcquired() ); + PyRef ret( PyObject_CallObject( excClass.get() , argsTuple.get() ), SAL_NO_ACQUIRE ); + if( ! ret.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "Couldn't instantiate python representation of structered UNO type " ); + buf.append( a.getValueType().getTypeName() ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + + if( com::sun::star::uno::TypeClass_EXCEPTION == a.getValueTypeClass() ) + { + // add the message in a standard python way ! + PyRef args( PyTuple_New( 1 ), SAL_NO_ACQUIRE ); + + // assuming that the Message is always the first member, wuuuu + void *pData = (void*)a.getValue(); + OUString message = *(OUString * )pData; + PyRef pymsg = ustring2PyString( message ); + PyTuple_SetItem( args.get(), 0 , pymsg.getAcquired() ); + // the exception base functions want to have an "args" tuple, + // which contains the message + PyObject_SetAttrString( ret.get(), "args", args.get() ); + } + return ret; + } + case typelib_TypeClass_SEQUENCE: + { + Sequence<Any> s; + + Sequence< sal_Int8 > byteSequence; + if( a >>= byteSequence ) + { + // byte sequence is treated in a special way because of peformance reasons + // @since 0.9.2 + return PyRef( PyUNO_ByteSequence_new( byteSequence, *this ), SAL_NO_ACQUIRE ); + } + else + { + Reference< XTypeConverter > tc = getImpl()->cargo->xTypeConverter; + Reference< XSingleServiceFactory > ssf = getImpl()->cargo->xInvocation; + tc->convertTo (a, ::getCppuType (&s)) >>= s; + PyRef tuple( PyTuple_New (s.getLength()), SAL_NO_ACQUIRE); + int i=0; + OUString errMsg; + try + { + for ( i = 0; i < s.getLength (); i++) + { + PyRef element; + element = any2PyObject (tc->convertTo (s[i], s[i].getValueType() )); + OSL_ASSERT( element.is() ); + PyTuple_SetItem( tuple.get(), i, element.getAcquired() ); + } + } + catch( com::sun::star::uno::Exception & ) + { + for( ; i < s.getLength() ; i ++ ) + { + Py_INCREF( Py_None ); + PyTuple_SetItem( tuple.get(), i, Py_None ); + } + throw; + } + return tuple; + } + } + case typelib_TypeClass_INTERFACE: + { + Reference< XUnoTunnel > tunnel; + a >>= tunnel; + if( tunnel.is() ) + { + sal_Int64 that = tunnel->getSomething( ::pyuno::Adapter::getUnoTunnelImplementationId() ); + if( that ) + return ((Adapter*)sal::static_int_cast< sal_IntPtr >(that))->getWrappedObject(); + } + //This is just like the struct case: + return PyRef( PyUNO_new (a, getImpl()->cargo->xInvocation), SAL_NO_ACQUIRE ); + } + default: + { + OUStringBuffer buf; + buf.appendAscii( "Unknonwn UNO type class " ); + buf.append( (sal_Int32 ) a.getValueTypeClass() ); + throw RuntimeException(buf.makeStringAndClear( ), Reference< XInterface > () ); + } + } + //We shouldn't be here... + Py_INCREF( Py_None ); + return Py_None; +} + +static Sequence< Type > invokeGetTypes( const Runtime & r , PyObject * o ) +{ + Sequence< Type > ret; + + PyRef method( PyObject_GetAttrString( o , "getTypes" ), SAL_NO_ACQUIRE ); + raiseInvocationTargetExceptionWhenNeeded( r ); + if( method.is() && PyCallable_Check( method.get() ) ) + { + PyRef types( PyObject_CallObject( method.get(), 0 ) , SAL_NO_ACQUIRE ); + raiseInvocationTargetExceptionWhenNeeded( r ); + if( types.is() && PyTuple_Check( types.get() ) ) + { + int size = PyTuple_Size( types.get() ); + + // add the XUnoTunnel interface for uno object identity concept (hack) + ret.realloc( size + 1 ); + for( int i = 0 ; i < size ; i ++ ) + { + Any a = r.pyObject2Any(PyTuple_GetItem(types.get(),i)); + a >>= ret[i]; + } + ret[size] = getCppuType( (Reference< com::sun::star::lang::XUnoTunnel> *) 0 ); + } + } + return ret; +} + +Any Runtime::pyObject2Any ( const PyRef & source, enum ConversionMode mode ) const + throw ( com::sun::star::uno::RuntimeException ) +{ + if( ! impl->cargo->valid ) + { + throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM( + "pyuno runtime must be initialized before calling any2PyObject" )), + Reference< XInterface > () ); + } + + Any a; + PyObject *o = source.get(); + if( Py_None == o ) + { + + } + // In Python 3, there is no PyInt type. +#if PY_MAJOR_VERSION < 3 + else if (PyInt_Check (o)) + { + if( o == Py_True ) + { + sal_Bool b = sal_True; + a = Any( &b, getBooleanCppuType() ); + } + else if ( o == Py_False ) + { + sal_Bool b = sal_False; + a = Any( &b, getBooleanCppuType() ); + } + else + { + sal_Int32 l = (sal_Int32) PyLong_AsLong( o ); + if( l < 128 && l >= -128 ) + { + sal_Int8 b = (sal_Int8 ) l; + a <<= b; + } + else if( l <= 0x7fff && l >= -0x8000 ) + { + sal_Int16 s = (sal_Int16) l; + a <<= s; + } + else + { + a <<= l; + } + } + } +#endif /* PY_MAJOR_VERSION < 3 */ + else if (PyLong_Check (o)) + { +#if PY_MAJOR_VERSION >= 3 + // Convert the Python 3 booleans that are actually of type PyLong. + if(o == Py_True) + { + sal_Bool b = sal_True; + a = Any(&b, getBooleanCppuType()); + } + else if(o == Py_False) + { + sal_Bool b = sal_False; + a = Any(&b, getBooleanCppuType()); + } + else + { +#endif /* PY_MAJOR_VERSION >= 3 */ + sal_Int64 l = (sal_Int64)PyLong_AsLong (o); + if( l < 128 && l >= -128 ) + { + sal_Int8 b = (sal_Int8 ) l; + a <<= b; + } + else if( l <= 0x7fff && l >= -0x8000 ) + { + sal_Int16 s = (sal_Int16) l; + a <<= s; + } + else if( l <= SAL_CONST_INT64(0x7fffffff) && + l >= -SAL_CONST_INT64(0x80000000) ) + { + sal_Int32 l32 = (sal_Int32) l; + a <<= l32; + } + else + { + a <<= l; + } +#if PY_MAJOR_VERSION >= 3 + } +#endif + } + else if (PyFloat_Check (o)) + { + double d = PyFloat_AsDouble (o); + a <<= d; + } + else if (PyString_Check(o) || PyUnicode_Check(o)) + { + a <<= pyString2ustring(o); + } + else if (PyTuple_Check (o)) + { + Sequence<Any> s (PyTuple_Size (o)); + for (int i = 0; i < PyTuple_Size (o); i++) + { + s[i] = pyObject2Any (PyTuple_GetItem (o, i), mode ); + } + a <<= s; + } + else + { + Runtime runtime; + // should be removed, in case ByteSequence gets derived from String + if( PyObject_IsInstance( o, getByteSequenceClass( runtime ).get() ) ) + { + PyRef str(PyObject_GetAttrString( o , "value" ),SAL_NO_ACQUIRE); + Sequence< sal_Int8 > seq; + if( PyString_Check( str.get() ) ) + { + seq = Sequence<sal_Int8 > ( + (sal_Int8*) PyString_AsString(str.get()), PyString_Size(str.get())); + } + a <<= seq; + } + else + if( PyObject_IsInstance( o, getTypeClass( runtime ).get() ) ) + { + Type t = PyType2Type( o ); + a <<= t; + } + else if( PyObject_IsInstance( o, getEnumClass( runtime ).get() ) ) + { + a = PyEnum2Enum( o ); + } + else if( isInstanceOfStructOrException( o ) ) + { + PyRef struc(PyObject_GetAttrString( o , "value" ),SAL_NO_ACQUIRE); + PyUNO * obj = (PyUNO*)struc.get(); + Reference< XMaterialHolder > holder( obj->members->xInvocation, UNO_QUERY ); + if( holder.is( ) ) + a = holder->getMaterial(); + else + { + throw RuntimeException( + USTR_ASCII( "struct or exception wrapper does not support XMaterialHolder" ), + Reference< XInterface > () ); + } + } + else if( PyObject_IsInstance( o, getPyUnoClass( runtime ).get() ) ) + { + PyUNO* o_pi; + o_pi = (PyUNO*) o; + if (o_pi->members->wrappedObject.getValueTypeClass () == + com::sun::star::uno::TypeClass_STRUCT || + o_pi->members->wrappedObject.getValueTypeClass () == + com::sun::star::uno::TypeClass_EXCEPTION) + { + Reference<XMaterialHolder> my_mh (o_pi->members->xInvocation, UNO_QUERY); + + if (!my_mh.is ()) + { + throw RuntimeException( + USTR_ASCII( "struct wrapper does not support XMaterialHolder" ), + Reference< XInterface > () ); + } + else + a = my_mh->getMaterial (); + } + else + { + a = o_pi->members->wrappedObject; + } + } + else if( PyObject_IsInstance( o, getCharClass( runtime ).get() ) ) + { + sal_Unicode c = PyChar2Unicode( o ); + a.setValue( &c, getCharCppuType( )); + } + else if( PyObject_IsInstance( o, getAnyClass( runtime ).get() ) ) + { + if( ACCEPT_UNO_ANY == mode ) + { + a = pyObject2Any( PyRef( PyObject_GetAttrString( o , "value" ), SAL_NO_ACQUIRE) ); + Type t; + pyObject2Any( PyRef( PyObject_GetAttrString( o, "type" ), SAL_NO_ACQUIRE ) ) >>= t; + + try + { + a = getImpl()->cargo->xTypeConverter->convertTo( a, t ); + } + catch( com::sun::star::uno::Exception & e ) + { + throw RuntimeException( e.Message, e.Context ); + } + } + else + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "uno.Any instance not accepted during method call, " + "use uno.invoke instead" ) ), + Reference< XInterface > () ); + } + } + else + { + Reference< XInterface > mappedObject; + Reference< XInvocation > adapterObject; + + // instance already mapped out to the world ? + PyRef2Adapter::iterator ii = impl->cargo->mappedObjects.find( PyRef( o ) ); + if( ii != impl->cargo->mappedObjects.end() ) + { + adapterObject = ii->second; + } + + if( adapterObject.is() ) + { + // object got already bridged ! + Reference< com::sun::star::lang::XUnoTunnel > tunnel( adapterObject, UNO_QUERY ); + + Adapter *pAdapter = ( Adapter * ) + sal::static_int_cast< sal_IntPtr >( + tunnel->getSomething( + ::pyuno::Adapter::getUnoTunnelImplementationId() ) ); + + mappedObject = impl->cargo->xAdapterFactory->createAdapter( + adapterObject, pAdapter->getWrappedTypes() ); + } + else + { + Sequence< Type > interfaces = invokeGetTypes( *this, o ); + if( interfaces.getLength() ) + { + Adapter *pAdapter = new Adapter( o, interfaces ); + mappedObject = + getImpl()->cargo->xAdapterFactory->createAdapter( + pAdapter, interfaces ); + + // keep a list of exported objects to ensure object identity ! + impl->cargo->mappedObjects[ PyRef(o) ] = + com::sun::star::uno::WeakReference< XInvocation > ( pAdapter ); + } + } + if( mappedObject.is() ) + { + a = com::sun::star::uno::makeAny( mappedObject ); + } + else + { + OUStringBuffer buf; + buf.appendAscii( "Couldn't convert " ); + PyRef reprString( PyObject_Str( o ) , SAL_NO_ACQUIRE ); + buf.appendAscii( PyString_AsString( reprString.get() ) ); + buf.appendAscii( " to a UNO type" ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + } + } + return a; +} + +Any Runtime::extractUnoException( const PyRef & excType, const PyRef &excValue, const PyRef &excTraceback) const +{ + OUString str; + Any ret; + if( excTraceback.is() ) + { + Exception e; + PyRef unoModule; + if ( impl ) + { + try + { + unoModule = impl->cargo->getUnoModule(); + } + catch (Exception ei) + { + e=ei; + } + } + if( unoModule.is() ) + { + PyRef extractTraceback( + PyDict_GetItemString(unoModule.get(),"_uno_extract_printable_stacktrace" ) ); + + if( PyCallable_Check(extractTraceback.get()) ) + { + PyRef args( PyTuple_New( 1), SAL_NO_ACQUIRE ); + PyTuple_SetItem( args.get(), 0, excTraceback.getAcquired() ); + PyRef pyStr( PyObject_CallObject( extractTraceback.get(),args.get() ), SAL_NO_ACQUIRE); + str = rtl::OUString::createFromAscii( PyString_AsString(pyStr.get()) ); + } + else + { + str = OUString(RTL_CONSTASCII_USTRINGPARAM("Couldn't find uno._uno_extract_printable_stacktrace")); + } + } + else + { + str = OUString(RTL_CONSTASCII_USTRINGPARAM("Could not load uno.py, no stacktrace available")); + if ( e.Message.getLength() > 0 ) + { + str += OUString (RTL_CONSTASCII_USTRINGPARAM(" (Error loading uno.py: ")); + str += e.Message; + str += OUString (RTL_CONSTASCII_USTRINGPARAM(")")); + } + } + + } + else + { + // it may occur, that no traceback is given (e.g. only native code below) + str = OUString( RTL_CONSTASCII_USTRINGPARAM( "no traceback available" ) ); + } + + if( isInstanceOfStructOrException( excValue.get() ) ) + { + ret = pyObject2Any( excValue ); + } + else + { + OUStringBuffer buf; + PyRef typeName( PyObject_Str( excType.get() ), SAL_NO_ACQUIRE ); + if( typeName.is() ) + { + buf.appendAscii( PyString_AsString( typeName.get() ) ); + } + else + { + buf.appendAscii( "no typename available" ); + } + buf.appendAscii( ": " ); + PyRef valueRep( PyObject_Str( excValue.get() ), SAL_NO_ACQUIRE ); + if( valueRep.is() ) + { + buf.appendAscii( PyString_AsString( valueRep.get())); + } + else + { + buf.appendAscii( "Couldn't convert exception value to a string" ); + } + buf.appendAscii( ", traceback follows\n" ); + if( str.getLength() > 0 ) + { + buf.append( str ); + buf.appendAscii( "\n" ); + } + else + { + buf.appendAscii( ", no traceback available\n" ); + } + RuntimeException e; + e.Message = buf.makeStringAndClear(); + ret = com::sun::star::uno::makeAny( e ); + } + return ret; +} + + +static const char * g_NUMERICID = "pyuno.lcNumeric"; +static ::std::vector< rtl::OString > g_localeList; + +static const char *ensureUnlimitedLifetime( const char *str ) +{ + int size = g_localeList.size(); + int i; + for( i = 0 ; i < size ; i ++ ) + { + if( 0 == strcmp( g_localeList[i].getStr(), str ) ) + break; + } + if( i == size ) + { + g_localeList.push_back( str ); + } + return g_localeList[i].getStr(); +} + + +PyThreadAttach::PyThreadAttach( PyInterpreterState *interp) + throw ( com::sun::star::uno::RuntimeException ) +{ + tstate = PyThreadState_New( interp ); + if( !tstate ) + throw RuntimeException( + OUString(RTL_CONSTASCII_USTRINGPARAM( "Couldn't create a pythreadstate" ) ), + Reference< XInterface > () ); + PyEval_AcquireThread( tstate); + // set LC_NUMERIC to "C" + const char * oldLocale = + ensureUnlimitedLifetime( setlocale( LC_NUMERIC, 0 ) ); + setlocale( LC_NUMERIC, "C" ); + PyRef locale( // python requires C locale + PyLong_FromVoidPtr( (void*)oldLocale ), SAL_NO_ACQUIRE); + PyDict_SetItemString( + PyThreadState_GetDict(), g_NUMERICID, locale.get() ); +} + +PyThreadAttach::~PyThreadAttach() +{ + PyObject *value = + PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID ); + if( value ) + setlocale( LC_NUMERIC, (const char * ) PyLong_AsVoidPtr( value ) ); + PyThreadState_Clear( tstate ); + PyEval_ReleaseThread( tstate ); + PyThreadState_Delete( tstate ); + +} + +PyThreadDetach::PyThreadDetach() throw ( com::sun::star::uno::RuntimeException ) +{ + tstate = PyThreadState_Get(); + PyObject *value = + PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID ); + if( value ) + setlocale( LC_NUMERIC, (const char * ) PyLong_AsVoidPtr( value ) ); + PyEval_ReleaseThread( tstate ); +} + + /** Acquires the global interpreter lock again + + */ +PyThreadDetach::~PyThreadDetach() +{ + PyEval_AcquireThread( tstate ); +// PyObject *value = +// PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID ); + + // python requires C LC_NUMERIC locale, + // always set even when it is already "C" + setlocale( LC_NUMERIC, "C" ); +} + + +PyRef RuntimeCargo::getUnoModule() +{ + if( ! dictUnoModule.is() ) + { + dictUnoModule = importUnoModule(); + } + return dictUnoModule; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_type.cxx b/pyuno/source/module/pyuno_type.cxx new file mode 100644 index 000000000000..8dac1a16e1fb --- /dev/null +++ b/pyuno/source/module/pyuno_type.cxx @@ -0,0 +1,434 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include "pyuno_impl.hxx" + +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> + +#include <typelib/typedescription.hxx> + +using rtl::OString; +using rtl::OUString; +using rtl::OUStringBuffer; +using rtl::OUStringToOString; +using rtl::OStringBuffer; + +using com::sun::star::uno::TypeClass; +using com::sun::star::uno::Type; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::Any; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Reference; +using com::sun::star::uno::TypeDescription; + +#define USTR_ASCII(x) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( x ) ) +namespace pyuno +{ +const char *typeClassToString( TypeClass t ) +{ + const char * ret = 0; + switch (t) + { + case com::sun::star::uno::TypeClass_VOID: + ret = "VOID"; break; + case com::sun::star::uno::TypeClass_CHAR: + ret = "CHAR"; break; + case com::sun::star::uno::TypeClass_BOOLEAN: + ret = "BOOLEAN"; break; + case com::sun::star::uno::TypeClass_BYTE: + ret = "BYTE"; break; + case com::sun::star::uno::TypeClass_SHORT: + ret = "SHORT"; break; + case com::sun::star::uno::TypeClass_UNSIGNED_SHORT: + ret = "UNSIGNED_SHORT"; break; + case com::sun::star::uno::TypeClass_LONG: + ret = "LONG"; break; + case com::sun::star::uno::TypeClass_UNSIGNED_LONG: + ret = "UNSIGNED_LONG"; break; + case com::sun::star::uno::TypeClass_HYPER: + ret = "HYPER"; break; + case com::sun::star::uno::TypeClass_UNSIGNED_HYPER: + ret = "UNSIGNED_HYPER"; break; + case com::sun::star::uno::TypeClass_FLOAT: + ret = "FLOAT"; break; + case com::sun::star::uno::TypeClass_DOUBLE: + ret = "DOUBLE"; break; + case com::sun::star::uno::TypeClass_STRING: + ret = "STRING"; break; + case com::sun::star::uno::TypeClass_TYPE: + ret = "TYPE"; break; + case com::sun::star::uno::TypeClass_ANY: + ret = "ANY";break; + case com::sun::star::uno::TypeClass_ENUM: + ret = "ENUM";break; + case com::sun::star::uno::TypeClass_STRUCT: + ret = "STRUCT"; break; + case com::sun::star::uno::TypeClass_EXCEPTION: + ret = "EXCEPTION"; break; + case com::sun::star::uno::TypeClass_SEQUENCE: + ret = "SEQUENCE"; break; + case com::sun::star::uno::TypeClass_INTERFACE: + ret = "INTERFACE"; break; + case com::sun::star::uno::TypeClass_TYPEDEF: + ret = "TYPEDEF"; break; + case com::sun::star::uno::TypeClass_UNION: + ret = "UNION"; break; + case com::sun::star::uno::TypeClass_ARRAY: + ret = "ARRAY"; break; + case com::sun::star::uno::TypeClass_SERVICE: + ret = "SERVICE"; break; + case com::sun::star::uno::TypeClass_MODULE: + ret = "MODULE"; break; + case com::sun::star::uno::TypeClass_INTERFACE_METHOD: + ret = "INTERFACE_METHOD"; break; + case com::sun::star::uno::TypeClass_INTERFACE_ATTRIBUTE: + ret = "INTERFACE_ATTRIBUTE"; break; + default: + ret = "UNKNOWN"; break; + } + return ret; +} + +static PyRef getClass( const Runtime & r , const char * name) +{ + return PyRef( PyDict_GetItemString( r.getImpl()->cargo->getUnoModule().get(), (char*) name ) ); +} + +PyRef getTypeClass( const Runtime & r ) +{ + return getClass( r , "Type" ); +} + +PyRef getEnumClass( const Runtime & r ) +{ + return getClass( r , "Enum" ); +} + +PyRef getCharClass( const Runtime & r ) +{ + return getClass( r , "Char" ); +} + +PyRef getByteSequenceClass( const Runtime & r ) +{ + return getClass( r , "ByteSequence" ); +} + +PyRef getAnyClass( const Runtime & r ) +{ + return getClass( r , "Any" ); +} + + +sal_Unicode PyChar2Unicode( PyObject *obj ) throw ( RuntimeException ) +{ + PyRef value( PyObject_GetAttrString( obj, "value" ), SAL_NO_ACQUIRE ); + if( ! PyUnicode_Check( value.get() ) ) + { + throw RuntimeException( + USTR_ASCII( "attribute value of uno.Char is not a unicode string" ), + Reference< XInterface > () ); + } + + if( PyUnicode_GetSize( value.get() ) < 1 ) + { + throw RuntimeException( + USTR_ASCII( "uno.Char contains an empty unicode string" ), + Reference< XInterface > () ); + } + + sal_Unicode c = (sal_Unicode)PyUnicode_AsUnicode( value.get() )[0]; + return c; +} + +Any PyEnum2Enum( PyObject *obj ) throw ( RuntimeException ) +{ + Any ret; + PyRef typeName( PyObject_GetAttrString( obj,"typeName" ), SAL_NO_ACQUIRE); + PyRef value( PyObject_GetAttrString( obj, "value" ), SAL_NO_ACQUIRE); + if( !PyString_Check( typeName.get() ) || ! PyString_Check( value.get() ) ) + { + throw RuntimeException( + USTR_ASCII( "attributes typeName and/or value of uno.Enum are not strings" ), + Reference< XInterface > () ); + } + + OUString strTypeName( OUString::createFromAscii( PyString_AsString( typeName.get() ) ) ); + char *stringValue = PyString_AsString( value.get() ); + + TypeDescription desc( strTypeName ); + if( desc.is() ) + { + if(desc.get()->eTypeClass != typelib_TypeClass_ENUM ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno.checkEnum: " ).append(strTypeName).appendAscii( "is a " ); + buf.appendAscii( + typeClassToString( (com::sun::star::uno::TypeClass) desc.get()->eTypeClass)); + buf.appendAscii( ", expected ENUM" ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () ); + } + + desc.makeComplete(); + + typelib_EnumTypeDescription *pEnumDesc = (typelib_EnumTypeDescription*) desc.get(); + int i = 0; + for( i = 0; i < pEnumDesc->nEnumValues ; i ++ ) + { + if( (*((OUString *)&pEnumDesc->ppEnumNames[i])).compareToAscii( stringValue ) == 0 ) + { + break; + } + } + if( i == pEnumDesc->nEnumValues ) + { + OUStringBuffer buf; + buf.appendAscii( "value " ).appendAscii( stringValue ).appendAscii( "is unknown in enum " ); + buf.appendAscii( PyString_AsString( typeName.get() ) ); + throw RuntimeException( buf.makeStringAndClear(), Reference<XInterface> () ); + } + ret = Any( &pEnumDesc->pEnumValues[i], desc.get()->pWeakRef ); + } + else + { + OUStringBuffer buf; + buf.appendAscii( "enum " ).appendAscii( PyString_AsString(typeName.get()) ).appendAscii( " is unknown" ); + throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () ); + } + return ret; +} + + +Type PyType2Type( PyObject * o ) throw(RuntimeException ) +{ + PyRef pyName( PyObject_GetAttrString( o, "typeName" ), SAL_NO_ACQUIRE); + if( !PyString_Check( pyName.get() ) ) + { + throw RuntimeException( + USTR_ASCII( "type object does not have typeName property" ), + Reference< XInterface > () ); + } + + PyRef pyTC( PyObject_GetAttrString( o, "typeClass" ), SAL_NO_ACQUIRE ); + Any enumValue = PyEnum2Enum( pyTC.get() ); + + OUString name( OUString::createFromAscii( PyString_AsString( pyName.get() ) ) ); + TypeDescription desc( name ); + if( ! desc.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "type " ).append(name).appendAscii( " is unknown" ); + throw RuntimeException( + buf.makeStringAndClear(), Reference< XInterface > () ); + } + if( desc.get()->eTypeClass != (typelib_TypeClass) *(sal_Int32*)enumValue.getValue() ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno.checkType: " ).append(name).appendAscii( " is a " ); + buf.appendAscii( typeClassToString( (TypeClass) desc.get()->eTypeClass) ); + buf.appendAscii( ", but type got construct with typeclass " ); + buf.appendAscii( typeClassToString( (TypeClass) *(sal_Int32*)enumValue.getValue() ) ); + throw RuntimeException( + buf.makeStringAndClear(), Reference< XInterface > () ); + } + return desc.get()->pWeakRef; +} + +PyObject *importToGlobal(PyObject *str, PyObject *dict, PyObject *target) +{ + // maybe a constant ? + PyObject *ret = 0; + OUString name = pyString2ustring(str); + try + { + Runtime runtime; + TypeDescription desc(name ); + desc.makeComplete(); + if( desc.is() ) + { + com::sun::star::uno::TypeClass tc = + (com::sun::star::uno::TypeClass)desc.get()->eTypeClass; + + PyRef typesModule( PyDict_GetItemString( dict, "unotypes" ) ); + if( ! typesModule.is() || ! PyModule_Check( typesModule.get() )) + { + typesModule = PyRef( PyModule_New( "unotypes" ), SAL_NO_ACQUIRE ); + Py_INCREF( typesModule.get() ); + PyDict_SetItemString( dict, "unotypes" , typesModule.get() ); + } + PyModule_AddObject( + typesModule.get(), + PyString_AsString( target ), + PyUNO_Type_new( PyString_AsString(str),tc,runtime ) ); + + if( com::sun::star::uno::TypeClass_EXCEPTION == tc || + com::sun::star::uno::TypeClass_STRUCT == tc ) + { + PyRef exc = getClass( name, runtime ); + PyDict_SetItem( dict, target, exc.getAcquired() ); + } + else if( com::sun::star::uno::TypeClass_ENUM == tc ) + { + // introduce all enums into the dictionary ! + typelib_EnumTypeDescription *pDesc = + (typelib_EnumTypeDescription *) desc.get(); + for( int i = 0 ; i < pDesc->nEnumValues; i ++ ) + { + OString enumElementName( + OUStringToOString( pDesc->ppEnumNames[i], RTL_TEXTENCODING_ASCII_US) ); + PyDict_SetItemString( + dict, (char*)enumElementName.getStr(), + PyUNO_Enum_new(PyString_AsString(str) , enumElementName.getStr(), runtime ) ); + } + } + Py_INCREF( Py_None ); + ret = Py_None; + } + else + { + Any a = runtime.getImpl()->cargo->xTdMgr->getByHierarchicalName(name); + if(a.hasValue()) + { + PyRef constant = runtime.any2PyObject( a ); + if( constant.is() ) + { + Py_INCREF( constant.get() ); + PyDict_SetItem( dict, target , constant.get()); + ret = constant.get(); + } + else + { + OStringBuffer buf; + buf.append( "constant " ).append(PyString_AsString(str)).append( " unknown" ); + PyErr_SetString( PyExc_RuntimeError, buf.getStr() ); + } + } + else + { + OUStringBuffer buf; + buf.appendAscii( "pyuno.imp unknown type " ); + buf.append( name ); + PyErr_SetString( + PyExc_RuntimeError, + OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US).getStr() ); + } + } + } + catch( com::sun::star::container::NoSuchElementException & ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno.imp unknown type " ); + buf.append( name ); + PyErr_SetString( + PyExc_RuntimeError, + OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US).getStr() ); + } + catch( com::sun::star::script::CannotConvertException & e ) + { + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + catch( com::sun::star::lang::IllegalArgumentException & e ) + { + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) ); + } + catch( RuntimeException &e ) + { + raisePyExceptionWithAny( com::sun::star::uno::makeAny( e )); + } + return ret; +} + +static PyObject* callCtor( const Runtime &r , const char * clazz, const PyRef & args ) +{ + PyRef code( PyDict_GetItemString( r.getImpl()->cargo->getUnoModule().get(), (char*)clazz ) ); + if( ! code.is() ) + { + OStringBuffer buf; + buf.append( "couldn't access uno." ); + buf.append( clazz ); + PyErr_SetString( PyExc_RuntimeError, buf.getStr() ); + return NULL; + } + PyRef instance( PyObject_CallObject( code.get(), args.get() ), SAL_NO_ACQUIRE); + Py_XINCREF( instance.get() ); + return instance.get(); + +} + + +PyObject *PyUNO_Enum_new( const char *enumBase, const char *enumValue, const Runtime &r ) +{ + PyRef args( PyTuple_New( 2 ), SAL_NO_ACQUIRE ); + PyTuple_SetItem( args.get() , 0 , PyString_FromString( enumBase ) ); + PyTuple_SetItem( args.get() , 1 , PyString_FromString( enumValue ) ); + + return callCtor( r, "Enum" , args ); +} + + +PyObject* PyUNO_Type_new (const char *typeName , TypeClass t , const Runtime &r ) +{ + // retrieve type object + PyRef args( PyTuple_New( 2 ), SAL_NO_ACQUIRE ); + + PyTuple_SetItem( args.get() , 0 , PyString_FromString( typeName ) ); + PyObject *typeClass = PyUNO_Enum_new( "com.sun.star.uno.TypeClass" , typeClassToString(t), r ); + if( ! typeClass ) + return NULL; + PyTuple_SetItem( args.get() , 1 , typeClass); + + return callCtor( r, "Type" , args ); +} + +PyObject* PyUNO_char_new ( sal_Unicode val , const Runtime &r ) +{ + // retrieve type object + PyRef args( PyTuple_New( 1 ), SAL_NO_ACQUIRE ); + + Py_UNICODE u[2]; + u[0] = val; + u[1] = 0; + PyTuple_SetItem( args.get() , 0 , PyUnicode_FromUnicode( u ,1) ); + + return callCtor( r, "Char" , args ); +} + +PyObject *PyUNO_ByteSequence_new( + const com::sun::star::uno::Sequence< sal_Int8 > &byteSequence, const Runtime &r ) +{ + PyRef str( + PyString_FromStringAndSize( (char*)byteSequence.getConstArray(), byteSequence.getLength()), + SAL_NO_ACQUIRE ); + PyRef args( PyTuple_New( 1 ), SAL_NO_ACQUIRE ); + PyTuple_SetItem( args.get() , 0 , str.getAcquired() ); + return callCtor( r, "ByteSequence" , args ); + +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/pyuno_util.cxx b/pyuno/source/module/pyuno_util.cxx new file mode 100644 index 000000000000..ae645a7c32e4 --- /dev/null +++ b/pyuno/source/module/pyuno_util.cxx @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "pyuno_impl.hxx" + +#include <time.h> +#include <osl/thread.h> + +#include <typelib/typedescription.hxx> + +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/time.h> + +#include <com/sun/star/beans/XMaterialHolder.hpp> + +using rtl::OUStringToOString; +using rtl::OUString; +using rtl::OString; +using rtl::OStringBuffer; +using rtl::OUStringBuffer; + + +using com::sun::star::uno::TypeDescription; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::TypeClass; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::XComponentContext; +using com::sun::star::lang::XSingleServiceFactory; +using com::sun::star::script::XTypeConverter; +using com::sun::star::beans::XMaterialHolder; + +#define USTR_ASCII(x) OUString( RTL_CONSTASCII_USTRINGPARAM( x ) ) +namespace pyuno +{ +PyRef ustring2PyUnicode( const OUString & str ) +{ + PyRef ret; +#if Py_UNICODE_SIZE == 2 + // YD force conversion since python/2 uses wchar_t + ret = PyRef( PyUnicode_FromUnicode( (const Py_UNICODE*)str.getStr(), str.getLength() ), SAL_NO_ACQUIRE ); +#else + OString sUtf8(OUStringToOString(str, RTL_TEXTENCODING_UTF8)); + ret = PyRef( PyUnicode_DecodeUTF8( sUtf8.getStr(), sUtf8.getLength(), NULL) , SAL_NO_ACQUIRE ); +#endif + return ret; +} + +PyRef ustring2PyString( const OUString &str ) +{ + OString o = OUStringToOString( str, osl_getThreadTextEncoding() ); + return PyRef( PyString_FromString( o.getStr() ), SAL_NO_ACQUIRE ); +} + +OUString pyString2ustring( PyObject *pystr ) +{ + OUString ret; + if( PyUnicode_Check( pystr ) ) + { +#if Py_UNICODE_SIZE == 2 + ret = OUString( (sal_Unicode * ) PyUnicode_AS_UNICODE( pystr ) ); +#else + PyObject* pUtf8 = PyUnicode_AsUTF8String(pystr); + ret = OUString(PyString_AsString(pUtf8), PyString_Size(pUtf8), RTL_TEXTENCODING_UTF8); + Py_DECREF(pUtf8); +#endif + } + else + { + char *name = PyString_AsString(pystr ); + ret = OUString( name, strlen(name), osl_getThreadTextEncoding() ); + } + return ret; +} + +PyRef getObjectFromUnoModule( const Runtime &runtime, const char * func ) + throw ( RuntimeException ) +{ + PyRef object(PyDict_GetItemString( runtime.getImpl()->cargo->getUnoModule().get(), (char*)func ) ); + if( !object.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "couldn't find core function " ); + buf.appendAscii( func ); + throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >()); + } + return object; +} + + +//------------------------------------------------------------------------------------ +// Logging +//------------------------------------------------------------------------------------ + +bool isLog( RuntimeCargo * cargo, sal_Int32 loglevel ) +{ + return cargo && cargo->logFile && loglevel <= cargo->logLevel; +} + +void log( RuntimeCargo * cargo, sal_Int32 level, const rtl::OUString &logString ) +{ + log( cargo, level, OUStringToOString( logString, osl_getThreadTextEncoding() ).getStr() ); +} + +void log( RuntimeCargo * cargo, sal_Int32 level, const char *str ) +{ + if( isLog( cargo, level ) ) + { + static const char *strLevel[] = { "NONE", "CALL", "ARGS" }; + + TimeValue systemTime; + TimeValue localTime; + oslDateTime localDateTime; + + osl_getSystemTime( &systemTime ); + osl_getLocalTimeFromSystemTime( &systemTime, &localTime ); + osl_getDateTimeFromTimeValue( &localTime, &localDateTime ); + + fprintf( cargo->logFile, + "%4i-%02i-%02i %02i:%02i:%02i,%03lu [%s,tid %ld]: %s\n", + localDateTime.Year, + localDateTime.Month, + localDateTime.Day, + localDateTime.Hours, + localDateTime.Minutes, + localDateTime.Seconds, + sal::static_int_cast< unsigned long >( + localDateTime.NanoSeconds/1000000), + strLevel[level], + sal::static_int_cast< long >( + (sal_Int32) osl_getThreadIdentifier( 0)), + str ); + } +} + +namespace { + +void appendPointer(rtl::OUStringBuffer & buffer, void * pointer) { + buffer.append( + sal::static_int_cast< sal_Int64 >( + reinterpret_cast< sal_IntPtr >(pointer)), + 16); +} + +} + +void logException( RuntimeCargo *cargo, const char *intro, + void * ptr, const rtl::OUString &aFunctionName, + const void * data, const com::sun::star::uno::Type & type ) +{ + if( isLog( cargo, LogLevel::CALL ) ) + { + rtl::OUStringBuffer buf( 128 ); + buf.appendAscii( intro ); + appendPointer(buf, ptr); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("].") ); + buf.append( aFunctionName ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " = " ) ); + buf.append( + val2str( data, type.getTypeLibType(), VAL2STR_MODE_SHALLOW ) ); + log( cargo,LogLevel::CALL, buf.makeStringAndClear() ); + } + +} + +void logReply( + RuntimeCargo *cargo, + const char *intro, + void * ptr, + const rtl::OUString & aFunctionName, + const Any &returnValue, + const Sequence< Any > & aParams ) +{ + rtl::OUStringBuffer buf( 128 ); + buf.appendAscii( intro ); + appendPointer(buf, ptr); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("].") ); + buf.append( aFunctionName ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("()=") ); + if( isLog( cargo, LogLevel::ARGS ) ) + { + buf.append( + val2str( returnValue.getValue(), returnValue.getValueTypeRef(), VAL2STR_MODE_SHALLOW) ); + for( int i = 0; i < aParams.getLength() ; i ++ ) + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", " ) ); + buf.append( + val2str( aParams[i].getValue(), aParams[i].getValueTypeRef(), VAL2STR_MODE_SHALLOW) ); + } + } + log( cargo,LogLevel::CALL, buf.makeStringAndClear() ); + +} + +void logCall( RuntimeCargo *cargo, const char *intro, + void * ptr, const rtl::OUString & aFunctionName, + const Sequence< Any > & aParams ) +{ + rtl::OUStringBuffer buf( 128 ); + buf.appendAscii( intro ); + appendPointer(buf, ptr); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("].") ); + buf.append( aFunctionName ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("(") ); + if( isLog( cargo, LogLevel::ARGS ) ) + { + for( int i = 0; i < aParams.getLength() ; i ++ ) + { + if( i > 0 ) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", " ) ); + buf.append( + val2str( aParams[i].getValue(), aParams[i].getValueTypeRef(), VAL2STR_MODE_SHALLOW) ); + } + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(")") ); + log( cargo,LogLevel::CALL, buf.makeStringAndClear() ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/source/module/uno.py b/pyuno/source/module/uno.py new file mode 100644 index 000000000000..e82d9d64e2dc --- /dev/null +++ b/pyuno/source/module/uno.py @@ -0,0 +1,369 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# 2011 Lionel Elie Mamane <lionel@mamane.lu> +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +import sys + +import pyuno + +try: + import __builtin__ +except ImportError: + import builtins as __builtin__ + +import socket # since on Windows sal3.dll no longer calls WSAStartup + +# all functions and variables starting with a underscore (_) must be considered private +# and can be changed at any time. Don't use them +_g_ctx = pyuno.getComponentContext( ) +_g_delegatee = __builtin__.__dict__["__import__"] + +def getComponentContext(): + """ returns the UNO component context, that was used to initialize the python runtime. + """ + return _g_ctx + +def getConstantByName( constant ): + "Looks up the value of a idl constant by giving its explicit name" + return pyuno.getConstantByName( constant ) + +def getTypeByName( typeName): + """ returns a uno.Type instance of the type given by typeName. In case the + type does not exist, a com.sun.star.uno.RuntimeException is raised. + """ + return pyuno.getTypeByName( typeName ) + +def createUnoStruct( typeName, *args, **kwargs ): + """creates a uno struct or exception given by typeName. Can be called with: + 1) No additional argument. + In this case, you get a default constructed uno structure. + ( e.g. createUnoStruct( "com.sun.star.uno.Exception" ) ) + 2) Exactly one additional argument that is an instance of typeName. + In this case, a copy constructed instance of typeName is returned + ( e.g. createUnoStruct( "com.sun.star.uno.Exception" , e ) ) + 3) As many additional arguments as the number of elements within typeName + (e.g. createUnoStruct( "com.sun.star.uno.Exception", "foo error" , self) ). + 4) Keyword arguments to give values for each element of the struct by name. + 5) A mix of 3) and 4), such that each struct element is given a value exactly once, + either by a positional argument or by a keyword argument. + The additional and/or keyword arguments must match the type of each struct element, + otherwise an exception is thrown. + """ + return getClass(typeName)( *args, **kwargs ) + +def getClass( typeName ): + """returns the class of a concrete uno exception, struct or interface + """ + return pyuno.getClass(typeName) + +def isInterface( obj ): + """returns true, when obj is a class of a uno interface""" + return pyuno.isInterface( obj ) + +def generateUuid(): + "returns a 16 byte sequence containing a newly generated uuid or guid, see rtl/uuid.h " + return pyuno.generateUuid() + +def systemPathToFileUrl( systemPath ): + "returns a file-url for the given system path" + return pyuno.systemPathToFileUrl( systemPath ) + +def fileUrlToSystemPath( url ): + "returns a system path (determined by the system, the python interpreter is running on)" + return pyuno.fileUrlToSystemPath( url ) + +def absolutize( path, relativeUrl ): + "returns an absolute file url from the given urls" + return pyuno.absolutize( path, relativeUrl ) + +def getCurrentContext(): + """Returns the currently valid current context. + see http://udk.openoffice.org/common/man/concept/uno_contexts.html#current_context + for an explanation on the current context concept + """ + return pyuno.getCurrentContext() + +def setCurrentContext( newContext ): + """Sets newContext as new uno current context. The newContext must + implement the XCurrentContext interface. The implemenation should + handle the desired properties and delegate unknown properties to the + old context. Ensure to reset the old one when you leave your stack ... + see http://udk.openoffice.org/common/man/concept/uno_contexts.html#current_context + """ + return pyuno.setCurrentContext( newContext ) + + +class Enum: + "Represents a UNO idl enum, use an instance of this class to explicitly pass a boolean to UNO" + #typeName the name of the enum as a string + #value the actual value of this enum as a string + def __init__(self,typeName, value): + self.typeName = typeName + self.value = value + pyuno.checkEnum( self ) + + def __repr__(self): + return "<uno.Enum %s (%r)>" % (self.typeName, self.value) + + def __eq__(self, that): + if not isinstance(that, Enum): + return False + return (self.typeName == that.typeName) and (self.value == that.value) + +class Type: + "Represents a UNO type, use an instance of this class to explicitly pass a boolean to UNO" +# typeName # Name of the UNO type +# typeClass # python Enum of TypeClass, see com/sun/star/uno/TypeClass.idl + def __init__(self, typeName, typeClass): + self.typeName = typeName + self.typeClass = typeClass + pyuno.checkType(self) + def __repr__(self): + return "<Type instance %s (%r)>" % (self.typeName, self.typeClass) + + def __eq__(self, that): + if not isinstance(that, Type): + return False + return self.typeClass == that.typeClass and self.typeName == that.typeName + + def __hash__(self): + return self.typeName.__hash__() + +class Bool(object): + """Represents a UNO boolean, use an instance of this class to explicitly + pass a boolean to UNO. + Note: This class is deprecated. Use python's True and False directly instead + """ + def __new__(cls, value): + if isinstance(value, str) and value == "true": + return True + if isinstance(value, str) and value == "false": + return False + if value: + return True + return False + +class Char: + "Represents a UNO char, use an instance of this class to explicitly pass a char to UNO" + # @param value pass a Unicode string with length 1 + def __init__(self,value): + assert isinstance(value, str) + assert len(value) == 1 + self.value=value + + def __repr__(self): + return "<Char instance %s>" % (self.value, ) + + def __eq__(self, that): + if isinstance(that, str): + if len(that) > 1: + return False + return self.value == that[0] + if isinstance(that, Char): + return self.value == that.value + return False + +# Suggested by Christian, but still some open problems which need to be solved first +# +#class ByteSequence(str): +# +# def __repr__(self): +# return "<ByteSequence instance %s>" % str.__repr__(self) + + # for a little bit compatitbility; setting value is not possible as + # strings are immutable +# def _get_value(self): +# return self +# +# value = property(_get_value) + +class ByteSequence: + def __init__(self, value): + if isinstance(value, str): + self.value = value + elif isinstance(value, ByteSequence): + self.value = value.value + else: + raise TypeError("expected string or bytesequence") + + def __repr__(self): + return "<ByteSequence instance '%s'>" % (self.value, ) + + def __eq__(self, that): + if isinstance( that, ByteSequence): + return self.value == that.value + if isinstance(that, str): + return self.value == that + return False + + def __len__(self): + return len(self.value) + + def __getitem__(self, index): + return self.value[index] + + def __iter__( self ): + return self.value.__iter__() + + def __add__( self , b ): + if isinstance( b, str ): + return ByteSequence( self.value + b ) + elif isinstance( b, ByteSequence ): + return ByteSequence( self.value + b.value ) + raise TypeError( "expected string or ByteSequence as operand" ) + + def __hash__( self ): + return self.value.hash() + + +class Any: + "use only in connection with uno.invoke() to pass an explicit typed any" + def __init__(self, type, value ): + if isinstance( type, Type ): + self.type = type + else: + self.type = getTypeByName( type ) + self.value = value + +def invoke( object, methodname, argTuple ): + "use this function to pass exactly typed anys to the callee (using uno.Any)" + return pyuno.invoke( object, methodname, argTuple ) + +#--------------------------------------------------------------------------------------- +# don't use any functions beyond this point, private section, likely to change +#--------------------------------------------------------------------------------------- +#def _uno_import( name, globals={}, locals={}, fromlist=[], level=-1 ): +def _uno_import( name, *optargs, **kwargs ): + try: +# print "optargs = " + repr(optargs) + return _g_delegatee( name, *optargs, **kwargs ) + except ImportError: + # process optargs + globals, locals, fromlist = list(optargs)[:3] + [kwargs.get('globals',{}), kwargs.get('locals',{}), kwargs.get('fromlist',[])][len(optargs):] + if not fromlist: + raise + modnames = name.split( "." ) + mod = None + d = sys.modules + for x in modnames: + if x in d: + mod = d[x] + else: + mod = pyuno.__class__(x) # How to create a module ?? + d = mod.__dict__ + + RuntimeException = pyuno.getClass( "com.sun.star.uno.RuntimeException" ) + for x in fromlist: + if x not in d: + if x.startswith( "typeOf" ): + try: + d[x] = pyuno.getTypeByName( name + "." + x[6:len(x)] ) + except RuntimeException as e: + raise ImportError( "type " + name + "." + x[6:len(x)] +" is unknown" ) + else: + try: + # check for structs, exceptions or interfaces + d[x] = pyuno.getClass( name + "." + x ) + except RuntimeException as e: + # check for enums + try: + d[x] = Enum( name , x ) + except RuntimeException as e2: + # check for constants + try: + d[x] = getConstantByName( name + "." + x ) + except RuntimeException as e3: + # no known uno type ! + raise ImportError( "type "+ name + "." +x + " is unknown" ) + return mod + +# private function, don't use +def _impl_extractName(name): + r = list(range(len(name)-1,0,-1)) + for i in r: + if name[i] == ".": + name = name[i+1:len(name)] + break + return name + +# private, referenced from the pyuno shared library +def _uno_struct__init__(self,*args, **kwargs): + if len(kwargs) == 0 and len(args) == 1 and hasattr(args[0], "__class__") and args[0].__class__ == self.__class__ : + self.__dict__["value"] = args[0] + else: + struct, used = pyuno._createUnoStructHelper(self.__class__.__pyunostruct__,args,**kwargs) + for kw in kwargs.keys(): + if not (kw in used and used[kw]): + RuntimeException = pyuno.getClass( "com.sun.star.uno.RuntimeException" ) + raise RuntimeException("_uno_struct__init__: unused keyword argument '" + kw + "'", None) + self.__dict__["value"] = struct + +# private, referenced from the pyuno shared library +def _uno_struct__getattr__(self,name): + return __builtin__.getattr(self.__dict__["value"],name) + +# private, referenced from the pyuno shared library +def _uno_struct__setattr__(self,name,value): + return __builtin__.setattr(self.__dict__["value"],name,value) + +# private, referenced from the pyuno shared library +def _uno_struct__repr__(self): + return repr(self.__dict__["value"]) + +def _uno_struct__str__(self): + return str(self.__dict__["value"]) + +# private, referenced from the pyuno shared library +def _uno_struct__eq__(self,cmp): + if hasattr(cmp,"value"): + return self.__dict__["value"] == cmp.__dict__["value"] + return False + +# referenced from pyuno shared lib and pythonscript.py +def _uno_extract_printable_stacktrace( trace ): + mod = None + try: + mod = __import__("traceback") + except ImportError as e: + pass + ret = "" + if mod: + lst = mod.extract_tb( trace ) + max = len(lst) + for j in range(max): + i = lst[max-j-1] + ret = ret + " " + str(i[0]) + ":" + \ + str(i[1]) + " in function " + \ + str(i[2]) + "() [" + str(i[3]) + "]\n" + else: + ret = "Couldn't import traceback module" + return ret + +# hook into the __import__ chain +__builtin__.__dict__["__import__"] = _uno_import + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/source/module/unohelper.py b/pyuno/source/module/unohelper.py new file mode 100644 index 000000000000..ee5f3712d941 --- /dev/null +++ b/pyuno/source/module/unohelper.py @@ -0,0 +1,306 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +import uno +import pyuno +import os +import sys + +from com.sun.star.lang import XTypeProvider, XSingleComponentFactory, XServiceInfo +from com.sun.star.uno import RuntimeException, XCurrentContext +from com.sun.star.beans.MethodConcept import ALL as METHOD_CONCEPT_ALL +from com.sun.star.beans.PropertyConcept import ALL as PROPERTY_CONCEPT_ALL + +from com.sun.star.reflection.ParamMode import \ + IN as PARAM_MODE_IN, \ + OUT as PARAM_MODE_OUT, \ + INOUT as PARAM_MODE_INOUT + +from com.sun.star.beans.PropertyAttribute import \ + MAYBEVOID as PROP_ATTR_MAYBEVOID, \ + BOUND as PROP_ATTR_BOUND, \ + CONSTRAINED as PROP_ATTR_CONSTRAINED, \ + TRANSIENT as PROP_ATTR_TRANSIENT, \ + READONLY as PROP_ATTR_READONLY, \ + MAYBEAMBIGUOUS as PROP_ATTR_MAYBEAMBIGUOUS, \ + MAYBEDEFAULT as PROP_ATTR_MAYBEDEFAULT, \ + REMOVEABLE as PROP_ATTR_REMOVEABLE + +def _mode_to_str( mode ): + ret = "[]" + if mode == PARAM_MODE_INOUT: + ret = "[inout]" + elif mode == PARAM_MODE_OUT: + ret = "[out]" + elif mode == PARAM_MODE_IN: + ret = "[in]" + return ret + +def _propertymode_to_str( mode ): + ret = "" + if PROP_ATTR_REMOVEABLE & mode: + ret = ret + "removeable " + if PROP_ATTR_MAYBEDEFAULT & mode: + ret = ret + "maybedefault " + if PROP_ATTR_MAYBEAMBIGUOUS & mode: + ret = ret + "maybeambigous " + if PROP_ATTR_READONLY & mode: + ret = ret + "readonly " + if PROP_ATTR_TRANSIENT & mode: + ret = ret + "tranient " + if PROP_ATTR_CONSTRAINED & mode: + ret = ret + "constrained " + if PROP_ATTR_BOUND & mode: + ret = ret + "bound " + if PROP_ATTR_MAYBEVOID & mode: + ret = ret + "maybevoid " + return ret.rstrip() + +def inspect( obj , out ): + if isinstance( obj, uno.Type ) or \ + isinstance( obj, uno.Char ) or \ + isinstance( obj, uno.Bool ) or \ + isinstance( obj, uno.ByteSequence ) or \ + isinstance( obj, uno.Enum ) or \ + isinstance( obj, uno.Any ): + out.write( str(obj) + "\n") + return + + ctx = uno.getComponentContext() + introspection = \ + ctx.ServiceManager.createInstanceWithContext( "com.sun.star.beans.Introspection", ctx ) + + out.write( "Supported services:\n" ) + if hasattr( obj, "getSupportedServiceNames" ): + names = obj.getSupportedServiceNames() + for ii in names: + out.write( " " + ii + "\n" ) + else: + out.write( " unknown\n" ) + + out.write( "Interfaces:\n" ) + if hasattr( obj, "getTypes" ): + interfaces = obj.getTypes() + for ii in interfaces: + out.write( " " + ii.typeName + "\n" ) + else: + out.write( " unknown\n" ) + + access = introspection.inspect( obj ) + methods = access.getMethods( METHOD_CONCEPT_ALL ) + out.write( "Methods:\n" ) + for ii in methods: + out.write( " " + ii.ReturnType.Name + " " + ii.Name ) + args = ii.ParameterTypes + infos = ii.ParameterInfos + out.write( "( " ) + for i in range( 0, len( args ) ): + if i > 0: + out.write( ", " ) + out.write( _mode_to_str( infos[i].aMode ) + " " + args[i].Name + " " + infos[i].aName ) + out.write( " )\n" ) + + props = access.getProperties( PROPERTY_CONCEPT_ALL ) + out.write ("Properties:\n" ) + for ii in props: + out.write( " ("+_propertymode_to_str( ii.Attributes ) + ") "+ii.Type.typeName+" "+ii.Name+ "\n" ) + +def createSingleServiceFactory( clazz, implementationName, serviceNames ): + return _FactoryHelper_( clazz, implementationName, serviceNames ) + +class _ImplementationHelperEntry: + def __init__(self, ctor,serviceNames): + self.ctor = ctor + self.serviceNames = serviceNames + +class ImplementationHelper: + def __init__(self): + self.impls = {} + + def addImplementation( self, ctor, implementationName, serviceNames ): + self.impls[implementationName] = _ImplementationHelperEntry(ctor,serviceNames) + + def writeRegistryInfo( self, regKey, smgr ): + for i in list(self.impls.items()): + keyName = "/"+ i[0] + "/UNO/SERVICES" + key = regKey.createKey( keyName ) + for serviceName in i[1].serviceNames: + key.createKey( serviceName ) + return 1 + + def getComponentFactory( self, implementationName , regKey, smgr ): + entry = self.impls.get( implementationName, None ) + if entry == None: + raise RuntimeException( implementationName + " is unknown" , None ) + return createSingleServiceFactory( entry.ctor, implementationName, entry.serviceNames ) + + def getSupportedServiceNames( self, implementationName ): + entry = self.impls.get( implementationName, None ) + if entry == None: + raise RuntimeException( implementationName + " is unknown" , None ) + return entry.serviceNames + + def supportsService( self, implementationName, serviceName ): + entry = self.impls.get( implementationName,None ) + if entry == None: + raise RuntimeException( implementationName + " is unknown", None ) + return serviceName in entry.serviceNames + + +class ImplementationEntry: + def __init__(self, implName, supportedServices, clazz ): + self.implName = implName + self.supportedServices = supportedServices + self.clazz = clazz + +def writeRegistryInfoHelper( smgr, regKey, seqEntries ): + for entry in seqEntries: + keyName = "/"+ entry.implName + "/UNO/SERVICES" + key = regKey.createKey( keyName ) + for serviceName in entry.supportedServices: + key.createKey( serviceName ) + +def systemPathToFileUrl( systemPath ): + "returns a file-url for the given system path" + return pyuno.systemPathToFileUrl( systemPath ) + +def fileUrlToSystemPath( url ): + "returns a system path (determined by the system, the python interpreter is running on)" + return pyuno.fileUrlToSystemPath( url ) + +def absolutize( path, relativeUrl ): + "returns an absolute file url from the given urls" + return pyuno.absolutize( path, relativeUrl ) + +def getComponentFactoryHelper( implementationName, smgr, regKey, seqEntries ): + for x in seqEntries: + if x.implName == implementationName: + return createSingleServiceFactory( x.clazz, implementationName, x.supportedServices ) + +def addComponentsToContext( toBeExtendedContext, contextRuntime, componentUrls, loaderName ): + smgr = contextRuntime.ServiceManager + loader = smgr.createInstanceWithContext( loaderName, contextRuntime ) + implReg = smgr.createInstanceWithContext( "com.sun.star.registry.ImplementationRegistration",contextRuntime) + + isWin = os.name == 'nt' or os.name == 'dos' + isMac = sys.platform == 'darwin' + # create a temporary registry + for componentUrl in componentUrls: + reg = smgr.createInstanceWithContext( "com.sun.star.registry.SimpleRegistry", contextRuntime ) + reg.open( "", 0, 1 ) + if not isWin and componentUrl.endswith( ".uno" ): # still allow platform independent naming + if isMac: + componentUrl = componentUrl + ".dylib" + else: + componentUrl = componentUrl + ".so" + + implReg.registerImplementation( loaderName,componentUrl, reg ) + rootKey = reg.getRootKey() + implementationKey = rootKey.openKey( "IMPLEMENTATIONS" ) + implNames = implementationKey.getKeyNames() + extSMGR = toBeExtendedContext.ServiceManager + for x in implNames: + fac = loader.activate( max(x.split("/")),"",componentUrl,rootKey) + extSMGR.insert( fac ) + reg.close() + +# never shrinks ! +_g_typeTable = {} +def _unohelper_getHandle( self): + ret = None + if self.__class__ in _g_typeTable: + ret = _g_typeTable[self.__class__] + else: + names = {} + traverse = list(self.__class__.__bases__) + while len( traverse ) > 0: + item = traverse.pop() + bases = item.__bases__ + if uno.isInterface( item ): + names[item.__pyunointerface__] = None + elif len(bases) > 0: + # the "else if", because we only need the most derived interface + traverse = traverse + list(bases)# + + lst = list(names.keys()) + types = [] + for x in lst: + t = uno.getTypeByName( x ) + types.append( t ) + + ret = tuple(types) , uno.generateUuid() + _g_typeTable[self.__class__] = ret + return ret + +class Base(XTypeProvider): + def getTypes( self ): + return _unohelper_getHandle( self )[0] + def getImplementationId(self): + return _unohelper_getHandle( self )[1] + +class CurrentContext(XCurrentContext, Base ): + """a current context implementation, which first does a lookup in the given + hashmap and if the key cannot be found, it delegates to the predecessor + if available + """ + def __init__( self, oldContext, hashMap ): + self.hashMap = hashMap + self.oldContext = oldContext + + def getValueByName( self, name ): + if name in self.hashMap: + return self.hashMap[name] + elif self.oldContext != None: + return self.oldContext.getValueByName( name ) + else: + return None + +# ------------------------------------------------- +# implementation details +# ------------------------------------------------- +class _FactoryHelper_( XSingleComponentFactory, XServiceInfo, Base ): + def __init__( self, clazz, implementationName, serviceNames ): + self.clazz = clazz + self.implementationName = implementationName + self.serviceNames = serviceNames + + def getImplementationName( self ): + return self.implementationName + + def supportsService( self, ServiceName ): + return ServiceName in self.serviceNames + + def getSupportedServiceNames( self ): + return self.serviceNames + + def createInstanceWithContext( self, context ): + return self.clazz( context ) + + def createInstanceWithArgumentsAndContext( self, args, context ): + return self.clazz( context, *args ) + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/pyuno/zipcore/makefile.mk b/pyuno/zipcore/makefile.mk new file mode 100755 index 000000000000..abc42b3b8deb --- /dev/null +++ b/pyuno/zipcore/makefile.mk @@ -0,0 +1,133 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJNAME=pyuno +PRJ=.. + +TARGET=zipcore +LIBTARGET=NO + +.INCLUDE : settings.mk +.IF "$(L10N_framework)"=="" +UWINAPILIB = + +.IF "$(SYSTEM_PYTHON)" == "YES" +systempython: + @echo "Not building python-core because system python is being used" +.ELSE + +.INCLUDE : pyversion.mk + +PYDIRNAME=python-core-$(PYVERSION) +DESTROOT=$(BIN)/$(PYDIRNAME) +.IF "$(GUI)" == "UNX" +PYTHONBINARY=$(BIN)/python$(EXECPOST).bin +.ELSE +.IF "$(COM)" == "GCC" +PYTHONBINARY=$(DESTROOT)/bin/python.bin +.ELSE +PYTHONBINARY=$(DESTROOT)/bin/python$(EXECPOST) +.ENDIF +.ENDIF + +.IF "$(OS)" != "MACOSX" +FINDLIBFILES:=$(subst,$(SOLARLIBDIR)/python, \ + $(shell @$(FIND) $(SOLARLIBDIR)/python -type f| $(GREP) -v "\.pyc" |$(GREP) -v "\.py~" |$(GREP) -v .orig | $(GREP) -v _failed)) + +FILES=\ + $(PYTHONBINARY) \ + $(foreach,i,$(FINDLIBFILES) $(DESTROOT)/lib$(i)) + +.IF "$(OS)" == "WNT" +APP1TARGET=python +APP1OBJS=$(OBJFILES) $(SOLARLIBDIR)/pathutils-obj.obj +APP1STDLIBS= +APP1RPATH=BRAND +OBJFILES=$(OBJ)/python.obj +.ENDIF + + +.INCLUDE: target.mk + +ALLTAR: \ + $(BIN)/$(PYDIRNAME).zip +.ENDIF + +.IF "$(GUI)" == "UNX" +ALLTAR : $(BIN)/python.sh + +STRIPMAC=-e '/^NONMACSECTION/d' -e '/^MACSECTION/,$$d' +STRIPNONMAC=-e '/^NONMACSECTION/,/^MACSECTION/d' + +$(BIN)/python.sh : python.sh + $(COMMAND_ECHO)sed -e 's/%%PYVERSION%%/$(eq,$(OS),MACOSX $(PYMAJOR).$(PYMINOR) $(PYVERSION))/g' -e 's/%%OOO_LIBRARY_PATH_VAR%%/$(OOO_LIBRARY_PATH_VAR)/g' \ + $(eq,$(OS),MACOSX $(STRIPNONMAC) $(STRIPMAC)) < $? > $@ + @chmod +x $@ +.ENDIF + +$(OBJ)/python.obj: $(OUT)/inc/pyversion.hxx + +$(OUT)/inc/pyversion.hxx: pyversion.inc + $(SED) $(USQ)s/@/$(PYVERSION)/g$(USQ) < $< > $@ + +$(BIN)/$(PYDIRNAME).zip : $(FILES) +.IF "$(GUI)" == "UNX" +.IF "$(OS)" != "AIX" + cd $(DESTROOT) && find . -name '*$(DLLPOST)' | xargs strip +.ENDIF +.ENDIF + -rm -f $@ + cd $(BIN) && zip -r $(PYDIRNAME).zip $(PYDIRNAME) + +$(DESTROOT)/lib/% : $(SOLARLIBDIR)/python/% + -$(MKDIRHIER) $(@:d) + -rm -f $@ + cat $< > $@ + +.IF "$(GUI)"== "UNX" +$(BIN)/python$(EXECPOST).bin : $(SOLARBINDIR)/python$(EXECPOST) + -$(MKDIRHIER) $(@:d) + -rm -f $@ + cat $< > $@ +.IF "$(OS)" != "MACOSX" && "$(OS)" != "AIX" + strip $@ +.ENDIF + chmod +x $@ +.ELSE +.IF "$(COM)" == "GCC" +$(DESTROOT)/bin/python.bin : $(SOLARBINDIR)/python$(EXECPOST) +.ELSE +$(DESTROOT)/bin/python$(EXECPOST) : $(SOLARBINDIR)/python$(EXECPOST) +.ENDIF + -$(MKDIRHIER) $(@:d) + -rm -f $@ + cat $< > $@ +.ENDIF + +.ENDIF +.ELSE +.ENDIF # L10N_framework diff --git a/pyuno/zipcore/python.cxx b/pyuno/zipcore/python.cxx new file mode 100644 index 000000000000..68991de1ff26 --- /dev/null +++ b/pyuno/zipcore/python.cxx @@ -0,0 +1,306 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <cstddef> +#include <stdlib.h> +#include <wchar.h> + +#define WIN32_LEAN_AND_MEAN +#if defined _MSC_VER +#pragma warning(push, 1) +#endif +#include <windows.h> +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include "tools/pathutils.hxx" + +#include "pyversion.hxx" + +#define MY_LENGTH(s) (sizeof (s) / sizeof *(s) - 1) +#define MY_STRING(s) (s), MY_LENGTH(s) + +wchar_t * encode(wchar_t * buffer, wchar_t const * text) { + *buffer++ = L'"'; + std::size_t n = 0; + for (;;) { + wchar_t c = *text++; + if (c == L'\0') { + break; + } else if (c == L'"') { + // Double any preceding backslashes as required by Windows: + for (std::size_t i = 0; i < n; ++i) { + *buffer++ = L'\\'; + } + *buffer++ = L'\\'; + *buffer++ = L'"'; + n = 0; + } else if (c == L'\\') { + *buffer++ = L'\\'; + ++n; + } else { + *buffer++ = c; + n = 0; + } + } + // The command line will continue with a double quote, so double any + // preceding backslashes as required by Windows: + for (std::size_t i = 0; i < n; ++i) { + *buffer++ = L'\\'; + } + *buffer++ = L'"'; + return buffer; +} + +#ifdef __MINGW32__ +int main(int argc, char ** argv, char **) { +#else +int wmain(int argc, wchar_t ** argv, wchar_t **) { +#endif + wchar_t path[MAX_PATH]; + DWORD n = GetModuleFileNameW(NULL, path, MAX_PATH); + if (n == 0 || n >= MAX_PATH) { + exit(EXIT_FAILURE); + } + wchar_t * pathEnd = tools::filename(path); + *pathEnd = L'\0'; + n = GetEnvironmentVariableW(L"UNO_PATH", NULL, 0); + if (n == 0) { + if (GetLastError() != ERROR_ENVVAR_NOT_FOUND || + !SetEnvironmentVariableW(L"UNO_PATH", path)) + { + exit(EXIT_FAILURE); + } + } + wchar_t bootstrap[MY_LENGTH(L"vnd.sun.star.pathname:") + MAX_PATH] = + L"vnd.sun.star.pathname:"; //TODO: overflow + wchar_t * bootstrapEnd = tools::buildPath( + bootstrap + MY_LENGTH(L"vnd.sun.star.pathname:"), path, pathEnd, + MY_STRING(L"fundamental.ini")); + if (bootstrapEnd == NULL || + (tools::buildPath(path, path, pathEnd, MY_STRING(L"..\\basis-link")) + == NULL)) + { + exit(EXIT_FAILURE); + } + pathEnd = tools::resolveLink(path); + wchar_t path1[MAX_PATH]; + wchar_t * path1End = tools::buildPath( + path1, path, pathEnd, MY_STRING(L"\\program")); + if (path1End == NULL) { + exit(EXIT_FAILURE); + } + wchar_t pythonpath2[MAX_PATH]; + wchar_t * pythonpath2End = tools::buildPath( + pythonpath2, path, pathEnd, + MY_STRING(L"\\program\\python-core-" MY_PYVERSION L"\\lib")); + if (pythonpath2End == NULL) { + exit(EXIT_FAILURE); + } + wchar_t pythonpath3[MAX_PATH]; + wchar_t * pythonpath3End = tools::buildPath( + pythonpath3, path, pathEnd, + MY_STRING( + L"\\program\\python-core-" MY_PYVERSION L"\\lib\\site-packages")); + if (pythonpath3End == NULL) { + exit(EXIT_FAILURE); + } +#ifdef __MINGW32__ + wchar_t pythonpath4[MAX_PATH]; + wchar_t * pythonpath4End = tools::buildPath( + pythonpath4, path, pathEnd, + MY_STRING(L"\\program\\python-core-" MY_PYVERSION L"\\lib\\lib-dynload")); + if (pythonpath4End == NULL) { + exit(EXIT_FAILURE); + } + wchar_t pythonpath5[MAX_PATH]; + wchar_t * pythonpath5End = tools::buildPath( + pythonpath5, path, pathEnd, + MY_STRING(L"\\program\\python-core-" MY_PYVERSION L"\\lib\\lib-dynload")); + if (pythonpath5End == NULL) { + exit(EXIT_FAILURE); + } +#endif + wchar_t pythonhome[MAX_PATH]; + wchar_t * pythonhomeEnd = tools::buildPath( + pythonhome, path, pathEnd, + MY_STRING(L"\\program\\python-core-" MY_PYVERSION)); + if (pythonhomeEnd == NULL) { + exit(EXIT_FAILURE); + } + wchar_t pythonexe[MAX_PATH]; + wchar_t * pythonexeEnd = tools::buildPath( + pythonexe, path, pathEnd, +#ifdef __MINGW32__ + MY_STRING( + L"\\program\\python-core-" MY_PYVERSION L"\\bin\\python.bin")); +#else + MY_STRING( + L"\\program\\python-core-" MY_PYVERSION L"\\bin\\python.exe")); +#endif + if (pythonexeEnd == NULL) { + exit(EXIT_FAILURE); + } + if (tools::buildPath(path, path, pathEnd, MY_STRING(L"\\ure-link")) == NULL) + { + exit(EXIT_FAILURE); + } + pathEnd = tools::resolveLink(path); + if (pathEnd == NULL) { + exit(EXIT_FAILURE); + } + pathEnd = tools::buildPath(path, path, pathEnd, MY_STRING(L"\\bin")); + if (pathEnd == NULL) { + exit(EXIT_FAILURE); + } + std::size_t clSize = MY_LENGTH(L"\"") + 4 * (pythonexeEnd - pythonexe) + + MY_LENGTH(L"\"\0"); //TODO: overflow + // 4 * len: each char preceded by backslash, each trailing backslash + // doubled + for (int i = 1; i < argc; ++i) { +#ifdef __MINGW32__ + clSize += MY_LENGTH(L" \"") + 4 * strlen(argv[i]) + +#else + clSize += MY_LENGTH(L" \"") + 4 * wcslen(argv[i]) + +#endif + MY_LENGTH(L"\""); //TODO: overflow + } + wchar_t * cl = new wchar_t[clSize]; + if (cl == NULL) { + exit(EXIT_FAILURE); + } + wchar_t * cp = encode(cl, pythonhome); + for (int i = 1; i < argc; ++i) { + *cp++ = L' '; +#ifdef __MINGW32__ + int nNeededWStrBuffSize = MultiByteToWideChar(CP_ACP, 0, argv[i], -1, NULL, 0); + WCHAR *buff = new WCHAR[nNeededWStrBuffSize+1]; + MultiByteToWideChar(CP_ACP, 0, argv[i], -1, buff, nNeededWStrBuffSize); + buff[nNeededWStrBuffSize] = 0; + cp = encode(cp, buff); + delete [] buff; +#else + cp = encode(cp, argv[i]); +#endif + } + *cp = L'\0'; + n = GetEnvironmentVariableW(L"PATH", NULL, 0); + wchar_t * orig; + if (n == 0) { + if (GetLastError() != ERROR_ENVVAR_NOT_FOUND) { + exit(EXIT_FAILURE); + } + orig = L""; + } else { + orig = new wchar_t[n]; + if (orig == NULL || + GetEnvironmentVariableW(L"PATH", orig, n) != n - 1) + { + exit(EXIT_FAILURE); + } + } + wchar_t * value = new wchar_t[ + (pathEnd - path) + MY_LENGTH(L";") + (path1End - path1) + + (n == 0 ? 0 : MY_LENGTH(L";") + (n - 1)) + 1]; //TODO: overflow + wsprintfW(value, L"%s;%s%s%s", path, path1, n == 0 ? L"" : L";", orig); + if (!SetEnvironmentVariableW(L"PATH", value)) { + exit(EXIT_FAILURE); + } + if (n != 0) { + delete [] orig; + } + delete [] value; + n = GetEnvironmentVariableW(L"PYTHONPATH", NULL, 0); + if (n == 0) { + if (GetLastError() != ERROR_ENVVAR_NOT_FOUND) { + exit(EXIT_FAILURE); + } + orig = L""; + } else { + orig = new wchar_t[n]; + if (orig == NULL || + GetEnvironmentVariableW(L"PYTHONPATH", orig, n) != n - 1) + { + exit(EXIT_FAILURE); + } + } +#ifdef __MINGW32__ + value = new wchar_t[ + (path1End - path1) + MY_LENGTH(L";") + (pythonpath2End - pythonpath2) + + MY_LENGTH(L";") + (pythonpath4End - pythonpath4) + + MY_LENGTH(L";") + (pythonpath5End - pythonpath5) + + MY_LENGTH(L";") + (pythonpath3End - pythonpath3) + + (n == 0 ? 0 : MY_LENGTH(L";") + (n - 1)) + 1]; //TODO: overflow + wsprintfW( + value, L"%s;%s;%s;%s;%s%s%s", path1, pythonpath2, pythonpath4, + pythonpath5, pythonpath3, + n == 0 ? L"" : L";", orig); +#else + value = new wchar_t[ + (path1End - path1) + MY_LENGTH(L";") + (pythonpath2End - pythonpath2) + + MY_LENGTH(L";") + (pythonpath3End - pythonpath3) + + (n == 0 ? 0 : MY_LENGTH(L";") + (n - 1)) + 1]; //TODO: overflow + wsprintfW( + value, L"%s;%s;%s%s%s", path1, pythonpath2, pythonpath3, + n == 0 ? L"" : L";", orig); +#endif + if (!SetEnvironmentVariableW(L"PYTHONPATH", value)) { + exit(EXIT_FAILURE); + } + if (n != 0) { + delete [] orig; + } + delete [] value; + if (!SetEnvironmentVariableW(L"PYTHONHOME", pythonhome)) { + exit(EXIT_FAILURE); + } + n = GetEnvironmentVariableW(L"URE_BOOTSTRAP", NULL, 0); + if (n == 0) { + if (GetLastError() != ERROR_ENVVAR_NOT_FOUND || + !SetEnvironmentVariableW(L"URE_BOOTSTRAP", bootstrap)) + { + exit(EXIT_FAILURE); + } + } + STARTUPINFOW startinfo; + ZeroMemory(&startinfo, sizeof (STARTUPINFOW)); + startinfo.cb = sizeof (STARTUPINFOW); + PROCESS_INFORMATION procinfo; + if (!CreateProcessW( + pythonexe, cl, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, NULL, + NULL, &startinfo, &procinfo)) { + exit(EXIT_FAILURE); + } + WaitForSingleObject(procinfo.hProcess,INFINITE); + DWORD exitStatus; + GetExitCodeProcess(procinfo.hProcess,&exitStatus); + exit(exitStatus); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/pyuno/zipcore/python.sh b/pyuno/zipcore/python.sh new file mode 100644 index 000000000000..e32f1370a0d0 --- /dev/null +++ b/pyuno/zipcore/python.sh @@ -0,0 +1,76 @@ +#!/bin/sh +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +# resolve installation directory +sd_cwd="`pwd`" +if [ -h "$0" ] ; then + sd_basename=`basename "$0"` + sd_script=`ls -l "$0" | sed "s/.*${sd_basename} -> //g"` + cd "`dirname "$0"`" + cd "`dirname "$sd_script"`" +else + cd "`dirname "$0"`" +fi +sd_prog=`pwd` +cd "$sd_cwd" + +# Set PATH so that crash_report is found: +PATH=$sd_prog${PATH+:$PATH} +export PATH + +# Set %%OOO_LIBRARY_PATH_VAR%% so that "import pyuno" finds libpyuno.so: +%%OOO_LIBRARY_PATH_VAR%%=$sd_prog/../basis-link/program:$sd_prog/../basis-link/ure-link/lib${%%OOO_LIBRARY_PATH_VAR%%:+:$%%OOO_LIBRARY_PATH_VAR%%} +export %%OOO_LIBRARY_PATH_VAR%% + +# Set UNO_PATH so that "officehelper.bootstrap()" can find soffice executable: +: ${UNO_PATH=$sd_prog} +export UNO_PATH + +# Set URE_BOOTSTRAP so that "uno.getComponentContext()" bootstraps a complete +# OOo UNO environment: +: ${URE_BOOTSTRAP=vnd.sun.star.pathname:$sd_prog/fundamentalrc} +export URE_BOOTSTRAP + +NONMACSECTION +PYTHONPATH=$sd_prog/../basis-link/program:$sd_prog/../basis-link/program/python-core-%%PYVERSION%%/lib:$sd_prog/../basis-link/program/python-core-%%PYVERSION%%/lib/lib-dynload:$sd_prog/../basis-link/program/python-core-%%PYVERSION%%/lib/lib-tk:$sd_prog/../basis-link/program/python-core-%%PYVERSION%%/lib/site-packages${PYTHONPATH+:$PYTHONPATH} +export PYTHONPATH +PYTHONHOME=$sd_prog/../basis-link/program/python-core-%%PYVERSION%% +export PYTHONHOME + +# execute binary +exec "$sd_prog/../basis-link/program/python.bin" "$@" +MACSECTION +PYTHONHOME=$sd_prog/../basis-link/program/OOoPython.framework +export PYTHONHOME + +pybasislibdir=$PYTHONHOME/Versions/%%PYVERSION%%/lib/python%%PYVERSION%% +PYTHONPATH=$sd_prog/../basis-link/program:$pybasislibdir:$pybasislibdir/lib-dynload:$pybasislibdir/lib-tk:$pybasislibdir/site-packages${PYTHONPATH+:$PYTHONPATH} +export PYTHONPATH + +# execute binary +exec "$PYTHONHOME/Versions/%%PYVERSION%%/Resources/Python.app/Contents/MacOS/OOoPython" "$@" diff --git a/pyuno/zipcore/pyversion.inc b/pyuno/zipcore/pyversion.inc new file mode 100644 index 000000000000..de71214717b4 --- /dev/null +++ b/pyuno/zipcore/pyversion.inc @@ -0,0 +1,28 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define MY_PYVERSION L"@" |