/src/libreoffice/cppuhelper/source/exc_thrower.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <rtl/instance.hxx> |
21 | | #include <osl/diagnose.h> |
22 | | #include <sal/log.hxx> |
23 | | #include <uno/dispatcher.hxx> |
24 | | #include <uno/lbnames.h> |
25 | | #include <uno/mapping.hxx> |
26 | | #include <cppuhelper/detail/XExceptionThrower.hpp> |
27 | | #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> |
28 | | #include <com/sun/star/ucb/NameClashException.hpp> |
29 | | #include <com/sun/star/uno/RuntimeException.hpp> |
30 | | |
31 | | #include <cppuhelper/exc_hlp.hxx> |
32 | | |
33 | | using namespace ::cppu; |
34 | | using namespace ::com::sun::star; |
35 | | using namespace ::com::sun::star::uno; |
36 | | |
37 | | namespace |
38 | | { |
39 | | |
40 | | using cppuhelper::detail::XExceptionThrower; |
41 | | |
42 | | |
43 | | struct ExceptionThrower : public uno_Interface, XExceptionThrower |
44 | | { |
45 | | ExceptionThrower(); |
46 | | |
47 | 0 | virtual ~ExceptionThrower() {} |
48 | | |
49 | | static Type const & getCppuType() |
50 | 26.1k | { |
51 | 26.1k | return cppu::UnoType<XExceptionThrower>::get(); |
52 | 26.1k | } |
53 | | |
54 | | // XInterface |
55 | | virtual Any SAL_CALL queryInterface( Type const & type ) override; |
56 | | virtual void SAL_CALL acquire() noexcept override; |
57 | | virtual void SAL_CALL release() noexcept override; |
58 | | |
59 | | // XExceptionThrower |
60 | | virtual void SAL_CALL throwException( Any const & exc ) override; |
61 | | virtual void SAL_CALL rethrowException() override; |
62 | | }; |
63 | | |
64 | | extern "C" |
65 | | { |
66 | | |
67 | | |
68 | | void ExceptionThrower_acquire_release_nop( |
69 | | SAL_UNUSED_PARAMETER uno_Interface * ) |
70 | 0 | {} |
71 | | |
72 | | |
73 | | void ExceptionThrower_dispatch( |
74 | | uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType, |
75 | | void * pReturn, void * pArgs [], uno_Any ** ppException ) |
76 | 0 | { |
77 | 0 | OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD ); |
78 | |
|
79 | 0 | switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription * >( |
80 | 0 | const_cast< typelib_TypeDescription * >( pMemberType ) )-> |
81 | 0 | nPosition) |
82 | 0 | { |
83 | 0 | case 0: // queryInterface() |
84 | 0 | { |
85 | 0 | Type const & rType_demanded = |
86 | 0 | *static_cast< Type const * >( pArgs[ 0 ] ); |
87 | 0 | if (rType_demanded.equals( cppu::UnoType<XInterface>::get() ) || |
88 | 0 | rType_demanded.equals( ExceptionThrower::getCppuType() )) |
89 | 0 | { |
90 | 0 | typelib_TypeDescription * pTD = nullptr; |
91 | 0 | TYPELIB_DANGER_GET( &pTD, rType_demanded.getTypeLibType() ); |
92 | 0 | uno_any_construct( |
93 | 0 | static_cast< uno_Any * >( pReturn ), &pUnoI, pTD, nullptr ); |
94 | 0 | TYPELIB_DANGER_RELEASE( pTD ); |
95 | 0 | } |
96 | 0 | else |
97 | 0 | { |
98 | 0 | uno_any_construct( |
99 | 0 | static_cast< uno_Any * >( pReturn ), nullptr, nullptr, nullptr ); |
100 | 0 | } |
101 | 0 | *ppException = nullptr; |
102 | 0 | break; |
103 | 0 | } |
104 | 0 | case 1: // acquire() |
105 | 0 | case 2: // release() |
106 | 0 | *ppException = nullptr; |
107 | 0 | break; |
108 | 0 | case 3: // throwException() |
109 | 0 | { |
110 | 0 | uno_Any * pAny = static_cast< uno_Any * >( pArgs[ 0 ] ); |
111 | 0 | OSL_ASSERT( pAny->pType->eTypeClass == typelib_TypeClass_EXCEPTION ); |
112 | 0 | uno_type_any_construct( *ppException, pAny->pData, pAny->pType, nullptr ); |
113 | 0 | break; |
114 | 0 | } |
115 | 0 | default: |
116 | 0 | { |
117 | 0 | OSL_ASSERT( false ); |
118 | 0 | RuntimeException exc( u"not implemented!"_ustr ); |
119 | 0 | uno_type_any_construct( |
120 | 0 | *ppException, &exc, cppu::UnoType<decltype(exc)>::get().getTypeLibType(), nullptr ); |
121 | 0 | break; |
122 | 0 | } |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | | } // extern "C" |
127 | | |
128 | | |
129 | | Any ExceptionThrower::queryInterface( Type const & type ) |
130 | 26.1k | { |
131 | 26.1k | if (type.equals( cppu::UnoType<XInterface>::get() ) || |
132 | 0 | type.equals( ExceptionThrower::getCppuType() )) |
133 | 26.1k | { |
134 | 26.1k | XExceptionThrower * that = this; |
135 | 26.1k | return Any( &that, type ); |
136 | 26.1k | } |
137 | 0 | return Any(); |
138 | 26.1k | } |
139 | | |
140 | | |
141 | | void ExceptionThrower::acquire() noexcept |
142 | 78.4k | { |
143 | 78.4k | } |
144 | | |
145 | | void ExceptionThrower::release() noexcept |
146 | 78.4k | { |
147 | 78.4k | } |
148 | | |
149 | | |
150 | | void ExceptionThrower::throwException( Any const & exc ) |
151 | 0 | { |
152 | 0 | OSL_FAIL( "unexpected!" ); |
153 | 0 | cppu::throwException( exc ); |
154 | 0 | } |
155 | | |
156 | | |
157 | | void ExceptionThrower::rethrowException() |
158 | 26.1k | { |
159 | 26.1k | throw; |
160 | 26.1k | } |
161 | | |
162 | | |
163 | | ExceptionThrower::ExceptionThrower() |
164 | 7 | { |
165 | 7 | uno_Interface::acquire = ExceptionThrower_acquire_release_nop; |
166 | 7 | uno_Interface::release = ExceptionThrower_acquire_release_nop; |
167 | 7 | uno_Interface::pDispatcher = ExceptionThrower_dispatch; |
168 | 7 | } |
169 | | |
170 | | #if defined(IOS) || defined(ANDROID) |
171 | | #define RETHROW_FAKE_EXCEPTIONS 1 |
172 | | #else |
173 | | #define RETHROW_FAKE_EXCEPTIONS 0 |
174 | | #endif |
175 | | |
176 | | class theExceptionThrower : public rtl::Static<ExceptionThrower, theExceptionThrower> {}; |
177 | | |
178 | | #if RETHROW_FAKE_EXCEPTIONS |
179 | | // In the native iOS / Android app, where we don't have any Java, Python, |
180 | | // BASIC, or other scripting, the only thing that would use the C++/UNO bridge |
181 | | // functionality that invokes codeSnippet() was cppu::throwException(). |
182 | | // |
183 | | // codeSnippet() is part of what corresponds to the code that uses |
184 | | // run-time-generated machine code on other platforms. We can't generate code |
185 | | // at run-time on iOS, that has been known forever. |
186 | | // |
187 | | // Instead of digging in and trying to understand what is wrong, another |
188 | | // solution was chosen. It turns out that the number of types of exception |
189 | | // objects thrown by cppu::throwException() is fairly small. During startup of |
190 | | // the LibreOffice code, and loading of an .odt document, only one kind of |
191 | | // exception is thrown this way... (The lovely |
192 | | // css::ucb:InteractiveAugmentedIOException.) |
193 | | // |
194 | | // So we can simply have code that checks what the type of object being thrown |
195 | | // is, and explicitly throws such an object then with a normal C++ throw |
196 | | // statement. Seems to work. |
197 | | template <class E> void tryThrow(css::uno::Any const& aException) |
198 | | { |
199 | | E aSpecificException; |
200 | | if (aException >>= aSpecificException) |
201 | | throw aSpecificException; |
202 | | } |
203 | | |
204 | | void lo_mobile_throwException(css::uno::Any const& aException) |
205 | | { |
206 | | assert(aException.getValueTypeClass() == css::uno::TypeClass_EXCEPTION); |
207 | | |
208 | | tryThrow<css::ucb::InteractiveAugmentedIOException>(aException); |
209 | | tryThrow<css::ucb::NameClashException>(aException); |
210 | | tryThrow<css::uno::RuntimeException>(aException); |
211 | | |
212 | | SAL_WARN("cppuhelper", "lo_mobile_throwException: Unhandled exception type: " << aException.getValueTypeName()); |
213 | | |
214 | | assert(false); |
215 | | } |
216 | | #endif // RETHROW_FAKE_EXCEPTIONS |
217 | | |
218 | | } // anonymous namespace |
219 | | |
220 | | |
221 | | namespace cppu |
222 | | { |
223 | | |
224 | | |
225 | | void SAL_CALL throwException( Any const & exc ) |
226 | 0 | { |
227 | 0 | if (exc.getValueTypeClass() != TypeClass_EXCEPTION) |
228 | 0 | { |
229 | 0 | throw RuntimeException( |
230 | 0 | u"no UNO exception given " |
231 | 0 | "(must be derived from com::sun::star::uno::Exception)!"_ustr ); |
232 | 0 | } |
233 | | |
234 | | #if RETHROW_FAKE_EXCEPTIONS |
235 | | lo_mobile_throwException(exc); |
236 | | #else |
237 | 0 | Mapping uno2cpp(Environment(u"" UNO_LB_UNO ""_ustr), Environment::getCurrent()); |
238 | 0 | if (! uno2cpp.is()) |
239 | 0 | { |
240 | 0 | throw RuntimeException( |
241 | 0 | u"cannot get binary UNO to C++ mapping!"_ustr ); |
242 | 0 | } |
243 | | |
244 | 0 | Reference< XExceptionThrower > xThrower; |
245 | 0 | uno2cpp.mapInterface( |
246 | 0 | reinterpret_cast< void ** >( &xThrower ), |
247 | 0 | static_cast< uno_Interface * >( &theExceptionThrower::get() ), |
248 | 0 | ExceptionThrower::getCppuType() ); |
249 | 0 | OSL_ASSERT( xThrower.is() ); |
250 | 0 | xThrower->throwException( exc ); |
251 | 0 | #endif // !RETHROW_FAKE_EXCEPTIONS |
252 | 0 | } |
253 | | |
254 | | |
255 | | Any SAL_CALL getCaughtException() |
256 | 26.1k | { |
257 | | // why does this differ from RETHROW_FAKE_EXCEPTIONS? |
258 | | #if defined(ANDROID) |
259 | | return Any(); |
260 | | #else |
261 | 26.1k | Mapping cpp2uno(Environment::getCurrent(), Environment(u"" UNO_LB_UNO ""_ustr)); |
262 | 26.1k | if (! cpp2uno.is()) |
263 | 0 | { |
264 | 0 | throw RuntimeException( |
265 | 0 | u"cannot get C++ to binary UNO mapping!"_ustr ); |
266 | 0 | } |
267 | 26.1k | Mapping uno2cpp(Environment(u"" UNO_LB_UNO ""_ustr), Environment::getCurrent()); |
268 | 26.1k | if (! uno2cpp.is()) |
269 | 0 | { |
270 | 0 | throw RuntimeException( |
271 | 0 | u"cannot get binary UNO to C++ mapping!"_ustr ); |
272 | 0 | } |
273 | | |
274 | 26.1k | typelib_TypeDescription * pTD = nullptr; |
275 | 26.1k | TYPELIB_DANGER_GET( |
276 | 26.1k | &pTD, ExceptionThrower::getCppuType().getTypeLibType() ); |
277 | | |
278 | 26.1k | UnoInterfaceReference unoI; |
279 | 26.1k | cpp2uno.mapInterface( |
280 | 26.1k | reinterpret_cast< void ** >( &unoI.m_pUnoI ), |
281 | 26.1k | static_cast< XExceptionThrower * >( &theExceptionThrower::get() ), pTD ); |
282 | 26.1k | OSL_ASSERT( unoI.is() ); |
283 | | |
284 | 26.1k | typelib_TypeDescription * pMemberTD = nullptr; |
285 | 26.1k | TYPELIB_DANGER_GET( |
286 | 26.1k | &pMemberTD, |
287 | 26.1k | reinterpret_cast< typelib_InterfaceTypeDescription * >( pTD )-> |
288 | 26.1k | ppMembers[ 1 ] /* rethrowException() */ ); |
289 | | |
290 | 26.1k | uno_Any exc_mem; |
291 | 26.1k | uno_Any * exc = &exc_mem; |
292 | 26.1k | unoI.dispatch( pMemberTD, nullptr, nullptr, &exc ); |
293 | | |
294 | 26.1k | TYPELIB_DANGER_RELEASE( pMemberTD ); |
295 | 26.1k | TYPELIB_DANGER_RELEASE( pTD ); |
296 | | |
297 | 26.1k | if (exc == nullptr) |
298 | 0 | { |
299 | 0 | throw RuntimeException( u"rethrowing C++ exception failed!"_ustr ); |
300 | 0 | } |
301 | | |
302 | 26.1k | Any ret; |
303 | 26.1k | uno_any_destruct( &ret, reinterpret_cast< uno_ReleaseFunc >(cpp_release) ); |
304 | 26.1k | uno_type_any_constructAndConvert( |
305 | 26.1k | &ret, exc->pData, exc->pType, uno2cpp.get() ); |
306 | 26.1k | uno_any_destruct( exc, nullptr ); |
307 | 26.1k | return ret; |
308 | 26.1k | #endif |
309 | 26.1k | } |
310 | | |
311 | | } |
312 | | |
313 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |