diff options
Diffstat (limited to 'cppuhelper/source/bootstrap.cxx')
-rw-r--r-- | cppuhelper/source/bootstrap.cxx | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/cppuhelper/source/bootstrap.cxx b/cppuhelper/source/bootstrap.cxx new file mode 100644 index 000000000000..245714827145 --- /dev/null +++ b/cppuhelper/source/bootstrap.cxx @@ -0,0 +1,667 @@ +/* -*- 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppuhelper.hxx" + +#include <string.h> +#include <vector> + +#include "rtl/process.h" +#include "rtl/bootstrap.hxx" +#include "rtl/random.h" +#include "rtl/string.hxx" +#include "rtl/ustrbuf.hxx" +#include "rtl/uri.hxx" +#if OSL_DEBUG_LEVEL > 0 +#include "rtl/strbuf.hxx" +#endif +#include "osl/diagnose.h" +#include "osl/file.hxx" +#include "osl/module.hxx" +#include "osl/security.hxx" +#include "osl/thread.hxx" + +#include "cppuhelper/shlib.hxx" +#include "cppuhelper/bootstrap.hxx" +#include "cppuhelper/component_context.hxx" +#include "cppuhelper/access_control.hxx" +#include "cppuhelper/findsofficepath.h" + +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/uno/XCurrentContext.hpp" + +#include "com/sun/star/lang/XSingleServiceFactory.hpp" +#include "com/sun/star/lang/XSingleComponentFactory.hpp" +#include "com/sun/star/lang/XInitialization.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/registry/XSimpleRegistry.hpp" +#include "com/sun/star/container/XSet.hpp" +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/io/IOException.hpp" +#include "com/sun/star/bridge/UnoUrlResolver.hpp" +#include "com/sun/star/bridge/XUnoUrlResolver.hpp" + +#include "macro_expander.hxx" + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) +#define ARLEN(x) sizeof (x) / sizeof *(x) + + +using namespace ::rtl; +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace cppu +{ + +OUString const & get_this_libpath() +{ + static OUString s_path; + if (0 == s_path.getLength()) + { + OUString path; + Module::getUrlFromAddress( reinterpret_cast<oslGenericFunction>(get_this_libpath), path ); + path = path.copy( 0, path.lastIndexOf( '/' ) ); + MutexGuard guard( Mutex::getGlobalMutex() ); + if (0 == s_path.getLength()) + s_path = path; + } + return s_path; +} + +Bootstrap const & get_unorc() SAL_THROW( () ) +{ + static rtlBootstrapHandle s_bstrap = 0; + if (! s_bstrap) + { + OUString iniName( + get_this_libpath() + OUSTR("/" SAL_CONFIGFILE("uno")) ); + rtlBootstrapHandle bstrap = rtl_bootstrap_args_open( iniName.pData ); + + ClearableMutexGuard guard( Mutex::getGlobalMutex() ); + if (s_bstrap) + { + guard.clear(); + rtl_bootstrap_args_close( bstrap ); + } + else + { + s_bstrap = bstrap; + } + } + return *(Bootstrap const *)&s_bstrap; +} + + +void addFactories( + char const * const * ppNames /* lib, implname, ..., 0 */, + OUString const & bootstrapPath, + Reference< lang::XMultiComponentFactory > const & xMgr, + Reference< registry::XRegistryKey > const & xKey ) + SAL_THROW( (Exception) ) +{ + Reference< container::XSet > xSet( xMgr, UNO_QUERY ); + OSL_ASSERT( xSet.is() ); + Reference< lang::XMultiServiceFactory > xSF( xMgr, UNO_QUERY ); + + while (*ppNames) + { + OUString lib( OUString::createFromAscii( *ppNames++ ) ); + OUString implName( OUString::createFromAscii( *ppNames++ ) ); + + Any aFac( makeAny( loadSharedLibComponentFactory( + lib, bootstrapPath, implName, xSF, xKey ) ) ); + xSet->insert( aFac ); +#if OSL_DEBUG_LEVEL > 1 + if (xSet->has( aFac )) + { + Reference< lang::XServiceInfo > xInfo; + if (aFac >>= xInfo) + { + ::fprintf( + stderr, "> implementation %s supports: ", ppNames[ -1 ] ); + Sequence< OUString > supported( + xInfo->getSupportedServiceNames() ); + for ( sal_Int32 nPos = supported.getLength(); nPos--; ) + { + OString str( OUStringToOString( + supported[ nPos ], RTL_TEXTENCODING_ASCII_US ) ); + ::fprintf( stderr, nPos ? "%s, " : "%s\n", str.getStr() ); + } + } + else + { + ::fprintf( + stderr, + "> implementation %s provides NO lang::XServiceInfo!!!\n", + ppNames[ -1 ] ); + } + } +#endif +#if OSL_DEBUG_LEVEL > 0 + if (! xSet->has( aFac )) + { + OStringBuffer buf( 64 ); + buf.append( "### failed inserting shared lib \"" ); + buf.append( ppNames[ -2 ] ); + buf.append( "\"!!!" ); + OString str( buf.makeStringAndClear() ); + OSL_ENSURE( 0, str.getStr() ); + } +#endif + } +} + +// private forward decl +Reference< lang::XMultiComponentFactory > bootstrapInitialSF( + OUString const & rBootstrapPath ) + SAL_THROW( (Exception) ); + +Reference< XComponentContext > bootstrapInitialContext( + Reference< lang::XMultiComponentFactory > const & xSF, + Reference< registry::XSimpleRegistry > const & types_xRegistry, + Reference< registry::XSimpleRegistry > const & services_xRegistry, + OUString const & rBootstrapPath, Bootstrap const & bootstrap ) + SAL_THROW( (Exception) ); + +Reference< XComponentContext > SAL_CALL createInitialCfgComponentContext( + ContextEntry_Init const * pEntries, sal_Int32 nEntries, + Reference< XComponentContext > const & xDelegate ) + SAL_THROW( () ); + +Reference< registry::XSimpleRegistry > SAL_CALL createRegistryWrapper( + const Reference< XComponentContext >& xContext ); + +namespace { + +template< class T > +inline beans::PropertyValue createPropertyValue( + OUString const & name, T const & value ) + SAL_THROW( () ) +{ + return beans::PropertyValue( + name, -1, makeAny( value ), beans::PropertyState_DIRECT_VALUE ); +} + +OUString findBoostrapArgument( + const Bootstrap & bootstrap, + const OUString & arg_name, + sal_Bool * pFallenBack ) + SAL_THROW(()) +{ + OUString result; + + OUString prefixed_arg_name = OUSTR("UNO_"); + prefixed_arg_name += arg_name.toAsciiUpperCase(); + + // environment not set -> try relative to executable + if(!bootstrap.getFrom(prefixed_arg_name, result)) + { + if(pFallenBack) + *pFallenBack = sal_True; + + OUString fileName; + bootstrap.getIniName(fileName); + + // cut the rc extension + OUStringBuffer result_buf( 64 ); + result_buf.append( + fileName.copy( + 0, fileName.getLength() - strlen(SAL_CONFIGFILE(""))) ); + result_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("_") ); + result_buf.append( arg_name.toAsciiLowerCase() ); + result_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(".rdb") ); + result = result_buf.makeStringAndClear(); + +#if OSL_DEBUG_LEVEL > 1 + OString result_dbg = + OUStringToOString(result, RTL_TEXTENCODING_ASCII_US); + OString arg_name_dbg = + OUStringToOString(arg_name, RTL_TEXTENCODING_ASCII_US); + OSL_TRACE( + "cppuhelper::findBoostrapArgument - " + "setting %s relative to executable: %s\n", + arg_name_dbg.getStr(), + result_dbg.getStr() ); +#endif + } + else + { + if(pFallenBack) + *pFallenBack = sal_False; + +#if OSL_DEBUG_LEVEL > 1 + OString prefixed_arg_name_dbg = OUStringToOString( + prefixed_arg_name, RTL_TEXTENCODING_ASCII_US ); + OString result_dbg = OUStringToOString( + result, RTL_TEXTENCODING_ASCII_US ); + OSL_TRACE( + "cppuhelper::findBoostrapArgument - found %s in env: %s", + prefixed_arg_name_dbg.getStr(), + result_dbg.getStr() ); +#endif + } + + return result; +} + +Reference< registry::XSimpleRegistry > nestRegistries( + const OUString baseDir, + const Reference< lang::XSingleServiceFactory > & xSimRegFac, + const Reference< lang::XSingleServiceFactory > & xNesRegFac, + OUString csl_rdbs, + const OUString & write_rdb, + sal_Bool forceWrite_rdb, + sal_Bool bFallenBack ) + SAL_THROW((Exception)) +{ + sal_Int32 index; + Reference< registry::XSimpleRegistry > lastRegistry; + + if(write_rdb.getLength()) // is there a write registry given? + { + lastRegistry.set(xSimRegFac->createInstance(), UNO_QUERY); + + try + { + lastRegistry->open(write_rdb, sal_False, forceWrite_rdb); + } + catch (registry::InvalidRegistryException & invalidRegistryException) + { + (void) invalidRegistryException; +#if OSL_DEBUG_LEVEL > 1 + OString rdb_name_tmp = OUStringToOString( + write_rdb, RTL_TEXTENCODING_ASCII_US); + OString message_dbg = OUStringToOString( + invalidRegistryException.Message, RTL_TEXTENCODING_ASCII_US); + OSL_TRACE( + "warning: couldn't open %s cause of %s", + rdb_name_tmp.getStr(), message_dbg.getStr() ); +#endif + } + + if(!lastRegistry->isValid()) + lastRegistry.clear(); + } + + do + { + index = csl_rdbs.indexOf((sal_Unicode)' '); + OUString rdb_name = (index == -1) ? csl_rdbs : csl_rdbs.copy(0, index); + csl_rdbs = (index == -1) ? OUString() : csl_rdbs.copy(index + 1); + + if (! rdb_name.getLength()) + continue; + + bool optional = ('?' == rdb_name[ 0 ]); + if (optional) + rdb_name = rdb_name.copy( 1 ); + + try + { + Reference<registry::XSimpleRegistry> simpleRegistry( + xSimRegFac->createInstance(), UNO_QUERY_THROW ); + + osl::FileBase::getAbsoluteFileURL(baseDir, rdb_name, rdb_name); + simpleRegistry->open(rdb_name, sal_True, sal_False); + + if(lastRegistry.is()) + { + Reference< registry::XSimpleRegistry > nestedRegistry( + xNesRegFac->createInstance(), UNO_QUERY ); + Reference< lang::XInitialization > nestedRegistry_xInit( + nestedRegistry, UNO_QUERY ); + + Sequence<Any> aArgs(2); + aArgs[0] <<= lastRegistry; + aArgs[1] <<= simpleRegistry; + + nestedRegistry_xInit->initialize(aArgs); + + lastRegistry = nestedRegistry; + } + else + lastRegistry = simpleRegistry; + } + catch(registry::InvalidRegistryException & invalidRegistryException) + { + if (! optional) + { + // if a registry was explicitly given, the exception shall fly + if( ! bFallenBack ) + throw; + } + + (void) invalidRegistryException; +#if OSL_DEBUG_LEVEL > 1 + OString rdb_name_tmp = OUStringToOString( + rdb_name, RTL_TEXTENCODING_ASCII_US ); + OString message_dbg = OUStringToOString( + invalidRegistryException.Message, RTL_TEXTENCODING_ASCII_US ); + OSL_TRACE( + "warning: couldn't open %s cause of %s", + rdb_name_tmp.getStr(), message_dbg.getStr() ); +#endif + } + } + while(index != -1 && csl_rdbs.getLength()); // are there more rdbs in list? + + return lastRegistry; +} + +Reference< XComponentContext > +SAL_CALL defaultBootstrap_InitialComponentContext( + Bootstrap const & bootstrap ) + SAL_THROW( (Exception) ) +{ + OUString bootstrapPath( get_this_libpath() ); + OUString iniDir; + + osl_getProcessWorkingDir(&iniDir.pData); + + Reference<lang::XMultiComponentFactory> smgr_XMultiComponentFactory( + bootstrapInitialSF(bootstrapPath) ); + Reference<lang::XMultiServiceFactory> smgr_XMultiServiceFactory( + smgr_XMultiComponentFactory, UNO_QUERY ); + + Reference<registry::XRegistryKey> xEmptyKey; + Reference<lang::XSingleServiceFactory> xSimRegFac( + loadSharedLibComponentFactory( + OUSTR("bootstrap.uno" SAL_DLLEXTENSION), bootstrapPath, + OUSTR("com.sun.star.comp.stoc.SimpleRegistry"), + smgr_XMultiServiceFactory, + xEmptyKey), + UNO_QUERY); + + Reference<lang::XSingleServiceFactory> xNesRegFac( + loadSharedLibComponentFactory( + OUSTR("bootstrap.uno" SAL_DLLEXTENSION), bootstrapPath, + OUSTR("com.sun.star.comp.stoc.NestedRegistry"), + smgr_XMultiServiceFactory, + xEmptyKey), + UNO_QUERY); + + sal_Bool bFallenback_types; + OUString cls_uno_types = + findBoostrapArgument( bootstrap, OUSTR("TYPES"), &bFallenback_types ); + + Reference<registry::XSimpleRegistry> types_xRegistry = + nestRegistries( + iniDir, xSimRegFac, xNesRegFac, cls_uno_types, + OUString(), sal_False, bFallenback_types ); + + // ==== bootstrap from services registry ==== + + sal_Bool bFallenback_services; + OUString cls_uno_services = findBoostrapArgument( + bootstrap, OUSTR("SERVICES"), &bFallenback_services ); + + sal_Bool fallenBackWriteRegistry; + OUString write_rdb = findBoostrapArgument( + bootstrap, OUSTR("WRITERDB"), &fallenBackWriteRegistry ); + if (fallenBackWriteRegistry) + { + // no standard write rdb anymore + write_rdb = OUString(); + } + + Reference<registry::XSimpleRegistry> services_xRegistry = nestRegistries( + iniDir, xSimRegFac, xNesRegFac, cls_uno_services, write_rdb, + !fallenBackWriteRegistry, bFallenback_services ); + + Reference< XComponentContext > xContext( + bootstrapInitialContext( + smgr_XMultiComponentFactory, types_xRegistry, services_xRegistry, + bootstrapPath, bootstrap ) ); + + // initialize sf + Reference< lang::XInitialization > xInit( + smgr_XMultiComponentFactory, UNO_QUERY ); + OSL_ASSERT( xInit.is() ); + Sequence< Any > aSFInit( 1 ); + aSFInit[ 0 ] <<= services_xRegistry; + xInit->initialize( aSFInit ); + + return xContext; +} + +} + +Reference< XComponentContext > +SAL_CALL defaultBootstrap_InitialComponentContext( + OUString const & iniFile ) + SAL_THROW( (Exception) ) +{ + Bootstrap bootstrap( iniFile ); + if (bootstrap.getHandle() == 0) + throw io::IOException(OUSTR("Cannot open for reading: ") + iniFile, 0); + return defaultBootstrap_InitialComponentContext( bootstrap ); +} + +Reference< XComponentContext > +SAL_CALL defaultBootstrap_InitialComponentContext() + SAL_THROW( (Exception) ) +{ + return defaultBootstrap_InitialComponentContext( get_unorc() ); +} + +BootstrapException::BootstrapException() +{ +} + +BootstrapException::BootstrapException( const ::rtl::OUString & rMessage ) + :m_aMessage( rMessage ) +{ +} + +BootstrapException::BootstrapException( const BootstrapException & e ) +{ + m_aMessage = e.m_aMessage; +} + +BootstrapException::~BootstrapException() +{ +} + +BootstrapException & BootstrapException::operator=( const BootstrapException & e ) +{ + m_aMessage = e.m_aMessage; + return *this; +} + +const ::rtl::OUString & BootstrapException::getMessage() const +{ + return m_aMessage; +} + +Reference< XComponentContext > SAL_CALL bootstrap() +{ + Reference< XComponentContext > xRemoteContext; + + try + { + char const * p1 = cppuhelper_detail_findSofficePath(); + if (p1 == NULL) { + throw BootstrapException( + OUSTR("no soffice installation found!")); + } + rtl::OUString p2; + if (!rtl_convertStringToUString( + &p2.pData, p1, strlen(p1), osl_getThreadTextEncoding(), + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) + { + throw BootstrapException( + OUSTR("bad characters in soffice installation path!")); + } + OUString path; + if (osl::FileBase::getFileURLFromSystemPath(p2, path) != + osl::FileBase::E_None) + { + throw BootstrapException( + OUSTR("cannot convert soffice installation path to URL!")); + } + if (path.getLength() > 0 && path[path.getLength() - 1] != '/') { + path += OUSTR("/"); + } + + OUString uri; + if (!Bootstrap::get(OUSTR("URE_BOOTSTRAP"), uri)) { + Bootstrap::set( + OUSTR("URE_BOOTSTRAP"), + Bootstrap::encode(path + OUSTR(SAL_CONFIGFILE("fundamental")))); + } + + // create default local component context + Reference< XComponentContext > xLocalContext( + defaultBootstrap_InitialComponentContext() ); + if ( !xLocalContext.is() ) + throw BootstrapException( OUSTR( "no local component context!" ) ); + + // create a random pipe name + rtlRandomPool hPool = rtl_random_createPool(); + if ( hPool == 0 ) + throw BootstrapException( OUSTR( "cannot create random pool!" ) ); + sal_uInt8 bytes[ 16 ]; + if ( rtl_random_getBytes( hPool, bytes, ARLEN( bytes ) ) + != rtl_Random_E_None ) + throw BootstrapException( OUSTR( "random pool error!" ) ); + rtl_random_destroyPool( hPool ); + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno" ) ); + for ( sal_uInt32 i = 0; i < ARLEN( bytes ); ++i ) + buf.append( static_cast< sal_Int32 >( bytes[ i ] ) ); + OUString sPipeName( buf.makeStringAndClear() ); + + // accept string + OSL_ASSERT( buf.getLength() == 0 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "-accept=pipe,name=" ) ); + buf.append( sPipeName ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ";urp;" ) ); + + // arguments + OUString args [] = { + OUSTR( "-nologo" ), + OUSTR( "-nodefault" ), + OUSTR( "-norestore" ), + OUSTR( "-nocrashreport" ), + OUSTR( "-nolockcheck" ), + buf.makeStringAndClear() + }; + rtl_uString * ar_args [] = { + args[ 0 ].pData, + args[ 1 ].pData, + args[ 2 ].pData, + args[ 3 ].pData, + args[ 4 ].pData, + args[ 5 ].pData + }; + ::osl::Security sec; + + // start office process + oslProcess hProcess = 0; + oslProcessError rc = osl_executeProcess( + (path + OUSTR("soffice")).pData, ar_args, ARLEN( ar_args ), + osl_Process_DETACHED, + sec.getHandle(), + 0, // => current working dir + 0, 0, // => no env vars + &hProcess ); + switch ( rc ) + { + case osl_Process_E_None: + osl_freeProcessHandle( hProcess ); + break; + case osl_Process_E_NotFound: + throw BootstrapException( OUSTR( "image not found!" ) ); + case osl_Process_E_TimedOut: + throw BootstrapException( OUSTR( "timout occured!" ) ); + case osl_Process_E_NoPermission: + throw BootstrapException( OUSTR( "permission denied!" ) ); + case osl_Process_E_Unknown: + throw BootstrapException( OUSTR( "unknown error!" ) ); + case osl_Process_E_InvalidError: + default: + throw BootstrapException( OUSTR( "unmapped error!" ) ); + } + + // create a URL resolver + Reference< bridge::XUnoUrlResolver > xUrlResolver( + bridge::UnoUrlResolver::create( xLocalContext ) ); + + // connection string + OSL_ASSERT( buf.getLength() == 0 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno:pipe,name=" ) ); + buf.append( sPipeName ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + ";urp;StarOffice.ComponentContext" ) ); + OUString sConnectString( buf.makeStringAndClear() ); + + // wait until office is started + for ( ; ; ) + { + try + { + // try to connect to office + xRemoteContext.set( + xUrlResolver->resolve( sConnectString ), UNO_QUERY_THROW ); + break; + } + catch ( connection::NoConnectException & ) + { + // wait 500 ms, then try to connect again + TimeValue tv = { 0 /* secs */, 500000000 /* nanosecs */ }; + ::osl::Thread::wait( tv ); + } + } + } + catch ( Exception & e ) + { + throw BootstrapException( + OUSTR( "unexpected UNO exception caught: " ) + e.Message ); + } + + return xRemoteContext; +} + +OUString bootstrap_expandUri(OUString const & uri) { + static char const PREFIX[] = "vnd.sun.star.expand:"; + return uri.matchAsciiL(RTL_CONSTASCII_STRINGPARAM(PREFIX)) + ? cppuhelper::detail::expandMacros( + rtl::Uri::decode( + uri.copy(RTL_CONSTASCII_LENGTH(PREFIX)), + rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8)) + : uri; +} + +} // namespace cppu + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |