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 
27 #include <typelib/typedescription.hxx>
28 
29 using rtl::OUString;
30 using rtl::OUStringBuffer;
31 using rtl::OUStringToOString;
32 
33 using com::sun::star::uno::RuntimeException;
34 using com::sun::star::uno::Sequence;
35 using com::sun::star::uno::Type;
36 using com::sun::star::uno::Reference;
37 using com::sun::star::uno::XInterface;
38 using com::sun::star::uno::TypeDescription;
39 
40 namespace pyuno
41 {
42 
raisePyExceptionWithAny(const com::sun::star::uno::Any & anyExc)43 void raisePyExceptionWithAny( const com::sun::star::uno::Any &anyExc )
44 {
45     try
46     {
47         Runtime runtime;
48         PyRef exc = runtime.any2PyObject( anyExc );
49         if( exc.is() )
50         {
51             PyRef type( getClass( anyExc.getValueType().getTypeName(),runtime ) );
52             PyErr_SetObject( type.get(), exc.get());
53         }
54         else
55         {
56             com::sun::star::uno::Exception e;
57             anyExc >>= e;
58 
59             OUStringBuffer buf;
60             buf.appendAscii( "Couldn't convert uno exception to a python exception (" );
61             buf.append(anyExc.getValueType().getTypeName());
62             buf.appendAscii( ": " );
63             buf.append(e.Message );
64             buf.appendAscii( ")" );
65             PyErr_SetString(
66                 PyExc_SystemError,
67                 OUStringToOString(buf.makeStringAndClear(),RTL_TEXTENCODING_ASCII_US) );
68         }
69     }
70     catch( com::sun::star::lang::IllegalArgumentException & e)
71     {
72         PyErr_SetString( PyExc_SystemError,
73                          OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) );
74     }
75     catch( com::sun::star::script::CannotConvertException & e)
76     {
77         PyErr_SetString( PyExc_SystemError,
78                          OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) );
79     }
80     catch( RuntimeException & e)
81     {
82         PyErr_SetString( PyExc_SystemError,
83                          OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) );
84     }
85 }
86 
87 
createClass(const OUString & name,const Runtime & runtime)88 static PyRef createClass( const OUString & name, const Runtime &runtime )
89     throw ( RuntimeException )
90 {
91     // assuming that this is never deleted !
92     // note I don't have the knowledge how to initialize these type objects correctly !
93     TypeDescription desc( name );
94     if( ! desc.is() )
95     {
96         OUStringBuffer buf;
97         buf.appendAscii( "pyuno.getClass: uno exception " );
98         buf.append(name).appendAscii( " is unknown" );
99         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () );
100     }
101 
102     sal_Bool isStruct = desc.get()->eTypeClass == typelib_TypeClass_STRUCT;
103     sal_Bool isExc = desc.get()->eTypeClass == typelib_TypeClass_EXCEPTION;
104     sal_Bool isInterface = desc.get()->eTypeClass == typelib_TypeClass_INTERFACE;
105     if( !isStruct  && !isExc && ! isInterface )
106     {
107         OUStringBuffer buf;
108         buf.appendAscii( "pyuno.getClass: " ).append(name).appendAscii( "is a " );
109         buf.appendAscii(
110             typeClassToString( (com::sun::star::uno::TypeClass) desc.get()->eTypeClass));
111         buf.appendAscii( ", expected EXCEPTION, STRUCT or INTERFACE" );
112         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface>() );
113     }
114 
115     // retrieve base class
116     PyRef base;
117     if( isInterface )
118     {
119         typelib_InterfaceTypeDescription *pDesc = (typelib_InterfaceTypeDescription * )desc.get();
120         if( pDesc->pBaseTypeDescription )
121         {
122             base = getClass( pDesc->pBaseTypeDescription->aBase.pTypeName, runtime );
123         }
124         else
125         {
126             // must be XInterface !
127         }
128     }
129     else
130     {
131         typelib_CompoundTypeDescription *pDesc = (typelib_CompoundTypeDescription*)desc.get();
132         if( pDesc->pBaseTypeDescription )
133         {
134             base = getClass( pDesc->pBaseTypeDescription->aBase.pTypeName, runtime );
135         }
136         else
137         {
138             if( isExc )
139                 // we are currently creating the root UNO exception
140                 base = PyRef(PyExc_Exception);
141         }
142     }
143     PyRef args( PyTuple_New( 3 ), SAL_NO_ACQUIRE );
144 
145     PyRef pyTypeName = USTR_TO_PYSTR( name /*.replace( '.', '_' )*/ );
146 
147     PyRef bases;
148     if( base.is() )
149     {
150         { // for CC, keeping ref-count being 1
151         bases = PyRef( PyTuple_New( 1 ), SAL_NO_ACQUIRE );
152         }
153         PyTuple_SetItem( bases.get(), 0 , base.getAcquired() );
154     }
155     else
156     {
157         bases = PyRef( PyTuple_New( 0 ), SAL_NO_ACQUIRE );
158     }
159 
160     PyTuple_SetItem( args.get(), 0, pyTypeName.getAcquired());
161     PyTuple_SetItem( args.get(), 1, bases.getAcquired() );
162     PyTuple_SetItem( args.get(), 2, PyDict_New() );
163 
164     PyRef ret(
165         PyObject_CallObject(reinterpret_cast<PyObject *>(&PyType_Type) , args.get()),
166         SAL_NO_ACQUIRE );
167 
168     // now overwrite ctor and attrib functions
169     if( isInterface )
170     {
171         PyObject_SetAttrString(
172             ret.get(), const_cast< char * >("__pyunointerface__"),
173             USTR_TO_PYSTR(name).get() );
174     }
175     else
176     {
177         PyRef ctor = getObjectFromUnoModule( runtime,"_uno_struct__init__" );
178         PyRef setter = getObjectFromUnoModule( runtime,"_uno_struct__setattr__" );
179         PyRef getter = getObjectFromUnoModule( runtime,"_uno_struct__getattr__" );
180         PyRef repr = getObjectFromUnoModule( runtime,"_uno_struct__repr__" );
181         PyRef eq = getObjectFromUnoModule( runtime,"_uno_struct__eq__" );
182 #if PY_MAJOR_VERSION >= 3
183         PyRef dir = getObjectFromUnoModule( runtime, "_uno_struct__dir__" );
184 #endif
185 
186         PyObject_SetAttrString(
187             ret.get(), const_cast< char * >("__pyunostruct__"),
188             USTR_TO_PYSTR(name).get() );
189         PyObject_SetAttrString(
190             ret.get(), const_cast< char * >("typeName"),
191             USTR_TO_PYSTR(name).get() );
192         PyObject_SetAttrString(
193             ret.get(), const_cast< char * >("__init__"), ctor.get() );
194         PyObject_SetAttrString(
195             ret.get(), const_cast< char * >("__getattr__"), getter.get() );
196         PyObject_SetAttrString(
197             ret.get(), const_cast< char * >("__setattr__"), setter.get() );
198         PyObject_SetAttrString(
199             ret.get(), const_cast< char * >("__repr__"), repr.get() );
200         PyObject_SetAttrString(
201             ret.get(), const_cast< char * >("__str__"), repr.get() );
202         PyObject_SetAttrString(
203             ret.get(), const_cast< char * >("__eq__"), eq.get() );
204 #if PY_MAJOR_VERSION >= 3
205         PyObject_SetAttrString(
206             ret.get(), const_cast< char * >("__dir__"), dir.get() );
207 #endif
208     }
209     return ret;
210 }
211 
isInstanceOfStructOrException(PyObject * obj)212 bool isInstanceOfStructOrException( PyObject *obj)
213 {
214     PyRef attr(
215         PyObject_GetAttrString(obj, const_cast< char * >("__class__")),
216         SAL_NO_ACQUIRE );
217     return PyObject_HasAttrString(
218         attr.get(), const_cast< char * >("__pyunostruct__"));
219 }
220 
isInterfaceClass(const Runtime & runtime,PyObject * obj)221 sal_Bool isInterfaceClass( const Runtime &runtime, PyObject * obj )
222 {
223     const ClassSet & set = runtime.getImpl()->cargo->interfaceSet;
224     return set.find( obj ) != set.end();
225 }
226 
getClass(const OUString & name,const Runtime & runtime)227 PyRef getClass( const OUString & name , const Runtime &runtime)
228 {
229     PyRef ret;
230 
231     RuntimeCargo *cargo =runtime.getImpl()->cargo;
232     ExceptionClassMap::iterator ii = cargo->exceptionMap.find( name );
233     if( ii == cargo->exceptionMap.end() )
234     {
235         ret = createClass( name, runtime );
236         cargo->exceptionMap[name] = ret;
237         if( PyObject_HasAttrString(
238                 ret.get(), const_cast< char * >("__pyunointerface__") ) )
239             cargo->interfaceSet.insert( ret );
240 
241         PyObject_SetAttrString(
242             ret.get(), const_cast< char * >("__pyunointerface__"),
243             USTR_TO_PYSTR(name).get() );
244     }
245     else
246     {
247         ret = ii->second;
248     }
249 
250     return ret;
251 }
252 
253 
254 }
255