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     PyObject_HEAD_INIT (&PyType_Type)
69     0,
70     const_cast< char * >("pyuno_runtime"),
71     sizeof (RuntimeImpl),
72     0,
73     (destructor) RuntimeImpl::del,
74     (printfunc) 0,
75     (getattrfunc) 0,
76     (setattrfunc) 0,
77     (cmpfunc) 0,
78     (reprfunc) 0,
79     0,
80     0,
81     0,
82     (hashfunc) 0,
83     (ternaryfunc) 0,
84     (reprfunc) 0,
85     (getattrofunc)0,
86     (setattrofunc)0,
87     NULL,
88     0,
89     NULL,
90     (traverseproc)0,
91     (inquiry)0,
92     (richcmpfunc)0,
93     0,
94     (getiterfunc)0,
95     (iternextfunc)0,
96     NULL,
97     NULL,
98     NULL,
99     NULL,
100     NULL,
101     (descrgetfunc)0,
102     (descrsetfunc)0,
103     0,
104     (initproc)0,
105     (allocfunc)0,
106     (newfunc)0,
107     (freefunc)0,
108     (inquiry)0,
109     NULL,
110     NULL,
111     NULL,
112     NULL,
113     NULL,
114     (destructor)0
115 #if PY_VERSION_HEX >= 0x02060000
116     , 0
117 #endif
118 };
119 
120 /*----------------------------------------------------------------------
121   Runtime implementation
122  -----------------------------------------------------------------------*/
123 static void getRuntimeImpl( PyRef & globalDict, PyRef &runtimeImpl )
124     throw ( com::sun::star::uno::RuntimeException )
125 {
126     PyThreadState * state = PyThreadState_Get();
127     if( ! state )
128     {
129         throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM(
130             "python global interpreter must be held (thread must be attached)" )),
131                                 Reference< XInterface > () );
132     }
133 
134     globalDict = PyRef( PyModule_GetDict(PyImport_AddModule(const_cast< char * >("__main__"))));
135 
136     if( ! globalDict.is() ) // FATAL !
137     {
138         throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM(
139             "can't find __main__ module" )), Reference< XInterface > ());
140     }
141     runtimeImpl = PyDict_GetItemString( globalDict.get() , "pyuno_runtime" );
142 }
143 
144 static PyRef importUnoModule( ) throw ( RuntimeException )
145 {
146     PyRef globalDict = PyRef( PyModule_GetDict(PyImport_AddModule(const_cast< char * >("__main__"))));
147     // import the uno module
148     PyRef module( PyImport_ImportModule( const_cast< char * >("uno") ), SAL_NO_ACQUIRE );
149     if( PyErr_Occurred() )
150     {
151         PyRef excType, excValue, excTraceback;
152         PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
153         PyRef str( PyObject_Repr( excTraceback.get() ), SAL_NO_ACQUIRE );
154 
155         OUStringBuffer buf;
156         buf.appendAscii( "python object raised an unknown exception (" );
157         PyRef valueRep( PyObject_Repr( excValue.get() ), SAL_NO_ACQUIRE );
158         buf.appendAscii( PyString_AsString( valueRep.get())).appendAscii( ", traceback follows\n" );
159         buf.appendAscii( PyString_AsString( str.get() ) );
160         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () );
161     }
162     PyRef dict( PyModule_GetDict( module.get() ) );
163     return dict;
164 }
165 
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  *-------------------------------------------------------------------*/
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 
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 
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 
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 
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 
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 
382 Runtime::Runtime( const Runtime & r )
383 {
384     impl = r.impl;
385     Py_XINCREF( reinterpret_cast< PyObject * >(impl) );
386 }
387 
388 Runtime::~Runtime()
389 {
390     Py_XDECREF( reinterpret_cast< PyObject * >(impl) );
391 }
392 
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 
402 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( PyInt_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 structered 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 = ustring2PyString( 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( "Unknonwn 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 
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 
646 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 (PyInt_Check (o))
663     {
664         if( o == Py_True )
665         {
666             sal_Bool b = sal_True;
667             a = Any( &b, getBooleanCppuType() );
668         }
669         else if ( o == Py_False )
670         {
671             sal_Bool b = sal_False;
672             a = Any( &b, getBooleanCppuType() );
673         }
674         else
675         {
676             sal_Int32 l = (sal_Int32) PyInt_AsLong( o );
677             if( l < 128 && l >= -128 )
678             {
679                 sal_Int8 b = (sal_Int8 ) l;
680                 a <<= b;
681             }
682             else if( l <= 0x7fff && l >= -0x8000 )
683             {
684                 sal_Int16 s = (sal_Int16) l;
685                 a <<= s;
686             }
687             else
688             {
689                 a <<= l;
690             }
691         }
692     }
693     else if (PyLong_Check (o))
694     {
695         sal_Int64 l = (sal_Int64)PyLong_AsLong (o);
696         if( l < 128 && l >= -128 )
697         {
698             sal_Int8 b = (sal_Int8 ) l;
699             a <<= b;
700         }
701         else if( l <= 0x7fff && l >= -0x8000 )
702         {
703             sal_Int16 s = (sal_Int16) l;
704             a <<= s;
705         }
706         else if( l <= SAL_CONST_INT64(0x7fffffff) &&
707                  l >= -SAL_CONST_INT64(0x80000000) )
708         {
709             sal_Int32 l32 = (sal_Int32) l;
710             a <<= l32;
711         }
712         else
713         {
714             a <<= l;
715         }
716     }
717     else if (PyFloat_Check (o))
718     {
719         double d = PyFloat_AsDouble (o);
720         a <<= d;
721     }
722     else if (PyString_Check (o))
723 	a <<= pyString2ustring(o);
724     else if( PyUnicode_Check( o ) )
725 	a <<= pyString2ustring(o);
726     else if (PyTuple_Check (o))
727     {
728         Sequence<Any> s (PyTuple_Size (o));
729         for (int i = 0; i < PyTuple_Size (o); i++)
730         {
731             s[i] = pyObject2Any (PyTuple_GetItem (o, i), mode );
732         }
733         a <<= s;
734     }
735     else
736     {
737         Runtime runtime;
738         // should be removed, in case ByteSequence gets derived from String
739         if( PyObject_IsInstance( o, getByteSequenceClass( runtime ).get() ) )
740         {
741             PyRef str(PyObject_GetAttrString( o , const_cast< char * >("value") ),SAL_NO_ACQUIRE);
742             Sequence< sal_Int8 > seq;
743             if( PyString_Check( str.get() ) )
744             {
745                 seq = Sequence<sal_Int8 > (
746                     (sal_Int8*) PyString_AsString(str.get()), PyString_Size(str.get()));
747             }
748             a <<= seq;
749         }
750         else
751         if( PyObject_IsInstance( o, getTypeClass( runtime ).get() ) )
752         {
753             Type t = PyType2Type( o );
754             a <<= t;
755         }
756         else if( PyObject_IsInstance( o, getEnumClass( runtime ).get() ) )
757         {
758             a = PyEnum2Enum( o );
759         }
760         else if( isInstanceOfStructOrException( o ) )
761         {
762             PyRef struc(PyObject_GetAttrString( o , const_cast< char * >("value") ),SAL_NO_ACQUIRE);
763             PyUNO * obj = (PyUNO*)struc.get();
764             Reference< XMaterialHolder > holder( obj->members->xInvocation, UNO_QUERY );
765             if( holder.is( ) )
766                 a = holder->getMaterial();
767             else
768             {
769                 throw RuntimeException(
770                     USTR_ASCII( "struct or exception wrapper does not support XMaterialHolder" ),
771                     Reference< XInterface > () );
772             }
773         }
774         else if( PyObject_IsInstance( o, getPyUnoClass( runtime ).get() ) )
775         {
776             PyUNO* o_pi;
777             o_pi = (PyUNO*) o;
778             if (o_pi->members->wrappedObject.getValueTypeClass () ==
779                 com::sun::star::uno::TypeClass_STRUCT ||
780                 o_pi->members->wrappedObject.getValueTypeClass () ==
781                 com::sun::star::uno::TypeClass_EXCEPTION)
782             {
783                 Reference<XMaterialHolder> my_mh (o_pi->members->xInvocation, UNO_QUERY);
784 
785                 if (!my_mh.is ())
786                 {
787                     throw RuntimeException(
788                         USTR_ASCII( "struct wrapper does not support XMaterialHolder" ),
789                         Reference< XInterface > () );
790                 }
791                 else
792                     a = my_mh->getMaterial ();
793             }
794             else
795             {
796                 a = o_pi->members->wrappedObject;
797             }
798         }
799         else if( PyObject_IsInstance( o, getCharClass( runtime ).get() ) )
800         {
801             sal_Unicode c = PyChar2Unicode( o );
802             a.setValue( &c, getCharCppuType( ));
803         }
804         else if( PyObject_IsInstance( o, getAnyClass( runtime ).get() ) )
805         {
806             if( ACCEPT_UNO_ANY == mode )
807             {
808                 a = pyObject2Any( PyRef( PyObject_GetAttrString( o , const_cast< char * >("value") ), SAL_NO_ACQUIRE) );
809                 Type t;
810                 pyObject2Any( PyRef( PyObject_GetAttrString( o, const_cast< char * >("type") ), SAL_NO_ACQUIRE ) ) >>= t;
811 
812                 try
813                 {
814                     a = getImpl()->cargo->xTypeConverter->convertTo( a, t );
815                 }
816                 catch( com::sun::star::uno::Exception & e )
817                 {
818                     throw RuntimeException( e.Message, e.Context );
819                 }
820             }
821             else
822             {
823                 throw RuntimeException(
824                     OUString( RTL_CONSTASCII_USTRINGPARAM(
825                                   "uno.Any instance not accepted during method call, "
826                                   "use uno.invoke instead" ) ),
827                     Reference< XInterface > () );
828             }
829         }
830         else
831         {
832             Reference< XInterface > mappedObject;
833             Reference< XInvocation > adapterObject;
834 
835             // instance already mapped out to the world ?
836             PyRef2Adapter::iterator ii = impl->cargo->mappedObjects.find( PyRef( o ) );
837             if( ii != impl->cargo->mappedObjects.end() )
838             {
839                 adapterObject = ii->second;
840             }
841 
842             if( adapterObject.is() )
843             {
844                 // object got already bridged !
845                 Reference< com::sun::star::lang::XUnoTunnel > tunnel( adapterObject, UNO_QUERY );
846 
847                 Adapter *pAdapter = ( Adapter * )
848                     sal::static_int_cast< sal_IntPtr >(
849                         tunnel->getSomething(
850                             ::pyuno::Adapter::getUnoTunnelImplementationId() ) );
851 
852                 mappedObject = impl->cargo->xAdapterFactory->createAdapter(
853                     adapterObject, pAdapter->getWrappedTypes() );
854             }
855             else
856             {
857                 Sequence< Type > interfaces = invokeGetTypes( *this, o );
858                 if( interfaces.getLength() )
859                 {
860                     Adapter *pAdapter = new Adapter( o, interfaces );
861                     mappedObject =
862                         getImpl()->cargo->xAdapterFactory->createAdapter(
863                             pAdapter, interfaces );
864 
865                     // keep a list of exported objects to ensure object identity !
866                     impl->cargo->mappedObjects[ PyRef(o) ] =
867                         com::sun::star::uno::WeakReference< XInvocation > ( pAdapter );
868                 }
869             }
870             if( mappedObject.is() )
871             {
872                 a = com::sun::star::uno::makeAny( mappedObject );
873             }
874             else
875             {
876                 OUStringBuffer buf;
877                 buf.appendAscii( "Couldn't convert " );
878                 PyRef reprString( PyObject_Str( o ) , SAL_NO_ACQUIRE );
879                 buf.appendAscii( PyString_AsString( reprString.get() ) );
880                 buf.appendAscii( " to a UNO type" );
881                 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () );
882             }
883         }
884     }
885     return a;
886 }
887 
888 Any Runtime::extractUnoException( const PyRef & excType, const PyRef &excValue, const PyRef &excTraceback) const
889 {
890     PyRef str;
891     Any ret;
892     if( excTraceback.is() )
893     {
894         PyRef unoModule( impl ? impl->cargo->getUnoModule() : 0 );
895         if( unoModule.is() )
896         {
897             PyRef extractTraceback(
898                 PyDict_GetItemString(unoModule.get(),"_uno_extract_printable_stacktrace" ) );
899 
900             if( extractTraceback.is() )
901             {
902                 PyRef args( PyTuple_New( 1), SAL_NO_ACQUIRE );
903                 PyTuple_SetItem( args.get(), 0, excTraceback.getAcquired() );
904                 str = PyRef( PyObject_CallObject( extractTraceback.get(),args.get() ), SAL_NO_ACQUIRE);
905             }
906             else
907             {
908                 str = PyRef(
909                     PyString_FromString( "Couldn't find uno._uno_extract_printable_stacktrace" ),
910                     SAL_NO_ACQUIRE );
911             }
912         }
913         else
914         {
915             str = PyRef(
916                 PyString_FromString( "Couldn't find uno.py, no stacktrace available" ),
917                 SAL_NO_ACQUIRE );
918         }
919 
920     }
921     else
922     {
923         // it may occur, that no traceback is given (e.g. only native code below)
924         str = PyRef( PyString_FromString( "no traceback available" ), SAL_NO_ACQUIRE);
925     }
926 
927     if( isInstanceOfStructOrException( excValue.get() ) )
928     {
929         ret = pyObject2Any( excValue );
930     }
931     else
932     {
933         OUStringBuffer buf;
934         PyRef typeName( PyObject_Str( excType.get() ), SAL_NO_ACQUIRE );
935         if( typeName.is() )
936         {
937             buf.appendAscii( PyString_AsString( typeName.get() ) );
938         }
939         else
940         {
941             buf.appendAscii( "no typename available" );
942         }
943         buf.appendAscii( ": " );
944         PyRef valueRep( PyObject_Str( excValue.get() ), SAL_NO_ACQUIRE );
945         if( valueRep.is() )
946         {
947             buf.appendAscii( PyString_AsString( valueRep.get()));
948         }
949         else
950         {
951             buf.appendAscii( "Couldn't convert exception value to a string" );
952         }
953         buf.appendAscii( ", traceback follows\n" );
954         if( str.is() )
955         {
956             buf.appendAscii( PyString_AsString( str.get() ) );
957         }
958         else
959         {
960             buf.appendAscii( ", no traceback available\n" );
961         }
962         RuntimeException e;
963         e.Message = buf.makeStringAndClear();
964         ret = com::sun::star::uno::makeAny( e );
965     }
966     return ret;
967 }
968 
969 
970 static const char * g_NUMERICID = "pyuno.lcNumeric";
971 static ::std::vector< rtl::OString > g_localeList;
972 
973 static const char *ensureUnlimitedLifetime( const char *str )
974 {
975     int size = g_localeList.size();
976     int i;
977     for( i = 0 ; i < size ; i ++ )
978     {
979         if( 0 == strcmp( g_localeList[i].getStr(), str ) )
980             break;
981     }
982     if( i == size )
983     {
984         g_localeList.push_back( str );
985     }
986     return g_localeList[i].getStr();
987 }
988 
989 
990 PyThreadAttach::PyThreadAttach( PyInterpreterState *interp)
991     throw ( com::sun::star::uno::RuntimeException )
992 {
993     tstate = PyThreadState_New( interp );
994     if( !tstate  )
995         throw RuntimeException(
996             OUString(RTL_CONSTASCII_USTRINGPARAM( "Couldn't create a pythreadstate" ) ),
997             Reference< XInterface > () );
998     PyEval_AcquireThread( tstate);
999     // set LC_NUMERIC to "C"
1000     const char * oldLocale =
1001         ensureUnlimitedLifetime( setlocale( LC_NUMERIC, 0 )  );
1002     setlocale( LC_NUMERIC, "C" );
1003     PyRef locale( // python requires C locale
1004         PyLong_FromVoidPtr( (void*)oldLocale ), SAL_NO_ACQUIRE);
1005     PyDict_SetItemString(
1006         PyThreadState_GetDict(), g_NUMERICID, locale.get() );
1007 }
1008 
1009 PyThreadAttach::~PyThreadAttach()
1010 {
1011     PyObject *value =
1012         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
1013     if( value )
1014         setlocale( LC_NUMERIC, (const char * ) PyLong_AsVoidPtr( value ) );
1015     PyThreadState_Clear( tstate );
1016     PyEval_ReleaseThread( tstate );
1017     PyThreadState_Delete( tstate );
1018 
1019 }
1020 
1021 PyThreadDetach::PyThreadDetach() throw ( com::sun::star::uno::RuntimeException )
1022 {
1023     tstate = PyThreadState_Get();
1024     PyObject *value =
1025         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
1026     if( value )
1027         setlocale( LC_NUMERIC, (const char * ) PyLong_AsVoidPtr( value ) );
1028     PyEval_ReleaseThread( tstate );
1029 }
1030 
1031     /** Acquires the global interpreter lock again
1032 
1033     */
1034 PyThreadDetach::~PyThreadDetach()
1035 {
1036     PyEval_AcquireThread( tstate );
1037 //     PyObject *value =
1038 //         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
1039 
1040     // python requires C LC_NUMERIC locale,
1041     // always set even when it is already "C"
1042     setlocale( LC_NUMERIC, "C" );
1043 }
1044 
1045 
1046 PyRef RuntimeCargo::getUnoModule()
1047 {
1048     if( ! dictUnoModule.is() )
1049     {
1050         dictUnoModule = importUnoModule();
1051     }
1052     return dictUnoModule;
1053 }
1054 }
1055