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