LibreOffice Module xmlhelp (master) 1
databases.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
32#include "inputstream.hxx"
33#include <algorithm>
34#include <cassert>
35#include <string.h>
36#include <string_view>
37
39
40// Extensible help
41#include <com/sun/star/deployment/ExtensionManager.hpp>
42#include <com/sun/star/deployment/ExtensionRemovedException.hpp>
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>
54
55#include <com/sun/star/awt/XVclWindowPeer.hpp>
56#include <com/sun/star/awt/XTopWindow.hpp>
57
60#include <utility>
61
62#include "databases.hxx"
63#include "urlparameter.hxx"
64
65#ifdef _WIN32
66#if !defined WIN32_LEAN_AND_MEAN
67# define WIN32_LEAN_AND_MEAN
68#endif
69#include <windows.h>
70#endif
71
72using namespace chelp;
73using namespace com::sun::star;
74using namespace com::sun::star::uno;
75using namespace com::sun::star::io;
76using namespace com::sun::star::container;
77using namespace com::sun::star::i18n;
78using namespace com::sun::star::lang;
79using namespace com::sun::star::deployment;
80using namespace com::sun::star::beans;
81
82OUString Databases::expandURL( const OUString& aURL )
83{
84 std::unique_lock aGuard(m_aMutex);
85 return expandURL(aGuard, aURL);
86}
87
88OUString Databases::expandURL( std::unique_lock<std::mutex>& /*rGuard*/, const OUString& aURL )
89{
90 OUString aRetURL = expandURL( aURL, m_xContext );
91 return aRetURL;
92}
93
94OUString Databases::expandURL( const OUString& aURL, const Reference< uno::XComponentContext >& xContext )
95{
96 static Reference< util::XMacroExpander > xMacroExpander;
98
99 if( !xMacroExpander.is() || !xFac.is() )
100 {
101 xFac = uri::UriReferenceFactory::create( xContext );
102
103 xMacroExpander = util::theMacroExpander::get(xContext);
104 }
105
106 OUString aRetURL = aURL;
107 if( xMacroExpander.is() )
108 {
110 for (;;)
111 {
112 uriRef = xFac->parse( aRetURL );
113 if ( uriRef.is() )
114 {
115 Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
116 if( !sxUri.is() )
117 break;
118
119 aRetURL = sxUri->expand( xMacroExpander );
120 }
121 }
122 }
123 return aRetURL;
124}
125
126const char vendVersion[] = "%VENDORVERSION";
127const char vendName[] = "%VENDORNAME";
128const char prodVersion[] = "%PRODUCTVERSION";
129const char vendShort[] = "%VENDORSHORT";
130const char prodName[] = "%PRODUCTNAME";
131const char newProdVersion[] = "$[officeversion]";
132const char newProdName[] = "$[officename]";
133
134Databases::Databases( bool showBasic,
135 const OUString& instPath,
136 const OUString& productName,
137 const OUString& productVersion,
138 const OUString& styleSheet,
139 Reference< uno::XComponentContext > const & xContext )
140 : m_xContext( xContext ),
141 m_bShowBasic(showBasic),
142 m_aCSS(styleSheet.toAsciiLowerCase())
143{
144 m_xSMgr = m_xContext->getServiceManager();
145
146 m_vAdd[0] = 12;
147 m_vAdd[1] = 15;
148 m_vAdd[2] = 11;
149 m_vAdd[3] = 14;
150 m_vAdd[4] = 12;
151 m_vAdd[5] = 13;
152 m_vAdd[6] = 16;
153
154 m_vReplacement[0] = productName;
155 m_vReplacement[1] = productVersion;
156 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
157 m_vReplacement[5] = productName;
158 m_vReplacement[6] = productVersion;
159
160 setInstallPath( instPath );
161
162 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
163}
164
166{
167 // unload the databases
168
169 // DatabasesTable
170 m_aDatabases.clear();
171
172 // ModInfoTable
173 m_aModInfo.clear();
174
175 // KeywordInfoTable
176 m_aKeywordInfo.clear();
177}
178
180{
181 uno::Reference< lang::XMultiServiceFactory > xConfigProvider =
182 configuration::theDefaultProvider::get(m_xContext);
183
184 // set root path
185 uno::Sequence<uno::Any> lParams(comphelper::InitAnyPropertySequence(
186 {
187 {"nodepath", uno::Any(OUString("org.openoffice.Office.Common"))}
188 }));
189
190 // open it
191 uno::Reference< uno::XInterface > xCFG( xConfigProvider->createInstanceWithArguments(
192 "com.sun.star.configuration.ConfigurationAccess",
193 lParams) );
194
195 uno::Reference< container::XHierarchicalNameAccess > xAccess(xCFG, uno::UNO_QUERY_THROW);
196 uno::Any aResult = xAccess->getByHierarchicalName("Misc/SymbolStyle");
197 OUString aSymbolsStyleName;
198 aResult >>= aSymbolsStyleName;
199
200 if ( aSymbolsStyleName.isEmpty() || aSymbolsStyleName == "auto" )
201 {
202 aSymbolsStyleName = "colibre";
203 }
204 return aSymbolsStyleName.toUtf8();
205}
206
207void Databases::replaceName( OUString& oustring ) const
208{
209 sal_Int32 idx = -1,idx1 = -1,idx2 = -1,k = 0,off;
210 bool cap = false;
211 OUStringBuffer aStrBuf( 0 );
212
213 while( true )
214 {
215 ++idx;
216 idx1 = oustring.indexOf( '%', idx);
217 idx2 = oustring.indexOf( '$', idx);
218
219 if(idx1 == -1 && idx2 == -1)
220 break;
221
222 if(idx1 == -1)
223 idx = idx2;
224 else if(idx2 == -1)
225 idx = idx1;
226 else {
227 // no index is zero
228 if(idx1 < idx2)
229 idx = idx1;
230 else if(idx2 < idx1 )
231 idx = idx2;
232 }
233
234 if( oustring.indexOf( prodName,idx ) == idx )
235 off = PRODUCTNAME;
236 else if( oustring.indexOf( prodVersion,idx ) == idx )
237 off = PRODUCTVERSION;
238 else if( oustring.indexOf( vendName,idx ) == idx )
239 off = VENDORNAME;
240 else if( oustring.indexOf( vendVersion,idx ) == idx )
241 off = VENDORVERSION;
242 else if( oustring.indexOf( vendShort,idx ) == idx )
243 off = VENDORSHORT;
244 else if( oustring.indexOf( newProdName,idx ) == idx )
245 off = NEWPRODUCTNAME;
246 else if( oustring.indexOf( newProdVersion,idx ) == idx )
247 off = NEWPRODUCTVERSION;
248 else
249 off = -1;
250
251 if( off != -1 )
252 {
253 if( ! cap )
254 {
255 cap = true;
256 aStrBuf.ensureCapacity( 256 );
257 }
258
259 aStrBuf.append( &oustring.getStr()[k],idx - k );
260 aStrBuf.append( m_vReplacement[off] );
261 k = idx + m_vAdd[off];
262 }
263 }
264
265 if( cap )
266 {
267 if( k < oustring.getLength() )
268 aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
269 oustring = aStrBuf.makeStringAndClear();
270 }
271}
272
274{
275 std::unique_lock aGuard( m_aMutex );
276
277 return m_aInstallDirectory;
278}
279
280OUString Databases::getInstallPathAsURL(std::unique_lock<std::mutex>& )
281{
282 return m_aInstallDirectory;
283}
284
285const std::vector< OUString >& Databases::getModuleList( const OUString& Language )
286{
287 if( m_avModules.empty() )
288 {
289 OUString fileName,dirName = getInstallPathAsURL() + processLang( Language );
290 osl::Directory dirFile( dirName );
291
292 osl::DirectoryItem aDirItem;
293 osl::FileStatus aStatus( osl_FileStatus_Mask_FileName );
294
295 if( osl::FileBase::E_None != dirFile.open() )
296 return m_avModules;
297
298 while( dirFile.getNextItem( aDirItem ) == osl::FileBase::E_None &&
299 aDirItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
300 {
301 if( ! aStatus.isValid( osl_FileStatus_Mask_FileName ) )
302 continue;
303
304 fileName = aStatus.getFileName();
305
306 // Check, whether fileName is of the form *.cfg
307 if (!fileName.endsWithIgnoreAsciiCase(".cfg", &fileName)) {
308 continue;
309 }
310 fileName = fileName.toAsciiLowerCase();
311 if (fileName == "picture"
312 || (!m_bShowBasic && fileName == "sbasic"))
313 {
314 continue;
315 }
316
317 m_avModules.push_back( fileName );
318 }
319 }
320 return m_avModules;
321}
322
324 const OUString& Language )
325{
326 std::unique_lock aGuard( m_aMutex );
327
328 OUString key = processLang(aGuard, Language) + "/" + Module;
329
330 std::pair< ModInfoTable::iterator,bool > aPair =
331 m_aModInfo.emplace(key,nullptr);
332
333 ModInfoTable::iterator it = aPair.first;
334
335 if( aPair.second && ! it->second )
336 {
337 osl::File cfgFile( m_aInstallDirectory + key + ".cfg" );
338
339 if( osl::FileBase::E_None != cfgFile.open( osl_File_OpenFlag_Read ) )
340 it->second = nullptr;
341 else
342 {
343 sal_uInt32 pos = 0;
344 sal_uInt64 nRead;
345 char buffer[2048];
346 sal_Unicode lineBuffer[1028];
347 OUStringBuffer fileContent;
348
349 while( osl::FileBase::E_None == cfgFile.read( &buffer,2048,nRead ) && nRead )
350 fileContent.append(OUString( buffer,sal_Int32( nRead ),RTL_TEXTENCODING_UTF8 ));
351
352 cfgFile.close();
353
354 const sal_Unicode* str = fileContent.getStr();
355 OUString current,program,startid,title;
356 OUString order( "1" );
357
358 for( sal_Int32 i = 0;i < fileContent.getLength();i++ )
359 {
360 sal_Unicode ch = str[ i ];
361 if( ch == '\n' || ch == '\r' )
362 {
363 if( pos )
364 {
365 current = OUString( lineBuffer,pos );
366
367 if( current.startsWith("Title") )
368 {
369 title = current.copy( current.indexOf( '=' ) + 1 );
370 }
371 else if( current.startsWith("Start") )
372 {
373 startid = current.copy( current.indexOf('=') + 1 );
374 }
375 else if( current.startsWith("Program") )
376 {
377 program = current.copy( current.indexOf('=') + 1 );
378 }
379 else if( current.startsWith("Order") )
380 {
381 order = current.copy( current.indexOf('=') + 1 );
382 }
383 }
384 pos = 0;
385 }
386 else
387 lineBuffer[ pos++ ] = ch;
388 }
389 replaceName( title );
390 it->second.reset(new StaticModuleInformation( title,
391 startid,
392 program,
393 order ));
394 }
395 }
396
397 return it->second.get();
398}
399
400OUString Databases::processLang( const OUString& Language )
401{
402 std::unique_lock aGuard( m_aMutex );
403 return processLang(aGuard, Language);
404}
405
406OUString Databases::processLang( std::unique_lock<std::mutex>& /*rGuard*/, const OUString& Language )
407{
408 OUString ret;
409 LangSetTable::iterator it = m_aLangSet.find( Language );
410
411 if( it == m_aLangSet.end() )
412 {
413 // XXX the old code looked for '-' and '_' as separator between
414 // language and country, no idea if '_' actually still can happen
415 // (probably not), but play safe and keep that and transform to proper
416 // BCP47.
417 const OUString aBcp47( Language.replaceAll( "_", "-"));
418
419 // Try if language tag or fallbacks are installed.
420 osl::DirectoryItem aDirItem;
421 std::vector<OUString> aFallbacks( LanguageTag( aBcp47).getFallbackStrings(true));
422 for (auto const & rFB : aFallbacks)
423 {
424 if (osl::FileBase::E_None == osl::DirectoryItem::get( m_aInstallDirectory + rFB, aDirItem))
425 {
426 ret = rFB;
427 m_aLangSet[ Language ] = ret;
428 break; // for
429 }
430 }
431 }
432 else
433 ret = it->second;
434
435 return ret;
436}
437
439 const OUString& Language, bool helpText,
440 const OUString* pExtensionPath )
441{
442 std::unique_lock aGuard( m_aMutex );
443
444 return getHelpDataFile(aGuard, Database, Language, helpText, pExtensionPath);
445}
446
447helpdatafileproxy::Hdf* Databases::getHelpDataFile(std::unique_lock<std::mutex>& rGuard,
448 std::u16string_view Database,
449 const OUString& Language, bool helpText,
450 const OUString* pExtensionPath )
451
452{
453 if( Database.empty() || Language.isEmpty() )
454 return nullptr;
455
456 OUString aFileExt( helpText ? OUString(".ht") : OUString(".db") );
457 OUString dbFileName = OUString::Concat("/") + Database + aFileExt;
458 OUString key;
459 if( pExtensionPath == nullptr )
460 key = processLang( rGuard, Language ) + dbFileName;
461 else
462 key = *pExtensionPath + Language + dbFileName; // make unique, don't change language
463
464 std::pair< DatabasesTable::iterator,bool > aPair =
465 m_aDatabases.emplace( key, nullptr);
466
467 DatabasesTable::iterator it = aPair.first;
468
469 if( aPair.second && ! it->second )
470 {
471 std::unique_ptr<helpdatafileproxy::Hdf> pHdf;
472
473 OUString fileURL;
474 if( pExtensionPath )
475 fileURL = expandURL(rGuard, *pExtensionPath) + Language + dbFileName;
476 else
477 fileURL = m_aInstallDirectory + key;
478
479 OUString fileNameHDFHelp( fileURL );
480 //Extensions always use the new format
481 if( pExtensionPath != nullptr )
482 fileNameHDFHelp += "_";
483 //SimpleFileAccess takes file URLs as arguments!!! Using filenames works accidentally but
484 //fails for example when using long path names on Windows (starting with \\?\‍)
485 if( m_xSFA->exists( fileNameHDFHelp ) )
486 {
487 pHdf.reset(new helpdatafileproxy::Hdf( fileNameHDFHelp, m_xSFA ));
488 }
489
490 it->second = std::move(pHdf);
491 }
492
493 return it->second.get();
494}
495
497Databases::getCollator(std::unique_lock<std::mutex>&, const OUString& Language)
498{
499 OUString key = Language;
500
501 CollatorTable::iterator it =
502 m_aCollatorTable.emplace( key, Reference< XCollator >() ).first;
503
504 if( ! it->second.is() )
505 {
506 it->second = Collator::create(m_xContext);
507 LanguageTag aLanguageTag( Language);
508 OUString countryStr = aLanguageTag.getCountry();
509 if( countryStr.isEmpty() )
510 {
511 const OUString langStr = aLanguageTag.getLanguage();
512 if( langStr == "de" )
513 countryStr = "DE";
514 else if( langStr == "en" )
515 countryStr = "US";
516 else if( langStr == "es" )
517 countryStr = "ES";
518 else if( langStr == "it" )
519 countryStr = "IT";
520 else if( langStr == "fr" )
521 countryStr = "FR";
522 else if( langStr == "sv" )
523 countryStr = "SE";
524 else if( langStr == "ja" )
525 countryStr = "JP";
526 else if( langStr == "ko" )
527 countryStr = "KR";
528
529 // XXX NOTE: there are no complex language tags involved in those
530 // "add country" cases, only because of this we can use this
531 // simplified construction.
532 if (!countryStr.isEmpty())
533 aLanguageTag.reset( langStr + "-" + countryStr);
534 }
535 it->second->loadDefaultCollator( aLanguageTag.getLocale(), 0);
536 }
537
538 return it->second;
539}
540
541namespace chelp {
542
544 {
546 : m_xCollator( xCollator )
547 { }
548
549 bool operator()( const KeywordInfo::KeywordElement& la,
550 const KeywordInfo::KeywordElement& ra ) const
551 {
552 const OUString& l = la.key;
553 const OUString& r = ra.key;
554
555 bool ret;
556
557 if( m_xCollator.is() )
558 {
559 sal_Int32 l1 = l.indexOf( ';' );
560 sal_Int32 l3 = ( l1 == -1 ? l.getLength() : l1 );
561
562 sal_Int32 r1 = r.indexOf( ';' );
563 sal_Int32 r3 = ( r1 == -1 ? r.getLength() : r1 );
564
565 sal_Int32 c1 = m_xCollator->compareSubstring( l,0,l3,r,0,r3 );
566
567 if( c1 == +1 )
568 ret = false;
569 else if( c1 == 0 )
570 {
571 sal_Int32 l2 = l.getLength() - l1 - 1;
572 sal_Int32 r2 = r.getLength() - r1 - 1;
573 ret = ( m_xCollator->compareSubstring( l,1+l1,l2,r,1+r1,r2 ) < 0 );
574 }
575 else
576 ret = true;
577 }
578 else
579 ret = l < r;
580
581 return ret;
582 }
583
585 }; // end struct KeywordElementComparator
586
587}
588
591 OUString ky,
592 std::u16string_view data )
593 : key(std::move( ky ))
594{
595 pDatabases->replaceName( key );
596 init( pDatabases,pHdf,data );
597}
598
599void KeywordInfo::KeywordElement::init( Databases const *pDatabases,helpdatafileproxy::Hdf* pHdf, std::u16string_view ids )
600{
601 std::vector< OUString > id,anchor;
602 size_t idx = std::u16string_view::npos;
603 size_t k = 0;
604 for (;;)
605 {
606 idx = ids.find( ';', k );
607 if( idx == std::u16string_view::npos )
608 break;
609 size_t h = ids.find( '#', k );
610 if( h == std::u16string_view::npos || h < idx )
611 {
612 // found an anchor
613 id.push_back( OUString(ids.substr( k, h-k )) );
614 anchor.push_back( OUString(ids.substr( h+1, idx-h-1 )) );
615 }
616 else
617 {
618 id.push_back( OUString(ids.substr( k, idx-k )) );
619 anchor.emplace_back( );
620 }
621 k = ++idx;
622 }
623
624 listId.realloc( id.size() );
625 auto plistId = listId.getArray();
626 listAnchor.realloc( id.size() );
627 auto plistAnchor = listAnchor.getArray();
628 listTitle.realloc( id.size() );
629 auto plistTitle = listTitle.getArray();
630
631 for( size_t i = 0; i < id.size(); ++i )
632 {
633 plistId[i] = id[i];
634 plistAnchor[i] = anchor[i];
635
637 const char* pData = nullptr;
638
639 if( pHdf )
640 {
641 OString idi = OUStringToOString( id[i], RTL_TEXTENCODING_UTF8 );
642 bool bSuccess = pHdf->getValueForKey( idi, aHDFData );
643 if( bSuccess )
644 pData = aHDFData.getData();
645 }
646
647 DbtToStringConverter converter( pData );
648
649 OUString title = converter.getTitle();
650 pDatabases->replaceName( title );
651 plistTitle[i] = title;
652 }
653}
654
655KeywordInfo::KeywordInfo( const std::vector< KeywordElement >& aVec )
656 : listKey( aVec.size() ),
657 listId( aVec.size() ),
658 listAnchor( aVec.size() ),
659 listTitle( aVec.size() )
660{
661 auto listKeyRange = asNonConstRange(listKey);
662 auto listIdRange = asNonConstRange(listId);
663 auto listAnchorRange = asNonConstRange(listAnchor);
664 auto listTitleRange = asNonConstRange(listTitle);
665 for( size_t i = 0; i < aVec.size(); ++i )
666 {
667 listKeyRange[i] = aVec[i].key;
668 listIdRange[i] = aVec[i].listId;
669 listAnchorRange[i] = aVec[i].listAnchor;
670 listTitleRange[i] = aVec[i].listTitle;
671 }
672}
673
675 ( std::u16string_view Database, const OUString& doclist )
676{
677 bool bBelongsToDatabase = true;
678
679 // Analyse doclist string to find module assignments
680 bool bFoundAtLeastOneModule = false;
681 bool bModuleMatch = false;
682 sal_Int32 nLen = doclist.getLength();
683 sal_Int32 nLastFound = doclist.lastIndexOf( ';' );
684 if( nLastFound == -1 )
685 nLastFound = nLen;
686 const sal_Unicode* pStr = doclist.getStr();
687 sal_Int32 nFound = doclist.lastIndexOf( '_' );
688 while( nFound != -1 )
689 {
690 // Simple optimization, stop if '_' is followed by "id"
691 if( nLen - nFound > 2 )
692 {
693 if( pStr[ nFound + 1 ] == 'i' &&
694 pStr[ nFound + 2 ] == 'd' )
695 break;
696 }
697
698 OUString aModule = doclist.copy( nFound + 1, nLastFound - nFound - 1 );
699 std::vector< OUString >::iterator result = std::find( m_avModules.begin(), m_avModules.end(), aModule );
700 if( result != m_avModules.end() )
701 {
702 bFoundAtLeastOneModule = true;
703 if( Database == aModule )
704 {
705 bModuleMatch = true;
706 break;
707 }
708 }
709
710 nLastFound = nFound;
711 if( nLastFound == 0 )
712 break;
713 nFound = doclist.lastIndexOf( '_', nLastFound - 1 );
714 }
715
716 if( bFoundAtLeastOneModule && !bModuleMatch )
717 bBelongsToDatabase = false;
718
719 return bBelongsToDatabase;
720}
721
722KeywordInfo* Databases::getKeyword( const OUString& Database,
723 const OUString& Language )
724{
725 std::unique_lock aGuard( m_aMutex );
726
727 OUString key = processLang(aGuard, Language) + "/" + Database;
728
729 std::pair< KeywordInfoTable::iterator,bool > aPair =
730 m_aKeywordInfo.emplace( key,nullptr );
731
732 KeywordInfoTable::iterator it = aPair.first;
733
734 if( aPair.second && ! it->second )
735 {
736 std::vector<KeywordInfo::KeywordElement> aVector;
737
738 KeyDataBaseFileIterator aDbFileIt( m_xContext, *this, Database, Language );
739 OUString fileURL;
740 bool bExtension = false;
741 for (;;)
742 {
743 fileURL = aDbFileIt.nextDbFile(aGuard, bExtension);
744 if( fileURL.isEmpty() )
745 break;
746 OUString fileNameHDFHelp( fileURL );
747 if( bExtension )
748 fileNameHDFHelp += "_";
749 if( m_xSFA->exists( fileNameHDFHelp ) )
750 {
751 helpdatafileproxy::Hdf aHdf( fileNameHDFHelp, m_xSFA );
754 if( aHdf.startIteration() )
755 {
756 helpdatafileproxy::Hdf* pHdf = getHelpDataFile(aGuard, Database,Language );
757 if( pHdf != nullptr )
758 {
759 pHdf->releaseHashMap();
760 pHdf->createHashMap( true/*bOptimizeForPerformance*/ );
761 }
762
763 while( aHdf.getNextKeyAndValue( aKey, aValue ) )
764 {
765 OUString keyword( aKey.getData(), aKey.getSize(),
766 RTL_TEXTENCODING_UTF8 );
767 OUString doclist( aValue.getData(), aValue.getSize(),
768 RTL_TEXTENCODING_UTF8 );
769
770 bool bBelongsToDatabase = true;
771 if( bExtension )
772 bBelongsToDatabase = checkModuleMatchForExtension( Database, doclist );
773
774 if( !bBelongsToDatabase )
775 continue;
776
777 aVector.emplace_back( this,
778 pHdf,
779 keyword,
780 doclist );
781 }
782 aHdf.stopIteration();
783
784 if( pHdf != nullptr )
785 pHdf->releaseHashMap();
786 }
787 }
788 }
789
790 // sorting
791 Reference<XCollator> xCollator = getCollator(aGuard, Language);
792 KeywordElementComparator aComparator( xCollator );
793 std::sort(aVector.begin(),aVector.end(),aComparator);
794
795 it->second.reset(new KeywordInfo( aVector ));
796 }
797
798 return it->second.get();
799}
800
802 std::unique_lock<std::mutex>& rGuard, std::u16string_view jar,
803 const OUString& Language )
804{
805 if( jar.empty() || Language.isEmpty() )
806 {
807 return Reference< XHierarchicalNameAccess >( nullptr );
808 }
809
810 OUString key = processLang(rGuard, Language) + "/" + jar;
811
812 ZipFileTable::iterator it =
813 m_aZipFileTable.emplace( key,Reference< XHierarchicalNameAccess >(nullptr) ).first;
814
815 if( ! it->second.is() )
816 {
817 try
818 {
819 OUString zipFile;
820 // Extension jar file? Search for ?
821 size_t nQuestionMark1 = jar.find( '?' );
822 size_t nQuestionMark2 = jar.rfind( '?' );
823 if( nQuestionMark1 != std::u16string_view::npos && nQuestionMark2 != std::u16string_view::npos && nQuestionMark1 != nQuestionMark2 )
824 {
825 std::u16string_view aExtensionPath = jar.substr( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
826 std::u16string_view aPureJar = jar.substr( nQuestionMark2 + 1 );
827
828 zipFile = expandURL(rGuard, OUString::Concat(aExtensionPath) + "/" + aPureJar);
829 }
830 else
831 {
832 zipFile = m_aInstallDirectory + key;
833 }
834
836 auto pArguments = aArguments.getArray();
837
839 if( p->CtorSuccess() )
840 {
841 pArguments[ 0 ] <<= Reference< XInputStream >( p );
842 }
843 else
844 {
845 p.clear();
846 pArguments[ 0 ] <<= zipFile;
847 }
848
849 // let ZipPackage be used ( no manifest.xml is required )
850 beans::NamedValue aArg;
851 aArg.Name = "StorageFormat";
852 aArg.Value <<= OUString(ZIP_STORAGE_FORMAT_STRING);
853 pArguments[ 1 ] <<= aArg;
854
856 = m_xSMgr->createInstanceWithArgumentsAndContext(
857 "com.sun.star.packages.comp.ZipPackage",
859
860 if ( xIfc.is() )
861 {
862 it->second.set( xIfc, UNO_QUERY );
863
864 OSL_ENSURE( it->second.is(),
865 "ContentProvider::createPackage - "
866 "Got no hierarchical name access!" );
867
868 }
869 }
870 catch ( RuntimeException & )
871 {
872 }
873 catch ( Exception & )
874 {
875 }
876 }
877
878 return it->second;
879}
880
882 ( const OUString& jar, const OUString& Language,
883 const OUString& path, OUString* o_pExtensionPath,
884 OUString* o_pExtensionRegistryPath )
885{
887 if( jar.isEmpty() || Language.isEmpty() )
888 {
889 return xNA;
890 }
891
892 ::std::unique_lock aGuard(m_aMutex);
893
894 JarFileIterator aJarFileIt( m_xContext, *this, jar, Language );
896 Reference< deployment::XPackage > xParentPackageBundle;
897 for (;;)
898 {
899 xTestNA = aJarFileIt.nextJarFile(aGuard, xParentPackageBundle, o_pExtensionPath, o_pExtensionRegistryPath);
900 if( !xTestNA.is() )
901 break;
902 if( xTestNA.is() && xTestNA->hasByHierarchicalName( path ) )
903 {
904 bool bSuccess = true;
905 if( xParentPackageBundle.is() )
906 {
907 OUString aIdentifierInPath;
908 sal_Int32 nFindSlash = path.indexOf( '/' );
909 if( nFindSlash != -1 )
910 aIdentifierInPath = path.copy( 0, nFindSlash );
911
912 beans::Optional<OUString> aIdentifierOptional = xParentPackageBundle->getIdentifier();
913 if( !aIdentifierInPath.isEmpty() && aIdentifierOptional.IsPresent )
914 {
915 OUString aUnencodedIdentifier = aIdentifierOptional.Value;
916 OUString aIdentifier = rtl::Uri::encode( aUnencodedIdentifier,
917 rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8 );
918
919 if( aIdentifierInPath != aIdentifier )
920 {
921 // path does not start with extension identifier -> ignore
922 bSuccess = false;
923 }
924 }
925 else
926 {
927 // No identifier -> ignore
928 bSuccess = false;
929 }
930 }
931
932 if( bSuccess )
933 {
934 xNA = xTestNA;
935 break;
936 }
937 }
938 }
939
940 return xNA;
941}
942
943void Databases::changeCSS(const OUString& newStyleSheet)
944{
945 m_aCSS = newStyleSheet.toAsciiLowerCase();
946 m_vCustomCSSDoc.clear();
947}
948
949void Databases::cascadingStylesheet( const OUString& Language,
950 OStringBuffer& buffer )
951{
952 if( m_vCustomCSSDoc.empty() )
953 {
954 int retry = 2;
955 bool error = true;
956 OUString fileURL;
957
958 bool bHighContrastMode = false;
959 OUString aCSS( m_aCSS );
960 if ( aCSS == "default" )
961 {
962 // #i50760: "default" needs to adapt HC mode
963 uno::Reference< awt::XToolkit2 > xToolkit =
964 awt::Toolkit::create( ::comphelper::getProcessComponentContext() );
965 uno::Reference< awt::XTopWindow > xTopWindow = xToolkit->getActiveTopWindow();
966 if ( xTopWindow.is() )
967 {
968 uno::Reference< awt::XVclWindowPeer > xVclWindowPeer( xTopWindow, uno::UNO_QUERY );
969 if ( xVclWindowPeer.is() )
970 {
971 uno::Any aHCMode = xVclWindowPeer->getProperty( "HighContrastMode" );
972 if ( ( aHCMode >>= bHighContrastMode ) && bHighContrastMode )
973 {
974 aCSS = "highcontrastblack";
975 #ifdef _WIN32
976 HKEY hKey = nullptr;
977 LONG lResult = RegOpenKeyExW( HKEY_CURRENT_USER, L"Control Panel\\Accessibility\\HighContrast", 0, KEY_QUERY_VALUE, &hKey );
978 if ( ERROR_SUCCESS == lResult )
979 {
980 WCHAR szBuffer[1024];
981 DWORD nSize = sizeof( szBuffer );
982 lResult = RegQueryValueExW( hKey, L"High Contrast Scheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(szBuffer), &nSize );
983 if ( ERROR_SUCCESS == lResult && nSize > 0 )
984 {
985 szBuffer[nSize] = '\0';
986 if ( wcscmp( szBuffer, L"High Contrast #1" ) == 0 )
987 aCSS = "highcontrast1";
988 if ( wcscmp( szBuffer, L"High Contrast #2" ) == 0 )
989 aCSS = "highcontrast2";
990 if ( wcscmp( szBuffer, L"High Contrast White" ) == 0 )
991 aCSS = "highcontrastwhite";
992 }
993 RegCloseKey( hKey );
994 }
995 #endif
996 }
997 }
998 }
999 }
1000
1001 while( error && retry )
1002 {
1003
1004 if( retry == 2 )
1005 fileURL =
1007 processLang( Language ) +
1008 "/" +
1009 aCSS +
1010 ".css";
1011 else if( retry == 1 )
1012 fileURL =
1014 aCSS +
1015 ".css";
1016
1017 osl::DirectoryItem aDirItem;
1018 osl::File aFile( fileURL );
1019 osl::FileStatus aStatus( osl_FileStatus_Mask_FileSize );
1020
1021 if( osl::FileBase::E_None == osl::DirectoryItem::get( fileURL,aDirItem ) &&
1022 osl::FileBase::E_None == aFile.open( osl_File_OpenFlag_Read ) &&
1023 osl::FileBase::E_None == aDirItem.getFileStatus( aStatus ) )
1024 {
1025 sal_uInt64 nSize;
1026 aFile.getSize( nSize );
1027 m_vCustomCSSDoc.resize( nSize + 1);
1028 m_vCustomCSSDoc[nSize] = 0;
1029 sal_uInt64 a = nSize,b = nSize;
1030 aFile.read( m_vCustomCSSDoc.data(), a, b );
1031 aFile.close();
1032 error = false;
1033 }
1034
1035 --retry;
1036 if ( !retry && error && bHighContrastMode )
1037 {
1038 // fall back to default css
1039 aCSS = "default";
1040 retry = 2;
1041 bHighContrastMode = false;
1042 }
1043 }
1044
1045 if( error )
1046 {
1047 m_vCustomCSSDoc.clear();
1048 }
1049 }
1050
1051 if (!m_vCustomCSSDoc.empty())
1052 buffer.append( m_vCustomCSSDoc.data(), m_vCustomCSSDoc.size() - 1 );
1053}
1054
1055void Databases::setActiveText( const OUString& Module,
1056 const OUString& Language,
1057 std::u16string_view Id,
1058 OStringBuffer& buffer )
1059{
1060 DataBaseIterator aDbIt( m_xContext, *this, Module, Language, true );
1061
1062 // #i84550 Cache information about failed ids
1063 OString id = OUStringToOString( Id, RTL_TEXTENCODING_UTF8 );
1064 EmptyActiveTextSet::iterator it = m_aEmptyActiveTextSet.find( id );
1065 bool bFoundAsEmpty = ( it != m_aEmptyActiveTextSet.end() );
1067
1068 int nSize = 0;
1069 const char* pData = nullptr;
1070
1071 bool bSuccess = false;
1072 if( !bFoundAsEmpty )
1073 {
1074 while( !bSuccess )
1075 {
1076 helpdatafileproxy::Hdf* pHdf = aDbIt.nextHdf();
1077 if( !pHdf )
1078 break;
1079 bSuccess = pHdf->getValueForKey( id, aHDFData );
1080 nSize = aHDFData.getSize();
1081 pData = aHDFData.getData();
1082 }
1083 }
1084
1085 if( bSuccess )
1086 {
1087 // ensure existence of tmp after for
1088 OString tmp;
1089 for( int i = 0; i < nSize; ++i )
1090 if( pData[i] == '%' || pData[i] == '$' )
1091 {
1092 // need of replacement
1093 OUString temp( pData, nSize, RTL_TEXTENCODING_UTF8 );
1094 replaceName( temp );
1095 tmp = OString( temp.getStr(),
1096 temp.getLength(),
1097 RTL_TEXTENCODING_UTF8 );
1098 nSize = tmp.getLength();
1099 pData = tmp.getStr();
1100 break;
1101 }
1102
1103 buffer.append( pData, nSize );
1104 }
1105 else
1106 {
1107 if( !bFoundAsEmpty )
1108 m_aEmptyActiveTextSet.insert( id );
1109 }
1110}
1111
1112void Databases::setInstallPath( const OUString& aInstDir )
1113{
1114 std::unique_lock aGuard( m_aMutex );
1115
1116 osl::FileBase::getFileURLFromSystemPath( aInstDir,m_aInstallDirectory );
1117 //TODO: check returned error code
1118
1119 if( !m_aInstallDirectory.endsWith( "/" ) )
1120 m_aInstallDirectory += "/";
1121}
1122
1123
1125
1127 Databases& rDatabases, OUString aInitialModule, OUString aLanguage )
1128 : m_xContext( xContext )
1129 , m_rDatabases( rDatabases )
1130 , m_eState( IteratorState::InitialModule )
1131 , m_aInitialModule(std::move( aInitialModule ))
1132 , m_aLanguage(std::move( aLanguage ))
1133{
1134 assert( m_xContext.is() );
1135 init();
1136}
1137
1139 OUString aInitialModule, OUString aLanguage )
1141 , m_rDatabases( rDatabases )
1142 , m_eState( IteratorState::InitialModule )
1143 , m_aInitialModule(std::move( aInitialModule ))
1144 , m_aLanguage(std::move( aLanguage ))
1145{
1146 init();
1147}
1148
1150{
1151 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
1152
1153 m_bUserPackagesLoaded = false;
1156 m_iUserPackage = 0;
1157 m_iSharedPackage = 0;
1159}
1160
1162 ( const Reference< deployment::XPackage >& xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
1163{
1164 o_xParentPackageBundle.clear();
1165
1167 if( !xPackage.is() )
1168 return xHelpPackage;
1169
1170 // #i84550 Cache information about help content in extension
1171 OUString aExtensionPath = xPackage->getURL();
1172 ExtensionHelpExistenceMap::iterator it = aHelpExistenceMap.find( aExtensionPath );
1173 bool bFound = ( it != aHelpExistenceMap.end() );
1174 bool bHasHelp = bFound && it->second;
1175 if( bFound && !bHasHelp )
1176 return xHelpPackage;
1177
1178 // Check if parent package is registered
1179 beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
1181 bool bRegistered = false;
1182 if( option.IsPresent )
1183 {
1184 beans::Ambiguous<sal_Bool> const & reg = option.Value;
1185 if( !reg.IsAmbiguous && reg.Value )
1186 bRegistered = true;
1187 }
1188 if( bRegistered )
1189 {
1190 OUString aHelpMediaType( "application/vnd.sun.star.help" );
1191 if( xPackage->isBundle() )
1192 {
1193 const Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
1195 auto pSubPkg = std::find_if(aPkgSeq.begin(), aPkgSeq.end(),
1197 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
1198 OUString aMediaType = xPackageTypeInfo->getMediaType();
1199 return aMediaType == aHelpMediaType;
1200 });
1201 if (pSubPkg != aPkgSeq.end())
1202 {
1203 xHelpPackage = *pSubPkg;
1204 o_xParentPackageBundle = xPackage;
1205 }
1206 }
1207 else
1208 {
1209 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
1210 OUString aMediaType = xPackageTypeInfo->getMediaType();
1211 if( aMediaType == aHelpMediaType )
1212 xHelpPackage = xPackage;
1213 }
1214 }
1215
1216 if( !bFound )
1217 aHelpExistenceMap[ aExtensionPath ] = xHelpPackage.is();
1218
1219 return xHelpPackage;
1220}
1221
1223 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1224{
1226
1228 {
1229 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1230 m_aUserPackagesSeq = xExtensionManager->getDeployedExtensions
1232 m_bUserPackagesLoaded = true;
1233 }
1234
1235 if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
1236 {
1237 m_eState = IteratorState::SharedExtensions; // Later: SHARED_MODULE
1238 }
1239 else
1240 {
1241 const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
1242 Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage++ ];
1243 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextUserHelpPackage(): Invalid package" );
1244 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1245 }
1246
1247 return xHelpPackage;
1248}
1249
1251 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1252{
1254
1256 {
1257 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1258 m_aSharedPackagesSeq = xExtensionManager->getDeployedExtensions
1261 }
1262
1263 if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
1264 {
1266 }
1267 else
1268 {
1269 const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
1270 Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage++ ];
1271 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextSharedHelpPackage(): Invalid package" );
1272 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1273 }
1274
1275 return xHelpPackage;
1276}
1277
1279 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1280{
1282
1284 {
1285 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1286 m_aBundledPackagesSeq = xExtensionManager->getDeployedExtensions
1289 }
1290
1291 if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
1292 {
1294 }
1295 else
1296 {
1297 const Reference< deployment::XPackage >* pBundledPackages =
1298 m_aBundledPackagesSeq.getConstArray();
1299 Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage++ ];
1300 OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextBundledHelpPackage(): Invalid package" );
1301 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1302 }
1303
1304 return xHelpPackage;
1305}
1306
1308 std::unique_lock<std::mutex> & rGuard,
1309 std::u16string_view rFileExtension, const Reference< deployment::XPackage >& xPackage )
1310{
1311 // No extension -> search for pure language folder
1312 bool bLangFolderOnly = rFileExtension.empty();
1313
1314 OUString aFile;
1315 OUString aLanguage = m_aLanguage;
1316 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1317 {
1318 OUString aStr = xPackage->getRegistrationDataURL().Value + "/" + aLanguage;
1319 if( !bLangFolderOnly )
1320 {
1321 aStr += OUString::Concat("/help") + rFileExtension;
1322 }
1323
1324 aFile = m_rDatabases.expandURL(rGuard, aStr);
1325 if( iPass == 0 )
1326 {
1327 if( m_xSFA->exists( aFile ) )
1328 break;
1329
1330 ::std::vector< OUString > av;
1331 implGetLanguageVectorFromPackage( av, xPackage );
1332 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1333 if( pFound != av.end() )
1334 aLanguage = *pFound;
1335 }
1336 }
1337 return aFile;
1338}
1339
1340
1342 std::u16string_view rFileExtension, const Reference< deployment::XPackage >& xPackage )
1343{
1344 // No extension -> search for pure language folder
1345 bool bLangFolderOnly = rFileExtension.empty();
1346
1347 OUString aFile;
1348 OUString aLanguage = m_aLanguage;
1349 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1350 {
1351 OUString aStr = xPackage->getRegistrationDataURL().Value + "/" + aLanguage;
1352 if( !bLangFolderOnly )
1353 {
1354 aStr += OUString::Concat("/help") + rFileExtension;
1355 }
1356
1357 aFile = m_rDatabases.expandURL( aStr );
1358 if( iPass == 0 )
1359 {
1360 if( m_xSFA->exists( aFile ) )
1361 break;
1362
1363 ::std::vector< OUString > av;
1364 implGetLanguageVectorFromPackage( av, xPackage );
1365 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1366 if( pFound != av.end() )
1367 aLanguage = *pFound;
1368 }
1369 }
1370 return aFile;
1371}
1372
1373static bool isLetter( sal_Unicode c )
1374{
1375 return rtl::isAsciiAlpha(c);
1376}
1377
1379 const css::uno::Reference< css::deployment::XPackage >& xPackage )
1380{
1381 rv.clear();
1382 OUString aExtensionPath = xPackage->getURL();
1383 const Sequence< OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1384
1385 for( const OUString& aEntry : aEntrySeq )
1386 {
1387 if( m_xSFA->isFolder( aEntry ) )
1388 {
1389 sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1390 if( nLastSlash != -1 )
1391 {
1392 OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1393
1394 // Check language scheme
1395 int nLen = aPureEntry.getLength();
1396 const sal_Unicode* pc = aPureEntry.getStr();
1397 bool bStartCanBeLanguage = ( nLen >= 2 && isLetter( pc[0] ) && isLetter( pc[1] ) );
1398 bool bIsLanguage = bStartCanBeLanguage &&
1399 ( nLen == 2 || (nLen == 5 && pc[2] == '-' && isLetter( pc[3] ) && isLetter( pc[4] )) );
1400 if( bIsLanguage )
1401 rv.push_back( aPureEntry );
1402 }
1403 }
1404 }
1405}
1406
1407
1408helpdatafileproxy::Hdf* DataBaseIterator::nextHdf( OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1409{
1410 helpdatafileproxy::Hdf* pRetHdf = nullptr;
1411
1412 while( !pRetHdf && m_eState != IteratorState::EndReached )
1413 {
1414 switch( m_eState )
1415 {
1418 m_eState = IteratorState::UserExtensions; // Later: SHARED_MODULE
1419 break;
1420
1421 // Later:
1422 //case SHARED_MODULE
1423
1424
1426 {
1427 Reference< deployment::XPackage > xParentPackageBundle;
1428 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1429 if( !xHelpPackage.is() )
1430 break;
1431 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1432 break;
1433 }
1434
1436 {
1437 Reference< deployment::XPackage > xParentPackageBundle;
1438 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1439 if( !xHelpPackage.is() )
1440 break;
1441
1442 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1443 break;
1444 }
1445
1447 {
1448 Reference< deployment::XPackage > xParentPackageBundle;
1449 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1450 if( !xHelpPackage.is() )
1451 break;
1452
1453 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1454 break;
1455 }
1456
1458 OSL_FAIL( "DataBaseIterator::nextDb(): Invalid case IteratorState::EndReached" );
1459 break;
1460 }
1461 }
1462
1463 return pRetHdf;
1464}
1465
1467 OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1468{
1469
1470 beans::Optional< OUString> optRegData;
1471 try
1472 {
1473 optRegData = xPackage->getRegistrationDataURL();
1474 }
1475 catch ( deployment::ExtensionRemovedException&)
1476 {
1477 return nullptr;
1478 }
1479
1480 helpdatafileproxy::Hdf* pRetHdf = nullptr;
1481 if (optRegData.IsPresent && !optRegData.Value.isEmpty())
1482 {
1483 OUString aRegDataUrl = optRegData.Value + "/";
1484
1485 OUString aHelpFilesBaseName("help");
1486
1487 OUString aUsedLanguage = m_aLanguage;
1488 pRetHdf = m_rDatabases.getHelpDataFile(
1489 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1490
1491 // Language fallback
1492 if( !pRetHdf )
1493 {
1494 ::std::vector< OUString > av;
1495 implGetLanguageVectorFromPackage( av, xPackage );
1496 ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1497 if( pFound != av.end() )
1498 {
1499 aUsedLanguage = *pFound;
1500 pRetHdf = m_rDatabases.getHelpDataFile(
1501 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1502 }
1503 }
1504
1505 if( o_pExtensionPath )
1506 *o_pExtensionPath = aRegDataUrl + aUsedLanguage;
1507
1508 if( o_pExtensionRegistryPath )
1509 *o_pExtensionRegistryPath = xPackage->getURL() + "/" + aUsedLanguage;
1510 }
1511
1512 return pRetHdf;
1513}
1514
1515
1516//returns a file URL
1517OUString KeyDataBaseFileIterator::nextDbFile(std::unique_lock<std::mutex>& rGuard, bool& o_rbExtension)
1518{
1519 OUString aRetFile;
1520
1521 while( aRetFile.isEmpty() && m_eState != IteratorState::EndReached )
1522 {
1523 switch( m_eState )
1524 {
1526 aRetFile = m_rDatabases.getInstallPathAsURL(rGuard) +
1528 "/" +
1529 m_aInitialModule + ".key";
1530
1531 o_rbExtension = false;
1532
1533 m_eState = IteratorState::UserExtensions; // Later: SHARED_MODULE
1534 break;
1535
1536 // Later:
1537 //case SHARED_MODULE
1538
1539
1541 {
1542 Reference< deployment::XPackage > xParentPackageBundle;
1543 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1544 if( !xHelpPackage.is() )
1545 break;
1546
1547 aRetFile = implGetDbFileFromPackage(rGuard, xHelpPackage);
1548 o_rbExtension = true;
1549 break;
1550 }
1551
1553 {
1554 Reference< deployment::XPackage > xParentPackageBundle;
1555 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1556 if( !xHelpPackage.is() )
1557 break;
1558
1559 aRetFile = implGetDbFileFromPackage(rGuard, xHelpPackage);
1560 o_rbExtension = true;
1561 break;
1562 }
1563
1565 {
1566 Reference< deployment::XPackage > xParentPackageBundle;
1567 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1568 if( !xHelpPackage.is() )
1569 break;
1570
1571 aRetFile = implGetDbFileFromPackage(rGuard, xHelpPackage);
1572 o_rbExtension = true;
1573 break;
1574 }
1575
1577 OSL_FAIL( "DataBaseIterator::nextDbFile(): Invalid case IteratorState::EndReached" );
1578 break;
1579 }
1580 }
1581
1582 return aRetFile;
1583}
1584
1585//Returns a file URL, that does not contain macros
1587 std::unique_lock<std::mutex>& rGuard,
1588 const Reference<deployment::XPackage>& xPackage)
1589{
1590 OUString aExpandedURL =
1591 implGetFileFromPackage(rGuard, u".key", xPackage);
1592
1593 return aExpandedURL;
1594}
1595
1596
1598 std::unique_lock<std::mutex>& rGuard,
1599 Reference< deployment::XPackage >& o_xParentPackageBundle,
1600 OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath )
1601{
1603
1604 while( !xNA.is() && m_eState != IteratorState::EndReached )
1605 {
1606 switch( m_eState )
1607 {
1610 m_eState = IteratorState::UserExtensions; // Later: SHARED_MODULE
1611 break;
1612
1613 // Later:
1614 //case SHARED_MODULE
1615
1616
1618 {
1619 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( o_xParentPackageBundle );
1620 if( !xHelpPackage.is() )
1621 break;
1622
1623 xNA = implGetJarFromPackage(rGuard, xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath);
1624 break;
1625 }
1626
1628 {
1629 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( o_xParentPackageBundle );
1630 if( !xHelpPackage.is() )
1631 break;
1632
1633 xNA = implGetJarFromPackage(rGuard, xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath);
1634 break;
1635 }
1636
1638 {
1639 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( o_xParentPackageBundle );
1640 if( !xHelpPackage.is() )
1641 break;
1642
1643 xNA = implGetJarFromPackage(rGuard, xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath);
1644 break;
1645 }
1646
1648 OSL_FAIL( "JarFileIterator::nextJarFile(): Invalid case IteratorState::EndReached" );
1649 break;
1650 }
1651 }
1652
1653 return xNA;
1654}
1655
1657 std::unique_lock<std::mutex>& rGuard,
1658 const Reference<deployment::XPackage>& xPackage, OUString* o_pExtensionPath, OUString* o_pExtensionRegistryPath)
1659{
1661
1662 OUString zipFile =
1663 implGetFileFromPackage(rGuard, u".jar", xPackage);
1664
1665 try
1666 {
1668 Any(zipFile),
1669 // let ZipPackage be used ( no manifest.xml is required )
1670 Any(comphelper::makePropertyValue("StorageFormat",
1671 OUString(ZIP_STORAGE_FORMAT_STRING)))
1672 };
1673
1676 = xSMgr->createInstanceWithArgumentsAndContext(
1677 "com.sun.star.packages.comp.ZipPackage",
1679
1680 if ( xIfc.is() )
1681 {
1682 xNA.set( xIfc, UNO_QUERY );
1683
1684 OSL_ENSURE( xNA.is(),
1685 "JarFileIterator::implGetJarFromPackage() - "
1686 "Got no hierarchical name access!" );
1687 }
1688 }
1689 catch ( RuntimeException & )
1690 {}
1691 catch ( Exception & )
1692 {}
1693
1694 if( xNA.is() && o_pExtensionPath != nullptr )
1695 {
1696 // Extract path including language from file name
1697 sal_Int32 nLastSlash = zipFile.lastIndexOf( '/' );
1698 if( nLastSlash != -1 )
1699 *o_pExtensionPath = zipFile.copy( 0, nLastSlash );
1700
1701 if( o_pExtensionRegistryPath != nullptr )
1702 {
1703 OUString& rPath = *o_pExtensionPath;
1704 sal_Int32 nLastSlashInPath = rPath.lastIndexOf( '/', rPath.getLength() - 1 );
1705
1706 *o_pExtensionRegistryPath = xPackage->getURL();
1707 *o_pExtensionRegistryPath += rPath.subView( nLastSlashInPath);
1708 }
1709 }
1710
1711 return xNA;
1712}
1713
1714
1715OUString IndexFolderIterator::nextIndexFolder( bool& o_rbExtension, bool& o_rbTemporary )
1716{
1717 OUString aIndexFolder;
1718
1719 while( aIndexFolder.isEmpty() && m_eState != IteratorState::EndReached )
1720 {
1721 switch( m_eState )
1722 {
1724 aIndexFolder = m_rDatabases.getInstallPathAsURL()
1726 + m_aInitialModule + ".idxl";
1727
1728 o_rbTemporary = false;
1729 o_rbExtension = false;
1730
1731 m_eState = IteratorState::UserExtensions; // Later: SHARED_MODULE
1732 break;
1733
1734 // Later:
1735 //case SHARED_MODULE
1736
1737
1739 {
1740 Reference< deployment::XPackage > xParentPackageBundle;
1741 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1742 if( !xHelpPackage.is() )
1743 break;
1744
1745 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1746 o_rbExtension = true;
1747 break;
1748 }
1749
1751 {
1752 Reference< deployment::XPackage > xParentPackageBundle;
1753 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1754 if( !xHelpPackage.is() )
1755 break;
1756
1757 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1758 o_rbExtension = true;
1759 break;
1760 }
1761
1763 {
1764 Reference< deployment::XPackage > xParentPackageBundle;
1765 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1766 if( !xHelpPackage.is() )
1767 break;
1768
1769 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1770 o_rbExtension = true;
1771 break;
1772 }
1773
1775 OSL_FAIL( "IndexFolderIterator::nextIndexFolder(): Invalid case IteratorState::EndReached" );
1776 break;
1777 }
1778 }
1779
1780 return aIndexFolder;
1781}
1782
1784{
1785 OUString aIndexFolder =
1786 implGetFileFromPackage( u".idxl", xPackage );
1787
1788 o_rbTemporary = false;
1789 if( !m_xSFA->isFolder( aIndexFolder ) )
1790 {
1791 // i98680: Missing index? Try to generate now
1792 OUString aLangURL = implGetFileFromPackage( std::u16string_view(), xPackage );
1793 if( m_xSFA->isFolder( aLangURL ) )
1794 {
1795 // Test write access (shared extension may be read only)
1796 bool bIsWriteAccess = false;
1797 try
1798 {
1799 OUString aCreateTestFolder = aLangURL + "CreateTestFolder";
1800 m_xSFA->createFolder( aCreateTestFolder );
1801 if( m_xSFA->isFolder( aCreateTestFolder ) )
1802 bIsWriteAccess = true;
1803
1804 m_xSFA->kill( aCreateTestFolder );
1805 }
1806 catch (const Exception &)
1807 {
1808 }
1809
1810 // TEST
1811 //bIsWriteAccess = false;
1812
1813 try
1814 {
1815 OUString aLang;
1816 sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
1817 if( nLastSlash != -1 )
1818 aLang = aLangURL.copy( nLastSlash + 1 );
1819 else
1820 aLang = "en";
1821
1822 OUString aZipDir = aLangURL;
1823 if( !bIsWriteAccess )
1824 {
1825 OUString aTempFileURL;
1826 ::osl::FileBase::RC eErr = ::osl::File::createTempFile( nullptr, nullptr, &aTempFileURL );
1827 if( eErr == ::osl::FileBase::E_None )
1828 {
1829 try
1830 {
1831 m_xSFA->kill( aTempFileURL );
1832 }
1833 catch (const Exception &)
1834 {
1835 }
1836 m_xSFA->createFolder( aTempFileURL );
1837
1838 aZipDir = aTempFileURL;
1839 o_rbTemporary = true;
1840 }
1841 }
1842
1843 HelpIndexer aIndexer(aLang, "help", aLangURL, aZipDir);
1844 aIndexer.indexDocuments();
1845
1846 if( bIsWriteAccess )
1847 aIndexFolder = implGetFileFromPackage( u".idxl", xPackage );
1848 else
1849 aIndexFolder = aZipDir + "/help.idxl";
1850 }
1851 catch (const Exception &)
1852 {
1853 }
1854 }
1855 }
1856
1857 return aIndexFolder;
1858}
1859
1860void IndexFolderIterator::deleteTempIndexFolder( std::u16string_view aIndexFolder )
1861{
1862 size_t nLastSlash = aIndexFolder.rfind( '/' );
1863 if( nLastSlash != std::u16string_view::npos )
1864 {
1865 OUString aTmpFolder( aIndexFolder.substr( 0, nLastSlash ) );
1866 try
1867 {
1868 m_xSFA->kill( aTmpFolder );
1869 }
1870 catch (const Exception &)
1871 {
1872 }
1873 }
1874}
1875
1876/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xContext
FILE * init(int, char **)
bool indexDocuments()
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
OUString getLanguage() const
OUString getCountry() const
::std::vector< OUString >::const_iterator getFallback(const ::std::vector< OUString > &rList, const OUString &rReference)
LanguageTag & reset(const OUString &rBcp47LanguageTag)
helpdatafileproxy::Hdf * nextHdf(OUString *o_pExtensionPath=nullptr, OUString *o_pExtensionRegistryPath=nullptr)
Definition: databases.cxx:1408
helpdatafileproxy::Hdf * implGetHdfFromPackage(const css::uno::Reference< css::deployment::XPackage > &xPackage, OUString *o_pExtensionPath, OUString *o_pExtensionRegistryPath)
Definition: databases.cxx:1466
css::uno::Reference< css::container::XHierarchicalNameAccess > findJarFileForPath(const OUString &jar, const OUString &Language, const OUString &path, OUString *o_pExtensionPath=nullptr, OUString *o_pExtensionRegistryPath=nullptr)
Definition: databases.cxx:882
KeywordInfo * getKeyword(const OUString &Module, const OUString &Language)
Definition: databases.cxx:722
OString getImageTheme() const
Definition: databases.cxx:179
void cascadingStylesheet(const OUString &Language, OStringBuffer &buffer)
Returns the cascading style sheet used to format the HTML-output.
Definition: databases.cxx:949
OUString m_aInstallDirectory
Definition: databases.hxx:253
std::mutex m_aMutex
Definition: databases.hxx:230
KeywordInfoTable m_aKeywordInfo
Definition: databases.hxx:267
helpdatafileproxy::Hdf * getHelpDataFile(std::u16string_view Module, const OUString &Language, bool helpText=false, const OUString *pExtensionPath=nullptr)
Definition: databases.cxx:438
OUString getInstallPathAsURL()
Definition: databases.cxx:273
ZipFileTable m_aZipFileTable
Definition: databases.hxx:273
std::vector< char > m_vCustomCSSDoc
Definition: databases.hxx:237
StaticModuleInformation * getStaticInformationForModule(std::u16string_view Module, const OUString &Language)
Definition: databases.cxx:323
css::uno::Reference< css::i18n::XCollator > getCollator(std::unique_lock< std::mutex > &rGuard, const OUString &Language)
The following method returns the Collator for the given language-country combination.
Definition: databases.cxx:497
OUString m_vReplacement[7]
Definition: databases.hxx:251
css::uno::Reference< css::lang::XMultiComponentFactory > m_xSMgr
Definition: databases.hxx:232
std::vector< OUString > m_avModules
Definition: databases.hxx:255
void changeCSS(const OUString &newStyleSheet)
Changes the stylesheet for further reads.
Definition: databases.cxx:943
const std::vector< OUString > & getModuleList(const OUString &Language)
Definition: databases.cxx:285
css::uno::Reference< css::container::XHierarchicalNameAccess > jarFile(std::unique_lock< std::mutex > &rGuard, std::u16string_view jar, const OUString &Language)
Has the purpose of forcing the jarfile to stay open.
Definition: databases.cxx:801
void replaceName(OUString &oustring) const
Definition: databases.cxx:207
Databases(bool showBasic, const OUString &instPath, const OUString &productName, const OUString &productVersion, const OUString &styleSheet, css::uno::Reference< css::uno::XComponentContext > const &xContext)
Input is the installdirectory in system dependent notation.
Definition: databases.cxx:134
DatabasesTable m_aDatabases
Definition: databases.hxx:258
LangSetTable m_aLangSet
Definition: databases.hxx:261
css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSFA
Definition: databases.hxx:233
CollatorTable m_aCollatorTable
Definition: databases.hxx:279
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: databases.hxx:231
void setActiveText(const OUString &Module, const OUString &Language, std::u16string_view Id, OStringBuffer &buffer)
Returns the active help text for the given module, language and id.
Definition: databases.cxx:1055
void setInstallPath(const OUString &aInstallDirectory)
Definition: databases.cxx:1112
OUString expandURL(const OUString &aURL)
Definition: databases.cxx:82
EmptyActiveTextSet m_aEmptyActiveTextSet
Definition: databases.hxx:285
ModInfoTable m_aModInfo
Definition: databases.hxx:264
bool checkModuleMatchForExtension(std::u16string_view Database, const OUString &doclist)
Definition: databases.cxx:675
OUString processLang(const OUString &Language)
Maps a given language-locale combination to language or locale.
Definition: databases.cxx:400
css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > m_aUserPackagesSeq
Definition: databases.hxx:352
css::uno::Reference< css::deployment::XPackage > implGetNextUserHelpPackage(css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle)
Definition: databases.cxx:1223
css::uno::Reference< css::deployment::XPackage > implGetNextSharedHelpPackage(css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle)
Definition: databases.cxx:1251
css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSFA
Definition: databases.hxx:343
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: databases.hxx:342
static css::uno::Reference< css::deployment::XPackage > implGetHelpPackageFromPackage(const css::uno::Reference< css::deployment::XPackage > &xPackage, css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle)
Definition: databases.cxx:1162
css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > m_aBundledPackagesSeq
Definition: databases.hxx:360
OUString implGetFileFromPackage(std::u16string_view rFileExtension, const css::uno::Reference< css::deployment::XPackage > &xPackage)
css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > m_aSharedPackagesSeq
Definition: databases.hxx:356
ExtensionIteratorBase(css::uno::Reference< css::uno::XComponentContext > const &xContext, Databases &rDatabases, OUString aInitialModule, OUString aLanguage)
void implGetLanguageVectorFromPackage(::std::vector< OUString > &rv, const css::uno::Reference< css::deployment::XPackage > &xPackage)
Definition: databases.cxx:1378
css::uno::Reference< css::deployment::XPackage > implGetNextBundledHelpPackage(css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle)
Definition: databases.cxx:1279
static ExtensionHelpExistenceMap aHelpExistenceMap
Definition: databases.hxx:313
void deleteTempIndexFolder(std::u16string_view aIndexFolder)
Definition: databases.cxx:1860
OUString nextIndexFolder(bool &o_rbExtension, bool &o_rbTemporary)
Definition: databases.cxx:1715
OUString implGetIndexFolderFromPackage(bool &o_rbTemporary, const css::uno::Reference< css::deployment::XPackage > &xPackage)
Definition: databases.cxx:1783
css::uno::Reference< css::container::XHierarchicalNameAccess > nextJarFile(std::unique_lock< std::mutex > &rGuard, css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle, OUString *o_pExtensionPath, OUString *o_pExtensionRegistryPath)
Definition: databases.cxx:1597
css::uno::Reference< css::container::XHierarchicalNameAccess > implGetJarFromPackage(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< css::deployment::XPackage > &xPackage, OUString *o_pExtensionPath, OUString *o_pExtensionRegistryPath)
Definition: databases.cxx:1656
OUString implGetDbFileFromPackage(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< css::deployment::XPackage > &xPackage)
Definition: databases.cxx:1586
OUString nextDbFile(std::unique_lock< std::mutex > &rGuard, bool &o_rbExtension)
Definition: databases.cxx:1517
KeywordElement(Databases const *pDatabases, helpdatafileproxy::Hdf *pHdf, OUString key, std::u16string_view ids)
Definition: databases.cxx:589
void init(Databases const *pDatabases, helpdatafileproxy::Hdf *pHdf, std::u16string_view ids)
Definition: databases.cxx:599
css::uno::Sequence< css::uno::Sequence< OUString > > listId
Definition: databases.hxx:126
css::uno::Sequence< css::uno::Sequence< OUString > > listAnchor
Definition: databases.hxx:126
css::uno::Sequence< css::uno::Sequence< OUString > > listTitle
Definition: databases.hxx:126
KeywordInfo(const std::vector< KeywordElement > &aVector)
Definition: databases.cxx:655
css::uno::Sequence< OUString > listKey
Definition: databases.hxx:125
int getSize() const
Definition: db.hxx:42
const char * getData() const
Definition: db.hxx:44
void releaseHashMap()
Definition: db.cxx:141
bool getNextKeyAndValue(HDFData &rKey, HDFData &rValue)
Definition: db.cxx:243
bool startIteration()
Definition: db.cxx:219
bool getValueForKey(const OString &rKey, HDFData &rValue)
Definition: db.cxx:152
void stopIteration()
Definition: db.cxx:260
void createHashMap(bool bOptimizeForPerformance)
Definition: db.cxx:81
const char vendVersion[]
Definition: databases.cxx:126
const char prodName[]
Definition: databases.cxx:130
const char prodVersion[]
Definition: databases.cxx:128
const char newProdName[]
Definition: databases.cxx:132
static bool isLetter(sal_Unicode c)
Definition: databases.cxx:1373
const char vendName[]
Definition: databases.cxx:127
const char vendShort[]
Definition: databases.cxx:129
const char newProdVersion[]
Definition: databases.cxx:131
URL aURL
float u
Reference< XMultiServiceFactory > xSMgr
anchor
const sal_uInt16 idx[]
Sequence< PropertyValue > aArguments
void * p
uno_Any a
aStr
std::unique_ptr< sal_Int32[]> pData
size
std::unordered_map< OUString, bool > ExtensionHelpExistenceMap
Definition: databases.hxx:309
IteratorState
Definition: databases.hxx:294
@ Exception
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
Reference< XComponentContext > getProcessComponentContext()
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
int i
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
sal_Int32 h
LONG
sal_uInt32 Id
const char *const aFileExt[]
constexpr OUStringLiteral ZIP_STORAGE_FORMAT_STRING
KeywordElementComparator(const Reference< XCollator > &xCollator)
Definition: databases.cxx:545
bool operator()(const KeywordInfo::KeywordElement &la, const KeywordInfo::KeywordElement &ra) const
Definition: databases.cxx:549
Reference< XCollator > m_xCollator
Definition: databases.cxx:584
JCOPY_OPTION option
const char aHelpMediaType[]
Definition: tvread.cxx:828
sal_uInt16 sal_Unicode
Any result
size_t pos