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 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_cppuhelper.hxx"
26 
27 #include "osl/diagnose.h"
28 #include "osl/doublecheckedlocking.h"
29 #include "osl/mutex.hxx"
30 #include "uno/dispatcher.hxx"
31 #include "uno/mapping.hxx"
32 #include "cppuhelper/detail/XExceptionThrower.hpp"
33 #include "com/sun/star/uno/RuntimeException.hpp"
34 
35 #include "cppuhelper/exc_hlp.hxx"
36 
37 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
38 
39 
40 using namespace ::rtl;
41 using namespace ::osl;
42 using namespace ::cppu;
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
45 
46 namespace
47 {
48 
49 using cppuhelper::detail::XExceptionThrower;
50 
51 //==============================================================================
52 struct ExceptionThrower : public uno_Interface, XExceptionThrower
53 {
54     inline ExceptionThrower();
55 
56 public:
57     static ExceptionThrower * get();
58     static inline Type const & getCppuType()
59     {
60         return ::getCppuType(
61             reinterpret_cast< Reference< XExceptionThrower > const * >(0) );
62     }
63 
64     // XInterface
65     virtual Any SAL_CALL queryInterface( Type const & type )
66         throw (RuntimeException);
67     virtual void SAL_CALL acquire() throw ();
68     virtual void SAL_CALL release() throw ();
69 
70     // XExceptionThrower
71     virtual void SAL_CALL throwException( Any const & exc ) throw (Exception);
72     virtual void SAL_CALL rethrowException() throw (Exception);
73 };
74 
75 extern "C"
76 {
77 
78 //------------------------------------------------------------------------------
79 static void SAL_CALL ExceptionThrower_acquire_release_nop( uno_Interface * )
80 {
81 }
82 
83 //------------------------------------------------------------------------------
84 static void SAL_CALL ExceptionThrower_dispatch(
85     uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType,
86     void * pReturn, void * pArgs [], uno_Any ** ppException )
87 {
88     OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD );
89 
90     switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription * >(
91                 const_cast< typelib_TypeDescription * >( pMemberType ) )->
92             nPosition)
93     {
94     case 0: // queryInterace()
95     {
96         Type const & rType_demanded =
97             *reinterpret_cast< Type const * >( pArgs[ 0 ] );
98         if (rType_demanded.equals(
99                 ::getCppuType( reinterpret_cast<
100                                Reference< XInterface > const * >(0) ) ) ||
101             rType_demanded.equals( ExceptionThrower::getCppuType() ))
102         {
103             typelib_TypeDescription * pTD = 0;
104             TYPELIB_DANGER_GET( &pTD, rType_demanded.getTypeLibType() );
105             uno_any_construct(
106                 reinterpret_cast< uno_Any * >( pReturn ), &pUnoI, pTD, 0 );
107             TYPELIB_DANGER_RELEASE( pTD );
108         }
109         else
110         {
111             uno_any_construct(
112                 reinterpret_cast< uno_Any * >( pReturn ), 0, 0, 0 );
113         }
114         *ppException = 0;
115         break;
116     }
117     case 1: // acquire()
118     case 2: // release()
119         *ppException = 0;
120         break;
121     case 3: // throwException()
122     {
123         uno_Any * pAny = reinterpret_cast< uno_Any * >( pArgs[ 0 ] );
124         OSL_ASSERT( pAny->pType->eTypeClass == typelib_TypeClass_EXCEPTION );
125         uno_type_any_construct( *ppException, pAny->pData, pAny->pType, 0 );
126         break;
127     }
128     default:
129     {
130         OSL_ASSERT( 0 );
131         RuntimeException exc(
132             OUSTR("not implemented!"), Reference< XInterface >() );
133         uno_type_any_construct(
134             *ppException, &exc, ::getCppuType( &exc ).getTypeLibType(), 0 );
135         break;
136     }
137     }
138 }
139 
140 } // extern "C"
141 
142 //______________________________________________________________________________
143 Any ExceptionThrower::queryInterface( Type const & type )
144     throw (RuntimeException)
145 {
146     if (type.equals( ::getCppuType( reinterpret_cast<
147                                     Reference< XInterface > const * >(0) ) ) ||
148         type.equals( ExceptionThrower::getCppuType() ))
149     {
150         XExceptionThrower * that = static_cast< XExceptionThrower * >( this );
151         return Any( &that, type );
152     }
153     return Any();
154 }
155 
156 //______________________________________________________________________________
157 void ExceptionThrower::acquire() throw ()
158 {
159 }
160 //______________________________________________________________________________
161 void ExceptionThrower::release() throw ()
162 {
163 }
164 
165 //______________________________________________________________________________
166 void ExceptionThrower::throwException( Any const & exc ) throw (Exception)
167 {
168     OSL_ENSURE( 0, "unexpected!" );
169     throwException( exc );
170 }
171 
172 //______________________________________________________________________________
173 void ExceptionThrower::rethrowException() throw (Exception)
174 {
175     throw;
176 }
177 
178 //______________________________________________________________________________
179 inline ExceptionThrower::ExceptionThrower()
180 {
181     uno_Interface::acquire = ExceptionThrower_acquire_release_nop;
182     uno_Interface::release = ExceptionThrower_acquire_release_nop;
183     uno_Interface::pDispatcher = ExceptionThrower_dispatch;
184 }
185 
186 //______________________________________________________________________________
187 ExceptionThrower * ExceptionThrower::get()
188 {
189     ExceptionThrower * s_pThrower = 0;
190     if (s_pThrower == 0)
191     {
192         MutexGuard guard( Mutex::getGlobalMutex() );
193         static ExceptionThrower s_thrower;
194         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
195         s_pThrower = &s_thrower;
196     }
197     else
198     {
199         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
200     }
201     return s_pThrower;
202 }
203 
204 } // anonymous namespace
205 
206 
207 namespace cppu
208 {
209 
210 //==============================================================================
211 void SAL_CALL throwException( Any const & exc ) SAL_THROW( (Exception) )
212 {
213     if (exc.getValueTypeClass() != TypeClass_EXCEPTION)
214     {
215         throw RuntimeException(
216             OUSTR("no UNO exception given "
217                   "(must be derived from com::sun::star::uno::Exception)!"),
218             Reference< XInterface >() );
219     }
220 
221     Mapping uno2cpp(Environment(OUSTR(UNO_LB_UNO)), Environment::getCurrent());
222     if (! uno2cpp.is())
223     {
224         throw RuntimeException(
225             OUSTR("cannot get binary UNO to C++ mapping!"),
226             Reference< XInterface >() );
227     }
228 
229     Reference< XExceptionThrower > xThrower;
230     uno2cpp.mapInterface(
231         reinterpret_cast< void ** >( &xThrower ),
232         static_cast< uno_Interface * >( ExceptionThrower::get() ),
233         ExceptionThrower::getCppuType() );
234     OSL_ASSERT( xThrower.is() );
235     xThrower->throwException( exc );
236 }
237 
238 //==============================================================================
239 Any SAL_CALL getCaughtException()
240 {
241     Mapping cpp2uno(Environment::getCurrent(), Environment(OUSTR(UNO_LB_UNO)));
242     if (! cpp2uno.is())
243     {
244         throw RuntimeException(
245             OUSTR("cannot get C++ to binary UNO mapping!"),
246             Reference< XInterface >() );
247     }
248     Mapping uno2cpp(Environment(OUSTR(UNO_LB_UNO)), Environment::getCurrent());
249     if (! uno2cpp.is())
250     {
251         throw RuntimeException(
252             OUSTR("cannot get binary UNO to C++ mapping!"),
253             Reference< XInterface >() );
254     }
255 
256     typelib_TypeDescription * pTD = 0;
257     TYPELIB_DANGER_GET(
258         &pTD, ExceptionThrower::getCppuType().getTypeLibType() );
259 
260     UnoInterfaceReference unoI;
261     cpp2uno.mapInterface(
262         reinterpret_cast< void ** >( &unoI.m_pUnoI ),
263         static_cast< XExceptionThrower * >( ExceptionThrower::get() ), pTD );
264     OSL_ASSERT( unoI.is() );
265 
266     typelib_TypeDescription * pMemberTD = 0;
267     TYPELIB_DANGER_GET(
268         &pMemberTD,
269         reinterpret_cast< typelib_InterfaceTypeDescription * >( pTD )->
270         ppMembers[ 1 ] /* rethrowException() */ );
271 
272     uno_Any exc_mem;
273     uno_Any * exc = &exc_mem;
274     unoI.dispatch( pMemberTD, 0, 0, &exc );
275 
276     TYPELIB_DANGER_RELEASE( pMemberTD );
277     TYPELIB_DANGER_RELEASE( pTD );
278 
279     if (exc == 0)
280     {
281         throw RuntimeException(
282             OUSTR("rethrowing C++ exception failed!"),
283             Reference< XInterface >() );
284     }
285 
286     Any ret;
287     uno_any_destruct( &ret, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
288     uno_type_any_constructAndConvert(
289         &ret, exc->pData, exc->pType, uno2cpp.get() );
290     uno_any_destruct( exc, 0 );
291     return ret;
292 }
293 
294 }
295