1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_cppuhelper.hxx"
35 #include "rtl/process.h"
36 #include "rtl/bootstrap.hxx"
37 #include "rtl/random.h"
38 #include "rtl/string.hxx"
39 #include "rtl/ustrbuf.hxx"
40 #include "rtl/uri.hxx"
41 #if OSL_DEBUG_LEVEL > 0
42 #include "rtl/strbuf.hxx"
44 #include "osl/diagnose.h"
45 #include "osl/file.hxx"
46 #include "osl/module.hxx"
47 #include "osl/security.hxx"
48 #include "osl/thread.hxx"
50 #include "cppuhelper/shlib.hxx"
51 #include "cppuhelper/bootstrap.hxx"
52 #include "cppuhelper/component_context.hxx"
53 #include "cppuhelper/access_control.hxx"
54 #include "cppuhelper/findsofficepath.h"
56 #include "com/sun/star/uno/XComponentContext.hpp"
57 #include "com/sun/star/uno/XCurrentContext.hpp"
59 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
60 #include "com/sun/star/lang/XSingleComponentFactory.hpp"
61 #include "com/sun/star/lang/XInitialization.hpp"
62 #include "com/sun/star/lang/XServiceInfo.hpp"
63 #include "com/sun/star/registry/XSimpleRegistry.hpp"
64 #include "com/sun/star/container/XSet.hpp"
65 #include "com/sun/star/beans/PropertyValue.hpp"
66 #include "com/sun/star/io/IOException.hpp"
67 #include "com/sun/star/bridge/UnoUrlResolver.hpp"
68 #include "com/sun/star/bridge/XUnoUrlResolver.hpp"
70 #include "macro_expander.hxx"
72 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
73 #define ARLEN(x) sizeof (x) / sizeof *(x)
76 using namespace ::rtl
;
77 using namespace ::osl
;
78 using namespace ::com::sun::star
;
79 using namespace ::com::sun::star::uno
;
84 OUString
const & get_this_libpath()
86 static OUString s_path
;
87 if (0 == s_path
.getLength())
90 Module::getUrlFromAddress( reinterpret_cast<oslGenericFunction
>(get_this_libpath
), path
);
91 path
= path
.copy( 0, path
.lastIndexOf( '/' ) );
92 MutexGuard
guard( Mutex::getGlobalMutex() );
93 if (0 == s_path
.getLength())
99 Bootstrap
const & get_unorc() SAL_THROW( () )
101 static rtlBootstrapHandle s_bstrap
= 0;
105 get_this_libpath() + OUSTR("/" SAL_CONFIGFILE("uno")) );
106 rtlBootstrapHandle bstrap
= rtl_bootstrap_args_open( iniName
.pData
);
108 ClearableMutexGuard
guard( Mutex::getGlobalMutex() );
112 rtl_bootstrap_args_close( bstrap
);
119 return *(Bootstrap
const *)&s_bstrap
;
124 char const * const * ppNames
/* lib, implname, ..., 0 */,
125 OUString
const & bootstrapPath
,
126 Reference
< lang::XMultiComponentFactory
> const & xMgr
,
127 Reference
< registry::XRegistryKey
> const & xKey
)
128 SAL_THROW( (Exception
) )
130 Reference
< container::XSet
> xSet( xMgr
, UNO_QUERY
);
131 OSL_ASSERT( xSet
.is() );
132 Reference
< lang::XMultiServiceFactory
> xSF( xMgr
, UNO_QUERY
);
136 OUString
lib( OUString::createFromAscii( *ppNames
++ ) );
137 OUString
implName( OUString::createFromAscii( *ppNames
++ ) );
139 Any
aFac( makeAny( loadSharedLibComponentFactory(
140 lib
, bootstrapPath
, implName
, xSF
, xKey
) ) );
141 xSet
->insert( aFac
);
142 #if OSL_DEBUG_LEVEL > 1
143 if (xSet
->has( aFac
))
145 Reference
< lang::XServiceInfo
> xInfo
;
149 stderr
, "> implementation %s supports: ", ppNames
[ -1 ] );
150 Sequence
< OUString
> supported(
151 xInfo
->getSupportedServiceNames() );
152 for ( sal_Int32 nPos
= supported
.getLength(); nPos
--; )
154 OString
str( OUStringToOString(
155 supported
[ nPos
], RTL_TEXTENCODING_ASCII_US
) );
156 ::fprintf( stderr
, nPos
? "%s, " : "%s\n", str
.getStr() );
163 "> implementation %s provides NO lang::XServiceInfo!!!\n",
168 #if OSL_DEBUG_LEVEL > 0
169 if (! xSet
->has( aFac
))
171 OStringBuffer
buf( 64 );
172 buf
.append( "### failed inserting shared lib \"" );
173 buf
.append( ppNames
[ -2 ] );
174 buf
.append( "\"!!!" );
175 OString
str( buf
.makeStringAndClear() );
176 OSL_ENSURE( 0, str
.getStr() );
182 // private forward decl
183 Reference
< lang::XMultiComponentFactory
> bootstrapInitialSF(
184 OUString
const & rBootstrapPath
)
185 SAL_THROW( (Exception
) );
187 Reference
< XComponentContext
> bootstrapInitialContext(
188 Reference
< lang::XMultiComponentFactory
> const & xSF
,
189 Reference
< registry::XSimpleRegistry
> const & types_xRegistry
,
190 Reference
< registry::XSimpleRegistry
> const & services_xRegistry
,
191 OUString
const & rBootstrapPath
, Bootstrap
const & bootstrap
)
192 SAL_THROW( (Exception
) );
194 Reference
< XComponentContext
> SAL_CALL
createInitialCfgComponentContext(
195 ContextEntry_Init
const * pEntries
, sal_Int32 nEntries
,
196 Reference
< XComponentContext
> const & xDelegate
)
199 Reference
< registry::XSimpleRegistry
> SAL_CALL
createRegistryWrapper(
200 const Reference
< XComponentContext
>& xContext
);
205 inline beans::PropertyValue
createPropertyValue(
206 OUString
const & name
, T
const & value
)
209 return beans::PropertyValue(
210 name
, -1, makeAny( value
), beans::PropertyState_DIRECT_VALUE
);
213 OUString
findBoostrapArgument(
214 const Bootstrap
& bootstrap
,
215 const OUString
& arg_name
,
216 sal_Bool
* pFallenBack
)
221 OUString prefixed_arg_name
= OUSTR("UNO_");
222 prefixed_arg_name
+= arg_name
.toAsciiUpperCase();
224 // environment not set -> try relative to executable
225 if(!bootstrap
.getFrom(prefixed_arg_name
, result
))
228 *pFallenBack
= sal_True
;
231 bootstrap
.getIniName(fileName
);
233 // cut the rc extension
234 OUStringBuffer
result_buf( 64 );
237 0, fileName
.getLength() - strlen(SAL_CONFIGFILE(""))) );
238 result_buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("_") );
239 result_buf
.append( arg_name
.toAsciiLowerCase() );
240 result_buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(".rdb") );
241 result
= result_buf
.makeStringAndClear();
243 #if OSL_DEBUG_LEVEL > 1
245 OUStringToOString(result
, RTL_TEXTENCODING_ASCII_US
);
246 OString arg_name_dbg
=
247 OUStringToOString(arg_name
, RTL_TEXTENCODING_ASCII_US
);
249 "cppuhelper::findBoostrapArgument - "
250 "setting %s relative to executable: %s\n",
251 arg_name_dbg
.getStr(),
252 result_dbg
.getStr() );
258 *pFallenBack
= sal_False
;
260 #if OSL_DEBUG_LEVEL > 1
261 OString prefixed_arg_name_dbg
= OUStringToOString(
262 prefixed_arg_name
, RTL_TEXTENCODING_ASCII_US
);
263 OString result_dbg
= OUStringToOString(
264 result
, RTL_TEXTENCODING_ASCII_US
);
266 "cppuhelper::findBoostrapArgument - found %s in env: %s",
267 prefixed_arg_name_dbg
.getStr(),
268 result_dbg
.getStr() );
275 Reference
< registry::XSimpleRegistry
> nestRegistries(
276 const OUString baseDir
,
277 const Reference
< lang::XSingleServiceFactory
> & xSimRegFac
,
278 const Reference
< lang::XSingleServiceFactory
> & xNesRegFac
,
280 const OUString
& write_rdb
,
281 sal_Bool forceWrite_rdb
,
282 sal_Bool bFallenBack
)
283 SAL_THROW((Exception
))
286 Reference
< registry::XSimpleRegistry
> lastRegistry
;
288 if(write_rdb
.getLength()) // is there a write registry given?
290 lastRegistry
.set(xSimRegFac
->createInstance(), UNO_QUERY
);
294 lastRegistry
->open(write_rdb
, sal_False
, forceWrite_rdb
);
296 catch (registry::InvalidRegistryException
& invalidRegistryException
)
298 (void) invalidRegistryException
;
299 #if OSL_DEBUG_LEVEL > 1
300 OString rdb_name_tmp
= OUStringToOString(
301 write_rdb
, RTL_TEXTENCODING_ASCII_US
);
302 OString message_dbg
= OUStringToOString(
303 invalidRegistryException
.Message
, RTL_TEXTENCODING_ASCII_US
);
305 "warning: couldn't open %s cause of %s",
306 rdb_name_tmp
.getStr(), message_dbg
.getStr() );
310 if(!lastRegistry
->isValid())
311 lastRegistry
.clear();
316 index
= csl_rdbs
.indexOf((sal_Unicode
)' ');
317 OUString rdb_name
= (index
== -1) ? csl_rdbs
: csl_rdbs
.copy(0, index
);
318 csl_rdbs
= (index
== -1) ? OUString() : csl_rdbs
.copy(index
+ 1);
320 if (! rdb_name
.getLength())
323 bool optional
= ('?' == rdb_name
[ 0 ]);
325 rdb_name
= rdb_name
.copy( 1 );
329 Reference
<registry::XSimpleRegistry
> simpleRegistry(
330 xSimRegFac
->createInstance(), UNO_QUERY_THROW
);
332 osl::FileBase::getAbsoluteFileURL(baseDir
, rdb_name
, rdb_name
);
333 simpleRegistry
->open(rdb_name
, sal_True
, sal_False
);
335 if(lastRegistry
.is())
337 Reference
< registry::XSimpleRegistry
> nestedRegistry(
338 xNesRegFac
->createInstance(), UNO_QUERY
);
339 Reference
< lang::XInitialization
> nestedRegistry_xInit(
340 nestedRegistry
, UNO_QUERY
);
342 Sequence
<Any
> aArgs(2);
343 aArgs
[0] <<= lastRegistry
;
344 aArgs
[1] <<= simpleRegistry
;
346 nestedRegistry_xInit
->initialize(aArgs
);
348 lastRegistry
= nestedRegistry
;
351 lastRegistry
= simpleRegistry
;
353 catch(registry::InvalidRegistryException
& invalidRegistryException
)
357 // if a registry was explicitly given, the exception shall fly
362 (void) invalidRegistryException
;
363 #if OSL_DEBUG_LEVEL > 1
364 OString rdb_name_tmp
= OUStringToOString(
365 rdb_name
, RTL_TEXTENCODING_ASCII_US
);
366 OString message_dbg
= OUStringToOString(
367 invalidRegistryException
.Message
, RTL_TEXTENCODING_ASCII_US
);
369 "warning: couldn't open %s cause of %s",
370 rdb_name_tmp
.getStr(), message_dbg
.getStr() );
374 while(index
!= -1 && csl_rdbs
.getLength()); // are there more rdbs in list?
379 Reference
< XComponentContext
>
380 SAL_CALL
defaultBootstrap_InitialComponentContext(
381 Bootstrap
const & bootstrap
)
382 SAL_THROW( (Exception
) )
384 OUString
bootstrapPath( get_this_libpath() );
387 osl_getProcessWorkingDir(&iniDir
.pData
);
389 Reference
<lang::XMultiComponentFactory
> smgr_XMultiComponentFactory(
390 bootstrapInitialSF(bootstrapPath
) );
391 Reference
<lang::XMultiServiceFactory
> smgr_XMultiServiceFactory(
392 smgr_XMultiComponentFactory
, UNO_QUERY
);
394 Reference
<registry::XRegistryKey
> xEmptyKey
;
395 Reference
<lang::XSingleServiceFactory
> xSimRegFac(
396 loadSharedLibComponentFactory(
397 OUSTR("bootstrap.uno" SAL_DLLEXTENSION
), bootstrapPath
,
398 OUSTR("com.sun.star.comp.stoc.SimpleRegistry"),
399 smgr_XMultiServiceFactory
,
403 Reference
<lang::XSingleServiceFactory
> xNesRegFac(
404 loadSharedLibComponentFactory(
405 OUSTR("bootstrap.uno" SAL_DLLEXTENSION
), bootstrapPath
,
406 OUSTR("com.sun.star.comp.stoc.NestedRegistry"),
407 smgr_XMultiServiceFactory
,
411 sal_Bool bFallenback_types
;
412 OUString cls_uno_types
=
413 findBoostrapArgument( bootstrap
, OUSTR("TYPES"), &bFallenback_types
);
415 Reference
<registry::XSimpleRegistry
> types_xRegistry
=
417 iniDir
, xSimRegFac
, xNesRegFac
, cls_uno_types
,
418 OUString(), sal_False
, bFallenback_types
);
420 // ==== bootstrap from services registry ====
422 sal_Bool bFallenback_services
;
423 OUString cls_uno_services
= findBoostrapArgument(
424 bootstrap
, OUSTR("SERVICES"), &bFallenback_services
);
426 sal_Bool fallenBackWriteRegistry
;
427 OUString write_rdb
= findBoostrapArgument(
428 bootstrap
, OUSTR("WRITERDB"), &fallenBackWriteRegistry
);
429 if (fallenBackWriteRegistry
)
431 // no standard write rdb anymore
432 write_rdb
= OUString();
435 Reference
<registry::XSimpleRegistry
> services_xRegistry
= nestRegistries(
436 iniDir
, xSimRegFac
, xNesRegFac
, cls_uno_services
, write_rdb
,
437 !fallenBackWriteRegistry
, bFallenback_services
);
439 Reference
< XComponentContext
> xContext(
440 bootstrapInitialContext(
441 smgr_XMultiComponentFactory
, types_xRegistry
, services_xRegistry
,
442 bootstrapPath
, bootstrap
) );
445 Reference
< lang::XInitialization
> xInit(
446 smgr_XMultiComponentFactory
, UNO_QUERY
);
447 OSL_ASSERT( xInit
.is() );
448 Sequence
< Any
> aSFInit( 1 );
449 aSFInit
[ 0 ] <<= services_xRegistry
;
450 xInit
->initialize( aSFInit
);
457 Reference
< XComponentContext
>
458 SAL_CALL
defaultBootstrap_InitialComponentContext(
459 OUString
const & iniFile
)
460 SAL_THROW( (Exception
) )
462 Bootstrap
bootstrap( iniFile
);
463 if (bootstrap
.getHandle() == 0)
464 throw io::IOException(OUSTR("Cannot open for reading: ") + iniFile
, 0);
465 return defaultBootstrap_InitialComponentContext( bootstrap
);
468 Reference
< XComponentContext
>
469 SAL_CALL
defaultBootstrap_InitialComponentContext()
470 SAL_THROW( (Exception
) )
472 return defaultBootstrap_InitialComponentContext( get_unorc() );
475 BootstrapException::BootstrapException()
479 BootstrapException::BootstrapException( const ::rtl::OUString
& rMessage
)
480 :m_aMessage( rMessage
)
484 BootstrapException::BootstrapException( const BootstrapException
& e
)
486 m_aMessage
= e
.m_aMessage
;
489 BootstrapException::~BootstrapException()
493 BootstrapException
& BootstrapException::operator=( const BootstrapException
& e
)
495 m_aMessage
= e
.m_aMessage
;
499 const ::rtl::OUString
& BootstrapException::getMessage() const
504 Reference
< XComponentContext
> SAL_CALL
bootstrap()
506 Reference
< XComponentContext
> xRemoteContext
;
510 char const * p1
= cppuhelper_detail_findSofficePath();
512 throw BootstrapException(
513 OUSTR("no soffice installation found!"));
516 if (!rtl_convertStringToUString(
517 &p2
.pData
, p1
, strlen(p1
), osl_getThreadTextEncoding(),
518 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
519 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
520 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
522 throw BootstrapException(
523 OUSTR("bad characters in soffice installation path!"));
526 if (osl::FileBase::getFileURLFromSystemPath(p2
, path
) !=
527 osl::FileBase::E_None
)
529 throw BootstrapException(
530 OUSTR("cannot convert soffice installation path to URL!"));
532 if (path
.getLength() > 0 && path
[path
.getLength() - 1] != '/') {
537 if (!Bootstrap::get(OUSTR("URE_BOOTSTRAP"), uri
)) {
539 OUSTR("URE_BOOTSTRAP"),
540 Bootstrap::encode(path
+ OUSTR(SAL_CONFIGFILE("fundamental"))));
543 // create default local component context
544 Reference
< XComponentContext
> xLocalContext(
545 defaultBootstrap_InitialComponentContext() );
546 if ( !xLocalContext
.is() )
547 throw BootstrapException( OUSTR( "no local component context!" ) );
549 // create a random pipe name
550 rtlRandomPool hPool
= rtl_random_createPool();
552 throw BootstrapException( OUSTR( "cannot create random pool!" ) );
553 sal_uInt8 bytes
[ 16 ];
554 if ( rtl_random_getBytes( hPool
, bytes
, ARLEN( bytes
) )
555 != rtl_Random_E_None
)
556 throw BootstrapException( OUSTR( "random pool error!" ) );
557 rtl_random_destroyPool( hPool
);
558 ::rtl::OUStringBuffer buf
;
559 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno" ) );
560 for ( sal_uInt32 i
= 0; i
< ARLEN( bytes
); ++i
)
561 buf
.append( static_cast< sal_Int32
>( bytes
[ i
] ) );
562 OUString
sPipeName( buf
.makeStringAndClear() );
565 OSL_ASSERT( buf
.getLength() == 0 );
566 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "-accept=pipe,name=" ) );
567 buf
.append( sPipeName
);
568 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( ";urp;" ) );
573 OUSTR( "-nodefault" ),
574 OUSTR( "-norestore" ),
575 OUSTR( "-nocrashreport" ),
576 OUSTR( "-nolockcheck" ),
577 buf
.makeStringAndClear()
579 rtl_uString
* ar_args
[] = {
589 // start office process
590 oslProcess hProcess
= 0;
591 oslProcessError rc
= osl_executeProcess(
592 (path
+ OUSTR("soffice")).pData
, ar_args
, ARLEN( ar_args
),
593 osl_Process_DETACHED
,
595 0, // => current working dir
596 0, 0, // => no env vars
600 case osl_Process_E_None
:
601 osl_freeProcessHandle( hProcess
);
603 case osl_Process_E_NotFound
:
604 throw BootstrapException( OUSTR( "image not found!" ) );
605 case osl_Process_E_TimedOut
:
606 throw BootstrapException( OUSTR( "timout occured!" ) );
607 case osl_Process_E_NoPermission
:
608 throw BootstrapException( OUSTR( "permission denied!" ) );
609 case osl_Process_E_Unknown
:
610 throw BootstrapException( OUSTR( "unknown error!" ) );
611 case osl_Process_E_InvalidError
:
613 throw BootstrapException( OUSTR( "unmapped error!" ) );
616 // create a URL resolver
617 Reference
< bridge::XUnoUrlResolver
> xUrlResolver(
618 bridge::UnoUrlResolver::create( xLocalContext
) );
621 OSL_ASSERT( buf
.getLength() == 0 );
622 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno:pipe,name=" ) );
623 buf
.append( sPipeName
);
624 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(
625 ";urp;StarOffice.ComponentContext" ) );
626 OUString
sConnectString( buf
.makeStringAndClear() );
628 // wait until office is started
633 // try to connect to office
635 xUrlResolver
->resolve( sConnectString
), UNO_QUERY_THROW
);
638 catch ( connection::NoConnectException
& )
640 // wait 500 ms, then try to connect again
641 TimeValue tv
= { 0 /* secs */, 500000000 /* nanosecs */ };
642 ::osl::Thread::wait( tv
);
646 catch ( Exception
& e
)
648 throw BootstrapException(
649 OUSTR( "unexpected UNO exception caught: " ) + e
.Message
);
652 return xRemoteContext
;
655 OUString
bootstrap_expandUri(OUString
const & uri
) {
656 static char const PREFIX
[] = "vnd.sun.star.expand:";
657 return uri
.matchAsciiL(RTL_CONSTASCII_STRINGPARAM(PREFIX
))
658 ? cppuhelper::detail::expandMacros(
660 uri
.copy(RTL_CONSTASCII_LENGTH(PREFIX
)),
661 rtl_UriDecodeWithCharset
, RTL_TEXTENCODING_UTF8
))
667 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */