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