1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dp_help.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_desktop.hxx"
34 #include "dp_help.hrc"
35 #include "dp_backend.h"
37 #include "rtl/uri.hxx"
38 #include "osl/file.hxx"
39 #include "ucbhelper/content.hxx"
40 #include "comphelper/servicedecl.hxx"
41 #include "svtools/inettype.hxx"
43 #include <transex3/compilehelp.hxx>
44 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
45 #include <com/sun/star/util/XMacroExpander.hpp>
46 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
47 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
48 #include <com/sun/star/script/XInvocation.hpp>
50 using namespace ::dp_misc
;
51 using namespace ::com::sun::star
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::ucb
;
54 using ::rtl::OUString
;
56 namespace dp_registry
{
61 //==============================================================================
62 class BackendImpl
: public ::dp_registry::backend::PackageRegistryBackend
64 class PackageImpl
: public ::dp_registry::backend::Package
66 BackendImpl
* getMyBackend() const;
69 virtual beans::Optional
< beans::Ambiguous
<sal_Bool
> > isRegistered_(
70 ::osl::ResettableMutexGuard
& guard
,
71 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
72 Reference
<XCommandEnvironment
> const & xCmdEnv
);
73 virtual void processPackage_(
74 ::osl::ResettableMutexGuard
& guard
,
76 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
77 Reference
<XCommandEnvironment
> const & xCmdEnv
);
81 ::rtl::Reference
<PackageRegistryBackend
> const & myBackend
,
82 OUString
const & url
, OUString
const & name
,
83 Reference
<deployment::XPackageTypeInfo
> const & xPackageType
)
84 : Package( myBackend
, url
, name
, name
, xPackageType
)
87 friend class PackageImpl
;
89 // PackageRegistryBackend
90 virtual Reference
<deployment::XPackage
> bindPackage_(
91 OUString
const & url
, OUString
const & mediaType
,
92 Reference
<XCommandEnvironment
> const & xCmdEnv
);
94 void implProcessHelp( Reference
< deployment::XPackage
> xPackage
, bool doRegisterPackage
);
95 void implCollectXhpFiles( const rtl::OUString
& aDir
,
96 std::vector
< rtl::OUString
>& o_rXhpFileVector
);
97 rtl::OUString
getFlagFileURL( Reference
< deployment::XPackage
> xPackage
, const char* pFlagStr
);
98 rtl::OUString
getRegisteredFlagFileURL( Reference
< deployment::XPackage
> xPackage
);
99 rtl::OUString
getCompiledFlagFileURL( Reference
< deployment::XPackage
> xPackage
);
100 rtl::OUString
expandURL( const rtl::OUString
& aURL
);
101 Reference
< ucb::XSimpleFileAccess
> getFileAccess( void );
102 Reference
< ucb::XSimpleFileAccess
> m_xSFA
;
104 const Reference
<deployment::XPackageTypeInfo
> m_xHelpTypeInfo
;
105 Sequence
< Reference
<deployment::XPackageTypeInfo
> > m_typeInfos
;
108 BackendImpl( Sequence
<Any
> const & args
,
109 Reference
<XComponentContext
> const & xComponentContext
);
112 virtual Sequence
< Reference
<deployment::XPackageTypeInfo
> > SAL_CALL
113 getSupportedPackageTypes() throw (RuntimeException
);
116 //______________________________________________________________________________
117 BackendImpl::BackendImpl(
118 Sequence
<Any
> const & args
,
119 Reference
<XComponentContext
> const & xComponentContext
)
120 : PackageRegistryBackend( args
, xComponentContext
),
121 m_xHelpTypeInfo( new Package::TypeInfo(
122 OUSTR("application/vnd.sun.star.help"),
124 getResourceString(RID_STR_HELP
),
125 RID_IMG_HELP
, RID_IMG_HELP_HC
) ),
128 m_typeInfos
[ 0 ] = m_xHelpTypeInfo
;
132 //______________________________________________________________________________
133 Sequence
< Reference
<deployment::XPackageTypeInfo
> >
134 BackendImpl::getSupportedPackageTypes() throw (RuntimeException
)
139 // PackageRegistryBackend
140 //______________________________________________________________________________
141 Reference
<deployment::XPackage
> BackendImpl::bindPackage_(
142 OUString
const & url
, OUString
const & mediaType_
,
143 Reference
<XCommandEnvironment
> const & xCmdEnv
)
145 // we don't support auto detection:
146 if (mediaType_
.getLength() == 0)
147 throw lang::IllegalArgumentException(
148 StrCannotDetectMediaType::get() + url
,
149 static_cast<OWeakObject
*>(this), static_cast<sal_Int16
>(-1) );
151 String type
, subType
;
152 INetContentTypeParameterList params
;
153 if (INetContentTypes::parse( mediaType_
, type
, subType
, ¶ms
))
155 if (type
.EqualsIgnoreCaseAscii("application"))
157 ::ucbhelper::Content
ucbContent( url
, xCmdEnv
);
158 if (subType
.EqualsIgnoreCaseAscii(
159 "vnd.sun.star.help"))
161 return new PackageImpl( this, url
,
162 ucbContent
.getPropertyValue( StrTitle::get() ).get
<OUString
>(), m_xHelpTypeInfo
);
166 throw lang::IllegalArgumentException(
167 StrUnsupportedMediaType::get() + mediaType_
,
168 static_cast<OWeakObject
*>(this),
169 static_cast<sal_Int16
>(-1) );
173 //##############################################################################
176 BackendImpl
* BackendImpl::PackageImpl::getMyBackend() const
178 BackendImpl
* pBackend
= static_cast<BackendImpl
*>(m_myBackend
.get());
179 if (NULL
== pBackend
)
181 //May throw a DisposedException
183 //We should never get here...
184 throw RuntimeException(
185 OUSTR("Failed to get the BackendImpl"),
186 static_cast<OWeakObject
*>(const_cast<PackageImpl
*>(this)));
191 //______________________________________________________________________________
192 beans::Optional
< beans::Ambiguous
<sal_Bool
> >
193 BackendImpl::PackageImpl::isRegistered_(
194 ::osl::ResettableMutexGuard
&,
195 ::rtl::Reference
<AbortChannel
> const &,
196 Reference
<XCommandEnvironment
> const & )
198 BackendImpl
* that
= getMyBackend();
199 Reference
< deployment::XPackage
> xThisPackage( this );
200 rtl::OUString aRegisteredFlagFile
= that
->getRegisteredFlagFileURL( xThisPackage
);
202 Reference
< ucb::XSimpleFileAccess
> xSFA
= that
->getFileAccess();
203 bool bReg
= xSFA
->exists( aRegisteredFlagFile
);
205 return beans::Optional
< beans::Ambiguous
<sal_Bool
> >( true, beans::Ambiguous
<sal_Bool
>( bReg
, false ) );
208 //______________________________________________________________________________
209 void BackendImpl::PackageImpl::processPackage_(
210 ::osl::ResettableMutexGuard
&,
211 bool doRegisterPackage
,
212 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
213 Reference
<XCommandEnvironment
> const & xCmdEnv
)
215 (void)doRegisterPackage
;
219 BackendImpl
* that
= getMyBackend();
220 Reference
< deployment::XPackage
> xThisPackage( this );
221 that
->implProcessHelp( xThisPackage
, doRegisterPackage
);
224 //##############################################################################
226 static rtl::OUString
aSlash( rtl::OUString::createFromAscii( "/" ) );
227 static rtl::OUString
aHelpStr( rtl::OUString::createFromAscii( "help" ) );
229 void BackendImpl::implProcessHelp
230 ( Reference
< deployment::XPackage
> xPackage
, bool doRegisterPackage
)
235 Reference
< ucb::XSimpleFileAccess
> xSFA
= getFileAccess();
237 rtl::OUString aRegisteredFlagFile
= getRegisteredFlagFileURL( xPackage
);
238 if( !doRegisterPackage
)
240 if( xSFA
->exists( aRegisteredFlagFile
) )
241 xSFA
->kill( aRegisteredFlagFile
);
245 bool bCompile
= true;
246 rtl::OUString aCompiledFlagFile
= getCompiledFlagFileURL( xPackage
);
247 if( xSFA
->exists( aCompiledFlagFile
) )
252 rtl::OUString aHelpURL
= xPackage
->getURL();
253 rtl::OUString aExpandedHelpURL
= expandURL( aHelpURL
);
254 rtl::OUString aName
= xPackage
->getName();
255 if( !xSFA
->isFolder( aExpandedHelpURL
) )
257 rtl::OUString aErrStr
= getResourceString( RID_STR_HELPPROCESSING_GENERAL_ERROR
);
258 aErrStr
+= rtl::OUString::createFromAscii( "No help folder" );
259 OWeakObject
* oWeakThis
= static_cast<OWeakObject
*>(this);
260 throw deployment::DeploymentException( rtl::OUString(), oWeakThis
,
261 makeAny( uno::Exception( aErrStr
, oWeakThis
) ) );
264 Reference
<XComponentContext
> const & xContext
= getComponentContext();
265 Reference
< script::XInvocation
> xInvocation
;
270 xInvocation
= Reference
< script::XInvocation
>(
271 xContext
->getServiceManager()->createInstanceWithContext( rtl::OUString::createFromAscii(
272 "com.sun.star.help.HelpIndexer" ), xContext
) , UNO_QUERY
);
276 // i98680: Survive missing lucene
281 Sequence
< rtl::OUString
> aLanguageFolderSeq
= xSFA
->getFolderContents( aExpandedHelpURL
, true );
282 sal_Int32 nLangCount
= aLanguageFolderSeq
.getLength();
283 const rtl::OUString
* pSeq
= aLanguageFolderSeq
.getConstArray();
284 for( sal_Int32 iLang
= 0 ; iLang
< nLangCount
; ++iLang
)
286 rtl::OUString aLangURL
= pSeq
[iLang
];
287 if( xSFA
->isFolder( aLangURL
) )
289 std::vector
< rtl::OUString
> aXhpFileVector
;
291 // Delete (old) files in any case to allow compiler to be started every time
292 rtl::OUString
aLangWithPureNameURL( aLangURL
);
293 aLangWithPureNameURL
+= aSlash
;
294 aLangWithPureNameURL
+= aHelpStr
;
295 rtl::OUString
aDbFile( aLangWithPureNameURL
);
296 aDbFile
+= rtl::OUString::createFromAscii( ".db" );
297 if( xSFA
->exists( aDbFile
) )
298 xSFA
->kill( aDbFile
);
299 rtl::OUString
aHtFile( aLangWithPureNameURL
);
300 aHtFile
+= rtl::OUString::createFromAscii( ".ht" );
301 if( xSFA
->exists( aHtFile
) )
302 xSFA
->kill( aHtFile
);
303 rtl::OUString
aKeyFile( aLangWithPureNameURL
);
304 aKeyFile
+= rtl::OUString::createFromAscii( ".key" );
305 if( xSFA
->exists( aKeyFile
) )
306 xSFA
->kill( aKeyFile
);
308 // calculate jar file URL
309 rtl::OUString
aJarFile( aLangURL
);
311 aJarFile
+= aHelpStr
;
312 aJarFile
+= rtl::OUString::createFromAscii( ".jar" );
313 // remove in any case to clean up
314 if( xSFA
->exists( aJarFile
) )
315 xSFA
->kill( aJarFile
);
317 rtl::OUString aEncodedJarFilePath
= rtl::Uri::encode( aJarFile
,
318 rtl_UriCharClassPchar
, rtl_UriEncodeIgnoreEscapes
, RTL_TEXTENCODING_UTF8
);
319 rtl::OUString aDestBasePath
= rtl::OUString::createFromAscii( "vnd.sun.star.pkg://" );
320 aDestBasePath
+= aEncodedJarFilePath
;
321 aDestBasePath
+= rtl::OUString::createFromAscii( "/" );
323 sal_Int32 nLenLangFolderURL
= aLangURL
.getLength() + 1;
325 Sequence
< rtl::OUString
> aSubLangSeq
= xSFA
->getFolderContents( aLangURL
, true );
326 sal_Int32 nSubLangCount
= aSubLangSeq
.getLength();
327 const rtl::OUString
* pSubLangSeq
= aSubLangSeq
.getConstArray();
328 for( sal_Int32 iSubLang
= 0 ; iSubLang
< nSubLangCount
; ++iSubLang
)
330 rtl::OUString aSubFolderURL
= pSubLangSeq
[iSubLang
];
331 if( !xSFA
->isFolder( aSubFolderURL
) )
334 implCollectXhpFiles( aSubFolderURL
, aXhpFileVector
);
336 // Copy to package (later: move?)
337 rtl::OUString aDestPath
= aDestBasePath
;
338 rtl::OUString aPureFolderName
= aSubFolderURL
.copy( nLenLangFolderURL
);
339 aDestPath
+= aPureFolderName
;
340 xSFA
->copy( aSubFolderURL
, aDestPath
);
344 sal_Int32 nXhpFileCount
= aXhpFileVector
.size();
345 rtl::OUString
* pXhpFiles
= new rtl::OUString
[nXhpFileCount
];
346 for( sal_Int32 iXhp
= 0 ; iXhp
< nXhpFileCount
; ++iXhp
)
348 rtl::OUString aXhpFile
= aXhpFileVector
[iXhp
];
349 rtl::OUString aXhpRelFile
= aXhpFile
.copy( nLenLangFolderURL
);
350 pXhpFiles
[iXhp
] = aXhpRelFile
;
353 HelpProcessingErrorInfo aErrorInfo
;
354 bool bSuccess
= compileExtensionHelp( aHelpStr
, aLangURL
,
355 nXhpFileCount
, pXhpFiles
, aErrorInfo
);
357 if( bSuccess
&& xInvocation
.is() )
359 Sequence
<uno::Any
> aParamsSeq( 6 );
361 aParamsSeq
[0] = uno::makeAny( rtl::OUString::createFromAscii( "-lang" ) );
364 sal_Int32 nLastSlash
= aLangURL
.lastIndexOf( '/' );
365 if( nLastSlash
!= -1 )
366 aLang
= aLangURL
.copy( nLastSlash
+ 1 );
368 aLang
= rtl::OUString::createFromAscii( "en" );
369 aParamsSeq
[1] = uno::makeAny( aLang
);
371 aParamsSeq
[2] = uno::makeAny( rtl::OUString::createFromAscii( "-mod" ) );
372 aParamsSeq
[3] = uno::makeAny( rtl::OUString::createFromAscii( "help" ) );
374 aParamsSeq
[4] = uno::makeAny( rtl::OUString::createFromAscii( "-zipdir" ) );
375 rtl::OUString aSystemPath
;
376 osl::FileBase::getSystemPathFromFileURL( aLangURL
, aSystemPath
);
377 aParamsSeq
[5] = uno::makeAny( aSystemPath
);
379 Sequence
< sal_Int16
> aOutParamIndex
;
380 Sequence
< uno::Any
> aOutParam
;
381 uno::Any aRet
= xInvocation
->invoke( rtl::OUString::createFromAscii( "createIndex" ),
382 aParamsSeq
, aOutParamIndex
, aOutParam
);
387 USHORT nErrStrId
= 0;
388 switch( aErrorInfo
.m_eErrorClass
)
390 case HELPPROCESSING_GENERAL_ERROR
:
391 case HELPPROCESSING_INTERNAL_ERROR
: nErrStrId
= RID_STR_HELPPROCESSING_GENERAL_ERROR
; break;
392 case HELPPROCESSING_XMLPARSING_ERROR
: nErrStrId
= RID_STR_HELPPROCESSING_XMLPARSING_ERROR
; break;
396 rtl::OUString aErrStr
;
399 aErrStr
= getResourceString( nErrStrId
);
402 rtl::OUString
aErrMsg( aErrorInfo
.m_aErrorMsg
);
403 sal_Unicode nCR
= 13, nLF
= 10;
404 sal_Int32 nSearchCR
= aErrMsg
.indexOf( nCR
);
405 sal_Int32 nSearchLF
= aErrMsg
.indexOf( nLF
);
407 if( nSearchCR
!= -1 || nSearchLF
!= -1 )
409 if( nSearchCR
== -1 )
411 else if( nSearchLF
== -1 )
414 nCopy
= ( nSearchCR
< nSearchLF
) ? nSearchCR
: nSearchLF
;
416 aErrMsg
= aErrMsg
.copy( 0, nCopy
);
419 if( nErrStrId
== RID_STR_HELPPROCESSING_XMLPARSING_ERROR
&& aErrorInfo
.m_aXMLParsingFile
.getLength() )
421 aErrStr
+= rtl::OUString::createFromAscii( " in " );
423 rtl::OUString aDecodedFile
= rtl::Uri::decode( aErrorInfo
.m_aXMLParsingFile
,
424 rtl_UriDecodeWithCharset
, RTL_TEXTENCODING_UTF8
);
425 aErrStr
+= aDecodedFile
;
426 if( aErrorInfo
.m_nXMLParsingLine
!= -1 )
428 aErrStr
+= rtl::OUString::createFromAscii( ", line " );
429 aErrStr
+= ::rtl::OUString::valueOf( aErrorInfo
.m_nXMLParsingLine
);
434 OWeakObject
* oWeakThis
= static_cast<OWeakObject
*>(this);
435 throw deployment::DeploymentException( rtl::OUString(), oWeakThis
,
436 makeAny( uno::Exception( aErrStr
, oWeakThis
) ) );
441 // Write compiled flag file (this code is only reached in case of success)
442 Reference
< io::XOutputStream
> xOutputStream
= xSFA
->openFileWrite( aCompiledFlagFile
);
443 if( xOutputStream
.is() )
444 xOutputStream
->closeOutput();
448 // Write registered flag file (this code is only reached in case of success)
449 if( !xSFA
->exists( aRegisteredFlagFile
) )
451 Reference
< io::XOutputStream
> xOutputStream
= xSFA
->openFileWrite( aRegisteredFlagFile
);
452 if( xOutputStream
.is() )
453 xOutputStream
->closeOutput();
457 rtl::OUString
BackendImpl::getFlagFileURL( Reference
< deployment::XPackage
> xPackage
, const char* pFlagStr
)
459 rtl::OUString aRetURL
;
462 rtl::OUString aHelpURL
= xPackage
->getURL();
463 aRetURL
= expandURL( aHelpURL
);
464 aRetURL
+= rtl::OUString::createFromAscii( pFlagStr
);
468 rtl::OUString
BackendImpl::getRegisteredFlagFileURL( Reference
< deployment::XPackage
> xPackage
)
470 return getFlagFileURL( xPackage
, "/RegisteredFlag" );
473 rtl::OUString
BackendImpl::getCompiledFlagFileURL( Reference
< deployment::XPackage
> xPackage
)
475 return getFlagFileURL( xPackage
, "/CompiledFlag" );
478 rtl::OUString
BackendImpl::expandURL( const rtl::OUString
& aURL
)
480 static Reference
< util::XMacroExpander
> xMacroExpander
;
481 static Reference
< uri::XUriReferenceFactory
> xFac
;
483 if( !xMacroExpander
.is() || !xFac
.is() )
485 Reference
<XComponentContext
> const & xContext
= getComponentContext();
488 xFac
= Reference
< uri::XUriReferenceFactory
>(
489 xContext
->getServiceManager()->createInstanceWithContext( rtl::OUString::createFromAscii(
490 "com.sun.star.uri.UriReferenceFactory"), xContext
) , UNO_QUERY
);
494 throw RuntimeException(
495 ::rtl::OUString::createFromAscii(
496 "dp_registry::backend::help::BackendImpl::expandURL(), "
497 "could not instatiate UriReferenceFactory." ),
498 Reference
< XInterface
>() );
501 xMacroExpander
= Reference
< util::XMacroExpander
>(
502 xContext
->getValueByName(
503 ::rtl::OUString::createFromAscii( "/singletons/com.sun.star.util.theMacroExpander" ) ),
507 rtl::OUString aRetURL
= aURL
;
508 if( xMacroExpander
.is() )
510 Reference
< uri::XUriReference
> uriRef
;
513 uriRef
= Reference
< uri::XUriReference
>( xFac
->parse( aRetURL
), UNO_QUERY
);
516 Reference
< uri::XVndSunStarExpandUrl
> sxUri( uriRef
, UNO_QUERY
);
520 aRetURL
= sxUri
->expand( xMacroExpander
);
527 void BackendImpl::implCollectXhpFiles( const rtl::OUString
& aDir
,
528 std::vector
< rtl::OUString
>& o_rXhpFileVector
)
530 Reference
< ucb::XSimpleFileAccess
> xSFA
= getFileAccess();
532 // Scan xhp files recursively
533 Sequence
< rtl::OUString
> aSeq
= xSFA
->getFolderContents( aDir
, true );
534 sal_Int32 nCount
= aSeq
.getLength();
535 const rtl::OUString
* pSeq
= aSeq
.getConstArray();
536 for( sal_Int32 i
= 0 ; i
< nCount
; ++i
)
538 rtl::OUString aURL
= pSeq
[i
];
539 if( xSFA
->isFolder( aURL
) )
541 implCollectXhpFiles( aURL
, o_rXhpFileVector
);
545 sal_Int32 nLastDot
= aURL
.lastIndexOf( '.' );
548 rtl::OUString aExt
= aURL
.copy( nLastDot
+ 1 );
549 if( aExt
.equalsIgnoreAsciiCase( rtl::OUString::createFromAscii( "xhp" ) ) )
550 o_rXhpFileVector
.push_back( aURL
);
556 Reference
< ucb::XSimpleFileAccess
> BackendImpl::getFileAccess( void )
560 Reference
<XComponentContext
> const & xContext
= getComponentContext();
563 m_xSFA
= Reference
< ucb::XSimpleFileAccess
>(
564 xContext
->getServiceManager()->createInstanceWithContext(
565 rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
566 xContext
), UNO_QUERY
);
570 throw RuntimeException(
571 ::rtl::OUString::createFromAscii(
572 "dp_registry::backend::help::BackendImpl::getFileAccess(), "
573 "could not instatiate SimpleFileAccess." ),
574 Reference
< XInterface
>() );
582 namespace sdecl
= comphelper::service_decl
;
583 sdecl::class_
<BackendImpl
, sdecl::with_args
<true> > serviceBI
;
584 extern sdecl::ServiceDecl
const serviceDecl(
586 "com.sun.star.comp.deployment.help.PackageRegistryBackend",
587 BACKEND_SERVICE_NAME
);
590 } // namespace backend
591 } // namespace dp_registry