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 #include <iostream>
25 
26 #include "osl/interlck.h"
27 #include "rtl/ustring.hxx"
28 #include "uno/environment.hxx"
29 #include "uno/mapping.hxx"
30 #include "uno/dispatcher.h"
31 
32 //#include "cascade_mappping.hxx"
33 #include "cppu/EnvDcp.hxx"
34 
35 
36 //#define LOG_CALLING_named_purpose_getMapping
37 
38 //#define LOG_LIFECYLE_MediatorMapping
39 #ifdef LOG_LIFECYLE_MediatorMapping
40 #  define LOG_LIFECYLE_MediatorMapping_emit(x) x
41 
42 #else
43 #  define LOG_LIFECYLE_MediatorMapping_emit(x)
44 
45 #endif
46 
47 
48 using namespace com::sun::star;
49 
50 class MediatorMapping : public uno_Mapping
51 {
52 	oslInterlockedCount m_refCount;
53 
54 	uno::Mapping        m_from2uno;
55 	uno::Mapping        m_uno2to;
56 
57 	uno::Environment    m_from;
58 	uno::Environment    m_interm;
59 	uno::Environment    m_to;
60 
61 public:
62 	void acquire(void);
63 	void release(void);
64 
65 	void mapInterface(void                            ** ppOut,
66 					  void                             * pInterface,
67 					  typelib_InterfaceTypeDescription * pInterfaceTypeDescr);
68 	MediatorMapping(uno_Environment * pFrom,
69 					uno_Environment * pInterm,
70 					uno_Environment * pTo);
71 	~MediatorMapping();
72 };
73 
74 extern "C" {
s_acquire(uno_Mapping * mapping)75 static void SAL_CALL s_acquire(uno_Mapping * mapping)
76 {
77 	MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
78 	pMediatorMapping->acquire();
79 }
80 
s_release(uno_Mapping * mapping)81 static void SAL_CALL s_release(uno_Mapping * mapping)
82 {
83 	MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
84 	pMediatorMapping->release();
85 }
86 
s_mapInterface(uno_Mapping * mapping,void ** ppOut,void * pInterface,typelib_InterfaceTypeDescription * pInterfaceTypeDescr)87 static void SAL_CALL s_mapInterface(
88 	uno_Mapping                      * mapping,
89 	void                            ** ppOut,
90 	void                             * pInterface,
91 	typelib_InterfaceTypeDescription * pInterfaceTypeDescr)
92 {
93 	MediatorMapping   * pMediatorMapping  = static_cast<MediatorMapping *>(mapping);
94 	pMediatorMapping->mapInterface(ppOut, pInterface, pInterfaceTypeDescr);
95 }
96 }
97 
MediatorMapping(uno_Environment * pFrom,uno_Environment * pInterm,uno_Environment * pTo)98 MediatorMapping::MediatorMapping(uno_Environment * pFrom,
99 								 uno_Environment * pInterm,
100 								 uno_Environment * pTo)
101     : m_refCount(0),
102 	  m_from2uno(pFrom, pInterm),
103 	  m_uno2to  (pInterm, pTo),
104 	  m_from    (pFrom),
105 	  m_interm  (pInterm),
106 	  m_to      (pTo)
107 {
108 	LOG_LIFECYLE_MediatorMapping_emit(std::cerr << __FUNCTION__ << std::endl);
109 
110 	if (!m_from2uno.get() || !m_uno2to.get())
111 		abort();
112 
113 	uno_Mapping::acquire      = s_acquire;
114 	uno_Mapping::release      = s_release;
115 	uno_Mapping::mapInterface = s_mapInterface;
116 }
117 
~MediatorMapping()118 MediatorMapping::~MediatorMapping()
119 {
120 	LOG_LIFECYLE_MediatorMapping_emit(std::cerr << __FUNCTION__ << std::endl);
121 }
122 
acquire(void)123 void MediatorMapping::acquire(void)
124 {
125 	LOG_LIFECYLE_MediatorMapping_emit(std::cerr << __FUNCTION__ << std::endl);
126 
127 	osl_incrementInterlockedCount(&m_refCount);
128 }
129 
release(void)130 void MediatorMapping::release(void)
131 {
132 	LOG_LIFECYLE_MediatorMapping_emit(std::cerr << __FUNCTION__ << std::endl);
133 
134 	if (osl_decrementInterlockedCount(&m_refCount) == 0)
135 	{
136         ::uno_revokeMapping(this);
137 	}
138 }
139 
s_mapInterface_v(va_list * pParam)140 extern "C" { static void s_mapInterface_v(va_list * pParam)
141 {
142 	void                            ** ppOut               = va_arg(*pParam, void **);
143 	void                             * pInterface          = va_arg(*pParam, void *);
144 	typelib_InterfaceTypeDescription * pInterfaceTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
145 	uno_Mapping                      * pMapping            = va_arg(*pParam, uno_Mapping *);
146 
147 	pMapping->mapInterface(pMapping, ppOut, pInterface, pInterfaceTypeDescr);
148 }}
149 
mapInterface(void ** ppOut,void * pInterface,typelib_InterfaceTypeDescription * pInterfaceTypeDescr)150 void MediatorMapping::mapInterface(
151 	void                            ** ppOut,
152 	void                             * pInterface,
153 	typelib_InterfaceTypeDescription * pInterfaceTypeDescr)
154 {
155 	if (*ppOut != 0)
156 	{
157 		uno_ExtEnvironment * env = m_to.get()->pExtEnv;
158 		OSL_ASSERT( env != 0 );
159 		env->releaseInterface( env, *ppOut );
160 		*ppOut = NULL;
161 	}
162 
163 	void * ret = 0;
164 	uno_Interface * pUnoI = 0;
165 
166 	m_from.invoke(s_mapInterface_v, &pUnoI, pInterface, pInterfaceTypeDescr, m_from2uno.get());
167 
168 	m_uno2to.mapInterface(&ret, pUnoI, pInterfaceTypeDescr);
169 
170 	if (pUnoI)
171 		m_interm.get()->pExtEnv->releaseInterface(m_interm.get()->pExtEnv, pUnoI);
172 
173 	*ppOut = ret;
174 }
175 
s_MediatorMapping_free(uno_Mapping * pMapping)176 extern "C" { static void SAL_CALL s_MediatorMapping_free(uno_Mapping * pMapping)
177     SAL_THROW_EXTERN_C()
178 {
179     delete static_cast<MediatorMapping *>(pMapping);
180 }}
181 
182 
183 
getPrefix(rtl::OUString const & str1,rtl::OUString const & str2)184 static rtl::OUString getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
185 {
186 	sal_Int32 nIndex1 = 0;
187 	sal_Int32 nIndex2 = 0;
188 	sal_Int32 sim = 0;
189 
190 	rtl::OUString token1;
191 	rtl::OUString token2;
192 
193 	do
194 	{
195 		token1 = str1.getToken(0, ':', nIndex1);
196 		token2 = str2.getToken(0, ':', nIndex2);
197 
198 		if (token1.equals(token2))
199 			sim += token1.getLength() + 1;
200 	}
201 	while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));
202 
203 	rtl::OUString result;
204 
205 	if (sim)
206 		result = str1.copy(0, sim - 1);
207 
208 	return result;
209 }
210 
211 // 	rtl::OUString str1(RTL_CONSTASCII_USTRINGPARAM("abc:def:ghi"));
212 // 	rtl::OUString str2(RTL_CONSTASCII_USTRINGPARAM("abc:def"));
213 // 	rtl::OUString str3(RTL_CONSTASCII_USTRINGPARAM("abc"));
214 // 	rtl::OUString str4(RTL_CONSTASCII_USTRINGPARAM(""));
215 
216 // 	rtl::OUString pref;
217 
218 // 	pref = getPrefix(str1, str1);
219 // 	pref = getPrefix(str1, str2);
220 // 	pref = getPrefix(str1, str3);
221 // 	pref = getPrefix(str1, str4);
222 
223 // 	pref = getPrefix(str2, str1);
224 // 	pref = getPrefix(str3, str1);
225 // 	pref = getPrefix(str4, str1);
226 
227 
getCascadeMapping(uno_Mapping ** ppMapping,uno_Environment * pFrom,uno_Environment * pTo,rtl_uString * pAddPurpose)228 void getCascadeMapping(uno_Mapping     ** ppMapping,
229 					   uno_Environment  * pFrom,
230 					   uno_Environment  * pTo,
231 					   rtl_uString      * pAddPurpose)
232 {
233 	if (pAddPurpose && pAddPurpose->length)
234 		return;
235 
236 	rtl::OUString uno_envType(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO));
237 
238 	rtl::OUString from_envType    = cppu::EnvDcp::getTypeName(pFrom->pTypeName);
239 	rtl::OUString to_envType      = cppu::EnvDcp::getTypeName(pTo->pTypeName);
240 	rtl::OUString from_envPurpose = cppu::EnvDcp::getPurpose(pFrom->pTypeName);
241 	rtl::OUString to_envPurpose   = cppu::EnvDcp::getPurpose(pTo->pTypeName);
242 
243 #ifdef LOG_CALLING_named_purpose_getMapping
244 	rtl::OString s_from_name = rtl::OUStringToOString(pFrom->pTypeName, RTL_TEXTENCODING_ASCII_US);
245 	rtl::OString s_to_name   = rtl::OUStringToOString(pTo->pTypeName,   RTL_TEXTENCODING_ASCII_US);
246 
247 	std::cerr << __FUNCTION__ << " - creating mediation ";
248 	std::cerr << "pFrom: " << s_from_name.getStr();
249 	std::cerr <<" pTo: "   << s_to_name.getStr() << std::endl;
250 #endif
251 
252 	if (from_envPurpose == to_envPurpose) // gcc:bla => uno:bla
253 		return;
254 
255 	// reaching this point means, we need a mediated mapping!!!
256 	// we generall mediate via uno[:free]
257 	uno_Environment * pInterm = NULL;
258 
259 	// chained uno -> uno
260 	if (from_envType == uno_envType && to_envType == uno_envType)
261 	{
262 		rtl::OUString purpose = getPrefix(from_envPurpose, to_envPurpose);
263 
264 		rtl::OUString uno_envDcp = uno_envType;
265 		uno_envDcp += purpose;
266 
267 		// direct mapping possible?
268 		// uno:bla-->uno:bla:blubb
269 		if (from_envPurpose.equals(purpose))
270 		{
271 			rtl::OUString rest = to_envPurpose.copy(purpose.getLength());
272 
273 			sal_Int32 index = rest.indexOf(':', 1);
274 			if (index == -1)
275 			{
276 				uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData);
277 				return;
278 			}
279 
280 			uno_envDcp += rest.copy(0, index);
281 		}
282 		else if (to_envPurpose.equals(purpose))
283 		{
284 			rtl::OUString rest = from_envPurpose.copy(purpose.getLength());
285 
286 			sal_Int32 index = rest.indexOf(':', 1);
287 			if (index == -1)
288 			{
289 				uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData);
290 				return;
291 			}
292 
293 			uno_envDcp += rest.copy(0, index);
294 		}
295 
296 		uno_getEnvironment(&pInterm, uno_envDcp.pData, NULL);
297 	}
298 	else if (from_envType != uno_envType && to_envType == uno_envType) // <ANY> -> UNO ?
299 		// mediate via uno:purpose(fromEnv)
300 	{
301 		rtl::OUString     envDcp = uno_envType;
302 
303 		envDcp += from_envPurpose;
304  		uno_getEnvironment(&pInterm, envDcp.pData, NULL);
305 	}
306 	else if (from_envType == uno_envType && to_envType != uno_envType) // UNO -> <ANY>?
307 		// mediate via uno(context)
308 	{
309 		rtl::OUString     envDcp = uno_envType;
310 
311  		envDcp += to_envPurpose;
312 		uno_getEnvironment(&pInterm, envDcp.pData, NULL);
313 	}
314 	else // everything else
315 		// mediate via uno:purpose
316 	{
317 		rtl::OUString purpose = getPrefix(from_envPurpose, to_envPurpose);
318 
319 		rtl::OUString uno_envDcp = uno_envType;
320 		uno_envDcp += purpose;
321 
322 		uno_getEnvironment(&pInterm, uno_envDcp.pData, NULL);
323 	}
324 
325 	uno_Mapping * pMapping = new MediatorMapping(pFrom, pInterm, pTo);
326 	pInterm->release(pInterm);
327 
328 
329 	pMapping->acquire(pMapping);
330 
331 	::uno_registerMapping(&pMapping, s_MediatorMapping_free, pFrom, pTo, pAddPurpose);
332 
333 	if (*ppMapping)
334 		(*ppMapping)->release(*ppMapping);
335 
336 	*ppMapping = pMapping;
337 }
338