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