diff options
Diffstat (limited to 'pyuno/source/module/pyuno_runtime.cxx')
-rw-r--r-- | pyuno/source/module/pyuno_runtime.cxx | 1058 |
1 files changed, 1058 insertions, 0 deletions
diff --git a/pyuno/source/module/pyuno_runtime.cxx b/pyuno/source/module/pyuno_runtime.cxx new file mode 100644 index 000000000000..754ce05e599e --- /dev/null +++ b/pyuno/source/module/pyuno_runtime.cxx @@ -0,0 +1,1058 @@ +/************************************************************************* + * + * 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::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 = +{ + PyObject_HEAD_INIT (&PyType_Type) + 0, + const_cast< char * >("pyuno_runtime"), + sizeof (RuntimeImpl), + 0, + (destructor) RuntimeImpl::del, + (printfunc) 0, + (getattrfunc) 0, + (setattrfunc) 0, + (cmpfunc) 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(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.appendAscii( PyString_AsString( valueRep.get())).appendAscii( ", traceback follows\n" ); + buf.appendAscii( PyString_AsString( 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; + return PyRef( PyInt_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(), 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 ) + { + + } + 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; + } + } + } + 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; + } + else if (PyString_Check (o)) + a <<= pyString2ustring(o); + 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( 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 , 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( 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 , 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.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 +{ + 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( + PyString_FromString( "Couldn't find uno._uno_extract_printable_stacktrace" ), + SAL_NO_ACQUIRE ); + } + } + else + { + str = PyRef( + PyString_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( PyString_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.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.is() ) + { + buf.appendAscii( PyString_AsString( 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; +} +} |