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_testtools.hxx"
30 #include <osl/diagnose.h>
31 #include <osl/interlck.h>
32 #include <rtl/ustring.hxx>
33 #include <typelib/typedescription.h>
34 #include <uno/dispatcher.h>
35 #include <uno/environment.h>
36 #include <uno/mapping.h>
37 #include <uno/lbnames.h>
38 
39 using namespace rtl;
40 
41 
42 namespace pseudo_uno
43 {
44 
45 //==================================================================================================
46 struct pseudo_Mapping : public uno_Mapping
47 {
48 	oslInterlockedCount		nRef;
49 
50 	uno_ExtEnvironment *	pFrom;
51 	uno_ExtEnvironment *	pTo;
52 
53 	pseudo_Mapping( uno_ExtEnvironment * pFrom_, uno_ExtEnvironment * pTo_ );
54 	~pseudo_Mapping();
55 };
56 
57 //==== a uno pseudo proxy =============================================================================
58 struct pseudo_unoInterfaceProxy : public uno_Interface
59 {
60 	oslInterlockedCount					nRef;
61 	pseudo_Mapping *					pPseudoMapping;
62 
63 	// mapping information
64 	uno_Interface *						pUnoI; // wrapped interface
65 	typelib_InterfaceTypeDescription *	pTypeDescr;
66 	OUString							oid;
67 
68 	// ctor
69 	inline pseudo_unoInterfaceProxy( pseudo_Mapping * pPseudoMapping_,
70 									 uno_Interface * pUnoI_,
71 									 typelib_InterfaceTypeDescription * pTypeDescr_,
72 									 const OUString & rOId_ );
73 };
74 //--------------------------------------------------------------------------------------------------
75 static void SAL_CALL pseudo_unoInterfaceProxy_dispatch(
76 	uno_Interface * pUnoI,
77 	const typelib_TypeDescription * pMemberType,
78 	void * pReturn,
79 	void * pArgs[],
80 	uno_Any ** ppException )
81 {
82 	pseudo_unoInterfaceProxy * pThis = static_cast< pseudo_unoInterfaceProxy * >( pUnoI );
83 	(*pThis->pUnoI->pDispatcher)( pThis->pUnoI, pMemberType, pReturn, pArgs, ppException );
84 }
85 
86 //--------------------------------------------------------------------------------------------------
87 static void SAL_CALL pseudo_unoInterfaceProxy_free( uno_ExtEnvironment * pEnv, void * pProxy )
88 {
89 	pseudo_unoInterfaceProxy * pThis =
90 		static_cast< pseudo_unoInterfaceProxy * >(
91 			reinterpret_cast< uno_Interface * >( pProxy ) );
92 	OSL_ASSERT( pEnv == pThis->pPseudoMapping->pTo );
93 
94 	(*pThis->pPseudoMapping->pFrom->revokeInterface)( pThis->pPseudoMapping->pFrom, pThis->pUnoI );
95 	(*pThis->pUnoI->release)( pThis->pUnoI );
96 	typelib_typedescription_release( (typelib_TypeDescription *)pThis->pTypeDescr );
97 	(*pThis->pPseudoMapping->release)( pThis->pPseudoMapping );
98 
99 #if OSL_DEBUG_LEVEL > 1
100 	*(int *)pProxy = 0xdeadbabe;
101 #endif
102 	delete pThis;
103 }
104 //--------------------------------------------------------------------------------------------------
105 static void SAL_CALL pseudo_unoInterfaceProxy_acquire( uno_Interface * pUnoI )
106 {
107 	if (1 == osl_incrementInterlockedCount( &static_cast< pseudo_unoInterfaceProxy * >( pUnoI )->nRef ))
108 	{
109 		// rebirth of proxy zombie
110 		// register at uno env
111 		void * pThis = static_cast< uno_Interface * >( pUnoI );
112 		(*static_cast< pseudo_unoInterfaceProxy * >( pUnoI )->pPseudoMapping->pTo->registerProxyInterface)(
113 			static_cast< pseudo_unoInterfaceProxy * >( pUnoI )->pPseudoMapping->pTo,
114 			&pThis, pseudo_unoInterfaceProxy_free,
115 			static_cast< pseudo_unoInterfaceProxy * >( pUnoI )->oid.pData,
116 			static_cast< pseudo_unoInterfaceProxy * >( pUnoI )->pTypeDescr );
117 		OSL_ASSERT( pThis == static_cast< uno_Interface * >( pUnoI ) );
118 	}
119 }
120 //--------------------------------------------------------------------------------------------------
121 static void SAL_CALL pseudo_unoInterfaceProxy_release( uno_Interface * pUnoI )
122 {
123 	if (! osl_decrementInterlockedCount( & static_cast< pseudo_unoInterfaceProxy * >( pUnoI )->nRef ))
124 	{
125 		// revoke from uno env on last release
126 		(*static_cast< pseudo_unoInterfaceProxy * >( pUnoI )->pPseudoMapping->pTo->revokeInterface)(
127 			static_cast< pseudo_unoInterfaceProxy * >( pUnoI )->pPseudoMapping->pTo, pUnoI );
128 	}
129 }
130 //__________________________________________________________________________________________________
131 inline pseudo_unoInterfaceProxy::pseudo_unoInterfaceProxy(
132 	pseudo_Mapping * pPseudoMapping_, uno_Interface * pUnoI_,
133 	typelib_InterfaceTypeDescription * pTypeDescr_, const OUString & rOId_ )
134 	: nRef( 1 )
135 	, pPseudoMapping( pPseudoMapping_ )
136 	, pUnoI( pUnoI_ )
137 	, pTypeDescr( pTypeDescr_ )
138 	, oid( rOId_ )
139 {
140 	(*pPseudoMapping->acquire)( pPseudoMapping );
141 	typelib_typedescription_acquire( (typelib_TypeDescription *)pTypeDescr );
142 	(*pPseudoMapping->pFrom->registerInterface)(
143 		pPseudoMapping->pFrom, reinterpret_cast< void ** >( &pUnoI ), oid.pData, pTypeDescr );
144 	(*pUnoI->acquire)( pUnoI );
145 
146 	// uno_Interface
147 	uno_Interface::acquire = pseudo_unoInterfaceProxy_acquire;
148 	uno_Interface::release = pseudo_unoInterfaceProxy_release;
149 	uno_Interface::pDispatcher = pseudo_unoInterfaceProxy_dispatch;
150 }
151 
152 //--------------------------------------------------------------------------------------------------
153 static void SAL_CALL pseudo_Mapping_mapInterface(
154 	uno_Mapping * pMapping, void ** ppOut,
155 	void * pUnoI, typelib_InterfaceTypeDescription * pTypeDescr )
156 {
157 	OSL_ASSERT( ppOut && pTypeDescr );
158 	if (*ppOut)
159 	{
160 		(*reinterpret_cast< uno_Interface * >( *ppOut )->release)(
161 			reinterpret_cast< uno_Interface * >( *ppOut ) );
162 		*ppOut = 0;
163 	}
164 	if (pUnoI && pTypeDescr)
165 	{
166 		// get object id of uno interface to be wrapped
167 		rtl_uString * pOId = 0;
168 		(*static_cast< pseudo_Mapping * >( pMapping )->pFrom->getObjectIdentifier)(
169 			static_cast< pseudo_Mapping * >( pMapping )->pFrom, &pOId, pUnoI );
170 		OSL_ASSERT( pOId );
171 
172 		if (pOId)
173 		{
174 			// try to get any known interface from target environment
175 			(*static_cast< pseudo_Mapping * >( pMapping )->pTo->getRegisteredInterface)(
176 				static_cast< pseudo_Mapping * >( pMapping )->pTo, ppOut, pOId, pTypeDescr );
177 			if (! *ppOut) // no existing interface, register new proxy interface
178 			{
179 				// try to publish a new proxy (ref count initially 1)
180 				void * pProxy = new pseudo_unoInterfaceProxy(
181 					static_cast< pseudo_Mapping * >( pMapping ),
182 					reinterpret_cast< uno_Interface * >( pUnoI ), pTypeDescr, pOId );
183 
184 				// proxy may be exchanged during registration
185 				(*static_cast< pseudo_Mapping * >( pMapping )->pTo->registerProxyInterface)(
186 					static_cast< pseudo_Mapping * >( pMapping )->pTo,
187 					&pProxy, pseudo_unoInterfaceProxy_free, pOId, pTypeDescr );
188 
189 				*ppOut = pProxy;
190 			}
191 			rtl_uString_release( pOId );
192 		}
193 	}
194 }
195 //--------------------------------------------------------------------------------------------------
196 static void SAL_CALL pseudo_Mapping_free( uno_Mapping * pMapping )
197 {
198 	delete static_cast< pseudo_Mapping * >( pMapping );
199 }
200 //--------------------------------------------------------------------------------------------------
201 static void SAL_CALL pseudo_Mapping_acquire( uno_Mapping * pMapping )
202 {
203 	if (1 == osl_incrementInterlockedCount( & static_cast< pseudo_Mapping * >( pMapping )->nRef ))
204 	{
205 		OUString aMappingPurpose( RTL_CONSTASCII_USTRINGPARAM("pseudo") );
206 		uno_registerMapping( &pMapping,
207 							 pseudo_Mapping_free,
208 							 (uno_Environment *)((pseudo_Mapping *)pMapping)->pFrom,
209 							 (uno_Environment *)((pseudo_Mapping *)pMapping)->pTo,
210 							 aMappingPurpose.pData );
211 	}
212 }
213 //--------------------------------------------------------------------------------------------------
214 static void SAL_CALL pseudo_Mapping_release( uno_Mapping * pMapping )
215 {
216 	if (! osl_decrementInterlockedCount( & static_cast< pseudo_Mapping * >( pMapping )->nRef ))
217 	{
218 		uno_revokeMapping( pMapping );
219 	}
220 }
221 
222 //__________________________________________________________________________________________________
223 pseudo_Mapping::pseudo_Mapping( uno_ExtEnvironment * pFrom_, uno_ExtEnvironment * pTo_ )
224 	: nRef( 1 )
225 	, pFrom( pFrom_ )
226 	, pTo( pTo_ )
227 {
228 	(*((uno_Environment *)pFrom)->acquire)( (uno_Environment *)pFrom );
229 	(*((uno_Environment *)pTo)->acquire)( (uno_Environment *)pTo );
230 	//
231 	uno_Mapping::acquire = pseudo_Mapping_acquire;
232 	uno_Mapping::release = pseudo_Mapping_release;
233 	uno_Mapping::mapInterface = pseudo_Mapping_mapInterface;
234 }
235 //__________________________________________________________________________________________________
236 pseudo_Mapping::~pseudo_Mapping()
237 {
238 	(*((uno_Environment *)pTo)->release)( (uno_Environment *)pTo );
239 	(*((uno_Environment *)pFrom)->release)( (uno_Environment *)pFrom );
240 }
241 
242 }
243 
244 //##################################################################################################
245 extern "C" void SAL_CALL uno_initEnvironment( uno_Environment * pUnoEnv )
246 {
247 	OSL_ENSURE( sal_False, "### no impl: unexpected call!" );
248 }
249 //##################################################################################################
250 extern "C" void SAL_CALL uno_ext_getMapping(
251 	uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
252 {
253 	OSL_ASSERT( ppMapping && pFrom && pTo );
254 	if (ppMapping && pFrom && pTo && pFrom->pExtEnv && pTo->pExtEnv)
255 	{
256 		uno_Mapping * pMapping = 0;
257 
258 		if (0 == rtl_ustr_ascii_compare( pFrom->pTypeName->buffer, UNO_LB_UNO ) &&
259 			0 == rtl_ustr_ascii_compare( pTo->pTypeName->buffer, UNO_LB_UNO ))
260 		{
261 			OUString aMappingPurpose( RTL_CONSTASCII_USTRINGPARAM("pseudo") );
262 			// ref count is initially 1
263 			pMapping = new pseudo_uno::pseudo_Mapping( pFrom->pExtEnv, pTo->pExtEnv );
264 			uno_registerMapping( &pMapping, pseudo_uno::pseudo_Mapping_free,
265 								 (uno_Environment *)pFrom->pExtEnv,
266 								 (uno_Environment *)pTo->pExtEnv,
267 								 aMappingPurpose.pData );
268 		}
269 
270 		if (*ppMapping)
271 			(*(*ppMapping)->release)( *ppMapping );
272 		*ppMapping = pMapping;
273 	}
274 }
275