bump product version to 5.0.4.1
[LibreOffice.git] / xmlhelp / source / cxxhelp / provider / databases.cxx
blobc2d11d1cab950ca0edd40e3025207b87e722536c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "db.hxx"
21 #include <osl/diagnose.h>
22 #include <osl/thread.h>
23 #include <osl/process.h>
24 #include <rtl/uri.hxx>
25 #include <osl/file.hxx>
26 #include <com/sun/star/lang/Locale.hpp>
27 #include <com/sun/star/awt/Toolkit.hpp>
28 #include <com/sun/star/i18n/Collator.hpp>
29 #include <rtl/ustrbuf.hxx>
30 #include "inputstream.hxx"
31 #include <algorithm>
32 #include <cassert>
33 #include <string.h>
35 #include <helpcompiler/HelpIndexer.hxx>
37 // Extensible help
38 #include <com/sun/star/deployment/ExtensionManager.hpp>
39 #include <com/sun/star/deployment/thePackageManagerFactory.hpp>
40 #include <comphelper/processfactory.hxx>
41 #include <com/sun/star/uno/XComponentContext.hpp>
42 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
43 #include <com/sun/star/beans/Optional.hpp>
44 #include <com/sun/star/beans/PropertyValue.hpp>
45 #include <com/sun/star/beans/NamedValue.hpp>
46 #include <com/sun/star/configuration/theDefaultProvider.hpp>
47 #include <com/sun/star/frame/XConfigManager.hpp>
48 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
49 #include <com/sun/star/util/theMacroExpander.hpp>
50 #include <com/sun/star/uri/UriReferenceFactory.hpp>
51 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
52 #include <com/sun/star/script/XInvocation.hpp>
53 #include <i18nlangtag/languagetag.hxx>
55 #include <com/sun/star/awt/XToolkit.hpp>
56 #include <com/sun/star/awt/XExtendedToolkit.hpp>
57 #include <com/sun/star/awt/XWindowPeer.hpp>
58 #include <com/sun/star/awt/XVclWindowPeer.hpp>
59 #include <com/sun/star/awt/XTopWindow.hpp>
61 #include <comphelper/storagehelper.hxx>
62 #include <comphelper/string.hxx>
64 #include <vcl/svapp.hxx>
66 #include "databases.hxx"
67 #include "urlparameter.hxx"
69 #ifdef WNT
70 #include <windows.h>
71 #endif
73 using namespace chelp;
74 using namespace com::sun::star;
75 using namespace com::sun::star::uno;
76 using namespace com::sun::star::io;
77 using namespace com::sun::star::container;
78 using namespace com::sun::star::i18n;
79 using namespace com::sun::star::lang;
80 using namespace com::sun::star::deployment;
81 using namespace com::sun::star::beans;
83 OUString Databases::expandURL( const OUString& aURL )
85 osl::MutexGuard aGuard( m_aMutex );
86 OUString aRetURL = expandURL( aURL, m_xContext );
87 return aRetURL;
90 OUString Databases::expandURL( const OUString& aURL, Reference< uno::XComponentContext > xContext )
92 static Reference< util::XMacroExpander > xMacroExpander;
93 static Reference< uri::XUriReferenceFactory > xFac;
95 if( !xMacroExpander.is() || !xFac.is() )
97 xFac = uri::UriReferenceFactory::create( xContext );
99 xMacroExpander = util::theMacroExpander::get(xContext);
102 OUString aRetURL = aURL;
103 if( xMacroExpander.is() )
105 Reference< uri::XUriReference > uriRef;
106 for (;;)
108 uriRef = Reference< uri::XUriReference >( xFac->parse( aRetURL ), UNO_QUERY );
109 if ( uriRef.is() )
111 Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
112 if( !sxUri.is() )
113 break;
115 aRetURL = sxUri->expand( xMacroExpander );
119 return aRetURL;
122 Databases::Databases( bool showBasic,
123 const OUString& instPath,
124 const OUString& productName,
125 const OUString& productVersion,
126 const OUString& styleSheet,
127 Reference< uno::XComponentContext > xContext )
128 : m_xContext( xContext ),
129 m_bShowBasic(showBasic),
130 m_pErrorDoc( 0 ),
131 m_nCustomCSSDocLength( 0 ),
132 m_pCustomCSSDoc( 0 ),
133 m_aCSS(styleSheet.toAsciiLowerCase()),
134 newProdName( "$[officename]" ),
135 newProdVersion( "$[officeversion]" ),
136 prodName( "%PRODUCTNAME" ),
137 prodVersion( "%PRODUCTVERSION" ),
138 vendName( "%VENDORNAME" ),
139 vendVersion( "%VENDORVERSION" ),
140 vendShort( "%VENDORSHORT" )
142 m_xSMgr = Reference< XMultiComponentFactory >( m_xContext->getServiceManager(), UNO_QUERY );
144 m_vAdd[0] = 12;
145 m_vAdd[1] = 15;
146 m_vAdd[2] = 11;
147 m_vAdd[3] = 14;
148 m_vAdd[4] = 12;
149 m_vAdd[5] = 13;
150 m_vAdd[6] = 16;
152 m_vReplacement[0] = productName;
153 m_vReplacement[1] = productVersion;
154 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
155 m_vReplacement[5] = productName;
156 m_vReplacement[6] = productVersion;
158 setInstallPath( instPath );
160 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
163 Databases::~Databases()
165 // release stylesheet
167 delete[] m_pCustomCSSDoc;
169 // release errorDocument
171 delete[] m_pErrorDoc;
173 // unload the databases
176 // DatabasesTable
177 DatabasesTable::iterator it = m_aDatabases.begin();
178 while( it != m_aDatabases.end() )
180 delete it->second;
181 ++it;
186 // ModInfoTable
188 ModInfoTable::iterator it = m_aModInfo.begin();
189 while( it != m_aModInfo.end() )
191 delete it->second;
192 ++it;
197 // KeywordInfoTable
199 KeywordInfoTable::iterator it = m_aKeywordInfo.begin();
200 while( it != m_aKeywordInfo.end() )
202 delete it->second;
203 ++it;
208 OString Databases::getImageTheme()
210 uno::Reference< lang::XMultiServiceFactory > xConfigProvider =
211 configuration::theDefaultProvider::get(m_xContext);
213 // set root path
214 uno::Sequence < uno::Any > lParams(1);
215 beans::PropertyValue aParam ;
216 aParam.Name = "nodepath";
217 aParam.Value <<= OUString("org.openoffice.Office.Common");
218 lParams[0] = uno::makeAny(aParam);
220 // open it
221 uno::Reference< uno::XInterface > xCFG( xConfigProvider->createInstanceWithArguments(
222 OUString("com.sun.star.configuration.ConfigurationAccess"),
223 lParams) );
225 uno::Reference< container::XHierarchicalNameAccess > xAccess(xCFG, uno::UNO_QUERY_THROW);
226 uno::Any aResult = xAccess->getByHierarchicalName(OUString("Misc/SymbolStyle"));
227 OUString aSymbolsStyleName;
228 aResult >>= aSymbolsStyleName;
230 if ( aSymbolsStyleName.isEmpty() || aSymbolsStyleName == "auto" )
232 aSymbolsStyleName = "tango";
234 return aSymbolsStyleName.toUtf8();
237 void Databases::replaceName( OUString& oustring ) const
239 sal_Int32 idx = -1,idx1 = -1,idx2 = -1,k = 0,off;
240 bool cap = false;
241 OUStringBuffer aStrBuf( 0 );
243 while( true )
245 ++idx;
246 idx1 = oustring.indexOf( '%', idx);
247 idx2 = oustring.indexOf( '$', idx);
249 if(idx1 == -1 && idx2 == -1)
250 break;
252 if(idx1 == -1)
253 idx = idx2;
254 else if(idx2 == -1)
255 idx = idx1;
256 else {
257 // no index is zero
258 if(idx1 < idx2)
259 idx = idx1;
260 else if(idx2 < idx1 )
261 idx = idx2;
264 if( oustring.indexOf( prodName,idx ) == idx )
265 off = PRODUCTNAME;
266 else if( oustring.indexOf( prodVersion,idx ) == idx )
267 off = PRODUCTVERSION;
268 else if( oustring.indexOf( vendName,idx ) == idx )
269 off = VENDORNAME;
270 else if( oustring.indexOf( vendVersion,idx ) == idx )
271 off = VENDORVERSION;
272 else if( oustring.indexOf( vendShort,idx ) == idx )
273 off = VENDORSHORT;
274 else if( oustring.indexOf( newProdName,idx ) == idx )
275 off = NEWPRODUCTNAME;
276 else if( oustring.indexOf( newProdVersion,idx ) == idx )
277 off = NEWPRODUCTVERSION;
278 else
279 off = -1;
281 if( off != -1 )
283 if( ! cap )
285 cap = true;
286 aStrBuf.ensureCapacity( 256 );
289 aStrBuf.append( &oustring.getStr()[k],idx - k );
290 aStrBuf.append( m_vReplacement[off] );
291 k = idx + m_vAdd[off];
295 if( cap )
297 if( k < oustring.getLength() )
298 aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
299 oustring = aStrBuf.makeStringAndClear();
303 OUString Databases::getInstallPathAsURL()
305 osl::MutexGuard aGuard( m_aMutex );
307 return m_aInstallDirectory;
310 const std::vector< OUString >& Databases::getModuleList( const OUString& Language )
312 if( m_avModules.empty() )
314 OUString fileName,dirName = getInstallPathAsURL() + processLang( Language );
315 osl::Directory dirFile( dirName );
317 osl::DirectoryItem aDirItem;
318 osl::FileStatus aStatus( osl_FileStatus_Mask_FileName );
320 sal_Int32 idx;
322 if( osl::FileBase::E_None != dirFile.open() )
323 return m_avModules;
325 while( dirFile.getNextItem( aDirItem ) == osl::FileBase::E_None &&
326 aDirItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
328 if( ! aStatus.isValid( osl_FileStatus_Mask_FileName ) )
329 continue;
331 fileName = aStatus.getFileName();
333 // Check, whether fileName is of the form *.cfg
334 idx = fileName.lastIndexOf( '.' );
336 if( idx == -1 )
337 continue;
339 const sal_Unicode* str = fileName.getStr();
341 if( fileName.getLength() == idx + 4 &&
342 ( str[idx + 1] == 'c' || str[idx + 1] == 'C' ) &&
343 ( str[idx + 2] == 'f' || str[idx + 2] == 'F' ) &&
344 ( str[idx + 3] == 'g' || str[idx + 3] == 'G' ) &&
345 ( fileName = fileName.copy(0,idx).toAsciiLowerCase() ) != "picture" ) {
346 if(! m_bShowBasic && fileName == "sbasic" )
347 continue;
348 m_avModules.push_back( fileName );
352 return m_avModules;
355 StaticModuleInformation* Databases::getStaticInformationForModule( const OUString& Module,
356 const OUString& Language )
358 osl::MutexGuard aGuard( m_aMutex );
360 OUString key = processLang(Language) + "/" + Module;
362 std::pair< ModInfoTable::iterator,bool > aPair =
363 m_aModInfo.insert( ModInfoTable::value_type( key,(StaticModuleInformation*)0 ) );
365 ModInfoTable::iterator it = aPair.first;
367 if( aPair.second && ! it->second )
369 osl::File cfgFile( getInstallPathAsURL() + key + ".cfg" );
371 if( osl::FileBase::E_None != cfgFile.open( osl_File_OpenFlag_Read ) )
372 it->second = 0;
373 else
375 sal_uInt32 pos = 0;
376 sal_uInt64 nRead;
377 sal_Char buffer[2048];
378 sal_Unicode lineBuffer[1028];
379 OUString fileContent;
381 while( osl::FileBase::E_None == cfgFile.read( &buffer,2048,nRead ) && nRead )
382 fileContent += OUString( buffer,sal_Int32( nRead ),RTL_TEXTENCODING_UTF8 );
384 cfgFile.close();
386 const sal_Unicode* str = fileContent.getStr();
387 OUString current,lang_,program,startid,title,heading,fulltext;
388 OUString order( "1" );
390 for( sal_Int32 i = 0;i < fileContent.getLength();i++ )
392 sal_Unicode ch = str[ i ];
393 if( ch == '\n' || ch == '\r' )
395 if( pos )
397 current = OUString( lineBuffer,pos );
399 if( current.startsWith("Title") )
401 title = current.copy( current.indexOf( '=' ) + 1 );
403 else if( current.startsWith("Start") )
405 startid = current.copy( current.indexOf('=') + 1 );
407 else if( current.startsWith("Language") )
409 lang_ = current.copy( current.indexOf('=') + 1 );
411 else if( current.startsWith("Program") )
413 program = current.copy( current.indexOf('=') + 1 );
415 else if( current.startsWith("Heading") )
417 heading = current.copy( current.indexOf('=') + 1 );
419 else if( current.startsWith("FullText") )
421 fulltext = current.copy( current.indexOf('=') + 1 );
423 else if( current.startsWith("Order") )
425 order = current.copy( current.indexOf('=') + 1 );
428 pos = 0;
430 else
431 lineBuffer[ pos++ ] = ch;
433 replaceName( title );
434 it->second = new StaticModuleInformation( title,
435 startid,
436 program,
437 heading,
438 fulltext,
439 order );
443 return it->second;
446 OUString Databases::processLang( const OUString& Language )
448 osl::MutexGuard aGuard( m_aMutex );
450 OUString ret;
451 LangSetTable::iterator it = m_aLangSet.find( Language );
453 if( it == m_aLangSet.end() )
455 sal_Int32 idx;
456 osl::DirectoryItem aDirItem;
458 if( osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language,aDirItem ) )
460 ret = Language;
461 m_aLangSet[ Language ] = ret;
463 else if( ( ( idx = Language.indexOf( '-' ) ) != -1 ||
464 ( idx = Language.indexOf( '_' ) ) != -1 ) &&
465 osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language.copy( 0,idx ),
466 aDirItem ) )
468 ret = Language.copy( 0,idx );
469 m_aLangSet[ Language ] = ret;
472 else
473 ret = it->second;
475 return ret;
478 OUString Databases::country( const OUString& Language )
480 sal_Int32 idx;
481 if( ( idx = Language.indexOf( '-' ) ) != -1 ||
482 ( idx = Language.indexOf( '_' ) ) != -1 )
483 return Language.copy( 1+idx );
485 return OUString();
488 helpdatafileproxy::Hdf* Databases::getHelpDataFile( const OUString& Database,
489 const OUString& Language, bool helpText,
490 const OUString* pExtensionPath )
492 if( Database.isEmpty() || Language.isEmpty() )
493 return 0;
495 osl::MutexGuard aGuard( m_aMutex );
497 OUString aFileExt( helpText ? OUString(".ht") : OUString(".db") );
498 OUString dbFileName = "/" + Database + aFileExt;
499 OUString key;
500 if( pExtensionPath == NULL )
501 key = processLang( Language ) + dbFileName;
502 else
503 key = *pExtensionPath + Language + dbFileName; // make unique, don't change language
505 std::pair< DatabasesTable::iterator,bool > aPair =
506 m_aDatabases.insert( DatabasesTable::value_type( key, reinterpret_cast<helpdatafileproxy::Hdf *>(0) ) );
508 DatabasesTable::iterator it = aPair.first;
510 if( aPair.second && ! it->second )
512 helpdatafileproxy::Hdf* pHdf = 0;
514 OUString fileURL;
515 if( pExtensionPath )
516 fileURL = expandURL(*pExtensionPath) + Language + dbFileName;
517 else
518 fileURL = getInstallPathAsURL() + key;
520 OUString fileNameHDFHelp( fileURL );
521 //Extensions always use the new format
522 if( pExtensionPath != NULL )
523 fileNameHDFHelp += "_";
524 //SimpleFileAccess takes file URLs as arguments!!! Using filenames works accidentally but
525 //fails for example when using long path names on Windows (starting with \\?\)
526 if( m_xSFA->exists( fileNameHDFHelp ) )
528 pHdf = new helpdatafileproxy::Hdf( fileNameHDFHelp, m_xSFA );
531 it->second = pHdf;
534 return it->second;
537 Reference< XCollator >
538 Databases::getCollator( const OUString& Language,
539 const OUString& System )
541 (void)System;
543 OUString key = Language;
545 osl::MutexGuard aGuard( m_aMutex );
547 CollatorTable::iterator it =
548 m_aCollatorTable.insert( CollatorTable::value_type( key, Reference< XCollator >() ) ).first;
550 if( ! it->second.is() )
552 it->second = Collator::create(m_xContext);
553 OUString langStr = processLang(Language);
554 OUString countryStr = country(Language);
555 if( countryStr.isEmpty() )
557 if( langStr == "de" )
558 countryStr = "DE";
559 else if( langStr == "en" )
560 countryStr = "US";
561 else if( langStr == "es" )
562 countryStr = "ES";
563 else if( langStr == "it" )
564 countryStr = "IT";
565 else if( langStr == "fr" )
566 countryStr = "FR";
567 else if( langStr == "sv" )
568 countryStr = "SE";
569 else if( langStr == "ja" )
570 countryStr = "JP";
571 else if( langStr == "ko" )
572 countryStr = "KR";
574 /* FIXME-BCP47: all this does not look right for language tag context,
575 * also check processLang() and country() methods */
576 it->second->loadDefaultCollator( Locale( langStr,
577 countryStr,
578 OUString() ),
579 0 );
582 return it->second;
585 namespace chelp {
587 struct KeywordElementComparator
589 KeywordElementComparator( const Reference< XCollator >& xCollator )
590 : m_xCollator( xCollator )
593 bool operator()( const KeywordInfo::KeywordElement& la,
594 const KeywordInfo::KeywordElement& ra ) const
596 const OUString& l = la.key;
597 const OUString& r = ra.key;
599 bool ret;
601 if( m_xCollator.is() )
603 sal_Int32 l1 = l.indexOf( ';' );
604 sal_Int32 l3 = ( l1 == -1 ? l.getLength() : l1 );
606 sal_Int32 r1 = r.indexOf( ';' );
607 sal_Int32 r3 = ( r1 == -1 ? r.getLength() : r1 );
609 sal_Int32 c1 = m_xCollator->compareSubstring( l,0,l3,r,0,r3 );
611 if( c1 == +1 )
612 ret = false;
613 else if( c1 == 0 )
615 sal_Int32 l2 = l.getLength() - l1 - 1;
616 sal_Int32 r2 = r.getLength() - r1 - 1;
617 ret = ( m_xCollator->compareSubstring( l,1+l1,l2,r,1+r1,r2 ) < 0 );
619 else
620 ret = true;
622 else
623 ret = bool( l < r );
625 return ret;
628 Reference< XCollator > m_xCollator;
629 }; // end struct KeywordElementComparator
633 KeywordInfo::KeywordElement::KeywordElement( Databases *pDatabases,
634 helpdatafileproxy::Hdf* pHdf,
635 OUString& ky,
636 OUString& data )
637 : key( ky )
639 pDatabases->replaceName( key );
640 init( pDatabases,pHdf,data );
643 void KeywordInfo::KeywordElement::init( Databases *pDatabases,helpdatafileproxy::Hdf* pHdf,const OUString& ids )
645 const sal_Unicode* idstr = ids.getStr();
646 std::vector< OUString > id,anchor;
647 int idx = -1,k;
648 while( ( idx = ids.indexOf( ';',k = ++idx ) ) != -1 )
650 int h = ids.indexOf( '#', k );
651 if( h < idx )
653 // found an anchor
654 id.push_back( OUString( &idstr[k],h-k ) );
655 anchor.push_back( OUString( &idstr[h+1],idx-h-1 ) );
657 else
659 id.push_back( OUString( &idstr[k],idx-k ) );
660 anchor.push_back( OUString() );
664 listId.realloc( id.size() );
665 listAnchor.realloc( id.size() );
666 listTitle.realloc( id.size() );
668 for( sal_uInt32 i = 0; i < id.size(); ++i )
670 listId[i] = id[i];
671 listAnchor[i] = anchor[i];
673 helpdatafileproxy::HDFData aHDFData;
674 const sal_Char* pData = NULL;
676 if( pHdf )
678 OString idi( id[i].getStr(),id[i].getLength(),RTL_TEXTENCODING_UTF8 );
679 bool bSuccess = pHdf->getValueForKey( idi, aHDFData );
680 if( bSuccess )
681 pData = aHDFData.getData();
684 DbtToStringConverter converter( pData );
686 OUString title = converter.getTitle();
687 pDatabases->replaceName( title );
688 listTitle[i] = title;
692 KeywordInfo::KeywordInfo( const std::vector< KeywordElement >& aVec )
693 : listKey( aVec.size() ),
694 listId( aVec.size() ),
695 listAnchor( aVec.size() ),
696 listTitle( aVec.size() )
698 for( unsigned int i = 0; i < aVec.size(); ++i )
700 listKey[i] = aVec[i].key;
701 listId[i] = aVec[i].listId;
702 listAnchor[i] = aVec[i].listAnchor;
703 listTitle[i] = aVec[i].listTitle;
707 bool Databases::checkModuleMatchForExtension
708 ( const OUString& Database, const OUString& doclist )
710 bool bBelongsToDatabase = true;
712 // Analyse doclist string to find module assignments
713 bool bFoundAtLeastOneModule = false;
714 bool bModuleMatch = false;
715 sal_Int32 nLen = doclist.getLength();
716 sal_Int32 nLastFound = doclist.lastIndexOf( ';' );
717 if( nLastFound == -1 )
718 nLastFound = nLen;
719 const sal_Unicode* pStr = doclist.getStr();
720 sal_Int32 nFound = doclist.lastIndexOf( '_' );
721 while( nFound != -1 )
723 // Simple optimization, stop if '_' is followed by "id"
724 if( nLen - nFound > 2 )
726 if( pStr[ nFound + 1 ] == 'i' &&
727 pStr[ nFound + 2 ] == 'd' )
728 break;
731 OUString aModule = doclist.copy( nFound + 1, nLastFound - nFound - 1 );
732 std::vector< OUString >::iterator result = std::find( m_avModules.begin(), m_avModules.end(), aModule );
733 if( result != m_avModules.end() )
735 bFoundAtLeastOneModule = true;
736 if( Database == aModule )
738 bModuleMatch = true;
739 break;
743 nLastFound = nFound;
744 if( nLastFound == 0 )
745 break;
746 nFound = doclist.lastIndexOf( '_', nLastFound - 1 );
749 if( bFoundAtLeastOneModule && !bModuleMatch )
750 bBelongsToDatabase = false;
752 return bBelongsToDatabase;
755 KeywordInfo* Databases::getKeyword( const OUString& Database,
756 const OUString& Language )
758 osl::MutexGuard aGuard( m_aMutex );
760 OUString key = processLang(Language) + "/" + Database;
762 std::pair< KeywordInfoTable::iterator,bool > aPair =
763 m_aKeywordInfo.insert( KeywordInfoTable::value_type( key,(KeywordInfo*)0 ) );
765 KeywordInfoTable::iterator it = aPair.first;
767 if( aPair.second && ! it->second )
769 std::vector<KeywordInfo::KeywordElement> aVector;
771 KeyDataBaseFileIterator aDbFileIt( m_xContext, *this, Database, Language );
772 OUString fileURL;
773 bool bExtension = false;
774 while( !(fileURL = aDbFileIt.nextDbFile( bExtension )).isEmpty() )
776 OUString fileNameHDFHelp( fileURL );
777 if( bExtension )
778 fileNameHDFHelp += "_";
779 if( m_xSFA->exists( fileNameHDFHelp ) )
781 helpdatafileproxy::Hdf aHdf( fileNameHDFHelp, m_xSFA );
782 helpdatafileproxy::HDFData aKey;
783 helpdatafileproxy::HDFData aValue;
784 if( aHdf.startIteration() )
786 helpdatafileproxy::Hdf* pHdf = getHelpDataFile( Database,Language );
787 if( pHdf != NULL )
789 bool bOptimizeForPerformance = true;
790 pHdf->releaseHashMap();
791 pHdf->createHashMap( bOptimizeForPerformance );
794 while( aHdf.getNextKeyAndValue( aKey, aValue ) )
796 OUString keyword( aKey.getData(), aKey.getSize(),
797 RTL_TEXTENCODING_UTF8 );
798 OUString doclist( aValue.getData(), aValue.getSize(),
799 RTL_TEXTENCODING_UTF8 );
801 bool bBelongsToDatabase = true;
802 if( bExtension )
803 bBelongsToDatabase = checkModuleMatchForExtension( Database, doclist );
805 if( !bBelongsToDatabase )
806 continue;
808 aVector.push_back( KeywordInfo::KeywordElement( this,
809 pHdf,
810 keyword,
811 doclist ) );
813 aHdf.stopIteration();
815 if( pHdf != NULL )
816 pHdf->releaseHashMap();
821 // sorting
822 Reference< XCollator > xCollator = getCollator( Language,OUString());
823 KeywordElementComparator aComparator( xCollator );
824 std::sort(aVector.begin(),aVector.end(),aComparator);
826 KeywordInfo* pInfo = it->second = new KeywordInfo( aVector );
827 (void)pInfo;
830 return it->second;
833 Reference< XHierarchicalNameAccess > Databases::jarFile( const OUString& jar,
834 const OUString& Language )
836 if( jar.isEmpty() || Language.isEmpty() )
838 return Reference< XHierarchicalNameAccess >( 0 );
840 OUString key = processLang(Language) + "/" + jar;
842 osl::MutexGuard aGuard( m_aMutex );
844 ZipFileTable::iterator it =
845 m_aZipFileTable.insert( ZipFileTable::value_type( key,Reference< XHierarchicalNameAccess >(0) ) ).first;
847 if( ! it->second.is() )
849 OUString zipFile;
852 // Extension jar file? Search for ?
853 sal_Int32 nQuestionMark1 = jar.indexOf( '?' );
854 sal_Int32 nQuestionMark2 = jar.lastIndexOf( '?' );
855 if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
857 OUString aExtensionPath = jar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
858 OUString aPureJar = jar.copy( nQuestionMark2 + 1 );
860 zipFile = expandURL( aExtensionPath + "/" + aPureJar );
862 else
864 zipFile = getInstallPathAsURL() + key;
867 Sequence< Any > aArguments( 2 );
869 XInputStream_impl* p = new XInputStream_impl( zipFile );
870 if( p->CtorSuccess() )
872 Reference< XInputStream > xInputStream( p );
873 aArguments[ 0 ] <<= xInputStream;
875 else
877 delete p;
878 aArguments[ 0 ] <<= zipFile;
881 // let ZipPackage be used ( no manifest.xml is required )
882 beans::NamedValue aArg;
883 aArg.Name = "StorageFormat";
884 aArg.Value <<= OUString(ZIP_STORAGE_FORMAT_STRING);
885 aArguments[ 1 ] <<= aArg;
887 Reference< XInterface > xIfc
888 = m_xSMgr->createInstanceWithArgumentsAndContext(
889 OUString(
890 "com.sun.star.packages.comp.ZipPackage" ),
891 aArguments, m_xContext );
893 if ( xIfc.is() )
895 it->second = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
897 OSL_ENSURE( it->second.is(),
898 "ContentProvider::createPackage - "
899 "Got no hierarchical name access!" );
903 catch ( RuntimeException & )
906 catch ( Exception & )
911 return it->second;
914 Reference< XHierarchicalNameAccess > Databases::findJarFileForPath
915 ( const OUString& jar, const OUString& Language,
916 const OUString& path, OUString* o_pExtensionPath,
917 OUString* o_pExtensionRegistryPath )
919 Reference< XHierarchicalNameAccess > xNA;
920 if( jar.isEmpty() || Language.isEmpty() )
922 return xNA;
925 JarFileIterator aJarFileIt( m_xContext, *this, jar, Language );
926 Reference< XHierarchicalNameAccess > xTestNA;
927 Reference< deployment::XPackage > xParentPackageBundle;
928 while( (xTestNA = aJarFileIt.nextJarFile( xParentPackageBundle, o_pExtensionPath, o_pExtensionRegistryPath )).is() )
930 if( xTestNA.is() && xTestNA->hasByHierarchicalName( path ) )
932 bool bSuccess = true;
933 if( xParentPackageBundle.is() )
935 OUString aIdentifierInPath;
936 sal_Int32 nFindSlash = path.indexOf( '/' );
937 if( nFindSlash != -1 )
938 aIdentifierInPath = path.copy( 0, nFindSlash );
940 beans::Optional<OUString> aIdentifierOptional = xParentPackageBundle->getIdentifier();
941 if( !aIdentifierInPath.isEmpty() && aIdentifierOptional.IsPresent )
943 OUString aUnencodedIdentifier = aIdentifierOptional.Value;
944 OUString aIdentifier = rtl::Uri::encode( aUnencodedIdentifier,
945 rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8 );
947 if( !aIdentifierInPath.equals( aIdentifier ) )
949 // path does not start with extension identifier -> ignore
950 bSuccess = false;
953 else
955 // No identifier -> ignore
956 bSuccess = false;
960 if( bSuccess )
962 xNA = xTestNA;
963 break;
968 return xNA;
971 void Databases::changeCSS(const OUString& newStyleSheet)
973 m_aCSS = newStyleSheet.toAsciiLowerCase();
974 delete[] m_pCustomCSSDoc, m_pCustomCSSDoc = 0,m_nCustomCSSDocLength = 0;
977 void Databases::cascadingStylesheet( const OUString& Language,
978 char** buffer,
979 int* byteCount )
981 if( ! m_pCustomCSSDoc )
983 int retry = 2;
984 bool error = true;
985 OUString fileURL;
987 bool bHighContrastMode = false;
988 OUString aCSS( m_aCSS );
989 if ( aCSS == "default" )
991 // #i50760: "default" needs to adapt HC mode
992 uno::Reference< awt::XToolkit2 > xToolkit =
993 awt::Toolkit::create( ::comphelper::getProcessComponentContext() );
994 uno::Reference< awt::XTopWindow > xTopWindow = xToolkit->getActiveTopWindow();
995 if ( xTopWindow.is() )
997 uno::Reference< awt::XVclWindowPeer > xVclWindowPeer( xTopWindow, uno::UNO_QUERY );
998 if ( xVclWindowPeer.is() )
1000 uno::Any aHCMode = xVclWindowPeer->getProperty( OUString( "HighContrastMode" ) );
1001 if ( ( aHCMode >>= bHighContrastMode ) && bHighContrastMode )
1003 aCSS = "highcontrastblack";
1004 #ifdef WNT
1005 HKEY hKey = NULL;
1006 LONG lResult = RegOpenKeyExA( HKEY_CURRENT_USER, "Control Panel\\Accessibility\\HighContrast", 0, KEY_QUERY_VALUE, &hKey );
1007 if ( ERROR_SUCCESS == lResult )
1009 CHAR szBuffer[1024];
1010 DWORD nSize = sizeof( szBuffer );
1011 lResult = RegQueryValueExA( hKey, "High Contrast Scheme", NULL, NULL, (LPBYTE)szBuffer, &nSize );
1012 if ( ERROR_SUCCESS == lResult && nSize > 0 )
1014 szBuffer[nSize] = '\0';
1015 if ( strncmp( szBuffer, "High Contrast #1", strlen("High Contrast #1") ) == 0 )
1016 aCSS = "highcontrast1";
1017 if ( strncmp( szBuffer, "High Contrast #2", strlen("High Contrast #2") ) == 0 )
1018 aCSS = "highcontrast2";
1019 if ( strncmp( szBuffer, "High Contrast White", strlen("High Contrast White") ) == 0 )
1020 aCSS = "highcontrastwhite";
1022 RegCloseKey( hKey );
1024 #endif
1030 while( error && retry )
1033 if( retry == 2 )
1034 fileURL =
1035 getInstallPathAsURL() +
1036 processLang( Language ) +
1037 "/" +
1038 aCSS +
1039 ".css";
1040 else if( retry == 1 )
1041 fileURL =
1042 getInstallPathAsURL() +
1043 aCSS +
1044 ".css";
1046 osl::DirectoryItem aDirItem;
1047 osl::File aFile( fileURL );
1048 osl::FileStatus aStatus( osl_FileStatus_Mask_FileSize );
1050 if( osl::FileBase::E_None == osl::DirectoryItem::get( fileURL,aDirItem ) &&
1051 osl::FileBase::E_None == aFile.open( osl_File_OpenFlag_Read ) &&
1052 osl::FileBase::E_None == aDirItem.getFileStatus( aStatus ) )
1054 sal_uInt64 nSize;
1055 aFile.getSize( nSize );
1056 m_nCustomCSSDocLength = (int)nSize;
1057 m_pCustomCSSDoc = new char[ 1 + m_nCustomCSSDocLength ];
1058 m_pCustomCSSDoc[ m_nCustomCSSDocLength ] = 0;
1059 sal_uInt64 a = m_nCustomCSSDocLength,b = m_nCustomCSSDocLength;
1060 aFile.read( m_pCustomCSSDoc,a,b );
1061 aFile.close();
1062 error = false;
1065 --retry;
1066 if ( !retry && error && bHighContrastMode )
1068 // fall back to default css
1069 aCSS = "default";
1070 retry = 2;
1071 bHighContrastMode = false;
1075 if( error )
1077 m_nCustomCSSDocLength = 0;
1078 m_pCustomCSSDoc = new char[ 1 ]; // Initialize with 1 to avoid gcc compiler warning
1082 *byteCount = m_nCustomCSSDocLength;
1083 *buffer = new char[ 1 + *byteCount ];
1084 (*buffer)[*byteCount] = 0;
1085 memcpy( *buffer,m_pCustomCSSDoc,m_nCustomCSSDocLength );
1089 void Databases::setActiveText( const OUString& Module,
1090 const OUString& Language,
1091 const OUString& Id,
1092 char** buffer,
1093 int* byteCount )
1095 DataBaseIterator aDbIt( m_xContext, *this, Module, Language, true );
1097 // #i84550 Cache information about failed ids
1098 OString id( Id.getStr(),Id.getLength(),RTL_TEXTENCODING_UTF8 );
1099 EmptyActiveTextSet::iterator it = m_aEmptyActiveTextSet.find( id );
1100 bool bFoundAsEmpty = ( it != m_aEmptyActiveTextSet.end() );
1101 helpdatafileproxy::HDFData aHDFData;
1103 int nSize = 0;
1104 const sal_Char* pData = NULL;
1106 bool bSuccess = false;
1107 if( !bFoundAsEmpty )
1109 helpdatafileproxy::Hdf* pHdf = 0;
1110 while( !bSuccess && (pHdf = aDbIt.nextHdf()) != NULL )
1112 bSuccess = pHdf->getValueForKey( id, aHDFData );
1113 nSize = aHDFData.getSize();
1114 pData = aHDFData.getData();
1118 if( bSuccess )
1120 // ensure existence of tmp after for
1121 OString tmp;
1122 for( int i = 0; i < nSize; ++i )
1123 if( pData[i] == '%' || pData[i] == '$' )
1125 // need of replacement
1126 OUString temp = OUString( pData, nSize, RTL_TEXTENCODING_UTF8 );
1127 replaceName( temp );
1128 tmp = OString( temp.getStr(),
1129 temp.getLength(),
1130 RTL_TEXTENCODING_UTF8 );
1131 nSize = tmp.getLength();
1132 pData = tmp.getStr();
1133 break;
1136 *byteCount = nSize;
1137 *buffer = new char[ 1 + nSize ];
1138 (*buffer)[nSize] = 0;
1139 memcpy( *buffer, pData, nSize );
1141 else
1143 *byteCount = 0;
1144 *buffer = new char[1]; // Initialize with 1 to avoid compiler warnings
1145 if( !bFoundAsEmpty )
1146 m_aEmptyActiveTextSet.insert( id );
1150 void Databases::setInstallPath( const OUString& aInstDir )
1152 osl::MutexGuard aGuard( m_aMutex );
1154 osl::FileBase::getFileURLFromSystemPath( aInstDir,m_aInstallDirectory );
1155 //TODO: check returned error code
1157 if( !m_aInstallDirectory.endsWith( "/" ) )
1158 m_aInstallDirectory += "/";
1161 // class ExtensionIteratorBase
1163 ExtensionHelpExistanceMap ExtensionIteratorBase::aHelpExistanceMap;
1165 ExtensionIteratorBase::ExtensionIteratorBase( Reference< XComponentContext > xContext,
1166 Databases& rDatabases, const OUString& aInitialModule, const OUString& aLanguage )
1167 : m_xContext( xContext )
1168 , m_rDatabases( rDatabases )
1169 , m_eState( INITIAL_MODULE )
1170 , m_aInitialModule( aInitialModule )
1171 , m_aLanguage( aLanguage )
1173 assert( m_xContext.is() );
1174 init();
1177 ExtensionIteratorBase::ExtensionIteratorBase( Databases& rDatabases,
1178 const OUString& aInitialModule, const OUString& aLanguage )
1179 : m_xContext( comphelper::getProcessComponentContext() )
1180 , m_rDatabases( rDatabases )
1181 , m_eState( INITIAL_MODULE )
1182 , m_aInitialModule( aInitialModule )
1183 , m_aLanguage( aLanguage )
1185 init();
1188 void ExtensionIteratorBase::init()
1190 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
1192 m_bUserPackagesLoaded = false;
1193 m_bSharedPackagesLoaded = false;
1194 m_bBundledPackagesLoaded = false;
1195 m_iUserPackage = 0;
1196 m_iSharedPackage = 0;
1197 m_iBundledPackage = 0;
1200 Reference< deployment::XPackage > ExtensionIteratorBase::implGetHelpPackageFromPackage
1201 ( Reference< deployment::XPackage > xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
1203 o_xParentPackageBundle.clear();
1205 Reference< deployment::XPackage > xHelpPackage;
1206 if( !xPackage.is() )
1207 return xHelpPackage;
1209 // #i84550 Cache information about help content in extension
1210 OUString aExtensionPath = xPackage->getURL();
1211 ExtensionHelpExistanceMap::iterator it = aHelpExistanceMap.find( aExtensionPath );
1212 bool bFound = ( it != aHelpExistanceMap.end() );
1213 bool bHasHelp = bFound && it->second;
1214 if( bFound && !bHasHelp )
1215 return xHelpPackage;
1217 // Check if parent package is registered
1218 beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
1219 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
1220 bool bRegistered = false;
1221 if( option.IsPresent )
1223 beans::Ambiguous<sal_Bool> const & reg = option.Value;
1224 if( !reg.IsAmbiguous && reg.Value )
1225 bRegistered = true;
1227 if( bRegistered )
1229 OUString aHelpMediaType( "application/vnd.sun.star.help" );
1230 if( xPackage->isBundle() )
1232 Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
1233 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
1234 sal_Int32 nPkgCount = aPkgSeq.getLength();
1235 const Reference< deployment::XPackage >* pSeq = aPkgSeq.getConstArray();
1236 for( sal_Int32 iPkg = 0 ; iPkg < nPkgCount ; ++iPkg )
1238 const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
1239 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
1240 OUString aMediaType = xPackageTypeInfo->getMediaType();
1241 if( aMediaType.equals( aHelpMediaType ) )
1243 xHelpPackage = xSubPkg;
1244 o_xParentPackageBundle = xPackage;
1245 break;
1249 else
1251 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
1252 OUString aMediaType = xPackageTypeInfo->getMediaType();
1253 if( aMediaType.equals( aHelpMediaType ) )
1254 xHelpPackage = xPackage;
1258 if( !bFound )
1259 aHelpExistanceMap[ aExtensionPath ] = xHelpPackage.is();
1261 return xHelpPackage;
1264 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextUserHelpPackage
1265 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1267 Reference< deployment::XPackage > xHelpPackage;
1269 if( !m_bUserPackagesLoaded )
1271 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1272 m_aUserPackagesSeq = xExtensionManager->getDeployedExtensions
1273 ( OUString("user"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1274 m_bUserPackagesLoaded = true;
1277 if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
1279 m_eState = SHARED_EXTENSIONS; // Later: SHARED_MODULE
1281 else
1283 const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
1284 Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage++ ];
1285 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextUserHelpPackage(): Invalid package" );
1286 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1289 return xHelpPackage;
1292 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextSharedHelpPackage
1293 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1295 Reference< deployment::XPackage > xHelpPackage;
1297 if( !m_bSharedPackagesLoaded )
1299 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1300 m_aSharedPackagesSeq = xExtensionManager->getDeployedExtensions
1301 ( OUString("shared"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1302 m_bSharedPackagesLoaded = true;
1305 if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
1307 m_eState = BUNDLED_EXTENSIONS;
1309 else
1311 const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
1312 Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage++ ];
1313 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextSharedHelpPackage(): Invalid package" );
1314 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1317 return xHelpPackage;
1320 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextBundledHelpPackage
1321 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1323 Reference< deployment::XPackage > xHelpPackage;
1325 if( !m_bBundledPackagesLoaded )
1327 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1328 m_aBundledPackagesSeq = xExtensionManager->getDeployedExtensions
1329 ( OUString("bundled"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1330 m_bBundledPackagesLoaded = true;
1333 if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
1335 m_eState = END_REACHED;
1337 else
1339 const Reference< deployment::XPackage >* pBundledPackages =
1340 m_aBundledPackagesSeq.getConstArray();
1341 Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage++ ];
1342 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextBundledHelpPackage(): Invalid package" );
1343 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1346 return xHelpPackage;
1349 OUString ExtensionIteratorBase::implGetFileFromPackage(
1350 const OUString& rFileExtension, Reference< deployment::XPackage > xPackage )
1352 // No extension -> search for pure language folder
1353 bool bLangFolderOnly = rFileExtension.isEmpty();
1355 OUString aFile;
1356 OUString aLanguage = m_aLanguage;
1357 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1359 OUString aStr = xPackage->getRegistrationDataURL().Value + "/" + aLanguage;
1360 if( !bLangFolderOnly )
1362 aStr += "/help" + rFileExtension;
1365 aFile = m_rDatabases.expandURL( aStr );
1366 if( iPass == 0 )
1368 if( m_xSFA->exists( aFile ) )
1369 break;
1371 ::std::vector< OUString > av;
1372 implGetLanguageVectorFromPackage( av, xPackage );
1373 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1374 if( pFound != av.end() )
1375 aLanguage = *pFound;
1378 return aFile;
1381 inline bool isLetter( sal_Unicode c )
1383 return comphelper::string::isalphaAscii(c);
1386 void ExtensionIteratorBase::implGetLanguageVectorFromPackage( ::std::vector< OUString > &rv,
1387 com::sun::star::uno::Reference< com::sun::star::deployment::XPackage > xPackage )
1389 rv.clear();
1390 OUString aExtensionPath = xPackage->getURL();
1391 Sequence< OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1393 const OUString* pSeq = aEntrySeq.getConstArray();
1394 sal_Int32 nCount = aEntrySeq.getLength();
1395 for( sal_Int32 i = 0 ; i < nCount ; ++i )
1397 OUString aEntry = pSeq[i];
1398 if( m_xSFA->isFolder( aEntry ) )
1400 sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1401 if( nLastSlash != -1 )
1403 OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1405 // Check language scheme
1406 int nLen = aPureEntry.getLength();
1407 const sal_Unicode* pc = aPureEntry.getStr();
1408 bool bStartCanBeLanguage = ( nLen >= 2 && isLetter( pc[0] ) && isLetter( pc[1] ) );
1409 bool bIsLanguage = bStartCanBeLanguage &&
1410 ( nLen == 2 || (nLen == 5 && pc[2] == '-' && isLetter( pc[3] ) && isLetter( pc[4] )) );
1411 if( bIsLanguage )
1412 rv.push_back( aPureEntry );
1418 // class DataBaseIterator
1420 helpdatafileproxy::Hdf* DataBaseIterator::nextHdf( OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1422 helpdatafileproxy::Hdf* pRetHdf = NULL;
1424 while( !pRetHdf && m_eState != END_REACHED )
1426 switch( m_eState )
1428 case INITIAL_MODULE:
1429 pRetHdf = m_rDatabases.getHelpDataFile( m_aInitialModule, m_aLanguage, m_bHelpText );
1430 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1431 break;
1433 // Later:
1434 //case SHARED_MODULE
1437 case USER_EXTENSIONS:
1439 Reference< deployment::XPackage > xParentPackageBundle;
1440 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1441 if( !xHelpPackage.is() )
1442 break;
1443 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1444 break;
1447 case SHARED_EXTENSIONS:
1449 Reference< deployment::XPackage > xParentPackageBundle;
1450 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1451 if( !xHelpPackage.is() )
1452 break;
1454 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1455 break;
1458 case BUNDLED_EXTENSIONS:
1460 Reference< deployment::XPackage > xParentPackageBundle;
1461 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1462 if( !xHelpPackage.is() )
1463 break;
1465 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1466 break;
1469 case END_REACHED:
1470 OSL_FAIL( "DataBaseIterator::nextDb(): Invalid case END_REACHED" );
1471 break;
1475 return pRetHdf;
1478 helpdatafileproxy::Hdf* DataBaseIterator::implGetHdfFromPackage( Reference< deployment::XPackage > xPackage,
1479 OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1482 beans::Optional< OUString> optRegData;
1485 optRegData = xPackage->getRegistrationDataURL();
1487 catch ( deployment::ExtensionRemovedException&)
1489 return NULL;
1492 helpdatafileproxy::Hdf* pRetHdf = NULL;
1493 if (optRegData.IsPresent && !optRegData.Value.isEmpty())
1495 OUString aRegDataUrl = optRegData.Value + "/";
1497 OUString aHelpFilesBaseName("help");
1499 OUString aUsedLanguage = m_aLanguage;
1500 pRetHdf = m_rDatabases.getHelpDataFile(
1501 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1503 // Language fallback
1504 if( !pRetHdf )
1506 ::std::vector< OUString > av;
1507 implGetLanguageVectorFromPackage( av, xPackage );
1508 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1509 if( pFound != av.end() )
1511 aUsedLanguage = *pFound;
1512 pRetHdf = m_rDatabases.getHelpDataFile(
1513 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1517 if( o_pExtensionPath )
1518 *o_pExtensionPath = aRegDataUrl + aUsedLanguage;
1520 if( o_pExtensionRegistryPath )
1521 *o_pExtensionRegistryPath = xPackage->getURL() + "/" + aUsedLanguage;
1524 return pRetHdf;
1527 // class KeyDataBaseFileIterator
1529 //returns a file URL
1530 OUString KeyDataBaseFileIterator::nextDbFile( bool& o_rbExtension )
1532 OUString aRetFile;
1534 while( aRetFile.isEmpty() && m_eState != END_REACHED )
1536 switch( m_eState )
1538 case INITIAL_MODULE:
1539 aRetFile = OUStringBuffer(m_rDatabases.getInstallPathAsURL()).
1540 append(m_rDatabases.processLang(m_aLanguage)).append('/').
1541 append(m_aInitialModule).append(".key").makeStringAndClear();
1543 o_rbExtension = false;
1545 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1546 break;
1548 // Later:
1549 //case SHARED_MODULE
1552 case USER_EXTENSIONS:
1554 Reference< deployment::XPackage > xParentPackageBundle;
1555 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1556 if( !xHelpPackage.is() )
1557 break;
1559 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1560 o_rbExtension = true;
1561 break;
1564 case SHARED_EXTENSIONS:
1566 Reference< deployment::XPackage > xParentPackageBundle;
1567 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1568 if( !xHelpPackage.is() )
1569 break;
1571 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1572 o_rbExtension = true;
1573 break;
1576 case BUNDLED_EXTENSIONS:
1578 Reference< deployment::XPackage > xParentPackageBundle;
1579 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1580 if( !xHelpPackage.is() )
1581 break;
1583 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1584 o_rbExtension = true;
1585 break;
1588 case END_REACHED:
1589 OSL_FAIL( "DataBaseIterator::nextDbFile(): Invalid case END_REACHED" );
1590 break;
1594 return aRetFile;
1597 //Returns a file URL, that does not contain macros
1598 OUString KeyDataBaseFileIterator::implGetDbFileFromPackage
1599 ( Reference< deployment::XPackage > xPackage )
1601 OUString aExpandedURL =
1602 implGetFileFromPackage( OUString( ".key" ), xPackage );
1604 return aExpandedURL;
1607 // class JarFileIterator
1609 Reference< XHierarchicalNameAccess > JarFileIterator::nextJarFile
1610 ( Reference< deployment::XPackage >& o_xParentPackageBundle,
1611 OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1613 Reference< XHierarchicalNameAccess > xNA;
1615 while( !xNA.is() && m_eState != END_REACHED )
1617 switch( m_eState )
1619 case INITIAL_MODULE:
1620 xNA = m_rDatabases.jarFile( m_aInitialModule, m_aLanguage );
1621 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1622 break;
1624 // Later:
1625 //case SHARED_MODULE
1628 case USER_EXTENSIONS:
1630 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( o_xParentPackageBundle );
1631 if( !xHelpPackage.is() )
1632 break;
1634 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1635 break;
1638 case SHARED_EXTENSIONS:
1640 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( o_xParentPackageBundle );
1641 if( !xHelpPackage.is() )
1642 break;
1644 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1645 break;
1648 case BUNDLED_EXTENSIONS:
1650 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( o_xParentPackageBundle );
1651 if( !xHelpPackage.is() )
1652 break;
1654 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1655 break;
1658 case END_REACHED:
1659 OSL_FAIL( "JarFileIterator::nextJarFile(): Invalid case END_REACHED" );
1660 break;
1664 return xNA;
1667 Reference< XHierarchicalNameAccess > JarFileIterator::implGetJarFromPackage
1668 ( Reference< deployment::XPackage > xPackage, OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1670 Reference< XHierarchicalNameAccess > xNA;
1672 OUString zipFile =
1673 implGetFileFromPackage( OUString( ".jar" ), xPackage );
1677 Sequence< Any > aArguments( 2 );
1678 aArguments[ 0 ] <<= zipFile;
1680 // let ZipPackage be used ( no manifest.xml is required )
1681 beans::NamedValue aArg;
1682 aArg.Name = "StorageFormat";
1683 aArg.Value <<= OUString(ZIP_STORAGE_FORMAT_STRING);
1684 aArguments[ 1 ] <<= aArg;
1686 Reference< XMultiComponentFactory >xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
1687 Reference< XInterface > xIfc
1688 = xSMgr->createInstanceWithArgumentsAndContext(
1689 OUString(
1690 "com.sun.star.packages.comp.ZipPackage" ),
1691 aArguments, m_xContext );
1693 if ( xIfc.is() )
1695 xNA = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1697 OSL_ENSURE( xNA.is(),
1698 "JarFileIterator::implGetJarFromPackage() - "
1699 "Got no hierarchical name access!" );
1702 catch ( RuntimeException & )
1704 catch ( Exception & )
1707 if( xNA.is() && o_pExtensionPath != NULL )
1709 // Extract path including language from file name
1710 sal_Int32 nLastSlash = zipFile.lastIndexOf( '/' );
1711 if( nLastSlash != -1 )
1712 *o_pExtensionPath = zipFile.copy( 0, nLastSlash );
1714 if( o_pExtensionRegistryPath != NULL )
1716 OUString& rPath = *o_pExtensionPath;
1717 sal_Int32 nLastSlashInPath = rPath.lastIndexOf( '/', rPath.getLength() - 1 );
1719 *o_pExtensionRegistryPath = xPackage->getURL();
1720 *o_pExtensionRegistryPath += rPath.copy( nLastSlashInPath);
1724 return xNA;
1727 // class IndexFolderIterator
1729 OUString IndexFolderIterator::nextIndexFolder( bool& o_rbExtension, bool& o_rbTemporary )
1731 OUString aIndexFolder;
1733 while( aIndexFolder.isEmpty() && m_eState != END_REACHED )
1735 switch( m_eState )
1737 case INITIAL_MODULE:
1738 aIndexFolder = m_rDatabases.getInstallPathAsURL()
1739 + m_rDatabases.processLang(m_aLanguage) + "/"
1740 + m_aInitialModule + ".idxl";
1742 o_rbTemporary = false;
1743 o_rbExtension = false;
1745 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1746 break;
1748 // Later:
1749 //case SHARED_MODULE
1752 case USER_EXTENSIONS:
1754 Reference< deployment::XPackage > xParentPackageBundle;
1755 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1756 if( !xHelpPackage.is() )
1757 break;
1759 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1760 o_rbExtension = true;
1761 break;
1764 case SHARED_EXTENSIONS:
1766 Reference< deployment::XPackage > xParentPackageBundle;
1767 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1768 if( !xHelpPackage.is() )
1769 break;
1771 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1772 o_rbExtension = true;
1773 break;
1776 case BUNDLED_EXTENSIONS:
1778 Reference< deployment::XPackage > xParentPackageBundle;
1779 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1780 if( !xHelpPackage.is() )
1781 break;
1783 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1784 o_rbExtension = true;
1785 break;
1788 case END_REACHED:
1789 OSL_FAIL( "IndexFolderIterator::nextIndexFolder(): Invalid case END_REACHED" );
1790 break;
1794 return aIndexFolder;
1797 OUString IndexFolderIterator::implGetIndexFolderFromPackage( bool& o_rbTemporary, Reference< deployment::XPackage > xPackage )
1799 OUString aIndexFolder =
1800 implGetFileFromPackage( OUString( ".idxl" ), xPackage );
1802 o_rbTemporary = false;
1803 if( !m_xSFA->isFolder( aIndexFolder ) )
1805 // i98680: Missing index? Try to generate now
1806 OUString aLangURL = implGetFileFromPackage( OUString(), xPackage );
1807 if( m_xSFA->isFolder( aLangURL ) )
1809 // Test write access (shared extension may be read only)
1810 bool bIsWriteAccess = false;
1813 OUString aCreateTestFolder = aLangURL + "CreateTestFolder";
1814 m_xSFA->createFolder( aCreateTestFolder );
1815 if( m_xSFA->isFolder( aCreateTestFolder ) )
1816 bIsWriteAccess = true;
1818 m_xSFA->kill( aCreateTestFolder );
1820 catch (const Exception &)
1824 // TEST
1825 //bIsWriteAccess = false;
1829 OUString aLang;
1830 sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
1831 if( nLastSlash != -1 )
1832 aLang = aLangURL.copy( nLastSlash + 1 );
1833 else
1834 aLang = "en";
1836 OUString aMod("help");
1838 OUString aZipDir = aLangURL;
1839 if( !bIsWriteAccess )
1841 OUString aTempFileURL;
1842 ::osl::FileBase::RC eErr = ::osl::File::createTempFile( 0, 0, &aTempFileURL );
1843 if( eErr == ::osl::FileBase::E_None )
1845 OUString aTempDirURL = aTempFileURL;
1848 m_xSFA->kill( aTempDirURL );
1850 catch (const Exception &)
1853 m_xSFA->createFolder( aTempDirURL );
1855 aZipDir = aTempDirURL;
1856 o_rbTemporary = true;
1860 HelpIndexer aIndexer(aLang, aMod, aLangURL, aZipDir);
1861 aIndexer.indexDocuments();
1863 if( bIsWriteAccess )
1864 aIndexFolder = implGetFileFromPackage( OUString( ".idxl" ), xPackage );
1865 else
1866 aIndexFolder = aZipDir + "/help.idxl";
1868 catch (const Exception &)
1874 return aIndexFolder;
1877 void IndexFolderIterator::deleteTempIndexFolder( const OUString& aIndexFolder )
1879 sal_Int32 nLastSlash = aIndexFolder.lastIndexOf( '/' );
1880 if( nLastSlash != -1 )
1882 OUString aTmpFolder = aIndexFolder.copy( 0, nLastSlash );
1885 m_xSFA->kill( aTmpFolder );
1887 catch (const Exception &)
1893 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */