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