/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ #include "osl/interlck.h" #include "rtl/ustring.hxx" #include "uno/environment.hxx" #include "uno/mapping.hxx" #include "uno/dispatcher.h" #include "cppu/EnvDcp.hxx" #ifdef LOG_LIFECYLE_MediatorMapping # include # 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(mapping); pMediatorMapping->acquire(); } static void SAL_CALL s_release(uno_Mapping * mapping) { MediatorMapping * pMediatorMapping = static_cast(mapping); pMediatorMapping->release(); } static void SAL_CALL s_mapInterface( uno_Mapping * mapping, void ** ppOut, void * pInterface, typelib_InterfaceTypeDescription * pInterfaceTypeDescr) { MediatorMapping * pMediatorMapping = static_cast(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(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) // -> 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 -> ? // 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; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */