fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / xmlhelp / source / cxxhelp / provider / databases.cxx
blob0c4bdab9c7507370120be8312160d57df988efdd
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;
84 OUString Databases::expandURL( const OUString& aURL )
86 osl::MutexGuard aGuard( m_aMutex );
87 OUString aRetURL = expandURL( aURL, m_xContext );
88 return aRetURL;
91 OUString Databases::expandURL( const OUString& aURL, Reference< uno::XComponentContext > xContext )
93 static Reference< util::XMacroExpander > xMacroExpander;
94 static Reference< uri::XUriReferenceFactory > xFac;
96 if( !xMacroExpander.is() || !xFac.is() )
98 xFac = uri::UriReferenceFactory::create( xContext );
100 xMacroExpander = util::theMacroExpander::get(xContext);
103 OUString aRetURL = aURL;
104 if( xMacroExpander.is() )
106 Reference< uri::XUriReference > uriRef;
107 for (;;)
109 uriRef = Reference< uri::XUriReference >( xFac->parse( aRetURL ), UNO_QUERY );
110 if ( uriRef.is() )
112 Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
113 if( !sxUri.is() )
114 break;
116 aRetURL = sxUri->expand( xMacroExpander );
120 return aRetURL;
123 Databases::Databases( sal_Bool showBasic,
124 const OUString& instPath,
125 const com::sun::star::uno::Sequence< OUString >& imagesZipPaths,
126 const OUString& productName,
127 const OUString& productVersion,
128 const OUString& styleSheet,
129 Reference< uno::XComponentContext > xContext )
130 : m_xContext( xContext ),
131 m_bShowBasic(showBasic),
132 m_pErrorDoc( 0 ),
133 m_nCustomCSSDocLength( 0 ),
134 m_pCustomCSSDoc( 0 ),
135 m_aCSS(styleSheet.toAsciiLowerCase()),
136 newProdName(OUString( "$[officename]" ) ),
137 newProdVersion(OUString( "$[officeversion]" ) ),
138 prodName( OUString( "%PRODUCTNAME" ) ),
139 prodVersion( OUString( "%PRODUCTVERSION" ) ),
140 vendName( OUString( "%VENDORNAME" ) ),
141 vendVersion( OUString( "%VENDORVERSION" ) ),
142 vendShort( OUString( "%VENDORSHORT" ) ),
143 m_aImagesZipPaths( imagesZipPaths ),
144 m_aSymbolsStyleName( "" )
146 m_xSMgr = Reference< XMultiComponentFactory >( m_xContext->getServiceManager(), UNO_QUERY );
148 m_vAdd[0] = 12;
149 m_vAdd[1] = 15;
150 m_vAdd[2] = 11;
151 m_vAdd[3] = 14;
152 m_vAdd[4] = 12;
153 m_vAdd[5] = 13;
154 m_vAdd[6] = 16;
156 m_vReplacement[0] = productName;
157 m_vReplacement[1] = productVersion;
158 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
159 m_vReplacement[5] = productName;
160 m_vReplacement[6] = productVersion;
162 setInstallPath( instPath );
164 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
167 Databases::~Databases()
169 // release stylesheet
171 delete[] m_pCustomCSSDoc;
173 // release errorDocument
175 delete[] m_pErrorDoc;
177 // unload the databases
180 // DatabasesTable
181 DatabasesTable::iterator it = m_aDatabases.begin();
182 while( it != m_aDatabases.end() )
184 delete it->second;
185 ++it;
190 // ModInfoTable
192 ModInfoTable::iterator it = m_aModInfo.begin();
193 while( it != m_aModInfo.end() )
195 delete it->second;
196 ++it;
201 // KeywordInfoTable
203 KeywordInfoTable::iterator it = m_aKeywordInfo.begin();
204 while( it != m_aKeywordInfo.end() )
206 delete it->second;
207 ++it;
212 static bool impl_getZipFile(
213 Sequence< OUString > & rImagesZipPaths,
214 const OUString & rZipName,
215 OUString & rFileName )
217 OUString aWorkingDir;
218 osl_getProcessWorkingDir( &aWorkingDir.pData );
219 const OUString *pPathArray = rImagesZipPaths.getArray();
220 for ( int i = 0; i < rImagesZipPaths.getLength(); ++i )
222 OUString aFileName = pPathArray[ i ];
223 if ( !aFileName.isEmpty() )
225 if ( 1 + aFileName.lastIndexOf( '/' ) != aFileName.getLength() )
227 aFileName += OUString( "/" );
229 aFileName += rZipName;
230 // the icons are not read when the URL is a symlink
231 osl::File::getAbsoluteFileURL( aWorkingDir, aFileName, rFileName );
233 // test existence
234 osl::DirectoryItem aDirItem;
235 if ( osl::DirectoryItem::get( rFileName, aDirItem ) == osl::FileBase::E_None )
236 return true;
239 return false;
242 OString Databases::getImagesZipFileURL()
244 OUString aSymbolsStyleName;
247 uno::Reference< lang::XMultiServiceFactory > xConfigProvider =
248 configuration::theDefaultProvider::get(m_xContext);
250 // set root path
251 uno::Sequence < uno::Any > lParams(1);
252 beans::PropertyValue aParam ;
253 aParam.Name = OUString("nodepath");
254 aParam.Value <<= OUString("org.openoffice.Office.Common");
255 lParams[0] = uno::makeAny(aParam);
257 // open it
258 uno::Reference< uno::XInterface > xCFG( xConfigProvider->createInstanceWithArguments(
259 OUString("com.sun.star.configuration.ConfigurationAccess"),
260 lParams) );
262 bool bChanged = false;
263 uno::Reference< container::XHierarchicalNameAccess > xAccess(xCFG, uno::UNO_QUERY_THROW);
264 uno::Any aResult = xAccess->getByHierarchicalName(OUString("Misc/SymbolStyle"));
265 if ( (aResult >>= aSymbolsStyleName) && m_aSymbolsStyleName != aSymbolsStyleName )
267 m_aSymbolsStyleName = aSymbolsStyleName;
268 bChanged = true;
271 if ( m_aImagesZipFileURL.isEmpty() || bChanged )
273 OUString aImageZip;
274 bool bFound = false;
276 if ( !aSymbolsStyleName.isEmpty() )
278 if ( aSymbolsStyleName.equalsAscii("auto") )
280 OUString const & env = Application::GetDesktopEnvironment();
281 if ( env.equalsIgnoreAsciiCase("tde") ||
282 env.equalsIgnoreAsciiCase("kde") )
283 aSymbolsStyleName = "crystal";
284 else if ( env.equalsIgnoreAsciiCase("kde4") )
285 aSymbolsStyleName = "oxygen";
286 else
287 aSymbolsStyleName = "tango";
289 OUString aZipName = OUString( "images_" );
290 aZipName += aSymbolsStyleName;
291 aZipName += OUString( ".zip" );
293 bFound = impl_getZipFile( m_aImagesZipPaths, aZipName, aImageZip );
296 if ( ! bFound )
297 bFound = impl_getZipFile( m_aImagesZipPaths, OUString( "images.zip" ), aImageZip );
299 if ( ! bFound )
300 aImageZip = OUString();
302 m_aImagesZipFileURL = OUStringToOString(
303 rtl::Uri::encode(
304 aImageZip,
305 rtl_UriCharClassPchar,
306 rtl_UriEncodeIgnoreEscapes,
307 RTL_TEXTENCODING_UTF8 ), RTL_TEXTENCODING_UTF8 );
310 catch ( NoSuchElementException const & )
314 return m_aImagesZipFileURL;
317 void Databases::replaceName( OUString& oustring ) const
319 sal_Int32 idx = -1,idx1 = -1,idx2 = -1,k = 0,off;
320 bool cap = false;
321 OUStringBuffer aStrBuf( 0 );
323 while( true )
325 ++idx;
326 idx1 = oustring.indexOf( sal_Unicode('%'),idx);
327 idx2 = oustring.indexOf( sal_Unicode('$'),idx);
329 if(idx1 == -1 && idx2 == -1)
330 break;
332 if(idx1 == -1)
333 idx = idx2;
334 else if(idx2 == -1)
335 idx = idx1;
336 else {
337 // no index is zero
338 if(idx1 < idx2)
339 idx = idx1;
340 else if(idx2 < idx1 )
341 idx = idx2;
344 if( oustring.indexOf( prodName,idx ) == idx )
345 off = PRODUCTNAME;
346 else if( oustring.indexOf( prodVersion,idx ) == idx )
347 off = PRODUCTVERSION;
348 else if( oustring.indexOf( vendName,idx ) == idx )
349 off = VENDORNAME;
350 else if( oustring.indexOf( vendVersion,idx ) == idx )
351 off = VENDORVERSION;
352 else if( oustring.indexOf( vendShort,idx ) == idx )
353 off = VENDORSHORT;
354 else if( oustring.indexOf( newProdName,idx ) == idx )
355 off = NEWPRODUCTNAME;
356 else if( oustring.indexOf( newProdVersion,idx ) == idx )
357 off = NEWPRODUCTVERSION;
358 else
359 off = -1;
361 if( off != -1 )
363 if( ! cap )
365 cap = true;
366 aStrBuf.ensureCapacity( 256 );
369 aStrBuf.append( &oustring.getStr()[k],idx - k );
370 aStrBuf.append( m_vReplacement[off] );
371 k = idx + m_vAdd[off];
375 if( cap )
377 if( k < oustring.getLength() )
378 aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
379 oustring = aStrBuf.makeStringAndClear();
383 OUString Databases::getInstallPathAsURL()
385 osl::MutexGuard aGuard( m_aMutex );
387 return m_aInstallDirectory;
390 const std::vector< OUString >& Databases::getModuleList( const OUString& Language )
392 if( m_avModules.empty() )
394 OUString fileName,dirName = getInstallPathAsURL() + processLang( Language );
395 osl::Directory dirFile( dirName );
397 osl::DirectoryItem aDirItem;
398 osl::FileStatus aStatus( osl_FileStatus_Mask_FileName );
400 sal_Int32 idx;
402 if( osl::FileBase::E_None != dirFile.open() )
403 return m_avModules;
405 while( dirFile.getNextItem( aDirItem ) == osl::FileBase::E_None &&
406 aDirItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
408 if( ! aStatus.isValid( osl_FileStatus_Mask_FileName ) )
409 continue;
411 fileName = aStatus.getFileName();
413 // Check, whether fileName is of the form *.cfg
414 idx = fileName.lastIndexOf( sal_Unicode( '.' ) );
416 if( idx == -1 )
417 continue;
419 const sal_Unicode* str = fileName.getStr();
421 if( fileName.getLength() == idx + 4 &&
422 ( str[idx + 1] == 'c' || str[idx + 1] == 'C' ) &&
423 ( str[idx + 2] == 'f' || str[idx + 2] == 'F' ) &&
424 ( str[idx + 3] == 'g' || str[idx + 3] == 'G' ) &&
425 ( fileName = fileName.copy(0,idx).toAsciiLowerCase() ).compareToAscii( "picture" ) != 0 ) {
426 if(! m_bShowBasic && fileName.compareToAscii("sbasic") == 0 )
427 continue;
428 m_avModules.push_back( fileName );
432 return m_avModules;
437 StaticModuleInformation* Databases::getStaticInformationForModule( const OUString& Module,
438 const OUString& Language )
440 osl::MutexGuard aGuard( m_aMutex );
442 OUString key = processLang(Language) + OUString( "/" ) + Module;
444 std::pair< ModInfoTable::iterator,bool > aPair =
445 m_aModInfo.insert( ModInfoTable::value_type( key,(StaticModuleInformation*)0 ) );
447 ModInfoTable::iterator it = aPair.first;
449 if( aPair.second && ! it->second )
451 osl::File cfgFile( getInstallPathAsURL() +
452 key +
453 OUString( ".cfg" ) );
455 if( osl::FileBase::E_None != cfgFile.open( osl_File_OpenFlag_Read ) )
456 it->second = 0;
457 else
459 sal_uInt32 pos = 0;
460 sal_uInt64 nRead;
461 sal_Char buffer[2048];
462 sal_Unicode lineBuffer[1028];
463 OUString fileContent;
465 while( osl::FileBase::E_None == cfgFile.read( &buffer,2048,nRead ) && nRead )
466 fileContent += OUString( buffer,sal_Int32( nRead ),RTL_TEXTENCODING_UTF8 );
468 cfgFile.close();
470 const sal_Unicode* str = fileContent.getStr();
471 OUString current,lang_,program,startid,title,heading,fulltext;
472 OUString order( "1" );
474 for( sal_Int32 i = 0;i < fileContent.getLength();i++ )
476 sal_Unicode ch = str[ i ];
477 if( ch == sal_Unicode( '\n' ) || ch == sal_Unicode( '\r' ) )
479 if( pos )
481 current = OUString( lineBuffer,pos );
483 if( current.startsWith("Title") )
485 title = current.copy( current.indexOf(sal_Unicode( '=' ) ) + 1 );
487 else if( current.startsWith("Start") )
489 startid = current.copy( current.indexOf('=') + 1 );
491 else if( current.startsWith("Language") )
493 lang_ = current.copy( current.indexOf('=') + 1 );
495 else if( current.startsWith("Program") )
497 program = current.copy( current.indexOf('=') + 1 );
499 else if( current.startsWith("Heading") )
501 heading = current.copy( current.indexOf('=') + 1 );
503 else if( current.startsWith("FullText") )
505 fulltext = current.copy( current.indexOf('=') + 1 );
507 else if( current.startsWith("Order") )
509 order = current.copy( current.indexOf('=') + 1 );
512 pos = 0;
514 else
515 lineBuffer[ pos++ ] = ch;
517 replaceName( title );
518 it->second = new StaticModuleInformation( title,
519 startid,
520 program,
521 heading,
522 fulltext,
523 order );
527 return it->second;
533 OUString Databases::processLang( const OUString& Language )
535 osl::MutexGuard aGuard( m_aMutex );
537 OUString ret;
538 LangSetTable::iterator it = m_aLangSet.find( Language );
540 if( it == m_aLangSet.end() )
542 sal_Int32 idx;
543 osl::DirectoryItem aDirItem;
545 if( osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language,aDirItem ) )
547 ret = Language;
548 m_aLangSet[ Language ] = ret;
550 else if( ( ( idx = Language.indexOf( '-' ) ) != -1 ||
551 ( idx = Language.indexOf( '_' ) ) != -1 ) &&
552 osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language.copy( 0,idx ),
553 aDirItem ) )
555 ret = Language.copy( 0,idx );
556 m_aLangSet[ Language ] = ret;
559 else
560 ret = it->second;
562 return ret;
566 OUString Databases::country( const OUString& Language )
568 sal_Int32 idx;
569 if( ( idx = Language.indexOf( '-' ) ) != -1 ||
570 ( idx = Language.indexOf( '_' ) ) != -1 )
571 return Language.copy( 1+idx );
573 return OUString();
578 helpdatafileproxy::Hdf* Databases::getHelpDataFile( const OUString& Database,
579 const OUString& Language, bool helpText,
580 const OUString* pExtensionPath )
582 if( Database.isEmpty() || Language.isEmpty() )
583 return 0;
585 osl::MutexGuard aGuard( m_aMutex );
588 OUString aFileExt( helpText ? OUString(".ht") : OUString(".db") );
589 OUString dbFileName = OUStringBuffer().append('/').append(Database).append(aFileExt).makeStringAndClear();
590 OUString key;
591 if( pExtensionPath == NULL )
592 key = processLang( Language ) + dbFileName;
593 else
594 key = *pExtensionPath + Language + dbFileName; // make unique, don't change language
596 std::pair< DatabasesTable::iterator,bool > aPair =
597 m_aDatabases.insert( DatabasesTable::value_type( key, reinterpret_cast<helpdatafileproxy::Hdf *>(0) ) );
599 DatabasesTable::iterator it = aPair.first;
601 if( aPair.second && ! it->second )
603 helpdatafileproxy::Hdf* pHdf = 0;
605 OUString fileURL;
606 if( pExtensionPath )
607 fileURL = expandURL(*pExtensionPath) + Language + dbFileName;
608 else
609 fileURL = getInstallPathAsURL() + key;
611 OUString fileNameHDFHelp( fileURL );
612 //Extensions always use the new format
613 if( pExtensionPath != NULL )
614 fileNameHDFHelp += OUString( "_" );
615 //SimpleFileAccess takes file URLs as arguments!!! Using filenames works accidentally but
616 //fails for example when using long path names on Windows (starting with \\?\)
617 if( m_xSFA->exists( fileNameHDFHelp ) )
619 pHdf = new helpdatafileproxy::Hdf( fileNameHDFHelp, m_xSFA );
622 it->second = pHdf;
625 return it->second;
628 Reference< XCollator >
629 Databases::getCollator( const OUString& Language,
630 const OUString& System )
632 (void)System;
634 OUString key = Language;
636 osl::MutexGuard aGuard( m_aMutex );
638 CollatorTable::iterator it =
639 m_aCollatorTable.insert( CollatorTable::value_type( key,(Reference< XCollator >)0 ) ).first;
641 if( ! it->second.is() )
643 it->second = Collator::create(m_xContext);
644 OUString langStr = processLang(Language);
645 OUString countryStr = country(Language);
646 if( countryStr.isEmpty() )
648 if( langStr.compareToAscii("de") == 0 )
649 countryStr = OUString("DE");
650 else if( langStr.compareToAscii("en") == 0 )
651 countryStr = OUString("US");
652 else if( langStr.compareToAscii("es") == 0 )
653 countryStr = OUString("ES");
654 else if( langStr.compareToAscii("it") == 0 )
655 countryStr = OUString("IT");
656 else if( langStr.compareToAscii("fr") == 0 )
657 countryStr = OUString("FR");
658 else if( langStr.compareToAscii("sv") == 0 )
659 countryStr = OUString("SE");
660 else if( langStr.compareToAscii("ja") == 0 )
661 countryStr = OUString("JP");
662 else if( langStr.compareToAscii("ko") == 0 )
663 countryStr = OUString("KR");
665 /* FIXME-BCP47: all this does not look right for language tag context,
666 * also check processLang() and country() methods */
667 it->second->loadDefaultCollator( Locale( langStr,
668 countryStr,
669 OUString() ),
670 0 );
673 return it->second;
678 namespace chelp {
680 struct KeywordElementComparator
682 KeywordElementComparator( const Reference< XCollator >& xCollator )
683 : m_xCollator( xCollator )
686 bool operator()( const KeywordInfo::KeywordElement& la,
687 const KeywordInfo::KeywordElement& ra ) const
689 const OUString& l = la.key;
690 const OUString& r = ra.key;
692 bool ret;
694 if( m_xCollator.is() )
696 sal_Int32 l1 = l.indexOf( sal_Unicode( ';' ) );
697 sal_Int32 l3 = ( l1 == -1 ? l.getLength() : l1 );
699 sal_Int32 r1 = r.indexOf( sal_Unicode( ';' ) );
700 sal_Int32 r3 = ( r1 == -1 ? r.getLength() : r1 );
702 sal_Int32 c1 = m_xCollator->compareSubstring( l,0,l3,r,0,r3 );
704 if( c1 == +1 )
705 ret = false;
706 else if( c1 == 0 )
708 sal_Int32 l2 = l.getLength() - l1 - 1;
709 sal_Int32 r2 = r.getLength() - r1 - 1;
710 ret = ( m_xCollator->compareSubstring( l,1+l1,l2,r,1+r1,r2 ) < 0 );
712 else
713 ret = true;
715 else
716 ret = bool( l < r );
718 return ret;
721 Reference< XCollator > m_xCollator;
722 }; // end struct KeywordElementComparator
728 KeywordInfo::KeywordElement::KeywordElement( Databases *pDatabases,
729 helpdatafileproxy::Hdf* pHdf,
730 OUString& ky,
731 OUString& data )
732 : key( ky )
734 pDatabases->replaceName( key );
735 init( pDatabases,pHdf,data );
740 void KeywordInfo::KeywordElement::init( Databases *pDatabases,helpdatafileproxy::Hdf* pHdf,const OUString& ids )
742 const sal_Unicode* idstr = ids.getStr();
743 std::vector< OUString > id,anchor;
744 int idx = -1,k;
745 while( ( idx = ids.indexOf( ';',k = ++idx ) ) != -1 )
747 int h = ids.indexOf( sal_Unicode( '#' ),k );
748 if( h < idx )
750 // found an anchor
751 id.push_back( OUString( &idstr[k],h-k ) );
752 anchor.push_back( OUString( &idstr[h+1],idx-h-1 ) );
754 else
756 id.push_back( OUString( &idstr[k],idx-k ) );
757 anchor.push_back( OUString() );
761 listId.realloc( id.size() );
762 listAnchor.realloc( id.size() );
763 listTitle.realloc( id.size() );
765 for( sal_uInt32 i = 0; i < id.size(); ++i )
767 listId[i] = id[i];
768 listAnchor[i] = anchor[i];
770 helpdatafileproxy::HDFData aHDFData;
771 const sal_Char* pData = NULL;
773 if( pHdf )
775 OString idi( id[i].getStr(),id[i].getLength(),RTL_TEXTENCODING_UTF8 );
776 bool bSuccess = pHdf->getValueForKey( idi, aHDFData );
777 if( bSuccess )
778 pData = aHDFData.getData();
781 DbtToStringConverter converter( pData );
783 OUString title = converter.getTitle();
784 pDatabases->replaceName( title );
785 listTitle[i] = title;
791 KeywordInfo::KeywordInfo( const std::vector< KeywordElement >& aVec )
792 : listKey( aVec.size() ),
793 listId( aVec.size() ),
794 listAnchor( aVec.size() ),
795 listTitle( aVec.size() )
797 for( unsigned int i = 0; i < aVec.size(); ++i )
799 listKey[i] = aVec[i].key;
800 listId[i] = aVec[i].listId;
801 listAnchor[i] = aVec[i].listAnchor;
802 listTitle[i] = aVec[i].listTitle;
806 bool Databases::checkModuleMatchForExtension
807 ( const OUString& Database, const OUString& doclist )
809 bool bBelongsToDatabase = true;
811 // Analyse doclist string to find module assignments
812 bool bFoundAtLeastOneModule = false;
813 bool bModuleMatch = false;
814 sal_Int32 nLen = doclist.getLength();
815 sal_Int32 nLastFound = doclist.lastIndexOf( sal_Unicode(';') );
816 if( nLastFound == -1 )
817 nLastFound = nLen;
818 const sal_Unicode* pStr = doclist.getStr();
819 sal_Int32 nFound = doclist.lastIndexOf( sal_Unicode('_') );
820 while( nFound != -1 )
822 // Simple optimization, stop if '_' is followed by "id"
823 if( nLen - nFound > 2 )
825 if( pStr[ nFound + 1 ] == sal_Unicode('i') &&
826 pStr[ nFound + 2 ] == sal_Unicode('d') )
827 break;
830 OUString aModule = doclist.copy( nFound + 1, nLastFound - nFound - 1 );
831 std::vector< OUString >::iterator result = std::find( m_avModules.begin(), m_avModules.end(), aModule );
832 if( result != m_avModules.end() )
834 bFoundAtLeastOneModule = true;
835 if( Database == aModule )
837 bModuleMatch = true;
838 break;
842 nLastFound = nFound;
843 if( nLastFound == 0 )
844 break;
845 nFound = doclist.lastIndexOf( sal_Unicode('_'), nLastFound - 1 );
848 if( bFoundAtLeastOneModule && !bModuleMatch )
849 bBelongsToDatabase = false;
851 return bBelongsToDatabase;
855 KeywordInfo* Databases::getKeyword( const OUString& Database,
856 const OUString& Language )
858 osl::MutexGuard aGuard( m_aMutex );
860 OUString key = processLang(Language) + OUString( "/" ) + Database;
862 std::pair< KeywordInfoTable::iterator,bool > aPair =
863 m_aKeywordInfo.insert( KeywordInfoTable::value_type( key,(KeywordInfo*)0 ) );
865 KeywordInfoTable::iterator it = aPair.first;
867 if( aPair.second && ! it->second )
869 std::vector<KeywordInfo::KeywordElement> aVector;
871 KeyDataBaseFileIterator aDbFileIt( m_xContext, *this, Database, Language );
872 OUString fileURL;
873 bool bExtension = false;
874 while( !(fileURL = aDbFileIt.nextDbFile( bExtension )).isEmpty() )
876 OUString fileNameHDFHelp( fileURL );
877 if( bExtension )
878 fileNameHDFHelp += OUString::createFromAscii( "_" );
879 if( m_xSFA->exists( fileNameHDFHelp ) )
881 helpdatafileproxy::Hdf aHdf( fileNameHDFHelp, m_xSFA );
882 helpdatafileproxy::HDFData aKey;
883 helpdatafileproxy::HDFData aValue;
884 if( aHdf.startIteration() )
886 helpdatafileproxy::Hdf* pHdf = getHelpDataFile( Database,Language );
887 if( pHdf != NULL )
889 bool bOptimizeForPerformance = true;
890 pHdf->releaseHashMap();
891 pHdf->createHashMap( bOptimizeForPerformance );
894 while( aHdf.getNextKeyAndValue( aKey, aValue ) )
896 OUString keyword( aKey.getData(), aKey.getSize(),
897 RTL_TEXTENCODING_UTF8 );
898 OUString doclist( aValue.getData(), aValue.getSize(),
899 RTL_TEXTENCODING_UTF8 );
901 bool bBelongsToDatabase = true;
902 if( bExtension )
903 bBelongsToDatabase = checkModuleMatchForExtension( Database, doclist );
905 if( !bBelongsToDatabase )
906 continue;
908 aVector.push_back( KeywordInfo::KeywordElement( this,
909 pHdf,
910 keyword,
911 doclist ) );
913 aHdf.stopIteration();
915 if( pHdf != NULL )
916 pHdf->releaseHashMap();
921 // sorting
922 Reference< XCollator > xCollator = getCollator( Language,OUString());
923 KeywordElementComparator aComparator( xCollator );
924 std::sort(aVector.begin(),aVector.end(),aComparator);
926 KeywordInfo* pInfo = it->second = new KeywordInfo( aVector );
927 (void)pInfo;
930 return it->second;
933 Reference< XHierarchicalNameAccess > Databases::jarFile( const OUString& jar,
934 const OUString& Language )
936 if( jar.isEmpty() || Language.isEmpty() )
938 return Reference< XHierarchicalNameAccess >( 0 );
940 OUString key = OUStringBuffer(processLang(Language)).append('/').append(jar).makeStringAndClear();
942 osl::MutexGuard aGuard( m_aMutex );
944 ZipFileTable::iterator it =
945 m_aZipFileTable.insert( ZipFileTable::value_type( key,Reference< XHierarchicalNameAccess >(0) ) ).first;
947 if( ! it->second.is() )
949 OUString zipFile;
952 // Extension jar file? Search for ?
953 sal_Int32 nQuestionMark1 = jar.indexOf( sal_Unicode('?') );
954 sal_Int32 nQuestionMark2 = jar.lastIndexOf( sal_Unicode('?') );
955 if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
957 OUString aExtensionPath = jar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
958 OUString aPureJar = jar.copy( nQuestionMark2 + 1 );
960 OUStringBuffer aStrBuf;
961 aStrBuf.append( aExtensionPath );
962 aStrBuf.append( '/' );
963 aStrBuf.append( aPureJar );
965 zipFile = expandURL( aStrBuf.makeStringAndClear() );
967 else
969 zipFile = getInstallPathAsURL() + key;
972 Sequence< Any > aArguments( 2 );
974 XInputStream_impl* p = new XInputStream_impl( zipFile );
975 if( p->CtorSuccess() )
977 Reference< XInputStream > xInputStream( p );
978 aArguments[ 0 ] <<= xInputStream;
980 else
982 delete p;
983 aArguments[ 0 ] <<= zipFile;
986 // let ZipPackage be used ( no manifest.xml is required )
987 beans::NamedValue aArg;
988 aArg.Name = OUString( "StorageFormat" );
989 aArg.Value <<= ZIP_STORAGE_FORMAT_STRING;
990 aArguments[ 1 ] <<= aArg;
992 Reference< XInterface > xIfc
993 = m_xSMgr->createInstanceWithArgumentsAndContext(
994 OUString(
995 "com.sun.star.packages.comp.ZipPackage" ),
996 aArguments, m_xContext );
998 if ( xIfc.is() )
1000 it->second = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1002 OSL_ENSURE( it->second.is(),
1003 "ContentProvider::createPackage - "
1004 "Got no hierarchical name access!" );
1008 catch ( RuntimeException & )
1011 catch ( Exception & )
1016 return it->second;
1019 Reference< XHierarchicalNameAccess > Databases::findJarFileForPath
1020 ( const OUString& jar, const OUString& Language,
1021 const OUString& path, OUString* o_pExtensionPath,
1022 OUString* o_pExtensionRegistryPath )
1024 Reference< XHierarchicalNameAccess > xNA;
1025 if( jar.isEmpty() || Language.isEmpty() )
1027 return xNA;
1030 JarFileIterator aJarFileIt( m_xContext, *this, jar, Language );
1031 Reference< XHierarchicalNameAccess > xTestNA;
1032 Reference< deployment::XPackage > xParentPackageBundle;
1033 while( (xTestNA = aJarFileIt.nextJarFile( xParentPackageBundle, o_pExtensionPath, o_pExtensionRegistryPath )).is() )
1035 if( xTestNA.is() && xTestNA->hasByHierarchicalName( path ) )
1037 bool bSuccess = true;
1038 if( xParentPackageBundle.is() )
1040 OUString aIdentifierInPath;
1041 sal_Int32 nFindSlash = path.indexOf( '/' );
1042 if( nFindSlash != -1 )
1043 aIdentifierInPath = path.copy( 0, nFindSlash );
1045 beans::Optional<OUString> aIdentifierOptional = xParentPackageBundle->getIdentifier();
1046 if( !aIdentifierInPath.isEmpty() && aIdentifierOptional.IsPresent )
1048 OUString aUnencodedIdentifier = aIdentifierOptional.Value;
1049 OUString aIdentifier = rtl::Uri::encode( aUnencodedIdentifier,
1050 rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8 );
1052 if( !aIdentifierInPath.equals( aIdentifier ) )
1054 // path does not start with extension identifier -> ignore
1055 bSuccess = false;
1058 else
1060 // No identifier -> ignore
1061 bSuccess = false;
1065 if( bSuccess )
1067 xNA = xTestNA;
1068 break;
1073 return xNA;
1076 void Databases::popupDocument( URLParameter* urlPar,char **buffer,int *byteCount )
1078 const char* pop1 =
1079 " <html> "
1080 " <head> "
1081 " <help:css-file-link xmlns:help=\"http://openoffice.org/2000/help\"/> "
1082 " </head> "
1083 " <body> "
1084 " <help:popup-cut Id=\"";
1085 const sal_Int32 l1 = strlen( pop1 );
1087 const char* pop3 = "\" Eid=\"";
1088 const sal_Int32 l3 = strlen( pop3 );
1090 const char* pop5 =
1091 "\" xmlns:help=\"http://openoffice.org/2000/help\"></help:popup-cut> "
1092 " </body> "
1093 " </html>";
1094 const sal_Int32 l5 = strlen( pop5 );
1095 sal_Int32 l2,l4;
1097 OUString val = urlPar->get_id();
1098 OString pop2O( val.getStr(),l2 = val.getLength(),RTL_TEXTENCODING_UTF8 );
1099 const char* pop2 = pop2O.getStr();
1101 val = urlPar->get_eid();
1102 OString pop4O( val.getStr(),l4 = val.getLength(),RTL_TEXTENCODING_UTF8 );
1103 const char* pop4 = pop4O.getStr();
1105 (*byteCount) = l1 + l2 + l3 + l4 + l5;
1107 *buffer = new char[ 1+*byteCount ];
1109 memcpy( *buffer,pop1,l1 );
1110 memcpy( *buffer+l1,pop2,l2 );
1111 memcpy( *buffer+(l1+l2),pop3,l3 );
1112 memcpy( *buffer+(l1+l2+l3),pop4,l4 );
1113 memcpy( *buffer+(l1+l2+l3+l4),pop5,l5 );
1114 (*buffer)[*byteCount] = 0;
1118 void Databases::changeCSS(const OUString& newStyleSheet)
1120 m_aCSS = newStyleSheet.toAsciiLowerCase();
1121 delete[] m_pCustomCSSDoc, m_pCustomCSSDoc = 0,m_nCustomCSSDocLength = 0;
1126 void Databases::cascadingStylesheet( const OUString& Language,
1127 char** buffer,
1128 int* byteCount )
1130 if( ! m_pCustomCSSDoc )
1132 int retry = 2;
1133 bool error = true;
1134 OUString fileURL;
1136 sal_Bool bHighContrastMode = sal_False;
1137 OUString aCSS( m_aCSS );
1138 if ( aCSS.compareToAscii( "default" ) == 0 )
1140 // #i50760: "default" needs to adapt HC mode
1141 uno::Reference< awt::XToolkit2 > xToolkit =
1142 awt::Toolkit::create( ::comphelper::getProcessComponentContext() );
1143 uno::Reference< awt::XTopWindow > xTopWindow = xToolkit->getActiveTopWindow();
1144 if ( xTopWindow.is() )
1146 uno::Reference< awt::XVclWindowPeer > xVclWindowPeer( xTopWindow, uno::UNO_QUERY );
1147 if ( xVclWindowPeer.is() )
1149 uno::Any aHCMode = xVclWindowPeer->getProperty( OUString( "HighContrastMode" ) );
1150 if ( ( aHCMode >>= bHighContrastMode ) && bHighContrastMode )
1152 aCSS = OUString( "highcontrastblack" );
1153 #ifdef WNT
1154 HKEY hKey = NULL;
1155 LONG lResult = RegOpenKeyExA( HKEY_CURRENT_USER, "Control Panel\\Accessibility\\HighContrast", 0, KEY_QUERY_VALUE, &hKey );
1156 if ( ERROR_SUCCESS == lResult )
1158 CHAR szBuffer[1024];
1159 DWORD nSize = sizeof( szBuffer );
1160 lResult = RegQueryValueExA( hKey, "High Contrast Scheme", NULL, NULL, (LPBYTE)szBuffer, &nSize );
1161 if ( ERROR_SUCCESS == lResult && nSize > 0 )
1163 szBuffer[nSize] = '\0';
1164 if ( strncmp( szBuffer, "High Contrast #1", strlen("High Contrast #1") ) == 0 )
1165 aCSS = OUString( "highcontrast1" );
1166 if ( strncmp( szBuffer, "High Contrast #2", strlen("High Contrast #2") ) == 0 )
1167 aCSS = OUString( "highcontrast2" );
1168 if ( strncmp( szBuffer, "High Contrast White", strlen("High Contrast White") ) == 0 )
1169 aCSS = OUString( "highcontrastwhite" );
1171 RegCloseKey( hKey );
1173 #endif
1179 while( error && retry )
1182 if( retry == 2 )
1183 fileURL =
1184 getInstallPathAsURL() +
1185 processLang( Language ) +
1186 OUString( "/" ) +
1187 aCSS +
1188 OUString( ".css" );
1189 else if( retry == 1 )
1190 fileURL =
1191 getInstallPathAsURL() +
1192 aCSS +
1193 OUString( ".css" );
1195 osl::DirectoryItem aDirItem;
1196 osl::File aFile( fileURL );
1197 osl::FileStatus aStatus( osl_FileStatus_Mask_FileSize );
1199 if( osl::FileBase::E_None == osl::DirectoryItem::get( fileURL,aDirItem ) &&
1200 osl::FileBase::E_None == aFile.open( osl_File_OpenFlag_Read ) &&
1201 osl::FileBase::E_None == aDirItem.getFileStatus( aStatus ) )
1203 sal_uInt64 nSize;
1204 aFile.getSize( nSize );
1205 m_nCustomCSSDocLength = (int)nSize;
1206 m_pCustomCSSDoc = new char[ 1 + m_nCustomCSSDocLength ];
1207 m_pCustomCSSDoc[ m_nCustomCSSDocLength ] = 0;
1208 sal_uInt64 a = m_nCustomCSSDocLength,b = m_nCustomCSSDocLength;
1209 aFile.read( m_pCustomCSSDoc,a,b );
1210 aFile.close();
1211 error = false;
1214 --retry;
1215 if ( !retry && error && bHighContrastMode )
1217 // fall back to default css
1218 aCSS = OUString( "default" );
1219 retry = 2;
1220 bHighContrastMode = sal_False;
1224 if( error )
1226 m_nCustomCSSDocLength = 0;
1227 m_pCustomCSSDoc = new char[ 1 ]; // Initialize with 1 to avoid gcc compiler warning
1231 *byteCount = m_nCustomCSSDocLength;
1232 *buffer = new char[ 1 + *byteCount ];
1233 (*buffer)[*byteCount] = 0;
1234 memcpy( *buffer,m_pCustomCSSDoc,m_nCustomCSSDocLength );
1239 void Databases::setActiveText( const OUString& Module,
1240 const OUString& Language,
1241 const OUString& Id,
1242 char** buffer,
1243 int* byteCount )
1245 DataBaseIterator aDbIt( m_xContext, *this, Module, Language, true );
1247 // #i84550 Cache information about failed ids
1248 OString id( Id.getStr(),Id.getLength(),RTL_TEXTENCODING_UTF8 );
1249 EmptyActiveTextSet::iterator it = m_aEmptyActiveTextSet.find( id );
1250 bool bFoundAsEmpty = ( it != m_aEmptyActiveTextSet.end() );
1251 helpdatafileproxy::HDFData aHDFData;
1253 int nSize = 0;
1254 const sal_Char* pData = NULL;
1256 bool bSuccess = false;
1257 if( !bFoundAsEmpty )
1259 helpdatafileproxy::Hdf* pHdf = 0;
1260 while( !bSuccess && (pHdf = aDbIt.nextHdf()) != NULL )
1262 bSuccess = pHdf->getValueForKey( id, aHDFData );
1263 nSize = aHDFData.getSize();
1264 pData = aHDFData.getData();
1268 if( bSuccess )
1270 // ensure existence of tmp after for
1271 OString tmp;
1272 for( int i = 0; i < nSize; ++i )
1273 if( pData[i] == '%' || pData[i] == '$' )
1275 // need of replacement
1276 OUString temp = OUString( pData, nSize, RTL_TEXTENCODING_UTF8 );
1277 replaceName( temp );
1278 tmp = OString( temp.getStr(),
1279 temp.getLength(),
1280 RTL_TEXTENCODING_UTF8 );
1281 nSize = tmp.getLength();
1282 pData = tmp.getStr();
1283 break;
1286 *byteCount = nSize;
1287 *buffer = new char[ 1 + nSize ];
1288 (*buffer)[nSize] = 0;
1289 memcpy( *buffer, pData, nSize );
1291 else
1293 *byteCount = 0;
1294 *buffer = new char[1]; // Initialize with 1 to avoid compiler warnings
1295 if( !bFoundAsEmpty )
1296 m_aEmptyActiveTextSet.insert( id );
1301 void Databases::setInstallPath( const OUString& aInstDir )
1303 osl::MutexGuard aGuard( m_aMutex );
1305 osl::FileBase::getFileURLFromSystemPath( aInstDir,m_aInstallDirectory );
1306 //TODO: check returned error code
1308 if( m_aInstallDirectory.lastIndexOf( sal_Unicode( '/' ) ) != m_aInstallDirectory.getLength() - 1 )
1309 m_aInstallDirectory += OUString( "/" );
1313 //===================================================================
1314 // class ExtensionIteratorBase
1316 ExtensionHelpExistanceMap ExtensionIteratorBase::aHelpExistanceMap;
1318 ExtensionIteratorBase::ExtensionIteratorBase( Reference< XComponentContext > xContext,
1319 Databases& rDatabases, const OUString& aInitialModule, const OUString& aLanguage )
1320 : m_xContext( xContext )
1321 , m_rDatabases( rDatabases )
1322 , m_eState( INITIAL_MODULE )
1323 , m_aInitialModule( aInitialModule )
1324 , m_aLanguage( aLanguage )
1326 assert( m_xContext.is() );
1327 init();
1330 ExtensionIteratorBase::ExtensionIteratorBase( Databases& rDatabases,
1331 const OUString& aInitialModule, const OUString& aLanguage )
1332 : m_xContext( comphelper::getProcessComponentContext() )
1333 , m_rDatabases( rDatabases )
1334 , m_eState( INITIAL_MODULE )
1335 , m_aInitialModule( aInitialModule )
1336 , m_aLanguage( aLanguage )
1338 init();
1341 void ExtensionIteratorBase::init()
1343 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
1345 m_bUserPackagesLoaded = false;
1346 m_bSharedPackagesLoaded = false;
1347 m_bBundledPackagesLoaded = false;
1348 m_iUserPackage = 0;
1349 m_iSharedPackage = 0;
1350 m_iBundledPackage = 0;
1353 Reference< deployment::XPackage > ExtensionIteratorBase::implGetHelpPackageFromPackage
1354 ( Reference< deployment::XPackage > xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
1356 o_xParentPackageBundle.clear();
1358 Reference< deployment::XPackage > xHelpPackage;
1359 if( !xPackage.is() )
1360 return xHelpPackage;
1362 // #i84550 Cache information about help content in extension
1363 OUString aExtensionPath = xPackage->getURL();
1364 ExtensionHelpExistanceMap::iterator it = aHelpExistanceMap.find( aExtensionPath );
1365 bool bFound = ( it != aHelpExistanceMap.end() );
1366 bool bHasHelp = bFound ? it->second : false;
1367 if( bFound && !bHasHelp )
1368 return xHelpPackage;
1370 // Check if parent package is registered
1371 beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
1372 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
1373 bool bRegistered = false;
1374 if( option.IsPresent )
1376 beans::Ambiguous<sal_Bool> const & reg = option.Value;
1377 if( !reg.IsAmbiguous && reg.Value )
1378 bRegistered = true;
1380 if( bRegistered )
1382 OUString aHelpMediaType( "application/vnd.sun.star.help" );
1383 if( xPackage->isBundle() )
1385 Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
1386 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
1387 sal_Int32 nPkgCount = aPkgSeq.getLength();
1388 const Reference< deployment::XPackage >* pSeq = aPkgSeq.getConstArray();
1389 for( sal_Int32 iPkg = 0 ; iPkg < nPkgCount ; ++iPkg )
1391 const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
1392 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
1393 OUString aMediaType = xPackageTypeInfo->getMediaType();
1394 if( aMediaType.equals( aHelpMediaType ) )
1396 xHelpPackage = xSubPkg;
1397 o_xParentPackageBundle = xPackage;
1398 break;
1402 else
1404 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
1405 OUString aMediaType = xPackageTypeInfo->getMediaType();
1406 if( aMediaType.equals( aHelpMediaType ) )
1407 xHelpPackage = xPackage;
1411 if( !bFound )
1412 aHelpExistanceMap[ aExtensionPath ] = xHelpPackage.is();
1414 return xHelpPackage;
1417 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextUserHelpPackage
1418 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1420 Reference< deployment::XPackage > xHelpPackage;
1422 if( !m_bUserPackagesLoaded )
1424 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1425 m_aUserPackagesSeq = xExtensionManager->getDeployedExtensions
1426 ( OUString("user"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1427 m_bUserPackagesLoaded = true;
1430 if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
1432 m_eState = SHARED_EXTENSIONS; // Later: SHARED_MODULE
1434 else
1436 const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
1437 Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage++ ];
1438 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextUserHelpPackage(): Invalid package" );
1439 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1442 return xHelpPackage;
1445 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextSharedHelpPackage
1446 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1448 Reference< deployment::XPackage > xHelpPackage;
1450 if( !m_bSharedPackagesLoaded )
1452 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1453 m_aSharedPackagesSeq = xExtensionManager->getDeployedExtensions
1454 ( OUString("shared"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1455 m_bSharedPackagesLoaded = true;
1458 if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
1460 m_eState = BUNDLED_EXTENSIONS;
1462 else
1464 const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
1465 Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage++ ];
1466 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextSharedHelpPackage(): Invalid package" );
1467 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1470 return xHelpPackage;
1473 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextBundledHelpPackage
1474 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1476 Reference< deployment::XPackage > xHelpPackage;
1478 if( !m_bBundledPackagesLoaded )
1480 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1481 m_aBundledPackagesSeq = xExtensionManager->getDeployedExtensions
1482 ( OUString("bundled"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1483 m_bBundledPackagesLoaded = true;
1486 if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
1488 m_eState = END_REACHED;
1490 else
1492 const Reference< deployment::XPackage >* pBundledPackages =
1493 m_aBundledPackagesSeq.getConstArray();
1494 Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage++ ];
1495 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextBundledHelpPackage(): Invalid package" );
1496 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1499 return xHelpPackage;
1502 OUString ExtensionIteratorBase::implGetFileFromPackage(
1503 const OUString& rFileExtension, Reference< deployment::XPackage > xPackage )
1505 // No extension -> search for pure language folder
1506 bool bLangFolderOnly = rFileExtension.isEmpty();
1508 OUString aFile;
1509 OUString aLanguage = m_aLanguage;
1510 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1512 OUStringBuffer aStrBuf;
1513 aStrBuf.append( xPackage->getRegistrationDataURL().Value);
1514 aStrBuf.append( '/' );
1515 aStrBuf.append( aLanguage );
1516 if( !bLangFolderOnly )
1518 aStrBuf.append( '/' );
1519 aStrBuf.append( "help" );
1520 aStrBuf.append( rFileExtension );
1523 aFile = m_rDatabases.expandURL( aStrBuf.makeStringAndClear() );
1524 if( iPass == 0 )
1526 if( m_xSFA->exists( aFile ) )
1527 break;
1529 ::std::vector< OUString > av;
1530 implGetLanguageVectorFromPackage( av, xPackage );
1531 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1532 if( pFound != av.end() )
1533 aLanguage = *pFound;
1536 return aFile;
1539 inline bool isLetter( sal_Unicode c )
1541 return comphelper::string::isalphaAscii(c);
1544 void ExtensionIteratorBase::implGetLanguageVectorFromPackage( ::std::vector< OUString > &rv,
1545 com::sun::star::uno::Reference< com::sun::star::deployment::XPackage > xPackage )
1547 rv.clear();
1548 OUString aExtensionPath = xPackage->getURL();
1549 Sequence< OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1551 const OUString* pSeq = aEntrySeq.getConstArray();
1552 sal_Int32 nCount = aEntrySeq.getLength();
1553 for( sal_Int32 i = 0 ; i < nCount ; ++i )
1555 OUString aEntry = pSeq[i];
1556 if( m_xSFA->isFolder( aEntry ) )
1558 sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1559 if( nLastSlash != -1 )
1561 OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1563 // Check language scheme
1564 int nLen = aPureEntry.getLength();
1565 const sal_Unicode* pc = aPureEntry.getStr();
1566 bool bStartCanBeLanguage = ( nLen >= 2 && isLetter( pc[0] ) && isLetter( pc[1] ) );
1567 bool bIsLanguage = bStartCanBeLanguage &&
1568 ( nLen == 2 || (nLen == 5 && pc[2] == '-' && isLetter( pc[3] ) && isLetter( pc[4] )) );
1569 if( bIsLanguage )
1570 rv.push_back( aPureEntry );
1577 //===================================================================
1578 // class DataBaseIterator
1580 helpdatafileproxy::Hdf* DataBaseIterator::nextHdf( OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1582 helpdatafileproxy::Hdf* pRetHdf = NULL;
1584 while( !pRetHdf && m_eState != END_REACHED )
1586 switch( m_eState )
1588 case INITIAL_MODULE:
1589 pRetHdf = m_rDatabases.getHelpDataFile( m_aInitialModule, m_aLanguage, m_bHelpText );
1590 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1591 break;
1593 // Later:
1594 //case SHARED_MODULE
1595 //...
1597 case USER_EXTENSIONS:
1599 Reference< deployment::XPackage > xParentPackageBundle;
1600 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1601 if( !xHelpPackage.is() )
1602 break;
1603 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1604 break;
1607 case SHARED_EXTENSIONS:
1609 Reference< deployment::XPackage > xParentPackageBundle;
1610 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1611 if( !xHelpPackage.is() )
1612 break;
1614 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1615 break;
1618 case BUNDLED_EXTENSIONS:
1620 Reference< deployment::XPackage > xParentPackageBundle;
1621 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1622 if( !xHelpPackage.is() )
1623 break;
1625 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1626 break;
1629 case END_REACHED:
1630 OSL_FAIL( "DataBaseIterator::nextDb(): Invalid case END_REACHED" );
1631 break;
1635 return pRetHdf;
1638 helpdatafileproxy::Hdf* DataBaseIterator::implGetHdfFromPackage( Reference< deployment::XPackage > xPackage,
1639 OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1642 beans::Optional< OUString> optRegData;
1645 optRegData = xPackage->getRegistrationDataURL();
1647 catch ( deployment::ExtensionRemovedException&)
1649 return NULL;
1652 helpdatafileproxy::Hdf* pRetHdf = NULL;
1653 if (optRegData.IsPresent && !optRegData.Value.isEmpty())
1655 OUString aRegDataUrl = OUStringBuffer(optRegData.Value).append('/').makeStringAndClear();
1657 OUString aHelpFilesBaseName("help");
1659 OUString aUsedLanguage = m_aLanguage;
1660 pRetHdf = m_rDatabases.getHelpDataFile(
1661 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1663 // Language fallback
1664 if( !pRetHdf )
1666 ::std::vector< OUString > av;
1667 implGetLanguageVectorFromPackage( av, xPackage );
1668 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1669 if( pFound != av.end() )
1671 aUsedLanguage = *pFound;
1672 pRetHdf = m_rDatabases.getHelpDataFile(
1673 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1677 if( o_pExtensionPath )
1678 *o_pExtensionPath = aRegDataUrl + aUsedLanguage;
1680 if( o_pExtensionRegistryPath )
1681 *o_pExtensionRegistryPath = OUStringBuffer(xPackage->getURL()).append('/').append(aUsedLanguage).makeStringAndClear();
1684 return pRetHdf;
1688 //===================================================================
1689 // class KeyDataBaseFileIterator
1691 //returns a file URL
1692 OUString KeyDataBaseFileIterator::nextDbFile( bool& o_rbExtension )
1694 OUString aRetFile;
1696 while( aRetFile.isEmpty() && m_eState != END_REACHED )
1698 switch( m_eState )
1700 case INITIAL_MODULE:
1701 aRetFile = OUStringBuffer(m_rDatabases.getInstallPathAsURL()).
1702 append(m_rDatabases.processLang(m_aLanguage)).append('/').
1703 append(m_aInitialModule).append(".key").makeStringAndClear();
1705 o_rbExtension = false;
1707 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1708 break;
1710 // Later:
1711 //case SHARED_MODULE
1712 //...
1714 case USER_EXTENSIONS:
1716 Reference< deployment::XPackage > xParentPackageBundle;
1717 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1718 if( !xHelpPackage.is() )
1719 break;
1721 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1722 o_rbExtension = true;
1723 break;
1726 case SHARED_EXTENSIONS:
1728 Reference< deployment::XPackage > xParentPackageBundle;
1729 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1730 if( !xHelpPackage.is() )
1731 break;
1733 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1734 o_rbExtension = true;
1735 break;
1738 case BUNDLED_EXTENSIONS:
1740 Reference< deployment::XPackage > xParentPackageBundle;
1741 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1742 if( !xHelpPackage.is() )
1743 break;
1745 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1746 o_rbExtension = true;
1747 break;
1750 case END_REACHED:
1751 OSL_FAIL( "DataBaseIterator::nextDbFile(): Invalid case END_REACHED" );
1752 break;
1756 return aRetFile;
1759 //Returns a file URL, that does not contain macros
1760 OUString KeyDataBaseFileIterator::implGetDbFileFromPackage
1761 ( Reference< deployment::XPackage > xPackage )
1763 OUString aExpandedURL =
1764 implGetFileFromPackage( OUString( ".key" ), xPackage );
1766 return aExpandedURL;
1770 //===================================================================
1771 // class JarFileIterator
1773 Reference< XHierarchicalNameAccess > JarFileIterator::nextJarFile
1774 ( Reference< deployment::XPackage >& o_xParentPackageBundle,
1775 OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1777 Reference< XHierarchicalNameAccess > xNA;
1779 while( !xNA.is() && m_eState != END_REACHED )
1781 switch( m_eState )
1783 case INITIAL_MODULE:
1784 xNA = m_rDatabases.jarFile( m_aInitialModule, m_aLanguage );
1785 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1786 break;
1788 // Later:
1789 //case SHARED_MODULE
1790 //...
1792 case USER_EXTENSIONS:
1794 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( o_xParentPackageBundle );
1795 if( !xHelpPackage.is() )
1796 break;
1798 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1799 break;
1802 case SHARED_EXTENSIONS:
1804 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( o_xParentPackageBundle );
1805 if( !xHelpPackage.is() )
1806 break;
1808 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1809 break;
1812 case BUNDLED_EXTENSIONS:
1814 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( o_xParentPackageBundle );
1815 if( !xHelpPackage.is() )
1816 break;
1818 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1819 break;
1822 case END_REACHED:
1823 OSL_FAIL( "JarFileIterator::nextJarFile(): Invalid case END_REACHED" );
1824 break;
1828 return xNA;
1831 Reference< XHierarchicalNameAccess > JarFileIterator::implGetJarFromPackage
1832 ( Reference< deployment::XPackage > xPackage, OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1834 Reference< XHierarchicalNameAccess > xNA;
1836 OUString zipFile =
1837 implGetFileFromPackage( OUString( ".jar" ), xPackage );
1841 Sequence< Any > aArguments( 2 );
1842 aArguments[ 0 ] <<= zipFile;
1844 // let ZipPackage be used ( no manifest.xml is required )
1845 beans::NamedValue aArg;
1846 aArg.Name = OUString( "StorageFormat" );
1847 aArg.Value <<= ZIP_STORAGE_FORMAT_STRING;
1848 aArguments[ 1 ] <<= aArg;
1850 Reference< XMultiComponentFactory >xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
1851 Reference< XInterface > xIfc
1852 = xSMgr->createInstanceWithArgumentsAndContext(
1853 OUString(
1854 "com.sun.star.packages.comp.ZipPackage" ),
1855 aArguments, m_xContext );
1857 if ( xIfc.is() )
1859 xNA = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1861 OSL_ENSURE( xNA.is(),
1862 "JarFileIterator::implGetJarFromPackage() - "
1863 "Got no hierarchical name access!" );
1866 catch ( RuntimeException & )
1868 catch ( Exception & )
1871 if( xNA.is() && o_pExtensionPath != NULL )
1873 // Extract path including language from file name
1874 sal_Int32 nLastSlash = zipFile.lastIndexOf( '/' );
1875 if( nLastSlash != -1 )
1876 *o_pExtensionPath = zipFile.copy( 0, nLastSlash );
1878 if( o_pExtensionRegistryPath != NULL )
1880 OUString& rPath = *o_pExtensionPath;
1881 sal_Int32 nLastSlashInPath = rPath.lastIndexOf( '/', rPath.getLength() - 1 );
1883 *o_pExtensionRegistryPath = xPackage->getURL();
1884 *o_pExtensionRegistryPath += rPath.copy( nLastSlashInPath);
1888 return xNA;
1892 //===================================================================
1893 // class IndexFolderIterator
1895 OUString IndexFolderIterator::nextIndexFolder( bool& o_rbExtension, bool& o_rbTemporary )
1897 OUString aIndexFolder;
1899 while( aIndexFolder.isEmpty() && m_eState != END_REACHED )
1901 switch( m_eState )
1903 case INITIAL_MODULE:
1904 aIndexFolder = OUStringBuffer(m_rDatabases.getInstallPathAsURL()).
1905 append(m_rDatabases.processLang(m_aLanguage)).append('/').
1906 append(m_aInitialModule).append(".idxl").makeStringAndClear();
1908 o_rbTemporary = false;
1909 o_rbExtension = false;
1911 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1912 break;
1914 // Later:
1915 //case SHARED_MODULE
1916 //...
1918 case USER_EXTENSIONS:
1920 Reference< deployment::XPackage > xParentPackageBundle;
1921 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1922 if( !xHelpPackage.is() )
1923 break;
1925 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1926 o_rbExtension = true;
1927 break;
1930 case SHARED_EXTENSIONS:
1932 Reference< deployment::XPackage > xParentPackageBundle;
1933 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1934 if( !xHelpPackage.is() )
1935 break;
1937 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1938 o_rbExtension = true;
1939 break;
1942 case BUNDLED_EXTENSIONS:
1944 Reference< deployment::XPackage > xParentPackageBundle;
1945 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1946 if( !xHelpPackage.is() )
1947 break;
1949 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1950 o_rbExtension = true;
1951 break;
1954 case END_REACHED:
1955 OSL_FAIL( "IndexFolderIterator::nextIndexFolder(): Invalid case END_REACHED" );
1956 break;
1960 return aIndexFolder;
1963 OUString IndexFolderIterator::implGetIndexFolderFromPackage( bool& o_rbTemporary, Reference< deployment::XPackage > xPackage )
1965 OUString aIndexFolder =
1966 implGetFileFromPackage( OUString( ".idxl" ), xPackage );
1968 o_rbTemporary = false;
1969 if( !m_xSFA->isFolder( aIndexFolder ) )
1971 // i98680: Missing index? Try to generate now
1972 OUString aLangURL = implGetFileFromPackage( OUString(), xPackage );
1973 if( m_xSFA->isFolder( aLangURL ) )
1975 // Test write access (shared extension may be read only)
1976 bool bIsWriteAccess = false;
1979 OUString aCreateTestFolder = aLangURL + OUString( "CreateTestFolder" );
1980 m_xSFA->createFolder( aCreateTestFolder );
1981 if( m_xSFA->isFolder( aCreateTestFolder ) )
1982 bIsWriteAccess = true;
1984 m_xSFA->kill( aCreateTestFolder );
1986 catch (const Exception &)
1990 // TEST
1991 //bIsWriteAccess = false;
1995 OUString aLang;
1996 sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
1997 if( nLastSlash != -1 )
1998 aLang = aLangURL.copy( nLastSlash + 1 );
1999 else
2000 aLang = OUString( "en" );
2002 OUString aMod("help");
2004 OUString aZipDir = aLangURL;
2005 if( !bIsWriteAccess )
2007 OUString aTempFileURL;
2008 ::osl::FileBase::RC eErr = ::osl::File::createTempFile( 0, 0, &aTempFileURL );
2009 if( eErr == ::osl::FileBase::E_None )
2011 OUString aTempDirURL = aTempFileURL;
2014 m_xSFA->kill( aTempDirURL );
2016 catch (const Exception &)
2019 m_xSFA->createFolder( aTempDirURL );
2021 aZipDir = aTempDirURL;
2022 o_rbTemporary = true;
2026 HelpIndexer aIndexer(aLang, aMod, aLangURL, aZipDir);
2027 aIndexer.indexDocuments();
2029 if( bIsWriteAccess )
2030 aIndexFolder = implGetFileFromPackage( OUString( ".idxl" ), xPackage );
2031 else
2032 aIndexFolder = aZipDir + OUString( "/help.idxl" );
2034 catch (const Exception &)
2040 return aIndexFolder;
2043 void IndexFolderIterator::deleteTempIndexFolder( const OUString& aIndexFolder )
2045 sal_Int32 nLastSlash = aIndexFolder.lastIndexOf( '/' );
2046 if( nLastSlash != -1 )
2048 OUString aTmpFolder = aIndexFolder.copy( 0, nLastSlash );
2051 m_xSFA->kill( aTmpFolder );
2053 catch (const Exception &)
2059 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */