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 
21 #include <cppu/helper/purpenv/Mapping.hxx>
22 
23 #include "Proxy.hxx"
24 
25 #include <osl/interlck.h>
26 #include <sal/log.hxx>
27 #include <uno/environment.hxx>
28 #include <uno/dispatcher.h>
29 
30 using namespace com::sun::star;
31 
32 class Mapping : public uno_Mapping
33 {
34     uno::Environment   m_from;
35     uno::Environment   m_to;
36 
37     oslInterlockedCount m_nCount;
38 
39     cppu::helper::purpenv::ProbeFun * m_probeFun;
40     void                            * m_pContext;
41 
42 public:
43     explicit  Mapping(uno_Environment                 * pFrom,
44                       uno_Environment                 * pTo,
45                       cppu::helper::purpenv::ProbeFun * probeFun,
46                       void                            * pProbeContext);
47     virtual  ~Mapping();
48 
49     void mapInterface(
50         uno_Interface                    ** ppOut,
51         uno_Interface                     * pUnoI,
52         typelib_InterfaceTypeDescription  * pTypeDescr);
53 
54     void acquire();
55     void release();
56 };
57 
s_mapInterface(uno_Mapping * puno_Mapping,void ** ppOut,void * pUnoI,typelib_InterfaceTypeDescription * pTypeDescr)58 static void s_mapInterface(
59     uno_Mapping                       * puno_Mapping,
60     void                             ** ppOut,
61     void                              * pUnoI,
62     typelib_InterfaceTypeDescription  * pTypeDescr )
63     SAL_THROW_EXTERN_C()
64 {
65     Mapping * pMapping = static_cast<Mapping *>(puno_Mapping);
66     pMapping->mapInterface(
67         reinterpret_cast<uno_Interface **>(ppOut),
68         static_cast<uno_Interface *>(pUnoI), pTypeDescr);
69 }
70 
71 extern "C" {
s_acquire(uno_Mapping * puno_Mapping)72 static void s_acquire(uno_Mapping * puno_Mapping)
73     SAL_THROW_EXTERN_C()
74 {
75     Mapping * pMapping = static_cast<Mapping *>(puno_Mapping);
76     pMapping->acquire();
77 }
78 
s_release(uno_Mapping * puno_Mapping)79 static void s_release(uno_Mapping * puno_Mapping)
80     SAL_THROW_EXTERN_C()
81 {
82     Mapping * pMapping = static_cast<Mapping * >(puno_Mapping);
83     pMapping->release();
84 }
85 
86 
s_getIdentifier_v(va_list * pParam)87 static void s_getIdentifier_v(va_list * pParam)
88 {
89     uno_ExtEnvironment *  pEnv  = va_arg(*pParam, uno_ExtEnvironment *);
90     rtl_uString        ** ppOid = va_arg(*pParam, rtl_uString **);
91     uno_Interface      *  pUnoI = va_arg(*pParam, uno_Interface *);
92 
93     pEnv->getObjectIdentifier(pEnv, ppOid, pUnoI);
94 }
95 
s_free(uno_Mapping * puno_Mapping)96 static void s_free(uno_Mapping * puno_Mapping)
97     SAL_THROW_EXTERN_C()
98 {
99     Mapping * pMapping = static_cast<Mapping *>(puno_Mapping);
100     delete pMapping;
101 }
102 }
103 
Mapping(uno_Environment * pFrom,uno_Environment * pTo,cppu::helper::purpenv::ProbeFun * probeFun,void * pProbeContext)104 Mapping::Mapping(uno_Environment                 * pFrom,
105                  uno_Environment                 * pTo,
106                  cppu::helper::purpenv::ProbeFun * probeFun,
107                  void                            * pProbeContext
108 )
109     : m_from    (pFrom),
110       m_to      (pTo),
111       m_nCount  (1),
112       m_probeFun(probeFun),
113       m_pContext(pProbeContext)
114 {
115     SAL_INFO("cppu.purpenv", "LIFE: Mapping::Mapping(uno_Environment * pFrom, uno_Environment * pTo -> " << this);
116 
117     uno_Mapping::acquire      = s_acquire;
118     uno_Mapping::release      = s_release;
119     uno_Mapping::mapInterface = s_mapInterface;
120 }
121 
~Mapping()122 Mapping::~Mapping()
123 {
124     SAL_INFO("cppu.purpenv", "LIFE: Mapping:~Mapping() -> " << this);
125 }
126 
127 
mapInterface(uno_Interface ** ppOut,uno_Interface * pUnoI,typelib_InterfaceTypeDescription * pTypeDescr)128 void Mapping::mapInterface(
129     uno_Interface                    ** ppOut,
130     uno_Interface                     * pUnoI,
131     typelib_InterfaceTypeDescription  * pTypeDescr)
132 {
133     OSL_ASSERT(ppOut && pTypeDescr);
134     if (*ppOut)
135     {
136         (*ppOut)->release(*ppOut);
137         *ppOut = nullptr;
138     }
139 
140     if (!pUnoI)
141         return;
142 
143     // get object id of uno interface to be wrapped
144     // need to enter environment because of potential "queryInterface" call
145     rtl_uString * pOId = nullptr;
146     uno_Environment_invoke(m_from.get(), s_getIdentifier_v, m_from.get(), &pOId, pUnoI);
147     OSL_ASSERT(pOId);
148 
149      // try to get any known interface from target environment
150     m_to.get()->pExtEnv->getRegisteredInterface(m_to.get()->pExtEnv, reinterpret_cast<void **>(ppOut), pOId, pTypeDescr);
151 
152     if (!*ppOut) // not yet there, register new proxy interface
153     {
154         // try to publish a new proxy (ref count initially 1)
155         uno_Interface * pProxy = new Proxy(this,
156                                            m_from.get(),
157                                            m_to.get(),
158                                            pUnoI,
159                                            pTypeDescr,
160                                            pOId,
161                                            m_probeFun,
162                                            m_pContext);
163 
164         // proxy may be exchanged during registration
165         m_to.get()->pExtEnv->registerProxyInterface(m_to.get()->pExtEnv,
166                                                     reinterpret_cast<void **>(&pProxy),
167                                                     Proxy_free,
168                                                     pOId,
169                                                     pTypeDescr);
170 
171         *ppOut = pProxy;
172     }
173 
174     rtl_uString_release(pOId);
175 }
176 
177 
acquire()178 void Mapping::acquire()
179 {
180     if (osl_atomic_increment(&m_nCount) == 1)
181     {
182         uno_Mapping * pMapping = this;
183 
184         ::uno_registerMapping(&pMapping, s_free, m_from.get(), m_to.get(), nullptr);
185     }
186 }
187 
release()188 void Mapping::release()
189 {
190     if (osl_atomic_decrement(&m_nCount) == 0)
191         ::uno_revokeMapping(this);
192 }
193 
194 
195 namespace cppu { namespace helper { namespace purpenv {
196 
createMapping(uno_Mapping ** ppMapping,uno_Environment * pFrom,uno_Environment * pTo,ProbeFun * probeFun,void * pContext)197 void createMapping(uno_Mapping     ** ppMapping,
198                    uno_Environment  * pFrom,
199                    uno_Environment  * pTo,
200                    ProbeFun         * probeFun,
201                    void             * pContext
202  )
203 {
204     *ppMapping = new Mapping(pFrom, pTo, probeFun, pContext);
205 
206     ::uno_registerMapping(ppMapping, s_free, pFrom, pTo, nullptr);
207 }
208 
209 }}}
210 
211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
212