| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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> |
| |
| #include <vector> |
| |
| 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::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; |
| |
| namespace pyuno |
| { |
| #define USTR_ASCII(x) OUString( RTL_CONSTASCII_USTRINGPARAM( x ) ) |
| |
| static PyTypeObject RuntimeImpl_Type = |
| { |
| PyVarObject_HEAD_INIT(&PyType_Type, 0) |
| const_cast< char * >("pyuno_runtime"), |
| sizeof (RuntimeImpl), |
| 0, |
| (destructor) RuntimeImpl::del, |
| (printfunc) 0, |
| (getattrfunc) 0, |
| (setattrfunc) 0, |
| #if PY_MAJOR_VERSION >= 3 |
| 0, |
| #else |
| (cmpfunc) 0, |
| #endif |
| (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(const_cast< char * >("__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 ) |
| { |
| PyRef globalDict = PyRef( PyModule_GetDict(PyImport_AddModule(const_cast< char * >("__main__")))); |
| // import the uno module |
| PyRef module( PyImport_ImportModule( const_cast< char * >("uno") ), SAL_NO_ACQUIRE ); |
| if( PyErr_Occurred() ) |
| { |
| PyRef excType, excValue, excTraceback; |
| PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback); |
| PyRef str( PyObject_Repr( 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.append( pyString2ustring( valueRep.get() ) ).appendAscii( ", traceback follows\n" ); |
| buf.append( pyString2ustring( str.get() ) ); |
| 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::createFromAscii( SAL_CONFIGFILE("pyuno") ); |
| rtl::Bootstrap bootstrapHandle( fileName ); |
| |
| OUString str; |
| if( bootstrapHandle.getFrom( USTR_ASCII( "PYUNO_LOGLEVEL" ), str ) ) |
| { |
| if( str.equalsAscii( "NONE" ) ) |
| *pLevel = LogLevel::NONE; |
| else if( str.equalsAscii( "CALL" ) ) |
| *pLevel = LogLevel::CALL; |
| else if( str.equalsAscii( "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.equalsAscii( "stdout" ) ) |
| *ppFile = stdout; |
| else if( str.equalsAscii( "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; |
| #if PY_MAJOR_VERSION >= 3 |
| return PyRef( PyLong_FromLong (l), SAL_NO_ACQUIRE ); |
| #else |
| return PyRef( PyInt_FromLong (l), SAL_NO_ACQUIRE ); |
| #endif |
| } |
| 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 = USTR_TO_PYSTR( 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(), const_cast< char * >("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 , const_cast< char * >("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 ) |
| { |
| |
| } |
| #if PY_MAJOR_VERSION >= 3 // Python 3 has no PyInt |
| else if (PyBool_Check(o)) |
| { |
| if( o == Py_True ) |
| { |
| sal_Bool b = sal_True; |
| a = Any( &b, getBooleanCppuType() ); |
| } |
| else |
| { |
| sal_Bool b = sal_False; |
| a = Any( &b, getBooleanCppuType() ); |
| } |
| } |
| #else |
| 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) PyInt_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 // Python 3 has no PyInt |
| else if (PyLong_Check (o)) |
| { |
| 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; |
| } |
| } |
| else if (PyFloat_Check (o)) |
| { |
| double d = PyFloat_AsDouble (o); |
| a <<= d; |
| } |
| #if PY_MAJOR_VERSION < 3 |
| else if (PyBytes_Check (o)) |
| a <<= pyString2ustring(o); |
| #endif |
| else if( 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 , const_cast< char * >("value") ),SAL_NO_ACQUIRE); |
| Sequence< sal_Int8 > seq; |
| if( PyBytes_Check( str.get() ) ) |
| { |
| seq = Sequence<sal_Int8 > ( |
| (sal_Int8*) PyBytes_AsString(str.get()), PyBytes_Size(str.get())); |
| } |
| #if PY_MAJOR_VERSION >= 3 |
| else if ( PyByteArray_Check( str.get() ) ) |
| { |
| seq = Sequence< sal_Int8 >( |
| (sal_Int8 *) PyByteArray_AS_STRING(str.get()), PyByteArray_GET_SIZE(str.get())); |
| } |
| #endif |
| 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 , const_cast< char * >("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().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 , const_cast< char * >("value") ), SAL_NO_ACQUIRE) ); |
| Type t; |
| pyObject2Any( PyRef( PyObject_GetAttrString( o, const_cast< char * >("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.append( pyString2ustring( 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 |
| { |
| PyRef str; |
| Any ret; |
| if( excTraceback.is() ) |
| { |
| PyRef unoModule( impl ? impl->cargo->getUnoModule() : 0 ); |
| if( unoModule.is() ) |
| { |
| PyRef extractTraceback( |
| PyDict_GetItemString(unoModule.get(),"_uno_extract_printable_stacktrace" ) ); |
| |
| if( extractTraceback.is() ) |
| { |
| PyRef args( PyTuple_New( 1), SAL_NO_ACQUIRE ); |
| PyTuple_SetItem( args.get(), 0, excTraceback.getAcquired() ); |
| str = PyRef( PyObject_CallObject( extractTraceback.get(),args.get() ), SAL_NO_ACQUIRE); |
| } |
| else |
| { |
| str = PyRef( |
| PyBytes_FromString( "Couldn't find uno._uno_extract_printable_stacktrace" ), |
| SAL_NO_ACQUIRE ); |
| } |
| } |
| else |
| { |
| str = PyRef( |
| PyBytes_FromString( "Couldn't find uno.py, no stacktrace available" ), |
| SAL_NO_ACQUIRE ); |
| } |
| |
| } |
| else |
| { |
| // it may occur, that no traceback is given (e.g. only native code below) |
| str = PyRef( PyBytes_FromString( "no traceback available" ), SAL_NO_ACQUIRE); |
| } |
| |
| if( isInstanceOfStructOrException( excValue.get() ) ) |
| { |
| ret = pyObject2Any( excValue ); |
| } |
| else |
| { |
| OUStringBuffer buf; |
| PyRef typeName( PyObject_Str( excType.get() ), SAL_NO_ACQUIRE ); |
| if( typeName.is() ) |
| { |
| buf.append( pyString2ustring( typeName.get() ) ); |
| } |
| else |
| { |
| buf.appendAscii( "no typename available" ); |
| } |
| buf.appendAscii( ": " ); |
| PyRef valueRep( PyObject_Str( excValue.get() ), SAL_NO_ACQUIRE ); |
| if( valueRep.is() ) |
| { |
| buf.append( pyString2ustring( valueRep.get())); |
| } |
| else |
| { |
| buf.appendAscii( "Couldn't convert exception value to a string" ); |
| } |
| buf.appendAscii( ", traceback follows\n" ); |
| if( str.is() ) |
| { |
| buf.append( pyString2ustring( str.get() ) ); |
| } |
| 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; |
| } |
| } |