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