update dev300-m58
[ooovba.git] / xmlhelp / source / cxxhelp / provider / databases.cxx
blobb920092f7f535b95a5b602a84422db4e33a77b56
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: databases.cxx,v $
10 * $Revision: 1.54 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmlhelp.hxx"
33 #include "db.hxx"
34 #include <vos/diagnose.hxx>
35 #include <osl/thread.h>
36 #include <osl/process.h>
37 #include <rtl/uri.hxx>
38 #include <osl/file.hxx>
39 #include <rtl/memory.h>
40 #include <com/sun/star/lang/Locale.hpp>
41 #include <rtl/ustrbuf.hxx>
42 #include <svtools/miscopt.hxx>
43 #include "inputstream.hxx"
44 #include <algorithm>
45 #include <string.h>
47 // Extensible help
48 #include "com/sun/star/deployment/thePackageManagerFactory.hpp"
49 #include <comphelper/processfactory.hxx>
50 #include <com/sun/star/beans/XPropertySet.hpp>
51 #include <com/sun/star/uno/XComponentContext.hpp>
52 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
53 #include <com/sun/star/beans/Optional.hpp>
54 #include <com/sun/star/frame/XConfigManager.hpp>
55 #include <com/sun/star/util/XMacroExpander.hpp>
56 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
57 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
58 #include <com/sun/star/script/XInvocation.hpp>
59 #include <comphelper/locale.hxx>
61 #include <xmlhelp/compilehelp.hxx>
63 #include "databases.hxx"
64 #include "urlparameter.hxx"
66 using namespace chelp;
67 using namespace berkeleydbproxy;
68 using namespace com::sun::star;
69 using namespace com::sun::star::uno;
70 using namespace com::sun::star::io;
71 using namespace com::sun::star::container;
72 using namespace com::sun::star::i18n;
73 using namespace com::sun::star::lang;
74 using namespace com::sun::star::deployment;
75 using namespace com::sun::star::beans;
78 static rtl::OUString aSlash( rtl::OUString::createFromAscii( "/" ) );
79 static rtl::OUString aHelpFilesBaseName( rtl::OUString::createFromAscii( "help" ) );
80 static rtl::OUString aHelpMediaType( rtl::OUString::createFromAscii( "application/vnd.sun.star.help" ) );
82 rtl::OUString Databases::expandURL( const rtl::OUString& aURL )
84 osl::MutexGuard aGuard( m_aMutex );
85 rtl::OUString aRetURL = expandURL( aURL, m_xContext );
86 return aRetURL;
89 rtl::OUString Databases::expandURL( const rtl::OUString& aURL, Reference< uno::XComponentContext > xContext )
91 static Reference< util::XMacroExpander > xMacroExpander;
92 static Reference< uri::XUriReferenceFactory > xFac;
94 if( !xContext.is() )
95 return rtl::OUString();
97 if( !xMacroExpander.is() || !xFac.is() )
99 Reference< XMultiComponentFactory > xSMgr( xContext->getServiceManager(), UNO_QUERY );
101 xFac = Reference< uri::XUriReferenceFactory >(
102 xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii(
103 "com.sun.star.uri.UriReferenceFactory"), xContext ) , UNO_QUERY );
104 if( !xFac.is() )
106 throw RuntimeException(
107 ::rtl::OUString::createFromAscii( "Databases::expand(), could not instatiate UriReferenceFactory." ),
108 Reference< XInterface >() );
111 xMacroExpander = Reference< util::XMacroExpander >(
112 xContext->getValueByName(
113 ::rtl::OUString::createFromAscii( "/singletons/com.sun.star.util.theMacroExpander" ) ),
114 UNO_QUERY_THROW );
117 rtl::OUString aRetURL = aURL;
118 if( xMacroExpander.is() )
120 Reference< uri::XUriReference > uriRef;
121 for (;;)
123 uriRef = Reference< uri::XUriReference >( xFac->parse( aRetURL ), UNO_QUERY );
124 if ( uriRef.is() )
126 Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
127 if( !sxUri.is() )
128 break;
130 aRetURL = sxUri->expand( xMacroExpander );
134 return aRetURL;
137 Databases::Databases( sal_Bool showBasic,
138 const rtl::OUString& instPath,
139 const com::sun::star::uno::Sequence< rtl::OUString >& imagesZipPaths,
140 const rtl::OUString& productName,
141 const rtl::OUString& productVersion,
142 const rtl::OUString& vendorName,
143 const rtl::OUString& vendorVersion,
144 const rtl::OUString& vendorShort,
145 const rtl::OUString& styleSheet,
146 Reference< uno::XComponentContext > xContext )
147 : m_xContext( xContext ),
148 m_bShowBasic(showBasic),
149 m_nErrorDocLength( 0 ),
150 m_pErrorDoc( 0 ),
151 m_nCustomCSSDocLength( 0 ),
152 m_pCustomCSSDoc( 0 ),
153 m_aCSS(styleSheet.toAsciiLowerCase()),
154 newProdName(rtl::OUString::createFromAscii( "$[officename]" ) ),
155 newProdVersion(rtl::OUString::createFromAscii( "$[officeversion]" ) ),
156 prodName( rtl::OUString::createFromAscii( "%PRODUCTNAME" ) ),
157 prodVersion( rtl::OUString::createFromAscii( "%PRODUCTVERSION" ) ),
158 vendName( rtl::OUString::createFromAscii( "%VENDORNAME" ) ),
159 vendVersion( rtl::OUString::createFromAscii( "%VENDORVERSION" ) ),
160 vendShort( rtl::OUString::createFromAscii( "%VENDORSHORT" ) ),
161 m_aImagesZipPaths( imagesZipPaths ),
162 m_nSymbolsStyle( 0 )
164 m_xSMgr = Reference< XMultiComponentFactory >( m_xContext->getServiceManager(), UNO_QUERY );
166 m_vAdd[0] = 12;
167 m_vAdd[1] = 15;
168 m_vAdd[2] = 11;
169 m_vAdd[3] = 14;
170 m_vAdd[4] = 12;
171 m_vAdd[5] = 13;
172 m_vAdd[6] = 16;
174 m_vReplacement[0] = productName;
175 m_vReplacement[1] = productVersion;
176 m_vReplacement[2] = vendorName;
177 m_vReplacement[3] = vendorVersion;
178 m_vReplacement[4] = vendorShort;
179 m_vReplacement[5] = productName;
180 m_vReplacement[6] = productVersion;
182 setInstallPath( instPath );
184 m_xSFA = Reference< ucb::XSimpleFileAccess >(
185 m_xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
186 m_xContext ), UNO_QUERY_THROW );
189 Databases::~Databases()
191 // release stylesheet
193 delete[] m_pCustomCSSDoc;
195 // release errorDocument
197 delete[] m_pErrorDoc;
199 // unload the databases
202 // DatabasesTable
203 DatabasesTable::iterator it = m_aDatabases.begin();
204 while( it != m_aDatabases.end() )
206 if( it->second )
207 it->second->close( 0 );
208 delete it->second;
209 ++it;
214 // ModInfoTable
216 ModInfoTable::iterator it = m_aModInfo.begin();
217 while( it != m_aModInfo.end() )
219 delete it->second;
220 ++it;
225 // KeywordInfoTable
227 KeywordInfoTable::iterator it = m_aKeywordInfo.begin();
228 while( it != m_aKeywordInfo.end() )
230 delete it->second;
231 ++it;
237 static bool impl_getZipFile(
238 Sequence< rtl::OUString > & rImagesZipPaths,
239 const rtl::OUString & rZipName,
240 rtl::OUString & rFileName )
242 rtl::OUString aWorkingDir;
243 osl_getProcessWorkingDir( &aWorkingDir.pData );
244 const rtl::OUString *pPathArray = rImagesZipPaths.getArray();
245 for ( int i = 0; i < rImagesZipPaths.getLength(); ++i )
247 rtl::OUString aFileName = pPathArray[ i ];
248 if ( aFileName.getLength() )
250 if ( 1 + aFileName.lastIndexOf( '/' ) != aFileName.getLength() )
252 aFileName += rtl::OUString::createFromAscii( "/" );
254 aFileName += rZipName;
255 // the icons are not read when the URL is a symlink
256 osl::File::getAbsoluteFileURL( aWorkingDir, aFileName, rFileName );
258 // test existence
259 osl::DirectoryItem aDirItem;
260 if ( osl::DirectoryItem::get( rFileName, aDirItem ) == osl::FileBase::E_None )
261 return true;
264 return false;
267 rtl::OString Databases::getImagesZipFileURL()
269 sal_Int16 nSymbolsStyle = SvtMiscOptions().GetCurrentSymbolsStyle();
270 if ( !m_aImagesZipFileURL.getLength() || ( m_nSymbolsStyle != nSymbolsStyle ) )
272 m_nSymbolsStyle = nSymbolsStyle;
274 rtl::OUString aImageZip;
275 rtl::OUString aSymbolsStyleName = SvtMiscOptions().GetCurrentSymbolsStyleName();
276 bool bFound = false;
278 if ( aSymbolsStyleName.getLength() != 0 )
280 rtl::OUString aZipName = rtl::OUString::createFromAscii( "images_" );
281 aZipName += aSymbolsStyleName;
282 aZipName += rtl::OUString::createFromAscii( ".zip" );
284 bFound = impl_getZipFile( m_aImagesZipPaths, aZipName, aImageZip );
287 if ( ! bFound )
288 bFound = impl_getZipFile( m_aImagesZipPaths, rtl::OUString::createFromAscii( "images.zip" ), aImageZip );
290 if ( ! bFound )
291 aImageZip = rtl::OUString();
293 m_aImagesZipFileURL = rtl::OUStringToOString(
294 rtl::Uri::encode(
295 aImageZip,
296 rtl_UriCharClassPchar,
297 rtl_UriEncodeIgnoreEscapes,
298 RTL_TEXTENCODING_UTF8 ), RTL_TEXTENCODING_UTF8 );
301 return m_aImagesZipFileURL;
305 void Databases::replaceName( rtl::OUString& oustring ) const
307 sal_Int32 idx = -1,idx1 = -1,idx2 = -1,k = 0,off;
308 bool cap = false;
309 rtl::OUStringBuffer aStrBuf( 0 );
311 while( true )
313 ++idx;
314 idx1 = oustring.indexOf( sal_Unicode('%'),idx);
315 idx2 = oustring.indexOf( sal_Unicode('$'),idx);
317 if(idx1 == -1 && idx2 == -1)
318 break;
320 if(idx1 == -1)
321 idx = idx2;
322 else if(idx2 == -1)
323 idx = idx1;
324 else {
325 // no index is zero
326 if(idx1 < idx2)
327 idx = idx1;
328 else if(idx2 < idx1 )
329 idx = idx2;
332 if( oustring.indexOf( prodName,idx ) == idx )
333 off = PRODUCTNAME;
334 else if( oustring.indexOf( prodVersion,idx ) == idx )
335 off = PRODUCTVERSION;
336 else if( oustring.indexOf( vendName,idx ) == idx )
337 off = VENDORNAME;
338 else if( oustring.indexOf( vendVersion,idx ) == idx )
339 off = VENDORVERSION;
340 else if( oustring.indexOf( vendShort,idx ) == idx )
341 off = VENDORSHORT;
342 else if( oustring.indexOf( newProdName,idx ) == idx )
343 off = NEWPRODUCTNAME;
344 else if( oustring.indexOf( newProdVersion,idx ) == idx )
345 off = NEWPRODUCTVERSION;
346 else
347 off = -1;
349 if( off != -1 )
351 if( ! cap )
353 cap = true;
354 aStrBuf.ensureCapacity( 256 );
357 aStrBuf.append( &oustring.getStr()[k],idx - k );
358 aStrBuf.append( m_vReplacement[off] );
359 k = idx + m_vAdd[off];
363 if( cap )
365 if( k < oustring.getLength() )
366 aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
367 oustring = aStrBuf.makeStringAndClear();
374 rtl::OUString Databases::getInstallPathAsSystemPath()
376 osl::MutexGuard aGuard( m_aMutex );
378 if( ! m_aInstallDirectoryAsSystemPath.getLength() )
380 #ifdef DBG_UTIL
381 bool bla =
382 osl::FileBase::E_None ==
383 osl::FileBase::getSystemPathFromFileURL( m_aInstallDirectory,m_aInstallDirectoryAsSystemPath );
384 VOS_ENSURE( bla,"HelpProvider, no installpath" );
385 #else
386 osl::FileBase::getSystemPathFromFileURL( m_aInstallDirectory,m_aInstallDirectoryAsSystemPath );
387 #endif
390 return m_aInstallDirectoryAsSystemPath;
396 rtl::OUString Databases::getInstallPathAsURL()
398 osl::MutexGuard aGuard( m_aMutex );
400 return m_aInstallDirectory;
404 const std::vector< rtl::OUString >& Databases::getModuleList( const rtl::OUString& Language )
406 if( m_avModules.size() == 0 )
408 rtl::OUString fileName,dirName = getInstallPathAsURL() + processLang( Language );
409 osl::Directory dirFile( dirName );
411 osl::DirectoryItem aDirItem;
412 osl::FileStatus aStatus( FileStatusMask_FileName );
414 sal_Int32 idx;
416 if( osl::FileBase::E_None != dirFile.open() )
417 return m_avModules;
419 while( dirFile.getNextItem( aDirItem ) == osl::FileBase::E_None &&
420 aDirItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
422 if( ! aStatus.isValid( FileStatusMask_FileName ) )
423 continue;
425 fileName = aStatus.getFileName();
427 // Check, whether fileName is of the form *.cfg
428 idx = fileName.lastIndexOf( sal_Unicode( '.' ) );
430 if( idx == -1 )
431 continue;
433 const sal_Unicode* str = fileName.getStr();
435 if( fileName.getLength() == idx + 4 &&
436 ( str[idx + 1] == 'c' || str[idx + 1] == 'C' ) &&
437 ( str[idx + 2] == 'f' || str[idx + 2] == 'F' ) &&
438 ( str[idx + 3] == 'g' || str[idx + 3] == 'G' ) &&
439 ( fileName = fileName.copy(0,idx).toAsciiLowerCase() ).compareToAscii( "picture" ) != 0 ) {
440 if(! m_bShowBasic && fileName.compareToAscii("sbasic") == 0 )
441 continue;
442 m_avModules.push_back( fileName );
446 return m_avModules;
451 StaticModuleInformation* Databases::getStaticInformationForModule( const rtl::OUString& Module,
452 const rtl::OUString& Language )
454 osl::MutexGuard aGuard( m_aMutex );
456 rtl::OUString key = processLang(Language) + rtl::OUString::createFromAscii( "/" ) + Module;
458 std::pair< ModInfoTable::iterator,bool > aPair =
459 m_aModInfo.insert( ModInfoTable::value_type( key,0 ) );
461 ModInfoTable::iterator it = aPair.first;
463 if( aPair.second && ! it->second )
465 osl::File cfgFile( getInstallPathAsURL() +
466 key +
467 rtl::OUString::createFromAscii( ".cfg" ) );
469 if( osl::FileBase::E_None != cfgFile.open( OpenFlag_Read ) )
470 it->second = 0;
471 else
473 sal_uInt32 pos = 0;
474 sal_uInt64 nRead;
475 sal_Char buffer[2048];
476 sal_Unicode lineBuffer[1028];
477 rtl::OUString fileContent;
479 while( osl::FileBase::E_None == cfgFile.read( &buffer,2048,nRead ) && nRead )
480 fileContent += rtl::OUString( buffer,sal_Int32( nRead ),RTL_TEXTENCODING_UTF8 );
482 cfgFile.close();
484 const sal_Unicode* str = fileContent.getStr();
485 rtl::OUString current,lang_,program,startid,title,heading,fulltext;
486 rtl::OUString order = rtl::OUString::createFromAscii( "1" );
488 for( sal_Int32 i = 0;i < fileContent.getLength();i++ )
490 sal_Unicode ch = str[ i ];
491 if( ch == sal_Unicode( '\n' ) || ch == sal_Unicode( '\r' ) )
493 if( pos )
495 current = rtl::OUString( lineBuffer,pos );
497 if( current.compareToAscii( "Title",5 ) == 0 )
499 title = current.copy( current.indexOf(sal_Unicode( '=' ) ) + 1 );
501 else if( current.compareToAscii( "Start",5 ) == 0 )
503 startid = current.copy( current.indexOf('=') + 1 );
505 else if( current.compareToAscii( "Language",8 ) == 0 )
507 lang_ = current.copy( current.indexOf('=') + 1 );
509 else if( current.compareToAscii( "Program",7 ) == 0 )
511 program = current.copy( current.indexOf('=') + 1 );
513 else if( current.compareToAscii( "Heading",7 ) == 0 )
515 heading = current.copy( current.indexOf('=') + 1 );
517 else if( current.compareToAscii( "FullText",8 ) == 0 )
519 fulltext = current.copy( current.indexOf('=') + 1 );
521 else if( current.compareToAscii( "Order",5 ) == 0 )
523 order = current.copy( current.indexOf('=') + 1 );
526 pos = 0;
528 else
529 lineBuffer[ pos++ ] = ch;
531 replaceName( title );
532 it->second = new StaticModuleInformation( title,
533 startid,
534 program,
535 heading,
536 fulltext,
537 order );
541 return it->second;
547 rtl::OUString Databases::processLang( const rtl::OUString& Language )
549 osl::MutexGuard aGuard( m_aMutex );
551 rtl::OUString ret;
552 LangSetTable::iterator it = m_aLangSet.find( Language );
554 if( it == m_aLangSet.end() )
556 sal_Int32 idx;
557 osl::DirectoryItem aDirItem;
559 if( osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language,aDirItem ) )
561 ret = Language;
562 m_aLangSet[ Language ] = ret;
564 else if( ( ( idx = Language.indexOf( '-' ) ) != -1 ||
565 ( idx = Language.indexOf( '_' ) ) != -1 ) &&
566 osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language.copy( 0,idx ),
567 aDirItem ) )
569 ret = Language.copy( 0,idx );
570 m_aLangSet[ Language ] = ret;
573 else
574 ret = it->second;
576 return ret;
580 rtl::OUString Databases::country( const rtl::OUString& Language )
582 sal_Int32 idx;
583 if( ( idx = Language.indexOf( '-' ) ) != -1 ||
584 ( idx = Language.indexOf( '_' ) ) != -1 )
585 return Language.copy( 1+idx );
587 return rtl::OUString();
592 Db* Databases::getBerkeley( const rtl::OUString& Database,
593 const rtl::OUString& Language, bool helpText,
594 const rtl::OUString* pExtensionPath )
596 if( ! Database.getLength() || ! Language.getLength() )
597 return 0;
599 osl::MutexGuard aGuard( m_aMutex );
602 rtl::OUString aFileExt( rtl::OUString::createFromAscii( helpText ? ".ht" : ".db" ) );
603 rtl::OUString dbFileName = aSlash + Database + aFileExt;
604 rtl::OUString key;
605 if( pExtensionPath == NULL )
606 key = processLang( Language ) + dbFileName;
607 else
608 key = *pExtensionPath + Language + dbFileName; // make unique, don't change language
610 std::pair< DatabasesTable::iterator,bool > aPair =
611 m_aDatabases.insert( DatabasesTable::value_type( key,0 ) );
613 DatabasesTable::iterator it = aPair.first;
615 if( aPair.second && ! it->second )
617 Db* table = new Db();
619 rtl::OUString fileNameOU;
620 if( pExtensionPath )
622 rtl::OUString aExpandedURL = expandURL( *pExtensionPath );
623 aExpandedURL += Language + dbFileName;
624 osl::FileBase::getSystemPathFromFileURL( aExpandedURL, fileNameOU );
626 else
627 fileNameOU = getInstallPathAsSystemPath() + key;
630 rtl::OString fileName( fileNameOU.getStr(),fileNameOU.getLength(),osl_getThreadTextEncoding() );
632 rtl::OUString fileNameDBHelp( fileNameOU );
633 if( pExtensionPath != NULL )
634 fileNameDBHelp += rtl::OUString::createFromAscii( "_" );
635 if( m_xSFA->exists( fileNameDBHelp ) )
637 DBHelp* pDBHelp = new DBHelp( fileNameDBHelp, m_xSFA );
638 table->setDBHelp( pDBHelp );
640 #ifdef TEST_DBHELP
641 bool bSuccess;
642 bool bOldDbAccess = false;
643 bSuccess = pDBHelp->testAgainstDb( fileName, bOldDbAccess );
645 bOldDbAccess = true;
646 bSuccess = pDBHelp->testAgainstDb( fileName, bOldDbAccess );
647 #endif
649 else if( table->open( 0,fileName.getStr(),0,DB_BTREE,DB_RDONLY,0644 ) )
651 table->close( 0 );
652 delete table;
653 table = 0;
656 it->second = table;
659 return it->second;
662 Reference< XCollator >
663 Databases::getCollator( const rtl::OUString& Language,
664 const rtl::OUString& System )
666 (void)System;
668 rtl::OUString key = Language;
670 osl::MutexGuard aGuard( m_aMutex );
672 CollatorTable::iterator it =
673 m_aCollatorTable.insert( CollatorTable::value_type( key,0 ) ).first;
675 if( ! it->second.is() )
677 it->second =
678 Reference< XCollator > (
679 m_xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.i18n.Collator" ),
680 m_xContext ), UNO_QUERY );
681 rtl::OUString langStr = processLang(Language);
682 rtl::OUString countryStr = country(Language);
683 if( !countryStr.getLength() )
685 if( langStr.compareToAscii("de") == 0 )
686 countryStr = rtl::OUString::createFromAscii("DE");
687 else if( langStr.compareToAscii("en") == 0 )
688 countryStr = rtl::OUString::createFromAscii("US");
689 else if( langStr.compareToAscii("es") == 0 )
690 countryStr = rtl::OUString::createFromAscii("ES");
691 else if( langStr.compareToAscii("it") == 0 )
692 countryStr = rtl::OUString::createFromAscii("IT");
693 else if( langStr.compareToAscii("fr") == 0 )
694 countryStr = rtl::OUString::createFromAscii("FR");
695 else if( langStr.compareToAscii("sv") == 0 )
696 countryStr = rtl::OUString::createFromAscii("SE");
697 else if( langStr.compareToAscii("ja") == 0 )
698 countryStr = rtl::OUString::createFromAscii("JP");
699 else if( langStr.compareToAscii("ko") == 0 )
700 countryStr = rtl::OUString::createFromAscii("KR");
702 it->second->loadDefaultCollator( Locale( langStr,
703 countryStr,
704 rtl::OUString() ),
705 0 );
708 return it->second;
713 namespace chelp {
715 struct KeywordElementComparator
717 KeywordElementComparator( const Reference< XCollator >& xCollator )
718 : m_xCollator( xCollator )
721 bool operator()( const KeywordInfo::KeywordElement& la,
722 const KeywordInfo::KeywordElement& ra ) const
724 const rtl::OUString& l = la.key;
725 const rtl::OUString& r = ra.key;
727 bool ret;
729 if( m_xCollator.is() )
731 sal_Int32 l1 = l.indexOf( sal_Unicode( ';' ) );
732 sal_Int32 l3 = ( l1 == -1 ? l.getLength() : l1 );
734 sal_Int32 r1 = r.indexOf( sal_Unicode( ';' ) );
735 sal_Int32 r3 = ( r1 == -1 ? r.getLength() : r1 );
737 sal_Int32 c1 = m_xCollator->compareSubstring( l,0,l3,r,0,r3 );
739 if( c1 == +1 )
740 ret = false;
741 else if( c1 == 0 )
743 sal_Int32 l2 = l.getLength() - l1 - 1;
744 sal_Int32 r2 = r.getLength() - r1 - 1;
745 ret = ( m_xCollator->compareSubstring( l,1+l1,l2,r,1+r1,r2 ) < 0 );
747 else
748 ret = true;
750 else
751 ret = bool( l < r );
753 return ret;
756 Reference< XCollator > m_xCollator;
757 }; // end struct KeywordElementComparator
763 KeywordInfo::KeywordElement::KeywordElement( Databases *pDatabases,
764 Db* pDb,
765 rtl::OUString& ky,
766 rtl::OUString& data )
767 : key( ky )
769 pDatabases->replaceName( key );
770 init( pDatabases,pDb,data );
775 void KeywordInfo::KeywordElement::init( Databases *pDatabases,Db* pDb,const rtl::OUString& ids )
777 const sal_Unicode* idstr = ids.getStr();
778 std::vector< rtl::OUString > id,anchor;
779 int idx = -1,k;
780 while( ( idx = ids.indexOf( ';',k = ++idx ) ) != -1 )
782 int h = ids.indexOf( sal_Unicode( '#' ),k );
783 if( h < idx )
785 // found an anchor
786 id.push_back( rtl::OUString( &idstr[k],h-k ) );
787 anchor.push_back( rtl::OUString( &idstr[h+1],idx-h-1 ) );
789 else
791 id.push_back( rtl::OUString( &idstr[k],idx-k ) );
792 anchor.push_back( rtl::OUString() );
796 listId.realloc( id.size() );
797 listAnchor.realloc( id.size() );
798 listTitle.realloc( id.size() );
800 int nSize = 0;
801 const sal_Char* pData = NULL;
802 const sal_Char pEmpty[] = "";
804 for( sal_uInt32 i = 0; i < id.size(); ++i )
806 listId[i] = id[i];
807 listAnchor[i] = anchor[i];
809 nSize = 0;
810 pData = pEmpty;
811 if( pDb )
813 rtl::OString idi( id[i].getStr(),id[i].getLength(),RTL_TEXTENCODING_UTF8 );
814 DBHelp* pDBHelp = pDb->getDBHelp();
815 if( pDBHelp != NULL )
817 DBData aDBData;
818 bool bSuccess = pDBHelp->getValueForKey( idi, aDBData );
819 if( bSuccess )
821 nSize = aDBData.getSize();
822 pData = aDBData.getData();
825 else
827 Dbt key_( static_cast< void* >( const_cast< sal_Char* >( idi.getStr() ) ),
828 idi.getLength() );
829 Dbt data;
830 pDb->get( 0,&key_,&data,0 );
831 nSize = data.get_size();
832 pData = static_cast<sal_Char*>( data.get_data() );
836 DbtToStringConverter converter( pData, nSize );
838 rtl::OUString title = converter.getTitle();
839 pDatabases->replaceName( title );
840 listTitle[i] = title;
846 KeywordInfo::KeywordInfo( const std::vector< KeywordElement >& aVec )
847 : listKey( aVec.size() ),
848 listId( aVec.size() ),
849 listAnchor( aVec.size() ),
850 listTitle( aVec.size() )
852 for( unsigned int i = 0; i < aVec.size(); ++i )
854 listKey[i] = aVec[i].key;
855 listId[i] = aVec[i].listId;
856 listAnchor[i] = aVec[i].listAnchor;
857 listTitle[i] = aVec[i].listTitle;
861 bool Databases::checkModuleMatchForExtension
862 ( const rtl::OUString& Database, const rtl::OUString& doclist )
864 bool bBelongsToDatabase = true;
866 // Analyse doclist string to find module assignments
867 bool bFoundAtLeastOneModule = false;
868 bool bModuleMatch = false;
869 sal_Int32 nLen = doclist.getLength();
870 sal_Int32 nLastFound = doclist.lastIndexOf( sal_Unicode(';') );
871 if( nLastFound == -1 )
872 nLastFound = nLen;
873 const sal_Unicode* pStr = doclist.getStr();
874 sal_Int32 nFound = doclist.lastIndexOf( sal_Unicode('_') );
875 while( nFound != -1 )
877 // Simple optimization, stop if '_' is followed by "id"
878 if( nLen - nFound > 2 )
880 if( pStr[ nFound + 1 ] == sal_Unicode('i') &&
881 pStr[ nFound + 2 ] == sal_Unicode('d') )
882 break;
885 rtl::OUString aModule = doclist.copy( nFound + 1, nLastFound - nFound - 1 );
886 std::vector< rtl::OUString >::iterator result = std::find( m_avModules.begin(), m_avModules.end(), aModule );
887 if( result != m_avModules.end() )
889 bFoundAtLeastOneModule = true;
890 if( Database == aModule )
892 bModuleMatch = true;
893 break;
897 nLastFound = nFound;
898 if( nLastFound == 0 )
899 break;
900 nFound = doclist.lastIndexOf( sal_Unicode('_'), nLastFound - 1 );
903 if( bFoundAtLeastOneModule && !bModuleMatch )
904 bBelongsToDatabase = false;
906 return bBelongsToDatabase;
910 KeywordInfo* Databases::getKeyword( const rtl::OUString& Database,
911 const rtl::OUString& Language )
913 osl::MutexGuard aGuard( m_aMutex );
915 rtl::OUString key = processLang(Language) + rtl::OUString::createFromAscii( "/" ) + Database;
917 std::pair< KeywordInfoTable::iterator,bool > aPair =
918 m_aKeywordInfo.insert( KeywordInfoTable::value_type( key,0 ) );
920 KeywordInfoTable::iterator it = aPair.first;
922 if( aPair.second && ! it->second )
924 std::vector<KeywordInfo::KeywordElement> aVector;
926 KeyDataBaseFileIterator aDbFileIt( m_xContext, *this, Database, Language );
927 rtl::OUString fileNameOU;
928 bool bExtension = false;
929 while( (fileNameOU = aDbFileIt.nextDbFile( bExtension )).getLength() > 0 )
931 rtl::OString fileName( fileNameOU.getStr(),
932 fileNameOU.getLength(),
933 osl_getThreadTextEncoding() );
935 Db table;
937 rtl::OUString fileNameDBHelp( fileNameOU );
938 if( bExtension )
939 fileNameDBHelp += rtl::OUString::createFromAscii( "_" );
940 if( m_xSFA->exists( fileNameDBHelp ) )
942 DBHelp aDBHelp( fileNameDBHelp, m_xSFA );
944 DBData aKey;
945 DBData aValue;
946 if( aDBHelp.startIteration() )
948 Db* idmap = getBerkeley( Database,Language );
950 DBHelp* pDBHelp = idmap->getDBHelp();
951 if( pDBHelp != NULL )
953 bool bOptimizeForPerformance = true;
954 pDBHelp->releaseHashMap();
955 pDBHelp->createHashMap( bOptimizeForPerformance );
958 while( aDBHelp.getNextKeyAndValue( aKey, aValue ) )
960 rtl::OUString keyword( aKey.getData(), aKey.getSize(),
961 RTL_TEXTENCODING_UTF8 );
962 rtl::OUString doclist( aValue.getData(), aValue.getSize(),
963 RTL_TEXTENCODING_UTF8 );
965 bool bBelongsToDatabase = true;
966 if( bExtension )
967 bBelongsToDatabase = checkModuleMatchForExtension( Database, doclist );
969 if( !bBelongsToDatabase )
970 continue;
972 aVector.push_back( KeywordInfo::KeywordElement( this,
973 idmap,
974 keyword,
975 doclist ) );
977 aDBHelp.stopIteration();
979 if( pDBHelp != NULL )
980 pDBHelp->releaseHashMap();
983 #ifdef TEST_DBHELP
984 bool bSuccess;
985 bool bOldDbAccess = false;
986 bSuccess = aDBHelp.testAgainstDb( fileName, bOldDbAccess );
988 bOldDbAccess = true;
989 bSuccess = aDBHelp.testAgainstDb( fileName, bOldDbAccess );
991 int nDummy = 0;
992 #endif
995 else if( 0 == table.open( 0,fileName.getStr(),0,DB_BTREE,DB_RDONLY,0644 ) )
997 Db* idmap = getBerkeley( Database,Language );
999 bool first = true;
1001 Dbc* cursor = 0;
1002 table.cursor( 0,&cursor,0 );
1003 Dbt key_,data;
1004 key_.set_flags( DB_DBT_MALLOC ); // Initially the cursor must allocate the necessary memory
1005 data.set_flags( DB_DBT_MALLOC );
1006 while( cursor && DB_NOTFOUND != cursor->get( &key_,&data,DB_NEXT ) )
1008 rtl::OUString keyword( static_cast<sal_Char*>(key_.get_data()),
1009 key_.get_size(),
1010 RTL_TEXTENCODING_UTF8 );
1011 rtl::OUString doclist( static_cast<sal_Char*>(data.get_data()),
1012 data.get_size(),
1013 RTL_TEXTENCODING_UTF8 );
1015 bool bBelongsToDatabase = true;
1016 if( bExtension )
1017 bBelongsToDatabase = checkModuleMatchForExtension( Database, doclist );
1019 if( !bBelongsToDatabase )
1020 continue;
1022 aVector.push_back( KeywordInfo::KeywordElement( this,
1023 idmap,
1024 keyword,
1025 doclist ) );
1026 if( first )
1028 key_.set_flags( DB_DBT_REALLOC );
1029 data.set_flags( DB_DBT_REALLOC );
1030 first = false;
1034 if( cursor ) cursor->close();
1036 table.close( 0 );
1039 // sorting
1040 Reference< XCollator > xCollator = getCollator( Language,rtl::OUString());
1041 KeywordElementComparator aComparator( xCollator );
1042 std::sort(aVector.begin(),aVector.end(),aComparator);
1044 KeywordInfo* pInfo = it->second = new KeywordInfo( aVector );
1045 (void)pInfo;
1048 return it->second;
1051 Reference< XHierarchicalNameAccess > Databases::jarFile( const rtl::OUString& jar,
1052 const rtl::OUString& Language )
1054 if( ! jar.getLength() ||
1055 ! Language.getLength() )
1057 return Reference< XHierarchicalNameAccess >( 0 );
1059 rtl::OUString key = processLang(Language) + aSlash + jar;
1061 osl::MutexGuard aGuard( m_aMutex );
1063 ZipFileTable::iterator it =
1064 m_aZipFileTable.insert( ZipFileTable::value_type( key,Reference< XHierarchicalNameAccess >(0) ) ).first;
1066 if( ! it->second.is() )
1068 rtl::OUString zipFile;
1071 // Extension jar file? Search for ?
1072 sal_Int32 nQuestionMark1 = jar.indexOf( sal_Unicode('?') );
1073 sal_Int32 nQuestionMark2 = jar.lastIndexOf( sal_Unicode('?') );
1074 if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
1076 ::rtl::OUString aExtensionPath = jar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
1077 ::rtl::OUString aPureJar = jar.copy( nQuestionMark2 + 1 );
1079 rtl::OUStringBuffer aStrBuf;
1080 aStrBuf.append( aExtensionPath );
1081 aStrBuf.append( aSlash );
1082 aStrBuf.append( aPureJar );
1084 zipFile = expandURL( aStrBuf.makeStringAndClear() );
1086 else
1088 zipFile = getInstallPathAsURL() + key;
1091 Sequence< Any > aArguments( 1 );
1093 XInputStream_impl* p = new XInputStream_impl( zipFile );
1094 if( p->CtorSuccess() )
1096 Reference< XInputStream > xInputStream( p );
1097 aArguments[ 0 ] <<= xInputStream;
1099 else
1101 delete p;
1102 aArguments[ 0 ] <<= zipFile;
1105 Reference< XInterface > xIfc
1106 = m_xSMgr->createInstanceWithArgumentsAndContext(
1107 rtl::OUString::createFromAscii(
1108 "com.sun.star.packages.comp.ZipPackage" ),
1109 aArguments, m_xContext );
1111 if ( xIfc.is() )
1113 it->second = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1115 VOS_ENSURE( it->second.is(),
1116 "ContentProvider::createPackage - "
1117 "Got no hierarchical name access!" );
1121 catch ( RuntimeException & )
1124 catch ( Exception & )
1129 return it->second;
1132 Reference< XHierarchicalNameAccess > Databases::findJarFileForPath
1133 ( const rtl::OUString& jar, const rtl::OUString& Language,
1134 const rtl::OUString& path, rtl::OUString* o_pExtensionPath )
1136 Reference< XHierarchicalNameAccess > xNA;
1137 if( ! jar.getLength() ||
1138 ! Language.getLength() )
1140 return xNA;
1143 JarFileIterator aJarFileIt( m_xContext, *this, jar, Language );
1144 Reference< XHierarchicalNameAccess > xTestNA;
1145 Reference< deployment::XPackage > xParentPackageBundle;
1146 while( (xTestNA = aJarFileIt.nextJarFile( xParentPackageBundle, o_pExtensionPath )).is() )
1148 if( xTestNA.is() && xTestNA->hasByHierarchicalName( path ) )
1150 bool bSuccess = true;
1151 if( xParentPackageBundle.is() )
1153 rtl::OUString aIdentifierInPath;
1154 sal_Int32 nFindSlash = path.indexOf( '/' );
1155 if( nFindSlash != -1 )
1156 aIdentifierInPath = path.copy( 0, nFindSlash );
1158 beans::Optional<rtl::OUString> aIdentifierOptional = xParentPackageBundle->getIdentifier();
1159 if( aIdentifierInPath.getLength() && aIdentifierOptional.IsPresent )
1161 rtl::OUString aUnencodedIdentifier = aIdentifierOptional.Value;
1162 rtl::OUString aIdentifier = rtl::Uri::encode( aUnencodedIdentifier,
1163 rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8 );
1165 if( !aIdentifierInPath.equals( aIdentifier ) )
1167 // path does not start with extension identifier -> ignore
1168 bSuccess = false;
1171 else
1173 // No identifier -> ignore
1174 bSuccess = false;
1178 if( bSuccess )
1180 xNA = xTestNA;
1181 break;
1186 return xNA;
1189 void Databases::popupDocument( URLParameter* urlPar,char **buffer,int *byteCount )
1191 const char* pop1 =
1192 " <html> "
1193 " <head> "
1194 " <help:css-file-link xmlns:help=\"http://openoffice.org/2000/help\"/> "
1195 " </head> "
1196 " <body> "
1197 " <help:popup-cut Id=\"";
1198 const sal_Int32 l1 = strlen( pop1 );
1200 const char* pop3 = "\" Eid=\"";
1201 const sal_Int32 l3 = strlen( pop3 );
1203 const char* pop5 =
1204 "\" xmlns:help=\"http://openoffice.org/2000/help\"></help:popup-cut> "
1205 " </body> "
1206 " </html>";
1207 const sal_Int32 l5 = strlen( pop5 );
1208 sal_Int32 l2,l4;
1210 rtl::OUString val = urlPar->get_id();
1211 rtl::OString pop2O( val.getStr(),l2 = val.getLength(),RTL_TEXTENCODING_UTF8 );
1212 const char* pop2 = pop2O.getStr();
1214 val = urlPar->get_eid();
1215 rtl::OString pop4O( val.getStr(),l4 = val.getLength(),RTL_TEXTENCODING_UTF8 );
1216 const char* pop4 = pop4O.getStr();
1218 (*byteCount) = l1 + l2 + l3 + l4 + l5;
1220 *buffer = new char[ 1+*byteCount ];
1222 rtl_copyMemory( *buffer,pop1,l1 );
1223 rtl_copyMemory( *buffer+l1,pop2,l2 );
1224 rtl_copyMemory( *buffer+(l1+l2),pop3,l3 );
1225 rtl_copyMemory( *buffer+(l1+l2+l3),pop4,l4 );
1226 rtl_copyMemory( *buffer+(l1+l2+l3+l4),pop5,l5 );
1227 (*buffer)[*byteCount] = 0;
1231 void Databases::changeCSS(const rtl::OUString& newStyleSheet)
1233 m_aCSS = newStyleSheet.toAsciiLowerCase();
1234 delete[] m_pCustomCSSDoc, m_pCustomCSSDoc = 0,m_nCustomCSSDocLength = 0;
1239 void Databases::cascadingStylesheet( const rtl::OUString& Language,
1240 char** buffer,
1241 int* byteCount )
1243 if( ! m_pCustomCSSDoc )
1245 int retry = 2;
1246 bool error = true;
1247 rtl::OUString fileURL;
1249 while( error && retry )
1251 if( retry == 2 )
1252 fileURL =
1253 getInstallPathAsURL() +
1254 processLang( Language ) +
1255 rtl::OUString::createFromAscii( "/" ) +
1256 m_aCSS +
1257 rtl::OUString::createFromAscii( ".css" );
1258 else if( retry == 1 )
1259 fileURL =
1260 getInstallPathAsURL() +
1261 m_aCSS +
1262 rtl::OUString::createFromAscii( ".css" );
1264 osl::DirectoryItem aDirItem;
1265 osl::File aFile( fileURL );
1266 osl::FileStatus aStatus( FileStatusMask_FileSize );
1268 if( osl::FileBase::E_None == osl::DirectoryItem::get( fileURL,aDirItem ) &&
1269 osl::FileBase::E_None == aFile.open( OpenFlag_Read ) &&
1270 osl::FileBase::E_None == aDirItem.getFileStatus( aStatus ) )
1272 sal_uInt64 nSize;
1273 aFile.getSize( nSize );
1274 m_nCustomCSSDocLength = (int)nSize;
1275 m_pCustomCSSDoc = new char[ 1 + m_nCustomCSSDocLength ];
1276 m_pCustomCSSDoc[ m_nCustomCSSDocLength ] = 0;
1277 sal_uInt64 a = m_nCustomCSSDocLength,b = m_nCustomCSSDocLength;
1278 aFile.read( m_pCustomCSSDoc,a,b );
1279 aFile.close();
1280 error = false;
1283 --retry;
1286 if( error )
1288 m_nCustomCSSDocLength = 0;
1289 m_pCustomCSSDoc = new char[ 1 ]; // Initialize with 1 to avoid gcc compiler warning
1293 *byteCount = m_nCustomCSSDocLength;
1294 *buffer = new char[ 1 + *byteCount ];
1295 (*buffer)[*byteCount] = 0;
1296 rtl_copyMemory( *buffer,m_pCustomCSSDoc,m_nCustomCSSDocLength );
1301 void Databases::setActiveText( const rtl::OUString& Module,
1302 const rtl::OUString& Language,
1303 const rtl::OUString& Id,
1304 char** buffer,
1305 int* byteCount )
1307 DataBaseIterator aDbIt( m_xContext, *this, Module, Language, true );
1309 // #i84550 Cache information about failed ids
1310 rtl::OString id( Id.getStr(),Id.getLength(),RTL_TEXTENCODING_UTF8 );
1311 EmptyActiveTextSet::iterator it = m_aEmptyActiveTextSet.find( id );
1312 bool bFoundAsEmpty = ( it != m_aEmptyActiveTextSet.end() );
1313 Dbt data;
1314 DBData aDBData;
1316 int nSize = 0;
1317 const sal_Char* pData = NULL;
1319 bool bSuccess = false;
1320 if( !bFoundAsEmpty )
1322 Db* db;
1323 Dbt key( static_cast< void* >( const_cast< sal_Char* >( id.getStr() ) ),id.getLength() );
1324 while( !bSuccess && (db = aDbIt.nextDb()) != NULL )
1326 DBHelp* pDBHelp = db->getDBHelp();
1327 if( pDBHelp != NULL )
1329 bSuccess = pDBHelp->getValueForKey( id, aDBData );
1330 nSize = aDBData.getSize();
1331 pData = aDBData.getData();
1333 else
1335 int err = db->get( 0, &key, &data, 0 );
1336 if( err == 0 )
1338 bSuccess = true;
1339 nSize = data.get_size();
1340 pData = static_cast<sal_Char*>( data.get_data() );
1346 if( bSuccess )
1348 // ensure existence of tmp after for
1349 rtl::OString tmp;
1350 for( int i = 0; i < nSize; ++i )
1351 if( pData[i] == '%' || pData[i] == '$' )
1353 // need of replacement
1354 rtl::OUString temp = rtl::OUString( pData, nSize, RTL_TEXTENCODING_UTF8 );
1355 replaceName( temp );
1356 tmp = rtl::OString( temp.getStr(),
1357 temp.getLength(),
1358 RTL_TEXTENCODING_UTF8 );
1359 nSize = tmp.getLength();
1360 pData = tmp.getStr();
1361 break;
1364 *byteCount = nSize;
1365 *buffer = new char[ 1 + nSize ];
1366 (*buffer)[nSize] = 0;
1367 rtl_copyMemory( *buffer, pData, nSize );
1369 else
1371 *byteCount = 0;
1372 *buffer = new char[1]; // Initialize with 1 to avoid compiler warnings
1373 if( !bFoundAsEmpty )
1374 m_aEmptyActiveTextSet.insert( id );
1379 void Databases::setInstallPath( const rtl::OUString& aInstDir )
1381 osl::MutexGuard aGuard( m_aMutex );
1383 osl::FileBase::getFileURLFromSystemPath( aInstDir,m_aInstallDirectory );
1384 //TODO: check returned error code
1386 if( m_aInstallDirectory.lastIndexOf( sal_Unicode( '/' ) ) != m_aInstallDirectory.getLength() - 1 )
1387 m_aInstallDirectory += rtl::OUString::createFromAscii( "/" );
1389 m_aInstallDirectoryWithoutEncoding = rtl::Uri::decode( m_aInstallDirectory,
1390 rtl_UriDecodeWithCharset,
1391 RTL_TEXTENCODING_UTF8 );
1395 //===================================================================
1396 // class ExtensionIteratorBase
1398 ExtensionHelpExistanceMap ExtensionIteratorBase::aHelpExistanceMap;
1400 ExtensionIteratorBase::ExtensionIteratorBase( Reference< XComponentContext > xContext,
1401 Databases& rDatabases, const rtl::OUString& aInitialModule, const rtl::OUString& aLanguage )
1402 : m_xContext( xContext )
1403 , m_rDatabases( rDatabases )
1404 , m_eState( INITIAL_MODULE )
1405 , m_aInitialModule( aInitialModule )
1406 , m_aLanguage( aLanguage )
1408 init();
1411 ExtensionIteratorBase::ExtensionIteratorBase( Databases& rDatabases,
1412 const rtl::OUString& aInitialModule, const rtl::OUString& aLanguage )
1413 : m_rDatabases( rDatabases )
1414 , m_eState( INITIAL_MODULE )
1415 , m_aInitialModule( aInitialModule )
1416 , m_aLanguage( aLanguage )
1418 init();
1421 void ExtensionIteratorBase::init()
1423 if( !m_xContext.is() )
1425 Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
1426 Reference< XPropertySet > xProps( xFactory, UNO_QUERY );
1427 OSL_ASSERT( xProps.is() );
1428 if (xProps.is())
1430 xProps->getPropertyValue(
1431 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= m_xContext;
1432 OSL_ASSERT( m_xContext.is() );
1435 if( !m_xContext.is() )
1437 throw RuntimeException(
1438 ::rtl::OUString::createFromAscii( "ExtensionIteratorBase::init(), no XComponentContext" ),
1439 Reference< XInterface >() );
1442 Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
1443 m_xSFA = Reference< ucb::XSimpleFileAccess >(
1444 xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
1445 m_xContext ), UNO_QUERY_THROW );
1447 m_bUserPackagesLoaded = false;
1448 m_bSharedPackagesLoaded = false;
1449 m_iUserPackage = 0;
1450 m_iSharedPackage = 0;
1453 Reference< deployment::XPackage > ExtensionIteratorBase::implGetHelpPackageFromPackage
1454 ( Reference< deployment::XPackage > xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
1456 o_xParentPackageBundle.clear();
1458 Reference< deployment::XPackage > xHelpPackage;
1459 if( !xPackage.is() )
1460 return xHelpPackage;
1462 // #i84550 Cache information about help content in extension
1463 rtl::OUString aExtensionPath = xPackage->getURL();
1464 ExtensionHelpExistanceMap::iterator it = aHelpExistanceMap.find( aExtensionPath );
1465 bool bFound = ( it != aHelpExistanceMap.end() );
1466 bool bHasHelp = bFound ? it->second : false;
1467 if( bFound && !bHasHelp )
1468 return xHelpPackage;
1470 // Check if parent package is registered
1471 beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
1472 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
1473 bool bRegistered = false;
1474 if( option.IsPresent )
1476 beans::Ambiguous<sal_Bool> const & reg = option.Value;
1477 if( !reg.IsAmbiguous && reg.Value )
1478 bRegistered = true;
1480 if( bRegistered )
1482 if( xPackage->isBundle() )
1484 Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
1485 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
1486 sal_Int32 nPkgCount = aPkgSeq.getLength();
1487 const Reference< deployment::XPackage >* pSeq = aPkgSeq.getConstArray();
1488 for( sal_Int32 iPkg = 0 ; iPkg < nPkgCount ; ++iPkg )
1490 const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
1491 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
1492 rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
1493 if( aMediaType.equals( aHelpMediaType ) )
1495 xHelpPackage = xSubPkg;
1496 o_xParentPackageBundle = xPackage;
1497 break;
1501 else
1503 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
1504 rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
1505 if( aMediaType.equals( aHelpMediaType ) )
1506 xHelpPackage = xPackage;
1510 if( !bFound )
1511 aHelpExistanceMap[ aExtensionPath ] = xHelpPackage.is();
1513 return xHelpPackage;
1516 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextUserHelpPackage
1517 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1519 Reference< deployment::XPackage > xHelpPackage;
1521 if( !m_bUserPackagesLoaded )
1523 Reference< XPackageManager > xUserManager =
1524 thePackageManagerFactory::get( m_xContext )->getPackageManager( rtl::OUString::createFromAscii("user") );
1525 m_aUserPackagesSeq = xUserManager->getDeployedPackages
1526 ( Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1528 m_bUserPackagesLoaded = true;
1531 if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
1533 m_eState = SHARED_EXTENSIONS; // Later: SHARED_MODULE
1535 else
1537 const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
1538 Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage++ ];
1539 VOS_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextUserHelpPackage(): Invalid package" );
1540 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1543 return xHelpPackage;
1546 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextSharedHelpPackage
1547 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1549 Reference< deployment::XPackage > xHelpPackage;
1551 if( !m_bSharedPackagesLoaded )
1553 Reference< XPackageManager > xSharedManager =
1554 thePackageManagerFactory::get( m_xContext )->getPackageManager( rtl::OUString::createFromAscii("shared") );
1555 m_aSharedPackagesSeq = xSharedManager->getDeployedPackages
1556 ( Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1558 m_bSharedPackagesLoaded = true;
1561 if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
1563 m_eState = END_REACHED;
1565 else
1567 const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
1568 Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage++ ];
1569 VOS_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextSharedHelpPackage(): Invalid package" );
1570 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1573 return xHelpPackage;
1576 rtl::OUString ExtensionIteratorBase::implGetFileFromPackage(
1577 const rtl::OUString& rFileExtension, Reference< deployment::XPackage > xPackage )
1579 // No extension -> search for pure language folder
1580 bool bLangFolderOnly = (rFileExtension.getLength() == 0);
1582 rtl::OUString aFile;
1583 rtl::OUString aLanguage = m_aLanguage;
1584 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1586 rtl::OUStringBuffer aStrBuf;
1587 aStrBuf.append( xPackage->getURL() );
1588 aStrBuf.append( aSlash );
1589 aStrBuf.append( aLanguage );
1590 if( !bLangFolderOnly )
1592 aStrBuf.append( aSlash );
1593 aStrBuf.append( aHelpFilesBaseName );
1594 aStrBuf.append( rFileExtension );
1597 aFile = m_rDatabases.expandURL( aStrBuf.makeStringAndClear() );
1598 if( iPass == 0 )
1600 if( m_xSFA->exists( aFile ) )
1601 break;
1603 ::std::vector< ::rtl::OUString > av;
1604 implGetLanguageVectorFromPackage( av, xPackage );
1605 ::std::vector< ::rtl::OUString >::const_iterator pFound = av.end();
1608 pFound = ::comphelper::Locale::getFallback( av, m_aLanguage );
1610 catch( ::comphelper::Locale::MalFormedLocaleException& )
1612 if( pFound != av.end() )
1613 aLanguage = *pFound;
1616 return aFile;
1619 inline bool isLetter( sal_Unicode c )
1621 bool bLetter = ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
1622 return bLetter;
1625 void ExtensionIteratorBase::implGetLanguageVectorFromPackage( ::std::vector< ::rtl::OUString > &rv,
1626 com::sun::star::uno::Reference< com::sun::star::deployment::XPackage > xPackage )
1628 rv.clear();
1629 rtl::OUString aExtensionPath = xPackage->getURL();
1630 Sequence< rtl::OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1632 const rtl::OUString* pSeq = aEntrySeq.getConstArray();
1633 sal_Int32 nCount = aEntrySeq.getLength();
1634 for( sal_Int32 i = 0 ; i < nCount ; ++i )
1636 rtl::OUString aEntry = pSeq[i];
1637 if( m_xSFA->isFolder( aEntry ) )
1639 sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1640 if( nLastSlash != -1 )
1642 rtl::OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1644 // Check language sceme
1645 int nLen = aPureEntry.getLength();
1646 const sal_Unicode* pc = aPureEntry.getStr();
1647 bool bStartCanBeLanguage = ( nLen >= 2 && isLetter( pc[0] ) && isLetter( pc[1] ) );
1648 bool bIsLanguage = bStartCanBeLanguage &&
1649 ( nLen == 2 || (nLen == 5 && pc[2] == '-' && isLetter( pc[3] ) && isLetter( pc[4] )) );
1650 if( bIsLanguage )
1651 rv.push_back( aPureEntry );
1658 //===================================================================
1659 // class DataBaseIterator
1661 Db* DataBaseIterator::nextDb( rtl::OUString* o_pExtensionPath )
1663 Db* pRetDb = NULL;
1665 while( !pRetDb && m_eState != END_REACHED )
1667 switch( m_eState )
1669 case INITIAL_MODULE:
1670 pRetDb = m_rDatabases.getBerkeley( m_aInitialModule, m_aLanguage, m_bHelpText );
1671 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1672 break;
1674 // Later:
1675 //case SHARED_MODULE
1676 //...
1678 case USER_EXTENSIONS:
1680 Reference< deployment::XPackage > xParentPackageBundle;
1681 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1682 if( !xHelpPackage.is() )
1683 break;
1684 pRetDb = implGetDbFromPackage( xHelpPackage, o_pExtensionPath );
1685 break;
1688 case SHARED_EXTENSIONS:
1690 Reference< deployment::XPackage > xParentPackageBundle;
1691 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1692 if( !xHelpPackage.is() )
1693 break;
1695 pRetDb = implGetDbFromPackage( xHelpPackage, o_pExtensionPath );
1696 break;
1698 case END_REACHED:
1699 VOS_ENSURE( false, "DataBaseIterator::nextDb(): Invalid case END_REACHED" );
1700 break;
1704 return pRetDb;
1707 Db* DataBaseIterator::implGetDbFromPackage( Reference< deployment::XPackage > xPackage,
1708 rtl::OUString* o_pExtensionPath )
1710 rtl::OUString aExtensionPath = xPackage->getURL();
1711 //if( o_pExtensionPath )
1712 //*o_pExtensionPath = aExtensionPath;
1713 aExtensionPath += aSlash;
1715 rtl::OUString aUsedLanguage = m_aLanguage;
1716 Db* pRetDb = m_rDatabases.getBerkeley( aHelpFilesBaseName, aUsedLanguage,
1717 m_bHelpText, &aExtensionPath );
1719 // Language fallback
1720 if( !pRetDb )
1722 ::std::vector< ::rtl::OUString > av;
1723 implGetLanguageVectorFromPackage( av, xPackage );
1724 ::std::vector< ::rtl::OUString >::const_iterator pFound = av.end();
1727 pFound = ::comphelper::Locale::getFallback( av, m_aLanguage );
1729 catch( ::comphelper::Locale::MalFormedLocaleException& )
1731 if( pFound != av.end() )
1733 aUsedLanguage = *pFound;
1734 pRetDb = m_rDatabases.getBerkeley( aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aExtensionPath );
1738 if( o_pExtensionPath )
1739 *o_pExtensionPath = aExtensionPath + aUsedLanguage;
1741 return pRetDb;
1745 //===================================================================
1746 // class KeyDataBaseFileIterator
1748 rtl::OUString KeyDataBaseFileIterator::nextDbFile( bool& o_rbExtension )
1750 rtl::OUString aRetFile;
1752 while( !aRetFile.getLength() && m_eState != END_REACHED )
1754 switch( m_eState )
1756 case INITIAL_MODULE:
1757 aRetFile =
1758 m_rDatabases.getInstallPathAsSystemPath() +
1759 m_rDatabases.processLang( m_aLanguage ) + aSlash + m_aInitialModule +
1760 rtl::OUString::createFromAscii( ".key" );
1762 o_rbExtension = false;
1764 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1765 break;
1767 // Later:
1768 //case SHARED_MODULE
1769 //...
1771 case USER_EXTENSIONS:
1773 Reference< deployment::XPackage > xParentPackageBundle;
1774 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1775 if( !xHelpPackage.is() )
1776 break;
1778 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1779 o_rbExtension = true;
1780 break;
1783 case SHARED_EXTENSIONS:
1785 Reference< deployment::XPackage > xParentPackageBundle;
1786 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1787 if( !xHelpPackage.is() )
1788 break;
1790 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1791 o_rbExtension = true;
1792 break;
1794 case END_REACHED:
1795 VOS_ENSURE( false, "DataBaseIterator::nextDbFile(): Invalid case END_REACHED" );
1796 break;
1800 return aRetFile;
1803 rtl::OUString KeyDataBaseFileIterator::implGetDbFileFromPackage
1804 ( Reference< deployment::XPackage > xPackage )
1806 rtl::OUString aExpandedURL =
1807 implGetFileFromPackage( rtl::OUString::createFromAscii( ".key" ), xPackage );
1809 rtl::OUString aRetFile;
1810 osl::FileBase::getSystemPathFromFileURL( aExpandedURL, aRetFile );
1812 return aRetFile;
1816 //===================================================================
1817 // class JarFileIterator
1819 Reference< XHierarchicalNameAccess > JarFileIterator::nextJarFile
1820 ( Reference< deployment::XPackage >& o_xParentPackageBundle, rtl::OUString* o_pExtensionPath )
1822 Reference< XHierarchicalNameAccess > xNA;
1824 while( !xNA.is() && m_eState != END_REACHED )
1826 switch( m_eState )
1828 case INITIAL_MODULE:
1829 xNA = m_rDatabases.jarFile( m_aInitialModule, m_aLanguage );
1830 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1831 break;
1833 // Later:
1834 //case SHARED_MODULE
1835 //...
1837 case USER_EXTENSIONS:
1839 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( o_xParentPackageBundle );
1840 if( !xHelpPackage.is() )
1841 break;
1843 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath );
1844 break;
1847 case SHARED_EXTENSIONS:
1849 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( o_xParentPackageBundle );
1850 if( !xHelpPackage.is() )
1851 break;
1853 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath );
1854 break;
1856 case END_REACHED:
1857 VOS_ENSURE( false, "JarFileIterator::nextJarFile(): Invalid case END_REACHED" );
1858 break;
1862 return xNA;
1865 Reference< XHierarchicalNameAccess > JarFileIterator::implGetJarFromPackage
1866 ( Reference< deployment::XPackage > xPackage, rtl::OUString* o_pExtensionPath )
1868 Reference< XHierarchicalNameAccess > xNA;
1870 rtl::OUString zipFile =
1871 implGetFileFromPackage( rtl::OUString::createFromAscii( ".jar" ), xPackage );
1875 Sequence< Any > aArguments( 1 );
1876 aArguments[ 0 ] <<= zipFile;
1878 Reference< XMultiComponentFactory >xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
1879 Reference< XInterface > xIfc
1880 = xSMgr->createInstanceWithArgumentsAndContext(
1881 rtl::OUString::createFromAscii(
1882 "com.sun.star.packages.comp.ZipPackage" ),
1883 aArguments, m_xContext );
1885 if ( xIfc.is() )
1887 xNA = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1889 VOS_ENSURE( xNA.is(),
1890 "JarFileIterator::implGetJarFromPackage() - "
1891 "Got no hierarchical name access!" );
1894 catch ( RuntimeException & )
1896 catch ( Exception & )
1899 if( xNA.is() && o_pExtensionPath != NULL )
1901 // Extract path including language from file name
1902 sal_Int32 nLastSlash = zipFile.lastIndexOf( '/' );
1903 if( nLastSlash != -1 )
1904 *o_pExtensionPath = zipFile.copy( 0, nLastSlash );
1907 return xNA;
1911 //===================================================================
1912 // class IndexFolderIterator
1914 rtl::OUString IndexFolderIterator::nextIndexFolder( bool& o_rbExtension, bool& o_rbTemporary )
1916 rtl::OUString aIndexFolder;
1918 while( !aIndexFolder.getLength() && m_eState != END_REACHED )
1920 switch( m_eState )
1922 case INITIAL_MODULE:
1923 aIndexFolder =
1924 m_rDatabases.getInstallPathAsURL() +
1925 m_rDatabases.processLang( m_aLanguage ) + aSlash + m_aInitialModule +
1926 rtl::OUString::createFromAscii( ".idxl" );
1928 o_rbTemporary = false;
1929 o_rbExtension = false;
1931 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1932 break;
1934 // Later:
1935 //case SHARED_MODULE
1936 //...
1938 case USER_EXTENSIONS:
1940 Reference< deployment::XPackage > xParentPackageBundle;
1941 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1942 if( !xHelpPackage.is() )
1943 break;
1945 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1946 o_rbExtension = true;
1947 break;
1950 case SHARED_EXTENSIONS:
1952 Reference< deployment::XPackage > xParentPackageBundle;
1953 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1954 if( !xHelpPackage.is() )
1955 break;
1957 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1958 o_rbExtension = true;
1959 break;
1961 case END_REACHED:
1962 VOS_ENSURE( false, "IndexFolderIterator::nextIndexFolder(): Invalid case END_REACHED" );
1963 break;
1967 return aIndexFolder;
1970 rtl::OUString IndexFolderIterator::implGetIndexFolderFromPackage( bool& o_rbTemporary, Reference< deployment::XPackage > xPackage )
1972 rtl::OUString aIndexFolder =
1973 implGetFileFromPackage( rtl::OUString::createFromAscii( ".idxl" ), xPackage );
1975 o_rbTemporary = false;
1976 if( !m_xSFA->isFolder( aIndexFolder ) )
1978 // i98680: Missing index? Try to generate now
1979 rtl::OUString aLangURL = implGetFileFromPackage( rtl::OUString(), xPackage );
1980 if( m_xSFA->isFolder( aLangURL ) )
1982 // Test write access (shared extension may be read only)
1983 bool bIsWriteAccess = false;
1986 rtl::OUString aCreateTestFolder = aLangURL + rtl::OUString::createFromAscii( "CreateTestFolder" );
1987 m_xSFA->createFolder( aCreateTestFolder );
1988 if( m_xSFA->isFolder( aCreateTestFolder ) )
1989 bIsWriteAccess = true;
1991 m_xSFA->kill( aCreateTestFolder );
1993 catch (Exception &)
1996 // TEST
1997 //bIsWriteAccess = false;
1999 Reference< script::XInvocation > xInvocation;
2000 Reference< XMultiComponentFactory >xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
2003 xInvocation = Reference< script::XInvocation >(
2004 m_xContext->getServiceManager()->createInstanceWithContext( rtl::OUString::createFromAscii(
2005 "com.sun.star.help.HelpIndexer" ), m_xContext ) , UNO_QUERY );
2007 if( xInvocation.is() )
2009 Sequence<uno::Any> aParamsSeq( bIsWriteAccess ? 6 : 8 );
2011 aParamsSeq[0] = uno::makeAny( rtl::OUString::createFromAscii( "-lang" ) );
2013 rtl::OUString aLang;
2014 sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
2015 if( nLastSlash != -1 )
2016 aLang = aLangURL.copy( nLastSlash + 1 );
2017 else
2018 aLang = rtl::OUString::createFromAscii( "en" );
2019 aParamsSeq[1] = uno::makeAny( aLang );
2021 aParamsSeq[2] = uno::makeAny( rtl::OUString::createFromAscii( "-mod" ) );
2022 aParamsSeq[3] = uno::makeAny( rtl::OUString::createFromAscii( "help" ) );
2024 rtl::OUString aZipDir = aLangURL;
2025 if( !bIsWriteAccess )
2027 rtl::OUString aTempFileURL;
2028 ::osl::FileBase::RC eErr = ::osl::File::createTempFile( 0, 0, &aTempFileURL );
2029 if( eErr == ::osl::FileBase::E_None )
2031 rtl::OUString aTempDirURL = aTempFileURL;
2034 m_xSFA->kill( aTempDirURL );
2036 catch (Exception &)
2038 m_xSFA->createFolder( aTempDirURL );
2040 aZipDir = aTempDirURL;
2041 o_rbTemporary = true;
2045 aParamsSeq[4] = uno::makeAny( rtl::OUString::createFromAscii( "-zipdir" ) );
2046 rtl::OUString aSystemPath;
2047 osl::FileBase::getSystemPathFromFileURL( aZipDir, aSystemPath );
2048 aParamsSeq[5] = uno::makeAny( aSystemPath );
2050 if( !bIsWriteAccess )
2052 aParamsSeq[6] = uno::makeAny( rtl::OUString::createFromAscii( "-srcdir" ) );
2053 rtl::OUString aSrcDirVal;
2054 osl::FileBase::getSystemPathFromFileURL( aLangURL, aSrcDirVal );
2055 aParamsSeq[7] = uno::makeAny( aSrcDirVal );
2058 Sequence< sal_Int16 > aOutParamIndex;
2059 Sequence< uno::Any > aOutParam;
2060 uno::Any aRet = xInvocation->invoke( rtl::OUString::createFromAscii( "createIndex" ),
2061 aParamsSeq, aOutParamIndex, aOutParam );
2063 if( bIsWriteAccess )
2064 aIndexFolder = implGetFileFromPackage( rtl::OUString::createFromAscii( ".idxl" ), xPackage );
2065 else
2066 aIndexFolder = aZipDir + rtl::OUString::createFromAscii( "/help.idxl" );
2069 catch (Exception &)
2074 return aIndexFolder;
2077 void IndexFolderIterator::deleteTempIndexFolder( const rtl::OUString& aIndexFolder )
2079 sal_Int32 nLastSlash = aIndexFolder.lastIndexOf( '/' );
2080 if( nLastSlash != -1 )
2082 rtl::OUString aTmpFolder = aIndexFolder.copy( 0, nLastSlash );
2085 m_xSFA->kill( aTmpFolder );
2087 catch (Exception &)