xref: /trunk/main/cppuhelper/source/implbase_ex.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 #include <sal/alloca.h>
27 
28 #include <string.h>
29 #include <osl/diagnose.h>
30 #include <rtl/byteseq.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <rtl/uuid.h>
33 #include <cppuhelper/compbase_ex.hxx>
34 
35 #include "com/sun/star/uno/RuntimeException.hpp"
36 
37 using namespace ::cppu;
38 using namespace ::osl;
39 using namespace ::rtl;
40 using namespace ::com::sun::star;
41 using namespace ::com::sun::star::uno;
42 
43 namespace cppu
44 {
45 
46 /** Shared mutex for implementation helper initialization.
47     Not for public use.
48 */
49 ::osl::Mutex & SAL_CALL getImplHelperInitMutex(void) SAL_THROW( () );
50 
51 //--------------------------------------------------------------------------------------------------
checkInterface(Type const & rType)52 static inline void checkInterface( Type const & rType )
53 {
54     if (TypeClass_INTERFACE != rType.getTypeClass())
55     {
56         OUStringBuffer buf( 64 );
57         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("querying for interface \"") );
58         buf.append( rType.getTypeName() );
59         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\": no interface type!") );
60         OUString msg( buf.makeStringAndClear() );
61 #if OSL_DEBUG_LEVEL > 0
62         OString str( OUStringToOString( msg, RTL_TEXTENCODING_ASCII_US ) );
63         OSL_ENSURE( 0, str.getStr() );
64 #endif
65         throw RuntimeException( msg, Reference< XInterface >() );
66     }
67 }
68 //--------------------------------------------------------------------------------------------------
isXInterface(rtl_uString * pStr)69 static inline bool isXInterface( rtl_uString * pStr ) SAL_THROW( () )
70 {
71     return (((OUString const *)&pStr)->equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ) != sal_False);
72 }
73 //--------------------------------------------------------------------------------------------------
makeInterface(sal_IntPtr nOffset,void * that)74 static inline void * makeInterface( sal_IntPtr nOffset, void * that ) SAL_THROW( () )
75 {
76     return (((char *)that) + nOffset);
77 }
78 //--------------------------------------------------------------------------------------------------
__td_equals(typelib_TypeDescriptionReference const * pTDR1,typelib_TypeDescriptionReference const * pTDR2)79 static inline bool __td_equals(
80     typelib_TypeDescriptionReference const * pTDR1,
81     typelib_TypeDescriptionReference const * pTDR2 )
82     SAL_THROW( () )
83 {
84     return ((pTDR1 == pTDR2) ||
85             ((OUString const *)&pTDR1->pTypeName)->equals( *(OUString const *)&pTDR2->pTypeName ) != sal_False);
86 }
87 //--------------------------------------------------------------------------------------------------
__getTypeEntries(class_data * cd)88 static inline type_entry * __getTypeEntries( class_data * cd )
89 {
90     type_entry * pEntries = cd->m_typeEntries;
91     if (! cd->m_storedTypeRefs) // not inited?
92     {
93         MutexGuard guard( getImplHelperInitMutex() );
94         if (! cd->m_storedTypeRefs) // not inited?
95         {
96             // get all types
97             for ( sal_Int32 n = cd->m_nTypes; n--; )
98             {
99                 type_entry * pEntry = &pEntries[ n ];
100                 Type const & rType = (*pEntry->m_type.getCppuType)( 0 );
101                 OSL_ENSURE( rType.getTypeClass() == TypeClass_INTERFACE, "### wrong helper init: expected interface!" );
102                 OSL_ENSURE( ! isXInterface( rType.getTypeLibType()->pTypeName ), "### want to implement XInterface: template argument is XInterface?!?!?!" );
103                 if (rType.getTypeClass() != TypeClass_INTERFACE)
104                 {
105                     OUStringBuffer buf( 48 );
106                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("type \"") );
107                     buf.append( rType.getTypeName() );
108                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" is no interface type!") );
109                     OUString msg( buf.makeStringAndClear() );
110 #if OSL_DEBUG_LEVEL > 0
111                     OString str( OUStringToOString( msg, RTL_TEXTENCODING_ASCII_US ) );
112                     OSL_ENSURE( 0, str.getStr() );
113 #endif
114                     throw RuntimeException( msg, Reference< XInterface >() );
115                 }
116                 // ref is statically held by getCppuType()
117                 pEntry->m_type.typeRef = rType.getTypeLibType();
118             }
119             cd->m_storedTypeRefs = sal_True;
120         }
121     }
122     return pEntries;
123 }
124 //--------------------------------------------------------------------------------------------------
__fillTypes(Type * types,class_data * cd)125 static inline void __fillTypes( Type * types, class_data * cd )
126 {
127     type_entry * pEntries = __getTypeEntries( cd );
128     for ( sal_Int32 n = cd->m_nTypes; n--; )
129     {
130         types[ n ] = pEntries[ n ].m_type.typeRef;
131     }
132 }
133 //--------------------------------------------------------------------------------------------------
134 namespace {
135 
recursivelyFindType(typelib_TypeDescriptionReference const * demandedType,typelib_InterfaceTypeDescription const * type,sal_IntPtr * offset)136 bool recursivelyFindType(
137     typelib_TypeDescriptionReference const * demandedType,
138     typelib_InterfaceTypeDescription const * type, sal_IntPtr * offset)
139 {
140     // This code assumes that the vtables of a multiple-inheritance class (the
141     // offset amount by which to adjust the this pointer) follow one another in
142     // the object layout, and that they contain slots for the inherited classes
143     // in a specific order.  In theory, that need not hold for any given
144     // platform; in practice, it seems to work well on all supported platforms:
145  next:
146     for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
147         if (i > 0) {
148             *offset += sizeof (void *);
149         }
150         typelib_InterfaceTypeDescription const * base = type->ppBaseTypes[i];
151         // ignore XInterface:
152         if (base->nBaseTypes > 0) {
153             if (__td_equals(
154                     reinterpret_cast<
155                         typelib_TypeDescriptionReference const * >(base),
156                     demandedType))
157             {
158                 return true;
159             }
160             // Profiling showed that it is important to speed up the common case
161             // of only one base:
162             if (type->nBaseTypes == 1) {
163                 type = base;
164                 goto next;
165             }
166             if (recursivelyFindType(demandedType, base, offset)) {
167                 return true;
168             }
169         }
170     }
171     return false;
172 }
173 
174 }
175 
__queryDeepNoXInterface(typelib_TypeDescriptionReference * pDemandedTDR,class_data * cd,void * that)176 static inline void * __queryDeepNoXInterface(
177     typelib_TypeDescriptionReference * pDemandedTDR, class_data * cd, void * that )
178 {
179     type_entry * pEntries = __getTypeEntries( cd );
180     sal_Int32 nTypes = cd->m_nTypes;
181     sal_Int32 n;
182 
183     // try top interfaces without getting td
184     for ( n = 0; n < nTypes; ++n )
185     {
186         if (__td_equals( pEntries[ n ].m_type.typeRef, pDemandedTDR ))
187         {
188             return makeInterface( pEntries[ n ].m_offset, that );
189         }
190     }
191     // query deep getting td
192     for ( n = 0; n < nTypes; ++n )
193     {
194         typelib_TypeDescription * pTD = 0;
195         TYPELIB_DANGER_GET( &pTD, pEntries[ n ].m_type.typeRef );
196         if (pTD)
197         {
198             // exclude top (already tested) and bottom (XInterface) interface
199             OSL_ENSURE(
200                 reinterpret_cast< typelib_InterfaceTypeDescription * >(pTD)->
201                     nBaseTypes > 0,
202                 "### want to implement XInterface:"
203                     " template argument is XInterface?!?!?!" );
204             sal_IntPtr offset = pEntries[n].m_offset;
205             bool found = recursivelyFindType(
206                 pDemandedTDR,
207                 reinterpret_cast< typelib_InterfaceTypeDescription * >(pTD),
208                 &offset);
209             TYPELIB_DANGER_RELEASE( pTD );
210             if (found) {
211                 return makeInterface( offset, that );
212             }
213         }
214         else
215         {
216             OUStringBuffer buf( 64 );
217             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("cannot get type description for type \"") );
218             buf.append( pEntries[ n ].m_type.typeRef->pTypeName );
219             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
220             OUString msg( buf.makeStringAndClear() );
221 #if OSL_DEBUG_LEVEL > 0
222             OString str( OUStringToOString( msg, RTL_TEXTENCODING_ASCII_US ) );
223             OSL_ENSURE( 0, str.getStr() );
224 #endif
225             throw RuntimeException( msg, Reference< XInterface >() );
226         }
227     }
228     return 0;
229 }
230 
231 // ImplHelper
232 //==================================================================================================
ImplHelper_query(Type const & rType,class_data * cd,void * that)233 Any SAL_CALL ImplHelper_query(
234     Type const & rType, class_data * cd, void * that )
235 {
236     checkInterface( rType );
237     typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
238 
239     void * p;
240     // shortcut for XInterface
241     if (isXInterface( pTDR->pTypeName ))
242     {
243         // take first one
244         p = makeInterface( cd->m_typeEntries[ 0 ].m_offset, that );
245     }
246     else
247     {
248         p = __queryDeepNoXInterface( pTDR, cd, that );
249         if (! p)
250         {
251             return Any();
252         }
253     }
254     return Any( &p, pTDR );
255 }
256 //==================================================================================================
ImplHelper_queryNoXInterface(Type const & rType,class_data * cd,void * that)257 Any SAL_CALL ImplHelper_queryNoXInterface(
258     Type const & rType, class_data * cd, void * that )
259 {
260     checkInterface( rType );
261     typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
262 
263     void * p = __queryDeepNoXInterface( pTDR, cd, that );
264     if (p)
265     {
266         return Any( &p, pTDR );
267     }
268     else
269     {
270         return Any();
271     }
272 }
273 //==================================================================================================
ImplHelper_getImplementationId(class_data * cd)274 Sequence< sal_Int8 > SAL_CALL ImplHelper_getImplementationId( class_data * cd )
275 {
276     if (! cd->m_createdId)
277     {
278         sal_uInt8 * id = (sal_uInt8 *)alloca( 16 );
279         ::rtl_createUuid( (sal_uInt8 *)id, 0, sal_True );
280 
281         MutexGuard guard( getImplHelperInitMutex() );
282         if (! cd->m_createdId)
283         {
284             memcpy( cd->m_id, id, 16 );
285             cd->m_createdId = sal_True;
286         }
287     }
288 
289     sal_Sequence * seq = 0;
290     ::rtl_byte_sequence_constructFromArray( &seq, cd->m_id, 16 );
291     return Sequence< sal_Int8 >( seq, SAL_NO_ACQUIRE );
292 }
293 //==================================================================================================
ImplHelper_getTypes(class_data * cd)294 Sequence< Type > SAL_CALL ImplHelper_getTypes(
295     class_data * cd )
296 {
297     Sequence< Type > types( cd->m_nTypes );
298     Type * pTypes = types.getArray();
299     __fillTypes( pTypes, cd );
300     return types;
301 }
302 //==================================================================================================
ImplInhHelper_getTypes(class_data * cd,Sequence<Type> const & rAddTypes)303 Sequence< Type >  SAL_CALL ImplInhHelper_getTypes(
304     class_data * cd, Sequence< Type > const & rAddTypes )
305 {
306     sal_Int32 nImplTypes = cd->m_nTypes;
307     sal_Int32 nAddTypes = rAddTypes.getLength();
308     Sequence< Type > types( nImplTypes + nAddTypes );
309     Type * pTypes = types.getArray();
310     __fillTypes( pTypes, cd );
311     // append base types
312     Type const * pAddTypes = rAddTypes.getConstArray();
313     while (nAddTypes--)
314     {
315         pTypes[ nImplTypes + nAddTypes ] = pAddTypes[ nAddTypes ];
316     }
317     return types;
318 }
319 
320 // WeakImplHelper
321 //==================================================================================================
WeakImplHelper_query(Type const & rType,class_data * cd,void * that,OWeakObject * pBase)322 Any SAL_CALL WeakImplHelper_query(
323     Type const & rType, class_data * cd, void * that, OWeakObject * pBase )
324 {
325     checkInterface( rType );
326     typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
327 
328     // shortcut XInterface to OWeakObject
329     if (! isXInterface( pTDR->pTypeName ))
330     {
331         void * p = __queryDeepNoXInterface( pTDR, cd, that );
332         if (p)
333         {
334             return Any( &p, pTDR );
335         }
336     }
337     return pBase->OWeakObject::queryInterface( rType );
338 }
339 //==================================================================================================
WeakImplHelper_getTypes(class_data * cd)340 Sequence< Type > SAL_CALL WeakImplHelper_getTypes(
341     class_data * cd )
342 {
343     sal_Int32 nTypes = cd->m_nTypes;
344     Sequence< Type > types( nTypes +1 );
345     Type * pTypes = types.getArray();
346     __fillTypes( pTypes, cd );
347     pTypes[ nTypes ] = ::getCppuType( (Reference< XWeak > const *)0 );
348     return types;
349 }
350 
351 // WeakAggImplHelper
352 //==================================================================================================
WeakAggImplHelper_queryAgg(Type const & rType,class_data * cd,void * that,OWeakAggObject * pBase)353 Any SAL_CALL WeakAggImplHelper_queryAgg(
354     Type const & rType, class_data * cd, void * that, OWeakAggObject * pBase )
355 {
356     checkInterface( rType );
357     typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
358 
359     // shortcut XInterface to OWeakAggObject
360     if (! isXInterface( pTDR->pTypeName ))
361     {
362         void * p = __queryDeepNoXInterface( pTDR, cd, that );
363         if (p)
364         {
365             return Any( &p, pTDR );
366         }
367     }
368     return pBase->OWeakAggObject::queryAggregation( rType );
369 }
370 //==================================================================================================
WeakAggImplHelper_getTypes(class_data * cd)371 Sequence< Type > SAL_CALL WeakAggImplHelper_getTypes(
372     class_data * cd )
373 {
374     sal_Int32 nTypes = cd->m_nTypes;
375     Sequence< Type > types( nTypes +2 );
376     Type * pTypes = types.getArray();
377     __fillTypes( pTypes, cd );
378     pTypes[ nTypes++ ] = ::getCppuType( (Reference< XWeak > const *)0 );
379     pTypes[ nTypes ] = ::getCppuType( (const Reference< XAggregation > *)0 );
380     return types;
381 }
382 
383 // WeakComponentImplHelper
384 //==================================================================================================
WeakComponentImplHelper_query(Type const & rType,class_data * cd,void * that,WeakComponentImplHelperBase * pBase)385 Any SAL_CALL WeakComponentImplHelper_query(
386     Type const & rType, class_data * cd, void * that, WeakComponentImplHelperBase * pBase )
387 {
388     checkInterface( rType );
389     typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
390 
391     // shortcut XInterface to WeakComponentImplHelperBase
392     if (! isXInterface( pTDR->pTypeName ))
393     {
394         void * p = __queryDeepNoXInterface( pTDR, cd, that );
395         if (p)
396         {
397             return Any( &p, pTDR );
398         }
399     }
400     return pBase->WeakComponentImplHelperBase::queryInterface( rType );
401 }
402 //==================================================================================================
WeakComponentImplHelper_getTypes(class_data * cd)403 Sequence< Type > SAL_CALL WeakComponentImplHelper_getTypes(
404     class_data * cd )
405 {
406     sal_Int32 nTypes = cd->m_nTypes;
407     Sequence< Type > types( nTypes +2 );
408     Type * pTypes = types.getArray();
409     __fillTypes( pTypes, cd );
410     pTypes[ nTypes++ ] = ::getCppuType( (Reference< XWeak > const *)0 );
411     pTypes[ nTypes ] = ::getCppuType( (Reference< lang::XComponent > const *)0 );
412     return types;
413 }
414 
415 // WeakAggComponentImplHelper
416 //==================================================================================================
WeakAggComponentImplHelper_queryAgg(Type const & rType,class_data * cd,void * that,WeakAggComponentImplHelperBase * pBase)417 Any SAL_CALL WeakAggComponentImplHelper_queryAgg(
418     Type const & rType, class_data * cd, void * that, WeakAggComponentImplHelperBase * pBase )
419 {
420     checkInterface( rType );
421     typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType();
422 
423     // shortcut XInterface to WeakAggComponentImplHelperBase
424     if (! isXInterface( pTDR->pTypeName ))
425     {
426         void * p = __queryDeepNoXInterface( pTDR, cd, that );
427         if (p)
428         {
429             return Any( &p, pTDR );
430         }
431     }
432     return pBase->WeakAggComponentImplHelperBase::queryAggregation( rType );
433 }
434 //==================================================================================================
WeakAggComponentImplHelper_getTypes(class_data * cd)435 Sequence< Type > SAL_CALL WeakAggComponentImplHelper_getTypes(
436     class_data * cd )
437 {
438     sal_Int32 nTypes = cd->m_nTypes;
439     Sequence< Type > types( nTypes +3 );
440     Type * pTypes = types.getArray();
441     __fillTypes( pTypes, cd );
442     pTypes[ nTypes++ ] = ::getCppuType( (Reference< XWeak > const *)0 );
443     pTypes[ nTypes++ ] = ::getCppuType( (const Reference< XAggregation > *)0 );
444     pTypes[ nTypes ] = ::getCppuType( (const Reference< lang::XComponent > *)0 );
445     return types;
446 }
447 
448 }
449