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 <cassert>
25 #include <string_view>
26 #include <unordered_map>
27 
28 #include <osl/module.hxx>
29 #include <osl/thread.h>
30 #include <osl/file.hxx>
31 #include <sal/log.hxx>
32 
33 #include <typelib/typedescription.hxx>
34 
35 #include <rtl/ustring.hxx>
36 #include <rtl/strbuf.hxx>
37 #include <rtl/ustrbuf.hxx>
38 #include <rtl/uuid.h>
39 #include <rtl/bootstrap.hxx>
40 
41 #include <uno/current_context.hxx>
42 #include <cppuhelper/bootstrap.hxx>
43 
44 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
45 #include <com/sun/star/reflection/XConstantTypeDescription.hpp>
46 #include <com/sun/star/reflection/XIdlClass.hpp>
47 #include <com/sun/star/registry/InvalidRegistryException.hpp>
48 #include <com/sun/star/script/CannotConvertException.hpp>
49 #include <com/sun/star/uno/XComponentContext.hpp>
50 #include <com/sun/star/script/XInvocation2.hpp>
51 #include <com/sun/star/reflection/XIdlReflection.hpp>
52 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
53 
54 using osl::Module;
55 
56 
57 using com::sun::star::uno::Sequence;
58 using com::sun::star::uno::Reference;
59 using com::sun::star::uno::Any;
60 using com::sun::star::uno::makeAny;
61 using com::sun::star::uno::RuntimeException;
62 using com::sun::star::uno::TypeDescription;
63 using com::sun::star::uno::XComponentContext;
64 using com::sun::star::container::NoSuchElementException;
65 using com::sun::star::reflection::XIdlClass;
66 using com::sun::star::script::XInvocation2;
67 
68 using namespace pyuno;
69 
70 namespace {
71 
72 /**
73    @ index of the next to be used member in the initializer list !
74  */
75 // LEM TODO: export member names as keyword arguments in initialiser?
76 // Python supports very flexible variadic functions. By marking
77 // variables with one asterisk (e.g. *var) the given variable is
78 // defined to be a tuple of all the extra arguments. By marking
79 // variables with two asterisks (e.g. **var) the given variable is a
80 // dictionary of all extra keyword arguments; the keys are strings,
81 // which are the names that were used to identify the arguments. If
82 // they exist, these arguments must be the last one in the list.
83 
84 class fillStructState
85 {
86     // Keyword arguments used
87     PyObject *used;
88     // Which structure members are initialised
89     std::unordered_map <OUString, bool> initialised;
90     // How many positional arguments are consumed
91     // This is always the so-many first ones
92     sal_Int32 nPosConsumed;
93 
94 public:
fillStructState()95     fillStructState()
96         : used (PyDict_New())
97         , initialised ()
98         , nPosConsumed (0)
99     {
100         if ( ! used )
101             throw RuntimeException("pyuno._createUnoStructHelper failed to create new dictionary");
102     }
~fillStructState()103     ~fillStructState()
104     {
105         Py_DECREF(used);
106     }
setUsed(PyObject * key)107     void setUsed(PyObject *key)
108     {
109         PyDict_SetItem(used, key, Py_True);
110     }
setInitialised(const OUString & key,sal_Int32 pos=-1)111     void setInitialised(const OUString& key, sal_Int32 pos = -1)
112     {
113         if (initialised[key])
114         {
115             OUStringBuffer buf;
116             buf.append( "pyuno._createUnoStructHelper: member '" + key + "'");
117             if ( pos >= 0 )
118             {
119                 buf.append( " at position " + OUString::number(pos));
120             }
121             buf.append( " initialised multiple times.");
122             throw RuntimeException(buf.makeStringAndClear());
123         }
124         initialised[key] = true;
125         if ( pos >= 0 )
126             ++nPosConsumed;
127     }
isInitialised(const OUString & key)128     bool isInitialised(const OUString& key)
129     {
130         return initialised[key];
131     }
getUsed() const132     PyObject *getUsed() const
133     {
134         return used;
135     }
getCntConsumed() const136     sal_Int32 getCntConsumed() const
137     {
138         return nPosConsumed;
139     }
140 };
141 
142 /// @throws RuntimeException
fillStruct(const Reference<XInvocation2> & inv,typelib_CompoundTypeDescription * pCompType,PyObject * initializer,PyObject * kwinitializer,fillStructState & state,const Runtime & runtime)143 void fillStruct(
144     const Reference< XInvocation2 > &inv,
145     typelib_CompoundTypeDescription *pCompType,
146     PyObject *initializer,
147     PyObject *kwinitializer,
148     fillStructState &state,
149     const Runtime &runtime)
150 {
151     if( pCompType->pBaseTypeDescription )
152         fillStruct( inv, pCompType->pBaseTypeDescription, initializer, kwinitializer, state, runtime );
153 
154     const sal_Int32 nMembers = pCompType->nMembers;
155     {
156         for( int i = 0 ; i < nMembers ; i ++ )
157         {
158             const OUString OUMemberName (pCompType->ppMemberNames[i]);
159             PyObject *pyMemberName =
160                 PyUnicode_FromString(OUStringToOString(OUMemberName,
161                         RTL_TEXTENCODING_UTF8).getStr());
162             if ( PyObject *element = PyDict_GetItem(kwinitializer, pyMemberName ) )
163             {
164                 state.setInitialised(OUMemberName);
165                 state.setUsed(pyMemberName);
166                 Any a = runtime.pyObject2Any( element, ACCEPT_UNO_ANY );
167                 inv->setValue( OUMemberName, a );
168             }
169         }
170     }
171     {
172         const int remainingPosInitialisers = PyTuple_Size(initializer) - state.getCntConsumed();
173         for( int i = 0 ; i < remainingPosInitialisers && i < nMembers ; i ++ )
174         {
175             const int tupleIndex = state.getCntConsumed();
176             const OUString& rMemberName (pCompType->ppMemberNames[i]);
177             state.setInitialised(rMemberName, tupleIndex);
178             PyObject *element = PyTuple_GetItem( initializer, tupleIndex );
179             Any a = runtime.pyObject2Any( element, ACCEPT_UNO_ANY );
180             inv->setValue( rMemberName, a );
181         }
182     }
183     if ( PyTuple_Size( initializer ) <= 0 )
184         return;
185 
186     // Allow partial initialisation when only keyword arguments are given
187     for ( int i = 0; i < nMembers ; ++i)
188     {
189         const OUString memberName (pCompType->ppMemberNames[i]);
190         if ( ! state.isInitialised( memberName ) )
191         {
192             OUString buf = "pyuno._createUnoStructHelper: member '" +
193                 memberName +
194                 "' of struct type '" +
195                 OUString::unacquired(&pCompType->aBase.pTypeName) +
196                 "' not given a value.";
197             throw RuntimeException(buf);
198         }
199     }
200 }
201 
getLibDir()202 OUString getLibDir()
203 {
204     static OUString sLibDir = []() {
205         OUString libDir;
206 
207         // workarounds the $(ORIGIN) until it is available
208         if (Module::getUrlFromAddress(reinterpret_cast<oslGenericFunction>(getLibDir), libDir))
209         {
210             libDir = libDir.copy(0, libDir.lastIndexOf('/'));
211             OUString name("PYUNOLIBDIR");
212             rtl_bootstrap_set(name.pData, libDir.pData);
213         }
214         return libDir;
215     }();
216 
217     return sLibDir;
218 }
219 
raisePySystemException(const char * exceptionType,std::u16string_view message)220 void raisePySystemException( const char * exceptionType, std::u16string_view message )
221 {
222     OString buf = OString::Concat("Error during bootstrapping uno (") +
223             exceptionType +
224             "):" +
225             OUStringToOString( message, osl_getThreadTextEncoding() );
226     PyErr_SetString( PyExc_SystemError, buf.getStr() );
227 }
228 
229 extern "C" {
230 
getComponentContext(SAL_UNUSED_PARAMETER PyObject *,SAL_UNUSED_PARAMETER PyObject *)231 static PyObject* getComponentContext(
232     SAL_UNUSED_PARAMETER PyObject*, SAL_UNUSED_PARAMETER PyObject*)
233 {
234     PyRef ret;
235     try
236     {
237         Reference<XComponentContext> ctx;
238 
239         // getLibDir() must be called in order to set bootstrap variables correctly !
240         OUString path( getLibDir());
241         if( Runtime::isInitialized() )
242         {
243             Runtime runtime;
244             ctx = runtime.getImpl()->cargo->xContext;
245         }
246         else
247         {
248             if( path.isEmpty() )
249             {
250                 PyErr_SetString(
251                     PyExc_RuntimeError, "osl_getUrlFromAddress fails, that's why I cannot find ini "
252                     "file for bootstrapping python uno bridge\n" );
253                 return nullptr;
254             }
255 
256             OUString iniFile = path +
257 #ifdef MACOSX
258                     "/../" LIBO_ETC_FOLDER
259 #endif
260                     "/" SAL_CONFIGFILE( "pyuno" );
261             osl::DirectoryItem item;
262             if( osl::DirectoryItem::get( iniFile, item ) == osl::FileBase::E_None )
263             {
264                 // in case pyuno.ini exists, use this file for bootstrapping
265                 PyThreadDetach antiguard;
266                 ctx = cppu::defaultBootstrap_InitialComponentContext (iniFile);
267             }
268             else
269             {
270                 // defaulting to the standard bootstrapping
271                 PyThreadDetach antiguard;
272                 ctx = cppu::defaultBootstrap_InitialComponentContext ();
273             }
274 
275         }
276 
277         if( ! Runtime::isInitialized() )
278         {
279             Runtime::initialize( ctx );
280         }
281         Runtime runtime;
282         ret = runtime.any2PyObject( makeAny( ctx ) );
283     }
284     catch (const css::registry::InvalidRegistryException &e)
285     {
286         // can't use raisePyExceptionWithAny() here, because the function
287         // does any conversions, which will not work with a
288         // wrongly bootstrapped pyuno!
289         raisePySystemException( "InvalidRegistryException", e.Message );
290     }
291     catch(const css::lang::IllegalArgumentException & e)
292     {
293         raisePySystemException( "IllegalArgumentException", e.Message );
294     }
295     catch(const css::script::CannotConvertException & e)
296     {
297         raisePySystemException( "CannotConvertException", e.Message );
298     }
299     catch (const css::uno::RuntimeException & e)
300     {
301         raisePySystemException( "RuntimeException", e.Message );
302     }
303     catch (const css::uno::Exception & e)
304     {
305         raisePySystemException( "uno::Exception", e.Message );
306     }
307     return ret.getAcquired();
308 }
309 
310 // While pyuno.private_initTestEnvironment is called from individual Python tests (e.g., from
311 // UnoInProcess in unotest/source/python/org/libreoffice/unotest.py, which makes sure to call it
312 // only once), pyuno.private_deinitTestEnvironment is called centrally from
313 // unotest/source/python/org/libreoffice/unittest.py at the end of every PythonTest (to DeInitVCL
314 // exactly once near the end of the process, if InitVCL has ever been called via
315 // pyuno.private_initTestEnvironment):
316 
317 osl::Module * testModule = nullptr;
318 
initTestEnvironment(SAL_UNUSED_PARAMETER PyObject *,SAL_UNUSED_PARAMETER PyObject *)319 static PyObject* initTestEnvironment(
320     SAL_UNUSED_PARAMETER PyObject*, SAL_UNUSED_PARAMETER PyObject*)
321 {
322     // this tries to bootstrap enough of the soffice from python to run
323     // unit tests, which is only possible indirectly because pyuno is URE
324     // so load "test" library and invoke a function there to do the work
325     assert(testModule == nullptr);
326     try
327     {
328         PyObject *const ctx(getComponentContext(nullptr, nullptr));
329         if (!ctx) { abort(); }
330         Runtime const runtime;
331         Any const a(runtime.pyObject2Any(ctx));
332         Reference<XComponentContext> xContext;
333         a >>= xContext;
334         if (!xContext.is()) { abort(); }
335         using css::lang::XMultiServiceFactory;
336         Reference<XMultiServiceFactory> const xMSF(
337             xContext->getServiceManager(),
338             css::uno::UNO_QUERY_THROW);
339         char *const testlib = getenv("TEST_LIB");
340         if (!testlib) { abort(); }
341 #ifdef _WIN32
342         OString const libname = OString(testlib, strlen(testlib))
343             .replaceAll(OString('/'), OString('\\'));
344 #else
345         OString const libname(testlib, strlen(testlib));
346 #endif
347 
348         osl::Module &mod = runtime.getImpl()->cargo->testModule;
349         mod.load(OStringToOUString(libname, osl_getThreadTextEncoding()),
350                                 SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL);
351         if (!mod.is()) { abort(); }
352         oslGenericFunction const pFunc(
353                 mod.getFunctionSymbol("test_init"));
354         if (!pFunc) { abort(); }
355         reinterpret_cast<void (SAL_CALL *)(XMultiServiceFactory*)>(pFunc)(xMSF.get());
356         testModule = &mod;
357     }
358     catch (const css::uno::Exception &)
359     {
360         abort();
361     }
362     return Py_None;
363 }
364 
deinitTestEnvironment(SAL_UNUSED_PARAMETER PyObject *,SAL_UNUSED_PARAMETER PyObject *)365 static PyObject* deinitTestEnvironment(
366     SAL_UNUSED_PARAMETER PyObject*, SAL_UNUSED_PARAMETER PyObject*)
367 {
368     if (testModule != nullptr)
369     {
370         try
371         {
372             oslGenericFunction const pFunc(
373                     testModule->getFunctionSymbol("test_deinit"));
374             if (!pFunc) { abort(); }
375             reinterpret_cast<void (SAL_CALL *)()>(pFunc)();
376         }
377         catch (const css::uno::Exception &)
378         {
379             abort();
380         }
381     }
382     return Py_None;
383 }
384 
extractOneStringArg(PyObject * args,char const * funcName)385 PyObject * extractOneStringArg( PyObject *args, char const *funcName )
386 {
387     if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 )
388     {
389         OString buf = funcName + OString::Concat(": expecting one string argument");
390         PyErr_SetString( PyExc_RuntimeError, buf.getStr() );
391         return nullptr;
392     }
393     PyObject *obj = PyTuple_GetItem( args, 0 );
394     if (!PyUnicode_Check(obj))
395     {
396         OString buf = funcName + OString::Concat(": expecting one string argument");
397         PyErr_SetString( PyExc_TypeError, buf.getStr());
398         return nullptr;
399     }
400     return obj;
401 }
402 
createUnoStructHelper(SAL_UNUSED_PARAMETER PyObject *,PyObject * args,PyObject * keywordArgs)403 static PyObject *createUnoStructHelper(
404     SAL_UNUSED_PARAMETER PyObject *, PyObject* args, PyObject* keywordArgs)
405 {
406     Any IdlStruct;
407     PyRef ret;
408     try
409     {
410         Runtime runtime;
411         if( PyTuple_Size( args ) == 2 )
412         {
413             PyObject *structName = PyTuple_GetItem(args, 0);
414             PyObject *initializer = PyTuple_GetItem(args, 1);
415 
416             if (PyUnicode_Check(structName))
417             {
418                 if( PyTuple_Check( initializer ) && PyDict_Check ( keywordArgs ) )
419                 {
420                     OUString typeName( OUString::createFromAscii(PyUnicode_AsUTF8(structName)));
421                     RuntimeCargo *c = runtime.getImpl()->cargo;
422                     Reference<XIdlClass> idl_class = c->xCoreReflection->forName (typeName);
423                     if (idl_class.is ())
424                     {
425                         idl_class->createObject (IdlStruct);
426                         PyRef returnCandidate( PyUNOStruct_new( IdlStruct, c->xInvocation ) );
427                         PyUNO *me = reinterpret_cast<PyUNO*>( returnCandidate.get() );
428                         TypeDescription desc( typeName );
429                         OSL_ASSERT( desc.is() ); // could already instantiate an XInvocation2 !
430 
431                         typelib_CompoundTypeDescription *pCompType =
432                             reinterpret_cast<typelib_CompoundTypeDescription *>(desc.get());
433                         fillStructState state;
434                         if ( PyTuple_Size( initializer ) > 0 || PyDict_Size( keywordArgs ) > 0 )
435                             fillStruct( me->members->xInvocation, pCompType, initializer, keywordArgs, state, runtime );
436                         if( state.getCntConsumed() != PyTuple_Size(initializer) )
437                         {
438                             throw RuntimeException( "pyuno._createUnoStructHelper: too many "
439                                 "elements in the initializer list, expected " +
440                                 OUString::number(state.getCntConsumed()) + ", got " +
441                                 OUString::number( PyTuple_Size(initializer) ) );
442                         }
443                         ret = PyRef( PyTuple_Pack(2, returnCandidate.get(), state.getUsed()), SAL_NO_ACQUIRE);
444                     }
445                     else
446                     {
447                         OStringBuffer buf;
448                         buf.append( "UNO struct " );
449                         buf.append( PyUnicode_AsUTF8(structName) );
450                         buf.append( " is unknown" );
451                         PyErr_SetString (PyExc_RuntimeError, buf.getStr());
452                     }
453                 }
454                 else
455                 {
456                     PyErr_SetString(
457                         PyExc_RuntimeError,
458                         "pyuno._createUnoStructHelper: 2nd argument (initializer sequence) is no tuple" );
459                 }
460             }
461             else
462             {
463                 PyErr_SetString (PyExc_AttributeError, "createUnoStruct: first argument wasn't a string");
464             }
465         }
466         else
467         {
468             PyErr_SetString (PyExc_AttributeError, "pyuno._createUnoStructHelper: expects exactly two non-keyword arguments:\n\tStructure Name\n\tinitialiser tuple; may be the empty tuple");
469         }
470     }
471     catch( const css::uno::RuntimeException & e )
472     {
473         raisePyExceptionWithAny( makeAny( e ) );
474     }
475     catch( const css::script::CannotConvertException & e )
476     {
477         raisePyExceptionWithAny( makeAny( e ) );
478     }
479     catch( const css::uno::Exception & e )
480     {
481         raisePyExceptionWithAny( makeAny( e ) );
482     }
483     return ret.getAcquired();
484 }
485 
getTypeByName(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)486 static PyObject *getTypeByName(
487     SAL_UNUSED_PARAMETER PyObject *, PyObject *args )
488 {
489     PyObject * ret = nullptr;
490 
491     try
492     {
493         char *name;
494 
495         if (PyArg_ParseTuple (args, "s", &name))
496         {
497             OUString typeName ( OUString::createFromAscii( name ) );
498             TypeDescription typeDesc( typeName );
499             if( typeDesc.is() )
500             {
501                 Runtime runtime;
502                 ret = PyUNO_Type_new(
503                     name, static_cast<css::uno::TypeClass>(typeDesc.get()->eTypeClass), runtime );
504             }
505             else
506             {
507                 OString buf = OString::Concat("Type ") + name +  " is unknown";
508                 PyErr_SetString( PyExc_RuntimeError, buf.getStr() );
509             }
510         }
511     }
512     catch ( const RuntimeException & e )
513     {
514         raisePyExceptionWithAny( makeAny( e ) );
515     }
516     return ret;
517 }
518 
getConstantByName(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)519 static PyObject *getConstantByName(
520     SAL_UNUSED_PARAMETER PyObject *, PyObject *args )
521 {
522     PyObject *ret = nullptr;
523     try
524     {
525         char *name;
526 
527         if (PyArg_ParseTuple (args, "s", &name))
528         {
529             OUString typeName ( OUString::createFromAscii( name ) );
530             Runtime runtime;
531             css::uno::Reference< css::reflection::XConstantTypeDescription > td;
532             if (!(runtime.getImpl()->cargo->xTdMgr->getByHierarchicalName(
533                       typeName)
534                   >>= td))
535             {
536                 throw RuntimeException( "pyuno.getConstantByName: " + typeName + "is not a constant" );
537             }
538             PyRef constant = runtime.any2PyObject( td->getConstantValue() );
539             ret = constant.getAcquired();
540         }
541     }
542     catch( const NoSuchElementException & e )
543     {
544         // to the python programmer, this is a runtime exception,
545         // do not support tweakings with the type system
546         RuntimeException runExc( e.Message );
547         raisePyExceptionWithAny( makeAny( runExc ) );
548     }
549     catch(const css::script::CannotConvertException & e)
550     {
551         raisePyExceptionWithAny( makeAny( e ) );
552     }
553     catch(const css::lang::IllegalArgumentException & e)
554     {
555         raisePyExceptionWithAny( makeAny( e ) );
556     }
557     catch( const RuntimeException & e )
558     {
559         raisePyExceptionWithAny( makeAny(e) );
560     }
561     return ret;
562 }
563 
checkType(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)564 static PyObject *checkType( SAL_UNUSED_PARAMETER PyObject *, PyObject *args )
565 {
566     if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 )
567     {
568         OString buf = "pyuno.checkType : expecting one uno.Type argument";
569         PyErr_SetString( PyExc_RuntimeError, buf.getStr() );
570         return nullptr;
571     }
572     PyObject *obj = PyTuple_GetItem( args, 0 );
573 
574     try
575     {
576         PyType2Type( obj );
577     }
578     catch(const  RuntimeException & e)
579     {
580         raisePyExceptionWithAny( makeAny( e ) );
581         return nullptr;
582     }
583     Py_INCREF( Py_None );
584     return Py_None;
585 }
586 
checkEnum(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)587 static PyObject *checkEnum( SAL_UNUSED_PARAMETER PyObject *, PyObject *args )
588 {
589     if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 )
590     {
591         OString buf = "pyuno.checkType : expecting one uno.Type argument";
592         PyErr_SetString( PyExc_RuntimeError, buf.getStr() );
593         return nullptr;
594     }
595     PyObject *obj = PyTuple_GetItem( args, 0 );
596 
597     try
598     {
599         PyEnum2Enum( obj );
600     }
601     catch(const RuntimeException & e)
602     {
603         raisePyExceptionWithAny( makeAny( e) );
604         return nullptr;
605     }
606     Py_INCREF( Py_None );
607     return Py_None;
608 }
609 
getClass(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)610 static PyObject *getClass( SAL_UNUSED_PARAMETER PyObject *, PyObject *args )
611 {
612     PyObject *obj = extractOneStringArg( args, "pyuno.getClass");
613     if( ! obj )
614         return nullptr;
615 
616     try
617     {
618         Runtime runtime;
619         PyRef ret = getClass(pyString2ustring(obj), runtime);
620         Py_XINCREF( ret.get() );
621         return ret.get();
622     }
623     catch(const RuntimeException & e)
624     {
625         raisePyExceptionWithAny( makeAny(e) );
626     }
627     return nullptr;
628 }
629 
isInterface(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)630 static PyObject *isInterface( SAL_UNUSED_PARAMETER PyObject *, PyObject *args )
631 {
632 
633     if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
634     {
635         PyObject *obj = PyTuple_GetItem( args, 0 );
636         Runtime r;
637         return PyLong_FromLong( isInterfaceClass( r, obj ) );
638     }
639     return PyLong_FromLong( 0 );
640 }
641 
generateUuid(SAL_UNUSED_PARAMETER PyObject *,SAL_UNUSED_PARAMETER PyObject *)642 static PyObject * generateUuid(
643     SAL_UNUSED_PARAMETER PyObject *, SAL_UNUSED_PARAMETER PyObject * )
644 {
645     Sequence< sal_Int8 > seq( 16 );
646     rtl_createUuid( reinterpret_cast<sal_uInt8*>(seq.getArray()) , nullptr , false );
647     PyRef ret;
648     try
649     {
650         Runtime runtime;
651         ret = runtime.any2PyObject( makeAny( seq ) );
652     }
653     catch( const RuntimeException & e )
654     {
655         raisePyExceptionWithAny( makeAny(e) );
656     }
657     return ret.getAcquired();
658 }
659 
systemPathToFileUrl(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)660 static PyObject *systemPathToFileUrl(
661     SAL_UNUSED_PARAMETER PyObject *, PyObject * args )
662 {
663     PyObject *obj = extractOneStringArg( args, "pyuno.systemPathToFileUrl" );
664     if( ! obj )
665         return nullptr;
666 
667     OUString sysPath = pyString2ustring( obj );
668     OUString url;
669     osl::FileBase::RC e = osl::FileBase::getFileURLFromSystemPath( sysPath, url );
670 
671     if( e != osl::FileBase::E_None )
672     {
673         OUString buf = "Couldn't convert " +
674                 sysPath +
675                 " to a file url for reason (" +
676                 OUString::number( static_cast<sal_Int32>(e) ) +
677                 ")";
678         raisePyExceptionWithAny(
679             makeAny( RuntimeException( buf )));
680         return nullptr;
681     }
682     return ustring2PyUnicode( url ).getAcquired();
683 }
684 
fileUrlToSystemPath(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)685 static PyObject * fileUrlToSystemPath(
686     SAL_UNUSED_PARAMETER PyObject *, PyObject * args )
687 {
688     PyObject *obj = extractOneStringArg( args, "pyuno.fileUrlToSystemPath" );
689     if( ! obj )
690         return nullptr;
691 
692     OUString url = pyString2ustring( obj );
693     OUString sysPath;
694     osl::FileBase::RC e = osl::FileBase::getSystemPathFromFileURL( url, sysPath );
695 
696     if( e != osl::FileBase::E_None )
697     {
698         OUString buf = "Couldn't convert file url " +
699                 sysPath +
700                 " to a system path for reason (" +
701                 OUString::number( static_cast<sal_Int32>(e) ) +
702                 ")";
703         raisePyExceptionWithAny(
704             makeAny( RuntimeException( buf )));
705         return nullptr;
706     }
707     return ustring2PyUnicode( sysPath ).getAcquired();
708 }
709 
absolutize(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)710 static PyObject * absolutize( SAL_UNUSED_PARAMETER PyObject *, PyObject * args )
711 {
712     if( PyTuple_Check( args ) && PyTuple_Size( args ) == 2 )
713     {
714         OUString ouPath = pyString2ustring( PyTuple_GetItem( args , 0 ) );
715         OUString ouRel = pyString2ustring( PyTuple_GetItem( args, 1 ) );
716         OUString ret;
717         oslFileError e = osl_getAbsoluteFileURL( ouPath.pData, ouRel.pData, &(ret.pData) );
718         if( e != osl_File_E_None )
719         {
720             OUString buf =
721                     "Couldn't absolutize " +
722                     ouRel +
723                     " using root " +
724                     ouPath +
725                     " for reason (" +
726                     OUString::number(static_cast<sal_Int32>(e) ) +
727                     ")";
728 
729             PyErr_SetString(
730                 PyExc_OSError,
731                 OUStringToOString(buf,osl_getThreadTextEncoding()).getStr());
732             return nullptr;
733         }
734         return ustring2PyUnicode( ret ).getAcquired();
735     }
736     return nullptr;
737 }
738 
invoke(SAL_UNUSED_PARAMETER PyObject *,PyObject * args)739 static PyObject * invoke(SAL_UNUSED_PARAMETER PyObject *, PyObject *args)
740 {
741     PyObject *ret = nullptr;
742     if(PyTuple_Check(args) && PyTuple_Size(args) == 3)
743     {
744         PyObject *object = PyTuple_GetItem(args, 0);
745         PyObject *item1 = PyTuple_GetItem(args, 1);
746         if (PyUnicode_Check(item1))
747         {
748             const char *name = PyUnicode_AsUTF8(item1);
749             PyObject *item2 = PyTuple_GetItem(args, 2);
750             if(PyTuple_Check(item2))
751             {
752                 ret = PyUNO_invoke(object, name, item2);
753             }
754             else
755             {
756                 OStringBuffer buf;
757                 buf.append("uno.invoke expects a tuple as 3rd argument, got ");
758                 buf.append(PyUnicode_AsUTF8(PyObject_Str(item2)));
759                 PyErr_SetString(
760                     PyExc_RuntimeError, buf.makeStringAndClear().getStr());
761             }
762         }
763         else
764         {
765             OStringBuffer buf;
766             buf.append("uno.invoke expected a string as 2nd argument, got ");
767             buf.append(PyUnicode_AsUTF8(PyObject_Str(item1)));
768             PyErr_SetString(
769                 PyExc_RuntimeError, buf.makeStringAndClear().getStr());
770         }
771     }
772     else
773     {
774         OString buf = "uno.invoke expects object, name, (arg1, arg2, ... )\n";
775         PyErr_SetString(PyExc_RuntimeError, buf.getStr());
776     }
777     return ret;
778 }
779 
getCurrentContext(SAL_UNUSED_PARAMETER PyObject *,SAL_UNUSED_PARAMETER PyObject *)780 static PyObject *getCurrentContext(
781     SAL_UNUSED_PARAMETER PyObject *, SAL_UNUSED_PARAMETER PyObject * )
782 {
783     PyRef ret;
784     try
785     {
786         Runtime runtime;
787         ret = runtime.any2PyObject(
788             makeAny( css::uno::getCurrentContext() ) );
789     }
790     catch( const css::uno::Exception & e )
791     {
792         raisePyExceptionWithAny( makeAny( e ) );
793     }
794     return ret.getAcquired();
795 }
796 
setCurrentContext(SAL_UNUSED_PARAMETER PyObject *,SAL_UNUSED_PARAMETER PyObject * args)797 static PyObject *setCurrentContext(
798     SAL_UNUSED_PARAMETER PyObject *, SAL_UNUSED_PARAMETER PyObject * args )
799 {
800     PyRef ret;
801     try
802     {
803         if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
804         {
805 
806             Runtime runtime;
807             Any a = runtime.pyObject2Any( PyTuple_GetItem( args, 0 ) );
808 
809             Reference< css::uno::XCurrentContext > context;
810 
811             if( (a.hasValue() && (a >>= context)) || ! a.hasValue() )
812             {
813                 ret = css::uno::setCurrentContext( context ) ? Py_True : Py_False;
814             }
815             else
816             {
817                 OStringBuffer buf;
818                 buf.append( "uno.setCurrentContext expects an XComponentContext implementation, got " );
819                 buf.append(
820                     PyUnicode_AsUTF8(PyObject_Str(PyTuple_GetItem(args, 0))));
821                 PyErr_SetString(
822                     PyExc_RuntimeError, buf.makeStringAndClear().getStr() );
823             }
824         }
825         else
826         {
827             OString buf = "uno.setCurrentContext expects exactly one argument (the current Context)\n";
828             PyErr_SetString(
829                 PyExc_RuntimeError, buf.getStr() );
830         }
831     }
832     catch( const css::uno::Exception & e )
833     {
834         raisePyExceptionWithAny( makeAny( e ) );
835     }
836     return ret.getAcquired();
837 }
838 
sal_debug(SAL_UNUSED_PARAMETER PyObject *,SAL_UNUSED_PARAMETER PyObject * args)839 static PyObject *sal_debug(
840     SAL_UNUSED_PARAMETER PyObject *, SAL_UNUSED_PARAMETER PyObject * args )
841 {
842     Py_INCREF( Py_None );
843     if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 )
844         return Py_None;
845 
846     OUString line = pyString2ustring( PyTuple_GetItem( args, 0 ) );
847 
848     SAL_DEBUG(line);
849 
850     return Py_None;
851 }
852 
853 }
854 
855 struct PyMethodDef PyUNOModule_methods [] =
856 {
857     {"private_initTestEnvironment", initTestEnvironment, METH_VARARGS, nullptr},
858     {"private_deinitTestEnvironment", deinitTestEnvironment, METH_VARARGS, nullptr},
859     {"getComponentContext", getComponentContext, METH_VARARGS, nullptr},
860     {"_createUnoStructHelper", reinterpret_cast<PyCFunction>(createUnoStructHelper), METH_VARARGS | METH_KEYWORDS, nullptr},
861     {"getTypeByName", getTypeByName, METH_VARARGS, nullptr},
862     {"getConstantByName", getConstantByName, METH_VARARGS, nullptr},
863     {"getClass", getClass, METH_VARARGS, nullptr},
864     {"checkEnum", checkEnum, METH_VARARGS, nullptr},
865     {"checkType", checkType, METH_VARARGS, nullptr},
866     {"generateUuid", generateUuid, METH_VARARGS, nullptr},
867     {"systemPathToFileUrl", systemPathToFileUrl, METH_VARARGS, nullptr},
868     {"fileUrlToSystemPath", fileUrlToSystemPath, METH_VARARGS, nullptr},
869     {"absolutize", absolutize, METH_VARARGS | METH_KEYWORDS, nullptr},
870     {"isInterface", isInterface, METH_VARARGS, nullptr},
871     {"invoke", invoke, METH_VARARGS | METH_KEYWORDS, nullptr},
872     {"setCurrentContext", setCurrentContext, METH_VARARGS, nullptr},
873     {"getCurrentContext", getCurrentContext, METH_VARARGS, nullptr},
874     {"sal_debug", sal_debug, METH_VARARGS, nullptr},
875     {nullptr, nullptr, 0, nullptr}
876 };
877 
878 }
879 
880 extern "C"
PyInit_pyuno()881 PyObject* PyInit_pyuno()
882 {
883     PyUNO_initType();
884     PyUNOStruct_initType();
885     // noop when called already, otherwise needed to allow multiple threads
886 #if PY_VERSION_HEX < 0x03090000
887     PyEval_InitThreads();
888 #endif
889     static struct PyModuleDef moduledef =
890     {
891         PyModuleDef_HEAD_INIT,
892         "pyuno",             // module name
893         nullptr,                   // module documentation
894         -1,                  // module keeps state in global variables,
895         PyUNOModule_methods, // modules methods
896         nullptr,                   // m_reload (must be 0)
897         nullptr,                   // m_traverse
898         nullptr,                   // m_clear
899         nullptr,                   // m_free
900     };
901     return PyModule_Create(&moduledef);
902 }
903 
904 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
905