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