1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_desktop.hxx"
30 
31 #include "dp_help.hrc"
32 #include "dp_backend.h"
33 #include "dp_helpbackenddb.hxx"
34 #include "dp_ucb.h"
35 #include "rtl/uri.hxx"
36 #include "osl/file.hxx"
37 #include "rtl/bootstrap.hxx"
38 #include "ucbhelper/content.hxx"
39 #include "comphelper/servicedecl.hxx"
40 #include "svl/inettype.hxx"
41 #include "unotools/pathoptions.hxx"
42 
43 #include <l10ntools/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>
49 #include "boost/optional.hpp"
50 
51 using namespace ::dp_misc;
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::ucb;
55 using ::rtl::OUString;
56 
57 namespace dp_registry {
58 namespace backend {
59 namespace help {
60 namespace {
61 
62 //==============================================================================
63 class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend
64 {
65     class PackageImpl : public ::dp_registry::backend::Package
66     {
67         BackendImpl * getMyBackend() const;
68 
69 //        HelpBackendDb::Data m_dbData;
70 
71         // Package
72         virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
73             ::osl::ResettableMutexGuard & guard,
74             ::rtl::Reference<AbortChannel> const & abortChannel,
75             Reference<XCommandEnvironment> const & xCmdEnv );
76         virtual void processPackage_(
77             ::osl::ResettableMutexGuard & guard,
78             bool registerPackage,
79             bool startup,
80             ::rtl::Reference<AbortChannel> const & abortChannel,
81             Reference<XCommandEnvironment> const & xCmdEnv );
82 
83 
84     public:
85         PackageImpl(
86             ::rtl::Reference<PackageRegistryBackend> const & myBackend,
87             OUString const & url, OUString const & name,
88             Reference<deployment::XPackageTypeInfo> const & xPackageType,
89             bool bRemoved, OUString const & identifier);
90 
91         bool extensionContainsCompiledHelp();
92 
93         //XPackage
94         virtual css::beans::Optional< ::rtl::OUString > SAL_CALL getRegistrationDataURL()
95             throw (deployment::ExtensionRemovedException, css::uno::RuntimeException);
96     };
97     friend class PackageImpl;
98 
99     // PackageRegistryBackend
100     virtual Reference<deployment::XPackage> bindPackage_(
101         OUString const & url, OUString const & mediaType,
102         sal_Bool bRemoved, OUString const & identifier,
103         Reference<XCommandEnvironment> const & xCmdEnv );
104 
105 	void implProcessHelp( PackageImpl * package, bool doRegisterPackage,
106                           Reference<ucb::XCommandEnvironment> const & xCmdEnv);
107 	void implCollectXhpFiles( const rtl::OUString& aDir,
108 		std::vector< rtl::OUString >& o_rXhpFileVector );
109 
110     void addDataToDb(OUString const & url, HelpBackendDb::Data const & data);
111     ::boost::optional<HelpBackendDb::Data> readDataFromDb(OUString const & url);
112     bool hasActiveEntry(OUString const & url);
113     void revokeEntryFromDb(OUString const & url);
114     bool activateEntry(OUString const & url);
115 
116 	Reference< ucb::XSimpleFileAccess > getFileAccess( void );
117 	Reference< ucb::XSimpleFileAccess > m_xSFA;
118 
119     const Reference<deployment::XPackageTypeInfo> m_xHelpTypeInfo;
120     Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
121     std::auto_ptr<HelpBackendDb> m_backendDb;
122 
123 public:
124     BackendImpl( Sequence<Any> const & args,
125                  Reference<XComponentContext> const & xComponentContext );
126 
127     // XPackageRegistry
128     virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
129 	    getSupportedPackageTypes() throw (RuntimeException);
130     virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
131         throw (deployment::DeploymentException,
132                uno::RuntimeException);
133 
134 };
135 
136 //______________________________________________________________________________
137 BackendImpl::BackendImpl(
138     Sequence<Any> const & args,
139     Reference<XComponentContext> const & xComponentContext )
140     : PackageRegistryBackend( args, xComponentContext ),
141       m_xHelpTypeInfo( new Package::TypeInfo(
142                                OUSTR("application/vnd.sun.star.help"),
143                                rtl::OUString(),
144                                getResourceString(RID_STR_HELP),
145                                RID_IMG_HELP, RID_IMG_HELP_HC ) ),
146       m_typeInfos( 1 )
147 {
148     m_typeInfos[ 0 ] = m_xHelpTypeInfo;
149     if (!transientMode())
150     {
151         OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml"));
152         m_backendDb.reset(
153             new HelpBackendDb(getComponentContext(), dbFile));
154 
155         //clean up data folders which are no longer used.
156         //This must not be done in the same process where the help files
157         //are still registers. Only after revoking and restarting OOo the folders
158         //can be removed. This works now, because the extension manager is a singleton
159         //and the backends are only create once per process.
160         ::std::list<OUString> folders = m_backendDb->getAllDataUrls();
161         deleteUnusedFolders(OUString(), folders);
162    }
163 }
164 
165 // XPackageRegistry
166 //______________________________________________________________________________
167 Sequence< Reference<deployment::XPackageTypeInfo> >
168 BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
169 {
170     return m_typeInfos;
171 }
172 
173 void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
174         throw (deployment::DeploymentException,
175                uno::RuntimeException)
176 {
177     if (m_backendDb.get())
178         m_backendDb->removeEntry(url);
179 }
180 
181 // PackageRegistryBackend
182 //______________________________________________________________________________
183 Reference<deployment::XPackage> BackendImpl::bindPackage_(
184     OUString const & url, OUString const & mediaType_,
185     sal_Bool bRemoved, OUString const & identifier,
186     Reference<XCommandEnvironment> const & xCmdEnv )
187 {
188 	// we don't support auto detection:
189     if (mediaType_.getLength() == 0)
190         throw lang::IllegalArgumentException(
191             StrCannotDetectMediaType::get() + url,
192             static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
193 
194     String type, subType;
195     INetContentTypeParameterList params;
196 	if (INetContentTypes::parse( mediaType_, type, subType, &params ))
197     {
198         if (type.EqualsIgnoreCaseAscii("application"))
199         {
200             OUString name;
201             if (!bRemoved)
202             {
203                 ::ucbhelper::Content ucbContent( url, xCmdEnv );
204                 name = ucbContent.getPropertyValue(
205                     StrTitle::get() ).get<OUString>();
206             }
207 
208             if (subType.EqualsIgnoreCaseAscii(
209                     "vnd.sun.star.help"))
210 			{
211                 return new PackageImpl(
212                     this, url, name, m_xHelpTypeInfo, bRemoved,
213                     identifier);
214             }
215         }
216     }
217     throw lang::IllegalArgumentException(
218         StrUnsupportedMediaType::get() + mediaType_,
219         static_cast<OWeakObject *>(this),
220         static_cast<sal_Int16>(-1) );
221 }
222 
223 void BackendImpl::addDataToDb(
224     OUString const & url, HelpBackendDb::Data const & data)
225 {
226     if (m_backendDb.get())
227         m_backendDb->addEntry(url, data);
228 }
229 
230 ::boost::optional<HelpBackendDb::Data> BackendImpl::readDataFromDb(
231     OUString const & url)
232 {
233     ::boost::optional<HelpBackendDb::Data> data;
234     if (m_backendDb.get())
235         data = m_backendDb->getEntry(url);
236     return data;
237 }
238 
239 bool BackendImpl::hasActiveEntry(OUString const & url)
240 {
241     if (m_backendDb.get())
242         return m_backendDb->hasActiveEntry(url);
243     return false;
244 }
245 
246 void BackendImpl::revokeEntryFromDb(OUString const & url)
247 {
248     if (m_backendDb.get())
249         m_backendDb->revokeEntry(url);
250 }
251 
252 bool BackendImpl::activateEntry(OUString const & url)
253 {
254     if (m_backendDb.get())
255         return m_backendDb->activateEntry(url);
256     return false;
257 }
258 
259 
260 //##############################################################################
261 BackendImpl::PackageImpl::PackageImpl(
262     ::rtl::Reference<PackageRegistryBackend> const & myBackend,
263     OUString const & url, OUString const & name,
264     Reference<deployment::XPackageTypeInfo> const & xPackageType,
265     bool bRemoved, OUString const & identifier)
266     : Package( myBackend, url, name, name, xPackageType, bRemoved,
267                identifier)
268 {
269 }
270 
271 // Package
272 BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
273 {
274     BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
275     if (NULL == pBackend)
276     {
277         //May throw a DisposedException
278         check();
279         //We should never get here...
280         throw RuntimeException(
281             OUSTR("Failed to get the BackendImpl"),
282             static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
283     }
284     return pBackend;
285 }
286 
287 bool BackendImpl::PackageImpl::extensionContainsCompiledHelp()
288 {
289     bool bCompiled = true;
290     rtl::OUString aExpandedHelpURL = dp_misc::expandUnoRcUrl(getURL());
291 
292     ::osl::Directory helpFolder(aExpandedHelpURL);
293     if ( helpFolder.open() == ::osl::File::E_None)
294     {
295         //iterate over the contents of the help folder
296         //We assume that all folders withing the help folder contain language specific
297         //help files. If just one of them does not contain compiled help then this
298         //function returns false.
299         ::osl::DirectoryItem item;
300         ::osl::File::RC errorNext = ::osl::File::E_None;
301         while ((errorNext = helpFolder.getNextItem(item)) == ::osl::File::E_None)
302         {
303             //No find the language folders
304             ::osl::FileStatus stat(FileStatusMask_Type | FileStatusMask_FileName |FileStatusMask_FileURL);
305             if (item.getFileStatus(stat) == ::osl::File::E_None)
306             {
307                 if (stat.getFileType() != ::osl::FileStatus::Directory)
308                     continue;
309 
310                 //look if there is the folder help.idxl in the language folder
311                 OUString compUrl(stat.getFileURL() + OUSTR("/help.idxl"));
312                 ::osl::Directory compiledFolder(compUrl);
313                 if (compiledFolder.open() != ::osl::File::E_None)
314                 {
315                     bCompiled = false;
316                     break;
317                 }
318             }
319             else
320             {
321                 //Error
322                 OSL_ASSERT(0);
323                 bCompiled = false;
324                 break;
325             }
326         }
327         if (errorNext != ::osl::File::E_NOENT
328             && errorNext != ::osl::File::E_None)
329         {
330             //Error
331             OSL_ASSERT(0);
332             bCompiled = false;
333         }
334     }
335     return bCompiled;
336 }
337 
338 //______________________________________________________________________________
339 beans::Optional< beans::Ambiguous<sal_Bool> >
340 BackendImpl::PackageImpl::isRegistered_(
341     ::osl::ResettableMutexGuard &,
342     ::rtl::Reference<AbortChannel> const &,
343     Reference<XCommandEnvironment> const & )
344 {
345     BackendImpl * that = getMyBackend();
346 
347 	bool bReg = false;
348     if (that->hasActiveEntry(getURL()))
349         bReg = true;
350 
351 	return beans::Optional< beans::Ambiguous<sal_Bool> >( true, beans::Ambiguous<sal_Bool>( bReg, false ) );
352 }
353 
354 //______________________________________________________________________________
355 void BackendImpl::PackageImpl::processPackage_(
356     ::osl::ResettableMutexGuard &,
357     bool doRegisterPackage,
358     bool /* startup */,
359     ::rtl::Reference<AbortChannel> const & abortChannel,
360     Reference<XCommandEnvironment> const & xCmdEnv )
361 {
362 	(void)doRegisterPackage;
363 	(void)abortChannel;
364 	(void)xCmdEnv;
365 
366     BackendImpl* that = getMyBackend();
367 	that->implProcessHelp( this, doRegisterPackage, xCmdEnv);
368 }
369 
370 beans::Optional< OUString > BackendImpl::PackageImpl::getRegistrationDataURL()
371     throw (deployment::ExtensionRemovedException,
372            css::uno::RuntimeException)
373 {
374     if (m_bRemoved)
375         throw deployment::ExtensionRemovedException();
376 
377     ::boost::optional<HelpBackendDb::Data> data =
378           getMyBackend()->readDataFromDb(getURL());
379 
380     if (data && getMyBackend()->hasActiveEntry(getURL()))
381         return beans::Optional<OUString>(true, data->dataUrl);
382 
383     return beans::Optional<OUString>(true, OUString());
384 }
385 
386 
387 //##############################################################################
388 
389 static rtl::OUString aSlash( rtl::OUString::createFromAscii( "/" ) );
390 static rtl::OUString aHelpStr( rtl::OUString::createFromAscii( "help" ) );
391 
392 
393 void BackendImpl::implProcessHelp(
394     PackageImpl * package, bool doRegisterPackage,
395     Reference<ucb::XCommandEnvironment> const & xCmdEnv)
396 {
397     Reference< deployment::XPackage > xPackage(package);
398     OSL_ASSERT(xPackage.is());
399     if (doRegisterPackage)
400     {
401         //revive already processed help if possible
402         if ( !activateEntry(xPackage->getURL()))
403         {
404             HelpBackendDb::Data data;
405             data.dataUrl = xPackage->getURL();
406             if (!package->extensionContainsCompiledHelp())
407             {
408                 const OUString sHelpFolder = createFolder(OUString(), xCmdEnv);
409                 data.dataUrl = sHelpFolder;
410 
411                 Reference< ucb::XSimpleFileAccess > xSFA = getFileAccess();
412                 rtl::OUString aHelpURL = xPackage->getURL();
413                 rtl::OUString aExpandedHelpURL = dp_misc::expandUnoRcUrl( aHelpURL );
414                 rtl::OUString aName = xPackage->getName();
415                 if( !xSFA->isFolder( aExpandedHelpURL ) )
416                 {
417                     rtl::OUString aErrStr = getResourceString( RID_STR_HELPPROCESSING_GENERAL_ERROR );
418                     aErrStr += rtl::OUString::createFromAscii( "No help folder" );
419                     OWeakObject* oWeakThis = static_cast<OWeakObject *>(this);
420                     throw deployment::DeploymentException( rtl::OUString(), oWeakThis,
421                                                            makeAny( uno::Exception( aErrStr, oWeakThis ) ) );
422                 }
423 
424                 Reference<XComponentContext> const & xContext = getComponentContext();
425                 Reference< script::XInvocation > xInvocation;
426                 if( xContext.is() )
427                 {
428                     try
429                     {
430                         xInvocation = Reference< script::XInvocation >(
431                             xContext->getServiceManager()->createInstanceWithContext( rtl::OUString::createFromAscii(
432                                                                                           "com.sun.star.help.HelpIndexer" ), xContext ) , UNO_QUERY );
433                     }
434                     catch (Exception &)
435                     {
436                         // i98680: Survive missing lucene
437                     }
438                 }
439 
440                 // Scan languages
441                 Sequence< rtl::OUString > aLanguageFolderSeq = xSFA->getFolderContents( aExpandedHelpURL, true );
442                 sal_Int32 nLangCount = aLanguageFolderSeq.getLength();
443                 const rtl::OUString* pSeq = aLanguageFolderSeq.getConstArray();
444                 for( sal_Int32 iLang = 0 ; iLang < nLangCount ; ++iLang )
445                 {
446                     rtl::OUString aLangURL = pSeq[iLang];
447                     if( xSFA->isFolder( aLangURL ) )
448                     {
449                         std::vector< rtl::OUString > aXhpFileVector;
450 
451                         // calculate jar file URL
452                         sal_Int32 indexStartSegment = aLangURL.lastIndexOf('/');
453                         // for example "/en"
454                         OUString langFolderURLSegment(
455                             aLangURL.copy(
456                                 indexStartSegment + 1, aLangURL.getLength() - indexStartSegment - 1));
457 
458                         //create the folder in the "temporary folder"
459                         ::ucbhelper::Content langFolderContent;
460                         const OUString langFolderDest = makeURL(sHelpFolder, langFolderURLSegment);
461                         const OUString langFolderDestExpanded = ::dp_misc::expandUnoRcUrl(langFolderDest);
462                         ::dp_misc::create_folder(
463                             &langFolderContent,
464                             langFolderDest, xCmdEnv);
465 
466                         rtl::OUString aJarFile(
467                             makeURL(sHelpFolder, langFolderURLSegment + aSlash + aHelpStr +
468                                     OUSTR(".jar")));
469                         aJarFile = ::dp_misc::expandUnoRcUrl(aJarFile);
470 
471                         rtl::OUString aEncodedJarFilePath = rtl::Uri::encode(
472                             aJarFile, rtl_UriCharClassPchar,
473                             rtl_UriEncodeIgnoreEscapes,
474                             RTL_TEXTENCODING_UTF8 );
475                         rtl::OUString aDestBasePath = rtl::OUString::createFromAscii( "vnd.sun.star.zip://" );
476                         aDestBasePath += aEncodedJarFilePath;
477                         aDestBasePath += rtl::OUString::createFromAscii( "/" );
478 
479                         sal_Int32 nLenLangFolderURL = aLangURL.getLength() + 1;
480 
481                         Sequence< rtl::OUString > aSubLangSeq = xSFA->getFolderContents( aLangURL, true );
482                         sal_Int32 nSubLangCount = aSubLangSeq.getLength();
483                         const rtl::OUString* pSubLangSeq = aSubLangSeq.getConstArray();
484                         for( sal_Int32 iSubLang = 0 ; iSubLang < nSubLangCount ; ++iSubLang )
485                         {
486                             rtl::OUString aSubFolderURL = pSubLangSeq[iSubLang];
487                             if( !xSFA->isFolder( aSubFolderURL ) )
488                                 continue;
489 
490                             implCollectXhpFiles( aSubFolderURL, aXhpFileVector );
491 
492                             // Copy to package (later: move?)
493                             rtl::OUString aDestPath = aDestBasePath;
494                             rtl::OUString aPureFolderName = aSubFolderURL.copy( nLenLangFolderURL );
495                             aDestPath += aPureFolderName;
496                             xSFA->copy( aSubFolderURL, aDestPath );
497                         }
498 
499                         // Call compiler
500                         sal_Int32 nXhpFileCount = aXhpFileVector.size();
501                         rtl::OUString* pXhpFiles = new rtl::OUString[nXhpFileCount];
502                         for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp )
503                         {
504                             rtl::OUString aXhpFile = aXhpFileVector[iXhp];
505                             rtl::OUString aXhpRelFile = aXhpFile.copy( nLenLangFolderURL );
506                             pXhpFiles[iXhp] = aXhpRelFile;
507                         }
508 
509                         rtl::OUString aOfficeHelpPath( SvtPathOptions().GetHelpPath() );
510                         rtl::OUString aOfficeHelpPathFileURL;
511                         ::osl::File::getFileURLFromSystemPath( aOfficeHelpPath, aOfficeHelpPathFileURL );
512 
513                         HelpProcessingErrorInfo aErrorInfo;
514                         bool bSuccess = compileExtensionHelp(
515                             aOfficeHelpPathFileURL, aHelpStr, aLangURL,
516                             nXhpFileCount, pXhpFiles,
517                             langFolderDestExpanded, aErrorInfo );
518 
519                         if( bSuccess && xInvocation.is() )
520                         {
521                             Sequence<uno::Any> aParamsSeq( 6 );
522 
523                             aParamsSeq[0] = uno::makeAny( rtl::OUString::createFromAscii( "-lang" ) );
524 
525                             rtl::OUString aLang;
526                             sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
527                             if( nLastSlash != -1 )
528                                 aLang = aLangURL.copy( nLastSlash + 1 );
529                             else
530                                 aLang = rtl::OUString::createFromAscii( "en" );
531                             aParamsSeq[1] = uno::makeAny( aLang );
532 
533                             aParamsSeq[2] = uno::makeAny( rtl::OUString::createFromAscii( "-mod" ) );
534                             aParamsSeq[3] = uno::makeAny( rtl::OUString::createFromAscii( "help" ) );
535 
536                             aParamsSeq[4] = uno::makeAny( rtl::OUString::createFromAscii( "-zipdir" ) );
537                             rtl::OUString aSystemPath;
538                             osl::FileBase::getSystemPathFromFileURL(
539                                 langFolderDestExpanded, aSystemPath );
540                             aParamsSeq[5] = uno::makeAny( aSystemPath );
541 
542                             Sequence< sal_Int16 > aOutParamIndex;
543                             Sequence< uno::Any > aOutParam;
544                             uno::Any aRet = xInvocation->invoke( rtl::OUString::createFromAscii( "createIndex" ),
545                                                                  aParamsSeq, aOutParamIndex, aOutParam );
546                         }
547 
548                         if( !bSuccess )
549                         {
550                             sal_uInt16 nErrStrId = 0;
551                             switch( aErrorInfo.m_eErrorClass )
552                             {
553                             case HELPPROCESSING_GENERAL_ERROR:
554                             case HELPPROCESSING_INTERNAL_ERROR:		nErrStrId = RID_STR_HELPPROCESSING_GENERAL_ERROR; break;
555                             case HELPPROCESSING_XMLPARSING_ERROR:	nErrStrId = RID_STR_HELPPROCESSING_XMLPARSING_ERROR; break;
556                             default: ;
557                             };
558 
559                             rtl::OUString aErrStr;
560                             if( nErrStrId != 0 )
561                             {
562                                 aErrStr = getResourceString( nErrStrId );
563 
564                                 // Remoce CR/LF
565                                 rtl::OUString aErrMsg( aErrorInfo.m_aErrorMsg );
566                                 sal_Unicode nCR = 13, nLF = 10;
567                                 sal_Int32 nSearchCR = aErrMsg.indexOf( nCR );
568                                 sal_Int32 nSearchLF = aErrMsg.indexOf( nLF );
569                                 sal_Int32 nCopy;
570                                 if( nSearchCR != -1 || nSearchLF != -1 )
571                                 {
572                                     if( nSearchCR == -1 )
573                                         nCopy = nSearchLF;
574                                     else if( nSearchLF == -1 )
575                                         nCopy = nSearchCR;
576                                     else
577                                         nCopy = ( nSearchCR < nSearchLF ) ? nSearchCR : nSearchLF;
578 
579                                     aErrMsg = aErrMsg.copy( 0, nCopy );
580                                 }
581                                 aErrStr += aErrMsg;
582                                 if( nErrStrId == RID_STR_HELPPROCESSING_XMLPARSING_ERROR && aErrorInfo.m_aXMLParsingFile.getLength() )
583                                 {
584                                     aErrStr += rtl::OUString::createFromAscii( " in " );
585 
586                                     rtl::OUString aDecodedFile = rtl::Uri::decode( aErrorInfo.m_aXMLParsingFile,
587                                                                                    rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
588                                     aErrStr += aDecodedFile;
589                                     if( aErrorInfo.m_nXMLParsingLine != -1 )
590                                     {
591                                         aErrStr += rtl::OUString::createFromAscii( ", line " );
592                                         aErrStr += ::rtl::OUString::valueOf( aErrorInfo.m_nXMLParsingLine );
593                                     }
594                                 }
595                             }
596 
597                             OWeakObject* oWeakThis = static_cast<OWeakObject *>(this);
598                             throw deployment::DeploymentException( rtl::OUString(), oWeakThis,
599                                                                    makeAny( uno::Exception( aErrStr, oWeakThis ) ) );
600                         }
601                     }
602                 }
603             }
604                 //Writing the data entry replaces writing the flag file. If we got to this
605                 //point the registration was successful.
606             addDataToDb(xPackage->getURL(), data);
607         }
608     } //if (doRegisterPackage)
609     else
610     {
611         revokeEntryFromDb(xPackage->getURL());
612     }
613 }
614 
615 
616 void BackendImpl::implCollectXhpFiles( const rtl::OUString& aDir,
617 	std::vector< rtl::OUString >& o_rXhpFileVector )
618 {
619 	Reference< ucb::XSimpleFileAccess > xSFA = getFileAccess();
620 
621 	// Scan xhp files recursively
622     Sequence< rtl::OUString > aSeq = xSFA->getFolderContents( aDir, true );
623     sal_Int32 nCount = aSeq.getLength();
624 	const rtl::OUString* pSeq = aSeq.getConstArray();
625 	for( sal_Int32 i = 0 ; i < nCount ; ++i )
626 	{
627 		rtl::OUString aURL = pSeq[i];
628 		if( xSFA->isFolder( aURL ) )
629 		{
630 			implCollectXhpFiles( aURL, o_rXhpFileVector );
631 		}
632 		else
633 		{
634 			sal_Int32 nLastDot = aURL.lastIndexOf( '.' );
635 			if( nLastDot != -1 )
636 			{
637 				rtl::OUString aExt = aURL.copy( nLastDot + 1 );
638 				if( aExt.equalsIgnoreAsciiCase( rtl::OUString::createFromAscii( "xhp" ) ) )
639 					o_rXhpFileVector.push_back( aURL );
640 			}
641 		}
642 	}
643 }
644 
645 Reference< ucb::XSimpleFileAccess > BackendImpl::getFileAccess( void )
646 {
647 	if( !m_xSFA.is() )
648 	{
649 		Reference<XComponentContext> const & xContext = getComponentContext();
650 		if( xContext.is() )
651 		{
652 			m_xSFA = Reference< ucb::XSimpleFileAccess >(
653 				xContext->getServiceManager()->createInstanceWithContext(
654 					rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
655 					xContext ), UNO_QUERY );
656 		}
657 		if( !m_xSFA.is() )
658 		{
659 			throw RuntimeException(
660 				::rtl::OUString::createFromAscii(
661 				"dp_registry::backend::help::BackendImpl::getFileAccess(), "
662 				"could not instatiate SimpleFileAccess." ),
663 				Reference< XInterface >() );
664 		}
665 	}
666 	return m_xSFA;
667 }
668 
669 } // anon namespace
670 
671 namespace sdecl = comphelper::service_decl;
672 sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
673 extern sdecl::ServiceDecl const serviceDecl(
674     serviceBI,
675     "com.sun.star.comp.deployment.help.PackageRegistryBackend",
676     BACKEND_SERVICE_NAME );
677 
678 } // namespace help
679 } // namespace backend
680 } // namespace dp_registry
681 
682