1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
24 #include "pyuno_impl.hxx"
26 #include <rtl/strbuf.hxx>
27 #include <rtl/ustrbuf.hxx>
29 #include <osl/thread.h>
31 #include <com/sun/star/lang/XServiceInfo.hpp>
32 #include <com/sun/star/lang/XTypeProvider.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/XMaterialHolder.hpp>
36 using com::sun::star::uno::Sequence
;
37 using com::sun::star::uno::Reference
;
38 using com::sun::star::uno::XInterface
;
39 using com::sun::star::uno::Any
;
40 using com::sun::star::uno::makeAny
;
41 using com::sun::star::uno::UNO_QUERY
;
42 using com::sun::star::uno::Type
;
43 using com::sun::star::uno::TypeClass
;
44 using com::sun::star::uno::RuntimeException
;
45 using com::sun::star::uno::Exception
;
46 using com::sun::star::uno::XComponentContext
;
47 using com::sun::star::lang::XSingleServiceFactory
;
48 using com::sun::star::lang::XServiceInfo
;
49 using com::sun::star::lang::XTypeProvider
;
50 using com::sun::star::script::XTypeConverter
;
51 using com::sun::star::script::XInvocation2
;
52 using com::sun::star::beans::XMaterialHolder
;
57 PyObject
*PyUNO_str( PyObject
* self
);
59 void PyUNO_del (PyObject
* self
)
61 PyUNO
* me
= reinterpret_cast< PyUNO
* > (self
);
63 PyThreadDetach antiguard
;
71 OUString
val2str( const void * pVal
, typelib_TypeDescriptionReference
* pTypeRef
, sal_Int32 mode
)
74 if (pTypeRef
->eTypeClass
== typelib_TypeClass_VOID
)
75 return OUString("void");
77 OUStringBuffer
buf( 64 );
79 buf
.append( pTypeRef
->pTypeName
);
82 switch (pTypeRef
->eTypeClass
)
84 case typelib_TypeClass_INTERFACE
:
87 buf
.append( reinterpret_cast< sal_IntPtr
>(*static_cast<void * const *>(pVal
)), 16 );
88 if( VAL2STR_MODE_DEEP
== mode
)
90 buf
.append( "{" ); Reference
< XInterface
> r
= *static_cast<Reference
< XInterface
> const *>(pVal
);
91 Reference
< XServiceInfo
> serviceInfo( r
, UNO_QUERY
);
92 Reference
< XTypeProvider
> typeProvider(r
,UNO_QUERY
);
93 if( serviceInfo
.is() )
95 buf
.append("implementationName=" );
96 buf
.append(serviceInfo
->getImplementationName() );
97 buf
.append(", supportedServices={" );
98 Sequence
< OUString
> seq
= serviceInfo
->getSupportedServiceNames();
99 for( int i
= 0 ; i
< seq
.getLength() ; i
++ )
101 buf
.append( seq
[i
] );
102 if( i
+1 != seq
.getLength() )
108 if( typeProvider
.is() )
110 buf
.append(", supportedInterfaces={" );
111 Sequence
< Type
> seq (typeProvider
->getTypes());
112 for( int i
= 0 ; i
< seq
.getLength() ; i
++ )
114 buf
.append(seq
[i
].getTypeName());
115 if( i
+1 != seq
.getLength() )
125 case typelib_TypeClass_STRUCT
:
126 case typelib_TypeClass_EXCEPTION
:
129 typelib_TypeDescription
* pTypeDescr
= 0;
130 TYPELIB_DANGER_GET( &pTypeDescr
, pTypeRef
);
131 assert( pTypeDescr
);
133 typelib_CompoundTypeDescription
* pCompType
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTypeDescr
);
134 sal_Int32 nDescr
= pCompType
->nMembers
;
136 if (pCompType
->pBaseTypeDescription
)
138 buf
.append( val2str( pVal
, pCompType
->pBaseTypeDescription
->aBase
.pWeakRef
, mode
) );
143 typelib_TypeDescriptionReference
** ppTypeRefs
= pCompType
->ppTypeRefs
;
144 sal_Int32
* pMemberOffsets
= pCompType
->pMemberOffsets
;
145 rtl_uString
** ppMemberNames
= pCompType
->ppMemberNames
;
147 for ( sal_Int32 nPos
= 0; nPos
< nDescr
; ++nPos
)
149 buf
.append( ppMemberNames
[nPos
] );
151 typelib_TypeDescription
* pMemberType
= 0;
152 TYPELIB_DANGER_GET( &pMemberType
, ppTypeRefs
[nPos
] );
153 buf
.append( val2str( static_cast<char const *>(pVal
) + pMemberOffsets
[nPos
], pMemberType
->pWeakRef
, mode
) );
154 TYPELIB_DANGER_RELEASE( pMemberType
);
155 if (nPos
< (nDescr
-1))
159 TYPELIB_DANGER_RELEASE( pTypeDescr
);
164 case typelib_TypeClass_SEQUENCE
:
166 typelib_TypeDescription
* pTypeDescr
= 0;
167 TYPELIB_DANGER_GET( &pTypeDescr
, pTypeRef
);
169 uno_Sequence
* pSequence
= *static_cast<uno_Sequence
* const *>(pVal
);
170 typelib_TypeDescription
* pElementTypeDescr
= 0;
171 TYPELIB_DANGER_GET( &pElementTypeDescr
, reinterpret_cast<typelib_IndirectTypeDescription
*>(pTypeDescr
)->pType
);
173 sal_Int32 nElementSize
= pElementTypeDescr
->nSize
;
174 sal_Int32 nElements
= pSequence
->nElements
;
179 char * pElements
= pSequence
->elements
;
180 for ( sal_Int32 nPos
= 0; nPos
< nElements
; ++nPos
)
182 buf
.append( val2str( pElements
+ (nElementSize
* nPos
), pElementTypeDescr
->pWeakRef
, mode
) );
183 if (nPos
< (nElements
-1))
192 TYPELIB_DANGER_RELEASE( pElementTypeDescr
);
193 TYPELIB_DANGER_RELEASE( pTypeDescr
);
196 case typelib_TypeClass_ANY
:
198 buf
.append( val2str( static_cast<uno_Any
const *>(pVal
)->pData
,
199 static_cast<uno_Any
const *>(pVal
)->pType
,
203 case typelib_TypeClass_TYPE
:
204 buf
.append( (*static_cast<typelib_TypeDescriptionReference
* const *>(pVal
))->pTypeName
);
206 case typelib_TypeClass_STRING
:
208 buf
.append( *static_cast<rtl_uString
* const *>(pVal
) );
211 case typelib_TypeClass_ENUM
:
213 typelib_TypeDescription
* pTypeDescr
= 0;
214 TYPELIB_DANGER_GET( &pTypeDescr
, pTypeRef
);
216 sal_Int32
* pValues
= reinterpret_cast<typelib_EnumTypeDescription
*>(pTypeDescr
)->pEnumValues
;
217 sal_Int32 nPos
= reinterpret_cast<typelib_EnumTypeDescription
*>(pTypeDescr
)->nEnumValues
;
220 if (pValues
[nPos
] == *static_cast<int const *>(pVal
))
224 buf
.append( reinterpret_cast<typelib_EnumTypeDescription
*>(pTypeDescr
)->ppEnumNames
[nPos
] );
228 TYPELIB_DANGER_RELEASE( pTypeDescr
);
231 case typelib_TypeClass_BOOLEAN
:
232 if (*static_cast<sal_Bool
const *>(pVal
))
233 buf
.append( "true" );
235 buf
.append( "false" );
237 case typelib_TypeClass_CHAR
:
239 buf
.append( *static_cast<sal_Unicode
const *>(pVal
) );
242 case typelib_TypeClass_FLOAT
:
243 buf
.append( *static_cast<float const *>(pVal
) );
245 case typelib_TypeClass_DOUBLE
:
246 buf
.append( *static_cast<double const *>(pVal
) );
248 case typelib_TypeClass_BYTE
:
250 buf
.append( (sal_Int32
)*static_cast<sal_Int8
const *>(pVal
), 16 );
252 case typelib_TypeClass_SHORT
:
254 buf
.append( (sal_Int32
)*static_cast<sal_Int16
const *>(pVal
), 16 );
256 case typelib_TypeClass_UNSIGNED_SHORT
:
258 buf
.append( (sal_Int32
)*static_cast<sal_uInt16
const *>(pVal
), 16 );
260 case typelib_TypeClass_LONG
:
262 buf
.append( *static_cast<sal_Int32
const *>(pVal
), 16 );
264 case typelib_TypeClass_UNSIGNED_LONG
:
266 buf
.append( (sal_Int64
)*static_cast<sal_uInt32
const *>(pVal
), 16 );
268 case typelib_TypeClass_HYPER
:
269 case typelib_TypeClass_UNSIGNED_HYPER
:
271 #if defined(__GNUC__) && defined(SPARC)
272 // I guess this really should check if there are strict alignment
273 // requirements, not just "GCC on SPARC".
276 *(sal_Int32
*)&aVal
= *(sal_Int32
*)pVal
;
277 *((sal_Int32
*)&aVal
+1)= *((sal_Int32
*)pVal
+1);
278 buf
.append( aVal
, 16 );
281 buf
.append( *static_cast<sal_Int64
const *>(pVal
), 16 );
285 case typelib_TypeClass_VOID
:
286 case typelib_TypeClass_UNKNOWN
:
287 case typelib_TypeClass_SERVICE
:
288 case typelib_TypeClass_MODULE
:
293 return buf
.makeStringAndClear();
297 PyObject
*PyUNO_repr( PyObject
* self
)
299 PyUNO
*me
= reinterpret_cast<PyUNO
*>(self
);
302 if( me
->members
->wrappedObject
.getValueType().getTypeClass()
303 == com::sun::star::uno::TypeClass_EXCEPTION
)
305 Reference
< XMaterialHolder
> rHolder(me
->members
->xInvocation
,UNO_QUERY
);
308 Any a
= rHolder
->getMaterial();
311 ret
= ustring2PyUnicode(e
.Message
).getAcquired();
316 ret
= PyUNO_str( self
);
321 PyObject
*PyUNO_invoke( PyObject
*object
, const char *name
, PyObject
*args
)
328 PyRef paras
,callable
;
329 if( PyObject_IsInstance( object
, getPyUnoClass().get() ) )
331 PyUNO
* me
= reinterpret_cast<PyUNO
*>(object
);
332 OUString attrName
= OUString::createFromAscii(name
);
333 if (! me
->members
->xInvocation
->hasMethod (attrName
))
336 buf
.append( "Attribute " );
337 buf
.append( attrName
);
338 buf
.append( " unknown" );
339 throw RuntimeException( buf
.makeStringAndClear() );
341 callable
= PyUNO_callable_new (
342 me
->members
->xInvocation
,
349 // clean the tuple from uno.Any !
350 int size
= PyTuple_Size( args
);
351 { // for CC, keeping ref-count of tuple being 1
352 paras
= PyRef(PyTuple_New( size
), SAL_NO_ACQUIRE
);
354 for( int i
= 0 ; i
< size
;i
++ )
356 PyObject
* element
= PyTuple_GetItem( args
, i
);
357 if( PyObject_IsInstance( element
, getAnyClass( runtime
).get() ) )
359 element
= PyObject_GetAttrString(
364 Py_XINCREF( element
);
366 PyTuple_SetItem( paras
.get(), i
, element
);
368 callable
= PyRef( PyObject_GetAttrString( object
, name
), SAL_NO_ACQUIRE
);
372 ret
= PyRef( PyObject_CallObject( callable
.get(), paras
.get() ), SAL_NO_ACQUIRE
);
374 catch (const ::com::sun::star::lang::IllegalArgumentException
&e
)
376 raisePyExceptionWithAny( com::sun::star::uno::makeAny( e
) );
378 catch (const ::com::sun::star::script::CannotConvertException
&e
)
380 raisePyExceptionWithAny( com::sun::star::uno::makeAny( e
) );
382 catch (const ::com::sun::star::uno::RuntimeException
&e
)
384 raisePyExceptionWithAny( com::sun::star::uno::makeAny( e
) );
386 catch (const ::com::sun::star::uno::Exception
&e
)
388 raisePyExceptionWithAny( com::sun::star::uno::makeAny( e
) );
391 return ret
.getAcquired();
394 PyObject
*PyUNO_str( PyObject
* self
)
396 PyUNO
*me
= reinterpret_cast<PyUNO
*>(self
);
401 if( me
->members
->wrappedObject
.getValueType().getTypeClass()
402 == com::sun::star::uno::TypeClass_STRUCT
||
403 me
->members
->wrappedObject
.getValueType().getTypeClass()
404 == com::sun::star::uno::TypeClass_EXCEPTION
)
406 Reference
< XMaterialHolder
> rHolder(me
->members
->xInvocation
,UNO_QUERY
);
409 PyThreadDetach antiguard
;
410 Any a
= rHolder
->getMaterial();
411 OUString s
= val2str( a
.getValue(), a
.getValueType().getTypeLibType() );
412 buf
.append( OUStringToOString(s
,RTL_TEXTENCODING_ASCII_US
) );
417 // a common UNO object
418 PyThreadDetach antiguard
;
419 buf
.append( "pyuno object " );
421 OUString s
= val2str( me
->members
->wrappedObject
.getValue(),
422 me
->members
->wrappedObject
.getValueType().getTypeLibType() );
423 buf
.append( OUStringToOString(s
,RTL_TEXTENCODING_ASCII_US
) );
426 return PyStr_FromString( buf
.getStr());
429 PyObject
* PyUNO_dir (PyObject
* self
)
431 PyUNO
* me
= reinterpret_cast<PyUNO
*>(self
);
433 PyObject
* member_list
= NULL
;
434 Sequence
<OUString
> oo_member_list
;
438 oo_member_list
= me
->members
->xInvocation
->getMemberNames ();
439 member_list
= PyList_New (oo_member_list
.getLength ());
440 for (int i
= 0; i
< oo_member_list
.getLength (); i
++)
442 // setitem steals a reference
443 PyList_SetItem (member_list
, i
, ustring2PyString(oo_member_list
[i
]).getAcquired() );
446 catch( const RuntimeException
&e
)
448 raisePyExceptionWithAny( makeAny(e
) );
455 PyObject
* PyUNO_getattr (PyObject
* self
, char* name
)
464 me
= reinterpret_cast<PyUNO
*>(self
);
465 if (strcmp (name
, "__dict__") == 0)
467 Py_INCREF (Py_TYPE(me
)->tp_dict
);
468 return Py_TYPE(me
)->tp_dict
;
470 if (strcmp (name
, "__class__") == 0)
472 if( me
->members
->wrappedObject
.getValueTypeClass() ==
473 com::sun::star::uno::TypeClass_STRUCT
||
474 me
->members
->wrappedObject
.getValueTypeClass() ==
475 com::sun::star::uno::TypeClass_EXCEPTION
)
478 me
->members
->wrappedObject
.getValueType().getTypeName(), runtime
).getAcquired();
484 OUString
attrName( OUString::createFromAscii( name
) );
485 //We need to find out if it's a method...
486 if (me
->members
->xInvocation
->hasMethod (attrName
))
488 //Create a callable object to invoke this...
489 PyRef ret
= PyUNO_callable_new (
490 me
->members
->xInvocation
,
492 Py_XINCREF( ret
.get() );
498 if (me
->members
->xInvocation
->hasProperty ( attrName
))
500 //Return the value of the property
503 PyThreadDetach antiguard
;
504 anyRet
= me
->members
->xInvocation
->getValue (attrName
);
506 PyRef ret
= runtime
.any2PyObject(anyRet
);
507 Py_XINCREF( ret
.get() );
512 PyErr_SetString (PyExc_AttributeError
, name
);
514 catch( const com::sun::star::reflection::InvocationTargetException
& e
)
516 raisePyExceptionWithAny( e
.TargetException
);
518 catch( const com::sun::star::beans::UnknownPropertyException
& e
)
520 raisePyExceptionWithAny( makeAny(e
) );
522 catch( const com::sun::star::lang::IllegalArgumentException
&e
)
524 raisePyExceptionWithAny( makeAny(e
) );
526 catch( const com::sun::star::script::CannotConvertException
&e
)
528 raisePyExceptionWithAny( makeAny(e
) );
530 catch( const RuntimeException
&e
)
532 raisePyExceptionWithAny( makeAny(e
) );
538 int PyUNO_setattr (PyObject
* self
, char* name
, PyObject
* value
)
542 me
= reinterpret_cast<PyUNO
*>(self
);
546 Any val
= runtime
.pyObject2Any(value
, ACCEPT_UNO_ANY
);
548 OUString
attrName( OUString::createFromAscii( name
) );
550 PyThreadDetach antiguard
;
551 if (me
->members
->xInvocation
->hasProperty (attrName
))
553 me
->members
->xInvocation
->setValue (attrName
, val
);
554 return 0; //Keep with Python's boolean system
558 catch( const com::sun::star::reflection::InvocationTargetException
& e
)
560 raisePyExceptionWithAny( e
.TargetException
);
563 catch( const com::sun::star::beans::UnknownPropertyException
& e
)
565 raisePyExceptionWithAny( makeAny(e
) );
568 catch( const com::sun::star::script::CannotConvertException
&e
)
570 raisePyExceptionWithAny( makeAny(e
) );
573 catch( const RuntimeException
& e
)
575 raisePyExceptionWithAny( makeAny( e
) );
578 PyErr_SetString (PyExc_AttributeError
, name
);
579 return 1; //as above.
582 // ensure object identity and struct equality
583 static PyObject
* PyUNO_cmp( PyObject
*self
, PyObject
*that
, int op
)
587 if(op
!= Py_EQ
&& op
!= Py_NE
)
589 PyErr_SetString(PyExc_TypeError
, "only '==' and '!=' comparisons are defined");
594 result
= (op
== Py_EQ
? Py_True
: Py_False
);
601 if( PyObject_IsInstance( that
, getPyUnoClass().get() ) )
604 PyUNO
*me
= reinterpret_cast< PyUNO
*> ( self
);
605 PyUNO
*other
= reinterpret_cast< PyUNO
*> (that
);
606 com::sun::star::uno::TypeClass tcMe
= me
->members
->wrappedObject
.getValueTypeClass();
607 com::sun::star::uno::TypeClass tcOther
= other
->members
->wrappedObject
.getValueTypeClass();
609 if( tcMe
== tcOther
)
611 if( tcMe
== com::sun::star::uno::TypeClass_STRUCT
||
612 tcMe
== com::sun::star::uno::TypeClass_EXCEPTION
)
614 Reference
< XMaterialHolder
> xMe( me
->members
->xInvocation
,UNO_QUERY
);
615 Reference
< XMaterialHolder
> xOther( other
->members
->xInvocation
,UNO_QUERY
);
616 if( xMe
->getMaterial() == xOther
->getMaterial() )
618 result
= (op
== Py_EQ
? Py_True
: Py_False
);
623 else if( tcMe
== com::sun::star::uno::TypeClass_INTERFACE
)
625 if( me
->members
->wrappedObject
== other
->members
->wrappedObject
)
627 result
= (op
== Py_EQ
? Py_True
: Py_False
);
635 catch( const com::sun::star::uno::RuntimeException
& e
)
637 raisePyExceptionWithAny( makeAny( e
) );
640 result
= (op
== Py_EQ
? Py_False
: Py_True
);
645 static PyMethodDef PyUNOMethods
[] =
647 {"__dir__", reinterpret_cast<PyCFunction
>(PyUNO_dir
), METH_NOARGS
, NULL
},
648 {NULL
, NULL
, 0, NULL
}
652 /* Python 2 has a tp_flags value for rich comparisons. Python 3 does not (on by default) */
653 #ifdef Py_TPFLAGS_HAVE_RICHCOMPARE
654 #define TP_FLAGS (Py_TPFLAGS_HAVE_RICHCOMPARE)
659 static PyTypeObject PyUNOType
=
661 PyVarObject_HEAD_INIT( &PyType_Type
, 0 )
665 (destructor
) PyUNO_del
,
667 (getattrfunc
) PyUNO_getattr
,
668 (setattrfunc
) PyUNO_setattr
,
669 /* this type does not exist in Python 3: (cmpfunc) */ 0,
670 (reprfunc
) PyUNO_repr
,
676 (reprfunc
) PyUNO_str
,
684 (richcmpfunc
) PyUNO_cmp
,
707 #if PY_VERSION_HEX >= 0x02060000
710 #if PY_VERSION_HEX >= 0x03040000
717 return PyType_Ready(&PyUNOType
);
720 PyRef
getPyUnoClass()
722 return PyRef( reinterpret_cast< PyObject
* > ( &PyUNOType
) );
725 PyObject
* PyUNO_new (
726 const Any
& targetInterface
, const Reference
<XSingleServiceFactory
> &ssf
)
728 Reference
<XInterface
> tmp_interface
;
730 targetInterface
>>= tmp_interface
;
732 if (!tmp_interface
.is ())
735 Py_INCREF( Py_None
);
738 return PyUNO_new_UNCHECKED (targetInterface
, ssf
);
742 PyObject
* PyUNO_new_UNCHECKED (
743 const Any
&targetInterface
,
744 const Reference
<XSingleServiceFactory
> &ssf
)
746 Reference
<XInterface
> tmp_interface
;
747 Reference
<XInvocation2
> tmp_invocation
;
749 PyThreadDetach antiguard
;
750 Sequence
<Any
> arguments(1);
751 arguments
[0] <<= targetInterface
;
752 tmp_interface
= ssf
->createInstanceWithArguments(arguments
);
753 tmp_invocation
.set(tmp_interface
, UNO_QUERY
);
754 if (!tmp_invocation
.is() && tmp_interface
.is()) {
755 throw RuntimeException("XInvocation2 not implemented, cannot interact with object");
758 if (!tmp_interface
.is())
760 Py_INCREF( Py_None
);
763 PyUNO
* self
= PyObject_New (PyUNO
, &PyUNOType
);
765 return NULL
; // == error
766 self
->members
= new PyUNOInternals();
767 self
->members
->xInvocation
= tmp_invocation
;
768 self
->members
->wrappedObject
= targetInterface
;
769 return reinterpret_cast<PyObject
*>(self
);
774 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */