tdf#130857 qt weld: Support "Java Start Parameters" dialog
[LibreOffice.git] / xmlhelp / source / cxxhelp / provider / databases.cxx
blobd1662f72da4a3d982aea4dcb8a62906a8e9ae386
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 <memory>
21 #include "db.hxx"
22 #include <osl/diagnose.h>
23 #include <osl/file.hxx>
24 #include <rtl/character.hxx>
25 #include <rtl/uri.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <rtl/ref.hxx>
28 #include <com/sun/star/lang/Locale.hpp>
29 #include <com/sun/star/awt/Toolkit.hpp>
30 #include <com/sun/star/i18n/Collator.hpp>
31 #include <comphelper/propertysequence.hxx>
32 #include "inputstream.hxx"
33 #include <algorithm>
34 #include <cassert>
35 #include <string.h>
36 #include <string_view>
38 #include <helpcompiler/HelpIndexer.hxx>
40 // Extensible help
41 #include <com/sun/star/deployment/ExtensionManager.hpp>
42 #include <com/sun/star/deployment/ExtensionRemovedException.hpp>
43 #include <comphelper/processfactory.hxx>
44 #include <com/sun/star/uno/XComponentContext.hpp>
45 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
46 #include <com/sun/star/beans/Optional.hpp>
47 #include <com/sun/star/beans/NamedValue.hpp>
48 #include <com/sun/star/configuration/theDefaultProvider.hpp>
49 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
50 #include <com/sun/star/util/theMacroExpander.hpp>
51 #include <com/sun/star/uri/UriReferenceFactory.hpp>
52 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
53 #include <i18nlangtag/languagetag.hxx>
55 #include <com/sun/star/awt/XVclWindowPeer.hpp>
56 #include <com/sun/star/awt/XTopWindow.hpp>
58 #include <comphelper/propertyvalue.hxx>
59 #include <comphelper/storagehelper.hxx>
60 #include <officecfg/Office/Common.hxx>
61 #include <utility>
63 #include "databases.hxx"
64 #include "urlparameter.hxx"
66 #ifdef _WIN32
67 #if !defined WIN32_LEAN_AND_MEAN
68 # define WIN32_LEAN_AND_MEAN
69 #endif
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 std::unique_lock aGuard(m_aMutex);
86 return expandURL(aGuard, aURL);
89 OUString Databases::expandURL( std::unique_lock<std::mutex>& /*rGuard*/, const OUString& aURL )
91 OUString aRetURL = expandURL( aURL, m_xContext );
92 return aRetURL;
95 OUString Databases::expandURL( const OUString& aURL, const Reference< uno::XComponentContext >& xContext )
97 static Reference< util::XMacroExpander > xMacroExpander;
98 static Reference< uri::XUriReferenceFactory > xFac;
100 if( !xMacroExpander.is() || !xFac.is() )
102 xFac = uri::UriReferenceFactory::create( xContext );
104 xMacroExpander = util::theMacroExpander::get(xContext);
107 OUString aRetURL = aURL;
108 if( xMacroExpander.is() )
110 Reference< uri::XUriReference > uriRef;
111 for (;;)
113 uriRef = xFac->parse( aRetURL );
114 if ( uriRef.is() )
116 Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
117 if( !sxUri.is() )
118 break;
120 aRetURL = sxUri->expand( xMacroExpander );
124 return aRetURL;
127 constexpr OUStringLiteral vendVersion = u"%VENDORVERSION";
128 constexpr OUStringLiteral vendName = u"%VENDORNAME";
129 constexpr OUStringLiteral prodVersion = u"%PRODUCTVERSION";
130 constexpr OUStringLiteral vendShort = u"%VENDORSHORT";
131 constexpr OUStringLiteral prodName = u"%PRODUCTNAME";
132 constexpr OUStringLiteral newProdVersion = u"$[officeversion]";
133 constexpr OUStringLiteral newProdName = u"$[officename]";
135 Databases::Databases( bool showBasic,
136 const OUString& instPath,
137 const OUString& productName,
138 const OUString& productVersion,
139 const OUString& styleSheet,
140 Reference< uno::XComponentContext > const & xContext )
141 : m_xContext( xContext ),
142 m_bShowBasic(showBasic),
143 m_aCSS(styleSheet.toAsciiLowerCase())
145 m_xSMgr = m_xContext->getServiceManager();
147 m_vAdd[0] = 12;
148 m_vAdd[1] = 15;
149 m_vAdd[2] = 11;
150 m_vAdd[3] = 14;
151 m_vAdd[4] = 12;
152 m_vAdd[5] = 13;
153 m_vAdd[6] = 16;
155 m_vReplacement[0] = productName;
156 m_vReplacement[1] = productVersion;
157 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
158 m_vReplacement[5] = productName;
159 m_vReplacement[6] = productVersion;
161 setInstallPath( instPath );
163 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
166 Databases::~Databases()
168 // unload the databases
170 // DatabasesTable
171 m_aDatabases.clear();
173 // ModInfoTable
174 m_aModInfo.clear();
176 // KeywordInfoTable
177 m_aKeywordInfo.clear();
180 // static
181 OString Databases::getImageTheme()
183 OUString aSymbolsStyleName = officecfg::Office::Common::Misc::SymbolStyle::get();
185 if ( aSymbolsStyleName.isEmpty() || aSymbolsStyleName == "auto" )
187 aSymbolsStyleName = "colibre";
189 return aSymbolsStyleName.toUtf8();
192 void Databases::replaceName( OUString& oustring ) const
194 sal_Int32 idx = -1,idx1 = -1,idx2 = -1,k = 0,off;
195 bool cap = false;
196 OUStringBuffer aStrBuf( 0 );
198 while( true )
200 ++idx;
201 idx1 = oustring.indexOf( '%', idx);
202 idx2 = oustring.indexOf( '$', idx);
204 if(idx1 == -1 && idx2 == -1)
205 break;
207 if(idx1 == -1)
208 idx = idx2;
209 else if(idx2 == -1)
210 idx = idx1;
211 else {
212 // no index is zero
213 if(idx1 < idx2)
214 idx = idx1;
215 else if(idx2 < idx1 )
216 idx = idx2;
219 if( oustring.indexOf( prodName,idx ) == idx )
220 off = PRODUCTNAME;
221 else if( oustring.indexOf( prodVersion,idx ) == idx )
222 off = PRODUCTVERSION;
223 else if( oustring.indexOf( vendName,idx ) == idx )
224 off = VENDORNAME;
225 else if( oustring.indexOf( vendVersion,idx ) == idx )
226 off = VENDORVERSION;
227 else if( oustring.indexOf( vendShort,idx ) == idx )
228 off = VENDORSHORT;
229 else if( oustring.indexOf( newProdName,idx ) == idx )
230 off = NEWPRODUCTNAME;
231 else if( oustring.indexOf( newProdVersion,idx ) == idx )
232 off = NEWPRODUCTVERSION;
233 else
234 off = -1;
236 if( off != -1 )
238 if( ! cap )
240 cap = true;
241 aStrBuf.ensureCapacity( 256 );
244 aStrBuf.append( &oustring.getStr()[k],idx - k );
245 aStrBuf.append( m_vReplacement[off] );
246 k = idx + m_vAdd[off];
250 if( cap )
252 if( k < oustring.getLength() )
253 aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
254 oustring = aStrBuf.makeStringAndClear();
258 OUString Databases::getInstallPathAsURL()
260 std::unique_lock aGuard( m_aMutex );
262 return m_aInstallDirectory;
265 const OUString & Databases::getInstallPathAsURL(std::unique_lock<std::mutex>& )
267 return m_aInstallDirectory;
270 const std::vector< OUString >& Databases::getModuleList( const OUString& Language )
272 if( m_avModules.empty() )
274 OUString fileName,dirName = getInstallPathAsURL() + processLang( Language );
275 osl::Directory dirFile( dirName );
277 osl::DirectoryItem aDirItem;
278 osl::FileStatus aStatus( osl_FileStatus_Mask_FileName );
280 if( osl::FileBase::E_None != dirFile.open() )
281 return m_avModules;
283 while( dirFile.getNextItem( aDirItem ) == osl::FileBase::E_None &&
284 aDirItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
286 if( ! aStatus.isValid( osl_FileStatus_Mask_FileName ) )
287 continue;
289 fileName = aStatus.getFileName();
291 // Check, whether fileName is of the form *.cfg
292 if (!fileName.endsWithIgnoreAsciiCase(u".cfg", &fileName)) {
293 continue;
295 fileName = fileName.toAsciiLowerCase();
296 if (fileName == "picture"
297 || (!m_bShowBasic && fileName == "sbasic"))
299 continue;
302 m_avModules.push_back( fileName );
305 return m_avModules;
308 StaticModuleInformation* Databases::getStaticInformationForModule( std::u16string_view Module,
309 const OUString& Language )
311 std::unique_lock aGuard( m_aMutex );
313 OUString key = processLang(aGuard, Language) + "/" + Module;
315 std::pair< ModInfoTable::iterator,bool > aPair =
316 m_aModInfo.emplace(key,nullptr);
318 ModInfoTable::iterator it = aPair.first;
320 if( aPair.second && ! it->second )
322 osl::File cfgFile( m_aInstallDirectory + key + ".cfg" );
324 if( osl::FileBase::E_None != cfgFile.open( osl_File_OpenFlag_Read ) )
325 it->second = nullptr;
326 else
328 sal_uInt32 pos = 0;
329 sal_uInt64 nRead;
330 char buffer[2048];
331 sal_Unicode lineBuffer[1028];
332 OUStringBuffer fileContent;
334 while( osl::FileBase::E_None == cfgFile.read( &buffer,2048,nRead ) && nRead )
335 fileContent.append(OUString( buffer,sal_Int32( nRead ),RTL_TEXTENCODING_UTF8 ));
337 cfgFile.close();
339 const sal_Unicode* str = fileContent.getStr();
340 OUString current,program,startid,title;
341 OUString order( u"1"_ustr );
343 for( sal_Int32 i = 0;i < fileContent.getLength();i++ )
345 sal_Unicode ch = str[ i ];
346 if( ch == '\n' || ch == '\r' )
348 if( pos )
350 current = OUString( lineBuffer,pos );
352 if( current.startsWith("Title") )
354 title = current.copy( current.indexOf( '=' ) + 1 );
356 else if( current.startsWith("Start") )
358 startid = current.copy( current.indexOf('=') + 1 );
360 else if( current.startsWith("Program") )
362 program = current.copy( current.indexOf('=') + 1 );
364 else if( current.startsWith("Order") )
366 order = current.copy( current.indexOf('=') + 1 );
369 pos = 0;
371 else
372 lineBuffer[ pos++ ] = ch;
374 replaceName( title );
375 it->second.reset(new StaticModuleInformation( title,
376 startid,
377 program,
378 order ));
382 return it->second.get();
385 OUString Databases::processLang( const OUString& Language )
387 std::unique_lock aGuard( m_aMutex );
388 return processLang(aGuard, Language);
391 OUString Databases::processLang( std::unique_lock<std::mutex>& /*rGuard*/, const OUString& Language )
393 OUString ret;
394 LangSetTable::iterator it = m_aLangSet.find( Language );
396 if( it == m_aLangSet.end() )
398 // XXX the old code looked for '-' and '_' as separator between
399 // language and country, no idea if '_' actually still can happen
400 // (probably not), but play safe and keep that and transform to proper
401 // BCP47.
402 const OUString aBcp47( Language.replaceAll( "_", "-"));
404 // Try if language tag or fallbacks are installed.
405 osl::DirectoryItem aDirItem;
406 std::vector<OUString> aFallbacks( LanguageTag( aBcp47).getFallbackStrings(true));
407 for (auto const & rFB : aFallbacks)
409 if (osl::FileBase::E_None == osl::DirectoryItem::get( m_aInstallDirectory + rFB, aDirItem))
411 ret = rFB;
412 m_aLangSet[ Language ] = ret;
413 break; // for
417 else
418 ret = it->second;
420 return ret;
423 helpdatafileproxy::Hdf* Databases::getHelpDataFile(std::u16string_view Database,
424 const OUString& Language, bool helpText,
425 const OUString* pExtensionPath )
427 std::unique_lock aGuard( m_aMutex );
429 return getHelpDataFile(aGuard, Database, Language, helpText, pExtensionPath);
432 helpdatafileproxy::Hdf* Databases::getHelpDataFile(std::unique_lock<std::mutex>& rGuard,
433 std::u16string_view Database,
434 const OUString& Language, bool helpText,
435 const OUString* pExtensionPath )
438 if( Database.empty() || Language.isEmpty() )
439 return nullptr;
441 OUString aFileExt( helpText ? u".ht"_ustr : u".db"_ustr );
442 OUString dbFileName = OUString::Concat("/") + Database + aFileExt;
443 OUString key;
444 if( pExtensionPath == nullptr )
445 key = processLang( rGuard, Language ) + dbFileName;
446 else
447 key = *pExtensionPath + Language + dbFileName; // make unique, don't change language
449 std::pair< DatabasesTable::iterator,bool > aPair =
450 m_aDatabases.emplace( key, nullptr);
452 DatabasesTable::iterator it = aPair.first;
454 if( aPair.second && ! it->second )
456 std::unique_ptr<helpdatafileproxy::Hdf> pHdf;
458 OUString fileURL;
459 if( pExtensionPath )
460 fileURL = expandURL(rGuard, *pExtensionPath) + Language + dbFileName;
461 else
462 fileURL = m_aInstallDirectory + key;
464 OUString fileNameHDFHelp( fileURL );
465 //Extensions always use the new format
466 if( pExtensionPath != nullptr )
467 fileNameHDFHelp += "_";
468 //SimpleFileAccess takes file URLs as arguments!!! Using filenames works accidentally but
469 //fails for example when using long path names on Windows (starting with \\?\)
470 if( m_xSFA->exists( fileNameHDFHelp ) )
472 pHdf.reset(new helpdatafileproxy::Hdf( fileNameHDFHelp, m_xSFA ));
475 it->second = std::move(pHdf);
478 return it->second.get();
481 Reference< XCollator >
482 Databases::getCollator(std::unique_lock<std::mutex>&, const OUString& Language)
484 OUString key = Language;
486 CollatorTable::iterator it =
487 m_aCollatorTable.emplace( key, Reference< XCollator >() ).first;
489 if( ! it->second.is() )
491 it->second = Collator::create(m_xContext);
492 LanguageTag aLanguageTag( Language);
493 OUString countryStr = aLanguageTag.getCountry();
494 if( countryStr.isEmpty() )
496 const OUString langStr = aLanguageTag.getLanguage();
497 if( langStr == "de" )
498 countryStr = "DE";
499 else if( langStr == "en" )
500 countryStr = "US";
501 else if( langStr == "es" )
502 countryStr = "ES";
503 else if( langStr == "it" )
504 countryStr = "IT";
505 else if( langStr == "fr" )
506 countryStr = "FR";
507 else if( langStr == "sv" )
508 countryStr = "SE";
509 else if( langStr == "ja" )
510 countryStr = "JP";
511 else if( langStr == "ko" )
512 countryStr = "KR";
514 // XXX NOTE: there are no complex language tags involved in those
515 // "add country" cases, only because of this we can use this
516 // simplified construction.
517 if (!countryStr.isEmpty())
518 aLanguageTag.reset( langStr + "-" + countryStr);
520 it->second->loadDefaultCollator( aLanguageTag.getLocale(), 0);
523 return it->second;
526 namespace chelp {
528 struct KeywordElementComparator
530 explicit KeywordElementComparator( const Reference< XCollator >& xCollator )
531 : m_xCollator( xCollator )
534 bool operator()( const KeywordInfo::KeywordElement& la,
535 const KeywordInfo::KeywordElement& ra ) const
537 const OUString& l = la.key;
538 const OUString& r = ra.key;
540 bool ret;
542 if( m_xCollator.is() )
544 sal_Int32 l1 = l.indexOf( ';' );
545 sal_Int32 l3 = ( l1 == -1 ? l.getLength() : l1 );
547 sal_Int32 r1 = r.indexOf( ';' );
548 sal_Int32 r3 = ( r1 == -1 ? r.getLength() : r1 );
550 sal_Int32 c1 = m_xCollator->compareSubstring( l,0,l3,r,0,r3 );
552 if( c1 == +1 )
553 ret = false;
554 else if( c1 == 0 )
556 sal_Int32 l2 = l.getLength() - l1 - 1;
557 sal_Int32 r2 = r.getLength() - r1 - 1;
558 ret = ( m_xCollator->compareSubstring( l,1+l1,l2,r,1+r1,r2 ) < 0 );
560 else
561 ret = true;
563 else
564 ret = l < r;
566 return ret;
569 Reference< XCollator > m_xCollator;
570 }; // end struct KeywordElementComparator
574 KeywordInfo::KeywordElement::KeywordElement( Databases const *pDatabases,
575 helpdatafileproxy::Hdf* pHdf,
576 OUString ky,
577 std::u16string_view data )
578 : key(std::move( ky ))
580 pDatabases->replaceName( key );
581 init( pDatabases,pHdf,data );
584 void KeywordInfo::KeywordElement::init( Databases const *pDatabases,helpdatafileproxy::Hdf* pHdf, std::u16string_view ids )
586 std::vector< OUString > id,anchor;
587 size_t idx = std::u16string_view::npos;
588 size_t k = 0;
589 for (;;)
591 idx = ids.find( ';', k );
592 if( idx == std::u16string_view::npos )
593 break;
594 size_t h = ids.find( '#', k );
595 if( h != std::u16string_view::npos && h < idx )
597 // found an anchor
598 id.push_back( OUString(ids.substr( k, h-k )) );
599 anchor.push_back( OUString(ids.substr( h+1, idx-h-1 )) );
601 else
603 id.push_back( OUString(ids.substr( k, idx-k )) );
604 anchor.emplace_back( );
606 k = ++idx;
609 listId.realloc( id.size() );
610 auto plistId = listId.getArray();
611 listAnchor.realloc( id.size() );
612 auto plistAnchor = listAnchor.getArray();
613 listTitle.realloc( id.size() );
614 auto plistTitle = listTitle.getArray();
616 for( size_t i = 0; i < id.size(); ++i )
618 plistId[i] = id[i];
619 plistAnchor[i] = anchor[i];
621 helpdatafileproxy::HDFData aHDFData;
622 const char* pData = nullptr;
624 if( pHdf )
626 OString idi = OUStringToOString( id[i], RTL_TEXTENCODING_UTF8 );
627 bool bSuccess = pHdf->getValueForKey( idi, aHDFData );
628 if( bSuccess )
629 pData = aHDFData.getData();
632 DbtToStringConverter converter( pData );
634 OUString title = converter.getTitle();
635 pDatabases->replaceName( title );
636 plistTitle[i] = title;
640 KeywordInfo::KeywordInfo( const std::vector< KeywordElement >& aVec )
641 : listKey( aVec.size() ),
642 listId( aVec.size() ),
643 listAnchor( aVec.size() ),
644 listTitle( aVec.size() )
646 auto listKeyRange = asNonConstRange(listKey);
647 auto listIdRange = asNonConstRange(listId);
648 auto listAnchorRange = asNonConstRange(listAnchor);
649 auto listTitleRange = asNonConstRange(listTitle);
650 for( size_t i = 0; i < aVec.size(); ++i )
652 listKeyRange[i] = aVec[i].key;
653 listIdRange[i] = aVec[i].listId;
654 listAnchorRange[i] = aVec[i].listAnchor;
655 listTitleRange[i] = aVec[i].listTitle;
659 bool Databases::checkModuleMatchForExtension
660 ( std::u16string_view Database, const OUString& doclist )
662 bool bBelongsToDatabase = true;
664 // Analyse doclist string to find module assignments
665 bool bFoundAtLeastOneModule = false;
666 bool bModuleMatch = false;
667 sal_Int32 nLen = doclist.getLength();
668 sal_Int32 nLastFound = doclist.lastIndexOf( ';' );
669 if( nLastFound == -1 )
670 nLastFound = nLen;
671 const sal_Unicode* pStr = doclist.getStr();
672 sal_Int32 nFound = doclist.lastIndexOf( '_' );
673 while( nFound != -1 )
675 // Simple optimization, stop if '_' is followed by "id"
676 if( nLen - nFound > 2 )
678 if( pStr[ nFound + 1 ] == 'i' &&
679 pStr[ nFound + 2 ] == 'd' )
680 break;
683 OUString aModule = doclist.copy( nFound + 1, nLastFound - nFound - 1 );
684 std::vector< OUString >::iterator result = std::find( m_avModules.begin(), m_avModules.end(), aModule );
685 if( result != m_avModules.end() )
687 bFoundAtLeastOneModule = true;
688 if( Database == aModule )
690 bModuleMatch = true;
691 break;
695 nLastFound = nFound;
696 if( nLastFound == 0 )
697 break;
698 nFound = doclist.lastIndexOf( '_', nLastFound - 1 );
701 if( bFoundAtLeastOneModule && !bModuleMatch )
702 bBelongsToDatabase = false;
704 return bBelongsToDatabase;
707 KeywordInfo* Databases::getKeyword( const OUString& Database,
708 const OUString& Language )
710 std::unique_lock aGuard( m_aMutex );
712 OUString key = processLang(aGuard, Language) + "/" + Database;
714 std::pair< KeywordInfoTable::iterator,bool > aPair =
715 m_aKeywordInfo.emplace( key,nullptr );
717 KeywordInfoTable::iterator it = aPair.first;
719 if( aPair.second && ! it->second )
721 std::vector<KeywordInfo::KeywordElement> aVector;
723 KeyDataBaseFileIterator aDbFileIt( m_xContext, *this, Database, Language );
724 OUString fileURL;
725 bool bExtension = false;
726 for (;;)
728 fileURL = aDbFileIt.nextDbFile(aGuard, bExtension);
729 if( fileURL.isEmpty() )
730 break;
731 OUString fileNameHDFHelp( fileURL );
732 if( bExtension )
733 fileNameHDFHelp += "_";
734 if( m_xSFA->exists( fileNameHDFHelp ) )
736 helpdatafileproxy::Hdf aHdf( fileNameHDFHelp, m_xSFA );
737 helpdatafileproxy::HDFData aKey;
738 helpdatafileproxy::HDFData aValue;
739 if( aHdf.startIteration() )
741 helpdatafileproxy::Hdf* pHdf = getHelpDataFile(aGuard, Database,Language );
742 if( pHdf != nullptr )
744 pHdf->releaseHashMap();
745 pHdf->createHashMap( true/*bOptimizeForPerformance*/ );
748 while( aHdf.getNextKeyAndValue( aKey, aValue ) )
750 OUString keyword( aKey.getData(), aKey.getSize(),
751 RTL_TEXTENCODING_UTF8 );
752 OUString doclist( aValue.getData(), aValue.getSize(),
753 RTL_TEXTENCODING_UTF8 );
755 bool bBelongsToDatabase = true;
756 if( bExtension )
757 bBelongsToDatabase = checkModuleMatchForExtension( Database, doclist );
759 if( !bBelongsToDatabase )
760 continue;
762 aVector.emplace_back( this,
763 pHdf,
764 keyword,
765 doclist );
767 aHdf.stopIteration();
769 if( pHdf != nullptr )
770 pHdf->releaseHashMap();
775 // sorting
776 Reference<XCollator> xCollator = getCollator(aGuard, Language);
777 std::sort(aVector.begin(), aVector.end(), KeywordElementComparator(xCollator));
779 it->second.reset(new KeywordInfo( aVector ));
782 return it->second.get();
785 Reference< XHierarchicalNameAccess > Databases::jarFile(
786 std::unique_lock<std::mutex>& rGuard, std::u16string_view jar,
787 const OUString& Language )
789 if( jar.empty() || Language.isEmpty() )
791 return Reference< XHierarchicalNameAccess >( nullptr );
794 OUString key = processLang(rGuard, Language) + "/" + jar;
796 ZipFileTable::iterator it =
797 m_aZipFileTable.emplace( key,Reference< XHierarchicalNameAccess >(nullptr) ).first;
799 if( ! it->second.is() )
803 OUString zipFile;
804 // Extension jar file? Search for ?
805 size_t nQuestionMark1 = jar.find( '?' );
806 size_t nQuestionMark2 = jar.rfind( '?' );
807 if( nQuestionMark1 != std::u16string_view::npos && nQuestionMark2 != std::u16string_view::npos && nQuestionMark1 != nQuestionMark2 )
809 std::u16string_view aExtensionPath = jar.substr( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
810 std::u16string_view aPureJar = jar.substr( nQuestionMark2 + 1 );
812 zipFile = expandURL(rGuard, OUString::Concat(aExtensionPath) + "/" + aPureJar);
814 else
816 zipFile = m_aInstallDirectory + key;
819 Sequence< Any > aArguments( 2 );
820 auto pArguments = aArguments.getArray();
822 rtl::Reference<XInputStream_impl> p(new XInputStream_impl( zipFile ));
823 if( p->CtorSuccess() )
825 pArguments[ 0 ] <<= Reference< XInputStream >( p );
827 else
829 p.clear();
830 pArguments[ 0 ] <<= zipFile;
833 // let ZipPackage be used ( no manifest.xml is required )
834 beans::NamedValue aArg;
835 aArg.Name = "StorageFormat";
836 aArg.Value <<= ZIP_STORAGE_FORMAT_STRING;
837 pArguments[ 1 ] <<= aArg;
839 Reference< XInterface > xIfc
840 = m_xSMgr->createInstanceWithArgumentsAndContext(
841 u"com.sun.star.packages.comp.ZipPackage"_ustr,
842 aArguments, m_xContext );
844 if ( xIfc.is() )
846 it->second.set( xIfc, UNO_QUERY );
848 OSL_ENSURE( it->second.is(),
849 "ContentProvider::createPackage - "
850 "Got no hierarchical name access!" );
854 catch ( RuntimeException & )
857 catch ( Exception & )
862 return it->second;
865 Reference< XHierarchicalNameAccess > Databases::findJarFileForPath
866 ( const OUString& jar, const OUString& Language,
867 const OUString& path, OUString* o_pExtensionPath,
868 OUString* o_pExtensionRegistryPath )
870 Reference< XHierarchicalNameAccess > xNA;
871 if( jar.isEmpty() || Language.isEmpty() )
873 return xNA;
876 ::std::unique_lock aGuard(m_aMutex);
878 JarFileIterator aJarFileIt( m_xContext, *this, jar, Language );
879 Reference< XHierarchicalNameAccess > xTestNA;
880 Reference< deployment::XPackage > xParentPackageBundle;
881 for (;;)
883 xTestNA = aJarFileIt.nextJarFile(aGuard, xParentPackageBundle, o_pExtensionPath, o_pExtensionRegistryPath);
884 if( !xTestNA.is() )
885 break;
886 if( xTestNA.is() && xTestNA->hasByHierarchicalName( path ) )
888 bool bSuccess = true;
889 if( xParentPackageBundle.is() )
891 OUString aIdentifierInPath;
892 sal_Int32 nFindSlash = path.indexOf( '/' );
893 if( nFindSlash != -1 )
894 aIdentifierInPath = path.copy( 0, nFindSlash );
896 beans::Optional<OUString> aIdentifierOptional = xParentPackageBundle->getIdentifier();
897 if( !aIdentifierInPath.isEmpty() && aIdentifierOptional.IsPresent )
899 OUString aUnencodedIdentifier = aIdentifierOptional.Value;
900 OUString aIdentifier = rtl::Uri::encode( aUnencodedIdentifier,
901 rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8 );
903 if( aIdentifierInPath != aIdentifier )
905 // path does not start with extension identifier -> ignore
906 bSuccess = false;
909 else
911 // No identifier -> ignore
912 bSuccess = false;
916 if( bSuccess )
918 xNA = xTestNA;
919 break;
924 return xNA;
927 void Databases::changeCSS(const OUString& newStyleSheet)
929 m_aCSS = newStyleSheet.toAsciiLowerCase();
930 m_vCustomCSSDoc.clear();
933 void Databases::cascadingStylesheet( const OUString& Language,
934 OStringBuffer& buffer )
936 if( m_vCustomCSSDoc.empty() )
938 int retry = 2;
939 bool error = true;
940 OUString fileURL;
942 bool bHighContrastMode = false;
943 OUString aCSS( m_aCSS );
944 if ( aCSS == "default" )
946 // #i50760: "default" needs to adapt HC mode
947 uno::Reference< awt::XToolkit2 > xToolkit =
948 awt::Toolkit::create( ::comphelper::getProcessComponentContext() );
949 uno::Reference< awt::XTopWindow > xTopWindow = xToolkit->getActiveTopWindow();
950 if ( xTopWindow.is() )
952 uno::Reference< awt::XVclWindowPeer > xVclWindowPeer( xTopWindow, uno::UNO_QUERY );
953 if ( xVclWindowPeer.is() )
955 uno::Any aHCMode = xVclWindowPeer->getProperty( u"HighContrastMode"_ustr );
956 if ( ( aHCMode >>= bHighContrastMode ) && bHighContrastMode )
958 aCSS = "highcontrastblack";
959 #ifdef _WIN32
960 HKEY hKey = nullptr;
961 LONG lResult = RegOpenKeyExW( HKEY_CURRENT_USER, L"Control Panel\\Accessibility\\HighContrast", 0, KEY_QUERY_VALUE, &hKey );
962 if ( ERROR_SUCCESS == lResult )
964 WCHAR szBuffer[1024];
965 DWORD nSize = sizeof( szBuffer );
966 lResult = RegQueryValueExW( hKey, L"High Contrast Scheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(szBuffer), &nSize );
967 if ( ERROR_SUCCESS == lResult && nSize > 0 )
969 szBuffer[nSize] = '\0';
970 if ( wcscmp( szBuffer, L"High Contrast #1" ) == 0 )
971 aCSS = "highcontrast1";
972 if ( wcscmp( szBuffer, L"High Contrast #2" ) == 0 )
973 aCSS = "highcontrast2";
974 if ( wcscmp( szBuffer, L"High Contrast White" ) == 0 )
975 aCSS = "highcontrastwhite";
977 RegCloseKey( hKey );
979 #endif
985 while( error && retry )
988 if( retry == 2 )
989 fileURL =
990 getInstallPathAsURL() +
991 processLang( Language ) +
992 "/" +
993 aCSS +
994 ".css";
995 else if( retry == 1 )
996 fileURL =
997 getInstallPathAsURL() +
998 aCSS +
999 ".css";
1001 osl::DirectoryItem aDirItem;
1002 osl::File aFile( fileURL );
1003 osl::FileStatus aStatus( osl_FileStatus_Mask_FileSize );
1005 if( osl::FileBase::E_None == osl::DirectoryItem::get( fileURL,aDirItem ) &&
1006 osl::FileBase::E_None == aFile.open( osl_File_OpenFlag_Read ) &&
1007 osl::FileBase::E_None == aDirItem.getFileStatus( aStatus ) )
1009 sal_uInt64 nSize;
1010 aFile.getSize( nSize );
1011 m_vCustomCSSDoc.resize( nSize + 1);
1012 m_vCustomCSSDoc[nSize] = 0;
1013 sal_uInt64 a = nSize,b = nSize;
1014 aFile.read( m_vCustomCSSDoc.data(), a, b );
1015 aFile.close();
1016 error = false;
1019 --retry;
1020 if ( !retry && error && bHighContrastMode )
1022 // fall back to default css
1023 aCSS = "default";
1024 retry = 2;
1025 bHighContrastMode = false;
1029 if( error )
1031 m_vCustomCSSDoc.clear();
1035 if (!m_vCustomCSSDoc.empty())
1036 buffer.append( m_vCustomCSSDoc.data(), m_vCustomCSSDoc.size() - 1 );
1039 void Databases::setActiveText( const OUString& Module,
1040 const OUString& Language,
1041 std::u16string_view Id,
1042 OStringBuffer& buffer )
1044 DataBaseIterator aDbIt( m_xContext, *this, Module, Language, true );
1046 // #i84550 Cache information about failed ids
1047 OString id = OUStringToOString( Id, RTL_TEXTENCODING_UTF8 );
1048 EmptyActiveTextSet::iterator it = m_aEmptyActiveTextSet.find( id );
1049 bool bFoundAsEmpty = ( it != m_aEmptyActiveTextSet.end() );
1050 helpdatafileproxy::HDFData aHDFData;
1052 int nSize = 0;
1053 const char* pData = nullptr;
1055 bool bSuccess = false;
1056 if( !bFoundAsEmpty )
1058 while( !bSuccess )
1060 helpdatafileproxy::Hdf* pHdf = aDbIt.nextHdf();
1061 if( !pHdf )
1062 break;
1063 bSuccess = pHdf->getValueForKey( id, aHDFData );
1064 nSize = aHDFData.getSize();
1065 pData = aHDFData.getData();
1069 if( bSuccess )
1071 // ensure existence of tmp after for
1072 OString tmp;
1073 for( int i = 0; i < nSize; ++i )
1074 if( pData[i] == '%' || pData[i] == '$' )
1076 // need of replacement
1077 OUString temp( pData, nSize, RTL_TEXTENCODING_UTF8 );
1078 replaceName( temp );
1079 tmp = OString( temp.getStr(),
1080 temp.getLength(),
1081 RTL_TEXTENCODING_UTF8 );
1082 nSize = tmp.getLength();
1083 pData = tmp.getStr();
1084 break;
1087 buffer.append( pData, nSize );
1089 else
1091 if( !bFoundAsEmpty )
1092 m_aEmptyActiveTextSet.insert( id );
1096 void Databases::setInstallPath( const OUString& aInstDir )
1098 std::unique_lock aGuard( m_aMutex );
1100 osl::FileBase::getFileURLFromSystemPath( aInstDir,m_aInstallDirectory );
1101 //TODO: check returned error code
1103 if( !m_aInstallDirectory.endsWith( "/" ) )
1104 m_aInstallDirectory += "/";
1108 ExtensionHelpExistenceMap ExtensionIteratorBase::aHelpExistenceMap;
1110 ExtensionIteratorBase::ExtensionIteratorBase( Reference< XComponentContext > const & xContext,
1111 Databases& rDatabases, OUString aInitialModule, OUString aLanguage )
1112 : m_xContext( xContext )
1113 , m_rDatabases( rDatabases )
1114 , m_eState( IteratorState::InitialModule )
1115 , m_aInitialModule(std::move( aInitialModule ))
1116 , m_aLanguage(std::move( aLanguage ))
1118 assert( m_xContext.is() );
1119 init();
1122 ExtensionIteratorBase::ExtensionIteratorBase( Databases& rDatabases,
1123 OUString aInitialModule, OUString aLanguage )
1124 : m_xContext( comphelper::getProcessComponentContext() )
1125 , m_rDatabases( rDatabases )
1126 , m_eState( IteratorState::InitialModule )
1127 , m_aInitialModule(std::move( aInitialModule ))
1128 , m_aLanguage(std::move( aLanguage ))
1130 init();
1133 void ExtensionIteratorBase::init()
1135 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
1137 m_bUserPackagesLoaded = false;
1138 m_bSharedPackagesLoaded = false;
1139 m_bBundledPackagesLoaded = false;
1140 m_iUserPackage = 0;
1141 m_iSharedPackage = 0;
1142 m_iBundledPackage = 0;
1145 Reference< deployment::XPackage > ExtensionIteratorBase::implGetHelpPackageFromPackage
1146 ( const Reference< deployment::XPackage >& xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
1148 o_xParentPackageBundle.clear();
1150 Reference< deployment::XPackage > xHelpPackage;
1151 if( !xPackage.is() )
1152 return xHelpPackage;
1154 // #i84550 Cache information about help content in extension
1155 OUString aExtensionPath = xPackage->getURL();
1156 ExtensionHelpExistenceMap::iterator it = aHelpExistenceMap.find( aExtensionPath );
1157 bool bFound = ( it != aHelpExistenceMap.end() );
1158 bool bHasHelp = bFound && it->second;
1159 if( bFound && !bHasHelp )
1160 return xHelpPackage;
1162 // Check if parent package is registered
1163 beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
1164 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
1165 bool bRegistered = false;
1166 if( option.IsPresent )
1168 beans::Ambiguous<sal_Bool> const & reg = option.Value;
1169 if( !reg.IsAmbiguous && reg.Value )
1170 bRegistered = true;
1172 if( bRegistered )
1174 OUString aHelpMediaType( u"application/vnd.sun.star.help"_ustr );
1175 if( xPackage->isBundle() )
1177 const Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
1178 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
1179 auto pSubPkg = std::find_if(aPkgSeq.begin(), aPkgSeq.end(),
1180 [&aHelpMediaType](const Reference< deployment::XPackage >& xSubPkg) {
1181 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
1182 OUString aMediaType = xPackageTypeInfo->getMediaType();
1183 return aMediaType == aHelpMediaType;
1185 if (pSubPkg != aPkgSeq.end())
1187 xHelpPackage = *pSubPkg;
1188 o_xParentPackageBundle = xPackage;
1191 else
1193 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
1194 OUString aMediaType = xPackageTypeInfo->getMediaType();
1195 if( aMediaType == aHelpMediaType )
1196 xHelpPackage = xPackage;
1200 if( !bFound )
1201 aHelpExistenceMap[ aExtensionPath ] = xHelpPackage.is();
1203 return xHelpPackage;
1206 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextUserHelpPackage
1207 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1209 Reference< deployment::XPackage > xHelpPackage;
1211 if( !m_bUserPackagesLoaded )
1213 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1214 m_aUserPackagesSeq = xExtensionManager->getDeployedExtensions
1215 ( u"user"_ustr, Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1216 m_bUserPackagesLoaded = true;
1219 if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
1221 m_eState = IteratorState::SharedExtensions; // Later: SHARED_MODULE
1223 else
1225 const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
1226 Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage++ ];
1227 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextUserHelpPackage(): Invalid package" );
1228 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1231 return xHelpPackage;
1234 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextSharedHelpPackage
1235 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1237 Reference< deployment::XPackage > xHelpPackage;
1239 if( !m_bSharedPackagesLoaded )
1241 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1242 m_aSharedPackagesSeq = xExtensionManager->getDeployedExtensions
1243 ( u"shared"_ustr, Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1244 m_bSharedPackagesLoaded = true;
1247 if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
1249 m_eState = IteratorState::BundledExtensions;
1251 else
1253 const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
1254 Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage++ ];
1255 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextSharedHelpPackage(): Invalid package" );
1256 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1259 return xHelpPackage;
1262 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextBundledHelpPackage
1263 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1265 Reference< deployment::XPackage > xHelpPackage;
1267 if( !m_bBundledPackagesLoaded )
1269 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1270 m_aBundledPackagesSeq = xExtensionManager->getDeployedExtensions
1271 ( u"bundled"_ustr, Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1272 m_bBundledPackagesLoaded = true;
1275 if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
1277 m_eState = IteratorState::EndReached;
1279 else
1281 const Reference< deployment::XPackage >* pBundledPackages =
1282 m_aBundledPackagesSeq.getConstArray();
1283 Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage++ ];
1284 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextBundledHelpPackage(): Invalid package" );
1285 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1288 return xHelpPackage;
1291 OUString ExtensionIteratorBase::implGetFileFromPackage(
1292 std::unique_lock<std::mutex> & rGuard,
1293 std::u16string_view rFileExtension, const Reference< deployment::XPackage >& xPackage )
1295 // No extension -> search for pure language folder
1296 bool bLangFolderOnly = rFileExtension.empty();
1298 OUString aFile;
1299 OUString aLanguage = m_aLanguage;
1300 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1302 OUString aStr = xPackage->getRegistrationDataURL().Value + "/" + aLanguage;
1303 if( !bLangFolderOnly )
1305 aStr += OUString::Concat("/help") + rFileExtension;
1308 aFile = m_rDatabases.expandURL(rGuard, aStr);
1309 if( iPass == 0 )
1311 if( m_xSFA->exists( aFile ) )
1312 break;
1314 ::std::vector< OUString > av;
1315 implGetLanguageVectorFromPackage( av, xPackage );
1316 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1317 if( pFound != av.end() )
1318 aLanguage = *pFound;
1321 return aFile;
1325 OUString ExtensionIteratorBase::implGetFileFromPackage(
1326 std::u16string_view rFileExtension, const Reference< deployment::XPackage >& xPackage )
1328 // No extension -> search for pure language folder
1329 bool bLangFolderOnly = rFileExtension.empty();
1331 OUString aFile;
1332 OUString aLanguage = m_aLanguage;
1333 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1335 OUString aStr = xPackage->getRegistrationDataURL().Value + "/" + aLanguage;
1336 if( !bLangFolderOnly )
1338 aStr += OUString::Concat("/help") + rFileExtension;
1341 aFile = m_rDatabases.expandURL( aStr );
1342 if( iPass == 0 )
1344 if( m_xSFA->exists( aFile ) )
1345 break;
1347 ::std::vector< OUString > av;
1348 implGetLanguageVectorFromPackage( av, xPackage );
1349 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1350 if( pFound != av.end() )
1351 aLanguage = *pFound;
1354 return aFile;
1357 static bool isLetter( sal_Unicode c )
1359 return rtl::isAsciiAlpha(c);
1362 void ExtensionIteratorBase::implGetLanguageVectorFromPackage( ::std::vector< OUString > &rv,
1363 const css::uno::Reference< css::deployment::XPackage >& xPackage )
1365 rv.clear();
1366 OUString aExtensionPath = xPackage->getURL();
1367 const Sequence< OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1369 for( const OUString& aEntry : aEntrySeq )
1371 if( m_xSFA->isFolder( aEntry ) )
1373 sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1374 if( nLastSlash != -1 )
1376 OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1378 // Check language scheme
1379 int nLen = aPureEntry.getLength();
1380 const sal_Unicode* pc = aPureEntry.getStr();
1381 bool bStartCanBeLanguage = ( nLen >= 2 && isLetter( pc[0] ) && isLetter( pc[1] ) );
1382 bool bIsLanguage = bStartCanBeLanguage &&
1383 ( nLen == 2 || (nLen == 5 && pc[2] == '-' && isLetter( pc[3] ) && isLetter( pc[4] )) );
1384 if( bIsLanguage )
1385 rv.push_back( aPureEntry );
1392 helpdatafileproxy::Hdf* DataBaseIterator::nextHdf( OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1394 helpdatafileproxy::Hdf* pRetHdf = nullptr;
1396 while( !pRetHdf && m_eState != IteratorState::EndReached )
1398 switch( m_eState )
1400 case IteratorState::InitialModule:
1401 pRetHdf = m_rDatabases.getHelpDataFile( m_aInitialModule, m_aLanguage, m_bHelpText );
1402 m_eState = IteratorState::UserExtensions; // Later: SHARED_MODULE
1403 break;
1405 // Later:
1406 //case SHARED_MODULE
1409 case IteratorState::UserExtensions:
1411 Reference< deployment::XPackage > xParentPackageBundle;
1412 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1413 if( !xHelpPackage.is() )
1414 break;
1415 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1416 break;
1419 case IteratorState::SharedExtensions:
1421 Reference< deployment::XPackage > xParentPackageBundle;
1422 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1423 if( !xHelpPackage.is() )
1424 break;
1426 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1427 break;
1430 case IteratorState::BundledExtensions:
1432 Reference< deployment::XPackage > xParentPackageBundle;
1433 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1434 if( !xHelpPackage.is() )
1435 break;
1437 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1438 break;
1441 case IteratorState::EndReached:
1442 OSL_FAIL( "DataBaseIterator::nextDb(): Invalid case IteratorState::EndReached" );
1443 break;
1447 return pRetHdf;
1450 helpdatafileproxy::Hdf* DataBaseIterator::implGetHdfFromPackage( const Reference< deployment::XPackage >& xPackage,
1451 OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1454 beans::Optional< OUString> optRegData;
1457 optRegData = xPackage->getRegistrationDataURL();
1459 catch ( deployment::ExtensionRemovedException&)
1461 return nullptr;
1464 helpdatafileproxy::Hdf* pRetHdf = nullptr;
1465 if (optRegData.IsPresent && !optRegData.Value.isEmpty())
1467 OUString aRegDataUrl = optRegData.Value + "/";
1469 OUString aHelpFilesBaseName(u"help"_ustr);
1471 OUString aUsedLanguage = m_aLanguage;
1472 pRetHdf = m_rDatabases.getHelpDataFile(
1473 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1475 // Language fallback
1476 if( !pRetHdf )
1478 ::std::vector< OUString > av;
1479 implGetLanguageVectorFromPackage( av, xPackage );
1480 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1481 if( pFound != av.end() )
1483 aUsedLanguage = *pFound;
1484 pRetHdf = m_rDatabases.getHelpDataFile(
1485 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1489 if( o_pExtensionPath )
1490 *o_pExtensionPath = aRegDataUrl + aUsedLanguage;
1492 if( o_pExtensionRegistryPath )
1493 *o_pExtensionRegistryPath = xPackage->getURL() + "/" + aUsedLanguage;
1496 return pRetHdf;
1500 //returns a file URL
1501 OUString KeyDataBaseFileIterator::nextDbFile(std::unique_lock<std::mutex>& rGuard, bool& o_rbExtension)
1503 OUString aRetFile;
1505 while( aRetFile.isEmpty() && m_eState != IteratorState::EndReached )
1507 switch( m_eState )
1509 case IteratorState::InitialModule:
1510 aRetFile = m_rDatabases.getInstallPathAsURL(rGuard) +
1511 m_rDatabases.processLang(rGuard, m_aLanguage) +
1512 "/" +
1513 m_aInitialModule + ".key";
1515 o_rbExtension = false;
1517 m_eState = IteratorState::UserExtensions; // Later: SHARED_MODULE
1518 break;
1520 // Later:
1521 //case SHARED_MODULE
1524 case IteratorState::UserExtensions:
1526 Reference< deployment::XPackage > xParentPackageBundle;
1527 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1528 if( !xHelpPackage.is() )
1529 break;
1531 aRetFile = implGetDbFileFromPackage(rGuard, xHelpPackage);
1532 o_rbExtension = true;
1533 break;
1536 case IteratorState::SharedExtensions:
1538 Reference< deployment::XPackage > xParentPackageBundle;
1539 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1540 if( !xHelpPackage.is() )
1541 break;
1543 aRetFile = implGetDbFileFromPackage(rGuard, xHelpPackage);
1544 o_rbExtension = true;
1545 break;
1548 case IteratorState::BundledExtensions:
1550 Reference< deployment::XPackage > xParentPackageBundle;
1551 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1552 if( !xHelpPackage.is() )
1553 break;
1555 aRetFile = implGetDbFileFromPackage(rGuard, xHelpPackage);
1556 o_rbExtension = true;
1557 break;
1560 case IteratorState::EndReached:
1561 OSL_FAIL( "DataBaseIterator::nextDbFile(): Invalid case IteratorState::EndReached" );
1562 break;
1566 return aRetFile;
1569 //Returns a file URL, that does not contain macros
1570 OUString KeyDataBaseFileIterator::implGetDbFileFromPackage(
1571 std::unique_lock<std::mutex>& rGuard,
1572 const Reference<deployment::XPackage>& xPackage)
1574 OUString aExpandedURL =
1575 implGetFileFromPackage(rGuard, u".key", xPackage);
1577 return aExpandedURL;
1581 Reference<XHierarchicalNameAccess> JarFileIterator::nextJarFile(
1582 std::unique_lock<std::mutex>& rGuard,
1583 Reference< deployment::XPackage >& o_xParentPackageBundle,
1584 OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1586 Reference< XHierarchicalNameAccess > xNA;
1588 while( !xNA.is() && m_eState != IteratorState::EndReached )
1590 switch( m_eState )
1592 case IteratorState::InitialModule:
1593 xNA = m_rDatabases.jarFile(rGuard, m_aInitialModule, m_aLanguage);
1594 m_eState = IteratorState::UserExtensions; // Later: SHARED_MODULE
1595 break;
1597 // Later:
1598 //case SHARED_MODULE
1601 case IteratorState::UserExtensions:
1603 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( o_xParentPackageBundle );
1604 if( !xHelpPackage.is() )
1605 break;
1607 xNA = implGetJarFromPackage(rGuard, xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath);
1608 break;
1611 case IteratorState::SharedExtensions:
1613 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( o_xParentPackageBundle );
1614 if( !xHelpPackage.is() )
1615 break;
1617 xNA = implGetJarFromPackage(rGuard, xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath);
1618 break;
1621 case IteratorState::BundledExtensions:
1623 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( o_xParentPackageBundle );
1624 if( !xHelpPackage.is() )
1625 break;
1627 xNA = implGetJarFromPackage(rGuard, xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath);
1628 break;
1631 case IteratorState::EndReached:
1632 OSL_FAIL( "JarFileIterator::nextJarFile(): Invalid case IteratorState::EndReached" );
1633 break;
1637 return xNA;
1640 Reference< XHierarchicalNameAccess > JarFileIterator::implGetJarFromPackage(
1641 std::unique_lock<std::mutex>& rGuard,
1642 const Reference<deployment::XPackage>& xPackage, OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath)
1644 Reference< XHierarchicalNameAccess > xNA;
1646 OUString zipFile =
1647 implGetFileFromPackage(rGuard, u".jar", xPackage);
1651 Sequence< Any > aArguments{
1652 Any(zipFile),
1653 // let ZipPackage be used ( no manifest.xml is required )
1654 Any(comphelper::makePropertyValue(u"StorageFormat"_ustr,
1655 ZIP_STORAGE_FORMAT_STRING))
1658 Reference< XMultiComponentFactory >xSMgr = m_xContext->getServiceManager();
1659 Reference< XInterface > xIfc
1660 = xSMgr->createInstanceWithArgumentsAndContext(
1661 u"com.sun.star.packages.comp.ZipPackage"_ustr,
1662 aArguments, m_xContext );
1664 if ( xIfc.is() )
1666 xNA.set( xIfc, UNO_QUERY );
1668 OSL_ENSURE( xNA.is(),
1669 "JarFileIterator::implGetJarFromPackage() - "
1670 "Got no hierarchical name access!" );
1673 catch ( RuntimeException & )
1675 catch ( Exception & )
1678 if( xNA.is() && o_pExtensionPath != nullptr )
1680 // Extract path including language from file name
1681 sal_Int32 nLastSlash = zipFile.lastIndexOf( '/' );
1682 if( nLastSlash != -1 )
1683 *o_pExtensionPath = zipFile.copy( 0, nLastSlash );
1685 if( o_pExtensionRegistryPath != nullptr )
1687 OUString& rPath = *o_pExtensionPath;
1688 sal_Int32 nLastSlashInPath = rPath.lastIndexOf( '/', rPath.getLength() - 1 );
1690 *o_pExtensionRegistryPath = xPackage->getURL();
1691 *o_pExtensionRegistryPath += rPath.subView( nLastSlashInPath);
1695 return xNA;
1699 OUString IndexFolderIterator::nextIndexFolder( bool& o_rbExtension, bool& o_rbTemporary )
1701 OUString aIndexFolder;
1703 while( aIndexFolder.isEmpty() && m_eState != IteratorState::EndReached )
1705 switch( m_eState )
1707 case IteratorState::InitialModule:
1708 aIndexFolder = m_rDatabases.getInstallPathAsURL()
1709 + m_rDatabases.processLang(m_aLanguage) + "/"
1710 + m_aInitialModule + ".idxl";
1712 o_rbTemporary = false;
1713 o_rbExtension = false;
1715 m_eState = IteratorState::UserExtensions; // Later: SHARED_MODULE
1716 break;
1718 // Later:
1719 //case SHARED_MODULE
1722 case IteratorState::UserExtensions:
1724 Reference< deployment::XPackage > xParentPackageBundle;
1725 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1726 if( !xHelpPackage.is() )
1727 break;
1729 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1730 o_rbExtension = true;
1731 break;
1734 case IteratorState::SharedExtensions:
1736 Reference< deployment::XPackage > xParentPackageBundle;
1737 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1738 if( !xHelpPackage.is() )
1739 break;
1741 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1742 o_rbExtension = true;
1743 break;
1746 case IteratorState::BundledExtensions:
1748 Reference< deployment::XPackage > xParentPackageBundle;
1749 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1750 if( !xHelpPackage.is() )
1751 break;
1753 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1754 o_rbExtension = true;
1755 break;
1758 case IteratorState::EndReached:
1759 OSL_FAIL( "IndexFolderIterator::nextIndexFolder(): Invalid case IteratorState::EndReached" );
1760 break;
1764 return aIndexFolder;
1767 OUString IndexFolderIterator::implGetIndexFolderFromPackage( bool& o_rbTemporary, const Reference< deployment::XPackage >& xPackage )
1769 OUString aIndexFolder =
1770 implGetFileFromPackage( u".idxl", xPackage );
1772 o_rbTemporary = false;
1773 if( !m_xSFA->isFolder( aIndexFolder ) )
1775 // i98680: Missing index? Try to generate now
1776 OUString aLangURL = implGetFileFromPackage( std::u16string_view(), xPackage );
1777 if( m_xSFA->isFolder( aLangURL ) )
1779 // Test write access (shared extension may be read only)
1780 bool bIsWriteAccess = false;
1783 OUString aCreateTestFolder = aLangURL + "CreateTestFolder";
1784 m_xSFA->createFolder( aCreateTestFolder );
1785 if( m_xSFA->isFolder( aCreateTestFolder ) )
1786 bIsWriteAccess = true;
1788 m_xSFA->kill( aCreateTestFolder );
1790 catch (const Exception &)
1794 // TEST
1795 //bIsWriteAccess = false;
1799 OUString aLang;
1800 sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
1801 if( nLastSlash != -1 )
1802 aLang = aLangURL.copy( nLastSlash + 1 );
1803 else
1804 aLang = "en";
1806 OUString aZipDir = aLangURL;
1807 if( !bIsWriteAccess )
1809 OUString aTempFileURL;
1810 ::osl::FileBase::RC eErr = ::osl::File::createTempFile( nullptr, nullptr, &aTempFileURL );
1811 if( eErr == ::osl::FileBase::E_None )
1815 m_xSFA->kill( aTempFileURL );
1817 catch (const Exception &)
1820 m_xSFA->createFolder( aTempFileURL );
1822 aZipDir = aTempFileURL;
1823 o_rbTemporary = true;
1827 HelpIndexer aIndexer(aLang, u"help"_ustr, aLangURL, aZipDir);
1828 aIndexer.indexDocuments();
1830 if( bIsWriteAccess )
1831 aIndexFolder = implGetFileFromPackage( u".idxl", xPackage );
1832 else
1833 aIndexFolder = aZipDir + "/help.idxl";
1835 catch (const Exception &)
1841 return aIndexFolder;
1844 void IndexFolderIterator::deleteTempIndexFolder( std::u16string_view aIndexFolder )
1846 size_t nLastSlash = aIndexFolder.rfind( '/' );
1847 if( nLastSlash != std::u16string_view::npos )
1849 OUString aTmpFolder( aIndexFolder.substr( 0, nLastSlash ) );
1852 m_xSFA->kill( aTmpFolder );
1854 catch (const Exception &)
1860 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */