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