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 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_cli_ure.hxx"
30 
31 #include <sal/alloca.h>
32 #include "rtl/ustrbuf.hxx"
33 #include "cli_base.h"
34 #include "cli_bridge.h"
35 
36 namespace sr=System::Reflection;
37 namespace css=com::sun::star;
38 using namespace rtl;
39 
40 namespace cli_uno
41 {
42 
43 union largest
44 {
45     sal_Int64 n;
46     double d;
47     void * p;
48     uno_Any a;
49 };
50 
51 System::Object* Bridge::call_uno(uno_Interface * pUnoI,
52                       typelib_TypeDescription* member_td,
53                       typelib_TypeDescriptionReference * return_type,
54                       sal_Int32 nParams, typelib_MethodParameter const * pParams,
55                       System::Object * args[], System::Type* argTypes[],
56                       System::Object** ppExc) const
57 {
58     // return mem
59     sal_Int32 return_size = sizeof (largest);
60     if ((0 != return_type) &&
61         (typelib_TypeClass_STRUCT == return_type->eTypeClass ||
62          typelib_TypeClass_EXCEPTION == return_type->eTypeClass))
63     {
64         TypeDescr return_td( return_type );
65         if (return_td.get()->nSize > sizeof (largest))
66             return_size = return_td.get()->nSize;
67     }
68     //Prepare memory that contains all converted arguments and return valuse
69     //The memory block contains first pointers to the arguments which are in the same block
70     // For example, 2 arguments, 1 ret.
71     //
72     //      | Pointer
73     //      | Pointer
74     //      | Return value
75     //      | Arg 1
76     //      | Arg 2
77     //
78     // If an argument is larger then union largest, such as some structures, then the pointer
79     // points to an extra block of memory. The same goes for a big return value.
80 
81     char * mem = (char *)alloca(
82         (nParams * sizeof (void *)) + return_size + (nParams * sizeof (largest)) );
83     //array of pointers to args
84     void ** uno_args = (void **)mem;
85     //If an attribute is set, then uno_ret must be null, e.g void setAttribute(int )
86     void * uno_ret= NULL;
87     if ( !(member_td->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE && nParams == 1))
88         uno_ret = (mem + (nParams * sizeof (void *)));
89     largest * uno_args_mem = (largest *)(mem + (nParams * sizeof (void *)) + return_size);
90 
91     OSL_ASSERT( (0 == nParams) || (nParams == args->get_Length()) );
92     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
93     {
94         typelib_MethodParameter const & param = pParams[ nPos ];
95         typelib_TypeDescriptionReference * type = param.pTypeRef;
96 
97         uno_args[ nPos ] = &uno_args_mem[ nPos ];
98         if (typelib_TypeClass_STRUCT == type->eTypeClass ||
99             typelib_TypeClass_EXCEPTION == type->eTypeClass)
100         {
101             TypeDescr td( type );
102             if (td.get()->nSize > sizeof (largest))
103                 uno_args[ nPos ] = alloca( td.get()->nSize );
104         }
105 
106         if (param.bIn)
107         {
108             try
109             {
110                 // in, in/out params
111                 map_to_uno(
112                     uno_args[ nPos ],args[nPos] , type, false /* no assign */);
113             }
114             catch (...)
115             {
116                 // cleanup uno in args
117                 for (sal_Int32 n = 0; n < nPos; ++n)
118                 {
119                     typelib_MethodParameter const & param = pParams[n];
120                     if (param.bIn)
121                     {
122                         uno_type_destructData(uno_args[n], param.pTypeRef, 0);
123                     }
124                 }
125                 throw;
126             }
127         }
128     }
129     uno_Any uno_exc_holder;
130     uno_Any * uno_exc = &uno_exc_holder;
131     // call binary uno
132 
133     (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
134 
135     if (0 == uno_exc)
136     {
137         // convert out args; destruct uno args
138         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
139         {
140             typelib_MethodParameter const & param = pParams[ nPos ];
141             typelib_TypeDescriptionReference * type = param.pTypeRef;
142             if (param.bOut)
143             {
144                 try
145                 {
146                     map_to_cli(
147                         &args[nPos], uno_args[nPos], param.pTypeRef,
148                         argTypes != NULL ? argTypes[nPos] : NULL, false );
149                 }
150                 catch (...)
151                 {
152                     // cleanup further uno args
153                     for ( sal_Int32 n = nPos; n < nParams; ++n )
154                     {
155                         uno_type_destructData( uno_args[n], pParams[n].pTypeRef, 0 );
156                     }
157                     // cleanup uno return value
158                     uno_type_destructData( uno_ret, return_type, 0 );
159                     throw;
160                 }
161             }
162             //cleanup args
163             if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
164                 typelib_TypeClass_ENUM != type->eTypeClass) // opt
165             {
166                 uno_type_destructData(uno_args[nPos], type, 0);
167             }
168         }
169 
170         if ((0 != return_type) &&
171             (typelib_TypeClass_VOID != return_type->eTypeClass))
172         {
173             // convert uno return value
174             try
175             {
176                 System::Object* cli_ret;
177                  map_to_cli(
178                      &cli_ret, uno_ret, return_type, 0, false);
179 				 uno_type_destructData(uno_ret, return_type, 0);
180                 return cli_ret;
181             }
182             catch (...)
183             {
184                 uno_type_destructData(uno_ret, return_type, 0);
185                 throw;
186             }
187         }
188         return 0; // void return
189     }
190     else // exception occured
191     {
192         // destruct uno in args
193         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
194         {
195             typelib_MethodParameter const & param = pParams[ nPos ];
196             if (param.bIn)
197             {
198                 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, 0 );
199             }
200         }
201         map_to_cli(ppExc, uno_exc_holder.pData,
202                 uno_exc_holder.pType, NULL, false);
203         return 0;
204     }
205 }
206 
207 void Bridge::call_cli(
208     System::Object* cliI,
209     sr::MethodInfo* method,
210     typelib_TypeDescriptionReference * return_type,
211     typelib_MethodParameter * params, int nParams,
212     void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const
213 {
214     System::Object *args[]=  new System::Object*[nParams];
215     for (int nPos= 0; nPos < nParams; nPos++)
216     {
217         typelib_MethodParameter const & param= params[nPos];
218         if (param.bIn)
219         {
220             map_to_cli( &args[nPos],
221                 uno_args[nPos], param.pTypeRef, 0, false);
222         }
223     }
224     System::Object* retInvoke= NULL;
225     try
226     {
227         retInvoke= method->Invoke(cliI, args);
228     }
229     catch (sr::TargetInvocationException* e)
230     {
231         System::Exception* exc= e->get_InnerException();
232         css::uno::TypeDescription td(mapCliType(exc->GetType()));
233         // memory for exception
234         std::auto_ptr< rtl_mem > memExc(rtl_mem::allocate(td.get()->nSize));
235         map_to_uno(memExc.get(), exc, td.get()->pWeakRef, false);
236         (*uno_exc)->pType= td.get()->pWeakRef;
237 		(*uno_exc)->pData= memExc.release();
238         return;
239     }
240     catch (System::Exception* e)
241     {
242         OUStringBuffer buf( 128 );
243         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
244                              "Unexspected exception during invocation of cli object. "
245                              "Original message is: \n") );
246         buf.append(mapCliString(e->get_Message()));
247         throw BridgeRuntimeError( buf.makeStringAndClear() );
248     }
249 
250     //convert out, in/out params
251     for (int nPos = 0; nPos < nParams; ++nPos )
252     {
253         typelib_MethodParameter const & param = params[ nPos ];
254 
255         if (param.bOut)
256         {
257             try
258             {
259                 map_to_uno(
260                     uno_args[ nPos ], args[ nPos ], param.pTypeRef,
261                          sal_True == param.bIn /* assign if inout */);
262                      // out array
263             }
264             catch (...)
265             {
266                 // cleanup uno pure out
267                 for ( sal_Int32 n = 0; n < nPos; ++n )
268                 {
269                     typelib_MethodParameter const & param = params[ n ];
270                     if (! param.bIn)
271                         uno_type_destructData( uno_args[ n ], param.pTypeRef, 0 );
272                 }
273                 throw;
274             }
275         }
276     }
277     // return value
278     if (0 != return_type)
279     {
280         map_to_uno(
281             uno_ret, retInvoke, return_type, false /* no assign */);
282     }
283     // no exception occured
284     *uno_exc = 0;
285 }
286 
287 
288 
289 
290 }
291