/src/libreoffice/cppu/source/uno/cascade_mapping.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <osl/interlck.h> |
21 | | #include <rtl/ustring.hxx> |
22 | | #include <uno/environment.hxx> |
23 | | #include <uno/lbnames.h> |
24 | | #include <uno/mapping.hxx> |
25 | | #include <uno/dispatcher.h> |
26 | | #include <o3tl/string_view.hxx> |
27 | | |
28 | | #include <cppu/EnvDcp.hxx> |
29 | | |
30 | | #include "cascade_mapping.hxx" |
31 | | |
32 | | using namespace com::sun::star; |
33 | | |
34 | | namespace { |
35 | | |
36 | | class MediatorMapping : public uno_Mapping |
37 | | { |
38 | | oslInterlockedCount m_refCount; |
39 | | |
40 | | uno::Mapping m_from2uno; |
41 | | uno::Mapping m_uno2to; |
42 | | |
43 | | uno::Environment m_from; |
44 | | uno::Environment m_interm; |
45 | | uno::Environment m_to; |
46 | | |
47 | | public: |
48 | | void acquire(); |
49 | | void release(); |
50 | | |
51 | | void mapInterface(void ** ppOut, |
52 | | void * pInterface, |
53 | | typelib_InterfaceTypeDescription * pInterfaceTypeDescr); |
54 | | MediatorMapping(uno_Environment * pFrom, |
55 | | uno_Environment * pInterm, |
56 | | uno_Environment * pTo); |
57 | | }; |
58 | | |
59 | | } |
60 | | |
61 | | extern "C" { |
62 | | static void s_acquire(uno_Mapping * mapping) |
63 | 0 | { |
64 | 0 | MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping); |
65 | 0 | pMediatorMapping->acquire(); |
66 | 0 | } |
67 | | |
68 | | static void s_release(uno_Mapping * mapping) |
69 | 0 | { |
70 | 0 | MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping); |
71 | 0 | pMediatorMapping->release(); |
72 | 0 | } |
73 | | |
74 | | static void s_mapInterface( |
75 | | uno_Mapping * mapping, |
76 | | void ** ppOut, |
77 | | void * pInterface, |
78 | | typelib_InterfaceTypeDescription * pInterfaceTypeDescr) |
79 | 0 | { |
80 | 0 | MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping); |
81 | 0 | pMediatorMapping->mapInterface(ppOut, pInterface, pInterfaceTypeDescr); |
82 | 0 | } |
83 | | } |
84 | | |
85 | | MediatorMapping::MediatorMapping(uno_Environment * pFrom, |
86 | | uno_Environment * pInterm, |
87 | | uno_Environment * pTo) |
88 | 0 | : m_refCount(0), |
89 | 0 | m_from2uno(pFrom, pInterm), |
90 | 0 | m_uno2to (pInterm, pTo), |
91 | 0 | m_from (pFrom), |
92 | 0 | m_interm (pInterm), |
93 | 0 | m_to (pTo) |
94 | 0 | { |
95 | 0 | if (!m_from2uno.get() || !m_uno2to.get()) |
96 | 0 | abort(); |
97 | | |
98 | 0 | uno_Mapping::acquire = s_acquire; |
99 | 0 | uno_Mapping::release = s_release; |
100 | 0 | uno_Mapping::mapInterface = s_mapInterface; |
101 | 0 | } |
102 | | |
103 | | void MediatorMapping::acquire() |
104 | 0 | { |
105 | 0 | osl_atomic_increment(&m_refCount); |
106 | 0 | } |
107 | | |
108 | | void MediatorMapping::release() |
109 | 0 | { |
110 | 0 | if (osl_atomic_decrement(&m_refCount) == 0) |
111 | 0 | { |
112 | 0 | ::uno_revokeMapping(this); |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | | extern "C" { static void s_mapInterface_v(va_list * pParam) |
117 | 0 | { |
118 | 0 | void ** ppOut = va_arg(*pParam, void **); |
119 | 0 | void * pInterface = va_arg(*pParam, void *); |
120 | 0 | typelib_InterfaceTypeDescription * pInterfaceTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *); |
121 | 0 | uno_Mapping * pMapping = va_arg(*pParam, uno_Mapping *); |
122 | |
|
123 | 0 | pMapping->mapInterface(pMapping, ppOut, pInterface, pInterfaceTypeDescr); |
124 | 0 | }} |
125 | | |
126 | | void MediatorMapping::mapInterface( |
127 | | void ** ppOut, |
128 | | void * pInterface, |
129 | | typelib_InterfaceTypeDescription * pInterfaceTypeDescr) |
130 | 0 | { |
131 | 0 | if (*ppOut != nullptr) |
132 | 0 | { |
133 | 0 | uno_ExtEnvironment * env = m_to.get()->pExtEnv; |
134 | 0 | assert(env != nullptr); |
135 | 0 | env->releaseInterface( env, *ppOut ); |
136 | 0 | *ppOut = nullptr; |
137 | 0 | } |
138 | |
|
139 | 0 | void * ret = nullptr; |
140 | 0 | uno_Interface * pUnoI = nullptr; |
141 | |
|
142 | 0 | m_from.invoke(s_mapInterface_v, &pUnoI, pInterface, pInterfaceTypeDescr, m_from2uno.get()); |
143 | |
|
144 | 0 | m_uno2to.mapInterface(&ret, pUnoI, pInterfaceTypeDescr); |
145 | |
|
146 | 0 | if (pUnoI) |
147 | 0 | m_interm.get()->pExtEnv->releaseInterface(m_interm.get()->pExtEnv, pUnoI); |
148 | |
|
149 | 0 | *ppOut = ret; |
150 | 0 | } |
151 | | |
152 | | extern "C" { static void s_MediatorMapping_free(uno_Mapping * pMapping) noexcept |
153 | 0 | { |
154 | 0 | delete static_cast<MediatorMapping *>(pMapping); |
155 | 0 | }} |
156 | | |
157 | | |
158 | | static OUString getPrefix(std::u16string_view str1, std::u16string_view str2) |
159 | 0 | { |
160 | 0 | sal_Int32 nIndex1 = 0; |
161 | 0 | sal_Int32 nIndex2 = 0; |
162 | 0 | sal_Int32 sim = 0; |
163 | |
|
164 | 0 | std::u16string_view token1; |
165 | 0 | std::u16string_view token2; |
166 | |
|
167 | 0 | do |
168 | 0 | { |
169 | 0 | token1 = o3tl::getToken(str1, 0, ':', nIndex1); |
170 | 0 | token2 = o3tl::getToken(str2, 0, ':', nIndex2); |
171 | |
|
172 | 0 | if (token1 == token2) |
173 | 0 | sim += token1.size() + 1; |
174 | 0 | } |
175 | 0 | while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1 == token2); |
176 | |
|
177 | 0 | OUString result; |
178 | |
|
179 | 0 | if (sim) |
180 | 0 | result = str1.substr(0, sim - 1); |
181 | |
|
182 | 0 | return result; |
183 | 0 | } |
184 | | |
185 | | // OUString str1("abc:def:ghi"); |
186 | | // OUString str2("abc:def"); |
187 | | // OUString str3("abc"); |
188 | | // OUString str4(""); |
189 | | |
190 | | // OUString pref; |
191 | | |
192 | | // pref = getPrefix(str1, str1); |
193 | | // pref = getPrefix(str1, str2); |
194 | | // pref = getPrefix(str1, str3); |
195 | | // pref = getPrefix(str1, str4); |
196 | | |
197 | | // pref = getPrefix(str2, str1); |
198 | | // pref = getPrefix(str3, str1); |
199 | | // pref = getPrefix(str4, str1); |
200 | | |
201 | | |
202 | | void getCascadeMapping(uno_Mapping ** ppMapping, |
203 | | uno_Environment * pFrom, |
204 | | uno_Environment * pTo, |
205 | | rtl_uString * pAddPurpose) |
206 | 136k | { |
207 | 136k | if (pAddPurpose && pAddPurpose->length) |
208 | 0 | return; |
209 | | |
210 | 136k | OUString uno_envType(u"" UNO_LB_UNO ""_ustr); |
211 | | |
212 | 136k | OUString from_envType = cppu::EnvDcp::getTypeName(pFrom->pTypeName); |
213 | 136k | OUString to_envType = cppu::EnvDcp::getTypeName(pTo->pTypeName); |
214 | 136k | OUString from_envPurpose = cppu::EnvDcp::getPurpose(pFrom->pTypeName); |
215 | 136k | OUString to_envPurpose = cppu::EnvDcp::getPurpose(pTo->pTypeName); |
216 | | |
217 | | #ifdef LOG_CALLING_named_purpose_getMapping |
218 | | OString s_from_name = OUStringToOString(pFrom->pTypeName, RTL_TEXTENCODING_ASCII_US); |
219 | | OString s_to_name = OUStringToOString(pTo->pTypeName, RTL_TEXTENCODING_ASCII_US); |
220 | | |
221 | | std::cerr << __FUNCTION__ << " - creating mediation "; |
222 | | std::cerr << "pFrom: " << s_from_name.getStr(); |
223 | | std::cerr <<" pTo: " << s_to_name.getStr() << std::endl; |
224 | | #endif |
225 | | |
226 | 136k | if (from_envPurpose == to_envPurpose) // gcc:bla => uno:bla |
227 | 136k | return; |
228 | | |
229 | | // reaching this point means, we need a mediated mapping!!! |
230 | | // we generally mediate via uno[:free] |
231 | 0 | uno_Environment * pInterm = nullptr; |
232 | | |
233 | | // chained uno -> uno |
234 | 0 | if (from_envType == uno_envType && to_envType == uno_envType) |
235 | 0 | { |
236 | 0 | OUString purpose = getPrefix(from_envPurpose, to_envPurpose); |
237 | |
|
238 | 0 | OUString uno_envDcp = uno_envType + purpose; |
239 | | |
240 | | // direct mapping possible? |
241 | | // uno:bla-->uno:bla:blubb |
242 | 0 | if (from_envPurpose == purpose) |
243 | 0 | { |
244 | 0 | OUString rest = to_envPurpose.copy(purpose.getLength()); |
245 | |
|
246 | 0 | sal_Int32 index = rest.indexOf(':', 1); |
247 | 0 | if (index == -1) |
248 | 0 | { |
249 | 0 | uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData); |
250 | 0 | return; |
251 | 0 | } |
252 | | |
253 | 0 | uno_envDcp += rest.subView(0, index); |
254 | 0 | } |
255 | 0 | else if (to_envPurpose == purpose) |
256 | 0 | { |
257 | 0 | OUString rest = from_envPurpose.copy(purpose.getLength()); |
258 | |
|
259 | 0 | sal_Int32 index = rest.indexOf(':', 1); |
260 | 0 | if (index == -1) |
261 | 0 | { |
262 | 0 | uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData); |
263 | 0 | return; |
264 | 0 | } |
265 | | |
266 | 0 | uno_envDcp += rest.subView(0, index); |
267 | 0 | } |
268 | | |
269 | 0 | uno_getEnvironment(&pInterm, uno_envDcp.pData, nullptr); |
270 | 0 | } |
271 | 0 | else if (from_envType != uno_envType && to_envType == uno_envType) // <ANY> -> UNO ? |
272 | | // mediate via uno:purpose(fromEnv) |
273 | 0 | { |
274 | 0 | OUString envDcp = uno_envType + from_envPurpose; |
275 | 0 | uno_getEnvironment(&pInterm, envDcp.pData, nullptr); |
276 | 0 | } |
277 | 0 | else if (from_envType == uno_envType && to_envType != uno_envType) // UNO -> <ANY>? |
278 | | // mediate via uno(context) |
279 | 0 | { |
280 | 0 | OUString envDcp = uno_envType + to_envPurpose; |
281 | 0 | uno_getEnvironment(&pInterm, envDcp.pData, nullptr); |
282 | 0 | } |
283 | 0 | else // everything else |
284 | | // mediate via uno:purpose |
285 | 0 | { |
286 | 0 | OUString purpose = getPrefix(from_envPurpose, to_envPurpose); |
287 | |
|
288 | 0 | OUString uno_envDcp = uno_envType + purpose; |
289 | |
|
290 | 0 | uno_getEnvironment(&pInterm, uno_envDcp.pData, nullptr); |
291 | 0 | } |
292 | | |
293 | 0 | uno_Mapping * pMapping = new MediatorMapping(pFrom, pInterm, pTo); |
294 | 0 | pInterm->release(pInterm); |
295 | | |
296 | |
|
297 | 0 | pMapping->acquire(pMapping); |
298 | |
|
299 | 0 | ::uno_registerMapping(&pMapping, s_MediatorMapping_free, pFrom, pTo, pAddPurpose); |
300 | |
|
301 | 0 | if (*ppMapping) |
302 | 0 | (*ppMapping)->release(*ppMapping); |
303 | |
|
304 | 0 | *ppMapping = pMapping; |
305 | 0 | } |
306 | | |
307 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |