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