1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #include "pyuno_impl.hxx"
24 
25 #include <rtl/ustrbuf.hxx>
26 #include <rtl/strbuf.hxx>
27 
28 #include <typelib/typedescription.hxx>
29 
30 using rtl::OString;
31 using rtl::OUString;
32 using rtl::OUStringBuffer;
33 using rtl::OUStringToOString;
34 using rtl::OStringBuffer;
35 
36 using com::sun::star::uno::TypeClass;
37 using com::sun::star::uno::Type;
38 using com::sun::star::uno::RuntimeException;
39 using com::sun::star::uno::Any;
40 using com::sun::star::uno::XInterface;
41 using com::sun::star::uno::Reference;
42 using com::sun::star::uno::TypeDescription;
43 
44 #define USTR_ASCII(x) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
45 namespace pyuno
46 {
typeClassToString(TypeClass t)47 const char *typeClassToString( TypeClass t )
48 {
49     const char * ret = 0;
50     switch (t)
51     {
52     case com::sun::star::uno::TypeClass_VOID:
53         ret = "VOID"; break;
54     case com::sun::star::uno::TypeClass_CHAR:
55         ret = "CHAR"; break;
56     case com::sun::star::uno::TypeClass_BOOLEAN:
57         ret = "BOOLEAN"; break;
58     case com::sun::star::uno::TypeClass_BYTE:
59         ret = "BYTE"; break;
60     case com::sun::star::uno::TypeClass_SHORT:
61         ret = "SHORT"; break;
62     case com::sun::star::uno::TypeClass_UNSIGNED_SHORT:
63         ret = "UNSIGNED_SHORT"; break;
64     case com::sun::star::uno::TypeClass_LONG:
65         ret = "LONG"; break;
66     case com::sun::star::uno::TypeClass_UNSIGNED_LONG:
67         ret = "UNSIGNED_LONG"; break;
68     case com::sun::star::uno::TypeClass_HYPER:
69         ret = "HYPER"; break;
70     case com::sun::star::uno::TypeClass_UNSIGNED_HYPER:
71 	    ret = "UNSIGNED_HYPER"; break;
72     case com::sun::star::uno::TypeClass_FLOAT:
73         ret = "FLOAT"; break;
74     case com::sun::star::uno::TypeClass_DOUBLE:
75         ret = "DOUBLE"; break;
76     case com::sun::star::uno::TypeClass_STRING:
77         ret = "STRING"; break;
78     case com::sun::star::uno::TypeClass_TYPE:
79         ret = "TYPE"; break;
80     case com::sun::star::uno::TypeClass_ANY:
81         ret = "ANY";break;
82     case com::sun::star::uno::TypeClass_ENUM:
83         ret = "ENUM";break;
84     case com::sun::star::uno::TypeClass_STRUCT:
85         ret = "STRUCT"; break;
86     case com::sun::star::uno::TypeClass_EXCEPTION:
87         ret = "EXCEPTION"; break;
88     case com::sun::star::uno::TypeClass_SEQUENCE:
89         ret = "SEQUENCE"; break;
90     case com::sun::star::uno::TypeClass_INTERFACE:
91         ret = "INTERFACE"; break;
92     case com::sun::star::uno::TypeClass_TYPEDEF:
93         ret = "TYPEDEF"; break;
94     case com::sun::star::uno::TypeClass_UNION:
95         ret = "UNION"; break;
96     case com::sun::star::uno::TypeClass_ARRAY:
97         ret = "ARRAY"; break;
98     case com::sun::star::uno::TypeClass_SERVICE:
99         ret = "SERVICE"; break;
100     case com::sun::star::uno::TypeClass_MODULE:
101         ret = "MODULE"; break;
102     case com::sun::star::uno::TypeClass_INTERFACE_METHOD:
103         ret = "INTERFACE_METHOD"; break;
104     case com::sun::star::uno::TypeClass_INTERFACE_ATTRIBUTE:
105         ret = "INTERFACE_ATTRIBUTE"; break;
106     default:
107         ret = "UNKNOWN"; break;
108     }
109     return ret;
110 }
111 
getClass(const Runtime & r,const char * name)112 static PyRef getClass( const Runtime & r , const char * name)
113 {
114     return PyRef( PyDict_GetItemString( r.getImpl()->cargo->getUnoModule().get(), (char*) name ) );
115 }
116 
getTypeClass(const Runtime & r)117 PyRef getTypeClass( const Runtime & r )
118 {
119     return getClass( r , "Type" );
120 }
121 
getEnumClass(const Runtime & r)122 PyRef getEnumClass( const Runtime & r )
123 {
124     return getClass( r , "Enum" );
125 }
126 
getCharClass(const Runtime & r)127 PyRef getCharClass( const Runtime & r )
128 {
129     return getClass( r , "Char" );
130 }
131 
getByteSequenceClass(const Runtime & r)132 PyRef getByteSequenceClass( const Runtime & r )
133 {
134     return getClass( r , "ByteSequence" );
135 }
136 
getAnyClass(const Runtime & r)137 PyRef getAnyClass( const Runtime & r )
138 {
139     return getClass( r , "Any" );
140 }
141 
142 
PyChar2Unicode(PyObject * obj)143 sal_Unicode PyChar2Unicode( PyObject *obj ) throw ( RuntimeException )
144 {
145     PyRef value( PyObject_GetAttrString( obj, const_cast< char * >("value") ), SAL_NO_ACQUIRE );
146     if( ! PyUnicode_Check( value.get() ) )
147     {
148         throw RuntimeException(
149             USTR_ASCII( "attribute value of uno.Char is not a unicode string" ),
150             Reference< XInterface > () );
151     }
152 
153     if( PyUnicode_GetSize( value.get() ) < 1 )
154     {
155         throw RuntimeException(
156             USTR_ASCII( "uno.Char contains an empty unicode string" ),
157             Reference< XInterface > () );
158     }
159 #if PY_VERSION_HEX >= 0x03030000
160     sal_Unicode c = (sal_Unicode)PyUnicode_ReadChar( value.get(), 0 );
161 #else
162     sal_Unicode c = (sal_Unicode)PyUnicode_AsUnicode( value.get() )[0];
163 #endif
164     return c;
165 }
166 
PyEnum2Enum(PyObject * obj)167 Any PyEnum2Enum( PyObject *obj ) throw ( RuntimeException )
168 {
169     Any ret;
170     PyRef typeName( PyObject_GetAttrString( obj,const_cast< char * >("typeName") ), SAL_NO_ACQUIRE);
171     PyRef value( PyObject_GetAttrString( obj, const_cast< char * >("value") ), SAL_NO_ACQUIRE);
172     if( !PYSTR_CHECK( typeName.get() ) || ! PYSTR_CHECK( value.get() ) )
173     {
174         throw RuntimeException(
175             USTR_ASCII( "attributes typeName and/or value of uno.Enum are not strings" ),
176             Reference< XInterface > () );
177     }
178 
179     OUString strTypeName( pyString2ustring( typeName.get() ) );
180     OUString strValue( pyString2ustring( value.get() ) );
181 
182     TypeDescription desc( strTypeName );
183     if( desc.is() )
184     {
185         if(desc.get()->eTypeClass != typelib_TypeClass_ENUM )
186         {
187             OUStringBuffer buf;
188             buf.appendAscii( "pyuno.checkEnum: " ).append( strTypeName ).appendAscii( " is a " );
189             buf.appendAscii(
190                 typeClassToString( (com::sun::star::uno::TypeClass) desc.get()->eTypeClass));
191             buf.appendAscii( ", expected ENUM" );
192             throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface>  () );
193         }
194 
195         desc.makeComplete();
196 
197         typelib_EnumTypeDescription *pEnumDesc = (typelib_EnumTypeDescription*) desc.get();
198         int i = 0;
199         for( i = 0; i < pEnumDesc->nEnumValues ; i ++ )
200         {
201             if( (*((OUString *)&pEnumDesc->ppEnumNames[i])).compareTo( strValue ) == 0 )
202             {
203                 break;
204             }
205         }
206         if( i == pEnumDesc->nEnumValues )
207         {
208             OUStringBuffer buf;
209             buf.appendAscii( "value " ).append( strValue ).appendAscii( " is unknown in enum " );
210             buf.append( strTypeName );
211             throw RuntimeException( buf.makeStringAndClear(), Reference<XInterface> () );
212         }
213         ret = Any( &pEnumDesc->pEnumValues[i], desc.get()->pWeakRef );
214     }
215     else
216     {
217         OUStringBuffer buf;
218         buf.appendAscii( "enum " ).append( strTypeName ).appendAscii( " is unknown" );
219         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface>  () );
220     }
221     return ret;
222 }
223 
224 
PyType2Type(PyObject * o)225 Type PyType2Type( PyObject * o ) throw(RuntimeException )
226 {
227     PyRef pyName( PyObject_GetAttrString( o, const_cast< char * >("typeName") ), SAL_NO_ACQUIRE);
228     if( !PYSTR_CHECK( pyName.get() ) )
229     {
230         throw RuntimeException(
231             USTR_ASCII( "type object does not have typeName property" ),
232             Reference< XInterface > () );
233     }
234 
235     PyRef pyTC( PyObject_GetAttrString( o, const_cast< char * >("typeClass") ), SAL_NO_ACQUIRE );
236     Any enumValue = PyEnum2Enum( pyTC.get() );
237 
238     OUString name( pyString2ustring( pyName.get() ) );
239     TypeDescription desc( name );
240     if( ! desc.is() )
241     {
242         OUStringBuffer buf;
243         buf.appendAscii( "type " ).append(name).appendAscii( " is unknown" );
244         throw RuntimeException(
245             buf.makeStringAndClear(), Reference< XInterface > () );
246     }
247     if( desc.get()->eTypeClass != (typelib_TypeClass) *(sal_Int32*)enumValue.getValue() )
248     {
249         OUStringBuffer buf;
250         buf.appendAscii( "pyuno.checkType: " ).append(name).appendAscii( " is a " );
251         buf.appendAscii( typeClassToString( (TypeClass) desc.get()->eTypeClass) );
252         buf.appendAscii( ", but type got construct with typeclass " );
253         buf.appendAscii( typeClassToString( (TypeClass) *(sal_Int32*)enumValue.getValue() ) );
254         throw RuntimeException(
255             buf.makeStringAndClear(), Reference< XInterface > () );
256     }
257     return desc.get()->pWeakRef;
258 }
259 
importToGlobal(PyObject * str,PyObject * dict,PyObject * target)260 PyObject *importToGlobal(PyObject *str, PyObject *dict, PyObject *target)
261 {
262     // maybe a constant ?
263     PyObject *ret = 0;
264     OUString name = pyString2ustring(str);
265     try
266     {
267         Runtime runtime;
268         TypeDescription desc(name );
269         desc.makeComplete();
270         if( desc.is() )
271         {
272             com::sun::star::uno::TypeClass tc =
273                 (com::sun::star::uno::TypeClass)desc.get()->eTypeClass;
274 
275             PyRef typesModule( PyDict_GetItemString( dict, "unotypes" ) );
276             if( ! typesModule.is() || ! PyModule_Check( typesModule.get() ))
277             {
278                 typesModule = PyRef( PyModule_New( const_cast< char * >("unotypes") ), SAL_NO_ACQUIRE );
279                 Py_INCREF( typesModule.get() );
280                 PyDict_SetItemString( dict, "unotypes" , typesModule.get() );
281             }
282 #if PY_VERSION_HEX >= 0x03030000
283             const char *targetName = PyUnicode_AsUTF8( target );
284             const char *typeName = PyUnicode_AsUTF8( str );
285 #elif PY_MAJOR_VERSION > 3
286             PyRef pUtf8( PyUnicode_AsUTF8String( target ), SAL_NO_ACQUIRE );
287             const char *targetName = PyBytes_AsString( pUtf8.get() );
288             PyRef pTypeName( PyUnicode_AsUTF8String( str ), SAL_NO_ACQUIRE );
289             const char *typeName = PyBytes_AsString( pTypeName.get() );
290 #else
291             /*const*/ char *targetName = PyBytes_AsString( target );
292             const char *typeName = PyBytes_AsString( str );
293 #endif
294             PyModule_AddObject(
295                 typesModule.get(),
296                 targetName,
297                 PyUNO_Type_new( typeName, tc, runtime ) );
298 
299             if( com::sun::star::uno::TypeClass_EXCEPTION == tc ||
300                 com::sun::star::uno::TypeClass_STRUCT    == tc )
301             {
302                 PyRef exc = getClass( name, runtime );
303                 PyDict_SetItem( dict, target, exc.getAcquired() );
304             }
305             else if( com::sun::star::uno::TypeClass_ENUM == tc )
306             {
307                 // introduce all enums into the dictionary !
308                 typelib_EnumTypeDescription *pDesc =
309                     (typelib_EnumTypeDescription *) desc.get();
310                 for( int i = 0 ; i < pDesc->nEnumValues; i ++ )
311                 {
312                     OString enumElementName(
313                         OUStringToOString( pDesc->ppEnumNames[i], RTL_TEXTENCODING_ASCII_US) );
314 #if PY_VERSION_HEX >= 0x03030000
315                     const char *name = PyUnicode_AsUTF8(str);
316 #elif PY_MAJOR_VERSION > 3
317                     PyRef *pUtf8( PyUnicode_AsUTF8String( str ), SAL_NO_ACQUIRE );
318                     const char *name = PyBytes_AsString( pUtf8.get() );
319 #else
320                     const char *name = PyBytes_AsString(str);
321 #endif
322                     PyDict_SetItemString(
323                         dict, (char*)enumElementName.getStr(),
324                         PyUNO_Enum_new(name, enumElementName.getStr(), runtime ) );
325                 }
326             }
327             Py_INCREF( Py_None );
328             ret = Py_None;
329         }
330         else
331         {
332             Any a = runtime.getImpl()->cargo->xTdMgr->getByHierarchicalName(name);
333             if(a.hasValue())
334             {
335                 PyRef constant = runtime.any2PyObject( a );
336                 if( constant.is() )
337                 {
338                     Py_INCREF( constant.get() );
339                     PyDict_SetItem( dict, target , constant.get());
340                     ret = constant.get();
341                 }
342                 else
343                 {
344                     OUStringBuffer buf;
345                     buf.appendAscii( "constant " ).append(pyString2ustring(str)).appendAscii(  " unknown" );
346                     PyErr_SetString(
347                         PyExc_RuntimeError,
348                         OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_UTF8).getStr() );
349                 }
350             }
351             else
352             {
353                 OUStringBuffer buf;
354                 buf.appendAscii( "pyuno.imp unknown type " );
355                 buf.append( name );
356                 PyErr_SetString(
357                     PyExc_RuntimeError,
358                     OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US).getStr() );
359             }
360         }
361     }
362     catch( com::sun::star::container::NoSuchElementException & )
363     {
364         OUStringBuffer buf;
365         buf.appendAscii( "pyuno.imp unknown type " );
366         buf.append( name );
367         PyErr_SetString(
368             PyExc_RuntimeError,
369             OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US).getStr() );
370     }
371     catch( com::sun::star::script::CannotConvertException & e )
372     {
373         raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
374     }
375     catch( com::sun::star::lang::IllegalArgumentException & e )
376     {
377         raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
378     }
379     catch( RuntimeException &e )
380     {
381         raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ));
382     }
383     return ret;
384 }
385 
callCtor(const Runtime & r,const char * clazz,const PyRef & args)386 static PyObject* callCtor( const Runtime &r , const char * clazz, const PyRef & args )
387 {
388     PyRef code( PyDict_GetItemString( r.getImpl()->cargo->getUnoModule().get(), (char*)clazz ) );
389     if( ! code.is() )
390     {
391         OStringBuffer buf;
392         buf.append( "couldn't access uno." );
393         buf.append( clazz );
394         PyErr_SetString( PyExc_RuntimeError, buf.getStr() );
395         return NULL;
396     }
397     PyRef instance( PyObject_CallObject( code.get(), args.get()  ), SAL_NO_ACQUIRE);
398     Py_XINCREF( instance.get() );
399     return instance.get();
400 
401 }
402 
403 
PyUNO_Enum_new(const char * enumBase,const char * enumValue,const Runtime & r)404 PyObject *PyUNO_Enum_new( const char *enumBase, const char *enumValue, const Runtime &r )
405 {
406     PyRef args( PyTuple_New( 2 ), SAL_NO_ACQUIRE );
407     PyTuple_SetItem( args.get() , 0 , PYSTR_FROMSTR( enumBase ) );
408     PyTuple_SetItem( args.get() , 1 , PYSTR_FROMSTR( enumValue ) );
409 
410     return callCtor( r, "Enum" , args );
411 }
412 
413 
PyUNO_Type_new(const char * typeName,TypeClass t,const Runtime & r)414 PyObject* PyUNO_Type_new (const char *typeName , TypeClass t , const Runtime &r )
415 {
416     // retrieve type object
417     PyRef args( PyTuple_New( 2 ), SAL_NO_ACQUIRE );
418 
419     PyTuple_SetItem( args.get() , 0 , PYSTR_FROMSTR( typeName ) );
420     PyObject *typeClass = PyUNO_Enum_new( "com.sun.star.uno.TypeClass" , typeClassToString(t), r );
421     if( ! typeClass )
422         return NULL;
423     PyTuple_SetItem( args.get() , 1 , typeClass);
424 
425     return callCtor( r, "Type" , args );
426 }
427 
PyUNO_char_new(sal_Unicode val,const Runtime & r)428 PyObject* PyUNO_char_new ( sal_Unicode val , const Runtime &r )
429 {
430     // retrieve type object
431     PyRef args( PyTuple_New( 1 ), SAL_NO_ACQUIRE );
432 
433 #if PY_VERSION_HEX >= 0x03030000
434     Py_UCS2 u[1];
435     u[0] = val;
436     PyTuple_SetItem( args.get(), 0, PyUnicode_FromKindAndData( PyUnicode_2BYTE_KIND, u, 1 ) );
437 #else
438     Py_UNICODE u[2];
439     u[0] = val;
440     u[1] = 0;
441     PyTuple_SetItem( args.get() , 0 , PyUnicode_FromUnicode( u ,1) );
442 #endif
443 
444     return callCtor( r, "Char" , args );
445 }
446 
PyUNO_ByteSequence_new(const com::sun::star::uno::Sequence<sal_Int8> & byteSequence,const Runtime & r)447 PyObject *PyUNO_ByteSequence_new(
448     const com::sun::star::uno::Sequence< sal_Int8 > &byteSequence, const Runtime &r )
449 {
450     PyRef str(
451         PyBytes_FromStringAndSize( (char*)byteSequence.getConstArray(), byteSequence.getLength()),
452         SAL_NO_ACQUIRE );
453     PyRef args( PyTuple_New( 1 ), SAL_NO_ACQUIRE );
454     PyTuple_SetItem( args.get() , 0 , str.getAcquired() );
455     return callCtor( r, "ByteSequence" , args );
456 
457 }
458 }
459