xref: /trunk/main/pyuno/source/module/pyuno_runtime.cxx (revision 27dee00ef8b391d4d520b7edb65b4093b02f83ed)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "pyuno_impl.hxx"
25 
26 #include <osl/thread.h>
27 #include <osl/module.h>
28 #include <osl/process.h>
29 #include <rtl/strbuf.hxx>
30 #include <rtl/ustrbuf.hxx>
31 #include <rtl/bootstrap.hxx>
32 #include <locale.h>
33 
34 #include <typelib/typedescription.hxx>
35 
36 #include <com/sun/star/beans/XMaterialHolder.hpp>
37 
38 #include <vector>
39 
40 using rtl::OUString;
41 using rtl::OUStringToOString;
42 using rtl::OUStringBuffer;
43 using rtl::OStringBuffer;
44 using rtl::OString;
45 
46 using com::sun::star::uno::Reference;
47 using com::sun::star::uno::XInterface;
48 using com::sun::star::uno::Any;
49 using com::sun::star::uno::TypeDescription;
50 using com::sun::star::uno::Sequence;
51 using com::sun::star::uno::Type;
52 using com::sun::star::uno::UNO_QUERY;
53 using com::sun::star::uno::RuntimeException;
54 using com::sun::star::uno::XComponentContext;
55 using com::sun::star::lang::XSingleServiceFactory;
56 using com::sun::star::lang::XUnoTunnel;
57 using com::sun::star::reflection::XIdlReflection;
58 using com::sun::star::script::XTypeConverter;
59 using com::sun::star::script::XInvocationAdapterFactory2;
60 using com::sun::star::script::XInvocation;
61 using com::sun::star::beans::XMaterialHolder;
62 using com::sun::star::beans::XIntrospection;
63 
64 namespace pyuno
65 {
66 #define USTR_ASCII(x) OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
67 
68 static PyTypeObject RuntimeImpl_Type =
69 {
70     PyVarObject_HEAD_INIT(&PyType_Type, 0)
71     const_cast< char * >("pyuno_runtime"),
72     sizeof (RuntimeImpl),
73     0,
74     (destructor) RuntimeImpl::del,
75     (printfunc) 0,
76     (getattrfunc) 0,
77     (setattrfunc) 0,
78     0,
79     (reprfunc) 0,
80     0,
81     0,
82     0,
83     (hashfunc) 0,
84     (ternaryfunc) 0,
85     (reprfunc) 0,
86     (getattrofunc)0,
87     (setattrofunc)0,
88     NULL,
89     0,
90     NULL,
91     (traverseproc)0,
92     (inquiry)0,
93     (richcmpfunc)0,
94     0,
95     (getiterfunc)0,
96     (iternextfunc)0,
97     NULL,
98     NULL,
99     NULL,
100     NULL,
101     NULL,
102     (descrgetfunc)0,
103     (descrsetfunc)0,
104     0,
105     (initproc)0,
106     (allocfunc)0,
107     (newfunc)0,
108     (freefunc)0,
109     (inquiry)0,
110     NULL,
111     NULL,
112     NULL,
113     NULL,
114     NULL,
115     (destructor)0,
116     0
117 };
118 
119 /*----------------------------------------------------------------------
120   Runtime implementation
121  -----------------------------------------------------------------------*/
getRuntimeImpl(PyRef & globalDict,PyRef & runtimeImpl)122 static void getRuntimeImpl( PyRef & globalDict, PyRef &runtimeImpl )
123     throw ( com::sun::star::uno::RuntimeException )
124 {
125     PyThreadState * state = PyThreadState_Get();
126     if( ! state )
127     {
128         throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM(
129             "python global interpreter must be held (thread must be attached)" )),
130                                 Reference< XInterface > () );
131     }
132 
133     globalDict = PyRef( PyModule_GetDict(PyImport_AddModule(const_cast< char * >("__main__"))));
134 
135     if( ! globalDict.is() ) // FATAL !
136     {
137         throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM(
138             "can't find __main__ module" )), Reference< XInterface > ());
139     }
140     runtimeImpl = PyDict_GetItemString( globalDict.get() , "pyuno_runtime" );
141 }
142 
importUnoModule()143 static PyRef importUnoModule( ) throw ( RuntimeException )
144 {
145     PyRef globalDict = PyRef( PyModule_GetDict(PyImport_AddModule(const_cast< char * >("__main__"))));
146     // import the uno module
147     PyRef module( PyImport_ImportModule( const_cast< char * >("uno") ), SAL_NO_ACQUIRE );
148     if( PyErr_Occurred() )
149     {
150         PyRef excType, excValue, excTraceback;
151         PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
152         PyRef str( PyObject_Repr( excTraceback.get() ), SAL_NO_ACQUIRE );
153 
154         OUStringBuffer buf;
155         buf.appendAscii( "python object raised an unknown exception (" );
156         PyRef valueRep( PyObject_Repr( excValue.get() ), SAL_NO_ACQUIRE );
157 
158         buf.append( pyString2ustring( valueRep.get() ) ).appendAscii( ", traceback follows\n" );
159         buf.append( pyString2ustring( str.get() ) );
160         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () );
161     }
162     PyRef dict( PyModule_GetDict( module.get() ) );
163     return dict;
164 }
165 
readLoggingConfig(sal_Int32 * pLevel,FILE ** ppFile)166 static void readLoggingConfig( sal_Int32 *pLevel, FILE **ppFile )
167 {
168     *pLevel = LogLevel::NONE;
169     *ppFile = 0;
170     OUString fileName;
171     osl_getModuleURLFromFunctionAddress(
172         reinterpret_cast< oslGenericFunction >(readLoggingConfig),
173         (rtl_uString **) &fileName );
174     fileName = OUString( fileName.getStr(), fileName.lastIndexOf( '/' )+1 );
175     fileName += OUString::createFromAscii(  SAL_CONFIGFILE("pyuno") );
176     rtl::Bootstrap bootstrapHandle( fileName );
177 
178     OUString str;
179     if( bootstrapHandle.getFrom( USTR_ASCII( "PYUNO_LOGLEVEL" ), str ) )
180     {
181         if( str.equalsAscii( "NONE" ) )
182             *pLevel = LogLevel::NONE;
183         else if( str.equalsAscii( "CALL" ) )
184             *pLevel = LogLevel::CALL;
185         else if( str.equalsAscii( "ARGS" ) )
186             *pLevel = LogLevel::ARGS;
187         else
188         {
189             fprintf( stderr, "unknown loglevel %s\n",
190                      OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
191         }
192     }
193     if( *pLevel > LogLevel::NONE )
194     {
195         *ppFile = stdout;
196         if( bootstrapHandle.getFrom( USTR_ASCII( "PYUNO_LOGTARGET" ), str ) )
197         {
198             if( str.equalsAscii( "stdout" ) )
199                 *ppFile = stdout;
200             else if( str.equalsAscii( "stderr" ) )
201                 *ppFile = stderr;
202             else
203             {
204                 oslProcessInfo data;
205                 data.Size = sizeof( data );
206                 osl_getProcessInfo(
207                     0 , osl_Process_IDENTIFIER , &data );
208                 osl_getSystemPathFromFileURL( str.pData, &str.pData);
209                 OString o = OUStringToOString( str, osl_getThreadTextEncoding() );
210                 o += ".";
211                 o += OString::valueOf( (sal_Int32)data.Ident );
212 
213                 *ppFile = fopen( o.getStr() , "w" );
214                 if ( *ppFile )
215                 {
216                     // do not buffer (useful if e.g. analyzing a crash)
217                     setvbuf( *ppFile, 0, _IONBF, 0 );
218                 }
219                 else
220                 {
221                     fprintf( stderr, "couldn't create file %s\n",
222                              OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
223 
224                 }
225             }
226         }
227     }
228 }
229 
230 /*-------------------------------------------------------------------
231  RuntimeImpl implementations
232  *-------------------------------------------------------------------*/
create(const Reference<XComponentContext> & ctx)233 PyRef stRuntimeImpl::create( const Reference< XComponentContext > &ctx )
234     throw( com::sun::star::uno::RuntimeException )
235 {
236     RuntimeImpl *me = PyObject_New (RuntimeImpl, &RuntimeImpl_Type);
237     if( ! me )
238         throw RuntimeException(
239             OUString( RTL_CONSTASCII_USTRINGPARAM( "cannot instantiate pyuno::RuntimeImpl" ) ),
240             Reference< XInterface > () );
241     me->cargo = 0;
242     // must use a different struct here, as the PyObject_New
243     // makes C++ unusable
244     RuntimeCargo *c = new RuntimeCargo();
245     readLoggingConfig( &(c->logLevel) , &(c->logFile) );
246     log( c, LogLevel::CALL, "Instantiating pyuno bridge" );
247 
248     c->valid = 1;
249     c->xContext = ctx;
250     c->xInvocation = Reference< XSingleServiceFactory > (
251         ctx->getServiceManager()->createInstanceWithContext(
252             OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.script.Invocation" ) ),
253             ctx ),
254         UNO_QUERY );
255     if( ! c->xInvocation.is() )
256         throw RuntimeException(
257             OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate invocation service" ) ),
258             Reference< XInterface > () );
259 
260     c->xTypeConverter = Reference< XTypeConverter > (
261         ctx->getServiceManager()->createInstanceWithContext(
262             OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.script.Converter" ) ),
263             ctx ),
264         UNO_QUERY );
265     if( ! c->xTypeConverter.is() )
266         throw RuntimeException(
267             OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate typeconverter service" )),
268             Reference< XInterface > () );
269 
270     c->xCoreReflection = Reference< XIdlReflection > (
271         ctx->getServiceManager()->createInstanceWithContext(
272             OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.reflection.CoreReflection" ) ),
273             ctx ),
274         UNO_QUERY );
275     if( ! c->xCoreReflection.is() )
276         throw RuntimeException(
277             OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate corereflection service" )),
278             Reference< XInterface > () );
279 
280     c->xAdapterFactory = Reference< XInvocationAdapterFactory2 > (
281         ctx->getServiceManager()->createInstanceWithContext(
282             OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.script.InvocationAdapterFactory" ) ),
283             ctx ),
284         UNO_QUERY );
285     if( ! c->xAdapterFactory.is() )
286         throw RuntimeException(
287             OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate invocation adapter factory service" )),
288             Reference< XInterface > () );
289 
290     c->xIntrospection = Reference< XIntrospection > (
291         ctx->getServiceManager()->createInstanceWithContext(
292             OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.Introspection" ) ),
293             ctx ),
294         UNO_QUERY );
295     if( ! c->xIntrospection.is() )
296         throw RuntimeException(
297             OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't instantiate introspection service" )),
298             Reference< XInterface > () );
299 
300     Any a = ctx->getValueByName(OUString(
301         RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.reflection.theTypeDescriptionManager" )) );
302     a >>= c->xTdMgr;
303     if( ! c->xTdMgr.is() )
304         throw RuntimeException(
305             OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: couldn't retrieve typedescriptionmanager" )),
306             Reference< XInterface > () );
307 
308     me->cargo =c;
309     return PyRef( reinterpret_cast< PyObject * > ( me ), SAL_NO_ACQUIRE );
310 }
311 
del(PyObject * self)312 void  stRuntimeImpl::del(PyObject* self)
313 {
314     RuntimeImpl *me = reinterpret_cast< RuntimeImpl * > ( self );
315     if( me->cargo->logFile )
316         fclose( me->cargo->logFile );
317     delete me->cargo;
318     PyObject_Del (self);
319 }
320 
321 
initialize(const Reference<XComponentContext> & ctx)322 void Runtime::initialize( const Reference< XComponentContext > & ctx )
323     throw ( RuntimeException )
324 {
325     PyRef globalDict, runtime;
326     getRuntimeImpl( globalDict , runtime );
327     RuntimeImpl *impl = reinterpret_cast< RuntimeImpl * > (runtime.get());
328 
329     if( runtime.is() && impl->cargo->valid )
330     {
331         throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM(
332             "pyuno runtime has already been initialized before" ) ),
333                                 Reference< XInterface > () );
334     }
335     PyRef keep( RuntimeImpl::create( ctx ) );
336     PyDict_SetItemString( globalDict.get(), "pyuno_runtime" , keep.get() );
337     Py_XINCREF( keep.get() );
338 }
339 
340 
isInitialized()341 bool Runtime::isInitialized() throw ( RuntimeException )
342 {
343     PyRef globalDict, runtime;
344     getRuntimeImpl( globalDict , runtime );
345     RuntimeImpl *impl = reinterpret_cast< RuntimeImpl * > (runtime.get());
346     return runtime.is() && impl->cargo->valid;
347 }
348 
finalize()349 void Runtime::finalize() throw (RuntimeException)
350 {
351     PyRef globalDict, runtime;
352     getRuntimeImpl( globalDict , runtime );
353     RuntimeImpl *impl = reinterpret_cast< RuntimeImpl * > (runtime.get());
354     if( !runtime.is() || ! impl->cargo->valid )
355     {
356         throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM(
357             "pyuno bridge must have been initialized before finalizing" )),
358                                 Reference< XInterface > () );
359     }
360     impl->cargo->valid = false;
361     impl->cargo->xInvocation.clear();
362     impl->cargo->xContext.clear();
363     impl->cargo->xTypeConverter.clear();
364 }
365 
Runtime()366 Runtime::Runtime() throw(  RuntimeException )
367     : impl( 0 )
368 {
369     PyRef globalDict, runtime;
370     getRuntimeImpl( globalDict , runtime );
371     if( ! runtime.is() )
372     {
373         throw RuntimeException(
374             OUString( RTL_CONSTASCII_USTRINGPARAM("pyuno runtime is not initialized, "
375                                                   "(the pyuno.bootstrap needs to be called before using any uno classes)")),
376             Reference< XInterface > () );
377     }
378     impl = reinterpret_cast< RuntimeImpl * > (runtime.get());
379     Py_XINCREF( runtime.get() );
380 }
381 
Runtime(const Runtime & r)382 Runtime::Runtime( const Runtime & r )
383 {
384     impl = r.impl;
385     Py_XINCREF( reinterpret_cast< PyObject * >(impl) );
386 }
387 
~Runtime()388 Runtime::~Runtime()
389 {
390     Py_XDECREF( reinterpret_cast< PyObject * >(impl) );
391 }
392 
operator =(const Runtime & r)393 Runtime & Runtime::operator = ( const Runtime & r )
394 {
395     PyRef temp( reinterpret_cast< PyObject * >(r.impl) );
396     Py_XINCREF( temp.get() );
397     Py_XDECREF( reinterpret_cast< PyObject * >(impl) );
398     impl = r.impl;
399     return *this;
400 }
401 
any2PyObject(const Any & a) const402 PyRef Runtime::any2PyObject (const Any &a ) const
403     throw ( com::sun::star::script::CannotConvertException,
404             com::sun::star::lang::IllegalArgumentException,
405             RuntimeException)
406 {
407     if( ! impl->cargo->valid )
408     {
409         throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM(
410             "pyuno runtime must be initialized before calling any2PyObject" )),
411                                 Reference< XInterface > () );
412     }
413 
414     switch (a.getValueTypeClass ())
415     {
416     case typelib_TypeClass_VOID:
417     {
418         Py_INCREF (Py_None);
419         return PyRef(Py_None);
420     }
421     case typelib_TypeClass_CHAR:
422     {
423         sal_Unicode c = *(sal_Unicode*)a.getValue();
424         return PyRef( PyUNO_char_new( c , *this ), SAL_NO_ACQUIRE );
425     }
426     case typelib_TypeClass_BOOLEAN:
427     {
428         sal_Bool b = sal_Bool();
429         if ((a >>= b) && b)
430             return Py_True;
431         else
432             return Py_False;
433     }
434     case typelib_TypeClass_BYTE:
435     case typelib_TypeClass_SHORT:
436     case typelib_TypeClass_UNSIGNED_SHORT:
437     case typelib_TypeClass_LONG:
438     {
439         sal_Int32 l = 0;
440         a >>= l;
441         return PyRef( PyLong_FromLong (l), SAL_NO_ACQUIRE );
442     }
443     case typelib_TypeClass_UNSIGNED_LONG:
444     {
445         sal_uInt32 l = 0;
446         a >>= l;
447         return PyRef( PyLong_FromUnsignedLong (l), SAL_NO_ACQUIRE );
448     }
449     case typelib_TypeClass_HYPER:
450     {
451         sal_Int64 l = 0;
452         a >>= l;
453         return PyRef( PyLong_FromLongLong (l), SAL_NO_ACQUIRE);
454     }
455     case typelib_TypeClass_UNSIGNED_HYPER:
456     {
457         sal_uInt64 l = 0;
458         a >>= l;
459         return PyRef( PyLong_FromUnsignedLongLong (l), SAL_NO_ACQUIRE);
460     }
461     case typelib_TypeClass_FLOAT:
462     {
463         float f = 0.0;
464         a >>= f;
465         return PyRef(PyFloat_FromDouble (f), SAL_NO_ACQUIRE);
466     }
467     case typelib_TypeClass_DOUBLE:
468     {
469         double d = 0.0;
470         a >>= d;
471         return PyRef( PyFloat_FromDouble (d), SAL_NO_ACQUIRE);
472     }
473     case typelib_TypeClass_STRING:
474     {
475         OUString tmp_ostr;
476         a >>= tmp_ostr;
477         return ustring2PyUnicode( tmp_ostr );
478     }
479     case typelib_TypeClass_TYPE:
480     {
481         Type t;
482         a >>= t;
483         OString o = OUStringToOString( t.getTypeName(), RTL_TEXTENCODING_ASCII_US );
484         return PyRef(
485             PyUNO_Type_new (
486                 o.getStr(),  (com::sun::star::uno::TypeClass)t.getTypeClass(), *this),
487             SAL_NO_ACQUIRE);
488     }
489     case typelib_TypeClass_ANY:
490     {
491         //I don't think this can happen.
492         Py_INCREF (Py_None);
493         return Py_None;
494     }
495     case typelib_TypeClass_ENUM:
496     {
497         sal_Int32 l = *(sal_Int32 *) a.getValue();
498         TypeDescription desc( a.getValueType() );
499         if( desc.is() )
500         {
501             desc.makeComplete();
502             typelib_EnumTypeDescription *pEnumDesc =
503                 (typelib_EnumTypeDescription *) desc.get();
504             for( int i = 0 ; i < pEnumDesc->nEnumValues ; i ++ )
505             {
506                 if( pEnumDesc->pEnumValues[i] == l )
507                 {
508                     OString v = OUStringToOString( pEnumDesc->ppEnumNames[i], RTL_TEXTENCODING_ASCII_US);
509                     OString e = OUStringToOString( pEnumDesc->aBase.pTypeName, RTL_TEXTENCODING_ASCII_US);
510                     return PyRef( PyUNO_Enum_new(e.getStr(),v.getStr(), *this ), SAL_NO_ACQUIRE );
511                 }
512             }
513         }
514         OUStringBuffer buf;
515         buf.appendAscii( "Any carries enum " );
516         buf.append( a.getValueType().getTypeName());
517         buf.appendAscii( " with invalid value " ).append( l );
518         throw RuntimeException( buf.makeStringAndClear() , Reference< XInterface > ()  );
519     }
520     case typelib_TypeClass_EXCEPTION:
521     case typelib_TypeClass_STRUCT:
522     {
523         PyRef excClass = getClass( a.getValueType().getTypeName(), *this );
524         PyRef value = PyRef( PyUNO_new_UNCHECKED (a, getImpl()->cargo->xInvocation), SAL_NO_ACQUIRE);
525         PyRef argsTuple( PyTuple_New( 1 ) , SAL_NO_ACQUIRE );
526         PyTuple_SetItem( argsTuple.get() , 0 , value.getAcquired() );
527         PyRef ret( PyObject_CallObject( excClass.get() , argsTuple.get() ), SAL_NO_ACQUIRE );
528         if( ! ret.is() )
529         {
530             OUStringBuffer buf;
531             buf.appendAscii( "Couldn't instantiate python representation of structured UNO type " );
532             buf.append( a.getValueType().getTypeName() );
533             throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () );
534         }
535 
536         if( com::sun::star::uno::TypeClass_EXCEPTION == a.getValueTypeClass() )
537         {
538             // add the message in a standard python way !
539             PyRef args( PyTuple_New( 1 ), SAL_NO_ACQUIRE );
540 
541             // assuming that the Message is always the first member, wuuuu
542             void *pData = (void*)a.getValue();
543             OUString message = *(OUString * )pData;
544             PyRef pymsg = USTR_TO_PYSTR( message );
545             PyTuple_SetItem( args.get(), 0 , pymsg.getAcquired() );
546             // the exception base functions want to have an "args" tuple,
547             // which contains the message
548             PyObject_SetAttrString( ret.get(), const_cast< char * >("args"), args.get() );
549         }
550         return ret;
551     }
552     case typelib_TypeClass_SEQUENCE:
553     {
554         Sequence<Any> s;
555 
556         Sequence< sal_Int8 > byteSequence;
557         if( a >>= byteSequence )
558         {
559             // byte sequence is treated in a special way because of peformance reasons
560             // @since 0.9.2
561             return PyRef( PyUNO_ByteSequence_new( byteSequence, *this ), SAL_NO_ACQUIRE );
562         }
563         else
564         {
565             Reference< XTypeConverter > tc = getImpl()->cargo->xTypeConverter;
566             Reference< XSingleServiceFactory > ssf = getImpl()->cargo->xInvocation;
567             tc->convertTo (a, ::getCppuType (&s)) >>= s;
568             PyRef tuple( PyTuple_New (s.getLength()), SAL_NO_ACQUIRE);
569             int i=0;
570             OUString errMsg;
571             try
572             {
573                 for ( i = 0; i < s.getLength (); i++)
574                 {
575                     PyRef element;
576                     element = any2PyObject (tc->convertTo (s[i], s[i].getValueType() ));
577                     OSL_ASSERT( element.is() );
578                     PyTuple_SetItem( tuple.get(), i, element.getAcquired() );
579                 }
580             }
581             catch( com::sun::star::uno::Exception & )
582             {
583                 for( ; i < s.getLength() ; i ++ )
584                 {
585                     Py_INCREF( Py_None );
586                     PyTuple_SetItem( tuple.get(), i,  Py_None );
587                 }
588                 throw;
589             }
590             return tuple;
591         }
592     }
593     case typelib_TypeClass_INTERFACE:
594     {
595         Reference< XUnoTunnel > tunnel;
596         a >>= tunnel;
597         if( tunnel.is() )
598         {
599             sal_Int64 that = tunnel->getSomething( ::pyuno::Adapter::getUnoTunnelImplementationId() );
600             if( that )
601                 return ((Adapter*)sal::static_int_cast< sal_IntPtr >(that))->getWrappedObject();
602         }
603         //This is just like the struct case:
604         return PyRef( PyUNO_new (a, getImpl()->cargo->xInvocation), SAL_NO_ACQUIRE );
605     }
606     default:
607     {
608         OUStringBuffer buf;
609         buf.appendAscii( "Unknown UNO type class " );
610         buf.append( (sal_Int32 ) a.getValueTypeClass() );
611         throw RuntimeException(buf.makeStringAndClear( ), Reference< XInterface > () );
612     }
613     }
614     //We shouldn't be here...
615     Py_INCREF( Py_None );
616     return Py_None;
617 }
618 
invokeGetTypes(const Runtime & r,PyObject * o)619 static Sequence< Type > invokeGetTypes( const Runtime & r , PyObject * o )
620 {
621     Sequence< Type > ret;
622 
623     PyRef method( PyObject_GetAttrString( o , const_cast< char * >("getTypes") ), SAL_NO_ACQUIRE );
624     raiseInvocationTargetExceptionWhenNeeded( r );
625     if( method.is() && PyCallable_Check( method.get() ) )
626     {
627         PyRef types( PyObject_CallObject( method.get(), 0 ) , SAL_NO_ACQUIRE );
628         raiseInvocationTargetExceptionWhenNeeded( r );
629         if( types.is() && PyTuple_Check( types.get() ) )
630         {
631             int size = PyTuple_Size( types.get() );
632 
633             // add the XUnoTunnel interface  for uno object identity concept (hack)
634             ret.realloc( size + 1 );
635             for( int i = 0 ; i < size ; i ++ )
636             {
637                 Any a = r.pyObject2Any(PyTuple_GetItem(types.get(),i));
638                 a >>= ret[i];
639             }
640             ret[size] = getCppuType( (Reference< com::sun::star::lang::XUnoTunnel> *) 0 );
641         }
642     }
643     return ret;
644 }
645 
pyObject2Any(const PyRef & source,enum ConversionMode mode) const646 Any Runtime::pyObject2Any ( const PyRef & source, enum ConversionMode mode ) const
647     throw ( com::sun::star::uno::RuntimeException )
648 {
649     if( ! impl->cargo->valid )
650     {
651         throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM(
652             "pyuno runtime must be initialized before calling any2PyObject" )),
653                                 Reference< XInterface > () );
654     }
655 
656     Any a;
657     PyObject *o = source.get();
658     if( Py_None == o )
659     {
660 
661     }
662     else if (PyBool_Check(o))
663     {
664         if( o == Py_True )
665         {
666             sal_Bool b = sal_True;
667             a = Any( &b, getBooleanCppuType() );
668         }
669         else
670         {
671             sal_Bool b = sal_False;
672             a = Any( &b, getBooleanCppuType() );
673         }
674     }
675     else if (PyLong_Check (o))
676     {
677         sal_Int64 l = (sal_Int64)PyLong_AsLong (o);
678         if( l < 128 && l >= -128 )
679         {
680             sal_Int8 b = (sal_Int8 ) l;
681             a <<= b;
682         }
683         else if( l <= 0x7fff && l >= -0x8000 )
684         {
685             sal_Int16 s = (sal_Int16) l;
686             a <<= s;
687         }
688         else if( l <= SAL_CONST_INT64(0x7fffffff) &&
689                  l >= -SAL_CONST_INT64(0x80000000) )
690         {
691             sal_Int32 l32 = (sal_Int32) l;
692             a <<= l32;
693         }
694         else
695         {
696             a <<= l;
697         }
698     }
699     else if (PyFloat_Check (o))
700     {
701         double d = PyFloat_AsDouble (o);
702         a <<= d;
703     }
704     else if( PyUnicode_Check( o ) )
705     a <<= pyString2ustring(o);
706     else if (PyTuple_Check (o))
707     {
708         Sequence<Any> s (PyTuple_Size (o));
709         for (int i = 0; i < PyTuple_Size (o); i++)
710         {
711             s[i] = pyObject2Any (PyTuple_GetItem (o, i), mode );
712         }
713         a <<= s;
714     }
715     else
716     {
717         Runtime runtime;
718         // should be removed, in case ByteSequence gets derived from String
719         if( PyObject_IsInstance( o, getByteSequenceClass( runtime ).get() ) )
720         {
721             PyRef str(PyObject_GetAttrString( o , const_cast< char * >("value") ),SAL_NO_ACQUIRE);
722             Sequence< sal_Int8 > seq;
723             if( PyBytes_Check( str.get() ) )
724             {
725                 seq = Sequence<sal_Int8 > (
726                     (sal_Int8*) PyBytes_AsString(str.get()), PyBytes_Size(str.get()));
727             }
728             else if ( PyByteArray_Check( str.get() ) )
729             {
730                 seq = Sequence< sal_Int8 >(
731                     (sal_Int8 *) PyByteArray_AS_STRING(str.get()), PyByteArray_GET_SIZE(str.get()));
732             }
733             a <<= seq;
734         }
735         else
736         if( PyObject_IsInstance( o, getTypeClass( runtime ).get() ) )
737         {
738             Type t = PyType2Type( o );
739             a <<= t;
740         }
741         else if( PyObject_IsInstance( o, getEnumClass( runtime ).get() ) )
742         {
743             a = PyEnum2Enum( o );
744         }
745         else if( isInstanceOfStructOrException( o ) )
746         {
747             PyRef struc(PyObject_GetAttrString( o , const_cast< char * >("value") ),SAL_NO_ACQUIRE);
748             PyUNO * obj = (PyUNO*)struc.get();
749             Reference< XMaterialHolder > holder( obj->members->xInvocation, UNO_QUERY );
750             if( holder.is( ) )
751                 a = holder->getMaterial();
752             else
753             {
754                 throw RuntimeException(
755                     USTR_ASCII( "struct or exception wrapper does not support XMaterialHolder" ),
756                     Reference< XInterface > () );
757             }
758         }
759         else if( PyObject_IsInstance( o, getPyUnoClass().get() ) )
760         {
761             PyUNO* o_pi;
762             o_pi = (PyUNO*) o;
763             if (o_pi->members->wrappedObject.getValueTypeClass () ==
764                 com::sun::star::uno::TypeClass_STRUCT ||
765                 o_pi->members->wrappedObject.getValueTypeClass () ==
766                 com::sun::star::uno::TypeClass_EXCEPTION)
767             {
768                 Reference<XMaterialHolder> my_mh (o_pi->members->xInvocation, UNO_QUERY);
769 
770                 if (!my_mh.is ())
771                 {
772                     throw RuntimeException(
773                         USTR_ASCII( "struct wrapper does not support XMaterialHolder" ),
774                         Reference< XInterface > () );
775                 }
776                 else
777                     a = my_mh->getMaterial ();
778             }
779             else
780             {
781                 a = o_pi->members->wrappedObject;
782             }
783         }
784         else if( PyObject_IsInstance( o, getCharClass( runtime ).get() ) )
785         {
786             sal_Unicode c = PyChar2Unicode( o );
787             a.setValue( &c, getCharCppuType( ));
788         }
789         else if( PyObject_IsInstance( o, getAnyClass( runtime ).get() ) )
790         {
791             if( ACCEPT_UNO_ANY == mode )
792             {
793                 a = pyObject2Any( PyRef( PyObject_GetAttrString( o , const_cast< char * >("value") ), SAL_NO_ACQUIRE) );
794                 Type t;
795                 pyObject2Any( PyRef( PyObject_GetAttrString( o, const_cast< char * >("type") ), SAL_NO_ACQUIRE ) ) >>= t;
796 
797                 try
798                 {
799                     a = getImpl()->cargo->xTypeConverter->convertTo( a, t );
800                 }
801                 catch( com::sun::star::uno::Exception & e )
802                 {
803                     throw RuntimeException( e.Message, e.Context );
804                 }
805             }
806             else
807             {
808                 throw RuntimeException(
809                     OUString( RTL_CONSTASCII_USTRINGPARAM(
810                                   "uno.Any instance not accepted during method call, "
811                                   "use uno.invoke instead" ) ),
812                     Reference< XInterface > () );
813             }
814         }
815         else
816         {
817             Reference< XInterface > mappedObject;
818             Reference< XInvocation > adapterObject;
819 
820             // instance already mapped out to the world ?
821             PyRef2Adapter::iterator ii = impl->cargo->mappedObjects.find( PyRef( o ) );
822             if( ii != impl->cargo->mappedObjects.end() )
823             {
824                 adapterObject = ii->second;
825             }
826 
827             if( adapterObject.is() )
828             {
829                 // object got already bridged !
830                 Reference< com::sun::star::lang::XUnoTunnel > tunnel( adapterObject, UNO_QUERY );
831 
832                 Adapter *pAdapter = ( Adapter * )
833                     sal::static_int_cast< sal_IntPtr >(
834                         tunnel->getSomething(
835                             ::pyuno::Adapter::getUnoTunnelImplementationId() ) );
836 
837                 mappedObject = impl->cargo->xAdapterFactory->createAdapter(
838                     adapterObject, pAdapter->getWrappedTypes() );
839             }
840             else
841             {
842                 Sequence< Type > interfaces = invokeGetTypes( *this, o );
843                 if( interfaces.getLength() )
844                 {
845                     Adapter *pAdapter = new Adapter( o, interfaces );
846                     mappedObject =
847                         getImpl()->cargo->xAdapterFactory->createAdapter(
848                             pAdapter, interfaces );
849 
850                     // keep a list of exported objects to ensure object identity !
851                     impl->cargo->mappedObjects[ PyRef(o) ] =
852                         com::sun::star::uno::WeakReference< XInvocation > ( pAdapter );
853                 }
854             }
855             if( mappedObject.is() )
856             {
857                 a = com::sun::star::uno::makeAny( mappedObject );
858             }
859             else
860             {
861                 OUStringBuffer buf;
862                 buf.appendAscii( "Couldn't convert " );
863                 PyRef reprString( PyObject_Str( o ) , SAL_NO_ACQUIRE );
864                 buf.append( pyString2ustring( reprString.get() ) );
865                 buf.appendAscii( " to a UNO type" );
866                 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () );
867             }
868         }
869     }
870     return a;
871 }
872 
extractUnoException(const PyRef & excType,const PyRef & excValue,const PyRef & excTraceback) const873 Any Runtime::extractUnoException( const PyRef & excType, const PyRef &excValue, const PyRef &excTraceback) const
874 {
875     PyRef str;
876     Any ret;
877     if( excTraceback.is() )
878     {
879         PyRef unoModule( impl ? impl->cargo->getUnoModule() : 0 );
880         if( unoModule.is() )
881         {
882             PyRef extractTraceback(
883                 PyDict_GetItemString(unoModule.get(),"_uno_extract_printable_stacktrace" ) );
884 
885             if( extractTraceback.is() )
886             {
887                 PyRef args( PyTuple_New( 1), SAL_NO_ACQUIRE );
888                 PyTuple_SetItem( args.get(), 0, excTraceback.getAcquired() );
889                 str = PyRef( PyObject_CallObject( extractTraceback.get(),args.get() ), SAL_NO_ACQUIRE);
890             }
891             else
892             {
893                 str = PyRef(
894                     PyBytes_FromString( "Couldn't find uno._uno_extract_printable_stacktrace" ),
895                     SAL_NO_ACQUIRE );
896             }
897         }
898         else
899         {
900             str = PyRef(
901                 PyBytes_FromString( "Couldn't find uno.py, no stacktrace available" ),
902                 SAL_NO_ACQUIRE );
903         }
904 
905     }
906     else
907     {
908         // it may occur, that no traceback is given (e.g. only native code below)
909         str = PyRef( PyBytes_FromString( "no traceback available" ), SAL_NO_ACQUIRE);
910     }
911 
912     if( isInstanceOfStructOrException( excValue.get() ) )
913     {
914         ret = pyObject2Any( excValue );
915     }
916     else
917     {
918         OUStringBuffer buf;
919         PyRef typeName( PyObject_Str( excType.get() ), SAL_NO_ACQUIRE );
920         if( typeName.is() )
921         {
922             buf.append( pyString2ustring( typeName.get() ) );
923         }
924         else
925         {
926             buf.appendAscii( "no typename available" );
927         }
928         buf.appendAscii( ": " );
929         PyRef valueRep( PyObject_Str( excValue.get() ), SAL_NO_ACQUIRE );
930         if( valueRep.is() )
931         {
932             buf.append( pyString2ustring( valueRep.get()));
933         }
934         else
935         {
936             buf.appendAscii( "Couldn't convert exception value to a string" );
937         }
938         buf.appendAscii( ", traceback follows\n" );
939         if( str.is() )
940         {
941             buf.append( pyString2ustring( str.get() ) );
942         }
943         else
944         {
945             buf.appendAscii( ", no traceback available\n" );
946         }
947         RuntimeException e;
948         e.Message = buf.makeStringAndClear();
949         ret = com::sun::star::uno::makeAny( e );
950     }
951     return ret;
952 }
953 
954 
955 static const char * g_NUMERICID = "pyuno.lcNumeric";
956 static ::std::vector< rtl::OString > g_localeList;
957 
ensureUnlimitedLifetime(const char * str)958 static const char *ensureUnlimitedLifetime( const char *str )
959 {
960     int size = g_localeList.size();
961     int i;
962     for( i = 0 ; i < size ; i ++ )
963     {
964         if( 0 == strcmp( g_localeList[i].getStr(), str ) )
965             break;
966     }
967     if( i == size )
968     {
969         g_localeList.push_back( str );
970     }
971     return g_localeList[i].getStr();
972 }
973 
974 
PyThreadAttach(PyInterpreterState * interp)975 PyThreadAttach::PyThreadAttach( PyInterpreterState *interp)
976     throw ( com::sun::star::uno::RuntimeException )
977 {
978     tstate = PyThreadState_New( interp );
979     if( !tstate  )
980         throw RuntimeException(
981             OUString(RTL_CONSTASCII_USTRINGPARAM( "Couldn't create a pythreadstate" ) ),
982             Reference< XInterface > () );
983     PyEval_AcquireThread( tstate);
984     // set LC_NUMERIC to "C"
985     const char * oldLocale =
986         ensureUnlimitedLifetime( setlocale( LC_NUMERIC, 0 )  );
987     setlocale( LC_NUMERIC, "C" );
988     PyRef locale( // python requires C locale
989         PyLong_FromVoidPtr( (void*)oldLocale ), SAL_NO_ACQUIRE);
990     PyDict_SetItemString(
991         PyThreadState_GetDict(), g_NUMERICID, locale.get() );
992 }
993 
~PyThreadAttach()994 PyThreadAttach::~PyThreadAttach()
995 {
996     PyObject *value =
997         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
998     if( value )
999         setlocale( LC_NUMERIC, (const char * ) PyLong_AsVoidPtr( value ) );
1000     PyThreadState_Clear( tstate );
1001     PyEval_ReleaseThread( tstate );
1002     PyThreadState_Delete( tstate );
1003 
1004 }
1005 
PyThreadDetach()1006 PyThreadDetach::PyThreadDetach() throw ( com::sun::star::uno::RuntimeException )
1007 {
1008     tstate = PyThreadState_Get();
1009     PyObject *value =
1010         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
1011     if( value )
1012         setlocale( LC_NUMERIC, (const char * ) PyLong_AsVoidPtr( value ) );
1013     PyEval_ReleaseThread( tstate );
1014 }
1015 
1016     /** Acquires the global interpreter lock again
1017 
1018     */
~PyThreadDetach()1019 PyThreadDetach::~PyThreadDetach()
1020 {
1021     PyEval_AcquireThread( tstate );
1022 //     PyObject *value =
1023 //         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
1024 
1025     // python requires C LC_NUMERIC locale,
1026     // always set even when it is already "C"
1027     setlocale( LC_NUMERIC, "C" );
1028 }
1029 
1030 
getUnoModule()1031 PyRef RuntimeCargo::getUnoModule()
1032 {
1033     if( ! dictUnoModule.is() )
1034     {
1035         dictUnoModule = importUnoModule();
1036     }
1037     return dictUnoModule;
1038 }
1039 }
1040