blob: 8e05b76ca2c6712722387b2d20eb6db099e75e8e [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include <iostream>
#include "osl/interlck.h"
#include "rtl/ustring.hxx"
#include "uno/environment.hxx"
#include "uno/mapping.hxx"
#include "uno/dispatcher.h"
//#include "cascade_mappping.hxx"
#include "cppu/EnvDcp.hxx"
//#define LOG_CALLING_named_purpose_getMapping
//#define LOG_LIFECYLE_MediatorMapping
#ifdef LOG_LIFECYLE_MediatorMapping
# define LOG_LIFECYLE_MediatorMapping_emit(x) x
#else
# define LOG_LIFECYLE_MediatorMapping_emit(x)
#endif
using namespace com::sun::star;
class MediatorMapping : public uno_Mapping
{
oslInterlockedCount m_refCount;
uno::Mapping m_from2uno;
uno::Mapping m_uno2to;
uno::Environment m_from;
uno::Environment m_interm;
uno::Environment m_to;
public:
void acquire(void);
void release(void);
void mapInterface(void ** ppOut,
void * pInterface,
typelib_InterfaceTypeDescription * pInterfaceTypeDescr);
MediatorMapping(uno_Environment * pFrom,
uno_Environment * pInterm,
uno_Environment * pTo);
~MediatorMapping();
};
extern "C" {
static void SAL_CALL s_acquire(uno_Mapping * mapping)
{
MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
pMediatorMapping->acquire();
}
static void SAL_CALL s_release(uno_Mapping * mapping)
{
MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
pMediatorMapping->release();
}
static void SAL_CALL s_mapInterface(
uno_Mapping * mapping,
void ** ppOut,
void * pInterface,
typelib_InterfaceTypeDescription * pInterfaceTypeDescr)
{
MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
pMediatorMapping->mapInterface(ppOut, pInterface, pInterfaceTypeDescr);
}
}
MediatorMapping::MediatorMapping(uno_Environment * pFrom,
uno_Environment * pInterm,
uno_Environment * pTo)
: m_refCount(0),
m_from2uno(pFrom, pInterm),
m_uno2to (pInterm, pTo),
m_from (pFrom),
m_interm (pInterm),
m_to (pTo)
{
LOG_LIFECYLE_MediatorMapping_emit(std::cerr << __FUNCTION__ << std::endl);
if (!m_from2uno.get() || !m_uno2to.get())
abort();
uno_Mapping::acquire = s_acquire;
uno_Mapping::release = s_release;
uno_Mapping::mapInterface = s_mapInterface;
}
MediatorMapping::~MediatorMapping()
{
LOG_LIFECYLE_MediatorMapping_emit(std::cerr << __FUNCTION__ << std::endl);
}
void MediatorMapping::acquire(void)
{
LOG_LIFECYLE_MediatorMapping_emit(std::cerr << __FUNCTION__ << std::endl);
osl_incrementInterlockedCount(&m_refCount);
}
void MediatorMapping::release(void)
{
LOG_LIFECYLE_MediatorMapping_emit(std::cerr << __FUNCTION__ << std::endl);
if (osl_decrementInterlockedCount(&m_refCount) == 0)
{
::uno_revokeMapping(this);
}
}
extern "C" { static void s_mapInterface_v(va_list * pParam)
{
void ** ppOut = va_arg(*pParam, void **);
void * pInterface = va_arg(*pParam, void *);
typelib_InterfaceTypeDescription * pInterfaceTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
uno_Mapping * pMapping = va_arg(*pParam, uno_Mapping *);
pMapping->mapInterface(pMapping, ppOut, pInterface, pInterfaceTypeDescr);
}}
void MediatorMapping::mapInterface(
void ** ppOut,
void * pInterface,
typelib_InterfaceTypeDescription * pInterfaceTypeDescr)
{
if (*ppOut != 0)
{
uno_ExtEnvironment * env = m_to.get()->pExtEnv;
OSL_ASSERT( env != 0 );
env->releaseInterface( env, *ppOut );
*ppOut = NULL;
}
void * ret = 0;
uno_Interface * pUnoI = 0;
m_from.invoke(s_mapInterface_v, &pUnoI, pInterface, pInterfaceTypeDescr, m_from2uno.get());
m_uno2to.mapInterface(&ret, pUnoI, pInterfaceTypeDescr);
if (pUnoI)
m_interm.get()->pExtEnv->releaseInterface(m_interm.get()->pExtEnv, pUnoI);
*ppOut = ret;
}
extern "C" { static void SAL_CALL s_MediatorMapping_free(uno_Mapping * pMapping)
SAL_THROW_EXTERN_C()
{
delete static_cast<MediatorMapping *>(pMapping);
}}
static rtl::OUString getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
{
sal_Int32 nIndex1 = 0;
sal_Int32 nIndex2 = 0;
sal_Int32 sim = 0;
rtl::OUString token1;
rtl::OUString token2;
do
{
token1 = str1.getToken(0, ':', nIndex1);
token2 = str2.getToken(0, ':', nIndex2);
if (token1.equals(token2))
sim += token1.getLength() + 1;
}
while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));
rtl::OUString result;
if (sim)
result = str1.copy(0, sim - 1);
return result;
}
// rtl::OUString str1(RTL_CONSTASCII_USTRINGPARAM("abc:def:ghi"));
// rtl::OUString str2(RTL_CONSTASCII_USTRINGPARAM("abc:def"));
// rtl::OUString str3(RTL_CONSTASCII_USTRINGPARAM("abc"));
// rtl::OUString str4(RTL_CONSTASCII_USTRINGPARAM(""));
// rtl::OUString pref;
// pref = getPrefix(str1, str1);
// pref = getPrefix(str1, str2);
// pref = getPrefix(str1, str3);
// pref = getPrefix(str1, str4);
// pref = getPrefix(str2, str1);
// pref = getPrefix(str3, str1);
// pref = getPrefix(str4, str1);
void getCascadeMapping(uno_Mapping ** ppMapping,
uno_Environment * pFrom,
uno_Environment * pTo,
rtl_uString * pAddPurpose)
{
if (pAddPurpose && pAddPurpose->length)
return;
rtl::OUString uno_envType(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO));
rtl::OUString from_envType = cppu::EnvDcp::getTypeName(pFrom->pTypeName);
rtl::OUString to_envType = cppu::EnvDcp::getTypeName(pTo->pTypeName);
rtl::OUString from_envPurpose = cppu::EnvDcp::getPurpose(pFrom->pTypeName);
rtl::OUString to_envPurpose = cppu::EnvDcp::getPurpose(pTo->pTypeName);
#ifdef LOG_CALLING_named_purpose_getMapping
rtl::OString s_from_name = rtl::OUStringToOString(pFrom->pTypeName, RTL_TEXTENCODING_ASCII_US);
rtl::OString s_to_name = rtl::OUStringToOString(pTo->pTypeName, RTL_TEXTENCODING_ASCII_US);
std::cerr << __FUNCTION__ << " - creating mediation ";
std::cerr << "pFrom: " << s_from_name.getStr();
std::cerr <<" pTo: " << s_to_name.getStr() << std::endl;
#endif
if (from_envPurpose == to_envPurpose) // gcc:bla => uno:bla
return;
// reaching this point means, we need a mediated mapping!!!
// we generall mediate via uno[:free]
uno_Environment * pInterm = NULL;
// chained uno -> uno
if (from_envType == uno_envType && to_envType == uno_envType)
{
rtl::OUString purpose = getPrefix(from_envPurpose, to_envPurpose);
rtl::OUString uno_envDcp = uno_envType;
uno_envDcp += purpose;
// direct mapping possible?
// uno:bla-->uno:bla:blubb
if (from_envPurpose.equals(purpose))
{
rtl::OUString rest = to_envPurpose.copy(purpose.getLength());
sal_Int32 index = rest.indexOf(':', 1);
if (index == -1)
{
uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData);
return;
}
uno_envDcp += rest.copy(0, index);
}
else if (to_envPurpose.equals(purpose))
{
rtl::OUString rest = from_envPurpose.copy(purpose.getLength());
sal_Int32 index = rest.indexOf(':', 1);
if (index == -1)
{
uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData);
return;
}
uno_envDcp += rest.copy(0, index);
}
uno_getEnvironment(&pInterm, uno_envDcp.pData, NULL);
}
else if (from_envType != uno_envType && to_envType == uno_envType) // <ANY> -> UNO ?
// mediate via uno:purpose(fromEnv)
{
rtl::OUString envDcp = uno_envType;
envDcp += from_envPurpose;
uno_getEnvironment(&pInterm, envDcp.pData, NULL);
}
else if (from_envType == uno_envType && to_envType != uno_envType) // UNO -> <ANY>?
// mediate via uno(context)
{
rtl::OUString envDcp = uno_envType;
envDcp += to_envPurpose;
uno_getEnvironment(&pInterm, envDcp.pData, NULL);
}
else // everything else
// mediate via uno:purpose
{
rtl::OUString purpose = getPrefix(from_envPurpose, to_envPurpose);
rtl::OUString uno_envDcp = uno_envType;
uno_envDcp += purpose;
uno_getEnvironment(&pInterm, uno_envDcp.pData, NULL);
}
uno_Mapping * pMapping = new MediatorMapping(pFrom, pInterm, pTo);
pInterm->release(pInterm);
pMapping->acquire(pMapping);
::uno_registerMapping(&pMapping, s_MediatorMapping_free, pFrom, pTo, pAddPurpose);
if (*ppMapping)
(*ppMapping)->release(*ppMapping);
*ppMapping = pMapping;
}