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