1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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"
36 #include <string_view>
38 #include <helpcompiler/HelpIndexer.hxx>
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>
63 #include "databases.hxx"
64 #include "urlparameter.hxx"
67 #if !defined WIN32_LEAN_AND_MEAN
68 # define WIN32_LEAN_AND_MEAN
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
);
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
;
113 uriRef
= xFac
->parse( aRetURL
);
116 Reference
< uri::XVndSunStarExpandUrl
> sxUri( uriRef
, UNO_QUERY
);
120 aRetURL
= sxUri
->expand( xMacroExpander
);
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();
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
171 m_aDatabases
.clear();
177 m_aKeywordInfo
.clear();
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
;
196 OUStringBuffer
aStrBuf( 0 );
201 idx1
= oustring
.indexOf( '%', idx
);
202 idx2
= oustring
.indexOf( '$', idx
);
204 if(idx1
== -1 && idx2
== -1)
215 else if(idx2
< idx1
)
219 if( oustring
.indexOf( prodName
,idx
) == idx
)
221 else if( oustring
.indexOf( prodVersion
,idx
) == idx
)
222 off
= PRODUCTVERSION
;
223 else if( oustring
.indexOf( vendName
,idx
) == idx
)
225 else if( oustring
.indexOf( vendVersion
,idx
) == idx
)
227 else if( oustring
.indexOf( vendShort
,idx
) == idx
)
229 else if( oustring
.indexOf( newProdName
,idx
) == idx
)
230 off
= NEWPRODUCTNAME
;
231 else if( oustring
.indexOf( newProdVersion
,idx
) == idx
)
232 off
= NEWPRODUCTVERSION
;
241 aStrBuf
.ensureCapacity( 256 );
244 aStrBuf
.append( &oustring
.getStr()[k
],idx
- k
);
245 aStrBuf
.append( m_vReplacement
[off
] );
246 k
= idx
+ m_vAdd
[off
];
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() )
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
) )
289 fileName
= aStatus
.getFileName();
291 // Check, whether fileName is of the form *.cfg
292 if (!fileName
.endsWithIgnoreAsciiCase(u
".cfg", &fileName
)) {
295 fileName
= fileName
.toAsciiLowerCase();
296 if (fileName
== "picture"
297 || (!m_bShowBasic
&& fileName
== "sbasic"))
302 m_avModules
.push_back( fileName
);
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;
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
));
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' )
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 );
372 lineBuffer
[ pos
++ ] = ch
;
374 replaceName( title
);
375 it
->second
.reset(new StaticModuleInformation( title
,
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
)
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
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
))
412 m_aLangSet
[ Language
] = 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() )
441 OUString
aFileExt( helpText
? u
".ht"_ustr
: u
".db"_ustr
);
442 OUString dbFileName
= OUString::Concat("/") + Database
+ aFileExt
;
444 if( pExtensionPath
== nullptr )
445 key
= processLang( rGuard
, Language
) + dbFileName
;
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
;
460 fileURL
= expandURL(rGuard
, *pExtensionPath
) + Language
+ dbFileName
;
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" )
499 else if( langStr
== "en" )
501 else if( langStr
== "es" )
503 else if( langStr
== "it" )
505 else if( langStr
== "fr" )
507 else if( langStr
== "sv" )
509 else if( langStr
== "ja" )
511 else if( langStr
== "ko" )
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);
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
;
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
);
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 );
569 Reference
< XCollator
> m_xCollator
;
570 }; // end struct KeywordElementComparator
574 KeywordInfo::KeywordElement::KeywordElement( Databases
const *pDatabases
,
575 helpdatafileproxy::Hdf
* pHdf
,
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
;
591 idx
= ids
.find( ';', k
);
592 if( idx
== std::u16string_view::npos
)
594 size_t h
= ids
.find( '#', k
);
595 if( h
!= std::u16string_view::npos
&& h
< idx
)
598 id
.push_back( OUString(ids
.substr( k
, h
-k
)) );
599 anchor
.push_back( OUString(ids
.substr( h
+1, idx
-h
-1 )) );
603 id
.push_back( OUString(ids
.substr( k
, idx
-k
)) );
604 anchor
.emplace_back( );
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
)
619 plistAnchor
[i
] = anchor
[i
];
621 helpdatafileproxy::HDFData aHDFData
;
622 const char* pData
= nullptr;
626 OString idi
= OUStringToOString( id
[i
], RTL_TEXTENCODING_UTF8
);
627 bool bSuccess
= pHdf
->getValueForKey( idi
, aHDFData
);
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 )
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' )
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
)
696 if( nLastFound
== 0 )
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
);
725 bool bExtension
= false;
728 fileURL
= aDbFileIt
.nextDbFile(aGuard
, bExtension
);
729 if( fileURL
.isEmpty() )
731 OUString
fileNameHDFHelp( fileURL
);
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;
757 bBelongsToDatabase
= checkModuleMatchForExtension( Database
, doclist
);
759 if( !bBelongsToDatabase
)
762 aVector
.emplace_back( this,
767 aHdf
.stopIteration();
769 if( pHdf
!= nullptr )
770 pHdf
->releaseHashMap();
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() )
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
);
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
);
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
);
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
& )
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() )
876 ::std::unique_lock
aGuard(m_aMutex
);
878 JarFileIterator
aJarFileIt( m_xContext
, *this, jar
, Language
);
879 Reference
< XHierarchicalNameAccess
> xTestNA
;
880 Reference
< deployment::XPackage
> xParentPackageBundle
;
883 xTestNA
= aJarFileIt
.nextJarFile(aGuard
, xParentPackageBundle
, o_pExtensionPath
, o_pExtensionRegistryPath
);
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
911 // No identifier -> ignore
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() )
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";
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";
985 while( error
&& retry
)
990 getInstallPathAsURL() +
991 processLang( Language
) +
995 else if( retry
== 1 )
997 getInstallPathAsURL() +
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
) )
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
);
1020 if ( !retry
&& error
&& bHighContrastMode
)
1022 // fall back to default css
1025 bHighContrastMode
= false;
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
;
1053 const char* pData
= nullptr;
1055 bool bSuccess
= false;
1056 if( !bFoundAsEmpty
)
1060 helpdatafileproxy::Hdf
* pHdf
= aDbIt
.nextHdf();
1063 bSuccess
= pHdf
->getValueForKey( id
, aHDFData
);
1064 nSize
= aHDFData
.getSize();
1065 pData
= aHDFData
.getData();
1071 // ensure existence of tmp after for
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(),
1081 RTL_TEXTENCODING_UTF8
);
1082 nSize
= tmp
.getLength();
1083 pData
= tmp
.getStr();
1087 buffer
.append( pData
, nSize
);
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() );
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
))
1133 void ExtensionIteratorBase::init()
1135 m_xSFA
= ucb::SimpleFileAccess::create(m_xContext
);
1137 m_bUserPackagesLoaded
= false;
1138 m_bSharedPackagesLoaded
= false;
1139 m_bBundledPackagesLoaded
= false;
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
)
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
;
1193 const Reference
< deployment::XPackageTypeInfo
> xPackageTypeInfo
= xPackage
->getPackageType();
1194 OUString aMediaType
= xPackageTypeInfo
->getMediaType();
1195 if( aMediaType
== aHelpMediaType
)
1196 xHelpPackage
= xPackage
;
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
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
;
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
;
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();
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
);
1311 if( m_xSFA
->exists( aFile
) )
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
;
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();
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
);
1344 if( m_xSFA
->exists( aFile
) )
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
;
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
)
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] )) );
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
)
1400 case IteratorState::InitialModule
:
1401 pRetHdf
= m_rDatabases
.getHelpDataFile( m_aInitialModule
, m_aLanguage
, m_bHelpText
);
1402 m_eState
= IteratorState::UserExtensions
; // Later: SHARED_MODULE
1406 //case SHARED_MODULE
1409 case IteratorState::UserExtensions
:
1411 Reference
< deployment::XPackage
> xParentPackageBundle
;
1412 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextUserHelpPackage( xParentPackageBundle
);
1413 if( !xHelpPackage
.is() )
1415 pRetHdf
= implGetHdfFromPackage( xHelpPackage
, o_pExtensionPath
, o_pExtensionRegistryPath
);
1419 case IteratorState::SharedExtensions
:
1421 Reference
< deployment::XPackage
> xParentPackageBundle
;
1422 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextSharedHelpPackage( xParentPackageBundle
);
1423 if( !xHelpPackage
.is() )
1426 pRetHdf
= implGetHdfFromPackage( xHelpPackage
, o_pExtensionPath
, o_pExtensionRegistryPath
);
1430 case IteratorState::BundledExtensions
:
1432 Reference
< deployment::XPackage
> xParentPackageBundle
;
1433 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextBundledHelpPackage( xParentPackageBundle
);
1434 if( !xHelpPackage
.is() )
1437 pRetHdf
= implGetHdfFromPackage( xHelpPackage
, o_pExtensionPath
, o_pExtensionRegistryPath
);
1441 case IteratorState::EndReached
:
1442 OSL_FAIL( "DataBaseIterator::nextDb(): Invalid case IteratorState::EndReached" );
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
&)
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
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
;
1500 //returns a file URL
1501 OUString
KeyDataBaseFileIterator::nextDbFile(std::unique_lock
<std::mutex
>& rGuard
, bool& o_rbExtension
)
1505 while( aRetFile
.isEmpty() && m_eState
!= IteratorState::EndReached
)
1509 case IteratorState::InitialModule
:
1510 aRetFile
= m_rDatabases
.getInstallPathAsURL(rGuard
) +
1511 m_rDatabases
.processLang(rGuard
, m_aLanguage
) +
1513 m_aInitialModule
+ ".key";
1515 o_rbExtension
= false;
1517 m_eState
= IteratorState::UserExtensions
; // Later: SHARED_MODULE
1521 //case SHARED_MODULE
1524 case IteratorState::UserExtensions
:
1526 Reference
< deployment::XPackage
> xParentPackageBundle
;
1527 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextUserHelpPackage( xParentPackageBundle
);
1528 if( !xHelpPackage
.is() )
1531 aRetFile
= implGetDbFileFromPackage(rGuard
, xHelpPackage
);
1532 o_rbExtension
= true;
1536 case IteratorState::SharedExtensions
:
1538 Reference
< deployment::XPackage
> xParentPackageBundle
;
1539 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextSharedHelpPackage( xParentPackageBundle
);
1540 if( !xHelpPackage
.is() )
1543 aRetFile
= implGetDbFileFromPackage(rGuard
, xHelpPackage
);
1544 o_rbExtension
= true;
1548 case IteratorState::BundledExtensions
:
1550 Reference
< deployment::XPackage
> xParentPackageBundle
;
1551 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextBundledHelpPackage( xParentPackageBundle
);
1552 if( !xHelpPackage
.is() )
1555 aRetFile
= implGetDbFileFromPackage(rGuard
, xHelpPackage
);
1556 o_rbExtension
= true;
1560 case IteratorState::EndReached
:
1561 OSL_FAIL( "DataBaseIterator::nextDbFile(): Invalid case IteratorState::EndReached" );
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
)
1592 case IteratorState::InitialModule
:
1593 xNA
= m_rDatabases
.jarFile(rGuard
, m_aInitialModule
, m_aLanguage
);
1594 m_eState
= IteratorState::UserExtensions
; // Later: SHARED_MODULE
1598 //case SHARED_MODULE
1601 case IteratorState::UserExtensions
:
1603 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextUserHelpPackage( o_xParentPackageBundle
);
1604 if( !xHelpPackage
.is() )
1607 xNA
= implGetJarFromPackage(rGuard
, xHelpPackage
, o_pExtensionPath
, o_pExtensionRegistryPath
);
1611 case IteratorState::SharedExtensions
:
1613 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextSharedHelpPackage( o_xParentPackageBundle
);
1614 if( !xHelpPackage
.is() )
1617 xNA
= implGetJarFromPackage(rGuard
, xHelpPackage
, o_pExtensionPath
, o_pExtensionRegistryPath
);
1621 case IteratorState::BundledExtensions
:
1623 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextBundledHelpPackage( o_xParentPackageBundle
);
1624 if( !xHelpPackage
.is() )
1627 xNA
= implGetJarFromPackage(rGuard
, xHelpPackage
, o_pExtensionPath
, o_pExtensionRegistryPath
);
1631 case IteratorState::EndReached
:
1632 OSL_FAIL( "JarFileIterator::nextJarFile(): Invalid case IteratorState::EndReached" );
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
;
1647 implGetFileFromPackage(rGuard
, u
".jar", xPackage
);
1651 Sequence
< Any
> aArguments
{
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
);
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
);
1699 OUString
IndexFolderIterator::nextIndexFolder( bool& o_rbExtension
, bool& o_rbTemporary
)
1701 OUString aIndexFolder
;
1703 while( aIndexFolder
.isEmpty() && m_eState
!= IteratorState::EndReached
)
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
1719 //case SHARED_MODULE
1722 case IteratorState::UserExtensions
:
1724 Reference
< deployment::XPackage
> xParentPackageBundle
;
1725 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextUserHelpPackage( xParentPackageBundle
);
1726 if( !xHelpPackage
.is() )
1729 aIndexFolder
= implGetIndexFolderFromPackage( o_rbTemporary
, xHelpPackage
);
1730 o_rbExtension
= true;
1734 case IteratorState::SharedExtensions
:
1736 Reference
< deployment::XPackage
> xParentPackageBundle
;
1737 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextSharedHelpPackage( xParentPackageBundle
);
1738 if( !xHelpPackage
.is() )
1741 aIndexFolder
= implGetIndexFolderFromPackage( o_rbTemporary
, xHelpPackage
);
1742 o_rbExtension
= true;
1746 case IteratorState::BundledExtensions
:
1748 Reference
< deployment::XPackage
> xParentPackageBundle
;
1749 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextBundledHelpPackage( xParentPackageBundle
);
1750 if( !xHelpPackage
.is() )
1753 aIndexFolder
= implGetIndexFolderFromPackage( o_rbTemporary
, xHelpPackage
);
1754 o_rbExtension
= true;
1758 case IteratorState::EndReached
:
1759 OSL_FAIL( "IndexFolderIterator::nextIndexFolder(): Invalid case IteratorState::EndReached" );
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
&)
1795 //bIsWriteAccess = false;
1800 sal_Int32 nLastSlash
= aLangURL
.lastIndexOf( '/' );
1801 if( nLastSlash
!= -1 )
1802 aLang
= aLangURL
.copy( nLastSlash
+ 1 );
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
);
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: */