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