xref: /AOO41X/main/xmlhelp/source/cxxhelp/provider/databases.cxx (revision 79aad27f7f29270c03e208e3d687e8e3850af11d)
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_xmlhelp.hxx"
26 #include "db.hxx"
27 #ifndef _VOS_DIAGNOSE_HXX_
28 #include <vos/diagnose.hxx>
29 #endif
30 #include <osl/thread.h>
31 #include <rtl/uri.hxx>
32 #include <osl/file.hxx>
33 #include <rtl/memory.h>
34 #include <com/sun/star/lang/Locale.hpp>
35 #include <rtl/ustrbuf.hxx>
36 #include "inputstream.hxx"
37 #include <algorithm>
38 #include <string.h>
39 
40 // Extensible help
41 #include "com/sun/star/deployment/ExtensionManager.hpp"
42 #include "com/sun/star/deployment/thePackageManagerFactory.hpp"
43 #include <comphelper/processfactory.hxx>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/uno/XComponentContext.hpp>
46 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
47 #include <com/sun/star/beans/Optional.hpp>
48 #include <com/sun/star/beans/PropertyValue.hpp>
49 #include <com/sun/star/beans/NamedValue.hpp>
50 #include <com/sun/star/frame/XConfigManager.hpp>
51 #include <com/sun/star/util/XMacroExpander.hpp>
52 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
53 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
54 #include <com/sun/star/script/XInvocation.hpp>
55 #include <comphelper/locale.hxx>
56 
57 #include <com/sun/star/awt/XToolkit.hpp>
58 #include <com/sun/star/awt/XExtendedToolkit.hpp>
59 #include <com/sun/star/awt/XWindowPeer.hpp>
60 #include <com/sun/star/awt/XVclWindowPeer.hpp>
61 #include <com/sun/star/awt/XTopWindow.hpp>
62 
63 #include <l10ntools/compilehelp.hxx>
64 #include <comphelper/storagehelper.hxx>
65 
66 #include "databases.hxx"
67 #include "urlparameter.hxx"
68 
69 using namespace chelp;
70 using namespace com::sun::star;
71 using namespace com::sun::star::uno;
72 using namespace com::sun::star::io;
73 using namespace com::sun::star::container;
74 using namespace com::sun::star::i18n;
75 using namespace com::sun::star::lang;
76 using namespace com::sun::star::deployment;
77 using namespace com::sun::star::beans;
78 
79 
80 static rtl::OUString aSlash( rtl::OUString::createFromAscii( "/" ) );
81 static rtl::OUString aHelpFilesBaseName( rtl::OUString::createFromAscii( "help" ) );
82 static rtl::OUString aHelpMediaType( rtl::OUString::createFromAscii( "application/vnd.sun.star.help" ) );
83 
expandURL(const rtl::OUString & aURL)84 rtl::OUString Databases::expandURL( const rtl::OUString& aURL )
85 {
86     osl::MutexGuard aGuard( m_aMutex );
87     rtl::OUString aRetURL = expandURL( aURL, m_xContext );
88     return aRetURL;
89 }
90 
expandURL(const rtl::OUString & aURL,Reference<uno::XComponentContext> xContext)91 rtl::OUString Databases::expandURL( const rtl::OUString& aURL, Reference< uno::XComponentContext > xContext )
92 {
93     static Reference< util::XMacroExpander > xMacroExpander;
94     static Reference< uri::XUriReferenceFactory > xFac;
95 
96     if( !xContext.is() )
97         return rtl::OUString();
98 
99     if( !xMacroExpander.is() || !xFac.is() )
100     {
101         Reference< XMultiComponentFactory > xSMgr( xContext->getServiceManager(), UNO_QUERY );
102 
103         xFac = Reference< uri::XUriReferenceFactory >(
104             xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii(
105             "com.sun.star.uri.UriReferenceFactory"), xContext ) , UNO_QUERY );
106         if( !xFac.is() )
107         {
108             throw RuntimeException(
109                 ::rtl::OUString::createFromAscii( "Databases::expand(), could not instatiate UriReferenceFactory." ),
110                 Reference< XInterface >() );
111         }
112 
113         xMacroExpander = Reference< util::XMacroExpander >(
114             xContext->getValueByName(
115             ::rtl::OUString::createFromAscii( "/singletons/com.sun.star.util.theMacroExpander" ) ),
116             UNO_QUERY_THROW );
117     }
118 
119     rtl::OUString aRetURL = aURL;
120     if( xMacroExpander.is() )
121     {
122         Reference< uri::XUriReference > uriRef;
123         for (;;)
124         {
125             uriRef = Reference< uri::XUriReference >( xFac->parse( aRetURL ), UNO_QUERY );
126             if ( uriRef.is() )
127             {
128                 Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
129                 if( !sxUri.is() )
130                     break;
131 
132                 aRetURL = sxUri->expand( xMacroExpander );
133             }
134         }
135     }
136     return aRetURL;
137 }
138 
Databases(sal_Bool showBasic,const rtl::OUString & instPath,const com::sun::star::uno::Sequence<rtl::OUString> & imagesZipPaths,const rtl::OUString & productName,const rtl::OUString & productVersion,const rtl::OUString & styleSheet,Reference<uno::XComponentContext> xContext)139 Databases::Databases( sal_Bool showBasic,
140                       const rtl::OUString& instPath,
141                       const com::sun::star::uno::Sequence< rtl::OUString >& imagesZipPaths,
142                       const rtl::OUString& productName,
143                       const rtl::OUString& productVersion,
144                       const rtl::OUString& styleSheet,
145                       Reference< uno::XComponentContext > xContext )
146     : m_xContext( xContext ),
147       m_bShowBasic(showBasic),
148       m_nErrorDocLength( 0 ),
149       m_pErrorDoc( 0 ),
150       m_nCustomCSSDocLength( 0 ),
151       m_pCustomCSSDoc( 0 ),
152       m_aCSS(styleSheet.toAsciiLowerCase()),
153       newProdName(rtl::OUString::createFromAscii( "$[officename]" ) ),
154       newProdVersion(rtl::OUString::createFromAscii( "$[officeversion]" ) ),
155       prodName( rtl::OUString::createFromAscii( "%PRODUCTNAME" ) ),
156       prodVersion( rtl::OUString::createFromAscii( "%PRODUCTVERSION" ) ),
157       vendName( rtl::OUString::createFromAscii( "%VENDORNAME" ) ),
158       vendVersion( rtl::OUString::createFromAscii( "%VENDORVERSION" ) ),
159       vendShort( rtl::OUString::createFromAscii( "%VENDORSHORT" ) ),
160       m_aImagesZipPaths( imagesZipPaths ),
161       m_nSymbolsStyle( 0 )
162 {
163     m_xSMgr = Reference< XMultiComponentFactory >( m_xContext->getServiceManager(), UNO_QUERY );
164 
165     m_vAdd[0] = 12;
166     m_vAdd[1] = 15;
167     m_vAdd[2] = 11;
168     m_vAdd[3] = 14;
169     m_vAdd[4] = 12;
170     m_vAdd[5] = 13;
171     m_vAdd[6] = 16;
172 
173     m_vReplacement[0] = productName;
174     m_vReplacement[1] = productVersion;
175     // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
176     m_vReplacement[5] = productName;
177     m_vReplacement[6] = productVersion;
178 
179     setInstallPath( instPath );
180 
181     m_xSFA = Reference< ucb::XSimpleFileAccess >(
182         m_xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
183         m_xContext ), UNO_QUERY_THROW );
184 }
185 
~Databases()186 Databases::~Databases()
187 {
188     // release stylesheet
189 
190     delete[] m_pCustomCSSDoc;
191 
192     // release errorDocument
193 
194     delete[] m_pErrorDoc;
195 
196     // unload the databases
197 
198     {
199         // DatabasesTable
200         DatabasesTable::iterator it = m_aDatabases.begin();
201         while( it != m_aDatabases.end() )
202         {
203             delete it->second;
204             ++it;
205         }
206     }
207 
208     {
209         //  ModInfoTable
210 
211         ModInfoTable::iterator it = m_aModInfo.begin();
212         while( it != m_aModInfo.end() )
213         {
214             delete it->second;
215             ++it;
216         }
217     }
218 
219     {
220         // KeywordInfoTable
221 
222         KeywordInfoTable::iterator it = m_aKeywordInfo.begin();
223         while( it != m_aKeywordInfo.end() )
224         {
225             delete it->second;
226             ++it;
227         }
228     }
229 }
230 
impl_getZipFile(Sequence<rtl::OUString> & rImagesZipPaths,const rtl::OUString & rZipName,rtl::OUString & rFileName)231 static bool impl_getZipFile(
232         Sequence< rtl::OUString > & rImagesZipPaths,
233         const rtl::OUString & rZipName,
234         rtl::OUString & rFileName )
235 {
236     const rtl::OUString *pPathArray = rImagesZipPaths.getArray();
237     for ( int i = 0; i < rImagesZipPaths.getLength(); ++i )
238     {
239         rFileName = pPathArray[ i ];
240         if ( rFileName.getLength() )
241         {
242             if ( 1 + rFileName.lastIndexOf( '/' ) != rFileName.getLength() )
243             {
244                 rFileName += rtl::OUString::createFromAscii( "/" );
245             }
246             rFileName += rZipName;
247 
248             // test existence
249             osl::DirectoryItem aDirItem;
250             if ( osl::DirectoryItem::get( rFileName, aDirItem ) == osl::FileBase::E_None )
251                 return true;
252         }
253     }
254     return false;
255 }
256 
getImagesZipFileURL()257 rtl::OString Databases::getImagesZipFileURL()
258 {
259     //sal_Int16 nSymbolsStyle = SvtMiscOptions().GetCurrentSymbolsStyle();
260     sal_Int16 nSymbolsStyle = 0;
261     try
262     {
263         uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
264             m_xSMgr ->createInstanceWithContext(::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationProvider"), m_xContext), uno::UNO_QUERY_THROW);
265 
266         // set root path
267         uno::Sequence < uno::Any > lParams(1);
268         beans::PropertyValue                       aParam ;
269         aParam.Name    = ::rtl::OUString::createFromAscii("nodepath");
270         aParam.Value <<= ::rtl::OUString::createFromAscii("org.openoffice.Office.Common");
271         lParams[0] = uno::makeAny(aParam);
272 
273         // open it
274         uno::Reference< uno::XInterface > xCFG( xConfigProvider->createInstanceWithArguments(
275                     ::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationAccess"),
276                     lParams) );
277 
278         bool bChanged = false;
279         uno::Reference< container::XHierarchicalNameAccess > xAccess(xCFG, uno::UNO_QUERY_THROW);
280         uno::Any aResult = xAccess->getByHierarchicalName(::rtl::OUString::createFromAscii("Misc/SymbolSet"));
281         if ( (aResult >>= nSymbolsStyle) && m_nSymbolsStyle != nSymbolsStyle )
282         {
283             m_nSymbolsStyle = nSymbolsStyle;
284             bChanged = true;
285         }
286 
287         if ( !m_aImagesZipFileURL.getLength() || bChanged )
288         {
289             rtl::OUString aImageZip, aSymbolsStyleName;
290             aResult = xAccess->getByHierarchicalName(::rtl::OUString::createFromAscii("Misc/SymbolStyle"));
291             aResult >>= aSymbolsStyleName;
292 
293             bool bFound = false;
294             if ( aSymbolsStyleName.getLength() != 0 )
295             {
296                 rtl::OUString aZipName = rtl::OUString::createFromAscii( "images_" );
297                 aZipName += aSymbolsStyleName;
298                 aZipName += rtl::OUString::createFromAscii( ".zip" );
299 
300                 bFound = impl_getZipFile( m_aImagesZipPaths, aZipName, aImageZip );
301             }
302 
303             if ( ! bFound )
304                 bFound = impl_getZipFile( m_aImagesZipPaths, rtl::OUString::createFromAscii( "images.zip" ), aImageZip );
305 
306             if ( ! bFound )
307                 aImageZip = rtl::OUString();
308 
309             m_aImagesZipFileURL = rtl::OUStringToOString(
310                         rtl::Uri::encode(
311                             aImageZip,
312                             rtl_UriCharClassPchar,
313                             rtl_UriEncodeIgnoreEscapes,
314                             RTL_TEXTENCODING_UTF8 ), RTL_TEXTENCODING_UTF8 );
315         }
316     }
317     catch ( NoSuchElementException const & )
318     {
319     }
320 
321     return m_aImagesZipFileURL;
322 }
323 
replaceName(rtl::OUString & oustring) const324 void Databases::replaceName( rtl::OUString& oustring ) const
325 {
326     sal_Int32 idx = -1,idx1 = -1,idx2 = -1,k = 0,off;
327     bool cap = false;
328     rtl::OUStringBuffer aStrBuf( 0 );
329 
330     while( true )
331     {
332         ++idx;
333         idx1 = oustring.indexOf( sal_Unicode('%'),idx);
334         idx2 = oustring.indexOf( sal_Unicode('$'),idx);
335 
336         if(idx1 == -1 && idx2 == -1)
337             break;
338 
339         if(idx1 == -1)
340             idx = idx2;
341         else if(idx2 == -1)
342             idx = idx1;
343         else {
344             // no index is zero
345             if(idx1 < idx2)
346                 idx = idx1;
347             else if(idx2 < idx1 )
348                 idx = idx2;
349         }
350 
351         if( oustring.indexOf( prodName,idx ) == idx )
352             off = PRODUCTNAME;
353         else if( oustring.indexOf( prodVersion,idx ) == idx )
354             off = PRODUCTVERSION;
355         else if( oustring.indexOf( vendName,idx ) == idx )
356             off = VENDORNAME;
357         else if( oustring.indexOf( vendVersion,idx ) == idx )
358             off = VENDORVERSION;
359         else if( oustring.indexOf( vendShort,idx ) == idx )
360             off = VENDORSHORT;
361         else if( oustring.indexOf( newProdName,idx ) == idx )
362             off = NEWPRODUCTNAME;
363         else if( oustring.indexOf( newProdVersion,idx ) == idx )
364             off = NEWPRODUCTVERSION;
365         else
366             off = -1;
367 
368         if( off != -1 )
369         {
370             if( ! cap )
371             {
372                 cap = true;
373                 aStrBuf.ensureCapacity( 256 );
374             }
375 
376             aStrBuf.append( &oustring.getStr()[k],idx - k );
377             aStrBuf.append( m_vReplacement[off] );
378             k = idx + m_vAdd[off];
379         }
380     }
381 
382     if( cap )
383     {
384         if( k < oustring.getLength() )
385             aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
386         oustring = aStrBuf.makeStringAndClear();
387     }
388 }
389 
390 
391 
392 
getInstallPathAsSystemPath()393 rtl::OUString Databases::getInstallPathAsSystemPath()
394 {
395     osl::MutexGuard aGuard( m_aMutex );
396 
397     if( ! m_aInstallDirectoryAsSystemPath.getLength() )
398     {
399 #ifdef DBG_UTIL
400         bool bla =
401             osl::FileBase::E_None ==
402             osl::FileBase::getSystemPathFromFileURL( m_aInstallDirectory,m_aInstallDirectoryAsSystemPath );
403         VOS_ENSURE( bla,"HelpProvider, no installpath" );
404 #else
405         osl::FileBase::getSystemPathFromFileURL( m_aInstallDirectory,m_aInstallDirectoryAsSystemPath );
406 #endif
407     }
408 
409     return m_aInstallDirectoryAsSystemPath;
410 }
411 
getInstallPathAsURL()412 rtl::OUString Databases::getInstallPathAsURL()
413 {
414     osl::MutexGuard aGuard( m_aMutex );
415 
416     return m_aInstallDirectory;
417 }
418 
419 
getModuleList(const rtl::OUString & Language)420 const std::vector< rtl::OUString >& Databases::getModuleList( const rtl::OUString& Language )
421 {
422     if( m_avModules.size() == 0 )
423     {
424         rtl::OUString  fileName,dirName = getInstallPathAsURL() + processLang( Language );
425         osl::Directory dirFile( dirName );
426 
427         osl::DirectoryItem aDirItem;
428         osl::FileStatus    aStatus( FileStatusMask_FileName );
429 
430         sal_Int32 idx;
431 
432         if( osl::FileBase::E_None != dirFile.open() )
433             return m_avModules;
434 
435         while( dirFile.getNextItem( aDirItem ) == osl::FileBase::E_None &&
436                aDirItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
437         {
438             if( ! aStatus.isValid( FileStatusMask_FileName ) )
439                 continue;
440 
441             fileName = aStatus.getFileName();
442 
443             // Check, whether fileName is of the form *.cfg
444             idx = fileName.lastIndexOf(  sal_Unicode( '.' ) );
445 
446             if( idx == -1 )
447                 continue;
448 
449             const sal_Unicode* str = fileName.getStr();
450 
451             if( fileName.getLength() == idx + 4                   &&
452                 ( str[idx + 1] == 'c' || str[idx + 1] == 'C' )    &&
453                 ( str[idx + 2] == 'f' || str[idx + 2] == 'F' )    &&
454                 ( str[idx + 3] == 'g' || str[idx + 3] == 'G' )    &&
455                 ( fileName = fileName.copy(0,idx).toAsciiLowerCase() ).compareToAscii( "picture" ) != 0 ) {
456               if(! m_bShowBasic && fileName.compareToAscii("sbasic") == 0 )
457                 continue;
458               m_avModules.push_back( fileName );
459             }
460         }
461     }
462     return m_avModules;
463 }
464 
465 
466 
getStaticInformationForModule(const rtl::OUString & Module,const rtl::OUString & Language)467 StaticModuleInformation* Databases::getStaticInformationForModule( const rtl::OUString& Module,
468                                                                    const rtl::OUString& Language )
469 {
470     osl::MutexGuard aGuard( m_aMutex );
471 
472     rtl::OUString key = processLang(Language) + rtl::OUString::createFromAscii( "/" ) + Module;
473 
474     std::pair< ModInfoTable::iterator,bool > aPair =
475         m_aModInfo.insert( ModInfoTable::value_type( key,0 ) );
476 
477     ModInfoTable::iterator it = aPair.first;
478 
479     if( aPair.second && ! it->second )
480     {
481         osl::File cfgFile( getInstallPathAsURL() +
482                            key +
483                            rtl::OUString::createFromAscii( ".cfg" ) );
484 
485         if( osl::FileBase::E_None != cfgFile.open( OpenFlag_Read ) )
486             it->second = 0;
487         else
488         {
489             sal_uInt32 pos = 0;
490             sal_uInt64 nRead;
491             sal_Char buffer[2048];
492             sal_Unicode lineBuffer[1028];
493             rtl::OUString fileContent;
494 
495             while( osl::FileBase::E_None == cfgFile.read( &buffer,2048,nRead ) && nRead )
496                 fileContent += rtl::OUString( buffer,sal_Int32( nRead ),RTL_TEXTENCODING_UTF8 );
497 
498             cfgFile.close();
499 
500             const sal_Unicode* str = fileContent.getStr();
501             rtl::OUString current,lang_,program,startid,title,heading,fulltext;
502             rtl::OUString order = rtl::OUString::createFromAscii( "1" );
503 
504             for( sal_Int32 i = 0;i < fileContent.getLength();i++ )
505             {
506                 sal_Unicode ch = str[ i ];
507                 if( ch == sal_Unicode( '\n' ) || ch == sal_Unicode( '\r' ) )
508                 {
509                     if( pos )
510                     {
511                         current = rtl::OUString( lineBuffer,pos );
512 
513                         if( current.compareToAscii( "Title",5 ) == 0 )
514                         {
515                             title = current.copy( current.indexOf(sal_Unicode( '=' ) ) + 1 );
516                         }
517                         else if( current.compareToAscii( "Start",5 ) == 0 )
518                         {
519                             startid = current.copy( current.indexOf('=') + 1 );
520                         }
521                         else if( current.compareToAscii( "Language",8 ) == 0 )
522                         {
523                             lang_ = current.copy( current.indexOf('=') + 1 );
524                         }
525                         else if( current.compareToAscii( "Program",7 ) == 0 )
526                         {
527                             program = current.copy( current.indexOf('=') + 1 );
528                         }
529                         else if( current.compareToAscii( "Heading",7 ) == 0 )
530                         {
531                             heading = current.copy( current.indexOf('=') + 1 );
532                         }
533                         else if( current.compareToAscii( "FullText",8 ) == 0 )
534                         {
535                             fulltext = current.copy( current.indexOf('=') + 1 );
536                         }
537                         else if( current.compareToAscii( "Order",5 ) == 0 )
538                         {
539                             order = current.copy( current.indexOf('=') + 1 );
540                         }
541                     }
542                     pos = 0;
543                 }
544                 else
545                     lineBuffer[ pos++ ] = ch;
546             }
547             replaceName( title );
548             it->second = new StaticModuleInformation( title,
549                                                       startid,
550                                                       program,
551                                                       heading,
552                                                       fulltext,
553                                                       order );
554         }
555     }
556 
557     return it->second;
558 }
559 
560 
561 
562 
processLang(const rtl::OUString & Language)563 rtl::OUString Databases::processLang( const rtl::OUString& Language )
564 {
565     osl::MutexGuard aGuard( m_aMutex );
566 
567     rtl::OUString ret;
568     LangSetTable::iterator it = m_aLangSet.find( Language );
569 
570     if( it == m_aLangSet.end() )
571     {
572         sal_Int32 idx;
573         osl::DirectoryItem aDirItem;
574 
575         if( osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language,aDirItem ) )
576         {
577             ret = Language;
578             m_aLangSet[ Language ] = ret;
579         }
580         else if( ( ( idx = Language.indexOf( '-' ) ) != -1 ||
581                    ( idx = Language.indexOf( '_' ) ) != -1 ) &&
582                     osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language.copy( 0,idx ),
583                                                                    aDirItem ) )
584         {
585             ret = Language.copy( 0,idx );
586             m_aLangSet[ Language ] = ret;
587         }
588     }
589     else
590         ret = it->second;
591 
592     return ret;
593 }
594 
595 
country(const rtl::OUString & Language)596 rtl::OUString Databases::country( const rtl::OUString& Language )
597 {
598     sal_Int32 idx;
599     if( ( idx = Language.indexOf( '-' ) ) != -1 ||
600         ( idx = Language.indexOf( '_' ) ) != -1 )
601         return Language.copy( 1+idx );
602 
603     return rtl::OUString();
604 }
605 
606 
607 
getHelpDataFile(const rtl::OUString & Database,const rtl::OUString & Language,bool helpText,const rtl::OUString * pExtensionPath)608 helpdatafileproxy::Hdf* Databases::getHelpDataFile( const rtl::OUString& Database,
609                             const rtl::OUString& Language, bool helpText,
610                             const rtl::OUString* pExtensionPath )
611 {
612     if( ! Database.getLength() || ! Language.getLength() )
613         return 0;
614 
615     osl::MutexGuard aGuard( m_aMutex );
616 
617 
618     rtl::OUString aFileExt( rtl::OUString::createFromAscii( helpText ? ".ht" : ".db" ) );
619     rtl::OUString dbFileName = aSlash + Database + aFileExt;
620     rtl::OUString key;
621     if( pExtensionPath == NULL )
622         key = processLang( Language ) + dbFileName;
623     else
624         key = *pExtensionPath + Language + dbFileName;      // make unique, don't change language
625 
626     std::pair< DatabasesTable::iterator,bool > aPair =
627         m_aDatabases.insert( DatabasesTable::value_type( key,0 ) );
628 
629     DatabasesTable::iterator it = aPair.first;
630 
631     if( aPair.second && ! it->second )
632     {
633         helpdatafileproxy::Hdf* pHdf = 0;
634 
635         rtl::OUString fileURL;
636         if( pExtensionPath )
637             fileURL = expandURL(*pExtensionPath) + Language + dbFileName;
638         else
639             fileURL = getInstallPathAsURL() + key;
640 
641         rtl::OUString fileNameHDFHelp( fileURL );
642         //Extensions always use the new format
643         if( pExtensionPath != NULL )
644             fileNameHDFHelp += rtl::OUString::createFromAscii( "_" );
645         //SimpleFileAccess takes file URLs as arguments!!! Using filenames works accidentally but
646         //fails for example when using long path names on Windows (starting with \\?\)
647         if( m_xSFA->exists( fileNameHDFHelp ) )
648         {
649             pHdf = new helpdatafileproxy::Hdf( fileNameHDFHelp, m_xSFA );
650         }
651 
652         it->second = pHdf;
653     }
654 
655     return it->second;
656 }
657 
658 Reference< XCollator >
getCollator(const rtl::OUString & Language,const rtl::OUString & System)659 Databases::getCollator( const rtl::OUString& Language,
660                         const rtl::OUString& System )
661 {
662     (void)System;
663 
664     rtl::OUString key = Language;
665 
666     osl::MutexGuard aGuard( m_aMutex );
667 
668     CollatorTable::iterator it =
669         m_aCollatorTable.insert( CollatorTable::value_type( key,0 ) ).first;
670 
671     if( ! it->second.is() )
672     {
673         it->second =
674             Reference< XCollator > (
675                 m_xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.i18n.Collator" ),
676                 m_xContext ), UNO_QUERY );
677         rtl::OUString langStr = processLang(Language);
678         rtl::OUString countryStr = country(Language);
679         if( !countryStr.getLength() )
680         {
681             if( langStr.compareToAscii("de") == 0 )
682                 countryStr = rtl::OUString::createFromAscii("DE");
683             else if( langStr.compareToAscii("en") == 0 )
684                 countryStr = rtl::OUString::createFromAscii("US");
685             else if( langStr.compareToAscii("es") == 0 )
686                 countryStr = rtl::OUString::createFromAscii("ES");
687             else if( langStr.compareToAscii("it") == 0 )
688                 countryStr = rtl::OUString::createFromAscii("IT");
689             else if( langStr.compareToAscii("fr") == 0 )
690                 countryStr = rtl::OUString::createFromAscii("FR");
691             else if( langStr.compareToAscii("sv") == 0 )
692                 countryStr = rtl::OUString::createFromAscii("SE");
693             else if( langStr.compareToAscii("ja") == 0 )
694                 countryStr = rtl::OUString::createFromAscii("JP");
695             else if( langStr.compareToAscii("ko") == 0 )
696                 countryStr = rtl::OUString::createFromAscii("KR");
697         }
698         it->second->loadDefaultCollator(  Locale( langStr,
699                                                   countryStr,
700                                                   rtl::OUString() ),
701                                           0 );
702     }
703 
704     return it->second;
705 }
706 
707 
708 
709 namespace chelp {
710 
711     struct KeywordElementComparator
712     {
KeywordElementComparatorchelp::KeywordElementComparator713         KeywordElementComparator( const Reference< XCollator >& xCollator )
714             : m_xCollator( xCollator )
715         { }
716 
operator ()chelp::KeywordElementComparator717         bool operator()( const KeywordInfo::KeywordElement& la,
718                          const KeywordInfo::KeywordElement& ra ) const
719         {
720             const rtl::OUString& l = la.key;
721             const rtl::OUString& r = ra.key;
722 
723             bool ret;
724 
725             if( m_xCollator.is() )
726             {
727                 sal_Int32 l1 = l.indexOf( sal_Unicode( ';' ) );
728                 sal_Int32 l3 = ( l1 == -1 ? l.getLength() : l1 );
729 
730                 sal_Int32 r1 = r.indexOf( sal_Unicode( ';' ) );
731                 sal_Int32 r3 = ( r1 == -1 ? r.getLength() : r1 );
732 
733                 sal_Int32 c1 = m_xCollator->compareSubstring( l,0,l3,r,0,r3 );
734 
735                 if( c1 == +1 )
736                     ret = false;
737                 else if( c1 == 0 )
738                 {
739                     sal_Int32 l2 = l.getLength() - l1 - 1;
740                     sal_Int32 r2 = r.getLength() - r1 - 1;
741                     ret = ( m_xCollator->compareSubstring( l,1+l1,l2,r,1+r1,r2 ) < 0 );
742                 }
743                 else
744                     ret = true;
745             }
746             else
747                 ret = bool( l < r );
748 
749             return ret;
750         }
751 
752         Reference< XCollator > m_xCollator;
753     }; // end struct KeywordElementComparator
754 
755 }
756 
757 
758 
KeywordElement(Databases * pDatabases,helpdatafileproxy::Hdf * pHdf,rtl::OUString & ky,rtl::OUString & data)759 KeywordInfo::KeywordElement::KeywordElement( Databases *pDatabases,
760                                              helpdatafileproxy::Hdf* pHdf,
761                                              rtl::OUString& ky,
762                                              rtl::OUString& data )
763     : key( ky )
764 {
765     pDatabases->replaceName( key );
766     init( pDatabases,pHdf,data );
767 }
768 
769 
770 
init(Databases * pDatabases,helpdatafileproxy::Hdf * pHdf,const rtl::OUString & ids)771 void KeywordInfo::KeywordElement::init( Databases *pDatabases,helpdatafileproxy::Hdf* pHdf,const rtl::OUString& ids )
772 {
773     const sal_Unicode* idstr = ids.getStr();
774     std::vector< rtl::OUString > id,anchor;
775     int idx = -1,k;
776     while( ( idx = ids.indexOf( ';',k = ++idx ) ) != -1 )
777     {
778         int h = ids.indexOf( sal_Unicode( '#' ),k );
779         if( h < idx )
780         {
781             // found an anchor
782             id.push_back( rtl::OUString( &idstr[k],h-k ) );
783             anchor.push_back( rtl::OUString( &idstr[h+1],idx-h-1 ) );
784         }
785         else
786         {
787             id.push_back( rtl::OUString( &idstr[k],idx-k ) );
788             anchor.push_back( rtl::OUString() );
789         }
790     }
791 
792     listId.realloc( id.size() );
793     listAnchor.realloc( id.size() );
794     listTitle.realloc( id.size() );
795 
796     int nSize = 0;
797     const sal_Char* pData = NULL;
798     const sal_Char pEmpty[] = "";
799 
800     for( sal_uInt32 i = 0; i < id.size(); ++i )
801     {
802         listId[i] = id[i];
803         listAnchor[i] = anchor[i];
804 
805         nSize = 0;
806         pData = pEmpty;
807         if( pHdf )
808         {
809             rtl::OString idi( id[i].getStr(),id[i].getLength(),RTL_TEXTENCODING_UTF8 );
810             helpdatafileproxy::HDFData aHDFData;
811             bool bSuccess = pHdf->getValueForKey( idi, aHDFData );
812             if( bSuccess )
813             {
814                 nSize = aHDFData.getSize();
815                 pData = aHDFData.getData();
816             }
817         }
818 
819         DbtToStringConverter converter( pData, nSize );
820 
821         rtl::OUString title = converter.getTitle();
822         pDatabases->replaceName( title );
823         listTitle[i] = title;
824     }
825 }
826 
827 
828 
KeywordInfo(const std::vector<KeywordElement> & aVec)829 KeywordInfo::KeywordInfo( const std::vector< KeywordElement >& aVec )
830     : listKey( aVec.size() ),
831       listId( aVec.size() ),
832       listAnchor( aVec.size() ),
833       listTitle( aVec.size() )
834 {
835     for( unsigned int i = 0; i < aVec.size(); ++i )
836     {
837         listKey[i] = aVec[i].key;
838         listId[i] = aVec[i].listId;
839         listAnchor[i] = aVec[i].listAnchor;
840         listTitle[i] = aVec[i].listTitle;
841     }
842 }
843 
checkModuleMatchForExtension(const rtl::OUString & Database,const rtl::OUString & doclist)844 bool Databases::checkModuleMatchForExtension
845     ( const rtl::OUString& Database, const rtl::OUString& doclist )
846 {
847     bool bBelongsToDatabase = true;
848 
849     // Analyse doclist string to find module assignments
850     bool bFoundAtLeastOneModule = false;
851     bool bModuleMatch = false;
852     sal_Int32 nLen = doclist.getLength();
853     sal_Int32 nLastFound = doclist.lastIndexOf( sal_Unicode(';') );
854     if( nLastFound == -1 )
855         nLastFound = nLen;
856     const sal_Unicode* pStr = doclist.getStr();
857     sal_Int32 nFound = doclist.lastIndexOf( sal_Unicode('_') );
858     while( nFound != -1 )
859     {
860         // Simple optimization, stop if '_' is followed by "id"
861         if( nLen - nFound > 2 )
862         {
863             if( pStr[ nFound + 1 ] == sal_Unicode('i') &&
864                 pStr[ nFound + 2 ] == sal_Unicode('d') )
865                     break;
866         }
867 
868         rtl::OUString aModule = doclist.copy( nFound + 1, nLastFound - nFound - 1 );
869         std::vector< rtl::OUString >::iterator result = std::find( m_avModules.begin(), m_avModules.end(), aModule );
870         if( result != m_avModules.end() )
871         {
872             bFoundAtLeastOneModule = true;
873             if( Database == aModule )
874             {
875                 bModuleMatch = true;
876                 break;
877             }
878         }
879 
880         nLastFound = nFound;
881         if( nLastFound == 0 )
882             break;
883         nFound = doclist.lastIndexOf( sal_Unicode('_'), nLastFound - 1 );
884     }
885 
886     if( bFoundAtLeastOneModule && !bModuleMatch )
887         bBelongsToDatabase = false;
888 
889     return bBelongsToDatabase;
890 }
891 
892 
getKeyword(const rtl::OUString & Database,const rtl::OUString & Language)893 KeywordInfo* Databases::getKeyword( const rtl::OUString& Database,
894                                     const rtl::OUString& Language )
895 {
896     osl::MutexGuard aGuard( m_aMutex );
897 
898     rtl::OUString key = processLang(Language) + rtl::OUString::createFromAscii( "/" ) + Database;
899 
900     std::pair< KeywordInfoTable::iterator,bool > aPair =
901         m_aKeywordInfo.insert( KeywordInfoTable::value_type( key,0 ) );
902 
903     KeywordInfoTable::iterator it = aPair.first;
904 
905     if( aPair.second && ! it->second )
906     {
907         std::vector<KeywordInfo::KeywordElement> aVector;
908 
909         KeyDataBaseFileIterator aDbFileIt( m_xContext, *this, Database, Language );
910         rtl::OUString fileURL;
911         bool bExtension = false;
912         while( (fileURL = aDbFileIt.nextDbFile( bExtension )).getLength() > 0 )
913         {
914             rtl::OUString fileNameHDFHelp( fileURL );
915             if( bExtension )
916                 fileNameHDFHelp += rtl::OUString::createFromAscii( "_" );
917             if( m_xSFA->exists( fileNameHDFHelp ) )
918             {
919                 helpdatafileproxy::Hdf aHdf( fileNameHDFHelp, m_xSFA );
920 
921                 helpdatafileproxy::HDFData aKey;
922                 helpdatafileproxy::HDFData aValue;
923                 if( aHdf.startIteration() )
924                 {
925                     helpdatafileproxy::Hdf* pHdf = getHelpDataFile( Database,Language );
926                     if( pHdf != NULL )
927                     {
928                         bool bOptimizeForPerformance = true;
929                         pHdf->releaseHashMap();
930                         pHdf->createHashMap( bOptimizeForPerformance );
931                     }
932 
933                     while( aHdf.getNextKeyAndValue( aKey, aValue ) )
934                     {
935                         rtl::OUString keyword( aKey.getData(), aKey.getSize(),
936                                                RTL_TEXTENCODING_UTF8 );
937                         rtl::OUString doclist( aValue.getData(), aValue.getSize(),
938                                                RTL_TEXTENCODING_UTF8 );
939 
940                         bool bBelongsToDatabase = true;
941                         if( bExtension )
942                             bBelongsToDatabase = checkModuleMatchForExtension( Database, doclist );
943 
944                         if( !bBelongsToDatabase )
945                             continue;
946 
947                         aVector.push_back( KeywordInfo::KeywordElement( this,
948                                                                         pHdf,
949                                                                         keyword,
950                                                                         doclist ) );
951                     }
952                     aHdf.stopIteration();
953 
954                     if( pHdf != NULL )
955                         pHdf->releaseHashMap();
956                 }
957             }
958         }
959 
960         // sorting
961         Reference< XCollator > xCollator = getCollator( Language,rtl::OUString());
962         KeywordElementComparator aComparator( xCollator );
963         std::sort(aVector.begin(),aVector.end(),aComparator);
964 
965         KeywordInfo* pInfo = it->second = new KeywordInfo( aVector );
966         (void)pInfo;
967     }
968 
969     return it->second;
970 }
971 
jarFile(const rtl::OUString & jar,const rtl::OUString & Language)972 Reference< XHierarchicalNameAccess > Databases::jarFile( const rtl::OUString& jar,
973                                                          const rtl::OUString& Language )
974 {
975     if( ! jar.getLength() ||
976         ! Language.getLength() )
977     {
978         return Reference< XHierarchicalNameAccess >( 0 );
979     }
980     rtl::OUString key = processLang(Language) + aSlash + jar;
981 
982     osl::MutexGuard aGuard( m_aMutex );
983 
984     ZipFileTable::iterator it =
985         m_aZipFileTable.insert( ZipFileTable::value_type( key,Reference< XHierarchicalNameAccess >(0) ) ).first;
986 
987     if( ! it->second.is() )
988     {
989         rtl::OUString zipFile;
990         try
991         {
992             // Extension jar file? Search for ?
993             sal_Int32 nQuestionMark1 = jar.indexOf( sal_Unicode('?') );
994             sal_Int32 nQuestionMark2 = jar.lastIndexOf( sal_Unicode('?') );
995             if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
996             {
997                 ::rtl::OUString aExtensionPath = jar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
998                 ::rtl::OUString aPureJar = jar.copy( nQuestionMark2 + 1 );
999 
1000                 rtl::OUStringBuffer aStrBuf;
1001                 aStrBuf.append( aExtensionPath );
1002                 aStrBuf.append( aSlash );
1003                 aStrBuf.append( aPureJar );
1004 
1005                 zipFile = expandURL( aStrBuf.makeStringAndClear() );
1006             }
1007             else
1008             {
1009                 zipFile = getInstallPathAsURL() + key;
1010             }
1011 
1012             Sequence< Any > aArguments( 2 );
1013 
1014             XInputStream_impl* p = new XInputStream_impl( zipFile );
1015             if( p->CtorSuccess() )
1016             {
1017                 Reference< XInputStream > xInputStream( p );
1018                 aArguments[ 0 ] <<= xInputStream;
1019             }
1020             else
1021             {
1022                 delete p;
1023                 aArguments[ 0 ] <<= zipFile;
1024             }
1025 
1026             // let ZipPackage be used ( no manifest.xml is required )
1027             beans::NamedValue aArg;
1028             aArg.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
1029             aArg.Value <<= ZIP_STORAGE_FORMAT_STRING;
1030             aArguments[ 1 ] <<= aArg;
1031 
1032             Reference< XInterface > xIfc
1033                 = m_xSMgr->createInstanceWithArgumentsAndContext(
1034                     rtl::OUString::createFromAscii(
1035                         "com.sun.star.packages.comp.ZipPackage" ),
1036                     aArguments, m_xContext );
1037 
1038             if ( xIfc.is() )
1039             {
1040                 it->second = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1041 
1042                 VOS_ENSURE( it->second.is(),
1043                             "ContentProvider::createPackage - "
1044                             "Got no hierarchical name access!" );
1045 
1046             }
1047         }
1048         catch ( RuntimeException & )
1049         {
1050         }
1051         catch ( Exception & )
1052         {
1053         }
1054     }
1055 
1056     return it->second;
1057 }
1058 
findJarFileForPath(const rtl::OUString & jar,const rtl::OUString & Language,const rtl::OUString & path,rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1059 Reference< XHierarchicalNameAccess > Databases::findJarFileForPath
1060     ( const rtl::OUString& jar, const rtl::OUString& Language,
1061       const rtl::OUString& path, rtl::OUString* o_pExtensionPath,
1062       rtl::OUString* o_pExtensionRegistryPath )
1063 {
1064     Reference< XHierarchicalNameAccess > xNA;
1065     if( ! jar.getLength() ||
1066         ! Language.getLength() )
1067     {
1068         return xNA;
1069     }
1070 
1071     JarFileIterator aJarFileIt( m_xContext, *this, jar, Language );
1072     Reference< XHierarchicalNameAccess > xTestNA;
1073     Reference< deployment::XPackage > xParentPackageBundle;
1074     while( (xTestNA = aJarFileIt.nextJarFile( xParentPackageBundle, o_pExtensionPath, o_pExtensionRegistryPath )).is() )
1075     {
1076         if( xTestNA.is() && xTestNA->hasByHierarchicalName( path ) )
1077         {
1078             bool bSuccess = true;
1079             if( xParentPackageBundle.is() )
1080             {
1081                 rtl::OUString aIdentifierInPath;
1082                 sal_Int32 nFindSlash = path.indexOf( '/' );
1083                 if( nFindSlash != -1 )
1084                     aIdentifierInPath = path.copy( 0, nFindSlash );
1085 
1086                 beans::Optional<rtl::OUString> aIdentifierOptional = xParentPackageBundle->getIdentifier();
1087                 if( aIdentifierInPath.getLength() && aIdentifierOptional.IsPresent )
1088                 {
1089                     rtl::OUString aUnencodedIdentifier = aIdentifierOptional.Value;
1090                     rtl::OUString aIdentifier = rtl::Uri::encode( aUnencodedIdentifier,
1091                         rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8 );
1092 
1093                     if( !aIdentifierInPath.equals( aIdentifier ) )
1094                     {
1095                         // path does not start with extension identifier -> ignore
1096                         bSuccess = false;
1097                     }
1098                 }
1099                 else
1100                 {
1101                     // No identifier -> ignore
1102                     bSuccess = false;
1103                 }
1104             }
1105 
1106             if( bSuccess )
1107             {
1108                 xNA = xTestNA;
1109                 break;
1110             }
1111         }
1112     }
1113 
1114     return xNA;
1115 }
1116 
popupDocument(URLParameter * urlPar,char ** buffer,int * byteCount)1117 void Databases::popupDocument( URLParameter* urlPar,char **buffer,int *byteCount )
1118 {
1119     const char* pop1 =
1120         " <html>                                                                "
1121         " <head>                                                                "
1122         " <help:css-file-link xmlns:help=\"http://openoffice.org/2000/help\"/>  "
1123         " </head>                                                               "
1124         " <body>                                                                "
1125         " <help:popup-cut Id=\"";
1126     const sal_Int32 l1 = strlen( pop1 );
1127 
1128     const char* pop3 = "\" Eid=\"";
1129     const sal_Int32 l3 = strlen( pop3 );
1130 
1131     const char* pop5 =
1132         "\" xmlns:help=\"http://openoffice.org/2000/help\"></help:popup-cut>  "
1133         " </body>                                                             "
1134         " </html>";
1135     const sal_Int32 l5 = strlen( pop5 );
1136     sal_Int32 l2,l4;
1137 
1138     rtl::OUString val = urlPar->get_id();
1139     rtl::OString pop2O( val.getStr(),l2 = val.getLength(),RTL_TEXTENCODING_UTF8 );
1140     const char* pop2 = pop2O.getStr();
1141 
1142     val = urlPar->get_eid();
1143     rtl::OString pop4O( val.getStr(),l4 = val.getLength(),RTL_TEXTENCODING_UTF8 );
1144     const char* pop4 = pop4O.getStr();
1145 
1146     (*byteCount) = l1 + l2 + l3 + l4 + l5;
1147 
1148     *buffer = new char[ 1+*byteCount ];
1149 
1150     rtl_copyMemory( *buffer,pop1,l1 );
1151     rtl_copyMemory( *buffer+l1,pop2,l2 );
1152     rtl_copyMemory( *buffer+(l1+l2),pop3,l3 );
1153     rtl_copyMemory( *buffer+(l1+l2+l3),pop4,l4 );
1154     rtl_copyMemory( *buffer+(l1+l2+l3+l4),pop5,l5 );
1155     (*buffer)[*byteCount] = 0;
1156 }
1157 
1158 
changeCSS(const rtl::OUString & newStyleSheet)1159 void Databases::changeCSS(const rtl::OUString& newStyleSheet)
1160 {
1161     m_aCSS = newStyleSheet.toAsciiLowerCase();
1162     delete[] m_pCustomCSSDoc, m_pCustomCSSDoc = 0,m_nCustomCSSDocLength = 0;
1163 }
1164 
1165 
1166 
cascadingStylesheet(const rtl::OUString & Language,char ** buffer,int * byteCount)1167 void Databases::cascadingStylesheet( const rtl::OUString& Language,
1168                                      char** buffer,
1169                                      int* byteCount )
1170 {
1171     if( ! m_pCustomCSSDoc )
1172     {
1173         int retry = 2;
1174         bool error = true;
1175         rtl::OUString fileURL;
1176 
1177         sal_Bool bHighContrastMode = sal_False;
1178         rtl::OUString aCSS( m_aCSS );
1179         if ( aCSS.compareToAscii( "default" ) == 0 )
1180         {
1181             // #i50760: "default" needs to adapt HC mode
1182             uno::Reference< awt::XToolkit > xToolkit = uno::Reference< awt::XToolkit >(
1183                     ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.Toolkit" ) ) ), uno::UNO_QUERY );
1184             if ( xToolkit.is() )
1185             {
1186                 uno::Reference< awt::XExtendedToolkit > xExtToolkit( xToolkit, uno::UNO_QUERY );
1187                 if ( xExtToolkit.is() )
1188                 {
1189                     uno::Reference< awt::XTopWindow > xTopWindow = xExtToolkit->getActiveTopWindow();
1190                     if ( xTopWindow.is() )
1191                     {
1192                         uno::Reference< awt::XVclWindowPeer > xVclWindowPeer( xTopWindow, uno::UNO_QUERY );
1193                         if ( xVclWindowPeer.is() )
1194                         {
1195                             uno::Any aHCMode = xVclWindowPeer->getProperty( rtl::OUString::createFromAscii( "HighContrastMode" ) );
1196                             if ( ( aHCMode >>= bHighContrastMode ) && bHighContrastMode )
1197                                 aCSS = rtl::OUString::createFromAscii( "highcontrastblack" );
1198                         }
1199                     }
1200                 }
1201             }
1202         }
1203 
1204         while( error && retry )
1205         {
1206 
1207             if( retry == 2 )
1208                 fileURL =
1209                     getInstallPathAsURL()  +
1210                     processLang( Language )       +
1211                     rtl::OUString::createFromAscii( "/" ) +
1212                     aCSS +
1213                     rtl::OUString::createFromAscii( ".css" );
1214             else if( retry == 1 )
1215                 fileURL =
1216                     getInstallPathAsURL()  +
1217                     aCSS +
1218                     rtl::OUString::createFromAscii( ".css" );
1219 
1220             osl::DirectoryItem aDirItem;
1221             osl::File aFile( fileURL );
1222             osl::FileStatus aStatus( FileStatusMask_FileSize );
1223 
1224             if( osl::FileBase::E_None == osl::DirectoryItem::get( fileURL,aDirItem ) &&
1225                 osl::FileBase::E_None == aFile.open( OpenFlag_Read )                 &&
1226                 osl::FileBase::E_None == aDirItem.getFileStatus( aStatus ) )
1227             {
1228                 m_nCustomCSSDocLength = int( aStatus.getFileSize() );
1229                 m_pCustomCSSDoc = new char[ 1 + m_nCustomCSSDocLength ];
1230                 m_pCustomCSSDoc[ m_nCustomCSSDocLength ] = 0;
1231                 sal_uInt64 a = m_nCustomCSSDocLength,b = m_nCustomCSSDocLength;
1232                 aFile.read( m_pCustomCSSDoc,a,b );
1233                 aFile.close();
1234                 error = false;
1235             }
1236 
1237             --retry;
1238             if ( !retry && error && bHighContrastMode )
1239             {
1240                 // fall back to default css
1241                 aCSS = rtl::OUString::createFromAscii( "default" );
1242                 retry = 2;
1243                 bHighContrastMode = sal_False;
1244             }
1245         }
1246 
1247         if( error )
1248         {
1249             m_nCustomCSSDocLength = 0;
1250             m_pCustomCSSDoc = new char[ 1 ]; // Initialize with 1 to avoid gcc compiler warning
1251         }
1252     }
1253 
1254     *byteCount = m_nCustomCSSDocLength;
1255     *buffer = new char[ 1 + *byteCount ];
1256     (*buffer)[*byteCount] = 0;
1257     rtl_copyMemory( *buffer,m_pCustomCSSDoc,m_nCustomCSSDocLength );
1258 
1259 }
1260 
1261 
setActiveText(const rtl::OUString & Module,const rtl::OUString & Language,const rtl::OUString & Id,char ** buffer,int * byteCount)1262 void Databases::setActiveText( const rtl::OUString& Module,
1263                                const rtl::OUString& Language,
1264                                const rtl::OUString& Id,
1265                                char** buffer,
1266                                int* byteCount )
1267 {
1268     DataBaseIterator aDbIt( m_xContext, *this, Module, Language, true );
1269 
1270     // #i84550 Cache information about failed ids
1271     rtl::OString id( Id.getStr(),Id.getLength(),RTL_TEXTENCODING_UTF8 );
1272     EmptyActiveTextSet::iterator it = m_aEmptyActiveTextSet.find( id );
1273     bool bFoundAsEmpty = ( it != m_aEmptyActiveTextSet.end() );
1274     helpdatafileproxy::HDFData aHDFData;
1275 
1276     int nSize = 0;
1277     const sal_Char* pData = NULL;
1278 
1279     bool bSuccess = false;
1280     if( !bFoundAsEmpty )
1281     {
1282         helpdatafileproxy::Hdf* pHdf = 0;
1283         while( !bSuccess && (pHdf = aDbIt.nextHdf()) != NULL )
1284         {
1285             bSuccess = pHdf->getValueForKey( id, aHDFData );
1286             nSize = aHDFData.getSize();
1287             pData = aHDFData.getData();
1288         }
1289     }
1290 
1291     if( bSuccess )
1292     {
1293         // ensure existence of tmp after for
1294         rtl::OString tmp;
1295         for( int i = 0; i < nSize; ++i )
1296             if( pData[i] == '%' || pData[i] == '$' )
1297             {
1298                 // need of replacement
1299                 rtl::OUString temp = rtl::OUString( pData, nSize, RTL_TEXTENCODING_UTF8 );
1300                 replaceName( temp );
1301                 tmp = rtl::OString( temp.getStr(),
1302                                     temp.getLength(),
1303                                     RTL_TEXTENCODING_UTF8 );
1304                 nSize = tmp.getLength();
1305                 pData = tmp.getStr();
1306                 break;
1307             }
1308 
1309         *byteCount = nSize;
1310         *buffer = new char[ 1 + nSize ];
1311         (*buffer)[nSize] = 0;
1312         rtl_copyMemory( *buffer, pData, nSize );
1313     }
1314     else
1315     {
1316         *byteCount = 0;
1317         *buffer = new char[1]; // Initialize with 1 to avoid compiler warnings
1318         if( !bFoundAsEmpty )
1319             m_aEmptyActiveTextSet.insert( id );
1320     }
1321 }
1322 
1323 
setInstallPath(const rtl::OUString & aInstDir)1324 void Databases::setInstallPath( const rtl::OUString& aInstDir )
1325 {
1326     osl::MutexGuard aGuard( m_aMutex );
1327 
1328     osl::FileBase::getFileURLFromSystemPath( aInstDir,m_aInstallDirectory );
1329         //TODO: check returned error code
1330 
1331     if( m_aInstallDirectory.lastIndexOf( sal_Unicode( '/' ) ) != m_aInstallDirectory.getLength() - 1 )
1332         m_aInstallDirectory += rtl::OUString::createFromAscii( "/" );
1333 
1334     m_aInstallDirectoryWithoutEncoding = rtl::Uri::decode( m_aInstallDirectory,
1335                                                            rtl_UriDecodeWithCharset,
1336                                                            RTL_TEXTENCODING_UTF8 );
1337 }
1338 
1339 
1340 //===================================================================
1341 // class ExtensionIteratorBase
1342 
1343 ExtensionHelpExistanceMap ExtensionIteratorBase::aHelpExistanceMap;
1344 
ExtensionIteratorBase(Reference<XComponentContext> xContext,Databases & rDatabases,const rtl::OUString & aInitialModule,const rtl::OUString & aLanguage)1345 ExtensionIteratorBase::ExtensionIteratorBase( Reference< XComponentContext > xContext,
1346     Databases& rDatabases, const rtl::OUString& aInitialModule, const rtl::OUString& aLanguage )
1347         : m_xContext( xContext )
1348         , m_rDatabases( rDatabases )
1349         , m_eState( INITIAL_MODULE )
1350         , m_aInitialModule( aInitialModule )
1351         , m_aLanguage( aLanguage )
1352 {
1353     init();
1354 }
1355 
ExtensionIteratorBase(Databases & rDatabases,const rtl::OUString & aInitialModule,const rtl::OUString & aLanguage)1356 ExtensionIteratorBase::ExtensionIteratorBase( Databases& rDatabases,
1357     const rtl::OUString& aInitialModule, const rtl::OUString& aLanguage )
1358         : m_rDatabases( rDatabases )
1359         , m_eState( INITIAL_MODULE )
1360         , m_aInitialModule( aInitialModule )
1361         , m_aLanguage( aLanguage )
1362 {
1363     init();
1364 }
1365 
init()1366 void ExtensionIteratorBase::init()
1367 {
1368     if( !m_xContext.is() )
1369     {
1370         Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
1371         Reference< XPropertySet > xProps( xFactory, UNO_QUERY );
1372         OSL_ASSERT( xProps.is() );
1373         if (xProps.is())
1374         {
1375             xProps->getPropertyValue(
1376                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= m_xContext;
1377             OSL_ASSERT( m_xContext.is() );
1378         }
1379     }
1380     if( !m_xContext.is() )
1381     {
1382         throw RuntimeException(
1383             ::rtl::OUString::createFromAscii( "ExtensionIteratorBase::init(), no XComponentContext" ),
1384             Reference< XInterface >() );
1385     }
1386 
1387     Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
1388     m_xSFA = Reference< ucb::XSimpleFileAccess >(
1389         xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
1390         m_xContext ), UNO_QUERY_THROW );
1391 
1392     m_bUserPackagesLoaded = false;
1393     m_bSharedPackagesLoaded = false;
1394     m_bBundledPackagesLoaded = false;
1395     m_iUserPackage = 0;
1396     m_iSharedPackage = 0;
1397     m_iBundledPackage = 0;
1398 }
1399 
implGetHelpPackageFromPackage(Reference<deployment::XPackage> xPackage,Reference<deployment::XPackage> & o_xParentPackageBundle)1400 Reference< deployment::XPackage > ExtensionIteratorBase::implGetHelpPackageFromPackage
1401     ( Reference< deployment::XPackage > xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
1402 {
1403     o_xParentPackageBundle.clear();
1404 
1405     Reference< deployment::XPackage > xHelpPackage;
1406     if( !xPackage.is() )
1407         return xHelpPackage;
1408 
1409     // #i84550 Cache information about help content in extension
1410     rtl::OUString aExtensionPath = xPackage->getURL();
1411     ExtensionHelpExistanceMap::iterator it = aHelpExistanceMap.find( aExtensionPath );
1412     bool bFound = ( it != aHelpExistanceMap.end() );
1413     bool bHasHelp = bFound ? it->second : false;
1414     if( bFound && !bHasHelp )
1415         return xHelpPackage;
1416 
1417     // Check if parent package is registered
1418     beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
1419         ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
1420     bool bRegistered = false;
1421     if( option.IsPresent )
1422     {
1423         beans::Ambiguous<sal_Bool> const & reg = option.Value;
1424         if( !reg.IsAmbiguous && reg.Value )
1425             bRegistered = true;
1426     }
1427     if( bRegistered )
1428     {
1429         if( xPackage->isBundle() )
1430         {
1431             Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
1432                 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
1433             sal_Int32 nPkgCount = aPkgSeq.getLength();
1434             const Reference< deployment::XPackage >* pSeq = aPkgSeq.getConstArray();
1435             for( sal_Int32 iPkg = 0 ; iPkg < nPkgCount ; ++iPkg )
1436             {
1437                 const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
1438                 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
1439                 rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
1440                 if( aMediaType.equals( aHelpMediaType ) )
1441                 {
1442                     xHelpPackage = xSubPkg;
1443                     o_xParentPackageBundle = xPackage;
1444                     break;
1445                 }
1446             }
1447         }
1448         else
1449         {
1450             const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
1451             rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
1452             if( aMediaType.equals( aHelpMediaType ) )
1453                 xHelpPackage = xPackage;
1454         }
1455     }
1456 
1457     if( !bFound )
1458         aHelpExistanceMap[ aExtensionPath ] = xHelpPackage.is();
1459 
1460     return xHelpPackage;
1461 }
1462 
implGetNextUserHelpPackage(Reference<deployment::XPackage> & o_xParentPackageBundle)1463 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextUserHelpPackage
1464     ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1465 {
1466     Reference< deployment::XPackage > xHelpPackage;
1467 
1468     if( !m_bUserPackagesLoaded )
1469     {
1470         Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1471         m_aUserPackagesSeq = xExtensionManager->getDeployedExtensions
1472             ( rtl::OUString::createFromAscii("user"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1473         m_bUserPackagesLoaded = true;
1474     }
1475 
1476     if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
1477     {
1478         m_eState = SHARED_EXTENSIONS;       // Later: SHARED_MODULE
1479     }
1480     else
1481     {
1482         const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
1483         Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage++ ];
1484         VOS_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextUserHelpPackage(): Invalid package" );
1485         xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1486     }
1487 
1488     return xHelpPackage;
1489 }
1490 
implGetNextSharedHelpPackage(Reference<deployment::XPackage> & o_xParentPackageBundle)1491 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextSharedHelpPackage
1492     ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1493 {
1494     Reference< deployment::XPackage > xHelpPackage;
1495 
1496     if( !m_bSharedPackagesLoaded )
1497     {
1498         Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1499         m_aSharedPackagesSeq = xExtensionManager->getDeployedExtensions
1500             ( rtl::OUString::createFromAscii("shared"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1501         m_bSharedPackagesLoaded = true;
1502     }
1503 
1504     if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
1505     {
1506         m_eState = BUNDLED_EXTENSIONS;
1507     }
1508     else
1509     {
1510         const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
1511         Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage++ ];
1512         VOS_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextSharedHelpPackage(): Invalid package" );
1513         xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1514     }
1515 
1516     return xHelpPackage;
1517 }
1518 
implGetNextBundledHelpPackage(Reference<deployment::XPackage> & o_xParentPackageBundle)1519 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextBundledHelpPackage
1520     ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1521 {
1522     Reference< deployment::XPackage > xHelpPackage;
1523 
1524     if( !m_bBundledPackagesLoaded )
1525     {
1526         Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1527         m_aBundledPackagesSeq = xExtensionManager->getDeployedExtensions
1528             ( rtl::OUString::createFromAscii("bundled"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1529         m_bBundledPackagesLoaded = true;
1530     }
1531 
1532     if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
1533     {
1534         m_eState = END_REACHED;
1535     }
1536     else
1537     {
1538         const Reference< deployment::XPackage >* pBundledPackages =
1539             m_aBundledPackagesSeq.getConstArray();
1540         Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage++ ];
1541         VOS_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextBundledHelpPackage(): Invalid package" );
1542         xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1543     }
1544 
1545     return xHelpPackage;
1546 }
1547 
implGetFileFromPackage(const rtl::OUString & rFileExtension,Reference<deployment::XPackage> xPackage)1548 rtl::OUString ExtensionIteratorBase::implGetFileFromPackage(
1549     const rtl::OUString& rFileExtension, Reference< deployment::XPackage > xPackage )
1550 {
1551     // No extension -> search for pure language folder
1552     bool bLangFolderOnly = (rFileExtension.getLength() == 0);
1553 
1554     rtl::OUString aFile;
1555     rtl::OUString aLanguage = m_aLanguage;
1556     for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1557     {
1558         rtl::OUStringBuffer aStrBuf;
1559         aStrBuf.append( xPackage->getRegistrationDataURL().Value);
1560         aStrBuf.append( aSlash );
1561         aStrBuf.append( aLanguage );
1562         if( !bLangFolderOnly )
1563         {
1564             aStrBuf.append( aSlash );
1565             aStrBuf.append( aHelpFilesBaseName );
1566             aStrBuf.append( rFileExtension );
1567         }
1568 
1569         aFile = m_rDatabases.expandURL( aStrBuf.makeStringAndClear() );
1570         if( iPass == 0 )
1571         {
1572             if( m_xSFA->exists( aFile ) )
1573                 break;
1574 
1575             ::std::vector< ::rtl::OUString > av;
1576             implGetLanguageVectorFromPackage( av, xPackage );
1577             ::std::vector< ::rtl::OUString >::const_iterator pFound = av.end();
1578             try
1579             {
1580                 pFound = ::comphelper::Locale::getFallback( av, m_aLanguage );
1581             }
1582             catch( ::comphelper::Locale::MalFormedLocaleException& )
1583             {}
1584             if( pFound != av.end() )
1585                 aLanguage = *pFound;
1586         }
1587     }
1588     return aFile;
1589 }
1590 
isLetter(sal_Unicode c)1591 inline bool isLetter( sal_Unicode c )
1592 {
1593     bool bLetter = ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
1594     return bLetter;
1595 }
1596 
implGetLanguageVectorFromPackage(::std::vector<::rtl::OUString> & rv,com::sun::star::uno::Reference<com::sun::star::deployment::XPackage> xPackage)1597 void ExtensionIteratorBase::implGetLanguageVectorFromPackage( ::std::vector< ::rtl::OUString > &rv,
1598     com::sun::star::uno::Reference< com::sun::star::deployment::XPackage > xPackage )
1599 {
1600     rv.clear();
1601     rtl::OUString aExtensionPath = xPackage->getURL();
1602     Sequence< rtl::OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1603 
1604     const rtl::OUString* pSeq = aEntrySeq.getConstArray();
1605     sal_Int32 nCount = aEntrySeq.getLength();
1606     for( sal_Int32 i = 0 ; i < nCount ; ++i )
1607     {
1608         rtl::OUString aEntry = pSeq[i];
1609         if( m_xSFA->isFolder( aEntry ) )
1610         {
1611             sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1612             if( nLastSlash != -1 )
1613             {
1614                 rtl::OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1615 
1616                 // Check language sceme
1617                 int nLen = aPureEntry.getLength();
1618                 const sal_Unicode* pc = aPureEntry.getStr();
1619                 bool bStartCanBeLanguage = ( nLen >= 2 && isLetter( pc[0] ) && isLetter( pc[1] ) );
1620                 bool bIsLanguage = bStartCanBeLanguage &&
1621                     ( nLen == 2 || (nLen == 5 && pc[2] == '-' && isLetter( pc[3] ) && isLetter( pc[4] )) );
1622                 if( bIsLanguage )
1623                     rv.push_back( aPureEntry );
1624             }
1625         }
1626     }
1627 }
1628 
1629 
1630 //===================================================================
1631 // class DataBaseIterator
1632 
nextHdf(rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1633 helpdatafileproxy::Hdf* DataBaseIterator::nextHdf( rtl::OUString* o_pExtensionPath, rtl::OUString* o_pExtensionRegistryPath )
1634 {
1635     helpdatafileproxy::Hdf* pRetHdf = NULL;
1636 
1637     while( !pRetHdf && m_eState != END_REACHED )
1638     {
1639         switch( m_eState )
1640         {
1641             case INITIAL_MODULE:
1642                 pRetHdf = m_rDatabases.getHelpDataFile( m_aInitialModule, m_aLanguage, m_bHelpText );
1643                 m_eState = USER_EXTENSIONS;     // Later: SHARED_MODULE
1644                 break;
1645 
1646             // Later:
1647             //case SHARED_MODULE
1648                 //...
1649 
1650             case USER_EXTENSIONS:
1651             {
1652                 Reference< deployment::XPackage > xParentPackageBundle;
1653                 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1654                 if( !xHelpPackage.is() )
1655                     break;
1656                 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1657                 break;
1658             }
1659 
1660             case SHARED_EXTENSIONS:
1661             {
1662                 Reference< deployment::XPackage > xParentPackageBundle;
1663                 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1664                 if( !xHelpPackage.is() )
1665                     break;
1666 
1667                 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1668                 break;
1669             }
1670 
1671             case BUNDLED_EXTENSIONS:
1672             {
1673                 Reference< deployment::XPackage > xParentPackageBundle;
1674                 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1675                 if( !xHelpPackage.is() )
1676                     break;
1677 
1678                 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1679                 break;
1680             }
1681 
1682             case END_REACHED:
1683                 VOS_ENSURE( false, "DataBaseIterator::nextDb(): Invalid case END_REACHED" );
1684                 break;
1685         }
1686     }
1687 
1688     return pRetHdf;
1689 }
1690 
implGetHdfFromPackage(Reference<deployment::XPackage> xPackage,rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1691 helpdatafileproxy::Hdf* DataBaseIterator::implGetHdfFromPackage( Reference< deployment::XPackage > xPackage,
1692             rtl::OUString* o_pExtensionPath, rtl::OUString* o_pExtensionRegistryPath )
1693 {
1694 
1695     beans::Optional< ::rtl::OUString> optRegData;
1696     try
1697     {
1698         optRegData = xPackage->getRegistrationDataURL();
1699     }
1700     catch ( deployment::ExtensionRemovedException&)
1701     {
1702         return NULL;
1703     }
1704 
1705     helpdatafileproxy::Hdf* pRetHdf = NULL;
1706     if (optRegData.IsPresent && optRegData.Value.getLength() > 0)
1707     {
1708         rtl::OUString aRegDataUrl(optRegData.Value);
1709         aRegDataUrl += aSlash;
1710 
1711         rtl::OUString aUsedLanguage = m_aLanguage;
1712         pRetHdf = m_rDatabases.getHelpDataFile(
1713             aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1714 
1715         // Language fallback
1716         if( !pRetHdf )
1717         {
1718             ::std::vector< ::rtl::OUString > av;
1719             implGetLanguageVectorFromPackage( av, xPackage );
1720             ::std::vector< ::rtl::OUString >::const_iterator pFound = av.end();
1721             try
1722             {
1723                 pFound = ::comphelper::Locale::getFallback( av, m_aLanguage );
1724             }
1725             catch( ::comphelper::Locale::MalFormedLocaleException& )
1726             {}
1727             if( pFound != av.end() )
1728             {
1729                 aUsedLanguage = *pFound;
1730                 pRetHdf = m_rDatabases.getHelpDataFile(
1731                     aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1732             }
1733         }
1734 
1735         if( o_pExtensionPath )
1736             *o_pExtensionPath = aRegDataUrl + aUsedLanguage;
1737 
1738         if( o_pExtensionRegistryPath )
1739             *o_pExtensionRegistryPath = xPackage->getURL() + aSlash + aUsedLanguage;
1740     }
1741 
1742     return pRetHdf;
1743 }
1744 
1745 
1746 //===================================================================
1747 // class KeyDataBaseFileIterator
1748 
1749 //returns a file URL
nextDbFile(bool & o_rbExtension)1750 rtl::OUString KeyDataBaseFileIterator::nextDbFile( bool& o_rbExtension )
1751 {
1752     rtl::OUString aRetFile;
1753 
1754     while( !aRetFile.getLength() && m_eState != END_REACHED )
1755     {
1756         switch( m_eState )
1757         {
1758             case INITIAL_MODULE:
1759                 aRetFile =
1760                     m_rDatabases.getInstallPathAsURL() +
1761                     m_rDatabases.processLang( m_aLanguage ) + aSlash + m_aInitialModule +
1762                     rtl::OUString::createFromAscii( ".key" );
1763 
1764                 o_rbExtension = false;
1765 
1766                 m_eState = USER_EXTENSIONS;     // Later: SHARED_MODULE
1767                 break;
1768 
1769             // Later:
1770             //case SHARED_MODULE
1771                 //...
1772 
1773             case USER_EXTENSIONS:
1774             {
1775                 Reference< deployment::XPackage > xParentPackageBundle;
1776                 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1777                 if( !xHelpPackage.is() )
1778                     break;
1779 
1780                 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1781                 o_rbExtension = true;
1782                 break;
1783             }
1784 
1785             case SHARED_EXTENSIONS:
1786             {
1787                 Reference< deployment::XPackage > xParentPackageBundle;
1788                 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1789                 if( !xHelpPackage.is() )
1790                     break;
1791 
1792                 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1793                 o_rbExtension = true;
1794                 break;
1795             }
1796 
1797             case BUNDLED_EXTENSIONS:
1798             {
1799                 Reference< deployment::XPackage > xParentPackageBundle;
1800                 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1801                 if( !xHelpPackage.is() )
1802                     break;
1803 
1804                 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1805                 o_rbExtension = true;
1806                 break;
1807             }
1808 
1809             case END_REACHED:
1810                 VOS_ENSURE( false, "DataBaseIterator::nextDbFile(): Invalid case END_REACHED" );
1811                 break;
1812         }
1813     }
1814 
1815     return aRetFile;
1816 }
1817 
1818 //Returns a file URL, that does not contain macros
implGetDbFileFromPackage(Reference<deployment::XPackage> xPackage)1819 rtl::OUString KeyDataBaseFileIterator::implGetDbFileFromPackage
1820     ( Reference< deployment::XPackage > xPackage )
1821 {
1822     rtl::OUString aExpandedURL =
1823         implGetFileFromPackage( rtl::OUString::createFromAscii( ".key" ), xPackage );
1824 
1825     return aExpandedURL;
1826 }
1827 
1828 
1829 //===================================================================
1830 // class JarFileIterator
1831 
nextJarFile(Reference<deployment::XPackage> & o_xParentPackageBundle,rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1832 Reference< XHierarchicalNameAccess > JarFileIterator::nextJarFile
1833     ( Reference< deployment::XPackage >& o_xParentPackageBundle,
1834         rtl::OUString* o_pExtensionPath, rtl::OUString* o_pExtensionRegistryPath )
1835 {
1836     Reference< XHierarchicalNameAccess > xNA;
1837 
1838     while( !xNA.is() && m_eState != END_REACHED )
1839     {
1840         switch( m_eState )
1841         {
1842             case INITIAL_MODULE:
1843                 xNA = m_rDatabases.jarFile( m_aInitialModule, m_aLanguage );
1844                 m_eState = USER_EXTENSIONS;     // Later: SHARED_MODULE
1845                 break;
1846 
1847             // Later:
1848             //case SHARED_MODULE
1849                 //...
1850 
1851             case USER_EXTENSIONS:
1852             {
1853                 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( o_xParentPackageBundle );
1854                 if( !xHelpPackage.is() )
1855                     break;
1856 
1857                 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1858                 break;
1859             }
1860 
1861             case SHARED_EXTENSIONS:
1862             {
1863                 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( o_xParentPackageBundle );
1864                 if( !xHelpPackage.is() )
1865                     break;
1866 
1867                 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1868                 break;
1869             }
1870 
1871             case BUNDLED_EXTENSIONS:
1872             {
1873                 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( o_xParentPackageBundle );
1874                 if( !xHelpPackage.is() )
1875                     break;
1876 
1877                 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1878                 break;
1879             }
1880 
1881             case END_REACHED:
1882                 VOS_ENSURE( false, "JarFileIterator::nextJarFile(): Invalid case END_REACHED" );
1883                 break;
1884         }
1885     }
1886 
1887     return xNA;
1888 }
1889 
implGetJarFromPackage(Reference<deployment::XPackage> xPackage,rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1890 Reference< XHierarchicalNameAccess > JarFileIterator::implGetJarFromPackage
1891 ( Reference< deployment::XPackage > xPackage, rtl::OUString* o_pExtensionPath, rtl::OUString* o_pExtensionRegistryPath )
1892 {
1893     Reference< XHierarchicalNameAccess > xNA;
1894 
1895     rtl::OUString zipFile =
1896         implGetFileFromPackage( rtl::OUString::createFromAscii( ".jar" ), xPackage );
1897 
1898     try
1899     {
1900         Sequence< Any > aArguments( 2 );
1901         aArguments[ 0 ] <<= zipFile;
1902 
1903         // let ZipPackage be used ( no manifest.xml is required )
1904         beans::NamedValue aArg;
1905         aArg.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
1906         aArg.Value <<= ZIP_STORAGE_FORMAT_STRING;
1907         aArguments[ 1 ] <<= aArg;
1908 
1909         Reference< XMultiComponentFactory >xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
1910         Reference< XInterface > xIfc
1911             = xSMgr->createInstanceWithArgumentsAndContext(
1912                 rtl::OUString::createFromAscii(
1913                     "com.sun.star.packages.comp.ZipPackage" ),
1914                 aArguments, m_xContext );
1915 
1916         if ( xIfc.is() )
1917         {
1918             xNA = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1919 
1920             VOS_ENSURE( xNA.is(),
1921                 "JarFileIterator::implGetJarFromPackage() - "
1922                 "Got no hierarchical name access!" );
1923         }
1924     }
1925     catch ( RuntimeException & )
1926     {}
1927     catch ( Exception & )
1928     {}
1929 
1930     if( xNA.is() && o_pExtensionPath != NULL )
1931     {
1932         // Extract path including language from file name
1933         sal_Int32 nLastSlash = zipFile.lastIndexOf( '/' );
1934         if( nLastSlash != -1 )
1935             *o_pExtensionPath = zipFile.copy( 0, nLastSlash );
1936 
1937         if( o_pExtensionRegistryPath != NULL )
1938         {
1939             rtl::OUString& rPath = *o_pExtensionPath;
1940             sal_Int32 nLastSlashInPath = rPath.lastIndexOf( '/', rPath.getLength() - 1 );
1941 
1942             *o_pExtensionRegistryPath = xPackage->getURL();
1943             *o_pExtensionRegistryPath += rPath.copy( nLastSlashInPath);
1944         }
1945     }
1946 
1947     return xNA;
1948 }
1949 
1950 
1951 //===================================================================
1952 // class IndexFolderIterator
1953 
nextIndexFolder(bool & o_rbExtension,bool & o_rbTemporary)1954 rtl::OUString IndexFolderIterator::nextIndexFolder( bool& o_rbExtension, bool& o_rbTemporary )
1955 {
1956     rtl::OUString aIndexFolder;
1957 
1958     while( !aIndexFolder.getLength() && m_eState != END_REACHED )
1959     {
1960         switch( m_eState )
1961         {
1962             case INITIAL_MODULE:
1963                 aIndexFolder =
1964                     m_rDatabases.getInstallPathAsURL() +
1965                     m_rDatabases.processLang( m_aLanguage ) + aSlash + m_aInitialModule +
1966                     rtl::OUString::createFromAscii( ".idxl" );
1967 
1968                 o_rbTemporary = false;
1969                 o_rbExtension = false;
1970 
1971                 m_eState = USER_EXTENSIONS;     // Later: SHARED_MODULE
1972                 break;
1973 
1974             // Later:
1975             //case SHARED_MODULE
1976                 //...
1977 
1978             case USER_EXTENSIONS:
1979             {
1980                 Reference< deployment::XPackage > xParentPackageBundle;
1981                 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1982                 if( !xHelpPackage.is() )
1983                     break;
1984 
1985                 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1986                 o_rbExtension = true;
1987                 break;
1988             }
1989 
1990             case SHARED_EXTENSIONS:
1991             {
1992                 Reference< deployment::XPackage > xParentPackageBundle;
1993                 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1994                 if( !xHelpPackage.is() )
1995                     break;
1996 
1997                 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1998                 o_rbExtension = true;
1999                 break;
2000             }
2001 
2002             case BUNDLED_EXTENSIONS:
2003             {
2004                 Reference< deployment::XPackage > xParentPackageBundle;
2005                 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
2006                 if( !xHelpPackage.is() )
2007                     break;
2008 
2009                 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
2010                 o_rbExtension = true;
2011                 break;
2012             }
2013 
2014             case END_REACHED:
2015                 VOS_ENSURE( false, "IndexFolderIterator::nextIndexFolder(): Invalid case END_REACHED" );
2016                 break;
2017         }
2018     }
2019 
2020     return aIndexFolder;
2021 }
2022 
implGetIndexFolderFromPackage(bool & o_rbTemporary,Reference<deployment::XPackage> xPackage)2023 rtl::OUString IndexFolderIterator::implGetIndexFolderFromPackage( bool& o_rbTemporary, Reference< deployment::XPackage > xPackage )
2024 {
2025     rtl::OUString aIndexFolder =
2026         implGetFileFromPackage( rtl::OUString::createFromAscii( ".idxl" ), xPackage );
2027 
2028     o_rbTemporary = false;
2029     if( !m_xSFA->isFolder( aIndexFolder ) )
2030     {
2031         // i98680: Missing index? Try to generate now
2032         rtl::OUString aLangURL = implGetFileFromPackage( rtl::OUString(), xPackage );
2033         if( m_xSFA->isFolder( aLangURL ) )
2034         {
2035             // Test write access (shared extension may be read only)
2036             bool bIsWriteAccess = false;
2037             try
2038             {
2039                 rtl::OUString aCreateTestFolder = aLangURL + rtl::OUString::createFromAscii( "CreateTestFolder" );
2040                 m_xSFA->createFolder( aCreateTestFolder );
2041                 if( m_xSFA->isFolder( aCreateTestFolder  ) )
2042                     bIsWriteAccess = true;
2043 
2044                 m_xSFA->kill( aCreateTestFolder );
2045             }
2046             catch (Exception &)
2047             {}
2048 
2049             // TEST
2050             //bIsWriteAccess = false;
2051 
2052             Reference< script::XInvocation > xInvocation;
2053             Reference< XMultiComponentFactory >xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
2054             try
2055             {
2056                 xInvocation = Reference< script::XInvocation >(
2057                     m_xContext->getServiceManager()->createInstanceWithContext( rtl::OUString::createFromAscii(
2058                     "com.sun.star.help.HelpIndexer" ), m_xContext ) , UNO_QUERY );
2059 
2060                 if( xInvocation.is() )
2061                 {
2062                     Sequence<uno::Any> aParamsSeq( bIsWriteAccess ? 6 : 8 );
2063 
2064                     aParamsSeq[0] = uno::makeAny( rtl::OUString::createFromAscii( "-lang" ) );
2065 
2066                     rtl::OUString aLang;
2067                     sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
2068                     if( nLastSlash != -1 )
2069                         aLang = aLangURL.copy( nLastSlash + 1 );
2070                     else
2071                         aLang = rtl::OUString::createFromAscii( "en" );
2072                     aParamsSeq[1] = uno::makeAny( aLang );
2073 
2074                     aParamsSeq[2] = uno::makeAny( rtl::OUString::createFromAscii( "-mod" ) );
2075                     aParamsSeq[3] = uno::makeAny( rtl::OUString::createFromAscii( "help" ) );
2076 
2077                     rtl::OUString aZipDir = aLangURL;
2078                     if( !bIsWriteAccess )
2079                     {
2080                         rtl::OUString aTempFileURL;
2081                         ::osl::FileBase::RC eErr = ::osl::File::createTempFile( 0, 0, &aTempFileURL );
2082                         if( eErr == ::osl::FileBase::E_None )
2083                         {
2084                             rtl::OUString aTempDirURL = aTempFileURL;
2085                             try
2086                             {
2087                                 m_xSFA->kill( aTempDirURL );
2088                             }
2089                             catch (Exception &)
2090                             {}
2091                             m_xSFA->createFolder( aTempDirURL );
2092 
2093                             aZipDir = aTempDirURL;
2094                             o_rbTemporary = true;
2095                         }
2096                     }
2097 
2098                     aParamsSeq[4] = uno::makeAny( rtl::OUString::createFromAscii( "-zipdir" ) );
2099                     rtl::OUString aSystemPath;
2100                     osl::FileBase::getSystemPathFromFileURL( aZipDir, aSystemPath );
2101                     aParamsSeq[5] = uno::makeAny( aSystemPath );
2102 
2103                     if( !bIsWriteAccess )
2104                     {
2105                         aParamsSeq[6] = uno::makeAny( rtl::OUString::createFromAscii( "-srcdir" ) );
2106                         rtl::OUString aSrcDirVal;
2107                         osl::FileBase::getSystemPathFromFileURL( aLangURL, aSrcDirVal );
2108                         aParamsSeq[7] = uno::makeAny( aSrcDirVal );
2109                     }
2110 
2111                     Sequence< sal_Int16 > aOutParamIndex;
2112                     Sequence< uno::Any > aOutParam;
2113                     uno::Any aRet = xInvocation->invoke( rtl::OUString::createFromAscii( "createIndex" ),
2114                         aParamsSeq, aOutParamIndex, aOutParam );
2115 
2116                     if( bIsWriteAccess )
2117                         aIndexFolder = implGetFileFromPackage( rtl::OUString::createFromAscii( ".idxl" ), xPackage );
2118                     else
2119                         aIndexFolder = aZipDir + rtl::OUString::createFromAscii( "/help.idxl" );
2120                 }
2121             }
2122             catch (Exception &)
2123             {}
2124         }
2125     }
2126 
2127     return aIndexFolder;
2128 }
2129 
deleteTempIndexFolder(const rtl::OUString & aIndexFolder)2130 void IndexFolderIterator::deleteTempIndexFolder( const rtl::OUString& aIndexFolder )
2131 {
2132     sal_Int32 nLastSlash = aIndexFolder.lastIndexOf( '/' );
2133     if( nLastSlash != -1 )
2134     {
2135         rtl::OUString aTmpFolder = aIndexFolder.copy( 0, nLastSlash );
2136         try
2137         {
2138             m_xSFA->kill( aTmpFolder );
2139         }
2140         catch (Exception &)
2141         {}
2142     }
2143 }
2144