/src/libreoffice/cppuhelper/source/implbase_ex.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 <osl/diagnose.h> |
21 | | #include <sal/log.hxx> |
22 | | #include <cppuhelper/compbase_ex.hxx> |
23 | | #include <cppuhelper/implbase_ex.hxx> |
24 | | |
25 | | #include "type_entries.hxx" |
26 | | |
27 | | #include <com/sun/star/uno/RuntimeException.hpp> |
28 | | |
29 | | #include <mutex> |
30 | | |
31 | | using namespace ::cppu; |
32 | | using namespace ::com::sun::star; |
33 | | using namespace ::com::sun::star::uno; |
34 | | |
35 | | namespace cppu |
36 | | { |
37 | | |
38 | | static void checkInterface( Type const & rType ) |
39 | 206M | { |
40 | 206M | if (TypeClass_INTERFACE != rType.getTypeClass()) |
41 | 0 | { |
42 | 0 | OUString msg( "querying for interface \"" + rType.getTypeName() + "\": no interface type!" ); |
43 | 0 | SAL_WARN( "cppuhelper", msg ); |
44 | 0 | throw RuntimeException( msg ); |
45 | 0 | } |
46 | 206M | } |
47 | | |
48 | | static bool isXInterface( rtl_uString * pStr ) |
49 | 187M | { |
50 | 187M | return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface"; |
51 | 187M | } |
52 | | |
53 | | static void * makeInterface( sal_IntPtr nOffset, void * that ) |
54 | 84.3M | { |
55 | 84.3M | return (static_cast<char *>(that) + nOffset); |
56 | 84.3M | } |
57 | | |
58 | | static bool td_equals( |
59 | | typelib_TypeDescriptionReference const * pTDR1, |
60 | | typelib_TypeDescriptionReference const * pTDR2 ) |
61 | 1.52G | { |
62 | 1.52G | return ((pTDR1 == pTDR2) || |
63 | 1.45G | OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName)); |
64 | 1.52G | } |
65 | | |
66 | | type_entry * getTypeEntries( class_data * cd ) |
67 | 133M | { |
68 | 133M | type_entry * pEntries = cd->m_typeEntries; |
69 | 133M | if (! cd->m_storedTypeRefs) // not inited? |
70 | 1.61k | { |
71 | 1.61k | static std::mutex aMutex; |
72 | 1.61k | std::scoped_lock guard( aMutex ); |
73 | 1.61k | if (! cd->m_storedTypeRefs) // not inited? |
74 | 1.61k | { |
75 | | // get all types |
76 | 9.71k | for ( sal_Int32 n = cd->m_nTypes; n--; ) |
77 | 8.10k | { |
78 | 8.10k | type_entry * pEntry = &pEntries[ n ]; |
79 | 8.10k | Type const & rType = (*pEntry->m_type.getCppuType)( nullptr ); |
80 | 8.10k | OSL_ENSURE( rType.getTypeClass() == TypeClass_INTERFACE, "### wrong helper init: expected interface!" ); |
81 | 8.10k | OSL_ENSURE( ! isXInterface( rType.getTypeLibType()->pTypeName ), "### want to implement XInterface: template argument is XInterface?!?!?!" ); |
82 | 8.10k | if (rType.getTypeClass() != TypeClass_INTERFACE) |
83 | 0 | { |
84 | 0 | OUString msg( "type \"" + rType.getTypeName() + "\" is no interface type!" ); |
85 | 0 | SAL_WARN( "cppuhelper", msg ); |
86 | 0 | throw RuntimeException( msg ); |
87 | 0 | } |
88 | | // ref is statically held by getCppuType() |
89 | 8.10k | pEntry->m_type.typeRef = rType.getTypeLibType(); |
90 | 8.10k | } |
91 | 1.61k | OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); |
92 | 1.61k | cd->m_storedTypeRefs = true; |
93 | 1.61k | } |
94 | 1.61k | } |
95 | 133M | else |
96 | 133M | { |
97 | 133M | OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); |
98 | 133M | } |
99 | 133M | return pEntries; |
100 | 133M | } |
101 | | |
102 | | static void fillTypes( Type * types, class_data * cd ) |
103 | 15 | { |
104 | 15 | type_entry * pEntries = getTypeEntries( cd ); |
105 | 110 | for ( sal_Int32 n = cd->m_nTypes; n--; ) |
106 | 95 | { |
107 | 95 | types[ n ] = pEntries[ n ].m_type.typeRef; |
108 | 95 | } |
109 | 15 | } |
110 | | |
111 | | namespace { |
112 | | |
113 | | bool recursivelyFindType( |
114 | | typelib_TypeDescriptionReference const * demandedType, |
115 | | typelib_InterfaceTypeDescription const * type, sal_IntPtr * offset) |
116 | 869M | { |
117 | | // This code assumes that the vtables of a multiple-inheritance class (the |
118 | | // offset amount by which to adjust the this pointer) follow one another in |
119 | | // the object layout, and that they contain slots for the inherited classes |
120 | | // in a specific order. In theory, that need not hold for any given |
121 | | // platform; in practice, it seems to work well on all supported platforms: |
122 | 1.09G | next: |
123 | 2.10G | for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { |
124 | 1.28G | if (i > 0) { |
125 | 184M | *offset += sizeof (void *); |
126 | 184M | } |
127 | 1.28G | typelib_InterfaceTypeDescription const * base = type->ppBaseTypes[i]; |
128 | | // ignore XInterface: |
129 | 1.28G | if (base->nBaseTypes > 0) { |
130 | 496M | if (td_equals( |
131 | 496M | reinterpret_cast< |
132 | 496M | typelib_TypeDescriptionReference const * >(base), |
133 | 496M | demandedType)) |
134 | 23.2M | { |
135 | 23.2M | return true; |
136 | 23.2M | } |
137 | | // Profiling showed that it is important to speed up the common case |
138 | | // of only one base: |
139 | 473M | if (type->nBaseTypes == 1) { |
140 | 226M | type = base; |
141 | 226M | goto next; |
142 | 226M | } |
143 | 246M | if (recursivelyFindType(demandedType, base, offset)) { |
144 | 20.2M | return true; |
145 | 20.2M | } |
146 | 246M | } |
147 | 1.28G | } |
148 | 825M | return false; |
149 | 1.09G | } |
150 | | |
151 | | } |
152 | | |
153 | | static void * queryDeepNoXInterface( |
154 | | typelib_TypeDescriptionReference const * pDemandedTDR, class_data * cd, void * that ) |
155 | 133M | { |
156 | 133M | type_entry * pEntries = getTypeEntries( cd ); |
157 | 133M | sal_Int32 nTypes = cd->m_nTypes; |
158 | 133M | sal_Int32 n; |
159 | | |
160 | | // try top interfaces without getting td |
161 | 1.11G | for ( n = 0; n < nTypes; ++n ) |
162 | 1.03G | { |
163 | 1.03G | if (td_equals( pEntries[ n ].m_type.typeRef, pDemandedTDR )) |
164 | 51.8M | { |
165 | 51.8M | return makeInterface( pEntries[ n ].m_offset, that ); |
166 | 51.8M | } |
167 | 1.03G | } |
168 | | // query deep getting td |
169 | 680M | for ( n = 0; n < nTypes; ++n ) |
170 | 622M | { |
171 | 622M | typelib_TypeDescription * pTD = nullptr; |
172 | 622M | TYPELIB_DANGER_GET( &pTD, pEntries[ n ].m_type.typeRef ); |
173 | 622M | if (pTD) |
174 | 622M | { |
175 | | // exclude top (already tested) and bottom (XInterface) interface |
176 | 622M | OSL_ENSURE( |
177 | 622M | reinterpret_cast< typelib_InterfaceTypeDescription * >(pTD)-> |
178 | 622M | nBaseTypes > 0, |
179 | 622M | "### want to implement XInterface:" |
180 | 622M | " template argument is XInterface?!?!?!" ); |
181 | 622M | sal_IntPtr offset = pEntries[n].m_offset; |
182 | 622M | bool found = recursivelyFindType( |
183 | 622M | pDemandedTDR, |
184 | 622M | reinterpret_cast< typelib_InterfaceTypeDescription * >(pTD), |
185 | 622M | &offset); |
186 | 622M | TYPELIB_DANGER_RELEASE( pTD ); |
187 | 622M | if (found) { |
188 | 23.2M | return makeInterface( offset, that ); |
189 | 23.2M | } |
190 | 622M | } |
191 | 2 | else |
192 | 2 | { |
193 | 2 | OUString msg( "cannot get type description for type \"" + OUString::unacquired(&pEntries[ n ].m_type.typeRef->pTypeName) + "\"!" ); |
194 | 2 | SAL_WARN( "cppuhelper", msg ); |
195 | 2 | throw RuntimeException( msg ); |
196 | 2 | } |
197 | 622M | } |
198 | 58.4M | return nullptr; |
199 | 81.7M | } |
200 | | |
201 | | // ImplHelper |
202 | | |
203 | | Any SAL_CALL ImplHelper_query( |
204 | | Type const & rType, class_data * cd, void * that ) |
205 | 13.6M | { |
206 | 13.6M | checkInterface( rType ); |
207 | 13.6M | typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); |
208 | | |
209 | 13.6M | void * p; |
210 | | // shortcut for XInterface |
211 | 13.6M | if (isXInterface( pTDR->pTypeName )) |
212 | 9.22M | { |
213 | | // take first one |
214 | 9.22M | p = makeInterface( cd->m_typeEntries[ 0 ].m_offset, that ); |
215 | 9.22M | } |
216 | 4.47M | else |
217 | 4.47M | { |
218 | 4.47M | p = queryDeepNoXInterface( pTDR, cd, that ); |
219 | 4.47M | if (! p) |
220 | 4.28M | { |
221 | 4.28M | return Any(); |
222 | 4.28M | } |
223 | 4.47M | } |
224 | 9.41M | return Any( &p, pTDR ); |
225 | 13.6M | } |
226 | | |
227 | | Any SAL_CALL ImplHelper_queryNoXInterface( |
228 | | Type const & rType, class_data * cd, void * that ) |
229 | 18.1M | { |
230 | 18.1M | checkInterface( rType ); |
231 | 18.1M | typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); |
232 | | |
233 | 18.1M | void * p = queryDeepNoXInterface( pTDR, cd, that ); |
234 | 18.1M | if (p) |
235 | 12.6M | { |
236 | 12.6M | return Any( &p, pTDR ); |
237 | 12.6M | } |
238 | 5.48M | return Any(); |
239 | 18.1M | } |
240 | | |
241 | | css::uno::Sequence<sal_Int8> ImplHelper_getImplementationId( |
242 | | SAL_UNUSED_PARAMETER class_data *) |
243 | 0 | { |
244 | 0 | return css::uno::Sequence<sal_Int8>(); |
245 | 0 | } |
246 | | |
247 | | Sequence< Type > SAL_CALL ImplHelper_getTypes( |
248 | | class_data * cd ) |
249 | 0 | { |
250 | 0 | Sequence< Type > types( cd->m_nTypes ); |
251 | 0 | Type * pTypes = types.getArray(); |
252 | 0 | fillTypes( pTypes, cd ); |
253 | 0 | return types; |
254 | 0 | } |
255 | | |
256 | | Sequence< Type > SAL_CALL ImplInhHelper_getTypes( |
257 | | class_data * cd, Sequence< Type > const & rAddTypes ) |
258 | 0 | { |
259 | 0 | sal_Int32 nImplTypes = cd->m_nTypes; |
260 | 0 | Sequence<Type> types(nImplTypes + rAddTypes.getLength()); |
261 | 0 | Type * pTypes = types.getArray(); |
262 | 0 | fillTypes( pTypes, cd ); |
263 | | // append base types |
264 | 0 | std::copy(rAddTypes.begin(), rAddTypes.end(), pTypes + nImplTypes); |
265 | 0 | return types; |
266 | 0 | } |
267 | | |
268 | | // WeakImplHelper |
269 | | |
270 | | Any SAL_CALL WeakImplHelper_query( |
271 | | Type const & rType, class_data * cd, void * that, OWeakObject * pBase ) |
272 | 41.8M | { |
273 | 41.8M | checkInterface( rType ); |
274 | 41.8M | typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); |
275 | | |
276 | | // shortcut XInterface to OWeakObject |
277 | 41.8M | if (! isXInterface( pTDR->pTypeName )) |
278 | 40.4M | { |
279 | 40.4M | void * p = queryDeepNoXInterface( pTDR, cd, that ); |
280 | 40.4M | if (p) |
281 | 26.6M | { |
282 | 26.6M | return Any( &p, pTDR ); |
283 | 26.6M | } |
284 | 40.4M | } |
285 | 15.1M | return pBase->OWeakObject::queryInterface( rType ); |
286 | 41.8M | } |
287 | | |
288 | | Sequence< Type > SAL_CALL WeakImplHelper_getTypes( |
289 | | class_data * cd ) |
290 | 10 | { |
291 | 10 | sal_Int32 nTypes = cd->m_nTypes; |
292 | 10 | Sequence< Type > types( nTypes +1 ); |
293 | 10 | Type * pTypes = types.getArray(); |
294 | 10 | fillTypes( pTypes, cd ); |
295 | 10 | pTypes[ nTypes ] = cppu::UnoType<XWeak>::get(); |
296 | 10 | return types; |
297 | 10 | } |
298 | | |
299 | | // WeakAggImplHelper |
300 | | |
301 | | Any SAL_CALL WeakAggImplHelper_queryAgg( |
302 | | Type const & rType, class_data * cd, void * that, OWeakAggObject * pBase ) |
303 | 4.99M | { |
304 | 4.99M | checkInterface( rType ); |
305 | 4.99M | typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); |
306 | | |
307 | | // shortcut XInterface to OWeakAggObject |
308 | 4.99M | if (! isXInterface( pTDR->pTypeName )) |
309 | 4.25M | { |
310 | 4.25M | void * p = queryDeepNoXInterface( pTDR, cd, that ); |
311 | 4.25M | if (p) |
312 | 3.46M | { |
313 | 3.46M | return Any( &p, pTDR ); |
314 | 3.46M | } |
315 | 4.25M | } |
316 | 1.52M | return pBase->OWeakAggObject::queryAggregation( rType ); |
317 | 4.99M | } |
318 | | |
319 | | Sequence< Type > SAL_CALL WeakAggImplHelper_getTypes( |
320 | | class_data * cd ) |
321 | 0 | { |
322 | 0 | sal_Int32 nTypes = cd->m_nTypes; |
323 | 0 | Sequence< Type > types( nTypes +2 ); |
324 | 0 | Type * pTypes = types.getArray(); |
325 | 0 | fillTypes( pTypes, cd ); |
326 | 0 | pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get(); |
327 | 0 | pTypes[ nTypes ] = cppu::UnoType<XAggregation>::get(); |
328 | 0 | return types; |
329 | 0 | } |
330 | | |
331 | | // WeakComponentImplHelper |
332 | | |
333 | | Any SAL_CALL WeakComponentImplHelper_query( |
334 | | Type const & rType, class_data * cd, void * that, WeakComponentImplHelperBase * pBase ) |
335 | 127M | { |
336 | 127M | checkInterface( rType ); |
337 | 127M | typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); |
338 | | |
339 | | // shortcut XInterface to WeakComponentImplHelperBase |
340 | 127M | if (! isXInterface( pTDR->pTypeName )) |
341 | 66.1M | { |
342 | 66.1M | void * p = queryDeepNoXInterface( pTDR, cd, that ); |
343 | 66.1M | if (p) |
344 | 32.1M | { |
345 | 32.1M | return Any( &p, pTDR ); |
346 | 32.1M | } |
347 | 66.1M | } |
348 | 95.2M | return pBase->WeakComponentImplHelperBase::queryInterface( rType ); |
349 | 127M | } |
350 | | |
351 | | Sequence< Type > SAL_CALL WeakComponentImplHelper_getTypes( |
352 | | class_data * cd ) |
353 | 5 | { |
354 | 5 | sal_Int32 nTypes = cd->m_nTypes; |
355 | 5 | Sequence< Type > types( nTypes +2 ); |
356 | 5 | Type * pTypes = types.getArray(); |
357 | 5 | fillTypes( pTypes, cd ); |
358 | 5 | pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get(); |
359 | 5 | pTypes[ nTypes ] = cppu::UnoType<lang::XComponent>::get(); |
360 | 5 | return types; |
361 | 5 | } |
362 | | |
363 | | // WeakAggComponentImplHelper |
364 | | |
365 | | Any SAL_CALL WeakAggComponentImplHelper_queryAgg( |
366 | | Type const & rType, class_data * cd, void * that, WeakAggComponentImplHelperBase * pBase ) |
367 | 107k | { |
368 | 107k | checkInterface( rType ); |
369 | 107k | typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); |
370 | | |
371 | | // shortcut XInterface to WeakAggComponentImplHelperBase |
372 | 107k | if (! isXInterface( pTDR->pTypeName )) |
373 | 107k | { |
374 | 107k | void * p = queryDeepNoXInterface( pTDR, cd, that ); |
375 | 107k | if (p) |
376 | 19.4k | { |
377 | 19.4k | return Any( &p, pTDR ); |
378 | 19.4k | } |
379 | 107k | } |
380 | 87.6k | return pBase->WeakAggComponentImplHelperBase::queryAggregation( rType ); |
381 | 107k | } |
382 | | |
383 | | Sequence< Type > SAL_CALL WeakAggComponentImplHelper_getTypes( |
384 | | class_data * cd ) |
385 | 0 | { |
386 | 0 | sal_Int32 nTypes = cd->m_nTypes; |
387 | 0 | Sequence< Type > types( nTypes +3 ); |
388 | 0 | Type * pTypes = types.getArray(); |
389 | 0 | fillTypes( pTypes, cd ); |
390 | 0 | pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get(); |
391 | 0 | pTypes[ nTypes++ ] = cppu::UnoType<XAggregation>::get(); |
392 | 0 | pTypes[ nTypes ] = cppu::UnoType<lang::XComponent>::get(); |
393 | 0 | return types; |
394 | 0 | } |
395 | | |
396 | | } |
397 | | |
398 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |