diff options
Diffstat (limited to 'cppu/source/uno/cascade_mapping.cxx')
-rw-r--r-- | cppu/source/uno/cascade_mapping.cxx | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/cppu/source/uno/cascade_mapping.cxx b/cppu/source/uno/cascade_mapping.cxx new file mode 100644 index 000000000000..ee870a52e286 --- /dev/null +++ b/cppu/source/uno/cascade_mapping.cxx @@ -0,0 +1,341 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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; +} |