Bump version to 24.04.3.4
[LibreOffice.git] / cppuhelper / source / implbase_ex.cxx
blob4ced30adbe5ca4fc9400e7eb9087e788c025ba5e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <osl/diagnose.h>
21 #include <sal/log.hxx>
22 #include <cppuhelper/compbase_ex.hxx>
23 #include <cppuhelper/implbase_ex.hxx>
25 #include <com/sun/star/uno/RuntimeException.hpp>
27 #include <mutex>
29 using namespace ::cppu;
30 using namespace ::osl;
31 using namespace ::com::sun::star;
32 using namespace ::com::sun::star::uno;
34 namespace cppu
37 static void checkInterface( Type const & rType )
39 if (TypeClass_INTERFACE != rType.getTypeClass())
41 OUString msg( "querying for interface \"" + rType.getTypeName() + "\": no interface type!" );
42 SAL_WARN( "cppuhelper", msg );
43 throw RuntimeException( msg );
47 static bool isXInterface( rtl_uString * pStr )
49 return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface";
52 static void * makeInterface( sal_IntPtr nOffset, void * that )
54 return (static_cast<char *>(that) + nOffset);
57 static bool td_equals(
58 typelib_TypeDescriptionReference const * pTDR1,
59 typelib_TypeDescriptionReference const * pTDR2 )
61 return ((pTDR1 == pTDR2) ||
62 OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
65 static type_entry * getTypeEntries( class_data * cd )
67 type_entry * pEntries = cd->m_typeEntries;
68 if (! cd->m_storedTypeRefs) // not inited?
70 static std::mutex aMutex;
71 std::scoped_lock guard( aMutex );
72 if (! cd->m_storedTypeRefs) // not inited?
74 // get all types
75 for ( sal_Int32 n = cd->m_nTypes; n--; )
77 type_entry * pEntry = &pEntries[ n ];
78 Type const & rType = (*pEntry->m_type.getCppuType)( nullptr );
79 OSL_ENSURE( rType.getTypeClass() == TypeClass_INTERFACE, "### wrong helper init: expected interface!" );
80 OSL_ENSURE( ! isXInterface( rType.getTypeLibType()->pTypeName ), "### want to implement XInterface: template argument is XInterface?!?!?!" );
81 if (rType.getTypeClass() != TypeClass_INTERFACE)
83 OUString msg( "type \"" + rType.getTypeName() + "\" is no interface type!" );
84 SAL_WARN( "cppuhelper", msg );
85 throw RuntimeException( msg );
87 // ref is statically held by getCppuType()
88 pEntry->m_type.typeRef = rType.getTypeLibType();
90 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
91 cd->m_storedTypeRefs = true;
94 else
96 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
98 return pEntries;
101 static void fillTypes( Type * types, class_data * cd )
103 type_entry * pEntries = getTypeEntries( cd );
104 for ( sal_Int32 n = cd->m_nTypes; n--; )
106 types[ n ] = pEntries[ n ].m_type.typeRef;
110 namespace {
112 bool recursivelyFindType(
113 typelib_TypeDescriptionReference const * demandedType,
114 typelib_InterfaceTypeDescription const * type, sal_IntPtr * offset)
116 // This code assumes that the vtables of a multiple-inheritance class (the
117 // offset amount by which to adjust the this pointer) follow one another in
118 // the object layout, and that they contain slots for the inherited classes
119 // in a specific order. In theory, that need not hold for any given
120 // platform; in practice, it seems to work well on all supported platforms:
121 next:
122 for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
123 if (i > 0) {
124 *offset += sizeof (void *);
126 typelib_InterfaceTypeDescription const * base = type->ppBaseTypes[i];
127 // ignore XInterface:
128 if (base->nBaseTypes > 0) {
129 if (td_equals(
130 reinterpret_cast<
131 typelib_TypeDescriptionReference const * >(base),
132 demandedType))
134 return true;
136 // Profiling showed that it is important to speed up the common case
137 // of only one base:
138 if (type->nBaseTypes == 1) {
139 type = base;
140 goto next;
142 if (recursivelyFindType(demandedType, base, offset)) {
143 return true;
147 return false;
152 static void * queryDeepNoXInterface(
153 typelib_TypeDescriptionReference const * pDemandedTDR, class_data * cd, void * that )
155 type_entry * pEntries = getTypeEntries( cd );
156 sal_Int32 nTypes = cd->m_nTypes;
157 sal_Int32 n;
159 // try top interfaces without getting td
160 for ( n = 0; n < nTypes; ++n )
162 if (td_equals( pEntries[ n ].m_type.typeRef, pDemandedTDR ))
164 return makeInterface( pEntries[ n ].m_offset, that );
167 // query deep getting td
168 for ( n = 0; n < nTypes; ++n )
170 typelib_TypeDescription * pTD = nullptr;
171 TYPELIB_DANGER_GET( &pTD, pEntries[ n ].m_type.typeRef );
172 if (pTD)
174 // exclude top (already tested) and bottom (XInterface) interface
175 OSL_ENSURE(
176 reinterpret_cast< typelib_InterfaceTypeDescription * >(pTD)->
177 nBaseTypes > 0,
178 "### want to implement XInterface:"
179 " template argument is XInterface?!?!?!" );
180 sal_IntPtr offset = pEntries[n].m_offset;
181 bool found = recursivelyFindType(
182 pDemandedTDR,
183 reinterpret_cast< typelib_InterfaceTypeDescription * >(pTD),
184 &offset);
185 TYPELIB_DANGER_RELEASE( pTD );
186 if (found) {
187 return makeInterface( offset, that );
190 else
192 OUString msg( "cannot get type description for type \"" + OUString::unacquired(&pEntries[ n ].m_type.typeRef->pTypeName) + "\"!" );
193 SAL_WARN( "cppuhelper", msg );
194 throw RuntimeException( msg );
197 return nullptr;
200 // ImplHelper
202 Any SAL_CALL ImplHelper_query(
203 Type const & rType, class_data * cd, void * that )
205 checkInterface( rType );
206 typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
208 void * p;
209 // shortcut for XInterface
210 if (isXInterface( pTDR->pTypeName ))
212 // take first one
213 p = makeInterface( cd->m_typeEntries[ 0 ].m_offset, that );
215 else
217 p = queryDeepNoXInterface( pTDR, cd, that );
218 if (! p)
220 return Any();
223 return Any( &p, pTDR );
226 Any SAL_CALL ImplHelper_queryNoXInterface(
227 Type const & rType, class_data * cd, void * that )
229 checkInterface( rType );
230 typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
232 void * p = queryDeepNoXInterface( pTDR, cd, that );
233 if (p)
235 return Any( &p, pTDR );
237 return Any();
240 css::uno::Sequence<sal_Int8> ImplHelper_getImplementationId(
241 SAL_UNUSED_PARAMETER class_data *)
243 return css::uno::Sequence<sal_Int8>();
246 Sequence< Type > SAL_CALL ImplHelper_getTypes(
247 class_data * cd )
249 Sequence< Type > types( cd->m_nTypes );
250 Type * pTypes = types.getArray();
251 fillTypes( pTypes, cd );
252 return types;
255 Sequence< Type > SAL_CALL ImplInhHelper_getTypes(
256 class_data * cd, Sequence< Type > const & rAddTypes )
258 sal_Int32 nImplTypes = cd->m_nTypes;
259 sal_Int32 nAddTypes = rAddTypes.getLength();
260 Sequence< Type > types( nImplTypes + nAddTypes );
261 Type * pTypes = types.getArray();
262 fillTypes( pTypes, cd );
263 // append base types
264 Type const * pAddTypes = rAddTypes.getConstArray();
265 while (nAddTypes--)
267 pTypes[ nImplTypes + nAddTypes ] = pAddTypes[ nAddTypes ];
269 return types;
272 // WeakImplHelper
274 Any SAL_CALL WeakImplHelper_query(
275 Type const & rType, class_data * cd, void * that, OWeakObject * pBase )
277 checkInterface( rType );
278 typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
280 // shortcut XInterface to OWeakObject
281 if (! isXInterface( pTDR->pTypeName ))
283 void * p = queryDeepNoXInterface( pTDR, cd, that );
284 if (p)
286 return Any( &p, pTDR );
289 return pBase->OWeakObject::queryInterface( rType );
292 Sequence< Type > SAL_CALL WeakImplHelper_getTypes(
293 class_data * cd )
295 sal_Int32 nTypes = cd->m_nTypes;
296 Sequence< Type > types( nTypes +1 );
297 Type * pTypes = types.getArray();
298 fillTypes( pTypes, cd );
299 pTypes[ nTypes ] = cppu::UnoType<XWeak>::get();
300 return types;
303 // WeakAggImplHelper
305 Any SAL_CALL WeakAggImplHelper_queryAgg(
306 Type const & rType, class_data * cd, void * that, OWeakAggObject * pBase )
308 checkInterface( rType );
309 typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
311 // shortcut XInterface to OWeakAggObject
312 if (! isXInterface( pTDR->pTypeName ))
314 void * p = queryDeepNoXInterface( pTDR, cd, that );
315 if (p)
317 return Any( &p, pTDR );
320 return pBase->OWeakAggObject::queryAggregation( rType );
323 Sequence< Type > SAL_CALL WeakAggImplHelper_getTypes(
324 class_data * cd )
326 sal_Int32 nTypes = cd->m_nTypes;
327 Sequence< Type > types( nTypes +2 );
328 Type * pTypes = types.getArray();
329 fillTypes( pTypes, cd );
330 pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get();
331 pTypes[ nTypes ] = cppu::UnoType<XAggregation>::get();
332 return types;
335 // WeakComponentImplHelper
337 Any SAL_CALL WeakComponentImplHelper_query(
338 Type const & rType, class_data * cd, void * that, WeakComponentImplHelperBase * pBase )
340 checkInterface( rType );
341 typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
343 // shortcut XInterface to WeakComponentImplHelperBase
344 if (! isXInterface( pTDR->pTypeName ))
346 void * p = queryDeepNoXInterface( pTDR, cd, that );
347 if (p)
349 return Any( &p, pTDR );
352 return pBase->WeakComponentImplHelperBase::queryInterface( rType );
355 Sequence< Type > SAL_CALL WeakComponentImplHelper_getTypes(
356 class_data * cd )
358 sal_Int32 nTypes = cd->m_nTypes;
359 Sequence< Type > types( nTypes +2 );
360 Type * pTypes = types.getArray();
361 fillTypes( pTypes, cd );
362 pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get();
363 pTypes[ nTypes ] = cppu::UnoType<lang::XComponent>::get();
364 return types;
367 // WeakAggComponentImplHelper
369 Any SAL_CALL WeakAggComponentImplHelper_queryAgg(
370 Type const & rType, class_data * cd, void * that, WeakAggComponentImplHelperBase * pBase )
372 checkInterface( rType );
373 typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
375 // shortcut XInterface to WeakAggComponentImplHelperBase
376 if (! isXInterface( pTDR->pTypeName ))
378 void * p = queryDeepNoXInterface( pTDR, cd, that );
379 if (p)
381 return Any( &p, pTDR );
384 return pBase->WeakAggComponentImplHelperBase::queryAggregation( rType );
387 Sequence< Type > SAL_CALL WeakAggComponentImplHelper_getTypes(
388 class_data * cd )
390 sal_Int32 nTypes = cd->m_nTypes;
391 Sequence< Type > types( nTypes +3 );
392 Type * pTypes = types.getArray();
393 fillTypes( pTypes, cd );
394 pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get();
395 pTypes[ nTypes++ ] = cppu::UnoType<XAggregation>::get();
396 pTypes[ nTypes ] = cppu::UnoType<lang::XComponent>::get();
397 return types;
402 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */