1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #include "pyuno_impl.hxx"
28 
29 #include <rtl/ustrbuf.hxx>
30 
31 #include <typelib/typedescription.hxx>
32 
33 using rtl::OUString;
34 using rtl::OUStringBuffer;
35 using rtl::OUStringToOString;
36 
37 using com::sun::star::uno::RuntimeException;
38 using com::sun::star::uno::Sequence;
39 using com::sun::star::uno::Type;
40 using com::sun::star::uno::Reference;
41 using com::sun::star::uno::XInterface;
42 using com::sun::star::uno::TypeDescription;
43 
44 namespace pyuno
45 {
46 
47 void raisePyExceptionWithAny( const com::sun::star::uno::Any &anyExc )
48 {
49     try
50     {
51         Runtime runtime;
52         PyRef exc = runtime.any2PyObject( anyExc );
53         if( exc.is() )
54         {
55             PyRef type( getClass( anyExc.getValueType().getTypeName(),runtime ) );
56             PyErr_SetObject( type.get(), exc.get());
57         }
58         else
59         {
60             com::sun::star::uno::Exception e;
61             anyExc >>= e;
62 
63             OUStringBuffer buf;
64             buf.appendAscii( "Couldn't convert uno exception to a python exception (" );
65             buf.append(anyExc.getValueType().getTypeName());
66             buf.appendAscii( ": " );
67             buf.append(e.Message );
68             buf.appendAscii( ")" );
69             PyErr_SetString(
70                 PyExc_SystemError,
71                 OUStringToOString(buf.makeStringAndClear(),RTL_TEXTENCODING_ASCII_US) );
72         }
73     }
74     catch( com::sun::star::lang::IllegalArgumentException & e)
75     {
76         PyErr_SetString( PyExc_SystemError,
77                          OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) );
78     }
79     catch( com::sun::star::script::CannotConvertException & e)
80     {
81         PyErr_SetString( PyExc_SystemError,
82                          OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) );
83     }
84     catch( RuntimeException & e)
85     {
86         PyErr_SetString( PyExc_SystemError,
87                          OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US) );
88     }
89 }
90 
91 
92 static PyRef createClass( const OUString & name, const Runtime &runtime )
93     throw ( RuntimeException )
94 {
95     // assuming that this is never deleted !
96     // note I don't have the knowledge how to initialize these type objects correctly !
97     TypeDescription desc( name );
98     if( ! desc.is() )
99     {
100         OUStringBuffer buf;
101         buf.appendAscii( "pyuno.getClass: uno exception " );
102         buf.append(name).appendAscii( " is unknown" );
103         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface > () );
104     }
105 
106     sal_Bool isStruct = desc.get()->eTypeClass == typelib_TypeClass_STRUCT;
107     sal_Bool isExc = desc.get()->eTypeClass == typelib_TypeClass_EXCEPTION;
108     sal_Bool isInterface = desc.get()->eTypeClass == typelib_TypeClass_INTERFACE;
109     if( !isStruct  && !isExc && ! isInterface )
110     {
111         OUStringBuffer buf;
112         buf.appendAscii( "pyuno.getClass: " ).append(name).appendAscii( "is a " );
113         buf.appendAscii(
114             typeClassToString( (com::sun::star::uno::TypeClass) desc.get()->eTypeClass));
115         buf.appendAscii( ", expected EXCEPTION, STRUCT or INTERFACE" );
116         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface>() );
117     }
118 
119     // retrieve base class
120     PyRef base;
121     if( isInterface )
122     {
123         typelib_InterfaceTypeDescription *pDesc = (typelib_InterfaceTypeDescription * )desc.get();
124         if( pDesc->pBaseTypeDescription )
125         {
126             base = getClass( pDesc->pBaseTypeDescription->aBase.pTypeName, runtime );
127         }
128         else
129         {
130             // must be XInterface !
131         }
132     }
133     else
134     {
135         typelib_CompoundTypeDescription *pDesc = (typelib_CompoundTypeDescription*)desc.get();
136         if( pDesc->pBaseTypeDescription )
137         {
138             base = getClass( pDesc->pBaseTypeDescription->aBase.pTypeName, runtime );
139         }
140         else
141         {
142             if( isExc )
143                 // we are currently creating the root UNO exception
144                 base = PyRef(PyExc_Exception);
145         }
146     }
147     PyRef args( PyTuple_New( 3 ), SAL_NO_ACQUIRE );
148 
149     PyRef pyTypeName = ustring2PyString( name /*.replace( '.', '_' )*/ );
150 
151     PyRef bases;
152     if( base.is() )
153     {
154         { // for CC, keeping ref-count being 1
155         bases = PyRef( PyTuple_New( 1 ), SAL_NO_ACQUIRE );
156         }
157         PyTuple_SetItem( bases.get(), 0 , base.getAcquired() );
158     }
159     else
160     {
161         bases = PyRef( PyTuple_New( 0 ), SAL_NO_ACQUIRE );
162     }
163 
164     PyTuple_SetItem( args.get(), 0, pyTypeName.getAcquired());
165     PyTuple_SetItem( args.get(), 1, bases.getAcquired() );
166     PyTuple_SetItem( args.get(), 2, PyDict_New() );
167 
168     PyRef ret(
169         PyObject_CallObject(reinterpret_cast<PyObject *>(&PyClass_Type) , args.get()),
170         SAL_NO_ACQUIRE );
171 
172     // now overwrite ctor and attrib functions
173     if( isInterface )
174     {
175         PyObject_SetAttrString(
176             ret.get(), const_cast< char * >("__pyunointerface__"),
177             ustring2PyString(name).get() );
178     }
179     else
180     {
181         PyRef ctor = getObjectFromUnoModule( runtime,"_uno_struct__init__" );
182         PyRef setter = getObjectFromUnoModule( runtime,"_uno_struct__setattr__" );
183         PyRef getter = getObjectFromUnoModule( runtime,"_uno_struct__getattr__" );
184         PyRef repr = getObjectFromUnoModule( runtime,"_uno_struct__repr__" );
185         PyRef eq = getObjectFromUnoModule( runtime,"_uno_struct__eq__" );
186 
187         PyObject_SetAttrString(
188             ret.get(), const_cast< char * >("__pyunostruct__"),
189             ustring2PyString(name).get() );
190         PyObject_SetAttrString(
191             ret.get(), const_cast< char * >("typeName"),
192             ustring2PyString(name).get() );
193         PyObject_SetAttrString(
194             ret.get(), const_cast< char * >("__init__"), ctor.get() );
195         PyObject_SetAttrString(
196             ret.get(), const_cast< char * >("__getattr__"), getter.get() );
197         PyObject_SetAttrString(
198             ret.get(), const_cast< char * >("__setattr__"), setter.get() );
199         PyObject_SetAttrString(
200             ret.get(), const_cast< char * >("__repr__"), repr.get() );
201         PyObject_SetAttrString(
202             ret.get(), const_cast< char * >("__str__"), repr.get() );
203         PyObject_SetAttrString(
204             ret.get(), const_cast< char * >("__eq__"), eq.get() );
205     }
206     return ret;
207 }
208 
209 bool isInstanceOfStructOrException( PyObject *obj)
210 {
211     PyRef attr(
212         PyObject_GetAttrString(obj, const_cast< char * >("__class__")),
213         SAL_NO_ACQUIRE );
214     return PyObject_HasAttrString(
215         attr.get(), const_cast< char * >("__pyunostruct__"));
216 }
217 
218 sal_Bool isInterfaceClass( const Runtime &runtime, PyObject * obj )
219 {
220     const ClassSet & set = runtime.getImpl()->cargo->interfaceSet;
221     return set.find( obj ) != set.end();
222 }
223 
224 PyRef getClass( const OUString & name , const Runtime &runtime)
225 {
226     PyRef ret;
227 
228     RuntimeCargo *cargo =runtime.getImpl()->cargo;
229     ExceptionClassMap::iterator ii = cargo->exceptionMap.find( name );
230     if( ii == cargo->exceptionMap.end() )
231     {
232         ret = createClass( name, runtime );
233         cargo->exceptionMap[name] = ret;
234         if( PyObject_HasAttrString(
235                 ret.get(), const_cast< char * >("__pyunointerface__") ) )
236             cargo->interfaceSet.insert( ret );
237 
238         PyObject_SetAttrString(
239             ret.get(), const_cast< char * >("__pyunointerface__"),
240             ustring2PyString(name).get() );
241     }
242     else
243     {
244         ret = ii->second;
245     }
246 
247     return ret;
248 }
249 
250 
251 }
252