LibreOffice Module pyuno (master) 1
pyuno.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; 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 <sal/config.h>
21
22#include <algorithm>
23#include <cassert>
24
25#include <rtl/ustrbuf.hxx>
26
27#include <typelib/typedescription.hxx>
28
29#include <com/sun/star/lang/XServiceInfo.hpp>
30#include <com/sun/star/lang/XTypeProvider.hpp>
31#include <com/sun/star/beans/UnknownPropertyException.hpp>
32#include <com/sun/star/container/XEnumerationAccess.hpp>
33#include <com/sun/star/container/XIndexAccess.hpp>
34#include <com/sun/star/container/XIndexContainer.hpp>
35#include <com/sun/star/container/XIndexReplace.hpp>
36#include <com/sun/star/container/XNameAccess.hpp>
37#include <com/sun/star/container/XNameContainer.hpp>
38#include <com/sun/star/container/XNameReplace.hpp>
39#include <com/sun/star/script/CannotConvertException.hpp>
40#include <com/sun/star/script/XInvocation2.hpp>
41#include <com/sun/star/script/XTypeConverter.hpp>
42#include <com/sun/star/lang/XSingleServiceFactory.hpp>
44
45#include "pyuno_impl.hxx"
46
49using com::sun::star::uno::XInterface;
50using com::sun::star::uno::Any;
51using com::sun::star::uno::UNO_QUERY;
52using com::sun::star::uno::Type;
53using com::sun::star::uno::TypeClass;
54using com::sun::star::uno::TypeDescription;
55using com::sun::star::uno::RuntimeException;
56using com::sun::star::uno::Exception;
57using com::sun::star::lang::XSingleServiceFactory;
58using com::sun::star::lang::XServiceInfo;
59using com::sun::star::lang::XTypeProvider;
60using com::sun::star::lang::XUnoTunnel;
61using com::sun::star::script::XInvocation2;
62using com::sun::star::container::XEnumeration;
63using com::sun::star::container::XEnumerationAccess;
64using com::sun::star::container::XIndexAccess;
65using com::sun::star::container::XIndexContainer;
66using com::sun::star::container::XIndexReplace;
67using com::sun::star::container::XNameAccess;
68using com::sun::star::container::XNameContainer;
69using com::sun::star::container::XNameReplace;
70
71namespace pyuno
72{
73
74static PyObject *PyUNO_str( PyObject * self );
75
76static void PyUNO_del (PyObject* self)
77{
78 PyUNO* me = reinterpret_cast< PyUNO* > (self);
79 {
80 PyThreadDetach antiguard;
81 delete me->members;
82 }
83 PyObject_Del (self);
84}
85
86
87OUString val2str( const void * pVal, typelib_TypeDescriptionReference * pTypeRef , sal_Int32 mode )
88{
89 assert( pVal );
90 if (pTypeRef->eTypeClass == typelib_TypeClass_VOID)
91 return "void";
92
93 OUStringBuffer buf( 64 );
94 buf.append( "(" + OUString::unacquired(&pTypeRef->pTypeName) + ")" );
95
96 switch (pTypeRef->eTypeClass)
97 {
98 case typelib_TypeClass_INTERFACE:
99 {
100 buf.append( "0x" +
101 OUString::number( reinterpret_cast< sal_IntPtr >(*static_cast<void * const *>(pVal)), 16 ));
102 if( VAL2STR_MODE_DEEP == mode )
103 {
104 buf.append( "{" ); Reference< XInterface > r = *static_cast<Reference< XInterface > const *>(pVal);
105 Reference< XServiceInfo > serviceInfo( r, UNO_QUERY);
106 Reference< XTypeProvider > typeProvider(r,UNO_QUERY);
107 if( serviceInfo.is() )
108 {
109 buf.append("implementationName="
110 + serviceInfo->getImplementationName()
111 + ", supportedServices={" );
112 Sequence< OUString > seq = serviceInfo->getSupportedServiceNames();
113 for( int i = 0 ; i < seq.getLength() ; i ++ )
114 {
115 buf.append( seq[i] );
116 if( i +1 != seq.getLength() )
117 buf.append( "," );
118 }
119 buf.append("}");
120 }
121
122 if( typeProvider.is() )
123 {
124 buf.append(", supportedInterfaces={" );
125 Sequence< Type > seq (typeProvider->getTypes());
126 for( int i = 0 ; i < seq.getLength() ; i ++ )
127 {
128 buf.append(seq[i].getTypeName());
129 if( i +1 != seq.getLength() )
130 buf.append( "," );
131 }
132 buf.append("}");
133 }
134 buf.append( "}" );
135 }
136
137 break;
138 }
139 case typelib_TypeClass_STRUCT:
140 case typelib_TypeClass_EXCEPTION:
141 {
142 buf.append( "{ " );
143 typelib_TypeDescription * pTypeDescr = nullptr;
144 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
145 assert( pTypeDescr );
146
147 typelib_CompoundTypeDescription * pCompType = reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr);
148 sal_Int32 nDescr = pCompType->nMembers;
149
150 if (pCompType->pBaseTypeDescription)
151 {
152 buf.append( val2str( pVal, pCompType->pBaseTypeDescription->aBase.pWeakRef, mode ) );
153 if (nDescr)
154 buf.append( ", " );
155 }
156
157 typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs;
158 sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets;
159 rtl_uString ** ppMemberNames = pCompType->ppMemberNames;
160
161 for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos )
162 {
163 buf.append( OUString::unacquired(&ppMemberNames[nPos]) + " = " );
164 typelib_TypeDescription * pMemberType = nullptr;
165 TYPELIB_DANGER_GET( &pMemberType, ppTypeRefs[nPos] );
166 buf.append( val2str( static_cast<char const *>(pVal) + pMemberOffsets[nPos], pMemberType->pWeakRef, mode ) );
167 TYPELIB_DANGER_RELEASE( pMemberType );
168 if (nPos < (nDescr -1))
169 buf.append( ", " );
170 }
171
172 TYPELIB_DANGER_RELEASE( pTypeDescr );
173
174 buf.append( " }" );
175 break;
176 }
177 case typelib_TypeClass_SEQUENCE:
178 {
179 typelib_TypeDescription * pTypeDescr = nullptr;
180 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
181
182 uno_Sequence * pSequence = *static_cast<uno_Sequence * const *>(pVal);
183 typelib_TypeDescription * pElementTypeDescr = nullptr;
184 TYPELIB_DANGER_GET( &pElementTypeDescr, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType );
185
186 sal_Int32 nElementSize = pElementTypeDescr->nSize;
187 sal_Int32 nElements = pSequence->nElements;
188
189 if (nElements)
190 {
191 buf.append( "{ " );
192 char * pElements = pSequence->elements;
193 for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
194 {
195 buf.append( val2str( pElements + (nElementSize * nPos), pElementTypeDescr->pWeakRef, mode ) );
196 if (nPos < (nElements -1))
197 buf.append( ", " );
198 }
199 buf.append( " }" );
200 }
201 else
202 {
203 buf.append( "{}" );
204 }
205 TYPELIB_DANGER_RELEASE( pElementTypeDescr );
206 TYPELIB_DANGER_RELEASE( pTypeDescr );
207 break;
208 }
209 case typelib_TypeClass_ANY:
210 buf.append( "{ "
211 + val2str( static_cast<uno_Any const *>(pVal)->pData,
212 static_cast<uno_Any const *>(pVal)->pType ,
213 mode)
214 + " }" );
215 break;
216 case typelib_TypeClass_TYPE:
217 buf.append( (*static_cast<typelib_TypeDescriptionReference * const *>(pVal))->pTypeName );
218 break;
219 case typelib_TypeClass_STRING:
220 buf.append( "\"" +
221 OUString::unacquired(&*static_cast<rtl_uString * const *>(pVal)) +
222 "\"" );
223 break;
224 case typelib_TypeClass_ENUM:
225 {
226 typelib_TypeDescription * pTypeDescr = nullptr;
227 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
228
229 sal_Int32 * pValues = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->pEnumValues;
230 sal_Int32 nPos = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nEnumValues;
231 while (nPos--)
232 {
233 if (pValues[nPos] == *static_cast<int const *>(pVal))
234 break;
235 }
236 if (nPos >= 0)
237 buf.append( reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->ppEnumNames[nPos] );
238 else
239 buf.append( '?' );
240
241 TYPELIB_DANGER_RELEASE( pTypeDescr );
242 break;
243 }
244 case typelib_TypeClass_BOOLEAN:
245 if (*static_cast<sal_Bool const *>(pVal))
246 buf.append( "true" );
247 else
248 buf.append( "false" );
249 break;
250 case typelib_TypeClass_CHAR:
251 buf.append( "\'"
252 + OUStringChar(*static_cast<sal_Unicode const *>(pVal) )
253 + "\'" );
254 break;
255 case typelib_TypeClass_FLOAT:
256 buf.append( *static_cast<float const *>(pVal) );
257 break;
258 case typelib_TypeClass_DOUBLE:
259 buf.append( *static_cast<double const *>(pVal) );
260 break;
261 case typelib_TypeClass_BYTE:
262 buf.append( "0x" +
263 OUString::number( static_cast<sal_Int32>(*static_cast<sal_Int8 const *>(pVal)), 16 ));
264 break;
265 case typelib_TypeClass_SHORT:
266 buf.append( "0x" +
267 OUString::number( static_cast<sal_Int32>(*static_cast<sal_Int16 const *>(pVal)), 16 ));
268 break;
269 case typelib_TypeClass_UNSIGNED_SHORT:
270 buf.append( "0x" +
271 OUString::number( static_cast<sal_Int32>(*static_cast<sal_uInt16 const *>(pVal)), 16 ));
272 break;
273 case typelib_TypeClass_LONG:
274 buf.append( "0x" +
275 OUString::number( *static_cast<sal_Int32 const *>(pVal), 16 ));
276 break;
277 case typelib_TypeClass_UNSIGNED_LONG:
278 buf.append( "0x" +
279 OUString::number( static_cast<sal_Int64>(*static_cast<sal_uInt32 const *>(pVal)), 16 ));
280 break;
281 case typelib_TypeClass_HYPER:
282 case typelib_TypeClass_UNSIGNED_HYPER:
283 buf.append( "0x" );
284#if defined(__GNUC__) && defined(SPARC)
285// I guess this really should check if there are strict alignment
286// requirements, not just "GCC on SPARC".
287 {
288 sal_Int64 aVal;
289 *(sal_Int32 *)&aVal = *(sal_Int32 *)pVal;
290 *((sal_Int32 *)&aVal +1)= *((sal_Int32 *)pVal +1);
291 buf.append( aVal, 16 );
292 }
293#else
294 buf.append( *static_cast<sal_Int64 const *>(pVal), 16 );
295#endif
296 break;
297
298 case typelib_TypeClass_VOID:
299 case typelib_TypeClass_UNKNOWN:
300 case typelib_TypeClass_SERVICE:
301 case typelib_TypeClass_MODULE:
302 default:
303 buf.append( '?' );
304 }
305
306 return buf.makeStringAndClear();
307}
308
309static sal_Int32 lcl_PyNumber_AsSal_Int32( PyObject *pObj )
310{
311 // Check object is an index
312 PyRef rIndex( PyNumber_Index( pObj ), SAL_NO_ACQUIRE );
313 if ( !rIndex.is() )
314 return -1;
315
316 // Convert Python number to platform long, then check actual value against
317 // bounds of sal_Int32
318 int nOverflow;
319 long nResult = PyLong_AsLongAndOverflow( pObj, &nOverflow );
320 if ( nOverflow || nResult > SAL_MAX_INT32 || nResult < SAL_MIN_INT32) {
321 PyErr_SetString( PyExc_IndexError, "Python int too large to convert to UNO long" );
322 return -1;
323 }
324
325 return nResult;
326}
327
328static int lcl_PySlice_GetIndicesEx( PyObject *pObject, sal_Int32 nLen, sal_Int32 *nStart, sal_Int32 *nStop, sal_Int32 *nStep, sal_Int32 *nSliceLength )
329{
330 Py_ssize_t nStart_ssize, nStop_ssize, nStep_ssize, nSliceLength_ssize;
331
332 int nResult = PySlice_GetIndicesEx(pObject,
333 nLen, &nStart_ssize, &nStop_ssize, &nStep_ssize, &nSliceLength_ssize );
334 if (nResult == -1)
335 return -1;
336
337 if ( nStart_ssize > SAL_MAX_INT32 || nStart_ssize < SAL_MIN_INT32
338 || nStop_ssize > SAL_MAX_INT32 || nStop_ssize < SAL_MIN_INT32
339 || nStep_ssize > SAL_MAX_INT32 || nStep_ssize < SAL_MIN_INT32
340 || nSliceLength_ssize > SAL_MAX_INT32 || nSliceLength_ssize < SAL_MIN_INT32 )
341 {
342 PyErr_SetString( PyExc_IndexError, "Python int too large to convert to UNO long" );
343 return -1;
344 }
345
346 *nStart = static_cast<sal_Int32>(nStart_ssize);
347 *nStop = static_cast<sal_Int32>(nStop_ssize);
348 *nStep = static_cast<sal_Int32>(nStep_ssize);
349 *nSliceLength = static_cast<sal_Int32>(nSliceLength_ssize);
350 return 0;
351}
352
353static bool lcl_hasInterfaceByName( Any const &object, OUString const & interfaceName )
354{
355 Reference< XInterface > xInterface( object, UNO_QUERY );
356 TypeDescription typeDesc( interfaceName );
357 Any aInterface = xInterface->queryInterface( typeDesc.get()->pWeakRef );
358
359 return aInterface.hasValue();
360}
361
362static PyObject *PyUNO_repr( PyObject * self )
363{
364 return PyUNO_str( self );
365}
366
367static Py_hash_t PyUNO_hash( PyObject *self )
368{
369
370 PyUNO *me = reinterpret_cast<PyUNO *>(self);
371
372 // Py_hash_t is not necessarily the same size as a pointer, but this is not
373 // important for hashing - it just has to return the same value each time
374 return sal::static_int_cast< Py_hash_t >( reinterpret_cast< sal_IntPtr > (
375 *static_cast<void * const *>(me->members->wrappedObject.getValue()) ) );
376
377}
378
379PyObject *PyUNO_invoke( PyObject *object, const char *name , PyObject *args )
380{
381 PyRef ret;
382 try
383 {
384 Runtime runtime;
385
386 PyRef paras,callable;
387 if( PyObject_IsInstance( object, getPyUnoClass().get() ) )
388 {
389 PyUNO* me = reinterpret_cast<PyUNO*>(object);
390 OUString attrName = OUString::createFromAscii(name);
391 if (! me->members->xInvocation->hasMethod (attrName))
392 {
393 throw RuntimeException( "Attribute " + attrName + " unknown" );
394 }
395 callable = PyUNO_callable_new (
396 me->members->xInvocation,
397 attrName,
399 paras = args;
400 }
401 else
402 {
403 // clean the tuple from uno.Any !
404 int size = PyTuple_Size( args );
405 { // for CC, keeping ref-count of tuple being 1
406 paras = PyRef(PyTuple_New( size ), SAL_NO_ACQUIRE);
407 }
408 for( int i = 0 ; i < size ;i ++ )
409 {
410 PyObject * element = PyTuple_GetItem( args , i );
411 if( PyObject_IsInstance( element , getAnyClass( runtime ).get() ) )
412 {
413 element = PyObject_GetAttrString(
414 element, "value" );
415 }
416 else
417 {
418 Py_XINCREF( element );
419 }
420 PyTuple_SetItem( paras.get(), i , element );
421 }
422 callable = PyRef( PyObject_GetAttrString( object , name ), SAL_NO_ACQUIRE );
423 if( !callable.is() )
424 return nullptr;
425 }
426 ret = PyRef( PyObject_CallObject( callable.get(), paras.get() ), SAL_NO_ACQUIRE );
427 }
428 catch (const css::lang::IllegalArgumentException &e)
429 {
430 raisePyExceptionWithAny( css::uno::Any( e ) );
431 }
432 catch (const css::script::CannotConvertException &e)
433 {
434 raisePyExceptionWithAny( css::uno::Any( e ) );
435 }
436 catch (const css::uno::RuntimeException &e)
437 {
438 raisePyExceptionWithAny( css::uno::Any( e ) );
439 }
440 catch (const css::uno::Exception &e)
441 {
442 raisePyExceptionWithAny( css::uno::Any( e ) );
443 }
444
445 return ret.getAcquired();
446}
447
448PyObject *PyUNO_str( PyObject * self )
449{
450 PyUNO *me = reinterpret_cast<PyUNO *>(self);
451
452 OString buf;
453
454 {
455 PyThreadDetach antiguard;
456
457 OUString s = val2str( me->members->wrappedObject.getValue(),
458 me->members->wrappedObject.getValueType().getTypeLibType() );
459 buf = "pyuno object " + OUStringToOString(s,RTL_TEXTENCODING_ASCII_US);
460 }
461
462 return PyUnicode_FromString( buf.getStr() );
463}
464
465static PyObject* PyUNO_dir (PyObject* self)
466{
467 PyUNO* me = reinterpret_cast<PyUNO*>(self);
468
469 PyObject* member_list = nullptr;
470 Sequence<OUString> oo_member_list;
471
472 try
473 {
474 oo_member_list = me->members->xInvocation->getMemberNames ();
475 member_list = PyList_New (oo_member_list.getLength ());
476 for (int i = 0; i < oo_member_list.getLength (); i++)
477 {
478 // setitem steals a reference
479 PyList_SetItem (member_list, i, ustring2PyString(oo_member_list[i]).getAcquired() );
480 }
481 }
482 catch( const RuntimeException &e )
483 {
485 }
486
487 return member_list;
488}
489
490static sal_Int32 lcl_detach_getLength( PyUNO const *me )
491{
492 PyThreadDetach antiguard;
493
494 // If both XIndexContainer and XNameContainer are implemented, it is
495 // assumed that getCount() gives the same result as the number of names
496 // returned by getElementNames(), or the user may be surprised.
497
498 // For XIndexContainer
499 Reference< XIndexAccess > xIndexAccess( me->members->xInvocation, UNO_QUERY );
500 if ( xIndexAccess.is() )
501 {
502 return xIndexAccess->getCount();
503 }
504
505 // For XNameContainer
506 // Not terribly efficient - get the count of all the names
507 Reference< XNameAccess > xNameAccess( me->members->xInvocation, UNO_QUERY );
508 if ( xNameAccess.is() )
509 {
510 return xNameAccess->getElementNames().getLength();
511 }
512
513 return -1;
514}
515
516static int PyUNO_bool( PyObject* self )
517{
518 PyUNO* me = reinterpret_cast<PyUNO*>(self);
519
520 try
521 {
522 int nLen = lcl_detach_getLength( me );
523 if (nLen >= 0)
524 return nLen == 0 ? 0 : 1;
525
526 // Anything which doesn't have members is a scalar object and therefore true
527 return 1;
528 }
529 catch( const css::uno::RuntimeException &e )
530 {
531 raisePyExceptionWithAny( css::uno::Any( e ) );
532 }
533
534 return -1;
535}
536
537static Py_ssize_t PyUNO_len( PyObject* self )
538{
539 PyUNO* me = reinterpret_cast<PyUNO*>(self);
540
541 try
542 {
543 int nLen = lcl_detach_getLength( me );
544 if (nLen >= 0)
545 return nLen;
546
547 PyErr_SetString( PyExc_TypeError, "object has no len()" );
548 }
549 catch( const css::uno::RuntimeException &e )
550 {
551 raisePyExceptionWithAny( css::uno::Any( e ) );
552 }
553
554 return -1;
555}
556
557static void lcl_getRowsColumns( PyUNO const * me, sal_Int32& nRows, sal_Int32& nColumns )
558{
559 Sequence<short> aOutParamIndex;
560 Sequence<Any> aOutParam;
561 Sequence<Any> aParams;
562 Any aRet = me->members->xInvocation->invoke ( "getRows", aParams, aOutParamIndex, aOutParam );
563 Reference< XIndexAccess > xIndexAccessRows( aRet, UNO_QUERY );
564 nRows = xIndexAccessRows->getCount();
565 aRet = me->members->xInvocation->invoke ( "getColumns", aParams, aOutParamIndex, aOutParam );
566 Reference< XIndexAccess > xIndexAccessCols( aRet, UNO_QUERY );
567 nColumns = xIndexAccessCols->getCount();
568}
569
570static PyRef lcl_indexToSlice( const PyRef& rIndex )
571{
572 Py_ssize_t nIndex = PyNumber_AsSsize_t( rIndex.get(), PyExc_IndexError );
573 if (nIndex == -1 && PyErr_Occurred())
574 return nullptr;
575 PyRef rStart( PyLong_FromSsize_t( nIndex ), SAL_NO_ACQUIRE );
576 PyRef rStop( PyLong_FromSsize_t( nIndex+1 ), SAL_NO_ACQUIRE );
577 PyRef rStep( PyLong_FromLong( 1 ), SAL_NO_ACQUIRE );
578 PyRef rSlice( PySlice_New( rStart.get(), rStop.get(), rStep.get() ), SAL_NO_ACQUIRE );
579
580 return rSlice;
581}
582
583static PyObject* lcl_getitem_XCellRange( PyUNO const * me, PyObject* pKey )
584{
585 Runtime runtime;
586
587 Sequence<short> aOutParamIndex;
588 Sequence<Any> aOutParam;
589 Sequence<Any> aParams;
590 Any aRet;
591
592 // Single string key is sugar for getCellRangeByName()
593 if ( PyUnicode_Check( pKey ) ) {
594
595 aParams = { Any(pyString2ustring( pKey )) };
596 {
597 PyThreadDetach antiguard;
598 aRet = me->members->xInvocation->invoke (
599 "getCellRangeByName", aParams, aOutParamIndex, aOutParam );
600 }
601 PyRef rRet = runtime.any2PyObject ( aRet );
602 return rRet.getAcquired();
603
604 }
605
606 PyRef rKey0, rKey1;
607 if ( PyIndex_Check( pKey ) )
608 {
609 // [0] is equivalent to [0,:]
610 rKey0 = pKey;
611 rKey1 = PySlice_New( nullptr, nullptr, nullptr );
612 }
613 else if ( PyTuple_Check( pKey ) && (PyTuple_Size( pKey ) == 2) )
614 {
615 rKey0 = PyTuple_GetItem( pKey, 0 );
616 rKey1 = PyTuple_GetItem( pKey, 1 );
617 }
618 else
619 {
620 PyErr_SetString( PyExc_KeyError, "invalid subscript" );
621 return nullptr;
622 }
623
624 // If both keys are indices, return the corresponding cell
625 if ( PyIndex_Check( rKey0.get() ) && PyIndex_Check( rKey1.get() ))
626 {
627 sal_Int32 nKey0_s = lcl_PyNumber_AsSal_Int32( rKey0.get() );
628 sal_Int32 nKey1_s = lcl_PyNumber_AsSal_Int32( rKey1.get() );
629
630 if ( ((nKey0_s == -1) || (nKey1_s == -1)) && PyErr_Occurred() )
631 return nullptr;
632
633 aParams = { Any(nKey1_s), Any(nKey0_s) };
634 {
635 PyThreadDetach antiguard;
636 aRet = me->members->xInvocation->invoke (
637 "getCellByPosition", aParams, aOutParamIndex, aOutParam );
638 }
639 PyRef rRet = runtime.any2PyObject( aRet );
640 return rRet.getAcquired();
641 }
642
643 // If either argument is an index, coerce it to a slice
644 if ( PyIndex_Check( rKey0.get() ) )
645 rKey0 = lcl_indexToSlice( rKey0 );
646
647 if ( PyIndex_Check( rKey1.get() ) )
648 rKey1 = lcl_indexToSlice( rKey1 );
649
650 // If both arguments are slices, return the corresponding cell range
651 if ( PySlice_Check( rKey0.get() ) && PySlice_Check( rKey1.get() ) )
652 {
653 sal_Int32 nLen0 = SAL_MAX_INT32, nLen1 = SAL_MAX_INT32;
654 sal_Int32 nStart0 = 0, nStop0 = 0, nStep0 = 0, nSliceLength0 = 0;
655 sal_Int32 nStart1 = 0, nStop1 = 0, nStep1 = 0, nSliceLength1 = 0;
656
657 {
658 PyThreadDetach antiguard;
659
660 if ( lcl_hasInterfaceByName( me->members->wrappedObject, "com.sun.star.table.XColumnRowRange" ) )
661 {
662 lcl_getRowsColumns (me, nLen0, nLen1);
663 }
664 }
665
666 int nSuccess1 = lcl_PySlice_GetIndicesEx( rKey0.get(), nLen0, &nStart0, &nStop0, &nStep0, &nSliceLength0 );
667 int nSuccess2 = lcl_PySlice_GetIndicesEx( rKey1.get(), nLen1, &nStart1, &nStop1, &nStep1, &nSliceLength1 );
668 if ( ((nSuccess1 == -1) || (nSuccess2 == -1)) && PyErr_Occurred() )
669 return nullptr;
670
671 if ( nSliceLength0 <= 0 || nSliceLength1 <= 0 )
672 {
673 PyErr_SetString( PyExc_KeyError, "invalid number of rows or columns" );
674 return nullptr;
675 }
676
677 if ( nStep0 == 1 && nStep1 == 1 )
678 {
679 aParams = { Any(nStart1), Any(nStart0), Any(nStop1 - 1), Any(nStop0 - 1) };
680 {
681 PyThreadDetach antiguard;
682 aRet = me->members->xInvocation->invoke (
683 "getCellRangeByPosition", aParams, aOutParamIndex, aOutParam );
684 }
685 PyRef rRet = runtime.any2PyObject( aRet );
686 return rRet.getAcquired();
687 }
688
689 PyErr_SetString( PyExc_KeyError, "step != 1 not supported" );
690 return nullptr;
691 }
692
693 PyErr_SetString( PyExc_KeyError, "invalid subscript" );
694 return nullptr;
695}
696
697static PyObject* lcl_getitem_index( PyUNO const *me, PyObject *pKey, Runtime const & runtime )
698{
699 Any aRet;
700 sal_Int32 nIndex;
701
703 if (nIndex == -1 && PyErr_Occurred())
704 return nullptr;
705
706 {
707 PyThreadDetach antiguard;
708
709 Reference< XIndexAccess > xIndexAccess( me->members->xInvocation, UNO_QUERY );
710 if ( xIndexAccess.is() )
711 {
712 if (nIndex < 0)
713 nIndex += xIndexAccess->getCount();
714 aRet = xIndexAccess->getByIndex( nIndex );
715 }
716 }
717 if ( aRet.hasValue() )
718 {
719 PyRef rRet ( runtime.any2PyObject( aRet ) );
720 return rRet.getAcquired();
721 }
722
723 return nullptr;
724}
725
726static PyObject* lcl_getitem_slice( PyUNO const *me, PyObject *pKey )
727{
728 Runtime runtime;
729
730 Reference< XIndexAccess > xIndexAccess;
731 sal_Int32 nLen = 0;
732
733 {
734 PyThreadDetach antiguard;
735
736 xIndexAccess.set( me->members->xInvocation, UNO_QUERY );
737 if ( xIndexAccess.is() )
738 nLen = xIndexAccess->getCount();
739 }
740
741 if ( !xIndexAccess )
742 return nullptr;
743
744 sal_Int32 nStart = 0, nStop = 0, nStep = 0, nSliceLength = 0;
745 int nSuccess = lcl_PySlice_GetIndicesEx(pKey, nLen, &nStart, &nStop, &nStep, &nSliceLength);
746 if ( nSuccess == -1 && PyErr_Occurred() )
747 return nullptr;
748
749 PyRef rTuple( PyTuple_New( nSliceLength ), SAL_NO_ACQUIRE, NOT_NULL );
750 sal_Int32 nCur, i;
751 for ( nCur = nStart, i = 0; i < nSliceLength; nCur += nStep, i++ )
752 {
753 Any aRet;
754
755 {
756 PyThreadDetach antiguard;
757
758 aRet = xIndexAccess->getByIndex( nCur );
759 }
760 PyRef rRet = runtime.any2PyObject( aRet );
761 PyTuple_SetItem( rTuple.get(), i, rRet.getAcquired() );
762 }
763
764 return rTuple.getAcquired();
765}
766
767static PyObject* lcl_getitem_string( PyUNO const *me, PyObject *pKey, Runtime const & runtime )
768{
769 OUString sKey = pyString2ustring( pKey );
770 Any aRet;
771
772 {
773 PyThreadDetach antiguard;
774
775 Reference< XNameAccess > xNameAccess( me->members->xInvocation, UNO_QUERY );
776 if ( xNameAccess.is() )
777 {
778 aRet = xNameAccess->getByName( sKey );
779 }
780 }
781 if ( aRet.hasValue() )
782 {
783 PyRef rRet = runtime.any2PyObject( aRet );
784 return rRet.getAcquired();
785 }
786
787 return nullptr;
788}
789
790static PyObject* PyUNO_getitem( PyObject *self, PyObject *pKey )
791{
792 PyUNO* me = reinterpret_cast<PyUNO*>(self);
793 Runtime runtime;
794
795 try
796 {
797 // XIndexAccess access by index
798 if ( PyIndex_Check( pKey ) )
799 {
800 PyObject* pRet = lcl_getitem_index( me, pKey, runtime );
801 if ( pRet != nullptr || PyErr_Occurred() )
802 return pRet;
803 }
804
805 // XIndexAccess access by slice
806 if ( PySlice_Check( pKey ) )
807 {
808 PyObject* pRet = lcl_getitem_slice( me, pKey );
809 if ( pRet != nullptr || PyErr_Occurred() )
810 return pRet;
811 }
812
813 // XNameAccess access by key
814 if ( PyUnicode_Check( pKey ) )
815 {
816 PyObject* pRet = lcl_getitem_string( me, pKey, runtime );
817 if ( pRet != nullptr )
818 return pRet;
819 }
820
821 // XCellRange/XColumnRowRange specialisation
822 // Uses reflection as we can't have a hard dependency on XCellRange here
823 bool hasXCellRange = false;
824
825 {
826 PyThreadDetach antiguard;
827
828 hasXCellRange = lcl_hasInterfaceByName( me->members->wrappedObject, "com.sun.star.table.XCellRange" );
829 }
830 if ( hasXCellRange )
831 {
832 return lcl_getitem_XCellRange( me, pKey );
833 }
834
835
836 // If the object is an XIndexAccess and/or XNameAccess, but the
837 // key passed wasn't suitable, give a TypeError which specifically
838 // describes this
839 Reference< XIndexAccess > xIndexAccess( me->members->xInvocation, UNO_QUERY );
840 Reference< XNameAccess > xNameAccess( me->members->xInvocation, UNO_QUERY );
841 if ( xIndexAccess.is() || xNameAccess.is() )
842 {
843 PyErr_SetString( PyExc_TypeError, "subscription with invalid type" );
844 return nullptr;
845 }
846
847 PyErr_SetString( PyExc_TypeError, "object is not subscriptable" );
848 }
849 catch( const css::lang::IndexOutOfBoundsException & )
850 {
851 PyErr_SetString( PyExc_IndexError, "index out of range" );
852 }
853 catch( const css::container::NoSuchElementException & )
854 {
855 PyErr_SetString( PyExc_KeyError, "key not found" );
856 }
857 catch( const css::script::CannotConvertException &e )
858 {
859 raisePyExceptionWithAny( css::uno::Any( e ) );
860 }
861 catch( const css::lang::IllegalArgumentException &e )
862 {
863 raisePyExceptionWithAny( css::uno::Any( e ) );
864 }
865 catch( const css::lang::WrappedTargetException &e )
866 {
867 raisePyExceptionWithAny( css::uno::Any( e ) );
868 }
869 catch( const css::uno::RuntimeException &e )
870 {
871 raisePyExceptionWithAny( css::uno::Any( e ) );
872 }
873
874 return nullptr;
875}
876
877static int lcl_setitem_index( PyUNO const *me, PyObject *pKey, PyObject *pValue )
878{
879 Runtime runtime;
880
881 Reference< XIndexContainer > xIndexContainer;
882 Reference< XIndexReplace > xIndexReplace;
883 sal_Int32 nIndex = lcl_PyNumber_AsSal_Int32( pKey );
884 if ( nIndex == -1 && PyErr_Occurred() )
885 return 0;
886
887 bool isTuple = false;
888
889 Any aValue;
890 if ( pValue != nullptr )
891 {
892 isTuple = PyTuple_Check( pValue );
893
894 try
895 {
896 aValue = runtime.pyObject2Any( pValue );
897 }
898 catch ( const css::uno::RuntimeException & )
899 {
900 // TODO pyObject2Any can't convert e.g. dicts but only throws
901 // RuntimeException on failure. Fixing this will require an audit of
902 // all the rest of PyUNO
903 throw css::script::CannotConvertException();
904 }
905 }
906
907 {
908 PyThreadDetach antiguard;
909
910 xIndexContainer.set( me->members->xInvocation, UNO_QUERY );
911 if ( xIndexContainer.is() )
912 xIndexReplace = xIndexContainer;
913 else
914 xIndexReplace.set( me->members->xInvocation, UNO_QUERY );
915
916 if ( xIndexReplace.is() && nIndex < 0 )
917 nIndex += xIndexReplace->getCount();
918
919 // XIndexReplace replace by index
920 if ( (pValue != nullptr) && xIndexReplace.is() )
921 {
922 if ( isTuple )
923 {
924 // Apply type specialisation to ensure the correct kind of sequence is passed
925 Type aType = xIndexReplace->getElementType();
926 aValue = runtime.getImpl()->cargo->xTypeConverter->convertTo( aValue, aType );
927 }
928
929 xIndexReplace->replaceByIndex( nIndex, aValue );
930 return 0;
931 }
932
933 // XIndexContainer remove by index
934 if ( (pValue == nullptr) && xIndexContainer.is() )
935 {
936 xIndexContainer->removeByIndex( nIndex );
937 return 0;
938 }
939 }
940
941 PyErr_SetString( PyExc_TypeError, "cannot assign to object" );
942 return 1;
943}
944
945static int lcl_setitem_slice( PyUNO const *me, PyObject *pKey, PyObject *pValue )
946{
947 // XIndexContainer insert/remove/replace by slice
948 Runtime runtime;
949
950 Reference< XIndexReplace > xIndexReplace;
951 Reference< XIndexContainer > xIndexContainer;
952 sal_Int32 nLen = 0;
953
954 {
955 PyThreadDetach antiguard;
956
957 xIndexContainer.set( me->members->xInvocation, UNO_QUERY );
958 if ( xIndexContainer.is() )
959 xIndexReplace = xIndexContainer;
960 else
961 xIndexReplace.set( me->members->xInvocation, UNO_QUERY );
962
963 if ( xIndexReplace.is() )
964 nLen = xIndexReplace->getCount();
965 }
966
967 if ( xIndexReplace.is() )
968 {
969 sal_Int32 nStart = 0, nStop = 0, nStep = 0, nSliceLength = 0;
970 int nSuccess = lcl_PySlice_GetIndicesEx( pKey, nLen, &nStart, &nStop, &nStep, &nSliceLength );
971 if ( (nSuccess == -1) && PyErr_Occurred() )
972 return 0;
973
974 if ( pValue == nullptr )
975 {
976 pValue = PyTuple_New( 0 );
977 }
978
979 if ( !PyTuple_Check (pValue) )
980 {
981 PyErr_SetString( PyExc_TypeError, "value is not a tuple" );
982 return 1;
983 }
984
985 Py_ssize_t nTupleLength_ssize = PyTuple_Size( pValue );
986 if ( nTupleLength_ssize > SAL_MAX_INT32 )
987 {
988 PyErr_SetString( PyExc_ValueError, "tuple too large" );
989 return 1;
990 }
991 sal_Int32 nTupleLength = static_cast<sal_Int32>(nTupleLength_ssize);
992
993 if ( (nTupleLength != nSliceLength) && (nStep != 1) )
994 {
995 PyErr_SetString( PyExc_ValueError, "number of items assigned must be equal" );
996 return 1;
997 }
998
999 if ( (nTupleLength != nSliceLength) && !xIndexContainer.is() )
1000 {
1001 PyErr_SetString( PyExc_ValueError, "cannot change length" );
1002 return 1;
1003 }
1004
1005 sal_Int32 nCur, i;
1006 sal_Int32 nMax = ::std::max( nSliceLength, nTupleLength );
1007 for ( nCur = nStart, i = 0; i < nMax; nCur += nStep, i++ )
1008 {
1009 if ( i < nTupleLength )
1010 {
1011 PyRef rItem = PyTuple_GetItem( pValue, i );
1012 bool isTuple = PyTuple_Check( rItem.get() );
1013
1014 Any aItem;
1015 try
1016 {
1017 aItem = runtime.pyObject2Any( rItem.get() );
1018 }
1019 catch ( const css::uno::RuntimeException & )
1020 {
1021 // TODO pyObject2Any can't convert e.g. dicts but only throws
1022 // RuntimeException on failure. Fixing this will require an audit of
1023 // all the rest of PyUNO
1024 throw css::script::CannotConvertException();
1025 }
1026
1027 {
1028 PyThreadDetach antiguard;
1029
1030 if ( isTuple )
1031 {
1032 // Apply type specialisation to ensure the correct kind of sequence is passed
1033 Type aType = xIndexReplace->getElementType();
1034 aItem = runtime.getImpl()->cargo->xTypeConverter->convertTo( aItem, aType );
1035 }
1036
1037 if ( i < nSliceLength )
1038 {
1039 xIndexReplace->replaceByIndex( nCur, aItem );
1040 }
1041 else
1042 {
1043 xIndexContainer->insertByIndex( nCur, aItem );
1044 }
1045 }
1046 }
1047 else
1048 {
1049 PyThreadDetach antiguard;
1050
1051 xIndexContainer->removeByIndex( nCur );
1052 nCur--;
1053 }
1054 }
1055
1056 return 0;
1057 }
1058
1059 PyErr_SetString( PyExc_TypeError, "cannot assign to object" );
1060 return 1;
1061}
1062
1063static int lcl_setitem_string( PyUNO const *me, PyObject *pKey, PyObject *pValue )
1064{
1065 Runtime runtime;
1066
1067 OUString sKey = pyString2ustring( pKey );
1068 bool isTuple = false;
1069
1070 Any aValue;
1071 if ( pValue != nullptr)
1072 {
1073 isTuple = PyTuple_Check( pValue );
1074 try
1075 {
1076 aValue = runtime.pyObject2Any( pValue );
1077 }
1078 catch( const css::uno::RuntimeException & )
1079 {
1080 // TODO pyObject2Any can't convert e.g. dicts but only throws
1081 // RuntimeException on failure. Fixing this will require an audit of
1082 // all the rest of PyUNO
1083 throw css::script::CannotConvertException();
1084 }
1085 }
1086
1087 {
1088 PyThreadDetach antiguard;
1089
1090 Reference< XNameContainer > xNameContainer( me->members->xInvocation, UNO_QUERY );
1091 Reference< XNameReplace > xNameReplace;
1092 if ( xNameContainer.is() )
1093 xNameReplace = xNameContainer;
1094 else
1095 xNameReplace.set( me->members->xInvocation, UNO_QUERY );
1096
1097 if ( xNameReplace.is() )
1098 {
1099 if ( isTuple && aValue.hasValue() )
1100 {
1101 // Apply type specialisation to ensure the correct kind of sequence is passed
1102 Type aType = xNameReplace->getElementType();
1103 aValue = runtime.getImpl()->cargo->xTypeConverter->convertTo( aValue, aType );
1104 }
1105
1106 if ( aValue.hasValue() )
1107 {
1108 if ( xNameContainer.is() )
1109 {
1110 try {
1111 xNameContainer->insertByName( sKey, aValue );
1112 return 0;
1113 }
1114 catch( const css::container::ElementExistException & )
1115 {
1116 // Fall through, try replace instead
1117 }
1118 }
1119
1120 xNameReplace->replaceByName( sKey, aValue );
1121 return 0;
1122 }
1123 else if ( xNameContainer.is() )
1124 {
1125 xNameContainer->removeByName( sKey );
1126 return 0;
1127 }
1128 }
1129 }
1130
1131 PyErr_SetString( PyExc_TypeError, "cannot assign to object" );
1132 return 1;
1133}
1134
1135static int PyUNO_setitem( PyObject *self, PyObject *pKey, PyObject *pValue )
1136{
1137 PyUNO* me = reinterpret_cast<PyUNO*>(self);
1138
1139 try
1140 {
1141 if ( PyIndex_Check( pKey ) )
1142 {
1143 return lcl_setitem_index( me, pKey, pValue );
1144 }
1145 else if ( PySlice_Check( pKey ) )
1146 {
1147 return lcl_setitem_slice( me, pKey, pValue );
1148 }
1149 else if ( PyUnicode_Check( pKey ) )
1150 {
1151 return lcl_setitem_string( me, pKey, pValue );
1152 }
1153
1154 PyErr_SetString( PyExc_TypeError, "list index has invalid type" );
1155 }
1156 catch( const css::lang::IndexOutOfBoundsException & )
1157 {
1158 PyErr_SetString( PyExc_IndexError, "list index out of range" );
1159 }
1160 catch( const css::container::NoSuchElementException & )
1161 {
1162 PyErr_SetString( PyExc_KeyError, "key not found" );
1163 }
1164 catch( const css::lang::IllegalArgumentException & )
1165 {
1166 PyErr_SetString( PyExc_TypeError, "value has invalid type" );
1167 }
1168 catch( const css::script::CannotConvertException & )
1169 {
1170 PyErr_SetString( PyExc_TypeError, "value has invalid type" );
1171 }
1172 catch( const css::container::ElementExistException &e )
1173 {
1174 raisePyExceptionWithAny( css::uno::Any( e ) );
1175 }
1176 catch( const css::lang::WrappedTargetException &e )
1177 {
1178 raisePyExceptionWithAny( css::uno::Any( e ) );
1179 }
1180 catch( const css::uno::RuntimeException &e )
1181 {
1182 raisePyExceptionWithAny( css::uno::Any( e ) );
1183 }
1184
1185 return 1;
1186}
1187
1188static PyObject* PyUNO_iter( PyObject *self )
1189{
1190 PyUNO* me = reinterpret_cast<PyUNO*>(self);
1191
1192 try
1193 {
1194 Reference< XEnumerationAccess > xEnumerationAccess;
1195 Reference< XEnumeration > xEnumeration;
1196 Reference< XIndexAccess > xIndexAccess;
1197 Reference< XNameAccess > xNameAccess;
1198
1199 {
1200 PyThreadDetach antiguard;
1201
1202 xEnumerationAccess.set( me->members->xInvocation, UNO_QUERY );
1203 if ( xEnumerationAccess.is() )
1204 xEnumeration = xEnumerationAccess->createEnumeration();
1205 else
1206 xEnumeration.set( me->members->wrappedObject, UNO_QUERY );
1207
1208 if ( !xEnumeration.is() )
1209 xIndexAccess.set( me->members->xInvocation, UNO_QUERY );
1210
1211 if ( !xIndexAccess.is() )
1212 xNameAccess.set( me->members->xInvocation, UNO_QUERY );
1213 }
1214
1215 // XEnumerationAccess iterator
1216 // XEnumeration iterator
1217 if (xEnumeration.is())
1218 {
1219 return PyUNO_iterator_new( xEnumeration );
1220 }
1221
1222 // XIndexAccess iterator
1223 if ( xIndexAccess.is() )
1224 {
1225 // We'd like to be able to use PySeqIter_New() here, but we're not
1226 // allowed to because we also implement the mapping protocol
1227 return PyUNO_list_iterator_new( xIndexAccess );
1228 }
1229
1230 // XNameAccess iterator
1231 if (xNameAccess.is())
1232 {
1233 // There's no generic mapping iterator, but we can cobble our own
1234 // together using PySeqIter_New()
1235 Runtime runtime;
1236 Any aRet;
1237
1238 {
1239 PyThreadDetach antiguard;
1240 aRet <<= xNameAccess->getElementNames();
1241 }
1242 PyRef rNames = runtime.any2PyObject( aRet );
1243 return PySeqIter_New( rNames.getAcquired() );
1244 }
1245
1246 PyErr_SetString ( PyExc_TypeError, "object is not iterable" );
1247 }
1248 catch( css::script::CannotConvertException &e )
1249 {
1250 raisePyExceptionWithAny( css::uno::Any( e ) );
1251 }
1252 catch( css::lang::IllegalArgumentException &e )
1253 {
1254 raisePyExceptionWithAny( css::uno::Any( e ) );
1255 }
1256 catch( const css::uno::RuntimeException &e )
1257 {
1258 raisePyExceptionWithAny( css::uno::Any( e ) );
1259 }
1260
1261 return nullptr;
1262}
1263
1264static int PyUNO_contains( PyObject *self, PyObject *pKey )
1265{
1266 PyUNO* me = reinterpret_cast<PyUNO*>(self);
1267
1268 Runtime runtime;
1269
1270 try
1271 {
1272 Any aValue;
1273 try
1274 {
1275 aValue = runtime.pyObject2Any( pKey );
1276 }
1277 catch( const css::uno::RuntimeException & )
1278 {
1279 // TODO pyObject2Any can't convert e.g. dicts but only throws
1280 // RuntimeException on failure. Fixing this will require an audit of
1281 // all the rest of PyUNO
1282 throw css::script::CannotConvertException();
1283 }
1284
1285 // XNameAccess is tried first, because checking key presence is much more
1286 // useful for objects which implement both XIndexAccess and XNameAccess
1287
1288 // For XNameAccess
1289 if ( PyUnicode_Check( pKey ) )
1290 {
1291 OUString sKey;
1292 aValue >>= sKey;
1293 Reference< XNameAccess > xNameAccess;
1294
1295 {
1296 PyThreadDetach antiguard;
1297
1298 xNameAccess.set( me->members->xInvocation, UNO_QUERY );
1299 if ( xNameAccess.is() )
1300 {
1301 bool hasKey = xNameAccess->hasByName( sKey );
1302 return hasKey ? 1 : 0;
1303 }
1304 }
1305 }
1306
1307 // For any other type of PyUNO iterable: Ugly iterative search by
1308 // content (XIndexAccess, XEnumerationAccess, XEnumeration)
1309 PyRef rIterator( PyUNO_iter( self ), SAL_NO_ACQUIRE );
1310 if ( rIterator.is() )
1311 {
1312 while ( PyObject* pItem = PyIter_Next( rIterator.get() ) )
1313 {
1314 PyRef rItem( pItem, SAL_NO_ACQUIRE );
1315 if ( PyObject_RichCompareBool( pKey, rItem.get(), Py_EQ ) == 1 )
1316 {
1317 return 1;
1318 }
1319 }
1320 return 0;
1321 }
1322
1323 PyErr_SetString( PyExc_TypeError, "argument is not iterable" );
1324 }
1325 catch( const css::script::CannotConvertException& )
1326 {
1327 PyErr_SetString( PyExc_TypeError, "invalid type passed as left argument to 'in'" );
1328 }
1329 catch( const css::container::NoSuchElementException &e )
1330 {
1331 raisePyExceptionWithAny( css::uno::Any( e ) );
1332 }
1333 catch( const css::lang::IndexOutOfBoundsException &e )
1334 {
1335 raisePyExceptionWithAny( css::uno::Any( e ) );
1336 }
1337 catch( const css::lang::IllegalArgumentException &e )
1338 {
1339 raisePyExceptionWithAny( css::uno::Any( e ) );
1340 }
1341 catch( const css::lang::WrappedTargetException &e )
1342 {
1343 raisePyExceptionWithAny( css::uno::Any( e ) );
1344 }
1345 catch( const css::uno::RuntimeException &e )
1346 {
1347 raisePyExceptionWithAny( css::uno::Any( e ) );
1348 }
1349
1350 return -1;
1351}
1352
1353static PyObject* PyUNO_getattr (PyObject* self, char* name)
1354{
1355 try
1356 {
1357
1358 Runtime runtime;
1359
1360 PyUNO* me = reinterpret_cast<PyUNO*>(self);
1361 if (strcmp (name, "__dict__") == 0)
1362 {
1363 Py_INCREF (Py_TYPE(me)->tp_dict);
1364 return Py_TYPE(me)->tp_dict;
1365 }
1366 if (strcmp (name, "__class__") == 0)
1367 {
1368 Py_INCREF (Py_None);
1369 return Py_None;
1370 }
1371
1372 PyObject *pRet = PyObject_GenericGetAttr( self, PyUnicode_FromString( name ) );
1373 if( pRet )
1374 return pRet;
1375 PyErr_Clear();
1376
1377 OUString attrName( OUString::createFromAscii( name ) );
1378 //We need to find out if it's a method...
1379 bool isMethod;
1380 {
1381 PyThreadDetach antiguard;
1382 isMethod = me->members->xInvocation->hasMethod (attrName);
1383 }
1384 if (isMethod)
1385 {
1386 //Create a callable object to invoke this...
1388 me->members->xInvocation,
1389 attrName);
1390 Py_XINCREF( ret.get() );
1391 return ret.get();
1392
1393 }
1394
1395 //or a property
1396 bool isProperty;
1397 Any anyRet;
1398 {
1399 PyThreadDetach antiguard;
1400 isProperty = me->members->xInvocation->hasProperty ( attrName);
1401 if (isProperty)
1402 {
1403 //Return the value of the property
1404 anyRet = me->members->xInvocation->getValue (attrName);
1405 }
1406 }
1407 if (isProperty)
1408 {
1409 PyRef ret = runtime.any2PyObject(anyRet);
1410 Py_XINCREF( ret.get() );
1411 return ret.get();
1412 }
1413
1414 //or else...
1415 PyErr_SetString (PyExc_AttributeError, name);
1416 }
1417 catch( const css::reflection::InvocationTargetException & e )
1418 {
1419 raisePyExceptionWithAny( e.TargetException );
1420 }
1421 catch( const css::beans::UnknownPropertyException & e )
1422 {
1424 }
1425 catch( const css::lang::IllegalArgumentException &e )
1426 {
1428 }
1429 catch( const css::script::CannotConvertException &e )
1430 {
1432 }
1433 catch( const RuntimeException &e )
1434 {
1436 }
1437
1438 return nullptr;
1439}
1440
1441static int PyUNO_setattr (PyObject* self, char* name, PyObject* value)
1442{
1443 PyUNO* me;
1444
1445 me = reinterpret_cast<PyUNO*>(self);
1446 try
1447 {
1448 Runtime runtime;
1449 Any val= runtime.pyObject2Any(value, ACCEPT_UNO_ANY);
1450
1451 OUString attrName( OUString::createFromAscii( name ) );
1452 {
1453 PyThreadDetach antiguard;
1454 if (me->members->xInvocation->hasProperty (attrName))
1455 {
1456 me->members->xInvocation->setValue (attrName, val);
1457 return 0; //Keep with Python's boolean system
1458 }
1459 }
1460 }
1461 catch( const css::reflection::InvocationTargetException & e )
1462 {
1463 raisePyExceptionWithAny( e.TargetException );
1464 return 1;
1465 }
1466 catch( const css::beans::UnknownPropertyException & e )
1467 {
1469 return 1;
1470 }
1471 catch( const css::script::CannotConvertException &e )
1472 {
1474 return 1;
1475 }
1476 catch( const RuntimeException & e )
1477 {
1479 return 1;
1480 }
1481 PyErr_SetString (PyExc_AttributeError, name);
1482 return 1; //as above.
1483}
1484
1485static PyObject* PyUNO_cmp( PyObject *self, PyObject *that, int op )
1486{
1487 PyObject *result;
1488
1489 if(op != Py_EQ && op != Py_NE)
1490 {
1491 PyErr_SetString(PyExc_TypeError, "only '==' and '!=' comparisons are defined");
1492 return nullptr;
1493 }
1494 if( self == that )
1495 {
1496 result = (op == Py_EQ ? Py_True : Py_False);
1497 Py_INCREF(result);
1498 return result;
1499 }
1500 try
1501 {
1502 Runtime runtime;
1503 if( PyObject_IsInstance( that, getPyUnoClass().get() ) )
1504 {
1505
1506 PyUNO *me = reinterpret_cast< PyUNO*> ( self );
1507 PyUNO *other = reinterpret_cast< PyUNO *> (that );
1508 css::uno::TypeClass tcMe = me->members->wrappedObject.getValueTypeClass();
1509 css::uno::TypeClass tcOther = other->members->wrappedObject.getValueTypeClass();
1510
1511 if( tcMe == tcOther )
1512 {
1513 if( me->members->wrappedObject == other->members->wrappedObject )
1514 {
1515 result = (op == Py_EQ ? Py_True : Py_False);
1516 Py_INCREF(result);
1517 return result;
1518 }
1519 }
1520 }
1521 }
1522 catch( const css::uno::RuntimeException & e)
1523 {
1525 }
1526
1527 result = (op == Py_EQ ? Py_False : Py_True);
1528 Py_INCREF(result);
1529 return result;
1530}
1531
1532static PyMethodDef PyUNOMethods[] =
1533{
1534 {"__dir__", reinterpret_cast<PyCFunction>(PyUNO_dir), METH_NOARGS, nullptr},
1535 {nullptr, nullptr, 0, nullptr}
1536};
1537
1538static PyNumberMethods PyUNONumberMethods[] =
1539{
1540 nullptr, /* nb_add */
1541 nullptr, /* nb_subtract */
1542 nullptr, /* nb_multiply */
1543 nullptr, /* nb_remainder */
1544 nullptr, /* nb_divmod */
1545 nullptr, /* nb_power */
1546 nullptr, /* nb_negative */
1547 nullptr, /* nb_positive */
1548 nullptr, /* nb_absolute */
1549 PyUNO_bool, /* nb_bool */
1550 nullptr, /* nb_invert */
1551 nullptr, /* nb_lshift */
1552 nullptr, /* nb_rshift */
1553 nullptr, /* nb_and */
1554 nullptr, /* nb_xor */
1555 nullptr, /* nb_or */
1556 nullptr, /* nb_int */
1557 nullptr, /* nb_reserved */
1558 nullptr, /* nb_float */
1559 nullptr, /* nb_inplace_add */
1560 nullptr, /* nb_inplace_subtract */
1561 nullptr, /* nb_inplace_multiply */
1562 nullptr, /* nb_inplace_remainder */
1563 nullptr, /* nb_inplace_power */
1564 nullptr, /* nb_inplace_lshift */
1565 nullptr, /* nb_inplace_rshift */
1566 nullptr, /* nb_inplace_and */
1567 nullptr, /* nb_inplace_xor */
1568 nullptr, /* nb_inplace_or */
1569
1570 nullptr, /* nb_floor_divide */
1571 nullptr, /* nb_true_divide */
1572 nullptr, /* nb_inplace_floor_divide */
1573 nullptr, /* nb_inplace_true_divide */
1574
1575 nullptr, /* nb_index */
1576#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 5
1577 nullptr, /* nb_matrix_multiply */
1578 nullptr, /* nb_inplace_matrix_multiply */
1579#endif
1580};
1581
1582static PySequenceMethods PyUNOSequenceMethods[] =
1583{
1584 nullptr, /* sq_length */
1585 nullptr, /* sq_concat */
1586 nullptr, /* sq_repeat */
1587 nullptr, /* sq_item */
1588 nullptr, /* sq_slice */
1589 nullptr, /* sq_ass_item */
1590 nullptr, /* sq_ass_slice */
1591 PyUNO_contains, /* sq_contains */
1592 nullptr, /* sq_inplace_concat */
1593 nullptr /* sq_inplace_repeat */
1594};
1595
1596static PyMappingMethods PyUNOMappingMethods[] =
1597{
1598 PyUNO_len, /* mp_length */
1599 PyUNO_getitem, /* mp_subscript */
1600 PyUNO_setitem, /* mp_ass_subscript */
1601};
1602
1603static PyTypeObject PyUNOType =
1604{
1605 PyVarObject_HEAD_INIT( &PyType_Type, 0 )
1606 "pyuno",
1607 sizeof (PyUNO),
1608 0,
1609 PyUNO_del,
1610#if PY_VERSION_HEX >= 0x03080000
1611 0, // Py_ssize_t tp_vectorcall_offset
1612#else
1613 nullptr, // printfunc tp_print
1614#endif
1617 /* this type does not exist in Python 3: (cmpfunc) */ nullptr,
1618 PyUNO_repr,
1622 PyUNO_hash,
1623 nullptr,
1624 PyUNO_str,
1625 nullptr,
1626 nullptr,
1627 nullptr,
1629 nullptr,
1630 nullptr,
1631 nullptr,
1632 PyUNO_cmp,
1633 0,
1634 PyUNO_iter,
1635 nullptr,
1637 nullptr,
1638 nullptr,
1639 nullptr,
1640 nullptr,
1641 nullptr,
1642 nullptr,
1643 0,
1644 nullptr,
1645 nullptr,
1646 nullptr,
1647 nullptr,
1648 nullptr,
1649 nullptr,
1650 nullptr,
1651 nullptr,
1652 nullptr,
1653 nullptr,
1654 nullptr
1655 , 0
1656#if PY_VERSION_HEX >= 0x03040000
1657 , nullptr
1658#if PY_VERSION_HEX >= 0x03080000
1659 , nullptr // vectorcallfunc tp_vectorcall
1660#if PY_VERSION_HEX < 0x03090000
1661#if defined __clang__
1662#pragma clang diagnostic push
1663#pragma clang diagnostic ignored "-Wdeprecated-declarations"
1664#endif
1665 , nullptr // tp_print
1666#if defined __clang__
1667#pragma clang diagnostic pop
1668#endif
1669#endif
1670#endif
1671#endif
1672};
1673
1675{
1676 return PyType_Ready(&PyUNOType);
1677}
1678
1680{
1681 return PyRef( reinterpret_cast< PyObject * > ( &PyUNOType ) );
1682}
1683
1685 const Any &targetInterface,
1687{
1689
1690 {
1691 PyThreadDetach antiguard;
1692 xInvocation.set(
1693 ssf->createInstanceWithArguments( Sequence<Any>( &targetInterface, 1 ) ), css::uno::UNO_QUERY_THROW );
1694
1695 auto that = comphelper::getFromUnoTunnel<Adapter>(
1696 xInvocation->getIntrospection()->queryAdapter(cppu::UnoType<XUnoTunnel>::get()));
1697 if( that )
1698 return that->getWrappedObject();
1699 }
1700 if( !Py_IsInitialized() )
1701 throw RuntimeException();
1702
1703 PyUNO* self = PyObject_New (PyUNO, &PyUNOType);
1704 if (self == nullptr)
1705 return PyRef(); // == error
1706 self->members = new PyUNOInternals;
1708 self->members->wrappedObject = targetInterface;
1709 return PyRef( reinterpret_cast<PyObject*>(self), SAL_NO_ACQUIRE );
1710
1711}
1712
1713}
1714
1715/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const PropertyValue * pValues
Helper class for keeping references to python objects.
Definition: pyuno.hxx:80
bool is() const
returns 1 when the reference points to a python object python object, otherwise 0.
Definition: pyuno.hxx:139
PyObject * get() const noexcept
Definition: pyuno.hxx:99
PyObject * getAcquired() const
Definition: pyuno.hxx:101
helper class for detaching the current thread from the python runtime to do some blocking,...
Definition: pyuno.hxx:300
The pyuno::Runtime class keeps the internal state of the python UNO bridge for the currently in use p...
Definition: pyuno.hxx:164
css::uno::Any pyObject2Any(const PyRef &source, enum ConversionMode mode=REJECT_UNO_ANY) const
converts a Python object to a UNO any
PyRef any2PyObject(const css::uno::Any &source) const
converts something contained in a UNO Any to a Python object
RuntimeImpl * getImpl() const
Returns the internal handle.
Definition: pyuno.hxx:242
Any value
sal_Int32 nElements
EmbeddedObjectRef * pObject
const char * name
sal_Int32 nIndex
sal_uInt16 nPos
const char * attrName
std::unique_ptr< sal_Int32[]> pData
struct _typelib_TypeDescription typelib_TypeDescription
struct _uno_Any uno_Any
size
Type
rtl::OUString getTypeName(rtl::OUString const &rEnvDcp)
int i
args
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Definition: pyuno.cxx:72
static Py_ssize_t PyUNO_len(PyObject *self)
Definition: pyuno.cxx:537
static PyObject * PyUNO_str(PyObject *self)
Definition: pyuno.cxx:448
static sal_Int32 lcl_PyNumber_AsSal_Int32(PyObject *pObj)
Definition: pyuno.cxx:309
static PyObject * lcl_getitem_XCellRange(PyUNO const *me, PyObject *pKey)
Definition: pyuno.cxx:583
static PySequenceMethods PyUNOSequenceMethods[]
Definition: pyuno.cxx:1582
static PyObject * PyUNO_cmp(PyObject *self, PyObject *that, int op)
Definition: pyuno.cxx:1485
PyObject * PyUNO_list_iterator_new(const css::uno::Reference< css::container::XIndexAccess > &xIndexAccess)
static PyNumberMethods PyUNONumberMethods[]
Definition: pyuno.cxx:1538
static sal_Int32 lcl_detach_getLength(PyUNO const *me)
Definition: pyuno.cxx:490
static Py_hash_t PyUNO_hash(PyObject *self)
Definition: pyuno.cxx:367
static void PyUNO_del(PyObject *self)
Definition: pyuno.cxx:76
PyRef PyUNO_new(const Any &targetInterface, const Reference< XSingleServiceFactory > &ssf)
Definition: pyuno.cxx:1684
const sal_Int32 VAL2STR_MODE_DEEP
Definition: pyuno_impl.hxx:91
@ ACCEPT_UNO_ANY
Definition: pyuno.hxx:153
static int PyUNO_setattr(PyObject *self, char *name, PyObject *value)
Definition: pyuno.cxx:1441
static int lcl_setitem_string(PyUNO const *me, PyObject *pKey, PyObject *pValue)
Definition: pyuno.cxx:1063
static int lcl_setitem_slice(PyUNO const *me, PyObject *pKey, PyObject *pValue)
Definition: pyuno.cxx:945
static PyObject * PyUNO_repr(PyObject *self)
Definition: pyuno.cxx:362
static PyRef lcl_indexToSlice(const PyRef &rIndex)
Definition: pyuno.cxx:570
PyRef ustring2PyString(std::u16string_view source)
Definition: pyuno_util.cxx:51
static PyObject * PyUNO_getattr(PyObject *self, char *name)
Definition: pyuno.cxx:1353
static PyObject * lcl_getitem_index(PyUNO const *me, PyObject *pKey, Runtime const &runtime)
Definition: pyuno.cxx:697
static int lcl_PySlice_GetIndicesEx(PyObject *pObject, sal_Int32 nLen, sal_Int32 *nStart, sal_Int32 *nStop, sal_Int32 *nStep, sal_Int32 *nSliceLength)
Definition: pyuno.cxx:328
static PyObject * PyUNO_dir(PyObject *self)
Definition: pyuno.cxx:465
static PyMethodDef PyUNOMethods[]
Definition: pyuno.cxx:1532
static int PyUNO_contains(PyObject *self, PyObject *pKey)
Definition: pyuno.cxx:1264
void raisePyExceptionWithAny(const css::uno::Any &anyExc)
static PyObject * lcl_getitem_string(PyUNO const *me, PyObject *pKey, Runtime const &runtime)
Definition: pyuno.cxx:767
PyObject * PyUNO_iterator_new(const css::uno::Reference< css::container::XEnumeration > &xEnumeration)
static int PyUNO_setitem(PyObject *self, PyObject *pKey, PyObject *pValue)
Definition: pyuno.cxx:1135
static int PyUNO_bool(PyObject *self)
Definition: pyuno.cxx:516
static PyTypeObject PyUNOType
Definition: pyuno.cxx:1603
OUString val2str(const void *pVal, typelib_TypeDescriptionReference *pTypeRef, sal_Int32 mode)
Definition: pyuno.cxx:87
static void lcl_getRowsColumns(PyUNO const *me, sal_Int32 &nRows, sal_Int32 &nColumns)
Definition: pyuno.cxx:557
static PyObject * lcl_getitem_slice(PyUNO const *me, PyObject *pKey)
Definition: pyuno.cxx:726
static PyObject * PyUNO_getitem(PyObject *self, PyObject *pKey)
Definition: pyuno.cxx:790
int PyUNO_initType()
Definition: pyuno.cxx:1674
OUString pyString2ustring(PyObject *str)
Definition: pyuno_util.cxx:57
PyObject * PyUNO_invoke(PyObject *object, const char *name, PyObject *args)
Definition: pyuno.cxx:379
@ NOT_NULL
definition of a no acquire enum for ctors
Definition: pyuno.hxx:65
PyRef PyUNO_callable_new(const Reference< XInvocation2 > &my_inv, const OUString &methodName, enum ConversionMode mode)
PyRef getAnyClass(const Runtime &)
Definition: pyuno_type.cxx:120
static bool lcl_hasInterfaceByName(Any const &object, OUString const &interfaceName)
Definition: pyuno.cxx:353
static PyMappingMethods PyUNOMappingMethods[]
Definition: pyuno.cxx:1596
static PyObject * PyUNO_iter(PyObject *self)
Definition: pyuno.cxx:1188
static int lcl_setitem_index(PyUNO const *me, PyObject *pKey, PyObject *pValue)
Definition: pyuno.cxx:877
PyRef getPyUnoClass()
Definition: pyuno.cxx:1679
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
ConversionMode mode
Reference< XInvocation2 > xInvocation
#define Py_TPFLAGS_HAVE_SEQUENCE_IN
Definition: pyuno_impl.hxx:36
#define Py_TPFLAGS_HAVE_ITER
Definition: pyuno_impl.hxx:30
#define Py_TPFLAGS_HAVE_RICHCOMPARE
Definition: pyuno_impl.hxx:33
css::uno::Any wrappedObject
Definition: pyuno_impl.hxx:132
css::uno::Reference< css::script::XInvocation2 > xInvocation
Definition: pyuno_impl.hxx:131
PyObject_HEAD PyUNOInternals * members
Definition: pyuno_impl.hxx:138
css::uno::Reference< css::script::XTypeConverter > xTypeConverter
Definition: pyuno_impl.hxx:217
PyObject_HEAD struct RuntimeCargo * cargo
Definition: pyuno_impl.hxx:238
#define SAL_MAX_INT32
unsigned char sal_Bool
#define SAL_MIN_INT32
sal_uInt16 sal_Unicode
signed char sal_Int8
Any result