/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include "loadsharedlibcomponentfactory.hxx" #if defined DISABLE_DYNLOADING #include #endif css::uno::Environment cppuhelper::detail::getEnvironment( rtl::OUString const & name, rtl::OUString const & implementation) { rtl::OUString n(name); if (!implementation.isEmpty()) { static char const * log = std::getenv("UNO_ENV_LOG"); if (log != nullptr && *log != 0) { rtl::OString imps(log); for (sal_Int32 i = 0; i != -1;) { rtl::OString imp(imps.getToken(0, ';', i)); //TODO: this assumes UNO_ENV_LOG only contains ASCII characters: if (implementation.equalsAsciiL(imp.getStr(), imp.getLength())) { n += ":log"; break; } } } } return css::uno::Environment(n); } namespace { #if !defined DISABLE_DYNLOADING css::uno::Environment getEnvironmentFromModule( osl::Module const & module, css::uno::Environment const & target, rtl::OUString const & implementation, rtl::OUString const & prefix) { char const * name = nullptr; css::uno::Environment env; rtl::OUString fullPrefix(prefix); if (!fullPrefix.isEmpty()) { fullPrefix += "_"; } component_getImplementationEnvironmentExtFunc fp1 = reinterpret_cast( module.getFunctionSymbol(fullPrefix + COMPONENT_GETENVEXT)); if (fp1 != nullptr) { (*fp1)( &name, reinterpret_cast(&env), (rtl::OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US) .getStr()), target.get()); } else { component_getImplementationEnvironmentFunc fp2 = reinterpret_cast( module.getFunctionSymbol(fullPrefix + COMPONENT_GETENV)); if (fp2 != nullptr) { (*fp2)(&name, reinterpret_cast(&env)); } else { name = CPPU_CURRENT_LANGUAGE_BINDING_NAME; //TODO: fail } } if (!env.is() && name != nullptr) { env = cppuhelper::detail::getEnvironment( rtl::OUString::createFromAscii(name), implementation); } return env; } #endif extern "C" void getFactory(va_list * args) { component_getFactoryFunc fn = va_arg(*args, component_getFactoryFunc); rtl::OString const * implementation = va_arg(*args, rtl::OString const *); void * smgr = va_arg(*args, void *); void ** factory = va_arg(*args, void **); *factory = (*fn)(implementation->getStr(), smgr, nullptr); } css::uno::Reference invokeComponentFactory( css::uno::Environment const & source, css::uno::Environment const & target, component_getFactoryFunc function, rtl::OUString const & uri, rtl::OUString const & implementation, css::uno::Reference const & serviceManager) { if (!(source.is() && target.is())) { throw css::loader::CannotActivateFactoryException( "cannot get environments", css::uno::Reference()); } rtl::OString impl( rtl::OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US)); if (source.get() == target.get()) { return css::uno::Reference( static_cast( (*function)(impl.getStr(), serviceManager.get(), nullptr)), SAL_NO_ACQUIRE); } css::uno::Mapping mapTo(source, target); css::uno::Mapping mapFrom(target, source); if (!(mapTo.is() && mapFrom.is())) { throw css::loader::CannotActivateFactoryException( "cannot get mappings", css::uno::Reference()); } void * smgr = mapTo.mapInterface( serviceManager.get(), cppu::UnoType::get()); void * factory = nullptr; target.invoke(getFactory, function, &impl, smgr, &factory); if (smgr != nullptr) { (*target.get()->pExtEnv->releaseInterface)( target.get()->pExtEnv, smgr); } if (factory == nullptr) { throw css::loader::CannotActivateFactoryException( ("calling factory function for \"" + implementation + "\" in <" + uri + "> returned null"), css::uno::Reference()); } css::uno::Reference res; mapFrom.mapInterface( reinterpret_cast(&res), factory, cppu::UnoType::get()); (*target.get()->pExtEnv->releaseInterface)( target.get()->pExtEnv, factory); return res; } #if !defined DISABLE_DYNLOADING extern "C" void getInstance(va_list * args) { cppuhelper::ImplementationConstructorFn * fn = va_arg(*args, cppuhelper::ImplementationConstructorFn *); void * ctxt = va_arg(*args, void *); assert(ctxt); void * argseq = va_arg(*args, void *); assert(argseq); void ** instance = va_arg(*args, void **); assert(instance); assert(*instance == nullptr); *instance = (*fn)(static_cast(ctxt), *static_cast const*>(argseq)); } cppuhelper::WrapperConstructorFn mapConstructorFn( css::uno::Environment const & source, css::uno::Environment const & target, cppuhelper::ImplementationConstructorFn *const constructorFunction) { if (!(source.is() && target.is())) { throw css::loader::CannotActivateFactoryException( "cannot get environments", css::uno::Reference()); } if (source.get() == target.get()) { return cppuhelper::WrapperConstructorFn(constructorFunction); } // note: it should be valid to capture these mappings because they are // ref-counted, and the returned closure will always be invoked in the // "source" environment css::uno::Mapping mapTo(source, target); css::uno::Mapping mapFrom(target, source); if (!(mapTo.is() && mapFrom.is())) { throw css::loader::CannotActivateFactoryException( "cannot get mappings", css::uno::Reference()); } return [mapFrom, mapTo, target, constructorFunction] (css::uno::XComponentContext *const context, css::uno::Sequence const& args) { void *const ctxt = mapTo.mapInterface( context, cppu::UnoType::get()); if (args.getLength() > 0) { std::abort(); // TODO map args } void * instance = nullptr; target.invoke(getInstance, constructorFunction, ctxt, &args, &instance); if (ctxt != nullptr) { (*target.get()->pExtEnv->releaseInterface)( target.get()->pExtEnv, ctxt); } css::uno::XInterface * res = nullptr; if (instance == nullptr) { return res; } mapFrom.mapInterface( reinterpret_cast(&res), instance, cppu::UnoType::get()); (*target.get()->pExtEnv->releaseInterface)( target.get()->pExtEnv, instance); return res; }; } #endif } void cppuhelper::detail::loadSharedLibComponentFactory( rtl::OUString const & uri, rtl::OUString const & environment, rtl::OUString const & prefix, rtl::OUString const & implementation, rtl::OUString const & constructor, css::uno::Reference const & serviceManager, WrapperConstructorFn * constructorFunction, css::uno::Reference * factory) { assert(constructor.isEmpty() || !environment.isEmpty()); assert( (constructorFunction == nullptr && constructor.isEmpty()) || !*constructorFunction); assert(factory != nullptr && !factory->is()); #if defined DISABLE_DYNLOADING assert(!environment.isEmpty()); if (constructor.isEmpty()) { css::uno::Environment curEnv(css::uno::Environment::getCurrent()); css::uno::Environment env(getEnvironment(environment, implementation)); if (!(curEnv.is() && env.is())) { throw css::loader::CannotActivateFactoryException( "cannot get environments", css::uno::Reference()); } if (curEnv.get() != env.get()) { std::abort();//TODO } rtl::OUString name(prefix == "direct" ? implementation : uri); SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri); lib_to_factory_mapping const * map = lo_get_factory_map(); component_getFactoryFunc fp = 0; for (int i = 0; map[i].name != 0; ++i) { if (name.equalsAscii(map[i].name)) { fp = map[i].component_getFactory_function; break; } } if (fp == 0) { SAL_WARN("cppuhelper", "unknown factory name \"" << name << "\""); #if defined IOS && !defined SAL_LOG_WARN // If the above SAL_WARN expanded to nothing, print to stderr... fprintf(stderr, "Unknown factory name %s\n", OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr()); #endif throw css::loader::CannotActivateFactoryException( "unknown factory name \"" + name + "\"", css::uno::Reference()); } *factory = invokeComponentFactory( css::uno::Environment::getCurrent(), getEnvironment(environment, implementation), fp, uri, implementation, serviceManager); } else { SAL_INFO("cppuhelper.shlib", "constructor=" << constructor); lib_to_constructor_mapping const * map = lo_get_constructor_map(); for (int i = 0; map[i].name != 0; ++i) { if (constructor.equalsAscii(map[i].name)) { *constructorFunction = reinterpret_cast( map[i].constructor_function); return; } } SAL_WARN("cppuhelper", "unknown constructor name \"" << constructor << "\""); #if defined IOS && !defined SAL_LOG_WARN // If the above SAL_WARN expanded to nothing, print to stderr... fprintf(stderr, "Unknown constructor name %s\n", OUStringToOString(constructor, RTL_TEXTENCODING_UTF8).getStr()); #endif throw css::loader::CannotActivateFactoryException( "unknown constructor name \"" + constructor + "\"", css::uno::Reference()); } #else osl::Module mod(uri, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL); if (!mod.is()) { throw css::loader::CannotActivateFactoryException( "loading component library <" + uri + "> failed", css::uno::Reference()); } if (constructor.isEmpty()) { rtl::OUString sym; SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri); if (prefix == "direct") { sym = implementation.replace('.', '_') + "_" COMPONENT_GETFACTORY; } else if (!prefix.isEmpty()) { sym = prefix + "_" COMPONENT_GETFACTORY; } else { sym = COMPONENT_GETFACTORY; } oslGenericFunction fp = mod.getFunctionSymbol(sym); if (fp == nullptr) { throw css::loader::CannotActivateFactoryException( ("no factory symbol \"" + sym + "\" in component library <" + uri + ">"), css::uno::Reference()); } css::uno::Environment curEnv(css::uno::Environment::getCurrent()); *factory = invokeComponentFactory( curEnv, (environment.isEmpty() ? getEnvironmentFromModule(mod, curEnv, implementation, prefix) : getEnvironment(environment, implementation)), reinterpret_cast(fp), uri, implementation, serviceManager); } else { SAL_INFO("cppuhelper.shlib", "constructor=" << constructor); oslGenericFunction fp = mod.getFunctionSymbol(constructor); if (fp == nullptr) { throw css::loader::CannotActivateFactoryException( ("no constructor symbol \"" + constructor + "\" in component library <" + uri + ">"), css::uno::Reference()); } css::uno::Environment curEnv(css::uno::Environment::getCurrent()); *constructorFunction = mapConstructorFn( curEnv, (environment.isEmpty() ? getEnvironmentFromModule(mod, curEnv, implementation, prefix) : getEnvironment(environment, implementation)), reinterpret_cast(fp)); } mod.release(); #endif } css::uno::Reference cppu::loadSharedLibComponentFactory( rtl::OUString const & uri, rtl::OUString const & rPath, rtl::OUString const & rImplName, css::uno::Reference const & xMgr, css::uno::Reference const & xKey) { assert(rPath.isEmpty()); (void) rPath; assert(!xKey.is()); (void) xKey; css::uno::Reference fac; cppuhelper::detail::loadSharedLibComponentFactory( uri, "", "", rImplName, "", xMgr, nullptr, &fac); return fac; } #if !defined DISABLE_DYNLOADING namespace { extern "C" void writeInfo(va_list * args) { component_writeInfoFunc fn = va_arg(*args, component_writeInfoFunc); void * smgr = va_arg(*args, void *); void * key = va_arg(*args, void *); sal_Bool * ok = va_arg(*args, sal_Bool *); *ok = (*fn)(smgr, key); } } void cppu::writeSharedLibComponentInfo( rtl::OUString const & uri, rtl::OUString const & rPath, css::uno::Reference const & xMgr, css::uno::Reference const & xKey) { assert(rPath.isEmpty()); (void) rPath; osl::Module mod(uri, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL); if (!mod.is()) { throw css::registry::CannotRegisterImplementationException( "loading component library <" + uri + "> failed", css::uno::Reference()); } oslGenericFunction fp = mod.getFunctionSymbol(COMPONENT_WRITEINFO); if (fp == nullptr) { throw css::registry::CannotRegisterImplementationException( ("no symbol \"" COMPONENT_WRITEINFO "\" in component library <" + uri + ">"), css::uno::Reference()); } css::uno::Environment curEnv(css::uno::Environment::getCurrent()); css::uno::Environment env(getEnvironmentFromModule(mod, curEnv, "", "")); if (!(curEnv.is() && env.is())) { throw css::registry::CannotRegisterImplementationException( "cannot get environments", css::uno::Reference()); } css::uno::Mapping map(curEnv, env); if (!map.is()) { throw css::registry::CannotRegisterImplementationException( "cannot get mapping", css::uno::Reference()); } void * smgr = map.mapInterface( xMgr.get(), cppu::UnoType::get()); void * key = map.mapInterface( xKey.get(), cppu::UnoType::get()); sal_Bool ok; env.invoke(writeInfo, fp, smgr, key, &ok); (*env.get()->pExtEnv->releaseInterface)(env.get()->pExtEnv, key); if (smgr != nullptr) { (*env.get()->pExtEnv->releaseInterface)(env.get()->pExtEnv, smgr); } if (!ok) { throw css::registry::CannotRegisterImplementationException( ("calling \"" COMPONENT_WRITEINFO "\" in component library <" + uri + "> returned false"), css::uno::Reference()); } } #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */